MQL5 Wizard: Cómo enseñar a un Asesor Experto a abrir las órdenes pendientes de cualquier precio

Vladimir Karputov | 7 mayo, 2014

Introducción

Un Asesor Experto generado usando MQL5 Wizard sólo puede abrir órdenes pendientes a una distancia fija desde el precio actual. Esto significa que si la situación del mercado cambia (por ejemplo un cambio en la volatilidad del mercado), el Asesor Experto tendrá que ejecutarse otra vez con nuevos parámetros.

Esto no sería conveniente para muchos sistemas de trading. En la mayoría de los casos, el nivel de precios para órdenes pendientes está determinado de forma dinámica por un sistema de trading. Y la distancia del precio actual cambia constantemente. En este artículo, analizaremos cómo modificar un Asesor Experto generado mediante MQL5 Wizard para que pueda abrir órdenes pendientes para variar distancias del precio actual.


1. El mecanismo de apertura de órdenes pendientes en el Asesor Experto generado mediante MQL5 Wizard

Un Asesor Experto generado tendría en su encabezamiento aproximadamente el mismo código que el siguiente:

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string             Expert_Title="ExpertMySignalEnvelopes.mq5";      // Document name
ulong                    Expert_MagicNumber        =3915;        // 
bool                     Expert_EveryTick          =false;       // 
//--- inputs for main signal
input int                Signal_ThresholdOpen      =10;          // Signal threshold value to open [0...100]
input int                Signal_ThresholdClose     =10;          // Signal threshold value to close [0...100]
input double             Signal_PriceLevel         =0.0;         // Price level to execute a deal
input double             Signal_StopLevel          =85.0;        // Stop Loss level (in points)
input double             Signal_TakeLevel          =195.0;       // Take Profit level (in points)
input int                Signal_Expiration         =0;           // Expiration of pending orders (in bars)
input int                Signal_Envelopes_PeriodMA =13;          // Envelopes(13,0,MODE_SMA,...) Period of averaging
input int                Signal_Envelopes_Shift    =0;           // Envelopes(13,0,MODE_SMA,...) Time shift
input ENUM_MA_METHOD     Signal_Envelopes_Method   =MODE_SMA;    // Envelopes(13,0,MODE_SMA,...) Method of averaging
input ENUM_APPLIED_PRICE Signal_Envelopes_Applied  =PRICE_CLOSE; // Envelopes(13,0,MODE_SMA,...) Prices series
input double             Signal_Envelopes_Deviation=0.2;         // Envelopes(13,0,MODE_SMA,...) Deviation
input double             Signal_Envelopes_Weight   =1.0;         // Envelopes(13,0,MODE_SMA,...) Weight [0...1.0]
//--- inputs for money
input double             Money_FixLot_Percent      =10.0;        // Percent
input double             Money_FixLot_Lots         =0.1;         // Fixed volume
//+------------------------------------------------------------------+

Tome nota del parámetro Signal_PriceLevel. De manera predeterminada, el Asesor Experto está generado con Signal_PriceLevel=0. Este parámetro define la distancia del precio actual. Si es igual a cero, se abrirá una orden al precio actual del mercado. Para abrir una orden pendiente, debe poner un valor distinto de cero para el parámetro Signal_PriceLevel , de hecho, Signal_PriceLevel puede ser negativo o positivo.

El valor de Signal_PriceLevel es generalmente un número bastante grande. A continuación, se muestra la diferencia entre valores negativos y positivos:

Signal_PriceLevel=-50:

Fig. 1. Signal_PriceLevel=-50

Fig. 1. Signal_PriceLevel=-50

Signal_PriceLevel=50:

Fig. 2. Signal_PriceLevel=50

Fig. 2. Signal_PriceLevel=50

Así, si Signal_PriceLevel=-50, se abrirá una orden pendiente en el precio que es menos favorable que el precio actual, mientras que si Signal_PriceLevel=50, se abrirá una orden pendiente en el precio que es mejor que el precio actual.

Esta versión del Asesor Experto abre órdenes Sell Stop y Buy Stop.


2. ¿Dónde almacenamos los datos de la distancia del precio de apertura de una orden pendiente?

Echemos primero un vistazo a la siguiente figura y luego continuemos con los comentarios:

Fig. 3. Almacenamiento de los datos en la distancia del precio actual

Fig. 3. Almacenamiento de los datos en la distancia del precio actual

Interpretación de la figura antes mencionada.

El Asesor Experto es el Asesor Experto generado mediante MQL5 Wizard.

Así, el parámetro Signal_PriceLevel donde la distancia del precio actual está almacenada y que fue declarada en el Asesor Experto se pasa al objeto de la señal de la clase CExpertSignal .

La clase CExpertSignal almacena el valor de la distancia del precio actual en la variable precio_variable_m declarada con el ámbito de la clase protegida:

class CExpertSignal : public CExpertBase
  {
protected:
   //--- variables
   double            m_base_price;     // base price for detection of level of entering (and/or exit?)
   //--- variables for working with additional filters
   CArrayObj         m_filters;        // array of additional filters (maximum number of fileter is 64)
   //--- Adjusted parameters
   double            m_weight;         // "weight" of a signal in a combined filter
   int               m_patterns_usage; // bit mask of  using of the market models of signals
   int               m_general;        // index of the "main" signal (-1 - no)
   long              m_ignore;         // bit mask of "ignoring" the additional filter
   long              m_invert;         // bit mask of "inverting" the additional filter
   int               m_threshold_open; // threshold value for opening
   int               m_threshold_close;// threshold level for closing
   double            m_price_level;    // level of placing a pending orders relatively to the base price
   double            m_stop_level;     // level of placing of the "stop loss" order relatively to the open price
   double            m_take_level;     // level of placing of the "take profit" order relatively to the open price
   int               m_expiration;     // time of expiration of a pending order in bars


3. Estructura del Asesor Experto generado mediante MQL5 Wizard

El Asesor Experto consiste en varios bloques con funcionalidades diferentes.


Fig. 4. Estructura del Asesor Experto 

Fig. 4. Estructura del Asesor Experto

Interpretación de la figura de arriba:


4. Bloques del Asesor Experto para la modificación

Como pudo ver de la estructura del Asesor Experto generado mediante MQL5 Wizard, hay bloques de clase base. Las clases base forman parte de la librería estándar.

Las clases son de por sí, descendientes de otras clases base y que a su vez se componen de una o más clases base. Más abajo puede encontrar las pocas primeras líneas del código de dos clases - CExpert y CExpertSignal:

//+------------------------------------------------------------------+
//|                                                       Expert.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
#include "ExpertTrade.mqh"
#include "ExpertSignal.mqh"
#include "ExpertMoney.mqh"
#include "ExpertTrailing.mqh"
//+------------------------------------------------------------------+
.
.
.
class CExpert : public CExpertBase

y

//+------------------------------------------------------------------+
//|                                                 ExpertSignal.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
.
.
.
class CExpertSignal : public CExpertBase

Estoy totalmente en contra de cualquier modificación de las clases base:

  1. Cuando se actualiza MetaEditor, se invalidan todos los cambios que se hacen a las clases base y se restauran las mismas a su estado inicial.
  2. La herencia sería más apropiada en este caso. Pero entonces tendrá que modificar la librería estándar ENTERA.

En vez de eso, sería mejor modificar el bloque del Asesor Experto y de los módulos del generador de señal de trading, especialmente desde que nuestro sistema de trading tenga ya un módulo modificado en uso; el generador de señal de trading del indicador de envoltura.

Por lo tanto, eso esto arreglado: haremos cambios a los bloques del Asesor Experto y al bloque del generador de señal de trading.


5. La Lógica de la Implementación

El puntero se pasará del Asesor Experto al generador de señal de trading.

Para este fin,tenemos que declarar además una variable con el alcance protegido y escribir un método que almacena el puntero del Asesor Experto en la variable interna:


  Fig. 5. La Lógica de la Implementación

Fig. 5. La Lógica de la Implementación


6. Sistema de Trading

El período de tiempo del gráfico es D1. El indicador que se va a utilizar es Envelopes con el período promedio de 13 y el método de promedio exponencial. Los tipos de órdenes que el Asesor Experto puede abrir son Sell Stop y Buy Stop.

Si la barra anterior era a la alza, ponemos una orden Sell Stop. Si la barra anterior era a la baja, ponemos una orden Buy Stop. Es decir, esperamos por la retirada:

Fig. 6. Sistema de Trading

Fig. 6. Sistema de Trading

Para generar señales de trading como las requeridas por el sistema de trading, el módulo estándar de SignalEnvelopes.mqh del generador de señal de trading ha sido modificado.

Tenga en cuenta que aquí puede utilizar cualquier generador de señal de trading de la librería estándar.


7. Modificación del generador de señal de trading. Conseguir el precio de la barra

Así que, empecemos. Debo decir que prefiero guardar mis programas en MQL5 Storage.

La primera cosa que debemos hacer para comenzar modificando el generador de señal de trading es la creación de un espacio en blanco del fichero a incluir, eliminar todo y pegar el contenido del generador de señal estándar de trading del indicador de envoltura (Envolpes).

Por defecto el generador de señal de tradig debe estar localizado debajo de ...MQL5\Include\Expert\Signal. No sobrecargar la ... carpeta \Signal de la librería estándar con demasiado información, cree una nueva carpeta debajo de la carpeta ...\Expert y llámela MySignals:

Fig. 7. Creación de la carpeta MySignals

Fig. 7. Creación de la carpeta MySignals

Luego, crearemos un archivo de inclusión que utiliza MQL5 Wizard.

En MetaEditor, seleccione "Nuevo" bajo el menú Archivo y a continuación seleccione "Incluir (*.mqh)".

Fig. 8. MQL5 Wizard. Creación de un archivo de inclusión

Fig. 8. MQL5 Wizard. Creación de un archivo de inclusión

El nombre de nuestra clase de generador de señal será MySignalEnvelopes.

Y se ubicará en: Include\Expert\MySignals\MySignalEnvelopes. Lo vamos a especificar:

Fig. 9. MQL5 Wizard. Ubicación del archivo de inclusión

Fig. 9. MQL5 Wizard. Ubicación del archivo de inclusión

Después de que haga clic en "Finalizar", MQL5 Wizard generará una plantilla vacía.

El archivo generado de MySignalEnvelopes.mqh se debe entonces añadir a MQL5 Storage:

Fig. 10. MQL5 Storage. Agregar el archivo

Fig. 10. MQL5 Storage. Agregar el archivo

Una vez añadido el archivo, debemos consignar los cambios a MQL5 Storage:

Fig. 11. Almacenamiento MQL5. Consignar los cambios

Fig. 11. MQL5 Storage. Consignar los cambios

Habiendo completado los pasos mencionados antes, podemos continuar modificando nuestro generador de señal de trading.

Dado que el generador está basado en el archivo \Include\Expert\Signal\SignalEnvelopes.mqh, copiamos el contenido entero del archivo y lo pegamos en el archivo del generador, dejando sólo el encabezamiento original:

//+------------------------------------------------------------------+
//|                                            MySignalEnvelopes.mqh |
//|                              Copyright © 2013, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2013, Vladimir Karputov"
#property link      "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);
  }
//+------------------------------------------------------------------+

Ahora, vamos a trabajar en las modificaciones de algunas partes del código.

Para evitar la confusión, el código modificado será resaltado:

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

El código modificado es el código que debe copiar y pegar en el generador de señal de trading. Espero que resaltarlo le ayudará a comprender mejor el código.

Dado que estamos escribiendo nuestra propia clase del generador de señal de trading, su nombre debe ser diferente del nombre de la clase base. Por lo tanto reemplazamos CSignalEnvelopes con CMySignalEnvelopes en todo el código:

Fig. 12. Cambiar el nombre de la clase

Fig. 12. Cambiar el nombre de la clase

Para asegurarse de que la clase del generador de señal de trading aparece en MQL5 Wizard bajo su nombre, cambie el nombre de la clase en el bloque de descripción

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

a

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

Cambie el valor del período de MA

//| Parameter=PeriodMA,int,45,Period of averaging                    |

a 13 (esto es sólo mi sugerencia, puede poner cualquier valor que usted prefiera)

//| Parameter=PeriodMA,int,13,Period of averaging                    |

Además, también modificamos el parámetro de desviación

//| Parameter=Deviation,double,0.15,Deviation                        |

poniendo un valor más grande

//| Parameter=Deviation,double,1.15,Deviation                        |

Según nuestra lógica de implementación, debemos declarar una variable interna que almacenará el puntero a la señal principal.

Dado que esto debe ser una variable interna (dentro del alcance de la clase del generador de señal de trading solamente), se añadirá al bloque el siguiente código:

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
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0
   CExpertSignal    *m_signal;         // storing the pointer to the main signal

Tenga también en cuenta que borré las variables innecesarias del código. 

El método para almacenar el puntero a la señal principal será declarado en otro bloque de código; "el método de establecer el puntero a la señal principal'. Aquí, también borré algunos métodos irrelevantes.

public:
                     CMySignalEnvelopes(void);
                    ~CMySignalEnvelopes(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;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=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);
   //--- method of setting the pointer to the main signal
   virtual bool      InitSignal(CExpertSignal *signal=NULL);

Ahora especifiquemos algunos parámetros modificados en el constructor y borremos las variables que ya no se necesitan:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMySignalEnvelopes::CMySignalEnvelopes(void) : m_ma_period(13),
                                               m_ma_shift(0),
                                               m_ma_method(MODE_SMA),
                                               m_ma_applied(PRICE_CLOSE),
                                               m_deviation(1.15),
                                               m_pattern_0(50)  

At this point, we can proceed to modifying the trading signal generation logic according to our trading system.

El bloque del código responsable de una señal de compra:

int CMySignalEnvelopes::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);
  }

será como se muestra a continuación, siguiendo los cambios necesarios:

int CMySignalEnvelopes::LongCondition(void) //---buy
  {
   int result=0;
   int idx   =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close<open)
        {
         prlevel=GetPriceLevelStopp(open,Open(0));
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }

El bloque del código responsable de una señal de venta:

int CMySignalEnvelopes::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);
  }

será como se muestra a continuación, siguiendo los cambios necesarios:

int CMySignalEnvelopes::ShortCondition(void) //---sell
  {
   int result  =0;
   int idx     =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close>open)
        {
         prlevel=GetPriceLevelStopp(Open(0),open);
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }


8. Unos pocos comentarios sobre el bloque del código de Señal

Si se cumple la condición necesaria para una señal concreta, llamamos al método GetPriceLevelStopp que devuelve un número como "20" o "15"; el valor de la distancia del precio actual.

Esto es seguido por una llamada al método PriceLevel del objeto m_signal (que establece la distancia para determinar el nivel de precio de la orden pendiente). Debe recordarse que m_signal es el objeto de la clase CExpertSignal que almacena el puntero a la señal principal.

El código del método GetPriceLevelStopp se proporciona a continuación:

double CMySignalEnvelopes::GetPriceLevelStopp(double price_0,double min)
  {
   double level;
   double temp;
   temp-=(price_0-min)/PriceLevelUnit();
   level=NormalizeDouble(temp,0);
   return(level);
  }

Tenemos que declarar este método en el encabezado de la clase:

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)); }
   double            GetPriceLevelStopp(double price,double min);
  };

Otro método que necesitaremos es el método de pasar el puntero a la señal principal para la variable interna:

bool CMySignalEnvelopes::InitSignal(CExpertSignal *signal)
  {
   m_signal=signal;
   return(true);
  }

 Después de esto deberíamos crear un Asesor Experto en MQL5 Wizard e incluir en el mismo el módulo de señal "MySignalEnvelopes".

También debemos añadir la llamada del método InitSignal al código del Asesor Experto generado mediante MQL5 Wizard:

//--- Set filter parameters
   filter0.PeriodMA(Signal_Envelopes_PeriodMA);
   filter0.Shift(Signal_Envelopes_Shift);
   filter0.Method(Signal_Envelopes_Method);
   filter0.Applied(Signal_Envelopes_Applied);
   filter0.Deviation(Signal_Envelopes_Deviation);
   filter0.Weight(Signal_Envelopes_Weight);
   filter0.InitSignal(signal);
//...

Para una mejor visualización del funcionamiento del Asesor Experto, he proporcionado un vídeo corto:

El código del Asesor Experto generado mediante MQL5 Wizard, así como el código del módulo de señal, están adjuntos al artículo.

Puede ver abajo, los resultados de la prueba del Asesor Experto. Se hizo la prueba para EURUSD y USDJPY con los siguientes parámetros: período de la prueba 2013.01.01 - 2013.09.01, período de tiempo - D1, nivel Stop Loss = 85, nivel Take Profit = 195.

Fig. 13. Prueba para EURUSD en D1

Fig. 13. Prueba para EURUSD en D1

Fig. 14. Prueba para USDJPYD en D1

Fig. 14. Prueba para USDJPYD en D1


Conclusión

Hemos visto cómo podemos modificar el código del módulo de señal de trading para la implementación de la funcionalidad que nos permite configurar órdenes pendientes a cualquier distancia del precio actual: puede ser el precio de Cierre o de Apertura de la barra anterior o el valor del promedio móvil. Hay muchas opciones. Lo importante es que puede establecer cualquier precio de apertura para una orden pendiente.

El artículo ha demostrado cómo podemos acceder al puntero, y de ahí a los métodos de la clase CExpertSignal. Creo que este artículo será muy útil para los traders que operan con órdenes pendientes.