Generador de señales comerciales del indicador de usuario

Vladimir Karputov | 16 enero, 2014

Introducción

En esta sección voy a hablar de cómo crear un generador de señales comerciales en base a un indicador de usuario. Le enseñaré cómo escribir su propio modelo comercial para un indicador de usuario. Asímismo, le explicaré el significado de los modelos "model 0" y para qué sirven las construcciones del tipo "IS_PATTERN_USAGE(0)" en el módulo de señales comerciales.

En el artículo van a estar presentes continuamente dos tipos de código: el código que sólo queremos cambiar y el código que ya hemos cambiado. El código modificado se distinguirá con color de la siguiente forma:

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2012, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+

El código modificado es aquel que hay que copiar y pegar en el genarador de señales comerciales. Espero que esta separación le ayude a la hora de percibir el código. 

 

1. Indicador de usuario

Estoy seguro de que ya hace mucho que usted tiene la descripción de un indicador de suministro no estándar. Y precisamente sobre la base de ese indicador usted querría construir un módulo de señales comerciales. En calidad de tal indicador de usuario tomaré el indicador MACD del suministro estándar. El camino hacia este indicador es el siguiente: ...MQL5\Indicators\Examples\MACD.mq5

Cada indicador puede describir uno o varios modelos de mercado. Un modelo de mercado es una unión determinada entre el valor del indicador y el valor del precio. El indicador MACD tiene los siguientes modelos: viraje,  cruce de las líneas básica y de señal, cruce del nivel cero, divergencia y divergencia doble.

1.1 Nuevo modelo para el indicador.

Supongamos que los datos del modelo de mercado para el indicador no nos convienen y queremos introducir nuestro propio modelo nuevo para el indicador. Descripción de un nuevo modelo de mercado: si el indicador MACD se encuentra por debajo de línea cero y los valores aumentan, significa que podemos suponer el crecimiento posterior y podemos abrir una posición larga.

Dibujo 1: Modelo del posible crecimiento del indicador 

Dibujo 1: Modelo del posible crecimiento del indicador

si el indicador MACD se encuentra por debajo de la línea cero y sus valores disminuyen, significa que podemos suponer su posterior disminución y podemos abrir una posición corta:

 Dibujo 2: Modelo de la posible disminución del indicador

Dibujo 2: Modelo del posible descenso del indicador 

Bien, ya hemos decidido qué indicador de usuario vamos a elegir. Ya hemos pensado y descrito el nuevo modelo comercial del indicador. Empecemos a escribir el código.

 

2. Escribimos el generador de señales comerciales de nuestro indicador de usuario.

Nuestro indicador es heredero directo del tipo básico CExpertSignal. El tipo básico CExpertSignal es una clase destinada a la creación de generadores de señales comerciales. El tipo CExpertSignal contiene un conjunto de métodos públicos (es decir, accesibles desde el exterior). Consultando estos métodos, el experto puede conocer la opinión del generador de señales comerciales sobre la entrada en el mercado o en uno u otro lado.

Como nosotros creamos nuestro propio generador de señales comerciales, debemos heredarlo del tipo CExpertSignal y determinar de nuevo (completar con nuestro propio código) los métodos virtuales correspondientes.

 

3. Creamos el tipo de generador de señales comerciales

El generador de señales comerciales debe encontrarse por defecto en la carpeta ...MQL5\Include\Expert\Signal. Para no llenar la carpeta de cosas innecesarias ...\Signal crearemos la biblioteca estándar en el directorio ...\Expert carpeta propia \MySignals:

Dibujo 3. Creamos la carpeta propia MySignals  

Dibujo 3. Creamos la carpeta propia MySignals 

El siguiente paso es crear un archivo incorporado con la ayuda de la Guía MQL5. Elija en el menú de archivo MetaEditor el punto "Crear" y marque el punto "Archivo incorporado (*.mqh)".

Dibujo 4. Guía MQL5. Creando un archivo incorporado 

Dibujo 4. Guía MQL5. Creando un archivo incorporado

Indicamos la clase de nuestro generador de señales MySignal. El camino hasta nuestra clase será el siguiente: Include\Expert\MySignals\MySignal. Indicamos esto:

Dibujo 5. Guía MQL5. Ubicación del archivo incorporado 

Dibujo 5. Guía MQL5. Ubicación del archivo incorporado

Después de pulsar el botón "Listo" la Guía MQL5 generará una plantilla vacía. Desde este momento ya podemos trabajar en lo sucesivo utilizando Copy-Paste. Quisiera llamar la atención sobre el hecho de que el contenido interno de todas las señales de la biblioteca Estándar es prácticamente idéntico. Las diferencias residen únicamente en los variados algoritmos de definición de los modelos comerciales.

Por eso, recomiendo tomar cualquier archivo de señal de la carpeta  \Include\Expert\Signal, copiar todo su contenido y pegarlo en la propia plantilla. Después de esto hay que comenzar a redactar el archivo obtenido del generador de señales comerciales.

 

4. Descripción de nuestro tipo de generador de señales comerciales

En calidad de plantilla he cogido el archivo \Include\Expert\Signal\SignalEnvelopes.mqh.  he seleccionado todo menos el encabezamiento:
//+------------------------------------------------------------------+
//|                                              SignalEnvelopes.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+

y lo he pegado en nuestra plantilla prácticamente vacia MySignal.mqh. Aquí tenemos el resultado: 

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2012, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalEnvelopes : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

public:
                     CSignalEnvelopes(void);
                    ~CSignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalEnvelopes::~CSignalEnvelopes(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+

Preste atención a la línea 6:

#include <Expert\ExpertSignal.mqh>

con esto estamos dando la orden al procesador de incluir en nuestra plantilla un tipo básico para la creación de un generador de señales comerciales CExpertSignal.

Continuamos con la redacción de la plantilla. Para que nuestra plantilla sea visible para la Guía MQL5 es necesario cambiar la descripción de nuestro tipo:

//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+

Bien, sigamos por orden. La línea

//| Title=Signals of indicator 'Envelopes'                           |

 se refiere a bajo qué nombre será visible nuestro tipo de señales en la Guía MQL5. Cambiamos este nombre aproximadamente así:

//| Title=Señal del indicador 'Indicador de usuario'             |

La línea siguiente: 

//| Name=Envelopes                                                   |

se refiere al nombre para la descripción de las variables de nuestro tipo de señales comerciales. Esta descripción será utilizada por la Guía MQL5. Redactamos la línea y obtenemos:

//| Name=MyCustomIndicator                                           |

La línea siguiente:

//| ShortName=Envelopes                                              |

Damos a este parámetro el mismo nombre:

//| ShortName=MyCustomIndicator                                      |

En la siguiente línea se asigna el nombre del tipo:

//| Class=CSignalEnvelopes                                           |

Renombramos este parámetro:

//| Class=CSignalMyCustInd                                           |

El siguiente parámetro lo dejamos sin cambio alguno.

//| Page=signal_envelopes                                            |

El siguiente grupo de parámetros es responsable de la descripción de los parámetros del indicador, sobre cuya base se crea el generador de señales comerciales. Como ya he dicho antes, en calidad de indicador de usuario utilizaré el indicador ...MQL5\Indicators\Examples\MACD.mq5. Este indicador tiene los siguientes parámetros:

//--- input parameters
input int                InpFastEMA=12;               // Fast EMA period
input int                InpSlowEMA=26;               // Slow EMA period
input int                InpSignalSMA=9;              // Signal SMA period
input ENUM_APPLIED_PRICE  InpAppliedPrice=PRICE_CLOSE; // Applied price

4.1 Bloque de descripción de parámetros 

Quisiera llamar la atención sobre el hecho de que estos parámetros para el  indicador de usuario  MACD.mq5. pueden resultar otros parámetros completamente diferentes en su indicador de usuario. Lo más importante es asegurarse de que los parámetros del indicador correspondan con su descripción en el tipo de señales comerciales. Si aplicamos al indicador que estamos viendo MACD.mq5 >el bloque de descripción de parámetros en la clase de señales comerciales tendrá el aspecto que sigue:

//| Parameter=PeriodFast,int,12,Period of fast EMA                   |
//| Parameter=PeriodSlow,int,24,Period of slow EMA                   |
//| Parameter=PeriodSignal,int,9,Period of averaging of difference   |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |

Preste atención a la correspondencia entre los parámetros en el indicador y en el bloque de descripciones de tipo. Después de todos los cambios, el bloque de descripciones de nuestra clase tendrá este aspecto:

//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Señal de indicador 'Indicador de usuario'             |
//| Type=SignalAdvanced                                              |
//| Name=MyCustomIndicator                                           |
//| ShortName=MyCustomIndicator                                      |
//| Class=CSignalMyCustInd                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodFast,int,12,Period of fast EMA                   |
//| Parameter=PeriodSlow,int,24,Period of slow EMA                   |
//| Parameter=PeriodSignal,int,9,Period of averaging of difference   |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//+------------------------------------------------------------------+

En programación se considera positivo hacer comentarios sobre el propio código, ya que así será más fácil comprenderlo trascurrido cierto tiempo. Por eso cambiamos el bloque siguiente:

//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+

a una descripción aplicada sobre nuestro tipo:

//+------------------------------------------------------------------+
//| Class CSignalMyCustInd.                                          |
//| Purpose: tipo de generador de señales comerciales en base            |
//|          al indicador de usuario.                           |
//| Deriva del tipo CExpertSignal.                    |
//+------------------------------------------------------------------+

Para no confundirse con el código es mejor cambiar todos los valores de "CSignalEnvelopes" a "CSignalMyCustInd"

Dibujo 6. Cambio de CSignalEnvelopes a CSignalMyCustInd 

Dibujo 6. Cambio de CSignalEnvelopes a CSignalMyCustInd 

Y ahora un poco de teoría.

 

5. Clase CiCustom

Para seguir trabajando en la descripción del código de la clase de indicadores comerciales de indicadores de usuario, necesitaremos el tipo CiCustom. El tipo CiCustom ha sido creado especialmente para trabajar con indicadores de usuario. El tipo CiCustom posibilita la creación, configuración y acceso a los datos de los indicadores de usuario.

 

6. El tipo CIndicators.

El tipo CIndicators es un tipo diseñado para la colección de ejemplares de las clases de serie temporal e indicadores técnicos. El tipo CIndicators posibilita la creación de ejemplares de las clases de indicadores técnicos, su conservación y gestión (sincronización de datos, gestión de indicadores (handle) y memoria).

Dentro del tipo CIndicators  nos interesa el método Create. Este método crea un indicador del tipo indicado con los parámetros indicados.

 

7. Continuemos escribiendo nuestra clase de señales comerciales

El siguiente bloque de código que vamos a cambiar es el siguiente(líneas 28-42):
class CSignalMyCustInd : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

 

8. Creación de indicadores de usuario en el generador de señales comerciales

Mire el bloque de código que se encuentra más arriba. En la línea

   CiEnvelopes       m_env;            // object-indicator

se enuncia el objeto indicador de clase CiEnvelopes. CiEnvelopes es una clase para el trabajo con indicadores técnicos de la biblioteca estándar.  La clase CiEnvelopes fue creada en base a un indicador técnico de la biblioteca estándar. Nosotros estamos escribiendo un código para el generador en base a nuestro propio indicador de usuario. Y, como resulta obvio, en la biblioteca estándar no existe ninguna clase ya preparada para su indicador de usuario. Su salida es usar la clase CiCustom.

Enunciamos nuestro indicador como clase CiCustom:

   CiCustom          m_mci;            // objeto-indicador "MyCustomIndicator"

8.1 Las cuatro variables

¿Recuerda el bloque de descripción de parametros en el tipo? En esta descripción había tres parámetros. Ahora, en nuestra clase de generador, en el campo protected, enunciamos las cuatro variables para la transmisión de los valores de nuestros cuatro parámetros:

   //--- parametros configurados
   int               m_period_fast;    // "periodo de EMA rápido"
   int               m_period_slow;    // "periodo de EMA" lento
   int               m_period_signal;  // "periodo de mediación de diferencia"
   ENUM_APPLIED_PRICE m_applied;       // "tipo de precio"

El siguiente bloque de código:

   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

En este código se enuncian las variables para la transmisión del "peso" con los modelos de nuestro generador de señales comerciales. Sustituimos el bloque de "pesos" por el código siguiente:

   //--- "peso" de los modelos de mercado (0-100)
   int               m_pattern_0;      // model 0 "the oscillator has required direction"
   int               m_pattern_1;      // model 1 "el indicador crece - buy; el indicador disminuye - sell"

 

9. "Model 0"

Como usted recordará, al principio del artículo decidimos describir sólo un modelo nuevo, que generará nuestro generador de señales comerciales. En el código descrito más arriba ya describí dos modelos de mercado (model 0 y model 1). Aquí, el "model 0" es un modelo auxiliar muy importante. El "model 0" es necesario al comerciar con órdenes pospuestas. El uso del modelo "model 0" posibilita la posposición de las dichas órdenes siguiendo el precio. Comprobemos nuestro generador de señales comerciales y las siguientes condiciones:

Estas condiciones describen de manera ideal nuestro modelo. Así se desarrollarán los acontecimientos: en el momento de creación de la barra "№1" se comprueban las condiciones de nuestro modelo comercial. Tenemos que: MACD se encuentra por debajo de la línea cero, MACD está creciendo. Esto se corresponde con la señal de compra. Significa que ponemos en venta la orden pospuesta:

Dibujo 7. Lanzamos la orden pospusta buy stop  

Dibujo 7. Lanzamos la orden pospusta buy stop 

En el momento de creación de la siguiente barra "№2" la comprobación de las condiciones mostraba: MACD se encuentra por debajo de la línea de cero, pero el MACD está disminuyendo. Según nuestro modelo comercial, en este caso no existen condiciones ni para la compra, ni para la venta. Atención aquí: de acuerdo con la lógica de la clase CExpertSignal, si no existen condiciones ni para la compra, ni para la venta, significa que hay que ELIMINAR todas las órdenes pospuestas. Además, si el precio asciende bruscamente, nosotros perderemos la posibilidad de comprar de manera rentable, ya que no tendremos orden pospuesta.

Precisamente en estos casos se usa el modelo auxiliar "model 0". El modelo "model 0" se pone en funcionamiento, si se cumplen las siguientes condiciones:

Significa que se puede poner en venta la orden pospuesta. Y como la orden está puesta a una distancia de 50 puntos del precio de apertura de la barra, entonces, de facto, estamos trasladando la orden pospuesta "buy stop" por debajo siguiendo el precio:

Dibujo 8. Trasladamos la orden buy stop más abajo  

Dibujo 8. Trasladamos la orden buy stop más abajo 

De esta forma, el uso del modelo auxiliar "model 0" nos da la oportunidad de trasladar la orden pospuesta siguiendo el precio.

 

10. Sigamos cambiando el código de nuestra plantilla

El siguiente bloque de código que vamos a cambiar es: 
public:
                     CSignalMyCustInd(void);
                    ~CSignalMyCustInd(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

 

En este bloque se enuncian los métodos de configuración de los parámetros configurables, los metodos de pesos de los modelos comerciales, el método de comprobación de la configuración, el método de inicialización del indicador y los métodos de comprobación de la formación de los modelos de mercado.

Teniendo en cuenta que ya enunciamos en los parámetros configurables las cuatro variables, el bloque de los metodos tendrá la apariencia siguiente:

   //--- métodos de configuración de los parámetros configurables
   void              PeriodFast(int value)               { m_period_fast=value;           }
   void              PeriodSlow(int value)               { m_period_slow=value;           }
   void              PeriodSignal(int value)             { m_period_signal=value;         }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_applied=value;               }

El siguiente código permanecerá sin cambios, a excepción de la traducción:

   //--- métodos de configuración de "pesos" de los modelos de mercado
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- método de comprobación de las configuraciones
   virtual bool      ValidationSettings(void);
   //--- método de creación del indicador y la serie temporal
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- métodos de comprobación de formación
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

El siguiente bloque de código que vamos a cambiar es: 

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };

Los cambios en este bloque no serán sustanciales. Preste atención a que uso el método GetData de clase CIndicator. El nombre de los métodos los doy directamente en código:

protected:
   //--- método de inicialización del indicador
   bool              InitMyCustomIndicator(CIndicators *indicators);
   //--- métodos de obtención de datos
   //- obtención de valores del indicador
   double            Main(int ind) { return(m_mci.GetData(0,ind));      }
   //- obtención de los valores de la línea de la señal
   double            Signal(int ind) { return(m_mci.GetData(1,ind));    }
   //- diferencia entre dos valores colindantes del indicador
   double            DiffMain(int ind) { return(Main(ind)-Main(ind+1)); }
   int               StateMain(int ind);
   double            State(int ind) { return(Main(ind)-Signal(ind)); }
   //- prepara los datos para la búsqueda
   bool              ExtState(int ind);
   //- busca un modelo de mercado con los parámetros indicados
   bool              CompareMaps(int map,int count,bool minimax=false,int start=0);
  };

 El siguiente bloque es el constructor

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalMyCustInd::CSignalMyCustInd(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }

En el constructor cambiamos los nombres de las variables. Sólo utilizaremos dos series: USE_SERIES_HIGH+USE_SERIES_LOW

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalMyCustInd::CSignalMyCustInd(void) : m_period_fast(12),
                                           m_period_slow(24),
                                           m_period_signal(9),
                                           m_applied(PRICE_CLOSE),
                                           m_pattern_0(10),
                                           m_pattern_1(50)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_HIGH+USE_SERIES_LOW;
  }

Cambiamos el método ValidationSettings de nuestra clase.

//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }

En el bloque de comprobaciones chequeamos la condición principal para este indicador de usuario: m_period_fast>=m_period_slow

//+------------------------------------------------------------------+
//| Comprobación de los paramétros de datos protegidos                            |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_period_fast>=m_period_slow)
     {
      printf(__FUNCTION__+": slow period must be greater than fast period");
      return(false);
     }
//--- ok
   return(true);
  }

El siguiente bloque es el de la creación del indicador:

//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }

Aplicándolo a nuestro indicador de usuario: 

//+------------------------------------------------------------------+
//| Creación de indicadores.                                            |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitIndicators(CIndicators *indicators)
  {
//--- check of pointer is performed in the method of the parent class
//---
//--- inicialización de los indicadores y las series temporales de los filtros adicionales
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- creación e inicialización de los indicadores de usuario
   if(!InitMyCustomIndicator(indicators))
      return(false);
//--- ok
   return(true);
  }

El siguiente es el bloque de inicialización de indicadores:

//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }

Primero añadimos el objeto a la colección. Luego establecemos los parámetros de nuestro indicador. Después usamos el método Create de clase CIndicators y creamos el indicador de usuario:

//+------------------------------------------------------------------+
//| Inicialización de indicadores.                                       |
//+------------------------------------------------------------------+
bool CSignalMyCustInd::InitMyCustomIndicator(CIndicators *indicators)
  {
//--- adición del objeto a la colección
   if(!indicators.Add(GetPointer(m_mci)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- introducción de los parámetros del indicador
   MqlParam parameters[4];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="Examples\\MACD.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_period_fast;
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_period_slow;
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_period_signal;
//--- inicialización del objeto
   if(!m_mci.Create(m_symbol.Name(),0,IND_CUSTOM,4,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- cantidad de búferes
   if(!m_mci.NumBuffers(4)) return(false);
//--- ok
   return(true);
  }

El siguiente bloque es la comprobación de las condiciones para la compra:

//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalMyCustInd::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

De acuerdo con nuestra decisión sobre el modelo "model 0", se comprueban los dos modelos:  

//+------------------------------------------------------------------+
//| "Votación" sobre si el precio va a subir.                       |
//+------------------------------------------------------------------+
int CSignalMyCustInd::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
//--- check direction of the main line
   if(DiffMain(idx)>0.0)
     {
      //--- la línea principal apunta hacia arriba, y esto corrobora la posibilidad del crecimiento del precio
      if(IS_PATTERN_USAGE(0))
         result=m_pattern_0;      // "confirming" signal number 0
      //--- if the model 1 is used, look for a reverse of the main line
      if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
         result=m_pattern_1;      // signal number 1
     }
//--- return the result
   return(result);
  }

El siguiente bloque es la comprobación de las condiciones de venta:  

//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalMyCustInd::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

De acuerdo con nuestra decisión sobre el modelo "model 0", se comprueban los dos modelos:  

//+------------------------------------------------------------------+
//| "Votación" sobre que el precio va a caer.                            |
//+------------------------------------------------------------------+
int CSignalMyCustInd::ShortCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
//--- check direction of the main line
   if(DiffMain(idx)<0.0)
     {
            //--- la línea principal apunta hacia abajo, y esto corrobora la posibilidad de la disminución del precio
      if(IS_PATTERN_USAGE(0))
         result=m_pattern_0;      // "confirming" signal number 0
      //--- if the model 1 is used, look for a reverse of the main line
      if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)>0.0)
         result=m_pattern_1;      // signal number 1
     }
//--- return the result
   return(result);
  }

 

Conclusión

Espero que con este artículo le haya ayudado a aclararse sobre cómo crear un generador de señales comerciales partiendo de su indicador de usuario.