English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
MQL5 Wizard: Cómo crear un módulo de señales de trading

MQL5 Wizard: Cómo crear un módulo de señales de trading

MetaTrader 5Sistemas comerciales | 3 abril 2014, 16:02
2 855 0
MetaQuotes
MetaQuotes

Introducción

MetaTrader 5 proporciona una herramienta potente para la comprobación rápida de los conceptos del trading. Se trata del generador de estrategias de trading de MQL5 Wizard (Asistente MQL). Se describe el uso del MQL5 Wizard para la creación automática de códigos de Expert Advisors en el artículo "MQL5 Wizard: Crear Expert Advisors sin programar". El hecho de que el sistema de generación del código sea abierto, le permite añadir sus propias clases de señales de trading, sistemas de gestión de dinero y módulos de trailing a las clases estándar.

Este artículo describe los principios de escritura de módulos de señales de trading para su uso durante la creación de Expert Advisors con MQL5 Wizard.

Los Expert Advisors creados con MQL5 Wizard, se basan en cuatro pilares; cuatro clases base:

Figura 1. La estructura de la clase base CExpert

Figura 1. La estructura de la clase base CExpert

La clase CExpert (o sus subclases) es el "motor" principal de un robot de trading. Una instancia de CExpert contiene una copia de cada clase: CExpertSignal, CExpertMoney y CExpertTrailing (o sus subclases):

  1. CExpertSignal es la base del generador de señales de trading. Una instancia de la clase derivada CExpertSignal, incluida en CExpert, proporciona un Expert Advisor con informaciones acerca de la posibilidad de entrar al mercado, los niveles de entrada y la colocación de las órdenes de protección, en base a unos algoritmos incorporados. La decisión final sobre la ejecución de operaciones de trading la lleva a cabo el EA.
  2. CExpertMoney es la base de los sistemas de gestión de dinero y de riesgo. Una instancia de la clase derivada CExpertMoney calcula los volúmenes para la apertura de posiciones y la colocación de órdenes pendientes. La decisión final sobre el volumen la lleva a cabo el EA.
  3. CExpertTrailing es la base del módulo del soporte de las posiciones abiertas. Una instancia de la clase derivada CExpertTrailing informa el EA sobre la necesidad de modificar los órdenes de protección de una posición. La decisión final sobre la modificación de una orden la lleva a cabo el EA.

Además, los miembros de la clase CExpert son instancias de las siguientes clases:

  • CExpertTrade (para el trading)
  • CIndicators (para el control de los indicadores y las series temporales implicados en el funcionamiento del EA)
  • CSymbolInfo (para obtener informaciones acerca del instrumento)
  • CAccountInfo (para obtener informaciones acerca del estado de la cuenta de trading)
  • CPositionInfo (para obtener informaciones acerca de las posiciones)
  • COrderInfo (para obtener informaciones acerca de las órdenes pendientes)

De aquí en adelante, con "expert" nos referimos a una instancia de CExpert o de su subclase.

Se describirá con más detalle la clase CExpert y su funcionamiento en un artículo aparte.


1. La clase base CExpertSignal

CExpertSignal es la base del generador de señales de trading. Para comunicar con el "mundo exterior", CExpertSignal dispone de una serie de métodos virtuales públicos:

Inicialización

 Descripción

virtual Init

La inicialización de la instancia de la clase proporciona la sincronización de los datos del módulo con los datos del EA.

virtual ValidationSettings

Validación de los parámetros establecidos

virtual InitIndicators

Creación e inicialización de todos los indicadores y series temporales que requiere el generador de señales de trading

Señales de apertura / inversión / cierre de posiciones

 

virtual CheckOpenLong

Generación de la señal de apertura de posición larga y definición de los niveles de entrada y colocación de órdenes de protección

virtual CheckOpenShort

Generación de la señal de apertura de posición corta y definición de los niveles de entrada y colocación de órdenes de protección

virtual CheckCloseLong

Generación de la señal de cierre de posición larga y definición del nivel de salida

virtual CheckCloseShort

Generación de la señal de cierre de posición corta y definición del nivel de salida

virtual CheckReverseLong

Generación de la señal de inversión de posición larga y definición de los niveles de inversión y colocación de órdenes de protección

virtual CheckReverseShort

Generación de la señal de inversión de posición corta y definición de los niveles de inversión y colocación de órdenes de protección

Gestión de órdenes pendientes

 

virtual CheckTrailingOrderLong

Generación de la señal de modificación de una orden pendiente de Compra y definición del nuevo precio de la orden

virtual CheckTrailingOrderShort

Generación de la señal de modificación de una orden de Venta pendiente y definición del nuevo precio de la orden

Descripción de los métodos

1.1. Inicialización de los métodos:

1.1.1 Init

Se llama al método Init() automáticamente justo después de añadir una instancia de clase al expert. Este método no requiere sobreescritura.

virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);

1.1.2 ValidationSettings

Se llama al método ValidationSettings() a partir del expert justo después de configurar todos los parámetros. Si hay algún otro parámetro de configuración, habrá que sobreescribir el método.

virtual bool ValidationSettings();

Si todas las opciones son válidas (se pueden usar), el método sobreescrito debe devolver true. Si por lo menos uno de los parámetros es incorrecto, debe devolver false (no puede seguir funcionando).

La clase base CExpertSignal no tiene parámetros ajustables, así que el método de la clase base siempre devolverá true sin llevar a cabo ninguna comprobación.

1.1.3 InitIndicators

El método InitIndicators () implementa la creación e inicialización de todos los indicadores y series temporales indispensables. Se le llama desde el expert después de configurar todos los parámetros y confirmar que son correctos. Si el generador de señales de trading usa por lo menos un indicador o serie temporal, habrá que sobreescribir el método.

virtual bool InitIndicators(CIndicators* indicators);

Hay que usar los métodos y/o series temporales con las clases de la librería estándar adecuadas. Se deben añadir los punteros de todos los indicadores y/o series temporales al conjunto de indicadores de un expert (un puntero que se le envía como un parámetro).

Si todas las operaciones con el indicador y/o serie temporal tienen éxito (su uso es viable), el método sobreescrito debe devolver true. Si falla al menos una operación con los indicadores y/o series temporales, el método tiene que devolver false (no puede seguir funcionando).

La clase base CExpertSignal no usa indicadores o series temporales, por tanto, el método de la clase base siempre devuelve true, sin llevar a cabo ninguna acción.


1.2. Los métodos de comprobación de la señal de apertura de una posición:

1.2.1 CheckOpenLong

El método CheckOpenLong() genera una señal de apertura de una posición larga, definiendo el nivel de entrada y los niveles de protección de colocación de órdenes. Se le llama mediante un expert para determinar si es necesario abrir una posición larga. Si se espera que se genere una señal de apertura de una posición larga, habrá que sobreescribir el método.

virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);

El método tiene que implementar el algoritmo de comprobación de la condición de apertura de una posición larga. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de apertura de una posición larga, así que el método de la clase base siempre devuelve false.

1.2.2 CheckOpenShort

El método CheckOpenShort() genera una señal de apertura de una posición corta, definiendo el nivel de entrada y los niveles de protección de colocación de órdenes. Se le llama mediante un expert para determinar si es necesario abrir una posición corta. Si se espera que se genere una señal de apertura de una posición corta, habrá que sobreescribir el método. 

virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);

El método tiene que implementar el algoritmo de comprobación de la condición de apertura de una posición corta. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de apertura de una posición corta, así que el método de la clase base siempre devuelve false.


1.3. Los métodos de comprobación de la señal de cierre de una posición:

1.3.1 CheckCloseLong

El método CheckCloseLong() genera una señal de cierre de una posición larga, definiendo el nivel de salida. Se le llama mediante un expert para determinar si es necesario cerrar una posición larga. Si se espera que se genere el cierre de una posición larga, habrá que sobreescribir el método.

virtual bool CheckCloseLong(double& price);

El método tiene que implementar el algoritmo de comprobación de la condición de cierre de una posición larga. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de cierre de una posición larga, así que el método de la clase base siempre devuelve false.

1.3.2 CheckCloseShort

El método CheckCloseShort() genera una señal de cierre de una posición corta, definiendo el nivel de salida. Se le llama mediante un expert para determinar si es necesario cerrar una posición corta. Si se espera que se genere el cierre de una posición corta, habrá que sobreescribir el método.

virtual bool CheckCloseShort(double& price);

El método tiene que implementar el algoritmo de comprobación de la condición de cierre de una posición corta. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de cierre de una posición corta, así que el método de la clase base siempre devuelve false.


1.4. Los métodos de comprobación de la señal de inversión de una posición:

1.4.1 CheckReverseLong

El método CheckReverseLong genera una señal de inversión de una posición larga, definiendo el nivel de inversión y los niveles de protección de colocación de órdenes. Se le llama mediante un expert para determinar si es necesario invertir una posición larga. Si se espera que se genere una señal de inversión de una posición larga, habrá que sobreescribir el método.

virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);

El método tiene que implementar el algoritmo de comprobación de la condición de inversión de una posición larga. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

En la clase base CExpertSignal se implementa el siguiente algoritmo para generar la señal de inversión de una posición larga:

  1. Comprobar si hay una señal para cerrar una posición larga.
  2. Comprobar si hay una señal para abrir una posición corta.
  3. Si ambas señales están activas (se cumplen las condiciones) y los precios de cierre y apertura coinciden, se asignan los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true.
Si no se cumple la condición, el método devuelve false.

1.4.2 CheckReverseShort

El método CheckReverseShort genera una señal de inversión de una posición corta, definiendo el nivel de inversión y los niveles de protección de colocación de órdenes. Se le llama mediante un expert para determinar si es necesario invertir una posición corta. Si se espera que se genere una señal de inversión de una posición larga mediante un algoritmo distinto al que está implementado en la clase base, habrá que sobreescribir el método.

virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);

El método tiene que implementar el algoritmo de comprobación de la condición de inversión de una posición corta. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

En la clase base CExpertSignal se implementa el siguiente algoritmo para generar la señal de inversión de una posición corta:

  1. Comprobar si hay una señal para cerrar una posición corta.
  2. Comprobar si hay una señal para abrir una posición larga.
  3. Si ambas señales están activas (se cumplen las condiciones) y los precios de cierre y apertura coinciden, se asignan los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true.

Si no se cumple la condición, el método devuelve false.


1.5. Los métodos de comprobación de la señal de modificación de una orden pendiente:

1.5.1 CheckTrailingOrderLong

El método CheckTrailingOrderLong() genera la señal de modificación de una orden de Compra pendiente, definiendo un nuevo precio de la orden. Se le llama mediante un expert para determinar si es necesario modificar la orden de Compra pendiente. Si se espera que se genere una señal de modificación de una orden de Compra pendiente, habrá que sobreescribir el método.

virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)

El método tiene que implementar el algoritmo de comprobación de la condición de modificación de una orden de Compra pendiente. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de modificación de una orden de Compra pendiente, así que el método de la clase base siempre devuelve false.

1.5.2 CheckTrailingOrderShort

El método CheckTrailingOrderShort() genera la señal de modificación de una orden de Venta pendiente, definiendo un nuevo precio de la orden. Se le llama mediante un expert para determinar si es necesario modificar la orden de Venta pendiente. Si se espera que se genere una señal de modificación de una orden de Venta pendiente, habrá que sobreescribir el método.

virtual bool CheckTrailingOrderShort(COrderInfo* order, double& price)

El método tiene que implementar el algoritmo de comprobación de la condición de modificación de una orden de Venta pendiente. Si se cumple la condición, hay que asignar los valores correspondientes a las variables price, sl, tp y expiration (cuyas referencias se envían como parámetros) y el método tiene que devolver true. Si no se cumple la condición, el método tiene que devolver false.

La clase base CExpertSignal no tiene incluido un algoritmo para la generación de la señal de modificación de una orden de Venta pendiente, así que el método de la clase base siempre devuelve false.


2. Desarrolle su propio generador de señales de trading

Ahora, tras haber repasado la estructura de la clase base CExpertSignal, puede empezar a crear su propio generador de señales de trading.

Como se ha mencionado anteriormente, la clase CExpertSignal es un conjunto de métodos virtuales públicos, cuyo uso permite al expert conocer el criterio del generador de señales de trading acerca de la entrada al mercado en una dirección u otra.

Por consiguiente, nuestro objetivo principal es crear nuestra propia clase de un generador de señales de trading, derivándola de la clase CExpertSignal y sobreescribiendo los métodos virtuales correspondientes con la implementación de los algoritmos necesarios.

Nuestro segundo objetivo (de igual importancia) es hacer que nuestra clase sea "visible" para MQL5 Wizard. Pero lo primero es lo primero.

2.1. Creación de la clase del generador de señales de trading

Comencemos:

En primer lugar, creamos (por ejemplo, mediante el mismo MQL5 Wizard) un archivo de inclusión con la extensión mqh.

Seleccione "Nuevo" (Create) a partir del menú Archivo (o pulse la combinación del teclado Ctrl+N) y elija la creación de un archivo de inclusión:

Figura 2. Crear un archivo de inclusión mediante MQL5 Wizard.

Figura 2. Crear un archivo de inclusión mediante MQL5 Wizard

Cabe señalar que, con el fin de que MQL5 Wizard pueda "reconocer" al archivo como un generador de señales, hay que crearlo en la carpeta Include\Expert\Signal\.

Para evitar conflictos con la librería estándar, creamos nuestra propia carpeta Include\Expert\Signal\MySignals, en la cual creamos el archivo SampleSignal.mqh, especificando los siguientes parámetros en MQL5 Wizard:

Figura 3. Configuración de la ubicación del archivo de inclusión

Figura 3. Configuración de la ubicación del archivo de inclusión

Como resultado del funcionamiento de MQL5 Wizard obtenemos la siguiente estructura:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

Lo que viene a continuación es un trabajo "manual". Eliminamos las partes innecesarias y añadimos las que necesitamos (incluir el archivo ExpertSignal.mqh de la librería estándar y la descripción de la clase que está vacía ahora).

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator.                      |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Ahora es necesario elegir los algoritmos.

Nuestro generador de señales de trading se basa en el modelo extendido "el precio cruza el promedio móvil". Pero hacemos una hipótesis más: "Después de cruzar el promedio móvil, el precio retrocede y solo entonces va en la dirección correcta." Recoja este planteamiento en su archivo.

En términos generales, no escatime en comentarios cuando escribe algo. Después de algún tiempo, la lectura de un código con sus comentarios resultará más cómoda.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Class CSampleSignal.                                             |
//| Purpose: Class of trading signal generator when price            |
//|          crosses moving average,                                 |
//|          entering on the subsequent back movement.               |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Vamos a definir ahora los datos necesarios para la toma de decisiones relacionadas con la generación de señales de trading. En nuestro caso, se trata del precio de apertura y el precio de cierre de la barra anterior, así como el valor del promedio móvil en la misma barra anterior.

Para acceder a estos datos, usamos las clases de la librería estándar CiOpen, CiClose y CiMA. Hablaremos de los indicadores y las series temporales más adelante.

Mientras tanto, vamos a definir una lista de ajustes para nuestro generador. En primer lugar, tenemos que configurar el promedio móvil. Estos parámetros incluyen el período, el desplazamiento a lo largo del eje temporal, el método empleado para calcular el promedio y el objeto del promedio. En segundo lugar, tenemos que configurar el nivel de entrada y los niveles de colocación de órdenes de protección, así que el tiempo de vigencia de la orden pendiente, ya que vamos a trabajar con órdenes pendientes.

Se almacenan todos los ajustes del generador en los miembros de datos protegidos de la clase class. Se implementará el acceso a estos ajustes mediante los métodos públicos correspondientes.

Vamos a incluir estos cambios en nuestro archivo:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;           // level to place a pending order relative to the MA
   double             m_stop_loss;       // level to place a stop loss order relative to the open price
   double             m_take_profit;     // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
  };
//+------------------------------------------------------------------+

Ya que estamos usando miembros de datos protegidos, tenemos que añadir un constructor de clase, en el cual vamos a inicializar estos datos con los valores por defecto.

Para comprobar los parámetros, vamos a sobreescribir el método virtual ValidationSettings según la descripción de la clase base.

Descripción de la clase:

class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
   //--- Methods to validate the parameters
   virtual bool       ValidationSettings();
  };

Implementación del método ValidationSettings():


//+------------------------------------------------------------------+
//| Validation of the setup parameters.                              |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+

Ahora que hemos completado la mayor parte de las tareas preliminares, vamos a hablar de indicadores y series temporales.

Los indicadores y las series temporales representan la fuente de información principal para la toma de decisión (por supuesto, puede usar el lanzamiento de monedas o las fases lunares, pero su normalización es muy difícil).

Como hemos mencionado anteriormente, necesitamos los siguientes datos para la toma de decisiones: el precio de apertura de la barra anterior, el precio de cierre de la barra anterior y el valor del promedio móvil en la misma barra anterior.

Para poder acceder a estos datos, usaremos las siguientes clases de la librería estándar:

  • CiOpen - para acceder al precio de apertura de la barra anterior,
  • CiClose - para acceder al precio de cierre de la barra anterior,
  • CiMA   - para acceder al valor del promedio móvil en la barra anterior.

Los lectores pueden preguntar: ¿Por qué utilizar el indicador o las series temporales, "empaquetados" en una clase, con el fin de obtener un solo número?

Hay un sentido implícito, que vamos a mostrar ahora.

¿Cómo usar los datos de un indicador o serie temporal?

En primer lugar, tenemos que crear un indicador.

En segundo lugar, tenemos que copiar la cantidad necesaria de datos en un buffer intermedio.

En tercer lugar, tenemos que comprobar si se ha completado la copia.

Solo después de estos tres pasos, se pueden utilizar los datos.

Mediante las clases de la librería estándar, puede evitar la necesidad de crear un indicador, preocuparse por la disponibilidad de buffers intermedios y la carga de datos o la liberación de un controlador. El objeto de la clase correspondiente hará esto. Se generarán todos los indicadores necesarios mediante nuestro generador de señales durante la etapa de inicialización y se proporcionarán todos los indicadores con el buffer temporal necesario. Además, una vez añadimos un objeto de indicador o serie temporal a la colección (el objeto de una clase especial), puede dejar de preocuparse por la relevancia de los datos (se actualizarán los datos automáticamente mediante el expert).

Colocaremos los objetos de estas clases en los miembros de datos protegidos. Para cada objeto, creamos un método de inicialización y un método de acceso a los datos.

Vamos a sobreescribir el método virtual InitIndicators (según la descripción de la clase base).

Descripción de la clase:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values om the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementación de los métodos InitIndicators, InitMA, InitOpen e InitClose:

//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+

Se han completado todas las tareas preliminares. Como puede observar, el contenido de nuestra clase ha aumentado de manera significativa.

Pero ahora estamos preparados para generar señales de trading.

Figura 4. Señales de trading del precio cruzando el promedio móvil

Figura 4. Señales de trading del precio cruzando el promedio móvil

Vamos a examinar nuestros algoritmos otra vez, pero con más detalle.

1. Aparece la señal para comprar cuando se cumplen las siguientes condiciones en la barra anterior:

  • el precio de apertura de la barra es inferior al valor del promedio móvil,
  • el precio de cierre de la barra es superior al valor del promedio móvil,
  • el promedio móvil está creciendo.

En este caso, proponemos colocar una orden pendiente de Compra con los parámetros definidos en la configuración. Para este propósito, sobreescribimos el método virtual CheckOpenLong y le asignamos la funcionalidad correspondiente.

2. Aparece la señal para vender cuando se cumplen las siguientes condiciones en la barra anterior:

  • el precio de apertura de la barra es superior al valor del promedio móvil,
  • el precio de cierre de la barra es inferior al valor del promedio móvil,
  • el promedio móvil está disminuyendo.

En este caso, proponemos colocar una orden pendiente de Venta con los parámetros definidos en la configuración. Para este propósito, sobreescribimos el método virtual CheckOpenShort y le asignamos la funcionalidad correspondiente.

3. No vamos a generar señales para cerrar posiciones. Dejamos que se cierren las posiciones mediante Stop Loss/Take Profit.

Por consiguiente, no vamos a sobreescribir métodos virtuales CheckCloseLong y CheckCloseShort.

4. Propondremos la modificación de una orden pendiente a lo largo del promedio móvil a la "distancia" indicada en la configuración.

 Para este propósito, sobreescribimos los métodos virtuales CheckTrailingOrderLong y CheckTrailingOrderShort, asignándoles la funcionalidad correspondiente.

Descripción de la clase:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values of the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters

   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };

Implementación de los métodos CheckOpenLong, CheckOpenShort, CheckTrailingOrderLong y CheckTrailingOrderShort:

//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Así que hemos resuelto el primer problema. El código anterior es el código fuente de la clase del generador de señales de trading que satisface las necesidades de nuestra tarea principal.


2.2. Preparación de una descripción de la clase de señales de trading para MQL5 Wizard

Pasamos ahora a resolver el segundo problema. El generador de estrategias de trading MQL5 Wizard tiene que "reconocer" nuestra señal.

Hemos finalizado la primera condición necesaria: hemos colocado el archivo donde lo va a "encontrar" MQL5 Wizard. Pero esto no es suficiente. MQL5 Wizard no solo debe "encontrar" el archivo, sino que también lo tiene que "reconocer". Para ello, tenemos que añadir al texto original el descriptor de clase para MQL5 Wizard.

Un descriptor de clase es un bloque de comentarios, elaborado de acuerdo con algunas reglas.

Veamos estas reglas.

1. El bloque de comentarios tiene que comenzar con las siguientes líneas:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |

2. La siguiente línea es un descriptor de texto (lo que veremos en MQL5 Wizard al seleccionar la señal) con el formato "//| Title=<Text> |". Si el texto es demasiado largo para la línea, se puede añadir una línea más (pero no más) a continuación. 

En nuestro caso, tenemos lo siguiente:

//| Title=Signal on the crossing of a price and the MA               |
//| entering on its back movement                                    |

3. Después, está la línea con el tipo de clase indicado con el formato "//| Type=<Type> |". El campo <Type> debe tener el valor Signal (señal) (además de las señales, MQL5 Wizard reconoce otros tipos de clases).

Escribimos:

//| Type=Signal                                                      |

4. La siguiente línea con el formato "//| Name=<Name> |" representa el nombre corto de la señal (la utiliza MQL5 Wizard para generar los nombres de las variables globales del expert).

Obtenemos lo siguiente:

//| Name=Sample                                                      |

5. El nombre de la clase es un elemento importante de la descripción. En la línea con el formato "//| Class=<ClassNameа> |", el parámetro <ClassName> debe corresponder al nombre de nuestra clase:

//| Class=CSampleSignal                                              |

6. No rellanamos esta línea, pero hay que tenerla en cuenta (este es el enlace a la sección de la documentación del lenguaje):

//| Page=                                                            |

7. También hay descripciones de los parámetros de configuración de la señal.

Este es un conjunto de líneas de código (el número de líneas es igual al número de parámetros).

El formato de cada línea es "//| Parameter=<NameOfMethod>,<TypeOfParameter>,<DefaultValue> |".

A continuación, tenemos nuestro conjunto de parámetros:

//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |

8. El bloque de comentarios debe finalizar con las siguientes líneas:

//+------------------------------------------------------------------+
// wizard description end

Vamos a añadir el descriptor al código fuente.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal on crossing of the price and the MA                 |
//| entering on the back movement                                    |
//| Type=Signal                                                      |
//| Name=Sample                                                      |
//| Class=CSampleSignal                                              |
//| Page=                                                            |
//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| CSampleSignal class.                                             |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;               // object to access the values of the moving average
   CiOpen             m_open;             // object to access the bar open prices
   CiClose            m_close;            // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;        // averaging period of the MA
   int                m_shift_ma;         // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;        // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;       // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //---Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
//+------------------------------------------------------------------+
//| CSampleSignal Constructor.                                       |
//| INPUT:  No.                                                      |
//| OUTPUT: No.                                                      |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
void CSampleSignal::CSampleSignal()
  {
//--- Setting the default values
   m_period_ma  =12;
   m_shift_ma   =0;
   m_method_ma  =MODE_EMA;
   m_applied_ma =PRICE_CLOSE;
   m_limit      =0.0;
   m_stop_loss  =50.0;
   m_take_profit=50.0;
   m_expiration =10;
  }
//+------------------------------------------------------------------+
//| Validation of parameters.                                        |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Bueno, eso es todo. Ya se puede utilizar la señal.

Para que el generador de estrategias de trading MQL5 Wizard pueda usar nuestra señal, tenemos que reiniciar MetaEditor (MQL5 Wizard analiza la carpeta Include\Expert en el arranque solo).

Tras el reinicio de MetaEditor, se puede utilizar el módulo de señales de trading con MQL5 Wizard:

Figura 5. El generador de señales de trading creado en MQL5 Wizard

Figura 5. El generador de señales de trading creado en MQL5 Wizard

Ya están disponibles los parámetros de entrada especificados en la descripción de los parámetros del generador de señales de trading:

Figura 6. Los parámetros de entrada del generador de señales de trading creado en MQL5 Wizard

Figura 6. Los parámetros de entrada del generador de señales de trading creado en MQL5 Wizard

Se pueden encontrar los mejores parámetros de entrada de la estrategia de trading implementada mediante el probador de estrategias del terminal de MetaTrader 5.


Conclusión

El generador de estrategias de trading de MQL5 Wizard simplifica enormemente los procesos de pruebas de los conceptos de trading. El código del expert generado se basa en las clases de las estrategias de trading de la librería estándar, que se usan para crear determinadas clases de señales de trading, clases de gestión de dinero y riesgo y clases de soporte de posición. 

En este artículo se explica el modo de escribir su propia clase de señales de trading con la implementación de señales en el cruce del precio con el promedio móvil y la manera de incluirla en el generador de estrategias de trading deMQL5 Wizard, también se describe la estructura y el formato de la clase generada para MQL5 Wizard.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/226

Archivos adjuntos |
samplesignal.mqh (15.49 KB)
Las Tablas Electrónicas en MQL5 Las Tablas Electrónicas en MQL5
El artículo describe una clase de matrices dinámicas bidimensionales que contienen los diferentes tipos de datos en su primera dimensión. Es conveniente almacenar los datos en forma de tablas para poder resolver una gran variedad de problemas de disposición, almacenamiento y funcionamiento con información de diferentes clases. El código fuente de la clase que implementa la funcionalidad de trabajar con tablas está adjunto al artículo.
Análisis de los gráficos mediante métodos econométricos Análisis de los gráficos mediante métodos econométricos
En este artículo se describen los métodos econométricos de análisis, el análisis de la correlación y el análisis de la varianza condicional en particular. ¿Cuáles son les beneficios del método descrito en este artículo? El uso de los modelos GARCH no lineales permite la representación formal de las series analizadas desde un punto de vista matemático y crear predicciones para un número determinado de pasos.
MQL5 Wizard: Cómo crear un módulo de gestión de riesgo y dinero MQL5 Wizard: Cómo crear un módulo de gestión de riesgo y dinero
El generador de estrategias de trading de MQL5 Wizard simplifica enormemente los procesos de pruebas de los conceptos de trading. En este artículo se describe el modo de desarrollar un módulo de gestión de dinero y habilitarlo en MQL5 Wizard. Como ejemplo, vamos a considerar un algoritmo de gestión de dinero, en el cual se determina el tamaño de la operación mediante los resultados de la transacción anterior. Además, el artículo aborda la descripción del formato de la clase creada para MQL5 Wizard.
Los indicadores de las tendencias menor, intermedia y principal Los indicadores de las tendencias menor, intermedia y principal
El objetivo de este artículo es investigar las posibilidades de la automatización del trading y el análisis, en base a algunos conceptos del libro de James Hyerczyk "Pattern, Price & Time: Using Gann Theory in Trading Systems" (Modelo, precio y tiempo: el uso de la teoría de Gann en los sistemas de trading), en forma de indicadores y Expert Advisors. Sin querer ser exhaustivo, solo investigamos el "Modelo" en este artículo; la primera parte de la teoría de Gann.