English Русский 中文 Deutsch 日本語 Português
Experto comercial universal: El comercio en grupo y la gestión de la cartera de estrategias (Parte 4)

Experto comercial universal: El comercio en grupo y la gestión de la cartera de estrategias (Parte 4)

MetaTrader 5Ejemplos | 18 febrero 2016, 13:29
944 0
Vasiliy Sokolov
Vasiliy Sokolov

Índice

 

Introducción

Muy a menudo es necesario crear algoritmos que deben "llevarse bien" los unos con los otros, es decir, en el funcionamiento de cada algoritmo por separado no deberá influir el funcionamiento de otros algoritmos que tenga lugar en ese mismo momento. Esta situación se produce cuando es necesario combinar varios algoritmos en un solo módulo ejecutable ex5. A pesar de su aparente sencillez, estas tareas ocultan varias "trampas" significativas: las peculiaridades algorítmicas que deben ser tenidas en cuenta al construir el motor de estrategias comerciales.

El motor comercial CStrategy incluye un conjunto de algoritmos que implementan el trabajo conjunto de dos y más estrategias comerciales. En la cuarta parte de esta serie de artículos vamos a describirlos con detalle. Asimismo, crearemos una cartera comercial, un conjunto de expertos que comercian de forma simultánea con el objetivo de diversificar los riesgos comerciales. La clase CStrategyList pertenece al tipo de algoritmos que posibilitan el funcionamiento simultáneo de varias estrategias. Se trata de un contenedor de estrategias del tipo CStrategy. Permite cargar presentaciones de estrategias en XML y crearlas dinámicamente con la ayuda del método correspondiente de la fábrica de estrategias.

Con la ayuda de un vídeo demostrativo, veremos el proceso de testeo de varias estrategias en el simulador de estrategias de MetaTrader 5. Además, todas las estrategias basadas en el motor comercial descrito se conforman por defecto en un panel de usuario, con la ayuda del cual será bastante sencillo gestionar estrategias concretas directamente en el gráfico.

 

El gestor de estrategias CStrategyList

El segundo artículo de la serie "Experto comercial universal" se dedicó a la clase básica CStrategy y los módulos principales de los que consta. Gracias a esta clase y al funcional implementado en estos módulos, cada estrategia comercial heredada de ella posee una lógica comercial unificada. Sin embargo, la organización del proceso comercial con ayuda de robots no trata simplemente de la ejecución de órdenes comerciales. Es importante asegurarse de su funcionamiento conjunto, incluyendo el funcionamiento de varios algoritmos en un solo módulo ejecutable ex5.

Precisamente para estos fines sirve la clase especial CStrategyList. Resulta sencillo adivinar que esta clase proporciona una lista de estrategias del tipo CStrategy, sin embargo, su funcionamiento es un poco más complejo que el funcionamiento de un contenedor de datos habitual. Las tareas que resuelve este módulo son las siguientes:

  • posibilitar el funcionamiento conjunto de varias estrategias comerciales;
  • suministrar eventos comerciales a cada ejemplar de la estrategia;
  • crear objetos-estrategias de la lista unificada de estrategias XML (deserialización de datos);
  • interactuar con el panel de usuario de los ajustes de los expertos.

Aquí se muestran los encabezamientos de la clase CStrategyList:

//+-------------------------------------------------------------------+
//| Clase contenedora para gestionar las estrategias de tipo CStrategy|
//+-------------------------------------------------------------------+
class CStrategyList
  {
private:
   CLog*       Log;                 // Registro
   CArrayObj   m_strategies;        // Estrategias del tipo CStrategy
   CLimits*    m_limits;
   void        ParseStrategies(CXmlElement* xmlStrategies, bool load_curr_symbol);
   void        ParseLimits(CXmlElement* xmlLimits);
   CStrBtn     StrButton;   
public:
   CStrategyList(void);
   ~CStrategyList(void);
   void LoadStrategiesFromXML(string xml_name, bool load_curr_symbol);
   bool AddStrategy(CStrategy* strategy);
   int  Total();
   CStrategy* At(int index);
   void OnTick();
   void OnTimer();
   void OnBookEvent(string symbol);
   void OnDeinit(const int reason);
   void OnChartEvent(const int id,
                     const long &lparam,
                     const double &dparam,
                     const string &sparam);
                     

  };

Como se puede ver, la mayoría de los métodos presentados en ella son manejadores de eventos comerciales. Su contenido es del mismo tipo. Echemos un vistazo a uno de ellos, OnBookEvent:

//+------------------------------------------------------------------+
//| Envía a todas las estrategias de la lista el evento OnBookEvent  |
//+------------------------------------------------------------------+
void CStrategyList::OnBookEvent(string symbol)
  {
   for(int i=0; i<m_strategies.Total(); i++)
     {
      CStrategy *strategy=m_strategies.At(i);
      strategy.OnBookEvent(symbol);
     }
  }

Como se puede ver por el contenido, ejecuta la iteración simple de las estrategias CStrategy en la lista e invoca el evento homónimo de cada una de ellas. De una forma análoga están construidos los métodos-eventos.

Aparte de la transmisión de eventos, CStrategyList también ejecuta procedimientos especiales de descarga de estrategias desde un archivo XML. En el siguiente apartado del artículo se habla con más detalle sobre cómo se organiza este proceso.

 

La carga de estrategias desde una lista XML. La cartera de estrategias

Cuando el módulo ejecutable ex5 incluye a la vez varios algoritmos comerciales, son necesarios los instrumentos de formación de la cartera de estrategias. Supongamos que en un módulo ejecutable único negocian dos algoritmos comerciales con diferentes parámetros. ¿Cómo configuramos estos parámetros? Lo más sencillo es mostrar los parámetros de cada estrategia en la ventana de propiedades del asesor. Pero, ¿qué hacer cuando hay varias estrategias y cada una de estas estrategias tiene muchos parámetros? En este caso, la lista de parámetros con diversos modificadores, banderas, líneas y comentarios crece hasta proporciones gigantescas. Por ejemplo, este es el aspecto de la ventana de parámetros de uno de los expertos, que comercia con tres estrategias diferentes:

Fig. 1. Lista de parámetros de un experto que comercia con tres estrategias

Fig. 1. Lista de parámetros de un experto que comercia con tres estrategias

Y es que la cantidad de algoritmos comerciales puede ser muy superior a tres. En este caso, la lista de parámetros puede alcanzar proporciones totalmente inimaginables. El segundo aspecto importante a la hora de comerciar con una cartera es la creación de estrategias "sobre la marcha". Supongamos que queremos iniciar la misma estrategia con dos conjuntos diferentes de parámetros. ¿Qué hacer en este caso? Resulta obvio que estas dos estrategias, a pesar de sus diferentes conjuntos de parámetros, son la misma estrategia, pero con diferentes configuraciones. En lugar de crear manualmente cada una de estas estrategias, es posible delegar esta tarea en una clase especial. Esta clase será capaz de crear automáticamente un objeto-estrategia y configurarlo de la forma necesaria.

Antes de crear una estrategia "sobre la marcha", es necesario dar una descripción completa y rigurosa de la misma. Esta descripción debe incluir lo siguiente:

  • el nombre de la estrategia;
  • el identificador único de la estrategia o su número mágico (Magic);
  • el instrumento en el que se ha iniciado la estrategia;
  • el marco temporal de trabajo con la estrategia;
  • la lista de parámetros únicos de las estrategias (cada estrategia tiene la suya propio).

Aparte de los puntos enumerados, en la descripción de las estrategias también se pueden incluir otras propiedades. Lo mejor es hacer una descripción de este tipo usando el lenguaje XML. Este lenguaje fue creado como una forma especial de describir algo. Permite muy bien describir objetos complejos, gracias a él es posible convertir un objeto, como por ejemplo una estrategia comercial, en un documento de texto XML, y también convertir un documento de texto en una estrategia. Por ejemplo, guiándose por un documento XML, el motor comercial puede crear una estrategia y configurar sus parámetros de la forma adecuada. Para trabajar con este tipo de documentos directamente desde MQL5, es necesario usar la biblioteca especial XML-Parser, ubicada en CodeBase.

Como ejemplo mostraremos la descripción en XML de una cartera que carga tres estrategias MovingAverage con parámetros diferentes:

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyOnly</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>12</FastMA>
                                <SlowMA>45</SlowMA>
                                <Shift>1</Shift>
                                <Method>MODE_EMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

Cada una de estas estrategias forma el bloque <Strategy>. En él se indican como atributos el nombre del instrumento (Symbol), el marco temporal (Timeframe), el número mágico (Magic) y el nombre de la estrategia (StrategyName). En el listing que mostramos se puede ver que cada una de las tres estrategias tiene su instrumento, número mágico y marco temporal de trabajo únicos. Además de estos parámetros obligatorios, en la lista XML se indican también otros parámetros de la estrategia. En la sección <TradeStateStart> se indica el modo comercial en el momento del inicio de la estrategia. La sección <Params> contiene los parámetros de la propia estrategia.

En el momento del inicio, el motor comercial intentará cargar las estrategias comerciales desde el archivo XML descrito más arriba. La descarga y creación inmediata de las estrategias basadas en este documento tiene lugar en la clase CStrategyList, en su método LoadStrategiesFromXML. Mostramos aquí su contenido y los métodos relacionados:

//+-------------------------------------------------------------------------------------+
//| Carga las estrategias desde el archivo transmitido en XML "xml_name"                |
//| Si la bandera load_curr_symbol está establecida con el valor verdadero, se cargarán |
//| solo aquellas estrategias cuyo símbolo corresponde al                               |
//| símbolo CurrentSymbol() actual                                                      |
//+-------------------------------------------------------------------------------------+
void CStrategyList::LoadStrategiesFromXML(string xml_name,bool load_curr_symbol)
  {
   CXmlDocument doc;
   string err;
   bool res=doc.CreateFromFile(xml_name,err);
   if(!res)
      printf(err);
   CXmlElement *global=GetPointer(doc.FDocumentElement);
   for(int i=0; i<global.GetChildCount(); i++)
     {
      CXmlElement* child = global.GetChild(i);
      if(child.GetName() == "Strategies")
         ParseStrategies(child,load_curr_symbol);
     }
  }
//+------------------------------------------------------------------+
//| Parsea las estrategias XML                                       |
//+------------------------------------------------------------------+
void CStrategyList::ParseStrategies(CXmlElement *xmlStrategies,bool load_curr_symbol)
  {
   CParamsBase *params=NULL;
   for(int i=0; i<xmlStrategies.GetChildCount(); i++)
     {
      CXmlElement *xStrategy=xmlStrategies.GetChild(i);
      if(CheckPointer(params)!=POINTER_INVALID)
         delete params;
      params=new CParamsBase(xStrategy);
      if(!params.IsValid() || (params.Symbol()!=Symbol() && load_curr_symbol))
         continue;
      CStrategy *str=CStrategy::GetStrategy(params.Name());
      if(str==NULL)
         continue;
      str.ExpertMagic(params.Magic());
      str.ExpertSymbol(params.Symbol());
      str.Timeframe(params.Timeframe());
      str.ExpertName(params.Name());
      string name=str.ExpertName();
      CXmlElement *xml_params=xStrategy.GetChild("Params");
      if(xml_params!=NULL)
         str.ParseXmlParams(xml_params);
      CXmlElement *xml_mm=xStrategy.GetChild("MoneyManagment");
      if(xml_mm!=NULL)
        {
         if(!str.MM.ParseByXml(xml_mm))
           {
            string text="Strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+") load MM from XML failed";
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      CXmlElement *xml_regim=xStrategy.GetChild("TradeStateStart");
      if(xml_regim!=NULL)
        {
         string regim=xml_regim.GetText();
         if(regim=="BuyAndSell")
            str.TradeState(TRADE_BUY_AND_SELL);
         else if(regim=="BuyOnly")
            str.TradeState(TRADE_BUY_ONLY);
         else if(regim=="SellOnly")
            str.TradeState(TRADE_SELL_ONLY);
         else if(regim=="Stop")
            str.TradeState(TRADE_STOP);
         else if(regim=="Wait")
            str.TradeState(TRADE_WAIT);
         else if(regim=="NoNewEntry")
            str.TradeState(TRADE_NO_NEW_ENTRY);
         else
           {
            string text="For strategy "+str.ExpertName()+" (Magic: "+(string)str.ExpertMagic()+
                        ") set not correctly trade state: "+regim;
            CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
            Log.AddMessage(msg);
           }
        }
      AddStrategy(str);
     }
   if(CheckPointer(params)!=POINTER_INVALID)
      delete params;
  }

El momento más interesante en el funcionamiento de estos métodos es la creación de la estrategia con ayuda del método estático especial CStrategy::GetStrategy. Como parámetro debe transmitir el nombre de la estrategia. Como valor retornado este método devolverá el ejemplar concreto de la estrategia asociado con este nombre. Este método se ha hecho estático para que haya acceso a él antes incluso del momento en el que se cree el objeto-estrategia. GetStrategy se muestra en un archivo de encabezamiento aparte, puesto que, a diferencia del resto de las partes del motor comercial, debe ser cambiado de vez en cuando, añadiéndole nuevas estrategias. Si desea que su estrategia se cargue desde un archivo XML, el procedimiento de su creación se debe añadir directamente a este método. Aquí está el código fuente de este archivo de encabezamiento:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   GetStrategy - fábrica de estrategias. Crea el objeto de la estrategia que corresponde a un nombre determinado.
   El método se muestra en un archivo aparte para que pueda ser automatizado.
*/
#include <Strategy\Strategy.mqh>
#include <Strategy\Samples\MovingAverage.mqh>
#include <Strategy\Samples\ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

Después de que la estrategia haya sido creada, se la debe analizar con los parámetros necesarios, ubicados en la sección <Params>. Dado que los parámetros de cada estrategia son únicos, no es posible inicializar estos parámetros al nivel del motor comercial. En lugar de esta clase básica de la estrategia, se puede invocar el método virtual ParseXmlParams. Si la estrategia a su vez redefine este método y parsea correctamente la lista de parámetros transmitida en él en forma de nodo XML, podrá establecer de forma independiente sus parámetros en el valor necesario. Como ejemplo, veamos el método ParseXmlParams de la estrategia CMovingAverage, que comercia con dos medias móviles, y cuyo algoritmo de funcionamiento se muestra en el primer capítulo de este artículo.

//+------------------------------------------------------------------+
//| Ejemplo de una estrategia clásica de dos medias móviles.         |
//| Si la media móvil rápida cruza la lenta de abajo hacia arriba    |
//| entonces compramos, si la cruza de arriba hacia abajo, vendemos. |
//+------------------------------------------------------------------+
class CMovingAverage : public CStrategy
  {
   ...
public:
   virtual bool      ParseXmlParams(CXmlElement *params);
  };
//+------------------------------------------------------------------+
//| Los parámetros específicos para la estrategia se analizan        |
//| en ella misma en el método dado, redefinido desde CStrategy      |
//+------------------------------------------------------------------+
bool CMovingAverage::ParseXmlParams(CXmlElement *params)
  {
   bool res=true;
   for(int i=0; i<params.GetChildCount(); i++)
     {
      CXmlElement *param=params.GetChild(i);
      string name=param.GetName();
      if(name=="FastMA")
        {
         int fastMA=(int)param.GetText();
         if(fastMA == 0)
           {
            string text="Parameter 'FastMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            FastMA.MaPeriod(fastMA);
        }
      else if(name=="SlowMA")
        {
         int slowMA=(int)param.GetText();
         if(slowMA == 0)
           {
            string text="Parameter 'SlowMA' must be a number";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         else
            SlowMA.MaPeriod(slowMA);
        }
      else if(name=="Shift")
        {
         FastMA.MaShift((int)param.GetText());
         SlowMA.MaShift((int)param.GetText());
        }
      else if(name=="Method")
        {
         string smethod=param.GetText();
         ENUM_MA_METHOD method=MODE_SMA;
         if(smethod== "MODE_SMA")
            method = MODE_SMA;
         else if(smethod=="MODE_EMA")
            method=MODE_EMA;
         else if(smethod=="MODE_SMMA")
            method=MODE_SMMA;
         else if(smethod=="MODE_LWMA")
            method=MODE_LWMA;
         else
           {
            string text="Parameter 'Method' must be type of ENUM_MA_METHOD";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.MaMethod(method);
         SlowMA.MaMethod(method);
        }
      else if(name=="AppliedPrice")
        {
         string price=param.GetText();
         ENUM_APPLIED_PRICE a_price=PRICE_CLOSE;
         if(price=="PRICE_CLOSE")
            a_price=PRICE_CLOSE;
         else if(price=="PRICE_OPEN")
            a_price=PRICE_OPEN;
         else if(price=="PRICE_HIGH")
            a_price=PRICE_HIGH;
         else if(price=="PRICE_LOW")
            a_price=PRICE_LOW;
         else if(price=="PRICE_MEDIAN")
            a_price=PRICE_MEDIAN;
         else if(price=="PRICE_TYPICAL")
            a_price=PRICE_TYPICAL;
         else if(price=="PRICE_WEIGHTED")
            a_price=PRICE_WEIGHTED;
         else
           {
            string text="Parameter 'AppliedPrice' must be type of ENUM_APPLIED_PRICE";
            CMessage *msg=new CMessage(MESSAGE_WARNING,SOURCE,text);
            Log.AddMessage(msg);
            res=false;
           }
         FastMA.AppliedPrice(a_price);
         SlowMA.AppliedPrice(a_price);
        }
     }
   return res;
  }

El funcionamiento de esta estrategia se describe con más detalle en el tercer artículo de la serie, dedicado concretamente a la escritura de estrategias de usuario.

Gracias al mecanismo de creación de estrategias a partir de un archivo, se puede configurar una vez un conjunto de estrategias, descargándolo después cada vez desde el archivo. Podemos seguir adelante y escribir un algoritmo que se optimice por sí mismo y que guarde los conjuntos de parámetros de sus pasadas en un archivo XML. Al comenzar, el motor comercial leerá este archivo y formulará un conjunto de estrategias basándose en él.

 

La gestión de estrategias con la ayuda del panel de usuario

Desde el punto de vista del usuario, gestionar las estrategias es algo cómodo a través del panel de usuario. Este panel aparecería en el gráfico después del inicio del experto y permitiría realizar operaciones sencillas con cada uno de los algoritmos comerciales:

  • cambiar el modo comercial de la estrategia;
  • comprar o vender el volumen necesario en lugar de la estrategia.

La última opción es útil si el experto por alguna razón no realizó las acciones adecuadas y su estado debe ser sincronizado con la situación actual del mercado.

La descripción de las clases que crean paneles de usuario y ventanas de diálogo, está más allá del alcance del tema estudiado y merece un artículo aparte. Nos limitaremos a dar una descripción de los aspectos más básicos relacionados con la conexión del panel.

El panel de gestión de expertos se implementa en una clase aparte, CPanel, que a su vez incluye diferentes elementos de gestión, tales como una lista, botones y etiquetas de texto. Todas las clases para la creación de la interfaz gráfica se encuentran en el catálogo <catálogo_de_datos>\MQL5\Include\Panel. Para que el panel funcione, es necesario procesar el evento OnChartEvent directamente en el archivo del experto mq5. El propio manejador de eventos en el gráfico está ubicado en la clase CStrategyList, por eso en la función OnChartEvent bastará con invocarlo precisamente a él:

CStrategyList Manager;
...

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

A su vez, el manejador de estos eventos en CStrategyList los enumera directamente al panel.

Al pulsar algún botón, el panel determina la acción a realizar, y acto seguido, la ejecuta. Por ejemplo, si en la lista de estrategias se elige una de las estrategias, el índice de la estrategia actual resultará igual a la estrategia elegida, y después de ello será posible hacer más acciones comerciales. Por ejemplo, se puede cambiar el modo comercial de la estrategia elegida, para ello, hay que seleccionar el punto correspondiente de lista desplegable de modos de estrategia:

Fig. 2. Lista de modos de la estrategia elegida

Fig. 2. Lista de modos de la estrategia elegida

De la misma forma funciona la compra o la venta en nombre de la estrategia elegida. El índice a la estrategia invoca a los métodos Buy y Sell de la clase básica CStrategy, que a su vez compran y venden el volumen que se les ha transmitido. Además, al realizar estas acciones comerciales, el número mágico corresponde al número mágico de la propia estrategia, y distinguir este comercio manual de las acciones del experto se convierte en algo imposible.

Merece la pena destacar que la lógica comercial del experto se ha hecho de tal forma que todas las posiciones abiertas por el usuario son continuadas por este experto de forma estándar. Comienza a acompañar estas posiciones exactamente de la misma forma que las posiciones abiertas por él en el modo automático.

 

El comercio de expertos en grupo

Ya podemos ensamblar la cartera de estrategias comerciales. Para ello, las estrategias escritas deben ser abastecidas con métodos que sean responsables del análisis de los parámetros XML, es decir, de redefinir el método ParseXmlParams. Asimismo, es necesario añadir la creación del tipo correspondiente de la estrategia al método CStrategy::GetStrategy. Por último, será necesario crear el archivo XML con una lista de las estrategias y sus parámetros. Después, la case CStrategyList creará ella misma los ejemplares de las estrategias y los añadirá a su lista de estrategias. El panel de usuario, en este caso, también comenzará a representar estas estrategias.

Como ejemplo, crearemos una cartera de estrategias que constará de los expertos descritos más arriba. Los ejemplos del parseo de los ajustes de XML para la estrategias CMovingAverage y CChannel se muestran en los apartados 3.5 y 4.3.

El contenido de CStrategy::GetStrategy para la creación de las dos estrategias enumeradas será como sigue:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   GetStrategy - fábrica de estrategias. Crea el objeto de la estrategia que corresponde a un nombre determinado.
   El método se muestra en un archivo aparte para que pueda ser automatizado.
*/
#include <Strategy\Strategy.mqh>
#include <Strategy\Samples\MovingAverage.mqh>
#include <Strategy\Samples\ChannelSample.mqh>

CStrategy *CStrategy::GetStrategy(string name)
  {
   if(name=="MovingAverage")
      return new CMovingAverage();
   if(name=="BollingerBands")
      return new CChannel();
   CLog *mlog=CLog::GetLog();
   string text="Strategy with name "+name+" not defined in GetStrategy method. Please define strategy in 'StrategyFactory.mqh'";
   CMessage *msg=new CMessage(MESSAGE_ERROR,__FUNCTION__,text);
   mlog.AddMessage(msg);
   return NULL;
  }

El último detalle será redefinir el método responsable del nombre completo del experto. Realizamos esta redefinición para la estrategia CMovingAverage:

//+------------------------------------------------------------------+
//| Nombre completo y único del experto                              |
//+------------------------------------------------------------------+
string CMovingAverage::ExpertNameFull(void)
  {
   string name=ExpertName();
   name += "[" + ExpertSymbol();
   name += "-" + StringSubstr(EnumToString(Timeframe()), 7);
   name += "-" + (string)FastMA.MaPeriod();
   name += "-" + (string)SlowMA.MaPeriod();
   name += "-" + StringSubstr(EnumToString(SlowMA.MaMethod()), 5);
   name += "]";
   return name;
  }

Ahora todo está listo para crear la cartera de estrategias. Nuestra cartera incluirá cuatro sistemas comerciales. Cada uno de ellos comerciará en su propio símbolo. Dos estrategias se basarán en MovingAverage, y otras dos en BollingerBands. Podrá ver una descripción más detallada de estas estrategias en el artículo anterior: "Experto comercial universal: Las estrategias de usuario y las clases comerciales auxiliares (Parte 3)".

Nuestra cartera XML será de la forma que sigue:

<Global>
        <Strategies>
                <Strategy Name="MovingAverage" Magic="100" Timeframe="PERIOD_M1" Symbol="Si">
                        <TradeStateStart>Stop</TradeStateStart>
                        <Params>
                                <FastMA>1</FastMA>
                                <SlowMA>3</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="MovingAverage" Magic="101" Timeframe="PERIOD_M5" Symbol="SBRF">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <FastMA>15</FastMA>
                                <SlowMA>21</SlowMA>
                                <Shift>0</Shift>
                                <Method>MODE_SMA</Method>
                                <AppliedPrice>PRICE_CLOSE</AppliedPrice>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="102" Timeframe="PERIOD_M15" Symbol="GAZR">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>30</Period>
                                <StdDev>1.5</StdDev>
                        </Params>
                </Strategy>
                <Strategy Name="BollingerBands" Magic="103" Timeframe="PERIOD_M30" Symbol="ED">
                        <TradeStateStart>BuyAndSell</TradeStateStart>
                        <Params>
                                <Period>20</Period>
                                <StdDev>2.0</StdDev>
                        </Params>
                </Strategy>
        </Strategies>
</Global>

Este archivo se debe guardar en el catálogo general de datos de la plataforma MetaTrader, con el nombre Strategies.xml.

Ahora vamos a mostrar el código fuente del propio módulo mq5, que crea el experto comercial:

//+------------------------------------------------------------------+
//|                                                       Expert.mq5 |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Strategy\StrategiesList.mqh>

CStrategyList Manager;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   Manager.LoadStrategiesFromXML(StrategiesXMLFile,LoadOnlyCurrentSymbol);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Manager.OnTick();
  }
//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
   Manager.OnBookEvent(symbol);
  }

void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
  {
   Manager.OnChartEvent(id,lparam,dparam,sparam);
  }

Las variables de usuario StrategiesXMLFile y LoadOnlyCurrentSymbol son definidas en la clase CStrategyList y se usan allí mismo para indicar la lista de estrategias que se debe cargar y el modo que permite cargar solo aquellas estrategias cuyo símbolo es igual al nombre del instrumento en el que se ha iniciado el experto. Asimismo, preste atención a que ciertos eventos del tipo OnBookEvent y OnTimer no se usan. Esto significa que tampoco llegarán a las estrategias de usuario.

La compilación debería producirse con normalidad. Después de la misma, el experto (en el proyecto se llama Agent.ex5) está listo para funcionar. Vamos a probar a iniciarlo en el gráfico. Antes de ello, es necesario asegurarse de que todos los símbolos utilizados están disponibles en la ventana de símbolos del terminal MetaTrader. Después del inicio, en la ventana superior derecha del gráfico debe aparecer el icono del experto, y en la esquina superior izquierda, un botón que abre el panel de usuario. Si en este panel elegimos la lista de expertos (está suscrita con la palabra Agent), se abrirá una lista con cuatro expertos diferentes:

Fig. 3. Lista de expertos cargados

Fig. 3. Lista de expertos cargados

Como se puede ver en la captura de pantalla, esta es precisamente la lista de expertos que formó nuestro archivo XML Strategies.xml. Después de un tiempo, las estrategias comenzarán a realizar acciones comerciales, cada estrategia en su símbolo.

 

Análisis del funcionamiento de los expertos en el simulador de estrategias

Tras formar la cartera de estrategias, podemos iniciarla en el simulador de estrategias para asegurarnos de que funciona correctamente. Para ello, deberemos realizar ciertas acciones concretas, puesto que la lista de estrategias XML se encuentra en el catálogo global de datos, accesible a través del simulador de estrategias. Si iniciamos en este el módulo Agent.ex5, todos los símbolos necesarios para el comercio se cargarán de forma automática. Cada experto realizará acciones comerciales según sus normas comerciales, dibujando su propio conjunto de indicadores. En el vídeo que presentamos más abajo, se muestra el proceso de simulación de la cartera en cuatro instrumentos diferentes:


El proceso de simulación de estrategias basadas en CStrategy no se diferencia en el simulador de estrategias prácticamente en nada con respecto al comercio según estas estrategias en el modo de tiempo real. Gracias a la posibilidad de simular en el modo visual, es bastante sencillo asegurarse de que las entradas y salidas de las estrategias sean correctas.

 

Conclusión

Hemos estudiado los algoritmos que permiten crear conjuntos aleatorios de estrategias comerciales. Con la ayuda de estos conjuntos o de las carteras de estartegias, se puede poner a escala el proceso comercial de una forma flexible y eficaz, gestionando al mismo tiempo varios algoritmos comerciales que se encuentran en un módulo ejecutable. Estos algoritmos pueden ser especialmente útiles para las estrategias que usen varios instrumentos comerciales al mismo tiempo. En el marco del enfoque propuesto, los algoritmos comerciales de este tipo son igualmente fáciles de crear que las estrategias comerciales habituales.

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

Archivos adjuntos |
strategyarticle.zip (85.76 KB)
Interfaces gráficas I: Probamos la librería en los programas de diferentes tipos y en el terminal MetaTrader 4 (Capítulo 5) Interfaces gráficas I: Probamos la librería en los programas de diferentes tipos y en el terminal MetaTrader 4 (Capítulo 5)
En el capítulo anterior de la primera parte de la serie sobre las interfaces gráficas, en la clase del formulario han sido añadidos los métodos que permiten manejar el formulario con los clics en los controles. En el presente artículo vamos a testear el trabajo realizado en diferentes tipos de programas MQL, como indicadores y scripts. En vista de que se ha planteado la tarea de diseñar una librería multiplataforma (en marco de las plataformas comerciales MetaTrader), también realizaremos las pruebas en MetaTrader 4.
Experto comercial universal: Las estrategias de usuario y las clases comerciales auxiliares (Parte 3) Experto comercial universal: Las estrategias de usuario y las clases comerciales auxiliares (Parte 3)
En este artículo continuamos con la descripción de los algoritmos del motor comercial CStrategy. En la tercera parte de esta serie de artículos se analizan con detalle ejemplos de escritura de estrategias comerciales específicas que utilizan este enfoque. Además, se presta gran atención a los algoritmos auxiliares: el sistema de registro y el acceso a los datos bursátiles con la ayuda de un indexador convencional (Close[1], Open[0], etc.).
Aserciones en los programas MQL5 Aserciones en los programas MQL5
Este artículo explica cómo utilizar aserciones en el lenguaje MQL5. Proporciona dos mecanismos de aserción a modo de ejemplo, así como una guía para implementarlas correctamente.
Interfaces gráficas I: Funciones para los botones del formulario y eliminación de los elementos de la interfaz (Capítulo 4) Interfaces gráficas I: Funciones para los botones del formulario y eliminación de los elementos de la interfaz (Capítulo 4)
En el presente artículo vamos a continuar desarrollando la clase CWindow. La clase será ampliada con los métodos que permitirán gestionar el formulario haciendo clics en sus controles. Vamos a implementar la posibilidad de cerrar el programa usando el botón en el formulario, así como minimizar y maximizar el formulario en caso de necesidad.