English Русский 中文 Deutsch 日本語
preview
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 5): Reglas de negociación autoadaptativas

Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 5): Reglas de negociación autoadaptativas

MetaTrader 5Ejemplos |
58 0
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

Los indicadores técnicos se han convertido en una herramienta indispensable en la mayoría de las aplicaciones de trading algorítmico debido a las señales de trading bien definidas que ofrecen, lo que permite un rápido desarrollo de las aplicaciones. Lamentablemente, es común que los operadores se encuentren enfrentando condiciones de mercado adversas que se desvían de las reglas estandarizadas sobre cómo usar cualquier indicador técnico. 

Por ejemplo, el Indicador de Fuerza Relativa (Relative Strength Indicator, RSI) se utiliza para medir la magnitud de las variaciones en los niveles de precios en un mercado determinado. Se reconoce ampliamente como buena práctica que los operadores deben establecer sus entradas de compra cuando el RSI arroja lecturas inferiores a 30 y entradas de venta cuando se observan lecturas del RSI superiores a 70. 

En la figura 1, a continuación, hemos aplicado un RSI de 20 períodos al precio diario del oro en dólares estadounidenses. El lector podrá observar que ninguna de las lecturas esperadas se mantuvo durante un período prolongado de 3 meses. Podemos observar, al analizar la línea de tendencia trazada en el gráfico, que desde septiembre de 2019 hasta diciembre de 2019, el precio del oro estuvo en una fuerte tendencia bajista.

Sin embargo, si el lector presta más atención, notará que durante este período de tendencia bajista, nuestro indicador RSI no produjo las señales esperadas para entrar en una posición corta.

Captura de pantalla 1

Figura 1: Es posible que las condiciones del mercado no produzcan la lectura esperada de un indicador técnico, lo que conduce a un comportamiento no deseado.

Algunos lectores podrían argumentar que "puedes intentar ajustar tu período en consecuencia y obtendrás el resultado estandarizado". Sin embargo, ajustar el período no siempre es una solución válida. Por ejemplo, los miembros de nuestra comunidad interesados en el análisis de múltiples símbolos pueden tener períodos específicos que mejor revelen el patrón transversal del mercado que buscan y, por lo tanto, la necesidad de mantener sus períodos fijos.

Además, los lectores que operan en un solo mercado a la vez deben tener en cuenta que aumentar el período del RSI empeorará el problema. Asimismo, disminuir el período del RSI capta más ruido del mercado y reduce la calidad general de las señales de negociación.

En resumen, abordar este problema de forma superficial puede provocar un comportamiento no deseado de las aplicaciones de negociación, lo que resultaría en la pérdida de beneficios por oportunidades no aprovechadas o una exposición al mercado mayor de la esperada, debido a que las condiciones de salida no se cumplen por completo.


Descripción general de la metodología

Es evidente que necesitamos diseñar aplicaciones de manera que les permitan adaptar sus reglas de negociación a los datos históricos disponibles. Analizaremos en detalle nuestra solución propuesta en las siguientes secciones de este artículo. Por ahora, nuestra solución propuesta se puede resumir mejor argumentando que, para saber qué es un movimiento fuerte, primero hay que saber cómo es un movimiento promedio en ese mercado en particular. De esta forma, el lector puede configurar sus aplicaciones para que solo tomen señales de entrada que estén por encima del promedio, o mejor aún, ser más específico y seleccionar movimientos que estén 2 o 3 veces por encima del promedio. 

Al configurar nuestras señales de negociación para que se decidan en relación con el tamaño de un movimiento promedio, eliminaremos de manera efectiva la posibilidad de pasar largos períodos de tiempo sin recibir una señal de negociación y, con suerte, eliminaremos la necesidad de optimizar sin cesar el período de cálculo del RSI. 


Introducción a MQL5

Nuestra exploración comienza estableciendo un nivel de rendimiento de referencia utilizando el probador de estrategias de MetaTrader 5. Nuestra estrategia se utilizará como andamiaje que el lector deberá reemplazar con sus propias estrategias de negociación. Desarrollaremos una estrategia en MQL5 que opere con rupturas de niveles clave de soporte o resistencia. Nuestro RSI nos confirmará que el nivel se ha superado con éxito. Ajustaremos el tamaño de nuestros límites de Stop Loss y Take Profit en todas las versiones de la aplicación para garantizar que los cambios en la rentabilidad provengan directamente de nuestras mejores decisiones. 

Existen diversas definiciones de lo que constituye un nivel válido de soporte o resistencia. Pero para nuestros fines, nos bastará con saber que un nivel de soporte es un nivel de precio bajo que generó un repunte en la acción del precio. Y, a la inversa, los niveles de resistencia son niveles de precios de interés que produjeron una fuerte tendencia bajista en nuestros gráficos. La duración exacta en que estos niveles se mantendrán válidos no se conoce al comienzo de ninguna sesión de negociación. 

Cuando se supera cualquiera de estos niveles, normalmente le sigue una fluctuación de precios muy volátil. Nuestro RSI nos servirá de guía para decidir si debemos realizar una operación cuando se produzca la ruptura observada. Buscamos oportunidades para entrar en posiciones largas cuando los niveles de precios hayan caído por debajo de los niveles de soporte clave, y solo tomar posiciones cortas si ocurre lo contrario en el nivel de resistencia.

Nuestros niveles de soporte y resistencia se encontrarán comparando los niveles de precios actuales con sus respectivos niveles de hace 5 días. 

Captura de pantalla 2

Figura 2: Visualización de los niveles de soporte y resistencia en el XAGUSD.

Algunos parámetros de nuestra discusión permanecerán fijos. Por lo tanto, para evitar la duplicación innecesaria de la misma información, analizaremos aquí estos parámetros fijos. Nuestro análisis se centrará en las rupturas de los niveles de soporte y resistencia, en el precio diario de la plata en dólares estadounidenses (XAGUSD). Probaremos nuestra estrategia con datos históricos de M15 desde el 1 de enero de 2017 hasta el 28 de enero de 2025.

Captura de pantalla 3

Figura 3: El período de tiempo que utilizaremos para nuestras pruebas retrospectivas.

Además, utilizaremos la configuración de "Retraso aleatorio" durante nuestra prueba retrospectiva, ya que esto es similar a la experiencia de operar en operaciones reales. Y hemos seleccionado "Cada tick basado en ticks reales" para realizar nuestras pruebas con datos de mercado reales, obtenidos de nuestro corredor.

Captura de pantalla 4

Figura 4: El segundo lote de ajustes fijos en nuestra prueba retrospectiva de hoy.

Una vez aclarado esto, ahora podemos centrar nuestra atención en la construcción de nuestra aplicación básica utilizando MQL5. Comenzaremos definiendo las constantes críticas del sistema que no se alterarán durante nuestra conversación. Estas constantes del sistema definen parámetros que controlan el comportamiento de nuestra aplicación de negociación, como la amplitud que deben tener el stop loss y el take profit, los marcos temporales que se deben utilizar y el tamaño de cada posición que tomamos, por nombrar solo algunas funciones.

//+------------------------------------------------------------------+
//|                                  Self Adapting Trading Rules.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
#define RSI_PERIOD 10              //The period for our RSI indicator
#define RSI_PRICE  PRICE_CLOSE     //The price level our RSI should be applied to
#define ATR_SIZE   1.5             //How wide should our Stop loss be?
#define ATR_PERIOD 14              //The period of calculation for our ATR indicator
#define TF_1       PERIOD_D1       //The primary time frame for our trading application
#define TF_2       PERIOD_M15      //The secondary time frame for our trading application
#define VOL        0.1             //Our trading volume   

Ahora importaremos la biblioteca de operaciones para ayudarnos a gestionar nuestras posiciones.

//+------------------------------------------------------------------+
//| Libraries we need                                                |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

A continuación, debemos definir algunas variables globales importantes.

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int rsi_handler,atr_handler;
double rsi[],atr[];
double support,resistance;

Nuestras aplicaciones MetaTrader 5 se basan principalmente en eventos que tienen lugar en nuestro terminal. Hemos creado métodos personalizados que se activarán, por turno, cuando se desencadene cada evento del terminal.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

Cuando nuestro indicador se cargue por primera vez, configuraremos nuestros indicadores técnicos y luego estableceremos nuestros niveles de soporte y resistencia en los niveles de precios más altos y más bajos que observamos la semana anterior.

//+------------------------------------------------------------------+
//| User defined methods                                             |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Initialize our system variables                                  |
//+------------------------------------------------------------------+
void setup(void)
  {
//Load our technical indicators
   atr_handler = iATR(Symbol(),TF_1,ATR_PERIOD);
   rsi_handler = iRSI(Symbol(),TF_2,RSI_PERIOD,RSI_PRICE);
   resistance  = iHigh(Symbol(),TF_1,5);
   support     = iLow(Symbol(),TF_1,5);
  }

Si nuestra aplicación de negociación ya no está en uso, debemos liberar los indicadores técnicos que ya no utilizamos.

//+------------------------------------------------------------------+
//| Let go of resources we are no longer consuming                   |
//+------------------------------------------------------------------+
void release(void)
  {
//Free up resources we are not using
   IndicatorRelease(atr_handler);
   IndicatorRelease(rsi_handler);
  }

Nuestra función de actualización se divide en 2 partes. La primera mitad se encarga de las tareas rutinarias que deben realizarse una vez al día, mientras que la segunda mitad se encarga de las tareas que deben realizarse con mayor frecuencia en un plazo más corto. Esto nos asegura que seremos sorprendidos por un comportamiento abrupto o anormal del mercado. 

//+------------------------------------------------------------------+
//| Update our system variables and look for trading setups          |
//+------------------------------------------------------------------+
void update(void)
  {
//Update our system variables
//Some duties must be performed periodically on the higher time frame
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_1,0);

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;

         //Update indicator readings
         CopyBuffer(rsi_handler,0,0,1,rsi);
         CopyBuffer(atr_handler,0,0,1,atr);

         //Update our support and resistance levels
         support    = iLow(Symbol(),TF_1,5);
         resistance = iHigh(Symbol(),TF_1,5);
         ObjectDelete(0,"Support");
         ObjectDelete(0,"Resistance");
         ObjectCreate(0,"Suppoprt",OBJ_HLINE,0,0,support);
         ObjectCreate(0,"Resistance",OBJ_HLINE,0,0,resistance);
        }
     }

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;   
                  
      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);
         
         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
            {
               //We are looking for opportunities to sell
               if(iLow(Symbol(),TF_2,0) > resistance)
                  {
                     if(rsi[0] > 70) Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
                  }
              
              //We are looking for opportunities to buy
              if(iHigh(Symbol(),TF_2,0) < support)
                  {
                     if(rsi[0] < 30) Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
                  }
            }
         }      
        }
     }

Por último, debemos desdefinir las constantes del sistema que definimos al comienzo de la aplicación.

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
//+------------------------------------------------------------------+

En conjunto, este es el aspecto que tiene nuestra base de código actual.

//+------------------------------------------------------------------+
//|                                  Self Adapting Trading Rules.mq5 |
//|                                               Gamuchirai Ndawana |
//|                    https://www.mql5.com/en/users/gamuchiraindawa |
//+------------------------------------------------------------------+
#property copyright "Gamuchirai Ndawana"
#property link      "https://www.mql5.com/en/users/gamuchiraindawa"
#property version   "1.00"

//+------------------------------------------------------------------+
//| System constants                                                 |
//+------------------------------------------------------------------+
#define RSI_PERIOD 10            //The period for our RSI indicator
#define RSI_PRICE  PRICE_CLOSE   //The price level our RSI should be applied to
#define ATR_SIZE   1.5             //How wide should our Stop loss be?
#define ATR_PERIOD 14            //The period of calculation for our ATR indicator
#define TF_1       PERIOD_D1     //The primary time frame for our trading application
#define TF_2       PERIOD_M15    //The secondary time frame for our trading application
#define VOL        0.1           //Our trading volume   

//+------------------------------------------------------------------+
//| Libraries we need                                                |
//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
CTrade Trade;

//+------------------------------------------------------------------+
//| Global variables                                                 |
//+------------------------------------------------------------------+
int rsi_handler,atr_handler;
double rsi[],atr[];
double support,resistance;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   setup();
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   release();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   update();
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| User defined methods                                             |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Initialize our system variables                                  |
//+------------------------------------------------------------------+
void setup(void)
  {
//Load our technical indicators
   atr_handler = iATR(Symbol(),TF_1,ATR_PERIOD);
   rsi_handler = iRSI(Symbol(),TF_2,RSI_PERIOD,RSI_PRICE);
   resistance  = iHigh(Symbol(),TF_1,5);
   support     = iLow(Symbol(),TF_1,5);
  }

//+------------------------------------------------------------------+
//| Let go of resources we are no longer consuming                   |
//+------------------------------------------------------------------+
void release(void)
  {
//Free up resources we are not using
   IndicatorRelease(atr_handler);
   IndicatorRelease(rsi_handler);
  }

//+------------------------------------------------------------------+
//| Update our system variables and look for trading setups          |
//+------------------------------------------------------------------+
void update(void)
  {
//Update our system variables
//Some duties must be performed periodically on the higher time frame
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_1,0);

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;

         //Update indicator readings
         CopyBuffer(rsi_handler,0,0,1,rsi);
         CopyBuffer(atr_handler,0,0,1,atr);

         //Update our support and resistance levels
         support    = iLow(Symbol(),TF_1,5);
         resistance = iHigh(Symbol(),TF_1,5);
         ObjectDelete(0,"Support");
         ObjectDelete(0,"Resistance");
         ObjectCreate(0,"Suppoprt",OBJ_HLINE,0,0,support);
         ObjectCreate(0,"Resistance",OBJ_HLINE,0,0,resistance);
        }
     }

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);

         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
           {
            //We are looking for opportunities to sell
            if(iLow(Symbol(),TF_2,0) > resistance)
              {
               if(rsi[0] > 70)
                  Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
              }

            //We are looking for opportunities to buy
            if(iHigh(Symbol(),TF_2,0) < support)
              {
               if(rsi[0] < 30)
                  Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
//+------------------------------------------------------------------+

Analicemos ahora el rendimiento de este algoritmo con datos históricos del mercado. Inicie su terminal MetaTrader 5 y seleccione la aplicación que acabamos de desarrollar juntos. Recuerda que las fechas y configuraciones de las pruebas se te proporcionan al principio de esta sección del artículo.

Captura de pantalla 5

Figura 5: Inicio de nuestra prueba retrospectiva en MetaTrader 5.

Nuestro asesor experto no tiene parámetros de entrada; una vez que haya cargado la aplicación y configurado las fechas de prueba correspondientes, inicie el Probador de estrategias de MetaTrader 5. La figura 6, a continuación, es la curva de capital producida al seguir las reglas de negociación clásicas construidas para el RSI. 

Captura de pantalla 6

Figura 6: La curva de capital obtenida al seguir la estrategia clásica de negociación RSI.

La figura 7 nos proporciona un resumen detallado de cómo se comportó nuestra aplicación de negociación basada en RSI en la primera prueba. Nuestro beneficio neto total fue de 588,60 dólares con un ratio de Sharpe de 0,85. Estos resultados son alentadores hasta el momento y servirán como objetivo para superarlos en la próxima versión de nuestra aplicación de negociación.

Captura de pantalla 7

Figura 7: Resumen detallado de los resultados obtenidos en nuestra prueba retrospectiva.



Mejorando nuestros resultados iniciales

Ahora hemos llegado a la solución propuesta que aborda los posibles problemas derivados de los resultados no estándar del indicador. Para sustituir los niveles clásicos 70 y 30 por niveles óptimos seleccionados directamente a partir del rendimiento histórico del mercado, primero debemos observar el rango de resultados que genera el indicador en el mercado en cuestión. A continuación, dividiremos en dos partes iguales las dos líneas paralelas que marcan la salida máxima y mínima generada por el indicador. Esta línea bisectriz se convierte en nuestro nuevo punto medio. Tenga en cuenta que, originalmente, el punto medio del indicador RSI es el nivel 50.

Una vez calculado nuestro nuevo punto medio, registraremos la diferencia absoluta de cada lectura del RSI con respecto al punto medio del indicador y calcularemos la media para obtener nuestra estimación del movimiento medio en ese mercado concreto. Posteriormente, daremos instrucciones a nuestra aplicación de negociación para que solo introduzca sus posiciones si observa un cambio en el valor del RSI dos veces superior al movimiento medio en ese mercado. Este nuevo parámetro nos permite controlar la sensibilidad de nuestra aplicación de trading, pero si seleccionamos valores demasiado altos, como 100, nuestra aplicación no realizará ninguna operación, nunca.

Para implementar estos cambios en nuestra aplicación, debemos realizar los siguientes cambios:

Cambio propuesto Propósito previsto
Creación de nuevas constantes del sistema Estas nuevas constantes del sistema corregirán la mayoría de los parámetros de la versión inicial de la aplicación, al tiempo que introducirán algunos nuevos que necesitamos.
Modificación de nuestros métodos definidos por el usuario Las funciones personalizadas que escribimos anteriormente necesitan ser ampliadas para proporcionar la nueva funcionalidad que deseamos.

Para empezar, vamos a crear primero las nuevas constantes del sistema que necesitamos. Necesitamos decidir dinámicamente cuántas barras se deben usar en los cálculos que queremos realizar. Esta será la responsabilidad de la nueva constante del sistema denominada "BARS". Devolverá un número entero cercano a la mitad del número total de barras disponibles. Además, también hemos decidido que solo nos interesan los cambios en el RSI que sean 2 veces mayores que el promedio. Por lo tanto, hemos creado una nueva constante llamada "BIG SIZE" que registra la fuerza que pretendemos observar detrás de nuestros movimientos.

Por último, nuestros niveles de soporte y resistencia se encontrarán comparando el precio actual con su valor de hace una semana o de hace 5 días.

//+---------------------------------------------------------------+
//| System constants                                              |
//+---------------------------------------------------------------+
#define RSI_PERIOD     10                                          //The period for our RSI indicator
#define RSI_PRICE      PRICE_CLOSE                                 //The price level our RSI should be applied to
#define ATR_SIZE       1.5                                         //How wide should our Stop loss be?
#define ATR_PERIOD     14                                          //The period of calculation for our ATR indicator
#define TF_1           PERIOD_D1                                   //The primary time frame for our trading application
#define TF_2           PERIOD_M15                                  //The secondary time frame for our trading application
#define VOL            0.1                                         //Our trading volume   
#define BARS           (int) MathFloor((iBars(Symbol(),TF_2) / 2)) //How many bars should we use for our calculation?
#define BIG_SIZE       2                                           //How many times bigger than the average move should the observed change be?
#define SUPPORT_PERIOD 5                                           //How far back into the past should we look to find our support and resistance levels?

Ahora modificaremos las condiciones que definen si abriremos nuestras posiciones. Observe que ya no colocamos nuestras entradas en niveles de indicadores fijos, sino en niveles calculados, que se derivan del búfer de memoria del indicador.

//While other duties need more attention, and must be handled on lower time frames.
     {
      static datetime time_stamp;
      datetime current_time = iTime(Symbol(),TF_2,0);
      double bid,ask;

      //Update the time
      if(time_stamp != current_time)
        {
         time_stamp = current_time;
         bid=SymbolInfoDouble(Symbol(),SYMBOL_BID);
         ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK);

         //Copy the rsi readings into a vector
         vector rsi_vector   = vector::Zeros(BARS);
         rsi_vector.CopyIndicatorBuffer(rsi_handler,0,1,BARS);

         //Let's see how far the RSI tends to deviate from its centre
         double rsi_midpoint = ((rsi_vector.Max() + rsi_vector.Min()) / 2);
         vector rsi_growth   = MathAbs(rsi_vector - rsi_midpoint);

         //Check if we have broken either extreme
         if(PositionsTotal() == 0)
           {
            //We are looking for opportunities to sell
            if(iLow(Symbol(),TF_2,0) > resistance)
              {
               if((rsi[0] - rsi_midpoint) > (rsi_growth.Mean() * BIG_SIZE))
                  Trade.Sell(VOL,Symbol(),bid,(ask + (ATR_SIZE * atr[0])),(ask - (ATR_SIZE * atr[0])));
              }

            //We are looking for opportunities to buy
            if(iHigh(Symbol(),TF_2,0) < support)
              {
               if((rsi[0] - rsi_midpoint) < (-(rsi_growth.Mean() * BIG_SIZE)))
                  Trade.Buy(VOL,Symbol(),ask,(bid - (ATR_SIZE * atr[0])),(bid + (ATR_SIZE * atr[0])));
              }
           }
        }
     }

Por último, debemos deshacer la definición de las nuevas constantes del sistema que hemos creado.

//+------------------------------------------------------------------+
//| Undefine the system constants                                    |
//+------------------------------------------------------------------+
#undef RSI_PERIOD
#undef RSI_PRICE
#undef ATR_PERIOD
#undef ATR_SIZE
#undef TF_1
#undef TF_2
#undef VOL
#undef BARS
#undef BIG_SIZE
#undef SUPPORT_PERIOD
//+------------------------------------------------------------------+

Ya estamos listos para probar nuestras nuevas reglas de negociación dinámicas para el RSI. Asegúrese de seleccionar la versión adecuada del Asesor Experto en su probador de estrategias antes de iniciar la prueba. Recuerda que la configuración de fecha será la misma que la que indicamos en la introducción del artículo.

Captura de pantalla 8

Figura 8: Seleccione la versión correcta de la aplicación de negociación para nuestra prueba.

La curva de capital producida por nuestra nueva versión del algoritmo de negociación RSI parece similar a los resultados iniciales que obtuvimos. Sin embargo, analicemos el resumen detallado de los resultados para obtener una perspectiva clara de la diferencia que se ha logrado.

Captura de pantalla 9

Figura 9: La curva de capital generada por nuestra versión del algoritmo de negociación de reglas dinámicas.

En nuestra prueba inicial, nuestro beneficio neto total fue de 588,60 dólares, obtenidos en un total de 136 operaciones. Nuestra nueva estrategia generó una ganancia de 703,20 dólares en 121 operaciones. Por lo tanto, nuestra rentabilidad ha aumentado aproximadamente un 19,5%, mientras que, por otro lado, el número total de operaciones que realizamos disminuyó alrededor de un 11%. Es evidente que nuestro nuevo sistema nos proporciona una clara ventaja competitiva sobre las reglas clásicas que definen cómo deberíamos utilizar normalmente el indicador. 

Captura de pantalla 10

Figura 10: Resultados detallados que resumen el rendimiento de nuestra nueva estrategia de negociación.



Conclusión

La solución que hemos explorado hoy le ha proporcionado un patrón de diseño sobre cómo utilizar su terminal MetaTrader 5 para obtener un nivel de control refinado sobre la sensibilidad de sus aplicaciones de negociación. Los operadores que analizan múltiples símbolos se beneficiarán de una nueva perspectiva sobre cómo comparar la magnitud de los cambios en los niveles de precios en diferentes mercados de una manera objetiva y bien pensada, eliminando las posibilidades de errores involuntarios que puedan fácilmente frustrar sus esfuerzos.

Además, nuestro algoritmo propuesto para sustituir cuidadosamente los niveles clásicos de 30 y 70 por niveles óptimos seleccionados directamente del rango observado del indicador cuando se aplica a cualquier mercado en particular puede darnos una ventaja material sobre los participantes ocasionales del mercado que esperan a que se observe el resultado estandarizado. 

Archivo adjunto Descripción
Self Adapting Trading Rules Versión de referencia de nuestra aplicación de negociación con reglas estáticas y fijas.
Self Adapting Trading Rules V2 Versión mejorada de nuestra aplicación de trading que adapta sus reglas en función de los datos de mercado disponibles.

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

Aprendizaje automático y Data Science (Parte 33): Pandas Dataframe en MQL5, recopilación de datos para facilitar el uso de ML Aprendizaje automático y Data Science (Parte 33): Pandas Dataframe en MQL5, recopilación de datos para facilitar el uso de ML
Cuando se trabaja con modelos de aprendizaje automático, es esencial garantizar la coherencia de los datos utilizados para el entrenamiento, la validación y las pruebas. En este artículo, crearemos nuestra propia versión de la biblioteca Pandas en MQL5 para garantizar un enfoque unificado para el manejo de datos de aprendizaje automático, con el fin de asegurar que se apliquen los mismos datos dentro y fuera de MQL5, donde se lleva a cabo la mayor parte del entrenamiento.
Optimización con el juego del caos — Game Optimization (CGO) Optimización con el juego del caos — Game Optimization (CGO)
Hoy presentamos el nuevo algoritmo metaheurístico de Chaos Game Optimisation (CGO), que demuestra una capacidad única para mantener una alta eficiencia al trabajar con problemas de alta dimensionalidad. A diferencia de la mayoría de los algoritmos de optimización, el CGO no solo no pierde rendimiento, sino que a veces incluso lo aumenta cuando se escala el problema, lo cual supone su característica clave.
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.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 10): Flujo externo (II) VWAP Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 10): Flujo externo (II) VWAP
¡Domina el poder del VWAP con nuestra guía completa! Aprenda a integrar el análisis VWAP en su estrategia de trading utilizando MQL5 y Python. Maximice su conocimiento del mercado y mejore sus decisiones comerciales hoy mismo.