En esta página
Volver a tutoriales

Gestión de Riesgo para EAs en MT5: Size, SL/TP y Trailing Stop

Protege tu capital: dimensionamiento (fijo, ATR, %), Stop Loss, Take Profit, trailing stops y reglas a nivel de cuenta. Mejores prácticas para que tu EA opere con seguridad.

📖 31 min read

📝 6,200 words

🏷️ MQL5 & Expert Advisors

Compartir este artículo:

¿Quieres crear una estrategia sin código ahora?

Crea tu cuenta gratis en segundos y empieza de inmediato.


Gestión de Riesgo en EA — Protege tu Capital con MetaTrader 5

Tu EA puede encontrar entradas perfectas, pero sin gestión de riesgo una mala operación puede borrar semanas de ganancias. Según la documentación de funciones de trading MQL5, cada orden que envías debe incluir volumen, Stop Loss y Take Profit sensatos — o arriesgas reventar tu cuenta. Esta guía te enseña dimensionamiento, SL/TP, trailing stops y protecciones de cuenta usando la API oficial de MetaTrader 5, para que tu EA opere con seguridad en demo y en vivo.


Por qué Importa la Gestión de Riesgo

Una estrategia que gana el 60% del tiempo puede seguir perdiendo dinero si las pérdidas son mayores que las ganancias. La gestión de riesgo controla cuánto arriesgas por operación y dónde cortas pérdidas. Según MqlTradeRequest: volume, sl y tp son campos esenciales — úsalos con criterio.

Qué añadiremos a tu EA:

TemaPor qué importa
DimensionamientoDecidir tamaño del lote por operación — fijo, % de riesgo o basado en ATR
Stop Loss (SL)Limitar pérdida por operación; el bróker ejecuta cuando el precio toca SL
Take Profit (TP)Asegurar beneficios; salir cuando el precio alcanza TP
Trailing stopMover SL a favor del beneficio para proteger ganancias
Protecciones de cuentaMáx. posiciones, comprobación de margen, límite de pérdida diaria

Paso 1: Tamaño de Lote Fijo

¿Qué es? El tamaño del lote es cuántas unidades operas. Un lote fijo significa que siempre abres 0.1, 0.5 o 1.0 lotes — sin importar el tamaño de la cuenta ni la volatilidad del mercado. Es la forma más sencilla de empezar.

¿Por qué usarlo? Para backtesting y estrategias simples, el lote fijo mantiene la lógica clara. No necesitas calcular nada — solo defines un input y lo usas.

Importante: Cada bróker define tamaño mínimo y máximo del lote (ej. mín 0.01, máx 100). Si envías 0.001 o 500 lotes, el bróker rechaza la orden. Debes leer estos límites primero.

MqlTradeRequest.volume espera el volumen en lotes. Según SymbolInfoDouble:

double volMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double volMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double volStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

double lot = MathMax(volMin, MathMin(volMax, InpLotSize));
lot = MathFloor(lot / volStep) * volStep;
lot = NormalizeDouble(lot, 2);

Aplica antes de OrderSend: request.volume = lot;


Paso 2: Riesgo por Operación (%)

¿Qué es? En lugar de un lote fijo, arriesgas un porcentaje fijo de tu cuenta por operación. Por ejemplo: "Nunca arriesgaré más del 1% de mi balance en una sola operación." Si tu balance es $10,000, cada operación arriesga como máximo $100. Si crece a $20,000, cada operación arriesga $200 — el tamaño del lote se ajusta solo.

¿Por qué usarlo? Un lote de 0.1 en una cuenta de $1,000 es enorme (puede acabarla en pocas operaciones malas). El mismo 0.1 lote en $50,000 es pequeño. El riesgo % mantiene tu riesgo proporcional a tu cuenta — así sobrevives a las rachas malas y creces de forma estable.

¿Cómo funciona? Decides: "Arriesgo 1% por operación." Luego calculas: "Si mi Stop Loss está a 50 pips, ¿cuántos lotes puedo abrir para que 50 pips = 1% de mi balance?" La respuesta te da el tamaño del lote. Usa AccountInfoDouble(ACCOUNT_BALANCE) y el valor del tick para el cálculo.

Fórmula:

  • Riesgo = Balance × (Riesgo% / 100)
  • Lote = Riesgo / (StopLoss en puntos × Valor por punto por lote)

Ejemplo — 1% riesgo, SL 50 pips en EURUSD:

double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskPct = 1.0;
double riskAmount = balance * (riskPct / 100.0);
double slPoints = 50 * 10;
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double valuePerPoint = (tickValue / tickSize) * point;
double lot = riskAmount / (slPoints * point * valuePerPoint);
lot = MathMax(volMin, MathMin(volMax, lot));
lot = MathFloor(lot / volStep) * volStep;
lot = NormalizeDouble(lot, 2);

Paso 3: Lote Basado en ATR

¿Qué es? El ATR (Average True Range) es un indicador que mide cuánto se mueve el precio de media. En días tranquilos, el ATR es bajo (ej. 20 pips). En días volátiles, es alto (ej. 80 pips). Si usas un Stop Loss fijo de 50 pips, en días volátiles el precio puede alcanzar tu SL fácilmente (stop falso). En días tranquilos, 50 pips pueden ser demasiado justos y sacarte por ruido normal.

¿Por qué usarlo? Al basar la distancia del Stop Loss en el ATR (ej. 1.5× ATR), te adaptas a la volatilidad actual. Cuando el mercado está tranquilo, tu SL está más cerca. Cuando es volátil, tu SL es más amplio — así no te sacan por oscilaciones normales. Luego usas esa distancia en tu fórmula de riesgo %: SL más amplio → lote menor para el mismo riesgo en dinero.

¿Cómo funciona? Obtén el valor del ATR con iATR y CopyBuffer. Multiplica por un factor (ej. 1.5) para obtener la distancia del SL en precio. Convierte a puntos y úsalo en el cálculo del lote.

int atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
CopyBuffer(atrHandle, 0, 0, 1, atrBuffer);
double atr = atrBuffer[0];
double slDistance = atr * 1.5;
double slPoints = slDistance / SymbolInfoDouble(_Symbol, SYMBOL_POINT);

Paso 4: Stop Loss y Take Profit

¿Qué es? Stop Loss (SL) y Take Profit (TP) son niveles de precio que defines al abrir una operación. Stop Loss = "Si el precio va contra mí hasta aquí, cierra la posición automáticamente." Take Profit = "Si el precio se mueve a mi favor hasta aquí, cierra y asegura el beneficio." El bróker los ejecuta por ti — no necesitas mirar el gráfico.

¿Por qué usarlos? Sin SL, una mala operación puede vaciar tu cuenta. Sin TP, puede que nunca cierres ganadores. SL y TP eliminan la emoción — el EA y el bróker gestionan las salidas automáticamente.

Importante: En MqlTradeRequest, sl y tp deben ser precios (ej. 1.0850), no puntos. Calculas el precio a partir del precio de entrada ± (pips × point). Defínelos al abrir:

PosiciónSLTP
CompraPor debajo del precio de entradaPor encima del precio de entrada
VentaPor encima del precio de entradaPor debajo del precio de entrada

Ejemplo — Compra con SL 50 pips y TP 100 pips:

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl = NormalizeDouble(ask - 50 * 10 * point, digits);
double tp = NormalizeDouble(ask + 100 * 10 * point, digits);
request.sl = sl;
request.tp = tp;

Paso 5: SYMBOL_TRADE_STOPS_LEVEL y NormalizeDouble

¿Qué es? Los brókers no permiten colocar SL/TP demasiado cerca del precio actual. Por ejemplo: no puedes poner un Stop Loss a 1 pip — los brókers exigen una distancia mínima (a menudo 10–50 puntos, según el símbolo). Si lo ignoras, OrderSend devuelve error 130 (invalid stops).

SYMBOL_TRADE_STOPS_LEVEL te indica la distancia mínima en puntos. NormalizeDouble redondea los precios al número correcto de decimales — los brókers rechazan precios como 1.0850123 cuando el símbolo espera 1.08501.

¿Por qué importa? Muchos principiantes reciben "invalid stops" porque ponen el SL demasiado cerca o envían precios con precisión incorrecta. Siempre comprueba SYMBOL_TRADE_STOPS_LEVEL y usa NormalizeDouble(precio, digits) antes de enviar. Según SymbolInfoInteger:

int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
if(stopLevel <= 0) stopLevel = 10;
double minDist = stopLevel * point;
double slDist = MathMax(minDist + 5 * point, 50 * 10 * point);
sl = NormalizeDouble(ask - slDist, digits);

Siempre usa NormalizeDouble(precio, digits) — los brókers rechazan precios con precisión incorrecta.


Paso 6: Trailing Stop

¿Qué es? Un trailing stop es un Stop Loss que se mueve cuando el precio se mueve a tu favor. Ejemplo: Compras en 1.0850 con SL en 1.0800. El precio sube a 1.0900. En lugar de dejar el SL en 1.0800, lo mueves a 1.0870 (30 pips por debajo del precio actual). Ahora, si el precio retrocede, aseguras 20 pips de beneficio en lugar de una pérdida. Si el precio sigue subiendo, sigues moviendo el SL — "siguiendo" al precio.

¿Por qué usarlo? Protege los beneficios. Sin trailing stop, una operación ganadora puede convertirse en perdedora si esperas demasiado. Con trailing stop, aseguras ganancias a medida que el mercado se mueve a tu favor.

¿Cómo funciona? En OnTick(), recorre tus posiciones. Para una Compra: si el Bid actual está lo bastante por encima del precio de apertura y por encima del SL actual, modifica el SL a un nuevo nivel (ej. Bid menos 30 pips). El bróker mantiene el nuevo SL — si el precio baja, cierra en ese nivel.

double trailPoints = 30 * 10;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
   ulong ticket = PositionGetTicket(i);
   if(ticket <= 0 || PositionGetInteger(POSITION_MAGIC) != InpMagic) continue;
   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double sl = PositionGetDouble(POSITION_SL);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
   {
      double newSL = NormalizeDouble(bid - trailPoints * point, digits);
      if(newSL > sl && newSL < bid)
      {
         MqlTradeRequest req = {};
         MqlTradeResult res = {};
         req.action = TRADE_ACTION_SLTP;
         req.position = ticket;
         req.symbol = _Symbol;
         req.sl = newSL;
         req.tp = PositionGetDouble(POSITION_TP);
         OrderSend(req, res);
      }
   }
}

Paso 7: Protecciones de Cuenta

¿Qué es? Las protecciones de cuenta son comprobaciones extra que añades para que tu EA no haga algo peligroso. Por ejemplo: "Nunca abrir más de 2 posiciones a la vez" o "No abrir una nueva operación si el margen libre está por debajo de $500." Estas reglas te protegen de errores (ej. un EA que abre 100 posiciones) o condiciones de mercado extremas.

¿Por qué usarlas? Incluso con un buen SL/TP, un error o un suceso inesperado puede provocar sobreoperación o sobreapalancamiento. Las protecciones son una red de seguridad — detienen el EA antes de que dañe tu cuenta.

Protecciones habituales:

Máximo de posiciones:

int countMyPositions()
{
   int n = 0;
   for(int i = 0; i < PositionsTotal(); i++)
      if(PositionGetInteger(POSITION_MAGIC) == InpMagic) n++;
   return n;
}
if(countMyPositions() >= InpMaxPositions) return;

Comprobación de margen: Usa AccountInfoDouble(ACCOUNT_MARGIN_FREE) y OrderCalcMargin antes de abrir.


Resumen — Lo que Construiste

Añadiste: lote fijo y % de riesgo, SL basado en ATR, SL/TP en MqlTradeRequest, respeto a SYMBOL_TRADE_STOPS_LEVEL, trailing stop y protecciones de cuenta. Tu EA respeta los límites del bróker y protege el capital.

Consejo extra: ¿Quieres añadir estas reglas de riesgo sin programar? Prueba AlfaTactix Strategy Builder gratis — configura dimensionamiento (fijo, % riesgo, ATR), Stop Loss, Take Profit, trailing stops y protecciones de cuenta en una interfaz visual. Exporta MQL5 que respeta los límites del bróker. La misma protección, cero código.


Código Completo

bool OpenBuyWithSLTP(double lot, double slPips, double tpPips)
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   int stopLevel = (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   if(stopLevel <= 0) stopLevel = 10;
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double sl = NormalizeDouble(ask - MathMax(stopLevel * point, slPips * 10 * point), digits);
   double tp = NormalizeDouble(ask + MathMax(stopLevel * point, tpPips * 10 * point), digits);
   MqlTradeRequest req = {};
   MqlTradeResult res = {};
   req.action = TRADE_ACTION_DEAL;
   req.symbol = _Symbol;
   req.volume = lot;
   req.type = ORDER_TYPE_BUY;
   req.price = ask;
   req.sl = sl;
   req.tp = tp;
   req.deviation = 10;
   req.magic = InpMagic;
   return OrderSend(req, res);
}

Resolución de Problemas

SíntomaCausaSolución
Invalid stops (130)SL/TP demasiado cerca o lado incorrectoUsa SYMBOL_TRADE_STOPS_LEVEL, NormalizeDouble y dirección correcta.
Not enough money (134)Lote demasiado grandeReduce lote, usa % de riesgo o OrderCalcMargin antes de enviar.
Lote redondeado a ceroRiesgo % muy bajo o SL muy amplioAsegura lot >= SYMBOL_VOLUME_MIN; aumenta riesgo % o reduce SL.
Trailing stop no se mueveCondición no cumplida o modificación fallidaRegistra newSL vs sl; comprueba retcode de OrderSend.

Consulta los códigos de retorno MQL5.

Crea tu estrategia de trading sin código ahora — gratis

Crea tu cuenta y empieza ahora mismo a construir una estrategia sin código. Añade indicadores, filtros y reglas de riesgo, y exporta MQL5 en minutos.

Preguntas Frecuentes

Es cómo decides el tamaño del lote en cada operación. Opciones: lote fijo (simple), riesgo por operación % (ej. arriesgar 1% del balance), o basado en ATR (se adapta a la volatilidad). Usa AccountInfoDouble(ACCOUNT_BALANCE) y SymbolInfoDouble para los cálculos.

Riesgo = Balance × 0.01. Lote = Riesgo / (StopLoss en puntos × TickValue). Usa OrderCalcProfit() o valor de pip por lote manual. Siempre normaliza con NormalizeDouble() y respeta SYMBOL_VOLUME_MIN/MAX.

Distancia mínima (en puntos) entre el precio actual y SL/TP definida por el bróker. Si tu SL está muy cerca, el bróker rechaza la orden. Usa SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL) y añade margen antes de enviar.

En OnTick(), recorre las posiciones con tu magic. Para Compra: si Bid - PositionGetDouble(POSITION_PRICE_OPEN) >= puntos de trail, modifica SL a Bid - trail. Usa TRADE_ACTION_SLTP para modificar.

SL/TP están demasiado cerca del precio o en el lado incorrecto. Comprueba SYMBOL_TRADE_STOPS_LEVEL, usa NormalizeDouble(precio, dígitos), y asegura Compra: SL < precio < TP, Venta: SL > precio > TP.

El lote fijo es simple pero ignora el tamaño de la cuenta — 0.1 lote en $1000 es muy distinto que en $10000. El riesgo % (ej. 1–2% por operación) escala con el balance y se recomienda para live.

Crea tu estrategia sin código ahora — gratis

Crear cuenta gratis