Optimización separada de una estrategia en condiciones de tendencia y flat

Alexander Fedosov | 27 marzo, 2019

Contenido


Introducción

No es un secreto que, a la hora de desarrollar estrategias comerciales, en la etapa inicial surge la necesidad de formular las condiciones de entrada en el mercado, el método de acompañamiento de posiciones y el momento de salida. Para ello, se usan diferentes métodos (matemáticos, estadísticos y otros) de evaluación del mercado, así como sistemas automáticos preparados, que se utilizan para dar una caracterización valorativa del mercado en forma de indicadores. Uno de los principales problemas al construir cualquier estrategia comercial es la ausencia de universalidad. Un sistema comercial no puede ser igualmente efectivo en todos los posibles estados del mercado. Por eso, normalmente, al crear expertos comerciales, se eligen unas ciertas condiciones para la detección de determinados estados del mercado, con la ayuda de las cuales se planea lograr beneficios. 

También sabemos todos que cada sistema comercial tiene sus defectos. Así, las estrategias de tendencia comienzan a funcionar mal en los estados de mercado de flat o laterales, o en los estados en los que el mercado está tranquilo, mientras que las estrategias de flat dan entradas falsas en los movimientos fuertes, etcétera. Para reducir el efecto de señales falsas y mejorar la rentabilidad, los sistemas se hacen flexibles, es decir, poseen un cierto conjunto de ajustes o datos de entrada configurables, lo cual se ve totalmente justificado por el hecho de que el mercado y sus características específicas cambien constantemente.

Con el tiempo, cualquier sistema se vuelve menos efectivo, por lo que se hace necesario adaptar sus parámetros a las nuevas realidades. Para ello, en la plataforma comercial MetaTrader 5 existe el Simulador de Estrategias. Se trata de una herramienta que ayuda a analizar con la historia del mercado la funcionalidad de cualquier experto comercial, y también a determinar los ajustes óptimos para su posterior uso como base en el comercio real.


El concepto de Optimización Separada

En este artículo proponemos estudiar el uso del Simulador de Estrategias en un sentido más amplio. Resulta obvio que la mayoría de sistemas del mercado comercia en dos direcciones, es decir, compran en determinadas condiciones, y venden en otras. En la fig.1 se representa un sencillo ejemplo del funcionamiento de una estrategia comercial en acción en condiciones ideales. Su esencia es simple: compramos a un precio bajo y vendemos a un precio alto.


Fig.1 Esquema de funcionamiento de una estrategia comercial de tendencia.

Está claro que para determinar una tendencia ascendente o descendente en un sistema así, se usa el mismo conjunto de ajustes, mientras que las condiciones de entrada son inversas unas con respecto a otras. Pero la cuestión es que las especificidades del crecimiento y caída pueden ser muy diferentes en muchas características, por ejemplo, en cuanto a velocidad y duración. Por este motivo, proponemos analizar la opción de un sistema que define de forma separada la entrada en el mercado con tendencia ascendente y descendente.

Para ello, necesitaremos dos conjuntos de parámetros que determinen las condiciones de entrada y salida del mercado. Y aquí nos acercamos ya al propio concepto de "optimización separada".

La optimización separada consiste en definir los parámetros ideales de un sistema comercial con la ayuda del Simulador de Estrategias de manera separada para la tendencia ascendente y descendente.

Para simular la optimización separada, hemos decidido elegir dos sistemas comerciales: uno de tendencia y otro de flat. En el de tendencia vamos a optimizar por separado las tendencias ascendentes y descendentes, y para el de flat, valoraremos la optimización separada de comercio en el canal. 


Eligiendo una estrategia comercial de tendencia

Como estrategia a usar en la simulación de la optimización separada, hemos elegido el uso del indicador Centro de Gravedad de Ehlers, representado en forma de histograma OSMA — CenterOfGravityOSMA. Su señal será confirmada por un indicador que calculará la velocidad media del precio (Average Speed).

ParámetroDescripción
Indicador utilizadoCenterOfGravityOSMA
Indicador utilizadoAverage Speed
Marco temporalH1
Condiciones de compraEl histograma Centro de Gravedad muestra un crecimiento (en este caso, además, el valor del indicador es inferior a cero), y el valor de Average Speed es superior al valor umbral (establecido inicialmente en los ajustes)
Condiciones de ventaEl histograma Centro de Gravedad muestra una caída (en este caso, además, el valor del indicador es superior a cero), y el valor de Average Speed es superior al valor umbral (establecido inicialmente en los ajustes)
Condiciones de salida  Take-profit/Stop-loss

Mostramos la estrategia de forma visual en la fig.2. Como podemos ver por el recuadro, en la estraegia comercial existen condiciones claramente definidas para la entrada en el mercado al comprar o vender. Dado que es una estrategia de tendencia, las condicones de compra se corresponderán con la tendencia ascendente, mientras que las condiciones de venta se corresponderán con la tendencia descendente. 

Fig.2 Condiciones de entrada según la estrategia de tendencia.

Al realizar la implementación de forma programática en el MetaEditor, debemos indicar las condiciones de funcionamiento del experto de tal forma que, si así lo deseáramos, pudiéramos usarlo solo en tendencia ascendente, solo en tendencia descendente o en ambas situaciones. 

Asimismo, debemos considerar lo siguiente:

  • La posibilidad de gestionar los modos de simulación para la tendencia ascendente, descendente y el funcionamiento conjunto.
  • Para la optimización separada será necesario usar un experto separadamente para la tendencia ascendente y descendente, así como para el trabajo conjunto;
  • Para los modos ascendente y descendente, deberán existir sus propios conjuntos de parámetros. Esto es necesario para usarlos en el comercio conjunto, pero con diferentes conjuntos de parámetros optimizados;

Para cumplir estas condiciones de creación del experto comercial, introduciremos el código siguiente:

//+------------------------------------------------------------------+
//| Enumeración de los modos de trabajo                              |
//+------------------------------------------------------------------+
enum Trend_type
  {
   UPTREND = 1,            //Uptrend       
   DOWNTREND,              //Downtrend
   BOTH                    //Both trends
  };

El conjunto de parámetros de entrada tiene el aspecto siguiente:

//+------------------------------------------------------------------+
//| Parámetros de entrada del experto                                |
//+------------------------------------------------------------------+
input string               Inp_EaComment="Trend Strategy";              //EA Comment
input double               Inp_Lot=0.01;                                //Lot
input MarginMode           Inp_MMode=LOT;                               //MM

input Trend_type           Inp_Trend_type=3;                            //Trend type
//--- Uptrend parameters
input string               Inp_Str_label1="===Uptrend parameters===";   //Label
input int                  Inp_MagicNum1=1111;                          //Magic number
input int                  Inp_StopLoss1=40;                            //Stop Loss(points)
input int                  Inp_TakeProfit1=60;                          //Take Profit(points)

//--- Parámetros del indicador CenterOfGravityOSMA
input uint                 Period_1=9;                                  //Averaging period
input uint                 SmoothPeriod1_1=3;                           //Smoothing period1
input ENUM_MA_METHOD       MA_Method_1_1=MODE_SMA;                      //Averaging method1
input uint                 SmoothPeriod2_1=3;                           //Smoothing period2
input ENUM_MA_METHOD       MA_Method_2_1=MODE_SMA;                      //Averaging method2
input Applied_price_       AppliedPrice1=PRICE_OPEN_;                   //Applied price

//--- Parámetros del indicador Average Speed
input int                  Inp_Bars1=1;                                 //Days
input ENUM_APPLIED_PRICE   Price1=PRICE_CLOSE;                          //Applied price
input double               Trend_lev1=2;                                //Trend Level

//--- Downtrend parameters
input string               Inp_Str_label2="===Downtrend parameters==="; //Label
input int                  Inp_MagicNum2=2222;                          //Magic number
input int                  Inp_StopLoss2=40;                            //Stop Loss(points)
input int                  Inp_TakeProfit2=60;                          //Take Profit(points)

//--- Parámetros del indicador CenterOfGravityOSMA
input uint                 Period_2=9;                                  //Averaging period
input uint                 SmoothPeriod1_2=3;                           //Smoothing period1
input ENUM_MA_METHOD       MA_Method_1_2=MODE_SMA;                      //Averaging method1
input uint                 SmoothPeriod2_2=3;                           //Smoothing period2
input ENUM_MA_METHOD       MA_Method_2_2=MODE_SMA;                      //Averaging method2
input Applied_price_       AppliedPrice2=PRICE_OPEN_;                   //Applied price

//--- Parámetros del indicador Average Speed
input int                  Inp_Bars2=1;                                 //Days
input ENUM_APPLIED_PRICE   Price2=PRICE_CLOSE;                          //Applied price
input double               Trend_lev2=2;                                //Trend Level

Como podemos ver por el código, la variable Inp_Trend_type se encarga de elegir el modo de funcionamiento del experto comercial, mientras que los parámetros de entrada para los modos Uptrend y Downtrend se dividen respectivamente en Uptrend parameters y Downtrend parameters. Conviene destacar que, al elegir el modo Both, los parámetros de entrada se usarán de ambos apartados.

El código principal de la implementación se muestra en la lista siguiente:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Obteniendo los datos para el cálculo

   if(!GetIndValue())
      return;

   if(Inp_Trend_type==1 && !Trade.IsOpenedByMagic(Inp_MagicNum1))
     {
      //--- Abriendo orden al darse la señal de compra
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
     }
   else if(Inp_Trend_type==2 && !Trade.IsOpenedByMagic(Inp_MagicNum2))
     {
      //--- Abriendo orden al darse la señal de venta
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);
     }
   else if(Inp_Trend_type==3)
     {
      //--- Abriendo orden al darse la señal de compra
      if(BuySignal() && !Trade.IsOpenedByMagic(Inp_MagicNum1))
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
      //--- Abriendo orden al darse la señal de venta
      if(SellSignal() && !Trade.IsOpenedByMagic(Inp_MagicNum2))
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);
     }
  }
//+------------------------------------------------------------------+
//| Condiciones de compra                                            |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   return(avr_speed1[0]>Trend_lev1 && cog1[1]<cog1[0] &&(cog1[1]<0 && cog1[0]<0))?true:false;
  }
//+------------------------------------------------------------------+
//| Condiciones de venta                                             |
//+------------------------------------------------------------------+
bool SellSignal()
  {
   return(avr_speed2[0]>Trend_lev2 && cog2[1]>cog2[0] &&(cog2[1]>0 && cog2[0]>0))?true:false;
  }
//+------------------------------------------------------------------+
//| Obteniendo los valores actuales de los indicadores               |
//+------------------------------------------------------------------+
bool GetIndValue()
  {
   return(CopyBuffer(InpInd_Handle1,0,0,2,cog1)<=0 ||
          CopyBuffer(InpInd_Handle2,0,0,2,cog2)<=0 ||
          CopyBuffer(InpInd_Handle3,0,0,2,avr_speed1)<=0 ||
          CopyBuffer(InpInd_Handle4,0,0,2,avr_speed2)<=0
          )?false:true;
  }
//+------------------------------------------------------------------+

Para los modos Uptrend y Downtrend, el esquema comercial es sencillo: comprar cuando la tendencia es ascendente, y vender cuando la tendencia es descendente, es decir, seguir la tendencia. En el modo Both, podemos ver que ambos sistemas funcionan de forma conjunta, independientemente el uno del otro, con parámetros de entrada únicos — Uptrend+Downtrend.


Simulando la estrategia de tendencia

Para simular y optimizar por separado la estrategia elegida, es lógico elegir periodos claramente definidos de tendencia ascendente para el modo Uptrend y de tendencia descendente para el modo Downtrend. Por eso, hemos decidido elegir los siguientes periodos de tiempo, representados en la fig.3.

Fig.3 Periodos de tiempo elegidos para la simulación.

Bien, vamos a resumir los ajustes de simulación que hemos obtenido.

  • Intervalo: Para el modo Uptrend 10.04.2017 — 01.02.2018. Para el modo Downtrend 08.05.2014 — 13.03.2015.
  • Pareja de divisas: EURUSD.
  • Modo de comercio: Sin retrasos. Las estaretegias no se relacionan con las de alta precisión, por eso la influencia de los retrasos sería muy pequeña.
  • Simulación: OHLC en М1. La simulación preliminar con ticks reales ha resultado casi indistinguible de este modo. 
  • Depósito inicial: 1000 USD.
  • Apalancamiento: 1:500.
  • Servidor: MetaQuotes-Demo.
  • Cotizaciones: de 5 dígitos.

Los parámetros de los indicadores usados en la estragia, así como los valores de Take Profit y Stop Loss, serán el objetivo de la simulación.

Para la tendencia ascendente se han obtenido los siguientes resultados de optimización:


Fig. 4 Resultados de la simulación y la optimización de la estrategia con tendencia ascendente.

Para la tendencia descendente, hemos obtenido los siguientes resultados:


Fig. 5 Resultados de la simulación y la optimización de la estrategia con tendencia descendente.

Bien, una vez determinados los parámetros rentables con la ayuda de la optimización en los intervalos de tiempo favorables para los modos seleccionados, debemos probar estos parámetros en un intervalo mixto, que tenga tanto tendencias de movimiento ascendente, como descendente. Con ello, también pondremos a prueba la vitalidad de esta estrategia comercial. 

Hemos decidido elegir el siguiente intervalo temporal, que conviene estupendamente para las solicitudes indicadas más arriba.

Fig.6 Periodo de tiempo elegido para la simulación mixta.

Como podemos ver en la fig.6, en este intervalo temporal están presentes tanto la tendencia ascendente, como la descendente, con retrocesos y movimientos laterales. Ahora vamos ver cómo se comporta el experto comercial en un intervalo de la historia desconocido para él.

Fig.7 Resultado de la simulación de la estrategia de tendencia optimizada en un intervalo desfavorable.


Según los resultados de la simulación de la estrategia comercial de tendencia, podemos observar lo siguiente:

  • La estrategia ha mostrado un resultado positivo en el intervalo desfavorable.
  • El porcentaje de transacciones largas ha resultado de mayor calidad que el porcentaje de transacciones cortas.
  • Asimismo, los valores de Rentabilidad y Esperanza Matemática de los beneficios muestran que en este intervalo de simulación la estrategia ha comerciado en general con una dinámica positiva. 

Eligiendo una estrategia de flat

Para realizar la optimización separada en flat se ha elegido la estrategia que sigue: el rango porcentual de Williams(WPR), que determina el estado de sobrecompra/sobreventa, se usará como indicador principal de búsqueda de entradas. Como confirmación, adoptaremos el indicador de tendencia ADX, pero lo usaremos no para determinar la tendencia, sino para determinar su ausencia.

ParámetroDescripción
Indicador utilizadoWilliams Percent Range
Indicador utilizadoADX
Marco temporalH1
Condiciones de compraEl indicador WPR se encuentra en la zona de sobreventa (por debajo de -80) y el valor de ADX está por debajo del valor umbral establecido.
Condiciones de ventaEl indicador WPR se encuentra en la zona de sobrecompra (por encima de -20) y el valor de ADX está por debajo del valor umbral establecido.
Condiciones de salida  Take-profit/Stop-loss

En la fig.5 se muestra un ejemplo visual de la entrada en el mercado según esta estrategia.

Fig.6 Condiciones de entrada según la estrategia de flat.

Partiendo de la estrategia seleccionada, la optimización separada se realizará según los tipos de transacciones. Más concretamente, en los modos Buy y Sell.

//+------------------------------------------------------------------+
//| Enumeración de los modos de trabajo                              |
//+------------------------------------------------------------------+
enum Trend_type
  {
   UPTREND = 1,            //Buy       
   DOWNTREND,              //Sell
   BOTH                    //Both 
  };

De esta forma, se podrá determinar cómo se comportará la estrategia elegida en condiciones de flat. Más abajo se muestra la lista del código del experto comercial:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Obteniendo los datos para el cálculo

   if(!GetIndValue())
      return;

   if(Inp_Trend_type==1 && !Trade.IsOpenedByMagic(Inp_MagicNum1))
     {
      //--- Abriendo orden al darse la señal de compra
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
     }
   else if(Inp_Trend_type==2 && !Trade.IsOpenedByMagic(Inp_MagicNum2))
     {
      //--- Abriendo orden al darse la señal de venta
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);
     }
   else if(Inp_Trend_type==3)
     {
      //--- Abriendo orden al darse la señal de compra
      if(BuySignal() && !Trade.IsOpenedByMagic(Inp_MagicNum1))
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
      //--- Abriendo orden al darse la señal de venta
      if(SellSignal() && !Trade.IsOpenedByMagic(Inp_MagicNum2))
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);
     }
  }
//+------------------------------------------------------------------+
//| Condiciones de compra                                            |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   return(wpr1[0]<-80 && adx1[0]<Inp_FlatLevel1)?true:false;
  }
//+------------------------------------------------------------------+
//| Condiciones de venta                                             |
//+------------------------------------------------------------------+
bool SellSignal()
  {
   return(wpr2[0]>=-20 && adx2[0]<Inp_FlatLevel2)?true:false;
  }
//+------------------------------------------------------------------+
//| Obteniendo los valores actuales de los indicadores               |
//+------------------------------------------------------------------+
bool GetIndValue()
  {
   return(CopyBuffer(InpInd_Handle1,0,0,2,wpr1)<=0  ||
          CopyBuffer(InpInd_Handle2,0,0,2,wpr2)<=0 || 
          CopyBuffer(InpInd_Handle3,0,0,2,adx1)<=0  ||
          CopyBuffer(InpInd_Handle4,0,0,2,adx2)<=0
          )?false:true;
  }
//+------------------------------------------------------------------+


Simulando la estrategia de flat

Al igual que en la simulación de la estrategia de tendencia, primero elegimos un segmento de la historia para el entrenamiento y la optimización de la estrategia de flat seleccionada. En la siguiente imagen se muestra el intervalo de simulación:

Fig.7 Intervalo de simulación elegido para la estrategia de flat.

Las condiciones generales para la simulación tienen el aspecto que sigue:

Para la simulación y optimización se usarán los parámetros de los indicadores y los valores de Take Profit y Stop Loss. Los resultados de la optimización separada en el modo Buy se muestran en el recuadro de abajo.


Fig. 7 Resultados de la simulación y la optimización de la estrategia de flat en el modo Buy.

Los resultados de la optimización en el modo Sell son los siguientes.


Fig. 8 Resultados de la simulación y la optimización de la estrategia de flat en el modo Sell.

Tras determinar los mejores parámetros para ambos modos con la ayuda de la optimización separada, ha llegado el momento de comprobar la estrategia en un intervalo desfavorable y descubrir si se adapta bien a condiciones nuevas para ella. Como experimento, elegiremos un intervalo temporal del mercado que no sea de flat, y aquel que ya seleccionamos para la simulación de la estrategia de tendencia. Nos referimos al intervalo mostrado en la fig.6. Lo hemos usado para la simulación mixta de la estrategia de tendencia en el modo Both(Uptrend+Downtrend).

Bien, este es el resultado que hemos obtenido:

Fig. 9 Resultado de la simulación de la estrategia de flat optimizada en un intervalo desfavorable.

Teniendo en cuenta que la estrategia es de flat, y el intervalo de simulación tiene movimientos de tendencia prolongados, ha demostrado buenos resultados, logrando un beneficio considerable. 


Combinando las estrategias

Hemos analizado estrategias de tendencia y flat como ejemplo para la optimización separada. Ambas estretagias se han dividido en dos componentes, han sido entrenadas en mercados favorables y han sido optimizadas. Después de ello, su viabilidad ha sido comprobada en un intervalo desconocido, y los resultados han sido muy positivos. Ahora, para reforzar el tema del artículo, nos gustaría comprobar cómo se comportará una estrategia que conste de las dos mostradas más arriba, en un intervalo temporal más amplio, prestando también atención a su resultado: si podrá funcionar o no en un modo tan universal. Pero primero, debemos combinarlas en una. 

Después de implementar de forma programática la estrategia, primero se han establecido los parámetros optimizados de los dos modos de la estrategia de tendencia y los dos modos de la estrategia de flat:

//+------------------------------------------------------------------+
//| Parámetros de entrada del experto                                |
//+------------------------------------------------------------------+
input string               Inp_EaComment="Universe Strategy";           //EA Comment
input double               Inp_Lot=0.01;                                //Lot
input MarginMode           Inp_MMode=LOT;                               //MM

//--- Uptrend parameters
input string               Inp_Str_label1="===Uptrend parameters===";   //Label
input int                  Inp_MagicNum1=1111;                          //Magic number
input int                  Inp_StopLoss1=50;                            //Stop Loss(points)
input int                  Inp_TakeProfit1=55;                          //Take Profit(points)

//--- Parámetros del indicador CenterOfGravityOSMA
input uint                 Period_1=9;                                  //Averaging period
input uint                 SmoothPeriod1_1=3;                           //Smoothing period1
input ENUM_MA_METHOD       MA_Method_1_1=MODE_SMA;                      //Averaging method1
input uint                 SmoothPeriod2_1=3;                           //Smoothing period2
input ENUM_MA_METHOD       MA_Method_2_1=MODE_SMA;                      //Averaging method2
input Applied_price_       AppliedPrice1=PRICE_TRENDFOLLOW1_;           //Applied price

//--- Parámetros del indicador Average Speed
input int                  Inp_Bars1=1;                                 //Days
input ENUM_APPLIED_PRICE   Price1=PRICE_LOW;                            //Applied price
input double               Trend_lev1=1.6;                              //Trend Level

//--- Downtrend parameters
input string               Inp_Str_label2="===Downtrend parameters==="; //Label
input int                  Inp_MagicNum2=2222;                          //Magic number
input int                  Inp_StopLoss2=40;                            //Stop Loss(points)
input int                  Inp_TakeProfit2=70;                          //Take Profit(points)

//--- Parámetros del indicador CenterOfGravityOSMA
input uint                 Period_2=15;                                 //Averaging period
input uint                 SmoothPeriod1_2=3;                           //Smoothing period1
input ENUM_MA_METHOD       MA_Method_1_2=MODE_SMA;                      //Averaging method1
input uint                 SmoothPeriod2_2=3;                           //Smoothing period2
input ENUM_MA_METHOD       MA_Method_2_2=MODE_SMA;                      //Averaging method2
input Applied_price_       AppliedPrice2=PRICE_HIGH_;                   //Applied price

//--- Parámetros del indicador Average Speed
input int                  Inp_Bars2=1;                                 //Days
input ENUM_APPLIED_PRICE   Price2=PRICE_WEIGHTED;                       //Applied price
input double               Trend_lev2=1.0;                              //Trend Level


//--- Buy parameters
input string               Inp_Str_label3="===Buy parameters===";       //Label
input int                  Inp_MagicNum3=3333;                          //Magic number
input int                  Inp_StopLoss3=40;                            //Stop Loss(points)
input int                  Inp_TakeProfit3=60;                          //Take Profit(points)

//--- Parámetros del indicador WPR
input int                  Inp_WPRPeriod1=11;                           //Period WPR
//--- Parámetros del indicador ADX
input int                  Inp_ADXPeriod1=13;                           //Period ADX
input int                  Inp_FlatLevel1=25;                           //Flat Level ADX

//--- Sell parameters
input string               Inp_Str_label4="===Sell parameters===";      //Label
input int                  Inp_MagicNum4=4444;                          //Magic number
input int                  Inp_StopLoss4=30;                            //Stop Loss(points)
input int                  Inp_TakeProfit4=30;                          //Take Profit(points)

//--- Parámetros del indicador WPR
input int                  Inp_WPRPeriod2=7;                            //Period WPR
//--- Parámetros del indicador ADX
input int                  Inp_ADXPeriod2=15;                           //Period ADX
input int                  Inp_FlatLevel2=40;                           //Flat Level ADX

Asimismo, se ha eliminado de los parámetros la posibilidad de establecer los modos, ya que el experto combinado no se someterá a entrenamiento u optimización. La propia estrategia se ha implementado así:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Obteniendo los datos para el cálculo

   if(!GetIndValue())
      return;

//--- Abriendo orden al darse la señal de compra(Estrategia de tendencia)
   if(BuySignal_1() && !Trade.IsOpenedByMagic(Inp_MagicNum1))
      Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss1,Inp_TakeProfit1,Inp_MagicNum1,Inp_EaComment);
//--- Abriendo orden al darse la señal de venta(Estrategia de tendencia)
   if(SellSignal_1() && !Trade.IsOpenedByMagic(Inp_MagicNum2))
      Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss2,Inp_TakeProfit2,Inp_MagicNum2,Inp_EaComment);

//--- Abriendo orden al darse la señal de compra(Estrategia de flat)
   if(BuySignal_2() && !Trade.IsOpenedByMagic(Inp_MagicNum3))
      Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss3,Inp_TakeProfit3,Inp_MagicNum3,Inp_EaComment);
//--- Abriendo orden al darse la señal de venta(Estrategia de flat)
   if(SellSignal_2() && !Trade.IsOpenedByMagic(Inp_MagicNum4))
      Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss4,Inp_TakeProfit4,Inp_MagicNum4,Inp_EaComment);
  }
//+------------------------------------------------------------------+
//| Condiciones de compra (Estrategia de tendencia)                  |
//+------------------------------------------------------------------+
bool BuySignal_1()
  {
   return(avr_speed1[0]>Trend_lev1 && cog1[1]<cog1[0] &&(cog1[1]<0 && cog1[0]<0))?true:false;
  }
//+------------------------------------------------------------------+
//| Condiciones de venta (Estrategia de tendencia)                   |
//+------------------------------------------------------------------+
bool SellSignal_1()
  {
   return(avr_speed2[0]>Trend_lev2 && cog2[1]>cog2[0] &&(cog2[1]>0 && cog2[0]>0))?true:false;
  }
//+------------------------------------------------------------------+
//| Condiciones de compra (Estrategia de flat)                       |
//+------------------------------------------------------------------+
bool BuySignal_2()
  {
   return(wpr1[0]<-80 && adx1[0]<Inp_FlatLevel1)?true:false;
  }
//+------------------------------------------------------------------+
//| Condiciones de venta (Estrategia de flat)                        |
//+------------------------------------------------------------------+
bool SellSignal_2()
  {
   return(wpr2[0]>=-20 && adx2[0]<Inp_FlatLevel2)?true:false;
  }
//+------------------------------------------------------------------+
//| Obteniendo los valores actuales de los indicadores               |
//+------------------------------------------------------------------+
bool GetIndValue()
  {
   return(CopyBuffer(InpInd_Handle1,0,0,2,cog1)<=0       ||
          CopyBuffer(InpInd_Handle2,0,0,2,cog2)<=0       ||
          CopyBuffer(InpInd_Handle3,0,0,2,avr_speed1)<=0 ||
          CopyBuffer(InpInd_Handle4,0,0,2,avr_speed2)<=0 ||
          CopyBuffer(InpInd_Handle5,0,0,2,wpr1)<=0       ||
          CopyBuffer(InpInd_Handle6,0,0,2,wpr2)<=0       ||
          CopyBuffer(InpInd_Handle7,0,0,2,adx1)<=0       ||
          CopyBuffer(InpInd_Handle8,0,0,2,adx2)<=0
          )?false:true;
  }
//+------------------------------------------------------------------+

Aquí debemos prestar atención a que los cuatro modos de las dos estrategias funcionan de forma autónoma unos con respecto a otros, tienen su propio conjunto de parámetros establecido después del entrenamiento y no se cruzan entre sí de ninguna forma. Para realizar la simulación, hemos decidido tomar un intervalo más amplio (los tres últimos años). La lista completa de condiciones de simulación se ha compuesto de la forma siguiente:

  • Intervalo: 01.01.2015 — 30.11.2018.
  • Pareja de divisas: EURUSD.
  • Modo de comercio: Sin retrasos. Las estaretegias no se relacionan con las de alta precisión, por eso la influencia de los retrasos sería muy pequeña.
  • Simulación: OHLC en М1. La simulación preliminar con ticks reales ha resultado casi indistinguible de este modo. 
  • Depósito inicial: 1000 USD.
  • Apalancamiento: 1:500.
  • Servidor: MetaQuotes-Demo.
  • Cotizaciones: de 5 dígitos.

Después de realizar la simulación, hemos obtenido estos resultados tan interesantes:

Fig.10 Resultados de la simulación de la estrategia combinada.

Debemos notar que no se ha realizado ninguna nueva optimización de parámetros, se han obtenido tal cual a partir de los valores óptimos encontrados en la optimización separada en intervalos favorables. Pero teniendo en cuenta que, en esencia, han funcionado cuatro estrategias independientes en una, y además en condiciones desfavorables para todas, el resultado obtenido es positivo.


Resumiendo

Tras comparar los resultados de simulación obtenidos de las dos estrategias comerciales usadas en tendencia ascendente, descendente y en flat, podemos sacar las siguientes conclusiones:

Teniendo en cuenta el hecho de que hemos seleccionado sistemas comerciales elegidos al azar para su simulación y mejora por medio de la optimización separada, y que la comprobación final se ha realizado en un intervalo de la historia lo más desfavorable posible, el resultado de esta investigación ha sido positivo. Los resultados han mostrado que el método de optimización separada es totalmente viable, y que su uso en el desarrollo y el ajuste de sistemas comerciales merece la pena.


Conclusión

Al final del artículo se adjunta un fichero con todos los archivos enumerados, clasificados por carpetas. Por eso, para que funcione correctamente, basta con colocar la carpeta MQL5 en la carpeta raíz del terminal.

Programas usados en el artículo:

#
 Nombre
Tipo
Descripción
1
TrendStrategy.mq5Experto
 Experto comercial basado en la estrategia de tendencia.
2
FlatStrategy.mq5Experto Experto comercial basado en la estrategia de flat.
3UniverseStrategy.mql5 Experto  Experto comercial basado en la estrategia combinada.
4Trade.mqhBiblioteca Clase de funciones comerciales.
5
average_speed.mq5Indicador Indicador de velocidad media de precio. Se usa en la estrategia de tendencia.
6centerofgravityosma.mq5Indicador Indicador de Centro de Gravedad de Ehlers. Se usa en la estrategia de tendencia.