MQL4 no te ayuda a estructurar nada. Tienes OnTick(), variables globales y un archivo. El camino de menor resistencia es un procedimiento largo donde la señal de entrada, la gestión de posiciones y los controles de riesgo se van entrelazando hasta que nadie puede tocar uno sin romper otro.
Ese entrelazado tiene un coste concreto: cuando la lógica de la estrategia se equivoca, la protección se equivoca con ella, porque comparten estado y comparten condiciones.
La regla que nos impusimos
El guardián no puede leer nada que la estrategia decida.
Una sola restricción, y ordena todo lo demás. El guardián no sabe cuál es el sesgo actual, ni si la señal está activa, ni qué nivel de la rejilla vamos. Sólo lee hechos del terminal: posiciones abiertas, su flotante, el capital de la cuenta, la hora.
Esto significa que el guardián vigila todas las posiciones del terminal — incluidas las de otros robots y las que abras a mano. No es un efecto secundario, es la consecuencia de no acoplarlo a nuestra estrategia.
Cómo queda en la práctica
El EA corre dos bloques independientes en cada tick:
OnTick()
Guardian_Check() // primero, siempre, pase lo que pase
Strategy_Step() // sólo si el guardián no ha pausado
Guardian_Check() no llama a nada de la estrategia. Strategy_Step() no llama a nada del guardián: consulta una bandera de pausa y ya.
Esa asimetría es deliberada. El guardián puede detener a la estrategia. La estrategia no puede ablandar al guardián. Si algún día alguien escribe if (senal_muy_buena) saltarse_el_stop(), la separación se acabó.
Dos identificadores mágicos, no uno
Un detalle de MQL4 que ahorra dolor: usamos un magic number distinto por dirección — uno para las posiciones de venta y otro para las de compra.
Con un solo identificador, agrupar posiciones para calcular el flotante de un conjunto obliga a filtrar por dirección en cada bucle, y esos filtros se copian mal. Con dos, OrdersTotal() filtrado por magic es el conjunto. La agrupación deja de ser código y pasa a ser una propiedad de los datos.
Estado: cuanto menos, mejor
La versión anterior tenía una capa adaptativa con estado propio: régimen actual, contador de freno, sesgo invertido. Al medirla y ver que no aportaba, la borramos entera.
Lo que quedó es que la función de sesgo es literalmente return -raw; — una línea, sin estado. Y el panel dejó de publicar dos bloques de diagnóstico que existían sólo para depurar esa capa.
Menos estado no es sólo elegancia. En un EA que corre desatendido durante días, cada variable persistente es un sitio donde el sistema puede quedarse en un estado que nunca previste tras una reconexión, un cambio de símbolo o un reinicio del terminal.
Lo que el guardián no puede hacer
Esta parte va en la documentación, no en el código, y es la más importante:
El guardián puede cortar un conjunto de posiciones, aplanar la cuenta y parar el día. No puede predecir un movimiento, no puede ejecutar cuando el bróker rechaza órdenes, no puede cerrar un hueco que ya estaba aguantando, no puede vigilar con el terminal apagado, y no puede convertir una estrategia de expectativa negativa en una positiva.
Una capa de protección bien separada te da garantías acotadas. Confundir «bien diseñada» con «te cubre siempre» es cómo la gente pierde dinero con sistemas correctamente programados.
De la construcción de Cerberus, Tuurt Labs. Instrumento de alto riesgo: operar CFDs apalancados puede provocar la pérdida total del capital. Esto no es asesoría de inversión.