Programamos los modos de funcionamiento del Asesor Experto usando la programación orientada a objetos

Denis Kirichenko | 21 septiembre, 2015

Introducción

En este artículo se trata de la programación de los modos en los que puede trabajar un Asesor Experto MQL5. El objetivo del artículo consiste en describir la idea “cada modo requiere su propia implementación”. Según el autor, este enfoque permite ejecutar las tareas en diferentes etapas del desarrollo del robot comercial con la mayor eficacia.

Primero veremos de qué etapas se compone el desarrollo de un Asesor Experto (EA). Luego analizaremos los modos en los que puede trabajar un EA en MetaTrader 5 y en sus aplicaciones auxiliares. Y para terminar, propongo desarrollar la jerarquía de las clases para poner en la práctica la idea mencionada.


1. Etapas del desarrollo

El desarrollo de un robot comercial (Asesor Experto) es un proceso de varios aspectos. Aquí hay dos bloques clave: la algoritmización de la idea y el testeo (prueba). Siendo de notar que se testea tanto la lógica comercial del robot, como el mismo código del algoritmo.

Podemos esquematizar las etapas de este proceso de la siguiente manera (Fig. 1).

Fig. 1. Etapas del desarrollo e implementación de un EA

Fig. 1. Etapas del desarrollo e implementación de un EA

La quinta etapa “Trading algorítmico” corona todos los esfuerzos del desarrollador, programador, analista y otros especialistas envolucrados en este asunto. Las más de las veces todos estos papeles se desempeñan por la única persona. Que sea el trader programador.

Se puede modificar y complementar este esquema. Desde mi punto de vista, ella ilustra los momentos más importantes del proceso de desarrollo de un robot. El carácter cíclico del esquema indica que se puede mejorar y modificar el código del robot a lo largo de toda su vida.

Cabe mencionar que en cada etapa se requiere del desarrollador el uso de sus herramientas, conocimientos y sus habilidades.

Me parece que el desarrollador se encuentra con una simple matriz de opciones (Fig. 2).

Matriz de opciones

Fig. 2. Matriz de opciones

Está claro que sólo el robot que implementa la idea comercial rentable con el código de calidad tiene que llegar hasta la quinta etapa “Trading algorítmico”.


2. Modos en MQL5

El entorno MQL5 permite trabajar con el robot en diferentes modos. En total son siete. Más tarde conoceremos cada uno de ellos.

Desde el punto de vista del tipo del archivo del programa, se puede destacar dos grupos:

  1. los modos que requieren el archivo del código fuente y el archivo ejecutable;
  2. los modos que requieren sólo el archivo ejecutable.

Al primer grupo le pertenecen los modos de depuración y perfilaje (análisis de rendimiento).

Otro criterio para clasificar los modos es el funcionamiento del EA en el flujo de cotizaciones reales o históricas. Todos los modos de prueba están relacionados con las cotizaciones históricas.

6 modos se definen por la programación. Dependiendo de los resultados, se puede deducir que si el EA trabaja en modo estándar (release) o no. El programa terminado (archivo con la extensión *.ex5), que ha sido codificado para trabajar en los mercados financieros, va a trabajar precisamente en este modo. El programa terminado permite dirigirse a otros modos en el Probador de Estrategias.

Vamos a crear la enumeración de los modos del trabajo del programa MQL5 con el nombre ENUM_MQL_MODE:

//+------------------------------------------------------------------+
//| Modo MQL                                                         |
//+------------------------------------------------------------------+
enum ENUM_MQL_MODE
  {
   MQL_MODE_RELEASE=0,       // Estándar
   MQL_MODE_DEBUG=1,         // Depuración
   MQL_MODE_PROFILER=2,      // Perfilaje  
   MQL_MODE_TESTER=3,        // Testeo
   MQL_MODE_OPTIMIZATION=4,  // Optimización
   MQL_MODE_VISUAL=5,        // Testeo visual 
   MQL_MODE_FRAME=6,         // Reunión de frames
  };

Vamos a necesitar esta enumeración más tarde para determinar el tipo del modo de trabajo del robot.


2.1. Funciones de identificación y comprobación del modo

Vamos a escribir una simple función que recorrerá todos los modos y mostrará la información en el diario.

//+------------------------------------------------------------------+
//| Comprobación de todos los modos MQL                              |
//+------------------------------------------------------------------+
void CheckMqlModes(void)
  {
//--- si es el modo de depuración
   if(MQLInfoInteger(MQL_DEBUG))
      Print("Debug mode: yes");
   else
      Print("Debug mode: no");
//--- si es el modo del perfilaje del código
   if(MQLInfoInteger(MQL_PROFILER))
      Print("Profile mode: yes");
   else
      Print("Profile mode: no");
//--- si es el modo de prueba
   if(MQLInfoInteger(MQL_TESTER))
      Print("Tester mode: yes");
   else
      Print("Tester mode: no");
//--- si es el modo de optimización
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      Print("Optimization mode: yes");
   else
      Print("Optimization mode: no");
//--- si es el modo de prueba visual
   if(MQLInfoInteger(MQL_VISUAL_MODE))
      Print("Visual mode: yes");
   else
      Print("Visual mode: no");
//--- si es el modo de reunión de los frames de resultados de la optimización
   if(MQLInfoInteger(MQL_FRAME_MODE))
      Print("Frame mode: yes");
   else
      Print("Frame mode: no");
  }

Vamos a comprobar el trabajo de esta función para cada modo. Se puede llamarla en el manejador OnInit.

Para los propósitos del testeo, vamos a crear la plantilla del EA Test1_Modes_EA.mq5.

En los parámetros input haremos la posibilidad de especificar el modo en el que el EA va a trabajar. Aquí es muy importante indicar el modo correctamente, de lo contrario, la información será imprecisa. Pues, eso es lo que hemos obtenido.

Vemos en modo estándar (release).

CL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Modo actual: MQL_MODE_RELEASE
QD      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
KM      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
EK      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CS      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
RJ      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

Para el modo release, las banderas de los demás modos están anuladas. Es decir, la función ha identificado que no se trata de la depuración (Debug mode: no), ni del perfilaje (Profile mode: no), etc. Usando el método de negación, hemos llegado a la conclusión de que estamos trabajando en modo release.

Ahora veremos el modo de depuración.

HG      0       17:27:47.709    Test1_Modes_EA (EURUSD.e,H1)     Modo actual: MQL_MODE_DEBUG
LD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: yes
RS      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
HE      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
NJ      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
KD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
RR      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

El modo de depuración ha sido identificado correctamente.

En cualquier manual de programación se puede encontrar la información de que la depuración facilita la búsqueda y localización de los errores en el código. También nos permite ver de qué y cómo “vive” el programa. El tema de la depuración en el entorno MQL se describe con más detalles en el artículo “Depuración de programas en MQL5”.

Este modo se utiliza con mayor frecuencia durante la formalización y algoritmización de la idea comercial.

En programación, la depuración se define usando la macro IS_DEBUG_MODE o la función MQLInfoInteger(), con el identificador MQL_DEBUG.

Pasamos ahora al modo de perfilaje.

GS      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Modo actual: MQL_MODE_PROFILER
OR      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
GE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: yes
QM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
FM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GJ      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

La función ha detectado correctamente que hemos trabajado con el Perfilador.

En este modo se puede comprobar con qué rapidez funciona el programa. El perfilador mostrará la información sobre el consumo de tiempo al ejecutar los bloques del programa. Se supone que esta herramienta podrá indicar los “cuellos de botella” del algoritmo. No siempre podemos librarnos de ellos, sin embargo esta información puede ser útil.

En programación, la depuración se define usando la macro IS_PROFILE_MODE o la función MQLInfoInteger(), con el identificador MQL_PROFILER.

Veremos ahora el modo de prueba. La información aparecerá en la pestaña “Diario” del Probador de Estrategias.

EG      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Modo actual: MQL_MODE_TESTER
OS      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Debug mode: no
GJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Profile mode: no
ER      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Tester mode: yes
ED      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Optimization mode: no
NL      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Visual mode: no
EJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Frame mode: no

El modo de prueba ha sido identificado correctamente.

Este modo de trabajo del EA aparece cuando abrimos el Probador de Estrategias.

No existe ninguna macro para este modo, por eso como los medios de MQL5 podemos utilizar sólo la función MQLInfoInteger(), con identificador MQL_TESTER.

Ahora pasamos a la optimización. El diario con las entradas estará en la carpeta del agente. En mi caso la ruta ha sido la siguiente: %Program Files\MetaTrader5\tester\Agent-127.0.0.1-3000\logs

OH      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Modo actual: MQL_MODE_OPTIMIZATION
KJ      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
NO      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
FI      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
KE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
LS      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
QE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Si el modo de optimización está activado, el modo de prueba se activa automáticamente.

El modo de optimización será activado en el Probador de Estrategias si el campo “Optimización” en la pestaña Ajustes no está deshabilitado.

Para llegar a saber que el robot se testea en modo de optimización, usamos los medios de MQL5 llamando a la función MQLInfoInteger(), con identificador MQL_OPTIMIZATION.

Ahora seguimos con el modo de visualización.

JQ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Modo actual: MQL_MODE_VISUAL
JK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
KF      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
CP      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
HJ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: no
LK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: yes
KS      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Aquí también podemos ver que se utiliza el modo visual de prueba y simplemente el modo de prueba.

En este modo el EA trabaja en el Probador de Estrategias si el campo “Visualización” de la pestaña Ajustes está señalado.

Para establecer el hecho de que el programa MQL5 se prueba en modo visual, se utiliza la función MQLInfoInteger(), con identificador MQL_VISUAL_MODE.

El último modo que nos queda es el procesamiento de los frames.

HI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Modo actual: MQL_MODE_FRAME
GR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
JR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
JG      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
GM      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
HR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
MI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Es curioso que la función ha detectado sólo los modos de prueba y optimización, mientras que la bandera de los frames es igual a cero. Intentaremos pasar la llamada a la función al manejador OnTesterInit().

Obtendremos las siguientes entradas en el diario “Asesores Expertos”:

IO      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Modo actual: MQL_MODE_FRAME
GE      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
ML      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
CJ      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
QR      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
PL      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GS      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: yes

Es interesante que ahora la función ha reconocido sólo el modo de reunión de frames.

Este modo será activado en el Probador de Estrategias si el campo “Optimización” en la pestaña “Ajustes” no está deshabilitado. Como ha demostrado la experiencia, el modo se define en el cuerpo de los manejadores OnTesterInit(), OnTesterPass(), OnTesterDeinit().

La función MQLInfoInteger()  con identificador MQL_FRAME_MODE permite identificar el hecho de la prueba del robot en modo de reunión de frames.

Abajo se encuentra la función de servicio MqlMode() que indica automáticamente en qué modo trabaja el EA.

//+------------------------------------------------------------------+
//| Determinar el modo MQL actual                                    |
//+------------------------------------------------------------------+
ENUM_MQL_MODE MqlMode(void)
  {
   ENUM_MQL_MODE curr_mode=WRONG_VALUE;

//--- si es el modo de depuración
   if(MQLInfoInteger(MQL_DEBUG))
      curr_mode=MQL_MODE_DEBUG;
//--- si es el modo del perfilaje del código
   else if(MQLInfoInteger(MQL_PROFILER))
      curr_mode=MQL_MODE_PROFILER;
//--- si es el modo de prueba visual
   else if(MQLInfoInteger(MQL_VISUAL_MODE))
      curr_mode=MQL_MODE_VISUAL;
//--- si es el modo de optimización
   else if(MQLInfoInteger(MQL_OPTIMIZATION))
      curr_mode=MQL_MODE_OPTIMIZATION;
//--- si es el modo de prueba
   else if(MQLInfoInteger(MQL_TESTER))
      curr_mode=MQL_MODE_TESTER;
//--- si es el modo de reunión de los frames de resultados de la optimización
   else if(MQLInfoInteger(MQL_FRAME_MODE))
      curr_mode=MQL_MODE_FRAME;
//--- si es el modo release
   else
      curr_mode=MQL_MODE_RELEASE;
//---
   return curr_mode;
  }

Si durante la optimización y la prueba visual también se identifica la prueba estándar, entonces se debe comprobar el modo de prueba estándar después de la optimización y visualización.

Veremos el funcionamiento de la función en la segunda plantilla del EA Test2_Modes_EA.mq5. Al iniciar la plantilla, en el diario aparece una entrada. Por ejemplo, para el modo de perfilaje aparece la siguiente entrada:

HG      0       11:23:52.992    Test2_Modes_EA (EURUSD.e,H1)    Modo actual: MQL_MODE_PROFILER

Hemos analizado las particularidades de los modos de funcionamiento del Asesor Experto MQL5 con el fin de crear un modelo de las clases correspondientes a un modo especificado. En el siguiente apartado intentaremos hacerlo.


3. Plantilla del EA diseñado para trabajar en varios modos

Propongo recordar de nuevo las etapas que un robot comercial recorre durante su desarrollo, sin olvidar del programador que lo está creando.

En la fase de algoritmización, el programador utiliza más la depuración y el perfilaje. Durante las pruebas con el historial, se dirige a todos los modos inherentes al Probador de Estrategias. El modo final (release) se utiliza para tradear en línea.

Según mi parecer, un robot totalmente funcional tiene que ser multifacético. En el sentido de que los requerimientos de las etapas del desarrollo y testeo tengan que ser reflejadas de alguna manera en su código.

Entonces, manteniendo el algoritmo principal de la idea comercial y siguiéndolo, el EA va a tener ciertas diferencias en su comportamiento durante el funcionamiento en diferentes modos. El conjunto de herramientas de la Programación orientada a objetos (POO) conviene perfectamente para la implementación de esta idea.

Fig. 2. Jerarquía de las clases para un EA diseñado para trabajar en varios modos

Fig. 3. Jerarquía de las clases para un EA diseñado para trabajar en varios modos

La jerarquía de las clases con la implementación de diferentes modos está representada en la figura 3.

La clase base CModeBase que encapsula todas las clases comunes va a tener 2 herederos directos: la clase CModeRelease y la clase CModeTester. El primero va a servir de padre para las clases de depuración, y el segundo para las clases relacionadas con las pruebas con datos históricos.

Vamos a intentar desarrollar la idea de combinar el enfoque procedimental y modular a la hora de desarrollar los métodos de la clase en el contexto del tema de los modos. Como ejemplo, vamos a considerar la siguiente lógica de trading:

  1. Apertura por la señal si no hay una posición abierta;
  2. Cierre por la señal si hay posición una abierta;
  3. Trailing Stop por la señal si hay una posición abierta.

La señal comercial la vamos a detectar en el indicador estándar MACD cuando aparezca una barra nueva.

La señal de compra aparece cuando la línea principal cruza la línea de señal de abajo arriba en la zona negativa de los valores del indicador MACD (Fig. 4).

Fig. 4. Señal de compra

Fig. 4. Señal de compra

La señal de venta aparece cuando la línea principal cruza la línea de señal de arriba abajo en la zona positiva de los valores del indicador MACD (Fig. 5).

Fig. 5. Señal de venta

Fig. 5. Señal de venta

La posición va a cerrarse cuando aparece la señal opuesta o por Stop Loss que se coloca si ha sido establecido el modo de seguimiento de la posición.

La definición de la clase base CModeBase puede ser la siguiente:

//+------------------------------------------------------------------+
//| Class CModeBase                                                  |
//| Purpose: a base class for MQL-modes                              |            
//+------------------------------------------------------------------+
class CModeBase
  {
//--- === Data members === --- 
private:
   //--- a macd object & values
   CiMACD            m_macd_obj;
   double            m_macd_main_vals[2];
   double            m_macd_sig_vals[2];

protected:
   long              m_pos_id;
   bool              m_is_new_bar;
   uint              m_trailing_stop;
   uint              m_trail_step;
   //--- trade objects
   CSymbolInfo       m_symbol_info;
   CTrade            m_trade;
   CPositionInfo     m_pos_info;
   CDealInfo         m_deal_info;
   //--- mql mode
   ENUM_MQL_MODE     m_mql_mode;

   //--- a new bar object
   CisNewBar         m_new_bar;
   //--- current tick signal flag
   bool              m_is_curr_tick_signal;
   //--- close order type
   ENUM_ORDER_TYPE   m_close_ord_type;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeBase();
   void             ~CModeBase(void){};
   //--- initialization
   virtual bool      Init(int _fast_ema,int slow_ema,int _sig,ENUM_APPLIED_PRICE _app_price);
   virtual void      Deinit(void){};

   //--- Modules
   virtual void      Main(void){};

   //--- Procedures
   virtual void      Open(void){};
   virtual void      Close(void){};
   virtual void      Trail(void){};

   //--- Service
   static ENUM_MQL_MODE CheckMqlMode(void);
   ENUM_MQL_MODE     GetMqlMode(void);
   void              SetMqlMode(const ENUM_MQL_MODE _mode);
   void              SetTrailing(const uint _trailing,const uint _trail_step);

protected:
   //--- Functions
   ENUM_ORDER_TYPE   CheckOpenSignal(const ENUM_ORDER_TYPE _open_sig);
   ENUM_ORDER_TYPE   CheckCloseSignal(const ENUM_ORDER_TYPE _close_sig);
   ENUM_ORDER_TYPE   CheckTrailSignal(const ENUM_ORDER_TYPE _trail_sig,double &_sl_pr);
   //---
   double            GetMacdVal(const int _idx,const bool _is_main=true);

private:
   //--- Macros
   bool              RefreshIndicatorData(void);
   //--- Normalization
   double            NormalPrice(double d);
   double            NormalDbl(double d,int n=-1);
   double            NormalSL(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint SL,double stop);
   double            NormalTP(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint _TP,double stop);
   double            NormalLot(const double _lot);
  };

En la clase base se puede incluir lo que sea, con tal que eso sirva para las clases herederas.

Los datos del indicador MACD no estarán disponibles para los herederos. Están representados por los miembros privados.

Cabe mencionar que entre los métodos hay métodos virtuales: Main(), Open(), Close(), Trail(). Su implementación va a depender del modo actual en el que trabaja el EA. Estos métodos se quedarán vacíos para la clase base.

Además, en la clase base hay métodos que guardan la misma lógica de trading para todos los modos MQL. Les pertenecen todos los métodos de señal:

Debe tener presente que este artículo no tiene el objetivo de crear el código para todos los tipos del modo MQL. De ejemplo van a servir las clases para la prueba estándar y visual.


3.1. Modo de prueba

Después de codificar y compilar el algoritmo, suelo dirigirme al Probador de Estrategias con el fin de testear la estrategia a base de datos históricos y verificar que todo funciona tal como se ha planeado.

En la mayoría de las veces, hay que comprobar la precisión con la que el sistema implementa las señales comerciales. En cualquier caso, el objetivo base para el robot en esta fase es iniciarse y empezar a tradear.

La clase CModeTester para la prueba estándar puede ser implementada de la siguiente manera:

//+------------------------------------------------------------------+
//| Class CModeTester                                                |
//| Purpose: a class for the tester mode                             |            
//| Derives from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeTester : public CModeBase
  {
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeTester(void){};
   void             ~CModeTester(void){};

   //--- Modules
   virtual void      Main(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);
   virtual void      Trail(void);
  };

El módulo principal está implementado así:

//+------------------------------------------------------------------+
//| Módulo principal                                                 |
//+------------------------------------------------------------------+
void CModeTester::Main(void)
  {
//--- 1) cierre
   this.Close();
//--- 2) apertura
   this.Open();
//--- 3) trailing stop
   this.Trail();
  }

Vamos a crear para el modo de prueba estándar la posibilidad de imprimir en el Journal la información sobre la aparición de señales comerciales.

Luego la completamos con líneas que contienen los valores de los indicadores que se consideran como la fuente de la señal.

Abajo se muestra el extracto del Journal sobre la señal de apertura de la posición y su posterior cierre.

HE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   ---=== Señal de apertura: SELL===---
FI      0       13:34:04.118    Core 1  2014.11.14 22:15:00   Barra antepasada, principal: 0.002117; de señal: 0.002109
DL      0       13:34:04.118    Core 1  2014.11.14 22:15:00   Barra pasada, principal: 0.002001; de señal: 0.002118
LO      0       13:34:04.118    Core 1  2014.11.14 22:15:00   market sell 0.03 EURUSD.e (1.25242 / 1.25251 / 1.25242)
KH      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal #660 sell 0.03 EURUSD.e at 1.25242 done (based on order #660)
GE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal performed [#660 sell 0.03 EURUSD.e at 1.25242]
OD      0       13:34:04.118    Core 1  2014.11.14 22:15:00   order performed sell 0.03 at 1.25242 [#660 sell 0.03 EURUSD.e at 1.25242]
IK      0       13:34:04.118    Core 1  2014.11.14 22:15:00   CTrade::OrderSend: market sell 0.03 EURUSD.e [done at 1.25242]
IL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   
CJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   ---=== Señal de cierre: SELL===---
GN      0       13:34:04.118    Core 1  2014.11.17 13:30:20   Barra antepasada, principal: -0.001218; de señal: -0.001148
QL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   Barra pasada, principal: -0.001123; de señal: -0.001189
EP      0       13:34:04.118    Core 1  2014.11.17 13:30:20   market buy 0.03 EURUSD.e (1.25039 / 1.25047 / 1.25039)
FG      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal #661 buy 0.03 EURUSD.e at 1.25047 done (based on order #661)
OJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal performed [#661 buy 0.03 EURUSD.e at 1.25047]
PD      0       13:34:04.118    Core 1  2014.11.17 13:30:20   order performed buy 0.03 at 1.25047 [#661 buy 0.03 EURUSD.e at 1.25047]
HE      0       13:34:04.118    Core 1  2014.11.17 13:30:20   CTrade::OrderSend: market buy 0.03 EURUSD.e [done at 1.25047]

Nótese que en el Probador no hay journal habitual “Asesores Expertos”. Toda la información se encuentra en la pestaña “Diario” donde se registran todas las entradas sobre las acciones ejecutadas por el Probador durante las pruebas y la optimización.

Por eso hay que buscar las cadenas necesarias. Si quiere separar de alguna manera esta información, se puede escribirla en el archivo.

La estrategia para el modo de prueba estándar está implementada en el código del EA TestMode_tester.mq5.


3.2. Modo de prueba visual

A veces es necesario referirse a un gráfico en vivo y ver cómo el EA procesa la situación actual.

La visualización simple permite no sólo ver con sus propios ojos cómo el sistema de trading reacciona a los ticks, sino también comparar los modelos similares de precios al final de la prueba.

La clase CModeVisual para la prueba visual puede ser definida de la siguiente manera:

//+------------------------------------------------------------------+
//| Class CModeVisual                                                |
//| Purpose: a class for the tester mode                             |            
//| Derived from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeVisual : public CModeTester
  {
//--- === Data members === --- 
private:
   CArrayObj         m_objects_arr;
   double            m_subwindow_max;
   double            m_subwindow_min;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeVisual(void);
   void             ~CModeVisual(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);

private:
   bool              CreateSignalLine(const bool _is_open_sig,const bool _is_new_bar=true);
   bool              CreateRectangle(const ENUM_ORDER_TYPE _signal);
   void              RefreshRectangles(void);
  };

La clase contiene los miembros ocultos. El miembro de la clase m_objects_arr implementa el array dinámico del tipo CArrayObj en el que van a entrar los objetos gráficos (por ejemplo, líneas, rectángulos). Otros dos miembros de la clase (m_subwindow_max, m_subwindow_min) controlan el tamaño máximo y mínimo de la subventana del indicador.

Los métodos privados son responsables del trabajo con los objetos gráficos.

En esta clase no hay métodos Main() y Trail(). Van a invocarse sus análogos de padres CModeTester::Main() y CModeTester::Trail(), respectivamente.

En modo de prueba visual se puede crear objetos gráficos. En otros modos del Probador de Estrategias no se podrá hacerlo.

Que se dibuje en el gráfico una línea vertical roja cuando se reciba la señal de entrada, y una línea azul cuando se reciba la señal de salida. Llenaremos el espacio entre los puntos de entrada y salida con rectángulo del color correspondiente en la subventana del indicador.

Si la posición es larga, el color del rectángulo será azul claro. Si la posición es corta, el color del rectángulo será rosado (Fig. 6).

Fig. 6. Objetos gráficos en modo visual de prueba

Fig. 6. Objetos gráficos en modo visual de prueba

La altura de los rectángulos depende de los valores del máximo y mínimo de la subventana del gráfico en el momento de su creación. Para que todos los rectángulos sean iguales de tamaño, en el código hay que añadir el bloque del cambio de coordenadas de los rectángulos si las coordenadas de la subventana han cambiado.

Así, en la subventana del indicador MACD tendremos las siguientes áreas: sin color (no hay posiciones), rosado (posición corta), azul claro (posición larga).

La estrategia para el modo de prueba visual está implementada en el código del EA TestMode_visual_tester.mq5.


Conclusión

En este artículo he tratado de demostrar los recursos de los modos del terminal MetaTrader 5 y del lenguaje MQL5. Hay que decir que el enfoque multi-modo para la programación de un algoritmo de trading, por un lado, implica muchos esfuerzos, y por otro, ofrece la posibilidad de pasar consecutivamente por cada etapa de creación del futuro robot. Volveré a repetir que en este caso la POO hecha una mano al programador lo más oportunamente.

Los modos de optimización y reunión de frames serán descritosmás detalladamente en futuros artículos sobre las propiedades estáticas del sistema de trading.