English Русский 中文 Español Deutsch 日本語
Expert Advisor Universal: Negociação em Grupo e Gestão de uma Carteira de Estratégias (Parte 4)

Expert Advisor Universal: Negociação em Grupo e Gestão de uma Carteira de Estratégias (Parte 4)

MetaTrader 5Exemplos | 22 julho 2016, 10:02
1 642 0
Vasiliy Sokolov
Vasiliy Sokolov

Tabela de Conteúdos

 

Introdução

Frequentemente precisamos criar algoritmos que devem se entender um com o outro, isto é, a operação de um algoritmo não deve ser influenciada pelo comportamento de outros algoritmos executados ao mesmo tempo. Essa situação ocorre quando você precisa combinar diversos algoritmos no módulo executável ex5. Apesar de sua aparente simplicidade, essas tarefas têm algumas "armadilhas" significativas - certas funções algorítmicos devem ser consideradas ao construir o motor das estratégias de negociação.

O motor de negociação CStrategy inclui um conjunto de algoritmos que implementam a cooperação de dua ou mais estratégias de negociação. Vamos discuti-los em detalhe na quarta parte desta série. Também vamos criar um perfil de negociação - um grupo de Expert Advisors com negociações simultâneas, a fim de diversificar os riscos de negociação. A classe CStrategyList - um pacote de diversas estratégias da classe CStrategy - pertence aos algoritmos que fornecem uma operação simultânea de estratégias. A classe permite o carregamento de apresentação das estratégias baseadas em XML, bem como criá-las dinâmicamente usando o método correspondente - uma fábrica de estratégias.

O vídeo em anexo demonstra o processo de teste de múltiplas estratégias no Testador de Estratégia do MetaTrader 5. Todas as estratégias com base no mecanismo de negociação descritas tem um painel personalizado padrão, que ajudam a controlar facilmente as estratégias separadas em linha reta do gráfico.

 

Gerenciamento da Estratégia CStrategyList

O segundo artigo da série "Expert Advisor Universal", descreveu a classe CStrategy e seus principais módulos. Através do uso desta classe e da sua funcionalidade implementada nos módulos, cada estratégia herdada mantém uma lógica de negociação unificada. No entanto, a organização de um processo de negociação com robôs é mais do que apenas uma mera execução de ordens de negociação. É importante assegurar a sua cooperação, incluindo a operação de vários algoritmos num módulo executável.

A classe especial CStrategyList é usado para este fim específico. Como você já pode imaginar a partir do nome da classe, ela fornece uma lista de estratégias do tipo CStrategy, mas sua operação é um pouco mais complicada do que o funcionamento de um pacote de dados usual. O módulo resolve as seguintes tarefas:

  • assegura o funcionamento simultâneo de várias estratégias de negociação;
  • entrega eventos de negociação para cada exemplo de estratégia;
  • desenvolve objetos de estratégia a partir de uma lista XML unificada (deserialização de dados);
  • interage com o painel personalizado usado para a configuração do EA.

Abaixo tem o código do cabeçalho da classe CStrategyList:

//+------------------------------------------------------------------+
//| Classe container para gerenciar estratégias do tipo CStrategy    |
//+------------------------------------------------------------------+
class CStrategyList
  {
private:
   CLog*       Log;                 // Carregamento
   CArrayObj   m_strategies;        // Estratégias do 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 você pode ver, a maioria dos métodos apresentados são manipuladores de eventos de negociação. Eles possuem o mesmo tipo de conteúdo. Vamos analisar um deles, o OnBookEvent:

//+------------------------------------------------------------------+
//| Envia OnBookEvent a todas as estratégias listadas                |
//+------------------------------------------------------------------+
void CStrategyList::OnBookEvent(string symbol)
  {
   for(int i=0; i<m_strategies.Total(); i++)
     {
      CStrategy *strategy=m_strategies.At(i);
      strategy.OnBookEvent(symbol);
     }
  }

Como pode ser visto a partir do conteúdo classe, ele procura por estratégias do CStrategy na lista e chama um evento apropriado a cada uma delas. O funcionamento de outros métodos de eventos é semelhante.

Além de transmitir os eventos, o CStrategyList executa procedimentos especiais no carregamento das estratégias a partir do arquivo XML. Para mais informações sobre como funciona, leia a próxima seção.

 

Carregando Estratégias de uma lista XML. Uma Carteira de Estratégias

Se um módulo executável ex5 contém vários algoritmos de negociação, precisamos de ferramentas para gerar uma carteira de estratégias. Imagine dois algoritmos com diferentes parâmetros de negociação dentro do módulo executável. Como configurar esses parâmetros? A coisa mais simples de se fazer é a retirada dos parâmetros de cada estratégia na janela de propriedades do EA. Mas o que fazer quando muitas estratégias são usadas e cada uma delas possui diversos parâmetros? Neste caso, a lista de parâmetros com diferentes modificadores, flags, strings e comentários seria enorme. A baixo está exemplo de como seria uma janela de parâmetros da negociação de um Expert Advisor com três estratégias:

Fig. 1. A lista de parâmetros da negociação do EA com três estratégias

Um Expert Advisor pode usar ainda mais estratégias. Neste caso, a lista de parâmetros pode ter um tamanho inimaginável. O segundo aspecto importante da carteira de negociação é a criação de estratégias "no fluxo". Suponha que deseja executar a mesma estratégia com dois conjuntos de parâmetros diferentes. O que devemos fazer? Obviamente, apesar dos diferentes conjuntos de parâmetros, estas duas estratégias são a mesma, embora com diferentes configurações. Em vez de criar cada uma das estratégias manualmente, podemos confiar esta tarefa a uma classe separada. A classe pode criar automaticamente um objeto de estratégia e configurá-lo corretamente.

Antes de criar uma estratégia "no fluxo", é necessário fornecer a sua descrição completa. A descrição deve conter os seguintes detalhes:

  • o nome da estratégia;
  • um único ID de estratégia ou seu número Mágico;
  • o símbolo da estratégia está sendo executado;
  • trabalhando o timeframe da estratégia;
  • uma lista de parâmetros únicos de estratégias (uma lista individual para cada uma delas).

Descrição da estratégia pode conter outras propriedades além da lista acima. A melhor maneira de fornecer tal descrição é usando o XML. A linguagem foi criado como uma ferramenta de descrição especial. Ela permite descrever convenientemente objetos complexos, de modo que um objeto como uma estratégia de negociação pode ser convertido como um documento XML de texto, um documento de texto por sua vez, pode ser convertido numa estratégia. Por exemplo, com base num documento XML, o mecanismo de negociação pode criar uma estratégia e configurar corretamente seus parâmetros. Para trabalhar com este tipo de documentos direto do MQL5, devemos usar uma biblioteca especial XML-Parser disponível no Base de Códigos.

Aqui está um exemplo da descrição XML de uma carteira que carrega três estratégias MovingAverage com diferentes parâmetros:

<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 uma das estratégias forma a unidade <Strategy>. Os seguintes atributos são especificados: Symbol, Timeframe, Magic e StrategyName. A partir do exemplo acima, vemos que cada uma das três estratégias tem seu próprio símbolo, número mágico e prazo. Além desses parâmetros necessários, outras propriedades de estratégia são especificadas na lista XML. A seção <TradeStateStart> especifica o modo de negociação no momento do lançamento da estratégia. A seção <Params> contém os parâmetros da estratégia.

No arranque, o motor de negociação tentará carregar as estratégias de negociação a partir do arquivo XML. A estratégia é carregada e criada com base neste documento, na classe CStrategyList do método LoadStrategiesFromXML. Estes são os conteúdos deste método, bem como de todos os métodos relacionados:

//+------------------------------------------------------------------+
//| Carrega estratégias a partir do arquivo XML "xml_name"           |
//| Se a flag load_curr_symbol é definida como verdadeira, carregará |  
//| as estratégias no símbolo correspondente ao                      |
//| atual símbolo CurrentSymbol()                                    |
//+------------------------------------------------------------------+
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);
     }
  }
//+------------------------------------------------------------------+
//| Análise das estratégias 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;
  }

A parte mais interessante dos métodos é a criação de uma estratégia usando o método estático especial CStrategy::GetStrategy. O nome da estratégia deve ser colocado neste método como um parâmetro. O método retorna uma instância específica da estratégia associada ao nome. O método foi idealizado como estático para permitir o acesso a ele antes mesmo do objeto da estratégia ser criado. O GetStrategy é escrito em arquivo de cabeçalho separado, porque ao contrário de outras partes do motor de negociação, você precisará editá-lo de vez em quando, adicionando novas estratégias para isto. Se você deseja que a sua estratégia seja carregada a partir do XML, o seu processo de criação deve ser adicionada diretamente a este método. O código fonte do arquivo de cabeçalho é o seguinte:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   O GetStrategy é uma fábrica de estratégias. Ele cria um objeto de estratégia correspondente a um determinado nome.
   O método está incluído num arquivo separado para fins de automação.
*/
#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;
  }

Uma vez que a estratégia foi criada, ela deve ser inicializada com os parâmetros necessários a partir da seção <Params>. Uma vez que os parâmetros de cada estratégia são únicos, não é possível inicializar estes parâmetros ao nível do sistema de negociação. Em vez disso, a classe base da estratégia pode chamar o método virtual ParseXmlParams. Se a estratégia substitui esse método e adequadamente analisa a lista de parâmetros como um nó XML a ela, ela poderá especificar os valores desejados dos seus próprios parâmetros. Como exemplo, olhe o método ParseXmlParams da estratégia CMovingAverage que negocia com base em duas médias móveis (seu algoritmo é descrito no primeiro capítulo deste artigo).

//+------------------------------------------------------------------+
//| Exemplo de estratégia clássica com base em duas Médias Móveis.   |
//| Se a MM rápida cruza a lenta de baixo para cima                  |
//| nós compramos, se de cima para baixo - nós vendemos.             |
//+------------------------------------------------------------------+
class CMovingAverage : public CStrategy
  {
   ...
public:
   virtual bool      ParseXmlParams(CXmlElement *params);
  };
//+------------------------------------------------------------------+
//| Parâmetros específicos da estratégia são analisados dentro dela  |
//| neste método, substituindo o 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;
  }

Os detalhes desta estratégia são descritos no terceiro artigo da série, que abrange o desenvolvimento de estratégias personalizadas.

Usando o mecanismo de criação de estratégia a partir de um arquivo, é possível configurar um conjunto de estratégias de uma única vez, em seguida, carregá-las a partir de um arquivo de cada vez. Você pode ir ainda mais longe e escrever um algoritmo de auto-otimização que salva os conjuntos dos parâmetros no arquivo XML. O motor de negociação irá ler este arquivo na inicialização e formará um conjunto de estratégias sobre a sua base.

 

Gerenciamento de Estratégias Usando um Painel Personalizado

Do ponto de vista do usuário, as estratégias podem ser convenientemente controladas usando um painel personalizado especial. Este painel será exibido no gráfico após anexar EA e permitirá a realização de operações simples com cada um dos algoritmos de negociação:

  • altera o modo de negociação da estratégia;
  • compra ou vende o volume necessário em vez da estratégia.

A última opção é útil se o EA não conseguiu executar a ação apropriada por algum motivo e você precisa sincronizar seu estado com a atual situação do mercado.

Descrição das classes que criam painéis personalizados e caixas de diálogo está fora do âmbito do tema discutido, pois requer um artigo separado. Descreveremos apenas os aspectos básicos relacionados a conecção do painel.

O painel de controle do Expert Advisor é implementado na classe separada CPanel que inclui vários controles, como: listas, botões e etiquetas de texto. Todas as classes para a criação da interface estão disponíveis no diretório: <data_folder>\MQL5\Include\Panel. Para garantir a operação do painel, é necessário lidar com o evento OnChartEvent diretamente no arquivo mq5 do EA. O manipulador de eventos do gráfico está localizado na classe CStrategyList, então a chamada do manipulador OnChartEvent é o suficiente:

CStrategyList Manager;
...

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

O manipulador destes eventos no CStrategyList os envia diretamente ao painel.

Com apenas um clique em qualquer botão no painel, você define a sua execução. Por exemplo, se selecionar uma estratégia a partir da lista, o índice da atual estratégia será igual ao selecionado, então você pode executar outras ações de negociação. Por exemplo, para alterar o modo de negociação da estratégia eleita, basta selecionar a opção apropriada no menu da lista suspensa dos modos de estratégia:

Fig. 2. A lista dos modos de uma estratégia selecionada

Fig. 2. A lista dos modos de uma estratégia selecionada

Compra e venda dentro do interesse da estratégia escolhida são realizadas da mesma maneira. Um ponteiro para a estratégia chama os métodos Buy eSell da classe base CStrategy. Os métodos para comprar e vender o volume são transmitidos neles. Neste caso, o número mágico nas operações realizadas corresponde ao número mágico da estratégia, por isso é impossível distinguir manualmente as negociação a partir das ações do EA.

Deve notar-se que a lógica de negociação do EA é implementado de modo que todas as posições abertas por um usuário são mantidas por este Expert Advisor no modo normal. Ele gerencia tais posições como as suas próprias posições abertas automaticamente.

 

Negociação de Expert Advisors em Grupo

Podemos montar uma carteira de estratégias de negociação. As estratégias devem conter métodos responsáveis pela análise dos parâmetros XML, ou seja, nós precisamos substituir o método ParseXmlParams. Também é necessário adicionar a criação do tipo apropriado de estratégia ao método CStrategy::GetStrategy. Por fim, será necessário criar um arquivo XML com uma lista de estratégias e seus parâmetros. Depois que a classe CStrategyList cria instâncias de estratégias e as adiciona na sua lista, o painel personalizado irá exibir essas estratégias.

Vamos criar uma carteira de estratégias que consistem dos Expert Advisors descritos acima. Exemplos de análise das configurações XML para as estratégias CMovingAverage e CChannel estão disponíveis nas seções 3.5 e 4.3.

O conteúdo do CStrategy::GetStrategy para a criação das duas estratégias será o seguinte:

//+------------------------------------------------------------------+
//|                                              StrategyFactory.mqh |
//|                                 Copyright 2015, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
/*
   O GetStrategy é uma fábrica de estratégias. Ele cria um objeto de estratégia correspondente a um determinado nome.
   O método está incluído num arquivo separado para fins de automação.
*/
#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;
  }

O toque final é substituir o método responsável pelo nome completo do EA. Realiza a estratégia dominante CMovingAverage:

//+------------------------------------------------------------------+
//| O nome exclusivo completo do Expert Advisor                      |
//+------------------------------------------------------------------+
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;
  }

Agora tudo está pronto para a criação de uma carteira de estratégias. Nossa carteira inclui quatro sistemas de negociação. Cada uma delas vai negociar o seu próprio símbolo. Duas estratégias serão baseadas no indicador MovingAverage, e outros duas vão usar o BollingerBands. Uma descrição mais detalhada dessas estratégias está disponível no artigo anterior: "Expert Advisor Universal: Estratégias Personalizadas e Classes Auxiliares de Negociação (Parte 3)".

Nossa carteira XML será a seguinte:

<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 arquivo deve ser salvo numa pasta comum de dados da plataforma MetaTrader como Strategies.xml.

Aqui está o código-fonte do módulo mq5 que cria um Expert Advisor:

//+------------------------------------------------------------------+
//|                                                       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;
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
   Manager.LoadStrategiesFromXML(StrategiesXMLFile,LoadOnlyCurrentSymbol);
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função de desinicialização do Expert                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
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);
  }

As variáveis personalizadas StrategiesXMLFile e LoadOnlyCurrentSymbol são definidas na classe CStrategyList. Elas são usados dentro desta classe para especificar a lista de estratégias a carregar e o modo que permite carregar apenas as estratégias com o símbolo igual ao nome do instrumento que o Expert Advisor está sendo executado. Observe também que alguns eventos, como OnBookEvent e OnTimer, não são utilizados. Isso significa que eles não serão usados nas estratégias personalizadas.

A compilação deve ser bem sucedida. Depois que o Expert Advisor (nomeado Agent.ex5 no projeto) está pronto para uso. Vamos tentar executá-lo no gráfico. Antes disso, temos de nos certificar de que todos os símbolos usados estão disponíveis na janela Observaçao do Mercado no terminal MetaTrader. Após um início bem sucedido, o ícone Expert Advisor irá aparecer no canto superior direito do gráfico. Outro botão é adicionadoao canto superior esquerdo do gráfico; ele maximiza o painel personalizado. Se selecionar a lista dos EAs (chamado de Agent) no painel, uma lista de quatro Expert Advisors será aberta:

Fig. 3. Lista de Expert Advisors carregados

Fig. 3. Lista de Expert Advisors carregados

A imagem apresenta a lista dos Expert Advisors formado pelo nosso arquivo XML Strategies.xml. Depois de um tempo, as estratégias iniciarão a negociação - cada estratégia no seu símbolo individual.

 

Analisando a Operação do Expert Advisor no Testador de Estratégia

Tendo gerado uma carteira de estratégias, podemos testá-las no Testador de Estratégia para nos certificarmos que funcionam corretamente. Não é necessária nenhuma ação específica adicional, porque a lista XML de estratégias está localizada na pasta de dados global, acessível através do Testador de Estratégia. Depois de lançar o módulo do EA Agent.ex5 no testador, todos os símbolos necessários serão carregados automaticamente. Cada Expert Advisor irá realizar operações de negociação seguindo suas regras de negociação individuais, e adicionalmente, desenharão o seu próprio conjunto de indicadores. O vídeo abaixo mostra o teste de uma carteira de estratégias sobre quatro instrumentos diferentes:


A simulação do CStrategy no Testador de estratégia com base nas estratégias é semelhante à negociação em tempo real usando estas estratégias. A opção de teste visual permite que você facilmente verifique a precisão das entradas e saídas das estratégias.

 

Conclusão

Nós consideramos os algoritmos que permitem a criação de conjuntos aleatórios de estratégias de negociação. Com esses conjuntos ou carteiras de estratégias, você pode escalar o processo de negociação de forma flexível e eficiente, enquanto gerencia vários algoritmos de negociação localizados no mesmo módulo executável. Os algoritmos são particularmente úteis para as estratégias que utilizam múltiplos instrumentos de negociação simultaneamente. Usando a abordagem proposta, criarmos algoritmos de negociação semelhantes é tão fácil como o desenvolvimento de estratégias de negociação convencionais.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2179

Arquivos anexados |
strategyarticle.zip (97.88 KB)
Expert Advisor Universal: Ordens Pendentes e Suporte para Cobertura de Risco (Parte 5) Expert Advisor Universal: Ordens Pendentes e Suporte para Cobertura de Risco (Parte 5)
Este artigo fornece uma descrição mais detalhada do mecanismo de negociação CStrategy. Por demanda popular dos usuários, nós adicionamos funções de apoio as ordem pendente no mecanismo de negociação. Além disso, a versão mais recente do MetaTrader 5 agora oferece suporte a contas com a opção de cobertura (hedge). O mesmo suporte foi adicionado ao CStrategy. O artigo fornece uma descrição detalhada de algoritmos para o uso de ordens pendentes, bem como dos princípios de funcionamento da classe CStrategy nas contas com a opção de cobertura (hedge) habilitada.
Interfaces Gráficas I: Animação na Interface Gráfica (Capítulo 3) Interfaces Gráficas I: Animação na Interface Gráfica (Capítulo 3)
No artigo anterior, nós começamos a desenvolver uma classe de formulário para os controles. Neste artigo, nós vamos continuar a desenvolver esta classe e preenchê-la com os métodos para mover um formulário sobre a área do gráfico. Em seguida, integraremos este componente da interface para o núcleo da biblioteca. Além disso, nós vamos garantir que os controles do formulário mudem de cor quando o cursor do mouse estiver pairando sobre eles.
Interfaces gráficas I: Funções para os Botões do Formulário e Remoção dos Elementos da Interface (Capítulo 4) Interfaces gráficas I: Funções para os Botões do Formulário e Remoção dos Elementos da Interface (Capítulo 4)
Neste artigo, nós vamos continuar desenvolvendo esta classe, adicionando os métodos que permitem gerir o formulário mediante os cliques em seus controles. Nós habilitaremos o fechamento do programa por um botão do formulário, bem como implementar a funcionalidade de minimização e maximização do mesmo.
Interfaces Gráficas I: Formulário para os Controles (Capítulo 2) Interfaces Gráficas I: Formulário para os Controles (Capítulo 2)
Neste artigo, nós vamos criar o primeiro e o principal elemento da interface gráfica - o formulário para os controles. Vários controles podem ser anexados a este formulário, podendo ser de qualquer lugar e qualquer combinação.