English Русский 中文 Deutsch 日本語
preview
Optimización y ajuste de código sin procesar para mejorar los resultados de las pruebas retrospectivas

Optimización y ajuste de código sin procesar para mejorar los resultados de las pruebas retrospectivas

MetaTrader 5Ejemplos |
38 2
Hlomohang John Borotho
Hlomohang John Borotho

Introducción

La búsqueda de resultados confiables en pruebas retrospectivas en el trading algorítmico depende no solo de una lógica estratégica sólida, sino también de la eficiencia y precisión del código subyacente. La optimización y el ajuste del código sin procesar son fundamentales para garantizar que los asesores expertos (EA) funcionen como se espera, minimizando la sobrecarga computacional y maximizando la precisión de ejecución. Un código mal optimizado puede distorsionar los resultados de las pruebas retrospectivas mediante la ejecución retrasada de órdenes, la detección incorrecta de señales o el agotamiento de recursos: problemas que enmascaran el verdadero potencial de una estrategia.

Durante el proceso de desarrollo de la estrategia, tomaremos varios pasos clave para garantizar que el EA sea funcionalmente sólido y técnicamente sólido. Comenzaremos agregando funciones auxiliares personalizadas y bloques lógicos reutilizables para agilizar las operaciones y evitar código repetitivo. Luego, presentaremos variables y constantes bien estructuradas que mejoran la legibilidad del código y simplifican los ajustes de parámetros. Estos ajustes fundamentales ayudarán a mantener el código y mejorar el tiempo de ejecución general durante cargas pesadas de pruebas retrospectivas o pruebas de múltiples símbolos.

Otro ámbito importante de mejora implica aprovechar los indicadores técnicos de manera más eficiente. En lugar de calcular indicadores a ciegas en cada tick o barra, implementaremos una lógica de actualización más inteligente para reducir la carga y el retraso. También experimentaremos con diferentes combinaciones de indicadores para apoyar una mejor toma de decisiones en la lógica del EA. Al combinar el refinamiento del código estructural, las funciones que tienen en cuenta el rendimiento y la optimización de indicadores, podemos mejorar drásticamente tanto la calidad como la velocidad de las pruebas retrospectivas, lo que nos acerca a una estrategia consistentemente rentable e implementable.



Desarrollo de la estrategia

El desarrollo de nuestra estrategia de trading algorítmico comienza con un enfoque estructurado y metódico para el reconocimiento de patrones y la validación de señales. En esencia, la estrategia emplea un marco basado en velas diseñado para identificar escenarios de reversión de alta probabilidad. Para posiciones largas, la lógica detecta sistemáticamente tres velas alcistas consecutivas, seguidas de una o dos velas bajistas correctivas, que culminan en una vela alcista de confirmación en el índice 1 (la barra cerrada más recientemente).

Por el contrario, las posiciones cortas se activan mediante un patrón inverso: tres velas bajistas consecutivas, sucedidas por una o dos velas alcistas de retroceso y finalizadas por una vela bajista de confirmación en el índice 1. Esta configuración garantiza que las señales se validen solo tras la formación de una nueva barra, alineando la ejecución con la acción del precio confirmada en lugar de con las fluctuaciones dentro de la barra.

Para operacionalizar esta lógica, la arquitectura de la estrategia priorizará el diseño de código modular y la eficiencia computacional. En primer lugar, se implementarán funciones auxiliares para abstraer tareas repetitivas, como la clasificación de velas (determinación alcista/bajista) y la validación de secuencia (verificaciones de patrones de velas consecutivas). Estas funciones aprovecharán los métodos de acceso a datos de precios nativos de MQL5, incluidos `iOpen()` y `iClose()`, al tiempo que minimizan los cálculos redundantes mediante el almacenamiento en caché de variables estáticas.

En segundo lugar, un modelo de ejecución basado en eventos garantizará que el Asesor Experto (EA) procese señales solo cuando se forme una nueva barra, según lo determinado por las comparaciones de marcas de tiempo en el índice 1. Este enfoque reduce la carga computacional innecesaria y evita activaciones falsas durante el desarrollo de la barra.

La fase final del desarrollo se centrará en la optimización del rendimiento y las pruebas de robustez. Se integrarán indicadores técnicos, como filtros de volumen o niveles de stop-loss ajustados a la volatilidad, para refinar la precisión de entrada/salida. Además, las matrices de buffer históricas se preasignarán para almacenar patrones de velas, lo que reducirá la sobrecarga de asignación de memoria en tiempo de ejecución. Al combinar estos elementos (diseño de código modular, ejecución basada en eventos e integración de indicadores estratégicos), el EA logrará un equilibrio entre capacidad de respuesta y eficiencia de recursos.

Código:

//+------------------------------------------------------------------+
//|                           Includes                               |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
MqlTick CTick, PTick;
CTrade trade;

enum InLot{
   Lot_fixed,
   Lot_dynamic,
};

//+------------------------------------------------------------------+
//|                           Inputs                                 |
//+------------------------------------------------------------------+
input group "--------------General Inputs--------------"
input int RSI_Period = 14;
input int    TakeProfit   = 100;     // TP in points
input ulong  MagicNumber  = 888888;  // EA identifier
input int    MaxBarsCheck = 8;       // Historical bars to analyze
input InLot Lot_mode = Lot_fixed;
input double  In_Lot = 0.01;
input bool TrailYourStop = true;
input int trailingStop = 50;
//input int StopLoss = 234;

//+------------------------------------------------------------------+
//|                      Global Variables                            |
//+------------------------------------------------------------------+
int rsiHandle, macdHanlde;
datetime lastBarTime;

double pointMultiplier;
double StopLoss     = 150;

bool bullish_pattern_met = false;
bool bearish_pattern_met = false;

double first_bullish_low = 0.0;
double first_bearish_high = 0.0;

ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;

La arquitectura del Asesor Experto integra bibliotecas y estructuras de datos esenciales para permitir una funcionalidad comercial perfecta. La inclusión de la biblioteca <Trade/Trade.mqh> proporciona acceso a la clase CTrade, lo que agiliza las operaciones de gestión de órdenes, como la apertura, modificación y cierre de posiciones. Se emplean dos estructuras MqlTick —`CTick` y `PTick`— para realizar un seguimiento de los datos de precios en tiempo real, lo que garantiza la precisión en el momento de la ejecución y el análisis de las condiciones del mercado. Una enumeración (InLot) define la metodología de dimensionamiento de posiciones, ofreciendo modos tanto fijos (Lot_fixed) como dinámicos (Lot_dynamic), reservándose este último para posibles cálculos de lotes ajustados al riesgo en futuras iteraciones.

La personalización del usuario se facilita a través de una interfaz de entrada dedicada, que permite ajustar los parámetros sin alterar el código central. Los ajustes críticos incluyen RSI_Period (por defecto: 14), que controla la sensibilidad del indicador que utilizaremos más adelante durante el desarrollo, y los valores `TakeProfit ` y `trailingStop` (en puntos) para definir los umbrales de riesgo-recompensa. El parámetro `MagicNumber` garantiza la integridad de la identificación de las operaciones, mientras que `MaxBarsCheck` determina la profundidad de los datos históricos para el análisis de patrones. La flexibilidad en el tamaño de las posiciones se consigue mediante Lot_mode e In_Lot, y las funciones de trailing stop (TrailYourStop, trailingStop) automatizan la protección de las ganancias a medida que las operaciones avanzan favorablemente.

Internamente, las variables globales gestionan flujos de trabajo operativos complejos. Los manejadores de indicadores (rsiHandle, macdHandle) almacenan y hacen referencia a instancias de indicadores durante el tiempo de ejecución, mientras que `lastBarTime` facilita la sincronización temporal al registrar la marca de tiempo de la vela analizada más recientemente. Los indicadores booleanos (bullish_pattern_met, bearish_pattern_met) y los marcadores de nivel de oscilación (first_bullish_low, first_bearish_high) supervisan dinámicamente las condiciones del mercado, y TimeFrame especifica la periodicidad operativa del EA, con el marco temporal del gráfico activo como valor predeterminado para su uso inmediato.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   // Create RSI and MACD indicator handles
   rsiHandle = iRSI(_Symbol, TimeFrame, RSI_Period, PRICE_CLOSE);
   macdHanlde = iMACD(_Symbol, TimeFrame, 12, 26, 9, PRICE_CLOSE);

   return(INIT_SUCCEEDED);
}

La función `Oninit()` inicializa correctamente los indicadores RSI y MACD asignando los ajustes correctos para sus períodos y tipos de precios. Estos indicadores se preparan en la memoria para su uso futuro en la optimización de las señales comerciales. Una configuración correcta devuelve INIT_SUCCEEDED para confirmar que el EA está listo para ejecutarse.

void OnTick(){

   if(!NewBarTrigger()) return;
   ThreeBar();
}
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Detects new bar formation                                        |
//+------------------------------------------------------------------+
bool NewBarTrigger(){

   datetime currentTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(currentTime != lastBarTime){
      lastBarTime = currentTime;
      return true;
   }
   return false;
}

double getHigh(int index) {
    return iHigh(_Symbol, _Period, index);
}

double getLow(int index) {
    return iLow(_Symbol, _Period, index);
}

//+------------------------------------------------------------------+
//| Execute trade with risk parameters                               |
//+------------------------------------------------------------------+
void ExecuteTrade(ENUM_ORDER_TYPE tradeType)
{
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double price = (tradeType == ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) :                                                  SymbolInfoDouble(_Symbol, SYMBOL_BID);

   // Convert StopLoss and TakeProfit from pips to actual price distances
   double sl_distance = StopLoss * point;
   double tp_distance = TakeProfit * point;
   
   double sl = (tradeType == ORDER_TYPE_BUY) ? price - sl_distance :
                                               price + sl_distance;   
   double tp = (tradeType == ORDER_TYPE_BUY) ? price + tp_distance :
                                               price - tp_distance;
   trade.PositionOpen(_Symbol, tradeType, In_Lot, price, sl, tp, NULL);
}

La función `OnTick()` actúa como el latido de nuestro EA, ejecutándose cada vez que llega un tick del mercado. Para evitar un procesamiento excesivo y cálculos innecesarios, primero comprueba si hay una nueva vela utilizando `NewBarTrigger()`. Si se ha formado una nueva barra, procedemos a llamar a la función `ThreeBar()`, que contiene nuestra lógica de negociación y nuestra rutina de detección de patrones.

La función `NewBarTrigger()` se encarga de detectar el inicio de una nueva vela. Lo hace comparando la hora de apertura de la vela actual con la hora almacenada previamente (`lastBarTime`). Si se detecta una nueva marca de tiempo, actualiza `lastBarTime` y devuelve verdadero, lo que permite que `OnTick()` continúe. Esto garantiza que las decisiones comerciales se tomen solo una vez por barra, lo que es crucial para nuestra estrategia que se basa en las confirmaciones de cierre de barras. Las funciones auxiliares `getHigh()` y `getLow()` son llamadas de utilidad simples que devuelven el precio alto y bajo de un índice de barra específico en el gráfico actual.

La función `ExecuteTrade()` maneja la colocación de operaciones con los parámetros de riesgo adecuados. Primero obtiene el precio de mercado actual en función del tipo de operación (compra o venta) y, a continuación, calcula el Stop Loss y el Take Profit en unidades de precio reales convirtiendo los valores de pip/punto definidos por el usuario utilizando el valor «Point» del símbolo. Estos niveles calculados se pasan al método `PositionOpen()` de la clase `CTrade`, lo que garantiza que cada operación se ejecute con controles de riesgo precisos y coherentes.

//+------------------------------------------------------------------+
//| Candle pattern detection Function                                |
//+------------------------------------------------------------------+
void ThreeBar() {
   // Settings
   string symbol = Symbol();              // Current symbol
   ENUM_TIMEFRAMES timeframe = PERIOD_M5; // Timeframe (e.g., 1-hour)

   // Pattern detection variables
   int min_bullish_count = 3;
   int min_bearish_count = 3;
   int check_candles = 6;  // Check the last 6 candles for patterns

   bool bullish_pattern = false;
   bool bearish_pattern = false;
   static bool bullish_pattern_detected = false;
   static bool bearish_pattern_detected = false;

   // Loop through recent candles to search for patterns
   for (int i = check_candles; i >= min_bullish_count; i--) {
      
      // Reset pattern flags for each loop iteration
      bullish_pattern = false;
      bearish_pattern = false;

      // 1. Check for Bullish Trend Pattern
      int bullish_count = 0;
      int bearish_count = 0;

      // Count initial bullish candles
      for (int j = i; j >= i - min_bullish_count + 1; j--) {
         if (iClose(symbol, timeframe, j) > iOpen(symbol, timeframe, j)){
            bullish_count++;
            first_bullish_low = getLow(5);
         }
         else
            break;
      }

      // Check for 1 or 2 bearish candles followed by a bullish candle
      if (bullish_count >= min_bullish_count) {
         for (int j = i - bullish_count; j >= i - bullish_count - 1; j--) {
            if (iClose(symbol, timeframe, j) < iOpen(symbol, timeframe, j))
               bearish_count++;
            else
               break;
         }
         if ((bearish_count == 1 || bearish_count == 2) &&
             iClose(symbol, timeframe, i - bullish_count - bearish_count) > iOpen(symbol, timeframe, i - bullish_count - bearish_count)) {
            bullish_pattern = true;
         }
      }

      // 2. Check for Bearish Trend Pattern
      int bearish_candles_count = 0;
      int bullish_candles_count = 0;

      // Count initial bearish candles
      for (int j = i; j >= i - min_bearish_count + 1; j--) {
         if (iClose(symbol, timeframe, j) < iOpen(symbol, timeframe, j)){
            bearish_candles_count++;
            first_bearish_high = getHigh(5);
         }
         else
            break;
      }

      // Check for 1 or 2 bullish candles followed by a bearish candle
      if (bearish_candles_count >= min_bearish_count) {
         for (int j = i - bearish_candles_count; j >= i - bearish_candles_count - 1; j--) {
            if (iClose(symbol, timeframe, j) > iOpen(symbol, timeframe, j))
               bullish_candles_count++;
            else
               break;
         }
         if ((bullish_candles_count == 1 || bullish_candles_count == 2) &&
             iClose(symbol, timeframe, i - bearish_candles_count - bullish_candles_count) < iOpen(symbol, timeframe, i - bearish_candles_count - bullish_candles_count)) {
            bearish_pattern = true;
         }
      }

      // Print result and call functions only once for each pattern
      if (bullish_pattern && !bullish_pattern_detected) {
         Print("Bullish pattern conditions are met");
         ExecuteTrade(ORDER_TYPE_BUY); // Call to buyer function
         bullish_pattern_detected = true;
      } else if (!bullish_pattern) {
         bullish_pattern_detected = false; // Reset when conditions no longer met
      }

      if (bearish_pattern && !bearish_pattern_detected) {
         Print("Bearish pattern conditions are met");
         ExecuteTrade(ORDER_TYPE_SELL); // Call to seller function
         bearish_pattern_detected = true;
      } else if (!bearish_pattern) {
         bearish_pattern_detected = false; // Reset when conditions no longer met
      }   
   }
}

La función `ThreeBar()` es la lógica central de detección de patrones de nuestro Asesor Experto. Analiza las formaciones recientes de velas japonesas en el marco temporal M5 o en cualquier marco temporal en el que se cargue el asesor experto para detectar posibles configuraciones de inversión de tendencia alcista o bajista. La lógica comienza analizando las últimas seis velas para identificar patrones en los que una serie de al menos tres velas alcistas o bajistas consecutivas va seguida de un breve retroceso (una o dos velas opuestas) y, a continuación, una vela de confirmación en la dirección de la tendencia original. Si se identifica una estructura de este tipo, se señala la presencia de un patrón válido.

Durante cada ciclo de escaneo, se capturan puntos clave de precios, como el mínimo de una oscilación alcista o el máximo de una oscilación bajista, para su posible uso futuro, como rupturas de estructura o filtros de operaciones.

Actualmente el EA abre dos posiciones cuando tenemos una vela bajista después de una vela alcista y abre otra operación después del cierre de la vela, pero abre una posición cuando tenemos dos velas bajistas seguidas de una vela alcista. Lo mismo ocurre con las señales de venta. Para resolver este problema, debemos añadir «break», que detiene inmediatamente el bucle una vez que un patrón ha activado una operación. Esto evita que el EA se adentre más en velas anteriores y encuentre el mismo patrón en una posición diferente, especialmente cuando la estructura permite retrocesos de 1 y 2 barras.

// Print result and call functions only once for each pattern
if (bullish_pattern && !bullish_pattern_detected) {
   Print("Bullish pattern conditions are met");
   ExecuteTrade(ORDER_TYPE_BUY);
   bullish_pattern_detected = true;
   break; // prevent further detection in this run
} else if (!bullish_pattern) {
   bullish_pattern_detected = false;
}
      
if (bearish_pattern && !bearish_pattern_detected) {
   Print("Bearish pattern conditions are met");
   ExecuteTrade(ORDER_TYPE_SELL);
   bearish_pattern_detected = true;
   break; // prevent further detection in this run
} else if (!bearish_pattern) {
   bearish_pattern_detected = false;
}

Incorporación de filtros indicadores:

// Indicator buffers
double rsi_value[1];    // Use array for buffer storage
double macd_main[1];    
double macd_signal[1];
   
// Get indicator values - with error checking
if (CopyBuffer(rsiHandle, 0, 0, 1, rsi_value) <= 0) {
    Print("RSI CopyBuffer error: ", GetLastError());
    return;
}
   
if (CopyBuffer(macdHandle, 0, 0, 1, macd_main) <= 0) { 
    Print("MACD Main Line error: ", GetLastError());
    return;
}
   
if (CopyBuffer(macdHandle, 1, 0, 1, macd_signal) <= 0) { 
    Print("MACD Signal Line error: ", GetLastError());
    return;
}

Antes de incorporar los filtros de indicadores en la lógica comercial, debemos recuperar y verificar los valores de los indicadores RSI y MACD utilizando `CopyBuffer()`. Esto garantiza que el EA obtenga las lecturas más recientes de los indicadores. En el código anterior, utilizamos matrices para almacenar un único valor de cada búfer indicador, y se incluye el manejo de errores después de cada copia del búfer para detectar cualquier problema, como un acceso fallido al controlador o datos faltantes.

Si algún búfer no consigue recuperar los datos, la función se cierra antes de tiempo y registra el error correspondiente, lo que evita que el EA tome decisiones comerciales basadas en entradas de indicadores no válidas o que faltan.

// Filter + Trade Logic
if (bullish_pattern && !bullish_pattern_detected &&
    rsi_value[0] > 50 && macd_main[0] > macd_signal[0])  
{
    Print("Bullish pattern confirmed with RSI(", rsi_value[0], ") and MACD(", 
          macd_main[0], "/", macd_signal[0], ")");
    ExecuteTrade(ORDER_TYPE_BUY);
    bullish_pattern_detected = true;
    break;
 }
else if (!bullish_pattern)
    bullish_pattern_detected = false;
      
if (bearish_pattern && !bearish_pattern_detected &&
    rsi_value[0] < 50 && macd_main[0] < macd_signal[0])  
{
    Print("Bearish pattern confirmed with RSI(", rsi_value[0], ") and MACD(", 
          macd_main[0], "/", macd_signal[0], ")");
    ExecuteTrade(ORDER_TYPE_SELL);
    bearish_pattern_detected = true;
    break;
}
else if (!bearish_pattern)
    bearish_pattern_detected = false;

El patrón de velas de tres barras por sí solo suele arrojar malos resultados en las pruebas retrospectivas, ya que no tiene en cuenta la tendencia general del mercado, lo que da lugar a frecuentes señales falsas. Para mejorar el rendimiento, introducimos la confirmación de tendencias incorporando los indicadores RSI y MACD directamente en el bloque de decisiones comerciales.

Para que una señal alcista sea válida, ahora requerimos que el RSI esté por encima de 50, lo que indica un impulso alcista, y que la línea principal del MACD esté por encima de la línea de señal, lo que sugiere una confirmación de la tendencia alcista. Del mismo modo, para las señales bajistas, el RSI debe estar por debajo de 50 y la línea principal del MACD debe estar por debajo de la línea de señal. Esta lógica de filtrado refuerza la precisión de las operaciones al alinear las entradas con el impulso general del mercado.

Al incorporar estos filtros, nos aseguramos de que las operaciones activadas por el patrón de tres barras solo se ejecuten cuando estén respaldadas por indicadores técnicos que reflejen la dirección predominante del mercado. Este enfoque de doble confirmación reduce la frecuencia de las operaciones durante los mercados volátiles o laterales y aumenta la probabilidad de entrar en operaciones que tienen impulso detrás.

En última instancia, este refinamiento mejora la capacidad de toma de decisiones del EA, lo que conduce a resultados de backtesting más consistentes y favorables, al tiempo que ayuda a evitar las oscilaciones bruscas causadas por basarse únicamente en la estructura de las velas japonesas.



Resultados de la prueba retrospectiva en (XAUUSD)

La prueba retrospectiva se evaluó utilizando datos históricos de precios del XAUUSD (oro/dólar estadounidense) en un intervalo de tiempo de 1 hora a lo largo de un periodo de prueba de 4 meses (del 26 de noviembre de 2021 al 17 de marzo de 2022). Los parámetros clave incluyeron:

  • Período RSI: 14
  • Gestión de riesgos: 500 puntos de Take Profit (TP), 150 puntos de Stop Loss (SL), tamaño de lote fijo.
  • Configuración del análisis: periodo histórico de 8 barras.

Contexto del mercado

Durante el periodo de prueba, el oro se negoció a un precio medio de 1.841,59 dólares, con una volatilidad extrema que osciló entre los 1.752,95 dólares (mínimo) y los 2.070,48 dólares (máximo). Esta trayectoria ascendente refleja una fuerte tendencia alcista, especialmente evidente a principios de 2022, cuando los precios subieron aproximadamente un 18 % hasta alcanzar el máximo en marzo. La marcada tendencia al alza durante este periodo concuerda con los factores macroeconómicos.



Conclusión

En este proceso de optimización abordamos las limitaciones de basarnos únicamente en un patrón de velas de tres barras para las entradas en las operaciones incorporando indicadores técnicos clave: el RSI y el MACD. Comenzamos por garantizar una recuperación de datos sólida mediante el uso de manejadores de indicadores y la copia de búferes con comprobaciones de errores. A continuación, aplicamos estos indicadores como filtros de confirmación dentro de la lógica de ejecución de operaciones, alineando las operaciones con la tendencia predominante del mercado. Esto mejora significativamente la calidad de las operaciones y la consistencia de las pruebas retrospectivas al filtrar las señales de baja probabilidad durante condiciones de rango o de contra tendencia.

En resumen, la combinación de patrones de acción del precio sin procesar con indicadores basados en el impulso, como el RSI y el MACD, crea un sistema de negociación más sensible al contexto. Este enfoque por capas mejora la capacidad del Asesor Experto para diferenciar entre configuraciones de operaciones de alta calidad y baja calidad. Al exigir la confluencia entre los patrones de velas japonesas y las señales de tendencia más amplias, el EA se vuelve más disciplinado y menos reactivo al ruido a corto plazo, lo que en última instancia se traduce en un mejor rendimiento y solidez tanto en las pruebas retrospectivas como en el trading en vivo.

Mejoras e investigación adicionales:

Área
 Sugerencia
Beneficio
Stop-Loss dinámico o Take-Profit
Ajuste SL/TP en función del ATR o la volatilidad reciente
Permite que la gestión de riesgos se adapte a las condiciones del mercado
Mejora del filtro de tendencias
Incluya medias móviles (por ejemplo, 200 EMA) para definir la tendencia a largo plazo
Mejora la precisión de la dirección de entrada
Control de frecuencia comercial
Añadir tiempo de espera entre operaciones o límite máximo de operaciones por día
Reduce el exceso de operaciones y la agrupación de operaciones
Análisis de múltiples marcos temporales
Confirmar las tendencias de RSI y MACD en marcos de tiempo más altos (por ejemplo, H1, H4)
Mejora la confiabilidad de la señal al alinearse en distintos períodos de tiempo
Filtrado de noticias
Integrar calendario económico o detección de tiempo de noticias
Evitar intercambios durante eventos de alto impacto

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/17702

Archivos adjuntos |
Ryan L Johnson
Ryan L Johnson | 2 ene 2026 en 00:59

Por favor, acláreme cómo funcionan CTick y PTick. Veo que ambos se declaran junto con Includes, pero no se hace referencia a ninguno de los dos en ninguna otra parte del código. En otras palabras, ¿qué es lo que CTick rastrea; y qué es lo que PTick rastrea?

(No encuentro nada en la documentación de MQ).

Alain Verleyen
Alain Verleyen | 2 ene 2026 en 15:38

The pursuit of reliable back-test results in algorithmic trading hinges not only on robust strategy logic but also on the efficiency and precision of the underlying code. Raw code optimization and tweaking are critical to ensuring that Expert Advisors (EAs) perform as intended, minimizing computational overhead while maximizing execution accuracy. Poorly optimized code can distort back-test outcomes through delayed order execution, incorrect signal detection, or resource exhaustion—issues that mask a strategy’s true potential.

Durante el proceso de desarrollo de la estrategia, daremos varios pasos clave para asegurarnos de que el EA es funcionalmente fuerte y técnicamente sólido. Empezaremos añadiendo funciones de ayuda personalizadas y bloques lógicos reutilizables para agilizar las operaciones y evitar el código repetitivo. A continuación, introduciremos variables y constantes bien estructuradas que mejoren la legibilidad del código y simplifiquen los ajustes de parámetros. Estos ajustes fundamentales ayudarán a mantener el código y mejorarán el tiempo de ejecución general durante cargas de backtest pesadas o pruebas multisímbolo.

Otro aspecto importante de la mejora es el aprovechamiento más eficaz de los indicadores técnicos. En lugar de calcular ciegamente los indicadores en cada tick o barra, implementaremos una lógica de actualización más inteligente para reducir la carga y el retardo. También experimentaremos con diferentes combinaciones de indicadores para apoyar una mejor toma de decisiones en la lógica del EA. Combinando el refinamiento estructural del código, las funciones que tienen en cuenta el rendimiento y la optimización de los indicadores, podemos mejorar drásticamente tanto la calidad como la velocidad de las pruebas retrospectivas, lo que nos acercará a una estrategia rentable y desplegable de forma consistente.

No quiero ofender a nadie, aunque tengo que decir que este artículo es un fracaso. Aquí arriba está la introducción, con un montón de afirmaciones fuertes y , todo lo cual el autor no logró poner en práctica.

Mi intención inicial era mostrar los problemas con el código, pero son tantos... así que me limitaré al punto 2.

   double sl_distance = StopLoss * point;
   double tp_distance = TakeProfit * point;
   
   double sl = (tradeType == ORDER_TYPE_BUY) ? price - sl_distance :
                                               price + sl_distance;
   
   double tp = (tradeType == ORDER_TYPE_BUY) ? price + tp_distance :
                                               price - tp_distance;

   trade.PositionOpen(_Symbol, tradeType, In_Lot, price, sl, tp, NULL);

¿Código robusto? ¿Dónde se comprueban los errores? Las entradas se utilizan tal cual sin ninguna comprobación, no se comprueban los stoplevels, no se comprueban los márgenes, no se comprueban las solicitudes de negociación...

      // Comprobar patrón alcista
      for (int j = i; j >= i - min_bullish_count + 1; j--) {
         if (iClose(symbol, timeframe, j) > iOpen(symbol, timeframe, j)) {
            bullish_count++;
            first_bullish_low = getLow(5);
         } else break;
      }

¿Rendimiento? ¿Usando iClose/iOpen vela por vela? Estas funciones son las más lentas para manejar datos.

Adicionalmente el getLow(5) parece un bug. No he comprobado más.

No voy a comentar sobre el algoritmo de trading en sí, sólo noté cómo el autor seleccionó convenientemente un corto período en la historia donde el EA da buenos resultados.

Este artículo es muy pobre.

Algoritmo basado en fractales — Fractal-Based Algorithm (FBA) Algoritmo basado en fractales — Fractal-Based Algorithm (FBA)
Hoy veremos un nuevo método metaheurístico basado en un enfoque fractal que permite particionar el espacio de búsqueda para resolver problemas de optimización. El algoritmo identifica y separa secuencialmente las áreas prometedoras, creando una estructura fractal autosimilar que concentra los recursos computacionales en las áreas más prometedoras. El mecanismo de mutación único orientado a las mejores soluciones garantiza un equilibrio óptimo entre la exploración y la explotación del espacio de búsqueda, aumentando significativamente la eficiencia del algoritmo.
Del básico al intermedio: Objetos (II) Del básico al intermedio: Objetos (II)
En este artículo, veremos cómo controlar, de forma simple, vía código, algunas propiedades de objetos. Veremos cómo podemos colocar más de un objeto en un mismo gráfico, usando, para esto, una aplicación. Y, además, empezaremos a ver la importancia de definir un nombre corto para todo y cualquier indicador que vayamos a implementar.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
El componente View para tablas en el paradigma MQL5 MVC: Elemento gráfico base El componente View para tablas en el paradigma MQL5 MVC: Elemento gráfico base
El artículo trata sobre el proceso de desarrollo de un elemento gráfico básico para el componente View como parte de la implementación de tablas en el paradigma MVC (Modelo-Vista-Controlador) en MQL5. Este es el primer artículo sobre el componente View y el tercero de una serie de artículos sobre la creación de tablas para el terminal cliente MetaTrader 5.