Blog · Riesgo
Auditoría de lotaje de un EA: lote solicitado frente a lote ejecutado
Dónde cambia el lotaje de un expert advisor de MT5 entre el cálculo y la ejecución (paso de volumen, mínimo y máximo, margen, ejecuciones parciales), código MQL5 para registrar la cadena completa de lotes y la tolerancia del 5% que separa el redondeo de un problema real.
Pregúntale a quien programó un EA qué lotaje opera su experto y te dará un número. Mira el extracto de la cuenta y a menudo encontrarás otro. La diferencia rara vez es un fallo de la estrategia: es la suma de pequeños ajustes entre el momento en que el EA decide un tamaño y el momento en que el bróker lo ejecuta. Esta guía muestra dónde cambia el lote, cómo registrarlo para que la diferencia se vea y qué tolerancia es razonable antes de tratarlo como un problema.
Cuatro números, no uno
| Etapa | Qué es | Quién lo cambia |
|---|---|---|
| Lote base | Lo que operaría la estrategia sin ajustes: tamaño fijo, o % de riesgo dividido por la distancia al stop. | Lógica de la estrategia |
| Multiplicador | Cualquier factor aplicado encima: escalado por equity, filtro de volatilidad, lógica de recuperación, un input manual de «riesgo x0,5». | Módulo de riesgo, operador |
| Lote solicitado | Base × multiplicador, tal como se envía en la orden. | EA |
| Lote final | Lo que realmente se ejecutó. | Bróker: paso de volumen, mínimo/máximo, margen, ejecuciones parciales |
La mayoría de EAs registran solo el lote solicitado, si acaso. La auditoría necesita los cuatro, por operación y con marca de tiempo.
Dónde cambia el bróker tu tamaño
- Paso de volumen. Un 0,137 solicitado en un símbolo con paso 0,01 se convierte en 0,13 o 0,14 según cómo redondee el EA. Normaliza siempre tú mismo con
SYMBOL_VOLUME_STEP, y redondea hacia abajo cuando el tamaño sale de un presupuesto de riesgo. - Mínimo y máximo. Por debajo de
SYMBOL_VOLUME_MINla orden se rechaza («invalid volume»); tras un drawdown, el lotaje por riesgo en una cuenta pequeña puede caer bajo el mínimo y el EA deja de operar en silencio. Por encima deSYMBOL_VOLUME_MAXo del tope de la prop firm, se rechaza o, peor, se divide. - Margen. Con varias posiciones abiertas, el margen libre puede no cubrir el tamaño solicitado. Algunos EAs reintentan con un lote menor; si el tuyo lo hace, esa reducción debe quedar registrada.
- Ejecuciones parciales. En cuentas ECN y tamaños grandes, la ejecución puede llegar en trozos o solo en parte. Lee el resultado de la operación ejecutada, no de tu solicitud.
Cómo registrarlo en MQL5
Registra la cadena en el momento del envío y después lee lo que se ejecutó:
double NormalizeLot(const string sym, double lot)
{
double step = SymbolInfoDouble(sym, SYMBOL_VOLUME_STEP);
double vmin = SymbolInfoDouble(sym, SYMBOL_VOLUME_MIN);
double vmax = SymbolInfoDouble(sym, SYMBOL_VOLUME_MAX);
lot = MathFloor(lot / step) * step; // hacia abajo: nunca superar el riesgo previsto
if(lot < vmin) return 0.0; // el llamador debe tratar 0 como «no operar»
return MathMin(lot, vmax);
}
// tras un OrderSend correcto:
double finalLot = 0.0;
if(HistoryDealSelect(result.deal))
finalLot = HistoryDealGetDouble(result.deal, DEAL_VOLUME);
PrintFormat("LOT_AUDIT sym=%s base=%.2f mult=%.2f requested=%.2f final=%.2f",
_Symbol, baseLot, multiplier, requestedLot, finalLot);
Devolver cero en lugar de subir el tamaño hasta el mínimo es deliberado. Un EA que opera 0,01 sin avisar cuando su modelo de riesgo pedía 0,004 está asumiendo dos veces y media el riesgo previsto, justo en la cuenta que menos se lo puede permitir.
Qué tolerancia es razonable
Compara el lote final con el lote esperado (base × el multiplicador que crees tener configurado). Una diferencia de hasta el 5% se explica por el redondeo al paso en tamaños normales. Más allá, está pasando otra cosa, y los sospechosos habituales son:
- Un input de multiplicador cambiado en un gráfico y no en los demás.
- Lógica de recuperación o martingala activada en un preset pensado para una cuenta prop.
- Dos instancias del EA en el mismo símbolo y mágico, cada una abriendo su posición.
- Un escalado por equity que lee la divisa de cuenta equivocada o un balance desactualizado.
- Un preset distinto tras una actualización: la versión nueva venía con otros valores por defecto.
Los errores de redondeo son simétricos y pequeños. Una desviación que siempre es al alza, o que solo aparece tras operaciones perdedoras, es un patrón, y es el patrón que busca el revisor de una prop firm.
Auditar una flota en lugar de una cuenta
En una cuenta puedes leer la pestaña Expertos. En diez, necesitas enviar los cuatro números a algún sitio donde se puedan comparar. El contrato de telemetría de Quantisentry lleva en cada reporte el lote base, el solicitado y el final, más el multiplicador aplicado y su origen; aplica automáticamente la tolerancia del 5% y marca las filas que la superan, por EA y por cuenta. Como la plataforma es de solo lectura, nadie puede acusar al registro de haber influido en las operaciones que describe, algo que importa cuando la auditoría es para un tercero.
Este artículo es educativo y no constituye asesoramiento de inversión.
Preguntas frecuentes
¿Por qué mi EA opera un lote distinto del que calculó?
Entre el cálculo y la ejecución el tamaño pasa por un multiplicador de riesgo, el redondeo al paso de volumen del bróker, los límites de volumen mínimo y máximo, las comprobaciones de margen y, a veces, ejecuciones parciales. Cada paso puede cambiarlo.
¿Debe un EA redondear el lote hacia arriba hasta el mínimo del bróker?
No. Si el modelo de riesgo pide menos que el volumen mínimo, operar el mínimo multiplica el riesgo previsto. Es mejor devolver cero y no abrir la operación.
¿Qué desviación entre lote esperado y ejecutado es aceptable?
Hasta un 5% aproximadamente se explica por el redondeo al paso de volumen en tamaños normales. Desviaciones mayores o siempre en el mismo sentido apuntan a un multiplicador cambiado, lógica de recuperación, instancias duplicadas del EA o un preset equivocado.
¿Cómo leo en MQL5 el volumen realmente ejecutado?
Tras un OrderSend correcto, selecciona la operación con HistoryDealSelect(result.deal) y lee DEAL_VOLUME, en lugar de fiarte del volumen de tu propia solicitud.