# Construye un panel de trading de MT5 con el starter de Next.js

> Una app de Next.js sobre la API de MT5 de fxapis: conecta una cuenta, mira sus posiciones y opera tras confirmar, con la clave siempre en el servidor.

Publicado el 2026-10-26 por ElWizard para fxapis. Canónica: https://fxapis.com/es/blog/panel-de-trading-mt5-con-nextjs

## En resumen

- fxapis-nextjs-starter es una app pequeña de Next.js que funciona: conecta una cuenta de MT5, la pone en línea, muestra sus posiciones y coloca una orden de mercado.
- La API key nunca llega al navegador: el cliente es solo de servidor, y las Server Actions hacen cada escritura.
- Las órdenes pasan por un paso de confirmación antes de operar que se vuelve a revisar en el servidor, y cada orden lleva una clave de idempotencia nueva.
- Es de un solo usuario a propósito: cambia un archivo por una base de datos y agrega tu propia autenticación para hacerla multiusuario.

[fxapis-nextjs-starter](https://github.com/FXapis/fxapis-nextjs-starter) es una app de Next.js pequeña y funcional sobre la API de MetaTrader 5 de fxapis, no un juguete. **Conecta una cuenta demo de un broker, la pone en línea, muestra sus posiciones abiertas y coloca una orden de mercado solo después de un paso de confirmación explícito.** Todo lo que toca tu API key o tus credenciales del broker corre en el servidor; el navegador nunca ve ninguna de las dos.

Tiene tres rutas que vale la pena leer: `/connect` conecta una cuenta y la pone en línea, `/dashboard` muestra el estado de la cuenta, sus posiciones abiertas y el formulario de trading, y `/` te envía a la que corresponda de las dos.

## Córrelo

```bash
git clone https://github.com/FXapis/fxapis-nextjs-starter.git
cd fxapis-nextjs-starter
npm install
cp .env.local.example .env.local   # add your fxapis API key
npm run dev
```

Abre `localhost:3000`. Sin ninguna cuenta conectada, te lleva a **Connect an account**: escribe el login, el servidor y la contraseña de trading de una cuenta **demo** de un broker, no la contraseña de inversor, que inicia sesión pero no puede operar ([conectar cuentas](https://docs.fxapis.com/es/guides/connect-accounts) explica la diferencia). La clave necesita `accounts:read`, `accounts:write`, `trading:read` y `trading:execute`; créala en la [consola](https://fxapis.com/dashboard/keys).

## Cómo está construido

- **La API key nunca sale del servidor.** `src/lib/fxapis-client.ts` crea el único cliente a partir de `FXAPIS_API_KEY` y empieza con `import "server-only"`: importarlo en un Client Component es un error de compilación, no una sorpresa en tiempo de ejecución.
- **Las Server Actions hacen cada escritura.** Conectar, poner en línea, colocar una orden y cerrar una posición son funciones `"use server"` llamadas directamente desde un formulario o un botón. No hay rutas de API aparte que mantener sincronizadas con la interfaz.
- **Una cuenta, sin base de datos.** `src/lib/store.ts` recuerda el id de la cuenta conectada en un archivo ignorado por git: suficiente para probarla sin configurar nada, y el único archivo que hay que reemplazar cuando deja de ser una demo.
- **Cada orden lleva una clave de idempotencia nueva**, así que un formulario reenviado nunca puede colocar la orden dos veces.
- **Las formas de las respuestas están tipadas a mano** en `src/lib/types.ts`, nombrando solo los campos que lee la app, porque el [SDK de TypeScript](https://fxapis.com/es/blog/api-de-mt5-para-nodejs-sdk-de-typescript) devuelve los datos de la API sin tipos.

## Confirmar antes de operar

El formulario de trading nunca envía una orden con el primer clic. Al enviarlo muestra exactamente lo que se enviará (dirección, volumen y símbolo) detrás de una casilla obligatoria, y solo un segundo clic explícito en **Confirm and send** la coloca. La Server Action vuelve a revisar la misma confirmación en el servidor, porque una revisión que vive solo en el navegador es una comodidad, no una protección: cualquier cosa que llame a la acción directamente se la saltaría.

## Por qué cada página es dinámica

`/` y `/dashboard` están marcadas con `export const dynamic = "force-dynamic"`. Un panel de trading lee un estado en vivo en cada solicitud, y de lo contrario Next.js lo prerenderizaría tranquilamente una vez al compilar y serviría en producción esa foto congelada. `/connect` es un formulario simple sin nada en vivo que leer, así que se prerenderiza normalmente. Mientras una cuenta se conecta, un pequeño componente de cliente consulta cada pocos segundos; es el único archivo que cambiar si prefieres recibir los [webhooks](https://docs.fxapis.com/guides/webhooks) de fxapis (en inglés).

## Ir más allá

- **Una base de datos real:** cambia `store.ts` por tu ORM y la app pasa a ser multicuenta y multiusuario; todos los demás archivos ya reciben el id de la cuenta como un valor.
- **Autenticación:** no tiene, a propósito. Pon tu capa de sesiones delante de `/dashboard`, como en cualquier app de Next.js.
- **Más de la API:** las órdenes pendientes, mover stops, las órdenes multicuenta y el historial están todos en el SDK; el [repositorio de ejemplos](https://fxapis.com/es/blog/ejemplos-de-api-de-mt5-en-python-nodejs-y-curl) tiene patrones para copiar.

## Adónde ir después

- [SDKs y ejemplos](https://docs.fxapis.com/es/sdks) y la [guía de Node.js](https://docs.fxapis.com/guides/nodejs) en la documentación (la guía, en inglés).
- [Trading](https://docs.fxapis.com/es/trading) para cada resultado que puede tener una orden, antes de agregar más tipos de orden.

## Preguntas

### ¿Es seguro apuntar el starter a una cuenta real?

Usa una cuenta demo de un broker. Una clave fx_test_ es una etiqueta, no un sandbox: toda clave de fxapis llega a un broker real. El starter además pide confirmación antes de cada orden.

### ¿Por qué las páginas del panel son dinámicas?

Un panel de trading muestra un estado en vivo. Sin force-dynamic, Next.js podría prerenderizar la página una vez al compilar y servir esa foto fija para siempre.

### ¿Cómo lo hago multiusuario?

Reemplaza src/lib/store.ts, que recuerda un id de cuenta en un archivo local, por tu base de datos, y pon tu autenticación delante de /dashboard. El resto de la app ya recibe el id de la cuenta como un valor.
