Creamos una nueva estrategia comercial usando una tecnología de colocación de entradas a los indicadores

Dmitriy Gizlyk | 9 enero, 2018


Introducción

No es un secreto que solo el 5% de los tráders consigue un beneficio estable en los mercados fiancieros, mientras que, como es lógico, el 100% quiere entrar en este selecto grupo. 

Para comerciar con éxito, es necesaria una estrategia comercial rentable. En las páginas temáticas y en la bibliografía sobre trading se describen cientos de diferentes estrategias comerciales, cada indicador dispone de un extenso análisis de señales, pero la estadística se mantiene inamovible: el 5% no se ha convertido en un 100%, ni siquiera en un 10%. Los ideólogos del trading culpan a la variabilidad del mercado, que convierte estrategias anteriormente rentables en herramientas carentes de efectividad.

En el artículo anterior ya hablamos de la colocación de entradas a los indicadores y mostramos un ejemplo de perfeccionamiento de la estrategia existente. Ahora proponemos crear nuestra propia estrategia "desde cero", usando la tecnología descrita. Esto permitirá ver los indicadores que ya conocemos de una forma totalmente nueva, reuniendo nuestra propia plantilla de indicadores y reformulando sus señales. El uso de la tecnología propuesta implica un enfoque creativo respecto a la interpretación de las señales de los indicadores, que permite a cada usuario crear su propia estrategia única.

1 Creando un modelo para la simulación y el análisis

Lo primero que vemos en el terminal comercial es el movimiento constante de los precios. En potencia, abriendo una transacción en cualquier momento, podemos obtener beneficios. ¿Cómo determinar en qué dirección y con qué intensidad se moverá el precio dentro de un momento? Los tráders tratan de encontrar la respuesta a esta pregunta con ayuda del análisis técnico y el análisis fundamental. Para llevar a cabo el análisis técnico se inventan y perfeccionan constantemente diversos indicadores. Propongo que usemos precisamente estos, aunque en este hecho no haya ninguna novedad. La novedad aquí reside en la interpretación de las señales de estos indicadores, que puede diferenciarse de la habitual.

Bien, la tecnología de colocación de entradas a los indicadores presupone la comparación de las posiciones abiertas con las indicaciones de los indicadores. Repetimos que, en potencia, podemos obtener beneficios en cualquier momento. Basándonos en estas entradas, al comienzo de cada vela vamos a abrir dos posiciones opuestas con los parámetros especificados. A continuación, analizaremos la rentabilidad de cada operación dependiendo de los índices de los indicadores.

Para resolver este problema, vamos a hacer un poco de trabajo preparatorio.

1.1. Creando la clase de las órdenes virtuales

Vamos a usar una cuenta de compensación. Por ello, para abrir órdenes opuestas, necesitaremos crear órdenes virtuales que se monitorizarán no en el terminal (de acuerdo con los ajustes de la cuenta), sino con el asesor. Para ello, crearemos la clase CDeal. Al inicialiazar un ejemplar de la clase, transmitiremos en el mismo las denominaciones del instrumento, el tipo de posición, la hora y el precio de apertura, así como el stop-loss y el take-profit. El volumen de la posición lo hemos omitido a propósito, puesto que no lo necesitamos en este trabajo. A nosotros nos importa el movimiento del precio, por eso el beneficio/pérdidas lo calcularemos no en dinero, sino en puntos.

Para ofrecer servicio, la clase se ha complementado con funciones de comprobación del estado de la posición:

  • IsClosed — retorna un valor lógico que indica si la posición está abierta o cerrada;
  • Type — retorna el tipo de posición;
  • GetProfit — retorna el beneficio de la posición cerrada (para una posición con pérdidas, el valor será negativo);
  • GetTime — retorna la hora de apertura de la posición.

class CDeal          :  public CObject
  {
private:
   string               s_Symbol;
   datetime             dt_OpenTime;         // Time of open position
   double               d_OpenPrice;         // Price of opened position
   double               d_SL_Price;          // Stop Loss of position
   double               d_TP_Price;          // Take Profit of position
   ENUM_POSITION_TYPE   e_Direct;            // Direct of opened position
   double               d_ClosePrice;        // Price of close position
   int                  i_Profit;            // Profit of position in pips
//---
   double               d_Point;
   
public:
                     CDeal(string symbol, ENUM_POSITION_TYPE type,datetime time,double open_price,double sl_price, double tp_price);
                    ~CDeal();
   //--- Check status
   bool              IsClosed(void);
   ENUM_POSITION_TYPE Type(void)    {  return e_Direct;    }
   double            GetProfit(void);
   datetime          GetTime(void)  {  return dt_OpenTime;  }
   //---
   void              Tick(void);
  };

Los ticks entrantes serán procesados en la función Tick, que comprobará y (en caso necesario) cerarrá la posición con un stop-loss o take-profit, y guardará el beneficio total.

void CDeal::Tick(void)
  {
   if(d_ClosePrice>0)
      return;
   double price=0;
   switch(e_Direct)
     {
      case POSITION_TYPE_BUY:
        price=SymbolInfoDouble(s_Symbol,SYMBOL_BID);
        if(d_SL_Price>0 && d_SL_Price>=price)
          {
           d_ClosePrice=price;
           i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point);
          }
        else
          {
           if(d_TP_Price>0 && d_TP_Price<=price)
             {
              d_ClosePrice=price;
              i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point);
             }
          }
        break;
      case POSITION_TYPE_SELL:
        price=SymbolInfoDouble(s_Symbol,SYMBOL_ASK);
        if(d_SL_Price>0 && d_SL_Price<=price)
          {
           d_ClosePrice=price;
           i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point);
          }
        else
          {
           if(d_TP_Price>0 && d_TP_Price>=price)
             {
              d_ClosePrice=price;
              i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point);
             }
          }
        break;
     }
  }

1.2. Creando una clase para trabajar con indicadores

Para guardar y analizar los datos de los indicadores hemos utilizado las clases descritas en el anterior artículo. Aquí mismo hemos creado la clase CDealsToIndicators, que generaliza todas las clases de indicador. Este almacenará las matrices de las clases de indicador y organizará su funcionamiento.

class CDealsToIndicators
  {
private:
   CADX              *ADX[];
   CAlligator        *Alligator[];
   COneBufferArray   *OneBuffer[];
   CMACD             *MACD[];
   CStaticOneBuffer  *OneBufferStatic[];
   CStaticMACD       *MACD_Static[];
   CStaticADX        *ADX_Static[];
   CStaticAlligator  *Alligator_Static[];
   
   template<typename T>
   void              CleareArray(T *&array[]);

public:
                     CDealsToIndicators();
                    ~CDealsToIndicators();
   //---
   bool              AddADX(string symbol, ENUM_TIMEFRAMES timeframe, int period, string name);
   bool              AddADX(string symbol, ENUM_TIMEFRAMES timeframe, int period, string name, int &handle);
   bool              AddAlligator(string symbol,ENUM_TIMEFRAMES timeframe,uint jaw_period, uint jaw_shift, uint teeth_period, uint teeth_shift, uint lips_period, uint lips_shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price, string name);
   bool              AddAlligator(string symbol,ENUM_TIMEFRAMES timeframe,uint jaw_period, uint jaw_shift, uint teeth_period, uint teeth_shift, uint lips_period, uint lips_shift, ENUM_MA_METHOD method, ENUM_APPLIED_PRICE price, string name, int &handle);
   bool              AddMACD(string symbol, ENUM_TIMEFRAMES timeframe, uint fast_ema, uint slow_ema, uint signal, ENUM_APPLIED_PRICE applied_price, string name);
   bool              AddMACD(string symbol, ENUM_TIMEFRAMES timeframe, uint fast_ema, uint slow_ema, uint signal, ENUM_APPLIED_PRICE applied_price, string name, int &handle);
   bool              AddOneBuffer(int handle, string name);
   //---
   bool              SaveNewValues(long ticket);
   //---
   bool              Static(CArrayObj *deals);
  };

1.3. Creando un asesor para la simulación

Ya hemos preparado todo. Ahora vamos a crear un asesor para trabajar en el simulador de estrategias. Primero tenemos que definir la lista de indicadores utilizados y sus parámetros. Para mostrar la tecnología, hemos tomado los siguientes indicadores:

  • ADX;
  • Alligator;
  • CCI;
  • Chaikin;
  • Force Index;
  • MACD.

Para cada uno de ellos se han creado 3 conjuntos de parámetros, los datos se monitorizan en tres marcos temporales.

El stop-loss y el take-profit han sido vinculados a los valores del indicador ATR y se han establecido a través de la proporción entre el beneficio y el riesgo.

//--- input parameters
input double            Reward_Risk    =  1.0;
input int               ATR_Period     =  288;
input ENUM_TIMEFRAMES   TimeFrame1     =  PERIOD_M5;
input ENUM_TIMEFRAMES   TimeFrame2     =  PERIOD_H1;
input ENUM_TIMEFRAMES   TimeFrame3     =  PERIOD_D1;
input string            s1                =  "ADX"                ;  //---
input uint              ADX_Period1       =  14                   ;
input uint              ADX_Period2       =  28                   ;
input uint              ADX_Period3       =  56                   ;
input string            s2                =  "Alligator"          ;  //---
input uint              JAW_Period1       =  13                   ;
input uint              JAW_Shift1        =  8                    ;
input uint              TEETH_Period1     =  8                    ;
input uint              TEETH_Shift1      =  5                    ;
input uint              LIPS_Period1      =  5                    ;
input uint              LIPS_Shift1       =  3                    ;
input uint              JAW_Period2       =  26                   ;
input uint              JAW_Shift2        =  16                   ;
input uint              TEETH_Period2     =  16                   ;
input uint              TEETH_Shift2      =  10                   ;
input uint              LIPS_Period2      =  10                   ;
input uint              LIPS_Shift2       =  6                    ;
input uint              JAW_Period3       =  42                   ;
input uint              JAW_Shift3        =  32                   ;
input uint              TEETH_Period3     =  32                   ;
input uint              TEETH_Shift3      =  20                   ;
input uint              LIPS_Period3      =  20                   ;
input uint              LIPS_Shift3       =  12                   ;
input ENUM_MA_METHOD    Alligator_Method  =  MODE_SMMA            ;
input ENUM_APPLIED_PRICE Alligator_Price  =  PRICE_MEDIAN         ;
input string            s5                =  "CCI"                ;  //---
input uint              CCI_Period1       =  14                   ;
input uint              CCI_Period2       =  28                   ;
input uint              CCI_Period3       =  56                   ;
input ENUM_APPLIED_PRICE CCI_Price        =  PRICE_TYPICAL        ;
input string            s6                =  "Chaikin"            ;  //---
input uint              Ch_Fast_Period1   =  3                    ;
input uint              Ch_Slow_Period1   =  14                   ;
input uint              Ch_Fast_Period2   =  6                    ;
input uint              Ch_Slow_Period2   =  28                   ;
input uint              Ch_Fast_Period3   =  12                   ;
input uint              Ch_Slow_Period3   =  56                   ;
input ENUM_MA_METHOD    Ch_Method         =  MODE_EMA             ;
input ENUM_APPLIED_VOLUME Ch_Volume       =  VOLUME_TICK          ;
input string            s7                =  "Force Index"        ;  //---
input uint              Force_Period1     =  14                   ;
input uint              Force_Period2     =  28                   ;
input uint              Force_Period3     =  56                   ;
input ENUM_MA_METHOD    Force_Method      =  MODE_SMA             ;
input ENUM_APPLIED_VOLUME Force_Volume    =  VOLUME_TICK          ;
input string            s8                =  "MACD"               ;  //---
input uint              MACD_Fast1        =  12                   ;
input uint              MACD_Slow1        =  26                   ;
input uint              MACD_Signal1      =  9                    ;
input uint              MACD_Fast2        =  24                   ;
input uint              MACD_Slow2        =  52                   ;
input uint              MACD_Signal2      =  18                   ;
input uint              MACD_Fast3        =  48                   ;
input uint              MACD_Slow3        =  104                  ;
input uint              MACD_Signal3      =  36                   ;
input ENUM_APPLIED_PRICE MACD_Price       =  PRICE_CLOSE          ;

En el bloque de variables globales declaramos:

  • la matriz para almacenar las clases de las transacciones Deals,
  • el ejemplar de la clase para trabajar con los indicadores IndicatorsStatic,
  • la variable para almacenar el manejador del indicador ATR,
  • 2 variables auxiliares para almacener la hora de la última barra procesada (last_bar) y de la última orden cerrada (last_closed_deal). Necesitaremos la última para iterar en cada tick las posiciones cerradas anteriormente.

En la función OnInit vamos a inicializar las variables globales y las clases de indicador necesarias.

int OnInit()
  {
//---
   last_bar=0;
   last_closed_deal=0;
//---
   Deals =  new CArrayObj();
   if(CheckPointer(Deals)==POINTER_INVALID)
      return INIT_FAILED;
//---
   IndicatorsStatic  =  new CDealsToIndicators();
   if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
      return INIT_FAILED;
//---
   atr=iATR(_Symbol,TimeFrame1,ATR_Period);
   if(atr==INVALID_HANDLE)
      return INIT_FAILED;
//---
   AddIndicators(TimeFrame1);
   AddIndicators(TimeFrame2);
   AddIndicators(TimeFrame3);
//---
   return(INIT_SUCCEEDED);
  }

Vamos a utilizar el mismo conjunto de indicadores en tres marcos temporales diferentes. Por eso, tiene sentido mostrar la inicialización de las clases de indicador en la función aparte AddIndicators. Vamos a transmitir el marco temporal necesario en sus parámetros.

bool AddIndicators(ENUM_TIMEFRAMES timeframe)
  {
   if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
     {
      IndicatorsStatic  =  new CDealsToIndicators();
      if(CheckPointer(IndicatorsStatic)==POINTER_INVALID)
         return false;
     }
   string tf_name=StringSubstr(EnumToString(timeframe),7);
   string name="ADX("+IntegerToString(ADX_Period1)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period1, name))
      return false;
   name="ADX("+IntegerToString(ADX_Period2)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period2, name))
      return false;
   name="ADX("+IntegerToString(ADX_Period3)+") "+tf_name;
   if(!IndicatorsStatic.AddADX(_Symbol, timeframe, ADX_Period3, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period1)+","+IntegerToString(TEETH_Period1)+","+IntegerToString(LIPS_Period1)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period1, JAW_Shift1, TEETH_Period1, TEETH_Shift1, LIPS_Period1, LIPS_Shift1, Alligator_Method, Alligator_Price, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period2)+","+IntegerToString(TEETH_Period2)+","+IntegerToString(LIPS_Period2)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period2, JAW_Shift2, TEETH_Period2, TEETH_Shift2, LIPS_Period2, LIPS_Shift2, Alligator_Method, Alligator_Price, name))
      return false;
   name="Alligator("+IntegerToString(JAW_Period3)+","+IntegerToString(TEETH_Period3)+","+IntegerToString(LIPS_Period3)+") "+tf_name;
   if(!IndicatorsStatic.AddAlligator(_Symbol, timeframe, JAW_Period3, JAW_Shift3, TEETH_Period3, TEETH_Shift3, LIPS_Period3, LIPS_Shift3, Alligator_Method, Alligator_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast1)+","+IntegerToString(MACD_Slow1)+","+IntegerToString(MACD_Signal1)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast1, MACD_Slow1, MACD_Signal1, MACD_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast2)+","+IntegerToString(MACD_Slow2)+","+IntegerToString(MACD_Signal2)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name))
      return false;
   name="MACD("+IntegerToString(MACD_Fast3)+","+IntegerToString(MACD_Slow3)+","+IntegerToString(MACD_Signal3)+") "+tf_name;
   if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast3, MACD_Slow3, MACD_Signal3, MACD_Price, name))
      return false;
   name="CCI("+IntegerToString(CCI_Period1)+") "+tf_name;
   int handle = iCCI(_Symbol, timeframe, CCI_Period1, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   name="CCI("+IntegerToString(CCI_Period2)+") "+tf_name;
   handle = iCCI(_Symbol, timeframe, CCI_Period2, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iCCI(_Symbol, timeframe, CCI_Period3, CCI_Price);
   name="CCI("+IntegerToString(CCI_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period1, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period1)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period2, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iForce(_Symbol, timeframe, Force_Period3, Force_Method, Force_Volume);
   name="Force("+IntegerToString(Force_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   name="CHO("+IntegerToString(Ch_Slow_Period1)+","+IntegerToString(Ch_Fast_Period1)+") "+tf_name;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period1, Ch_Slow_Period1, Ch_Method, Ch_Volume);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period2, Ch_Slow_Period2, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period2)+","+IntegerToString(Ch_Fast_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period3, Ch_Slow_Period3, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period3)+","+IntegerToString(Ch_Fast_Period3)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   return true;
  }

Las operaciones ejecutadas en la función OnTick se pueden dividir en 2 bloques: la comprobación de las posiciones abiertas y la apertura de nuevas posiciones.

El primer bloque de operaciones se ejecuta en cada tick. En este se extraen por turnos desde la matriz todas las transacciones abiertas anteriormente, y para cada una de ellas se llama la función Tick. Esta comprueba la activación del stop-loss y el take-profit de la posición; en caso necesario, la orden se cerrará al precio actual conservando el beneficio acumulado. Para no comprobar de nuevo las transacciones abiertas anteriormente, en la variable last_closed_deal se guarda el número de la transacción que antecedió a la primera sin cerrar. 

void OnTick()
  {
//---
   int total=Deals.Total();
   CDeal *deal;
   bool found=false;
   for(int i=last_closed_deal;i<total;i++)
     {
      deal  =  Deals.At(i);
      if(CheckPointer(deal)==POINTER_INVALID)
         continue;
      if(!found)
        {
         if(deal.IsClosed())
           {
            last_closed_deal=i;
            continue;
           }
         else
            found=true;
        }
      deal.Tick();
     }

El segundo bloque comienza con la comprobación de la llegada de una nueva barra. Al comienzo de cada barra cargamos el valor del indicador ATR en la última vela cerrada, calculamos los niveles de stop-loss y take-profit de acuerdo con los parámetros indicados y abrimos las posiciones virtuales. Almacenamos los datos para cada posición, llamando la función SaveNewValues de nuestra clase de trabajo con indicadores.

//---
   datetime cur_bar=(datetime)SeriesInfoInteger(_Symbol,PERIOD_CURRENT,SERIES_LASTBAR_DATE);
   datetime cur_time=TimeCurrent();
   if(cur_bar==last_bar || (cur_time-cur_bar)>10)
      return;
   double atrs[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0)
      return;

   last_bar=cur_bar;
   double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
   double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
   double sl=NormalizeDouble(stops,_Digits);
   double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
   deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
   if(CheckPointer(deal)!=POINTER_INVALID)
      if(Deals.Add(deal))
         IndicatorsStatic.SaveNewValues(Deals.Total()-1);
   deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
   if(CheckPointer(deal)!=POINTER_INVALID)
      if(Deals.Add(deal))
         IndicatorsStatic.SaveNewValues(Deals.Total()-1);
   return;
  }

En la función OnTester, reuniremos los resultados de la pasada de prueba y construiremos los gráficos para el análisis. Para ello, llamaremos la función Static de la clase de trabajo con los indicadores.

¡No debemos olvidar limpiar la memoria en la función OnDeinit!

Podrá familiarizarse con el código completo del asesor y las clases utilizadas en los anexos.

2. Análisis de los resultados de la simulación

Bien, hemos creado el asesor de prueba. Ahora vamos a elegir el periodo analizado. Al elegir el periodo, debemos tener en cuenta que tiene que ser lo suficientemente largo para que la objetividad del análisis sea posible. Otro requisito del periodo: debe incluir, no solo los movimientos en una misma dirección, sino también los periodos de los movimientos de las tendencias opuestas y las tendencias planas (flat). Este enfoque permitirá crear una estrategia comercial capaz de generar beneficio en los periodos de cualquier movimiento. En nuestro ejemplo, hemos analizado la pareja EURUSD en el periodo que va desde 1/01/2016 hasta 1/10/2017.

Periodo de simulaciónParámetros de simulación

Puesto que nuestro proceso será de naturaleza iterativa, le recomendamos que, después de instalar todos los parámetros necesarios del asesor de prueba, guarde la configuración de los archivos set para el trabajo posterior.

Cada etapa de la simulación se realizará en 2 pasadas con una proporción de beneficio/riesgo de 1/1 y 15/1. Según la primera pasada, valoraremos la probabilidad de un movimiento dirigido, y según la segunda, la fuerza del movimiento.

El asesor muestra muchos gráficos para el análisis, por eso no vamos a representarlos en el artículo, todos los informes se encuentran en los anexos. Aquí solo vamos a mostrar los gráficos sobre cuya base se tomaron decisiones acerca del uso de los indicadores en la nueva estrategia.

2.1. Primera etapa

Como era de esperar, la primera etapa de la simulación no nos ha dado zonas de beneficio claras. Pero, al mismo tiempo, merece la pena prestar atención al indicador del índice de fuerza. En el marco temporal М5, el gráfico de dependencia del beneficio de las transacciones con respecto a los valores del indicador cae bruscamente en la zona cero. Sobre la importancia de este momento da fe el hecho de que este fenómeno se muestre en los gráficos analíticos con todos los parámetros usados para la simulación. Para nuestra plantilla elegiremos parámetros con un carácter más perceptible en lo que respecta al fenómeno (reducción máxima).

Gráficos analíticos del indicador de fuerza con un periodo 56 en el marco temporal М5

Vamos a aumentar la escala del gráfico analizado. Podemos ver que la influencia de este factor se observa en el rango de -0.01 a 0.01. El fenómeno observado es igualmente cierto tanto para las transacciones de compra, como para las de venta.

Esta observación se puede explicar por la ausencia de volatilidad en el rango de valores observado. Para nuestra estrategia, marcaremos la prohibición de apertura de cualquier orden en este rango.

La dependencia del beneficio con respecto a los valores del indicador de fuerza está cerca de la marca cero

Vamos a añadir este filtro a nuestro asesor. Para ello, primero añadimos la variable global para el almacenamiento del manejador del indicador.

int                  force;

Puesto que el indicador imprescindible para nosostros como filtro ya se usa en el asesor, no lo adjuntaremos al gráfico de nuevo. Simplemente copiaremos su manejador en nuestra variable global en la función AddIndicators. Pero conviene recordar que esta función se llama tres veces para inicializar los indicadores en diferentes marcos temporales. Por consiguiente, antes de copiar el manejador del indicador, hay que comprobar la correspondencia del marco temporal.

   handle = iForce(_Symbol, timeframe, Force_Period3, Force_Method, Force_Volume);
   if(timeframe==TimeFrame1)
      force=handle;

Ahora añadimos un filtro directamente a la función OnTick. Al construir el filtro, debemos recordar que en la función de construcción del gráfico analítico los datos habían sido redondeados. Por eso, al filtrar las transacciones, también deberemos redondear las indicaciones del indicaodr.

   double atrs[];
   double force_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0)
      return;      // Some error of load indicator's data

   last_bar=cur_bar;
   double d_Step=_Point*1000;
   if(MathAbs(NormalizeDouble(force_data[0]/d_Step,0)*d_Step)<=0.01)
      return;    // Filtered by Force Index

El código completo del asesor se adjunta al artículo.

Tras añadir el filtro al asesor, pasamos a la segunda etapa de la simulación. Antes de la simulación, no conviene olvidar cargar los parámetros cargados anteriormente.

2.2. Segunda etapa

Después de simular de nuevo el asesor, tenemos que prestar atención al asesor MACD. En el gráfico han aparecido zonas con beneficios.

Gráfico de dependencia del beneficio con respecto a los valores del histograma del indicador MACD

En el gráfico estas zonas destacan de forma llamativa con una proporción de beneficio/riesgo de 15/1, lo que confirma el potencial de las señales en estos rangos.

Diagrama de dependencia del beneficio con respecto a los valores del histograma MACD (beneficio/riesgo = 15/1)

Añadimos este filtro al código de nuestro asesor. La lógica de adición del filtro es análoga a la mostrada en la descripción de la primera etapa.

A las variables globales:

int                  macd;

A la función AddIndicators:

   name="MACD("+IntegerToString(MACD_Fast2)+","+IntegerToString(MACD_Slow2)+","+IntegerToString(MACD_Signal2)+") "+tf_name;
   if(timeframe==TimeFrame1)
     {
      if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name, macd))
         return false;
     }
   else
     {
      if(!IndicatorsStatic.AddMACD(_Symbol, timeframe, MACD_Fast2, MACD_Slow2, MACD_Signal2, MACD_Price, name))
         return false;
     }

A la función OnTick:

   double macd_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0)
      return;

y

   double macd_Step=_Point*50;
   macd_data[0]=NormalizeDouble(macd_data[0]/macd_Step,0)*macd_Step;
   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035))
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

Después de añadir el filtro, pasamos a la tercera etapa de simulación.

2.3. Tercera etapa

En la tercera etapa, llama la atención el oscilador Chaikin. En los gráficos analíticos del oscilador, en el marco temporal D1 podemos ver el incremento del beneficio en las posiciones largas cuando disminuyen los valores; cuando estos aumentan, crece el beneficio en las posiciones cortas.

Dependencia del beneficio con respecto a las indicaciones del oscilador de Chaikin

Nuestras observaciones también se ven confirmadas al analizar los gráficos con una proporción de beneficio/riesgo de 15/1.

Dependencia del beneficio con respecto a las indicaciones del oscilador de Chaikin.

Vamos a añadir nuestras observaciones al código del asesor.

A las variables globales:

int                  cho;

A la función AddIndicators:

   handle = iChaikin(_Symbol, timeframe, Ch_Fast_Period2, Ch_Slow_Period2, Ch_Method, Ch_Volume);
   name="CHO("+IntegerToString(Ch_Slow_Period2)+","+IntegerToString(Ch_Fast_Period2)+") "+tf_name;
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   if(timeframe==TimeFrame3)
      cho=handle;

A la función OnTick:

   double cho_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2)
      return;

y

   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

Vamos a pasar a la siguiente etapa.

2.4. Cuarta etapa

Después de la nueva simulación del asesor, el marco temporal D1 atrajo de nuevo nuestra atención. Esta vez analizamos el indicaor CCI. Sus gráficos analíticos han mostrado un incremento del beneficio en las posiciones cortas al dismunir los valores del indicador, y un incremento del beneficio de las posiciones largas al aumentar los valores del indicador. Esta tendencia se ha observado en los tres periodos analizados, pero el beneficio máximo se ha alcanzado al usar el periodo 14, que es estándar para este oscilador.

Dependencia del beneficio con respecto a los valores del indicador CCI.

Los gráficos analíticos obtenidos durante la simulación con una proporción de beneficio/riesgo de 15/1 confirman nuestras observaciones.

Dependencia del beneficio con respecto a los valores del indicador CCI.

Vamos a añadir también esta observación al código del asesor de prueba.

A las variables globales:

int                  cci;

A la función AddIndicators:

   name="CCI("+IntegerToString(CCI_Period1)+") "+tf_name;
   int handle = iCCI(_Symbol, timeframe, CCI_Period1, CCI_Price);
   if(handle<0 || !IndicatorsStatic.AddOneBuffer(handle, name) )
      return false;
   if(timeframe==TimeFrame3)
      cci=handle;

A la función OnTick:

   double cci_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2 || CopyBuffer(cci,0,1,2,cci_data)<2)
      return;

y

   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0 && (cci_data[1]-cci_data[0])>0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_BUY,TimeCurrent(),ask,bid-sl,ask+tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0 && (cci_data[1]-cci_data[0])<0)
     {
      deal  =  new CDeal(_Symbol,POSITION_TYPE_SELL,TimeCurrent(),bid,ask+sl,bid-tp);
      if(CheckPointer(deal)!=POINTER_INVALID)
         if(Deals.Add(deal))
            IndicatorsStatic.SaveNewValues(Deals.Total()-1);
     }

En los anexos al artículo podrá familiarizarse con el código completo en todas las etapas.

3. Creación y simulación del asesor según las señales elegidas

Puesto que el perfeccionamiento no tiene límites, podríamos seguir analizando y añadiendo filtros para aumentar la rentabilidad de la estrategia. Pero creemos que las cuatro etapas expuestas son más que suficientes para hacer una demostración del funcionamiento de la tecnología. En el siguiente paso, vamos a crear un asesor sencillo para comprobar nuestra estrategia en el simulador. Esto permitirá valorar la rentabilidad y la reducción de nuestra estrategia, así como la dinámica del cambio en el balance.

En la estrategia hemos usado 4 indicadores para la toma de decisiones sobre la transacción, y el indicador ATR para colocar los stop-loss y los take-profit. Por consiguiente, en los parámetros de entrada del asesor deberemos establecer la información original necesaria para los indicadores. No vamos a crear money-management en esta etapa, todas las órdenes utilizarán un volumen fijo.

//--- input parameters
input double            Lot               =  0.1                  ;
input double            Reward_Risk       =  15.0                 ;
input ENUM_TIMEFRAMES   ATR_TimeFrame     =  PERIOD_M5            ;
input int               ATR_Period        =  288                  ;
input string            s1                =  "CCI"                ;  //---
input ENUM_TIMEFRAMES   CCI_TimeFrame     =  PERIOD_D1            ;
input uint              CCI_Period        =  14                   ;
input ENUM_APPLIED_PRICE CCI_Price        =  PRICE_TYPICAL        ;
input string            s2                =  "Chaikin"            ;  //---
input ENUM_TIMEFRAMES   Ch_TimeFrame      =  PERIOD_D1            ;
input uint              Ch_Fast_Period    =  6                    ;
input uint              Ch_Slow_Period    =  28                   ;
input ENUM_MA_METHOD    Ch_Method         =  MODE_EMA             ;
input ENUM_APPLIED_VOLUME Ch_Volume       =  VOLUME_TICK          ;
input string            s3                =  "Force Index"        ;  //---
input ENUM_TIMEFRAMES   Force_TimeFrame   =  PERIOD_M5            ;
input uint              Force_Period      =  56                   ;
input ENUM_MA_METHOD    Force_Method      =  MODE_SMA             ;
input ENUM_APPLIED_VOLUME Force_Volume    =  VOLUME_TICK          ;
input string            s4                =  "MACD"               ;  //---
input ENUM_TIMEFRAMES   MACD_TimeFrame    =  PERIOD_M5            ;
input uint              MACD_Fast         =  12                   ;
input uint              MACD_Slow         =  26                   ;
input uint              MACD_Signal       =  9                    ;
input ENUM_APPLIED_PRICE MACD_Price       =  PRICE_CLOSE          ;

En las variables globales, declaramos:

  • un ejemplar de la clase para realizar transacciones comerciales,
  • las variables para almacenar los manejadores de los indicadores utilizados,
  • las variables auxiliares para el almacenamiento de las fechas de la última barra procesada y la última transacción,
  • las variables para el almacenamiento del marco temporal máximo y mínimo.

En la función OnInit, inicializamos los indicadores y establecemos los valores iniciales de las variables.

int OnInit()
  {
//---
   last_bar=0;
   last_deal=0;
//---
   atr=iATR(_Symbol,ATR_TimeFrame,ATR_Period);
   if(atr==INVALID_HANDLE)
      return INIT_FAILED;
//---
   force=iForce(_Symbol,Force_TimeFrame,Force_Period,Force_Method,Force_Volume);
   if(force==INVALID_HANDLE)
      return INIT_FAILED;
//---
   macd=iMACD(_Symbol,MACD_TimeFrame,MACD_Fast,MACD_Slow,MACD_Signal,MACD_Price);
   if(macd==INVALID_HANDLE)
      return INIT_FAILED;
//---
   cho=iChaikin(_Symbol,Ch_TimeFrame,Ch_Fast_Period,Ch_Slow_Period,Ch_Method,Ch_Volume);
   if(cho==INVALID_HANDLE)
      return INIT_FAILED;
//---
   cci=iCCI(_Symbol,CCI_TimeFrame,CCI_Period,CCI_Price);
   if(cci==INVALID_HANDLE)
      return INIT_FAILED;
//---
   MaxPeriod=fmax(Force_TimeFrame,MACD_TimeFrame);
   MaxPeriod=fmax(MaxPeriod,Ch_TimeFrame);
   MaxPeriod=fmax(MaxPeriod,CCI_TimeFrame);
   MinPeriod=fmin(Force_TimeFrame,MACD_TimeFrame);
   MinPeriod=fmin(MinPeriod,Ch_TimeFrame);
   MinPeriod=fmin(MinPeriod,CCI_TimeFrame);
//---
   return(INIT_SUCCEEDED);
  }

En la función OnDeinit cerramos los indicadores utilizados.

void OnDeinit(const int reason)
  {
//---
   if(atr!=INVALID_HANDLE)
      IndicatorRelease(atr);
//---
   if(force==INVALID_HANDLE)
      IndicatorRelease(force);
//---
   if(macd==INVALID_HANDLE)
      IndicatorRelease(macd);
//---
   if(cho==INVALID_HANDLE)
      IndicatorRelease(cho);
//---
   if(cci==INVALID_HANDLE)
      IndicatorRelease(cci);
  }

Las acciones principales se mostrarán en la función OnTick.  Al inicio de la función comprobamos la llegada de una nueva barra. La nueva posición se abrirá solo en la apertura de una nueva barra según el marco temporal máximo (hemos puesto un límite de 10 segundos desde la apertura de la barra), y solo si aún no se ha abierto una posición en los límites de la barra actual según el marco temporal máximo. Así, limitamos la apertura a solo una orden por una señal.

void OnTick()
  {
//---
   datetime cur_bar=(datetime)SeriesInfoInteger(_Symbol,MinPeriod,SERIES_LASTBAR_DATE);
   datetime cur_max=(datetime)SeriesInfoInteger(_Symbol,MaxPeriod,SERIES_LASTBAR_DATE);
   datetime cur_time=TimeCurrent();
   if(cur_bar<=last_bar || (cur_time-cur_bar)>10 || cur_max<=last_deal)
      return;

A continuación, obtenemos los datos de los indicadores utilizados. En el caso de que haya un error en la obtención de los datos de aunque sea solo un indicador, salimos de la función.

   last_bar=cur_bar;
   double atrs[];
   double force_data[];
   double macd_data[];
   double cho_data[];
   double cci_data[];
   if(CopyBuffer(atr,0,1,1,atrs)<=0 || CopyBuffer(force,0,1,1,force_data)<=0 || CopyBuffer(macd,0,1,1,macd_data)<=0
      || CopyBuffer(cho,0,1,2,cho_data)<2 || CopyBuffer(cci,0,1,2,cci_data)<2)
     {
      return;
     }

A continuación, de acuerdo con nuestra estrategia, comprobamos el valor del índice de fuerza. Si no satisface nuestro filtro, salimos de la función hasta la apertura de la siguiente barra.

   double force_Step=_Point*1000;
   if(MathAbs(NormalizeDouble(force_data[0]/force_Step,0)*force_Step)<=0.01)
      return;

En la siguiente etapa, comprobamos la señal de apertura de la posición larga. Si hay una señal positiva, comprobamos si tenemos ya una posición abierta. Si la hay y esta es corta, la cerramos. Si hay abierta una posición larga que se encuentra en zona de pérdidas, ignoramos la señal y salimos de la función.

Después de ello, calculamos los parámetros para una nueva posición y abrimos una orden.

Realizamos las operaciones análogas para la posición corta.

   double macd_Step=_Point*50;
   macd_data[0]=NormalizeDouble(macd_data[0]/macd_Step,0)*macd_Step;
   if(macd_data[0]>=0.0015 && macd_data[0]<=0.0035 && (cho_data[1]-cho_data[0])<0 && (cci_data[1]-cci_data[0])>0)
     {
      if(PositionSelect(_Symbol))
        {
         switch((int)PositionGetInteger(POSITION_TYPE))
           {
            case POSITION_TYPE_BUY:
              if(PositionGetDouble(POSITION_PROFIT)<=0)
                 return;
              break;
            case POSITION_TYPE_SELL:
              Trade.PositionClose(_Symbol);
              break;
           }
        }
      last_deal=cur_max;
      double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
      double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      double sl=NormalizeDouble(stops,_Digits);
      double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
      double SL=NormalizeDouble(bid-sl,_Digits);
      double TP=NormalizeDouble(ask+tp,_Digits);
      if(!Trade.Buy(Lot,_Symbol,ask,SL,TP,"New Strategy"))
         Print("Error of open BUY ORDER "+Trade.ResultComment());
     }
   if(macd_data[0]<=(-0.0015) && macd_data[0]>=(-0.0035) && (cho_data[1]-cho_data[0])>0 && (cci_data[1]-cci_data[0])<0)
     {
      if(PositionSelect(_Symbol))
        {
         switch((int)PositionGetInteger(POSITION_TYPE))
           {
            case POSITION_TYPE_SELL:
              if(PositionGetDouble(POSITION_PROFIT)<=0)
                 return;
              break;
            case POSITION_TYPE_BUY:
              Trade.PositionClose(_Symbol);
              break;
           }
        }
      last_deal=cur_max;
      double stops=MathMax(2*atrs[0],SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)*_Point);
      double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
      double sl=NormalizeDouble(stops,_Digits);
      double tp=NormalizeDouble(Reward_Risk*(stops+ask-bid),_Digits);
      double SL=NormalizeDouble(ask+sl,_Digits);
      double TP=NormalizeDouble(bid-tp,_Digits);
      if(!Trade.Sell(Lot,_Symbol,bid,SL,TP,"New Strategy"))
         Print("Error of open SELL ORDER "+Trade.ResultComment());
     }
   return;
  }

Podrá familiarizarse con el código completo del asesor en los anexos.

Después de preparar el asesor, podemos realizar la simulación de nuestra estrategia. Para evitar la situación en la que se "adecua la estrategia al periodo", ampliaremos el periodo simulado: vamos a simular la estrategia desde el 1/01/2015 al 1/12/2017. El capital inicial de la simulación será de 10 000 USD, el tamaño de la transacción, de 1 lote.

Simulación de la estrategia. 

Según los resltados de simulación, el asesor ha mostrado un beneficio del 74.8% con reducciones máximas del balance del 12.4% y de la equidad de un 23.8%. Se han realizado en total 44 transacciones (22 posiciones cortas y 22 largas). El porcentaje de posiciones rentables ha sido del 18.2%, tanto para las posiciones cortas, como para las largas. El tanto por ciento tan bajo de posiciones rentables viene condicionado por el uso de una proporción alta del beneficio esperado con respecto al riesgo (15:1) y deja la posibilidad de perfeccionar la estrategia en lo sucesivo.

Resultados de la simulación de la estrategia.

Conclusión

En el artículo se muestra la tecnología de creación de una estrategia comercial "desde cero" usando el método de entrada a los indicadores. La estrategia obtenida como conclusión es capaz de generar beneficios durante un largo periodo, lo cual ha sido confirmado por la simulación de 3 años. A pesar de que al crear la estrategia se han usado indicadores del paquete estándar de MetaTrader, las señales de ejecución de transacciones se alejan bastante de las señales descritas en la literatura para los indicadores tomados. La tecnología propuesta da la posibilidad de realizar una aproximación más creativa al uso de los indicadores en las estrategias comerciales, sin tener que limitarse a los indicadores tomados. Es posible usar cualquier indicador personalizado y cualquier variante de evaluación para sus señales.

Enlaces

  1. Colocamos las entradas según los indicadores
  2. Gráficos y diagramas en formato HTML

Programas usados en el artículo:

#
 Nombre
Tipo 
Descripción 
  New_Strategy_Gizlyk.zip    
1 NewStrategy1.mq5  Asesor Experto  Asesor para llevar a cabo la primera etapa de creación de la estrategia
 2 NewStrategy2.mq5   Asesor Experto  Asesor para llevar a cabo la segunda etapa de creación de la estrategia
 3 NewStrategy3.mq5   Asesor Experto  Asesor para llevar a cabo la tercera etapa de creación de la estrategia 
 4 NewStrategy4.mq5   Asesor Experto   Asesor para llevar a cabo la cuarta etapa de creación de la estrategia 
 5 NewStrategy_Final.mq5  Asesor Experto   Asesor de simulación de la estrategia 
6 DealsToIndicators.mqh  Biblioteca de la clase  Clase para trabajar con las clases de indicador
7 Deal.mqh   Biblioteca de la clase  Clase para almacenar la información sobre la transacción
8 Value.mqh   Biblioteca de la clase  Clase para almacenar los datos sobre el estado del búfer de indicador
9 OneBufferArray.mqh  Biblioteca de la clase  Clase para almacenar la historia de datos del indicador de un solo búfer
10 StaticOneBuffer.mqh  Biblioteca de la clase  Clase para la recopilación y el análisis de la estadística del indicador de un solo búfer
11 ADXValue.mqh  Biblioteca de la clase  Clase para almacenar los datos sobre el estado del indicador ADX
12 ADX.mqh  Biblioteca de la clase  Clase para almacenar la historia de datos del indicador ADX
13 StaticADX.mqh  Biblioteca de la clase  Clase para la recopilación y el análisis de la estadística del indicador ADX
14 AlligatorValue.mqh  Biblioteca de la clase  Clase para almacenar los datos sobre el estado del indicador Alligator
15 Alligator.mqh  Biblioteca de la clase  Clase para almacenar la historia de datos del indicador Alligator
16 StaticAlligator.mqh  Biblioteca de la clase  Clase para la recopilación y el análisis de la estadística del indicador Alligator
17 MACDValue.mqh  Biblioteca de la clase  Clase para almacenar los datos sobre el estado del indicador MACD
18 MACD.mqh  Biblioteca de la clase  Clase para almacenar la historia de datos del indicador MACD
19 StaticMACD.mqh  Biblioteca de la clase  Clase para la recopilación y el análisis de la estadística del indicador MACD
   Common.zip    
20  NewStrategy1_Report_1to1_2016-17.html  Archivo de internet  Gráficos analíticos de la primera etapa de creación de la estrategia, beneficio/riesgo = 1/1
21  NewStrategy1_Report_15to1_2016-17.html  Archivo de internet  Gráficos analíticos de la primera etapa de creación de la estrategia, beneficio/riesgo = 15/1
22  NewStrategy2_Report_1to1_2016-17.html   Archivo de internet  Gráficos analíticos de la segunda etapa de creación de la estrategia, beneficio/riesgo = 1/1
23  NewStrategy2_Report_15to1_2016-17.html  Archivo de internet  Gráficos analíticos de la segunda etapa de creación de la estrategia, beneficio/riesgo = 15/1
24  NewStrategy3_Report_1to1_2016-17.html   Archivo de internet  Gráficos analíticos de la tercera etapa de creación de la estrategia, beneficio/riesgo = 1/1
25  NewStrategy3_Report_15to1_2016-17.html   Archivo de internet  Gráficos analíticos de la tercera etapa de creación de la estrategia, beneficio/riesgo = 15/1
26  NewStrategy4_Report_1to1_2016-17.html   Archivo de internet  Gráficos analíticos de la cuarta etapa de creación de la estrategia, beneficio/riesgo = 1/1
27  NewStrategy4_Report_15to1_2016-17.html   Archivo de internet  Gráficos analíticos de la cuarta etapa de creación de la estrategia, beneficio/riesgo = 15/1
28  NewStrategy_Final_Report.html  Archivo de internet  Informe de simulación de la estrategia