English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Sistemas de negociação adaptativos e seu uso no terminal do cliente do MetaTrader 5

Sistemas de negociação adaptativos e seu uso no terminal do cliente do MetaTrader 5

MetaTrader 5Sistemas de negociação | 10 janeiro 2014, 14:18
2 003 0
MetaQuotes
MetaQuotes

Introdução

Centenas de milhares de negociantes em todo o mundo utilizam plataformas de negociação desenvolvidas pela MetaQuotes Software Corp. O fator chave levando ao sucesso é a superioridade tecnológica baseada na experiência de muitos anos e as melhores soluções de software.

Muitas pessoas já estimaram novas oportunidades que se tornaram disponíveis com a nova linguagem MQL5. Suas características chave são o alto desempenho e a possibilidade de utilizar programação orientada a objetos. Adicionalmente a isso, com o aparecimento do verificador de estratégia de várias moedas correntes no terminal do cliente do MetaTrader 5, muitos negociantes adquiriram ferramentas únicas para desenvolvimento, aprendizado e uso de sistemas complexos de negociação.

O campeonato de negociação automática 2010 começa nesse outono; milhares de robôs de negociação escritos no MQL5 participarão. Um conselheiro especialista que ganha o lucro máximo durante da competição ganhará. Mas que estratégia parecerá a mais eficiente?

O verificador de estratégia do terminal do MetaTrader 5 permite encontrar o melhor conjunto de parâmetros, utilizando o sistema que ganhar a maior quantidade de lucro durante o período de tempo especificado. Mas isso pode ser feito no tempo real? A ideia da negociação virtual utilizando diversas estratégias em um conselheiro foi considerada no artigo "Contest of Expert Advisors inside an Expert Advisor", que contém sua implementação no MQL4.

Nesse artigo, mostraremos que a criação e análise das estratégias adaptativas se tornaram significativamente mais fáceis no MQL5 devido ao uso de programação orientada a objeto, classes para o trabalho com os dados e classes de negociação da biblioteca padrão.


1. Estratégias de negociação adaptativas

Mercados mudam constantemente. Estratégias de negociação precisam de sua adaptação para as condições do mercado atuais.

Os valores dos parâmetros que fornecem a rentabilidade máxima da estratégia podem ser encontrados sem utilizar a otimização através de mudança sequencial dos parâmetros e análise do resultado da verificação.

A figura 1 demonstra as curvas de igualdade para dez conselheiros especialistas (MA_3,...MA_93); cada uma delas negociada pela estratégia de médias móveis mas com períodos diferentes (3,13,..93). A verificação foi realizada em EURUSD H1, o período de verificação é 4.01.2010-20.08.2010.

Figura 1. Diagramas de curvas de igualdade de dez conselheiros especialistas na conta

Figura 1. Diagramas de curvas de igualdade de dez conselheiros especialistas na conta

Como você pode ver na figura 1 os conselheiros especialistas apresentam quase os mesmos resultados durante as primeiras duas semanas de trabalho, mas depois seus lucros começaram a divergir significativamente. Ao final do período de teste os melhores resultados de negociação foram mostrados pelos conselheiros especialistas com períodos 63, 53 e 43.

O mercado escolheu os melhores. Por que deveríamos seguir a escolha dele? E se nós combinarmos todas as dez estratégias em um único conselheiro especialista, fornecer a possibilidade de negociamento virtual para cada estratégia e, periodicamente, (por exemplo, no inicio de cada barra nova) determinar a melhor estratégia para a negociação real e negociar de acordo com seus sinais?

Os resultados da estratégia adaptativa obtida são mostrados na figura 2. A curva de igualdade da conta com negociação adaptativa é mostrada na cor vermelha. Observe que, durante mais de metade do período a forma da curva de igualdade para a estratégia adaptativa é a mesma que a da estratégia ma_63, que parece ser finalmente a vencedora.

Figura 2. Curvas de igualdade na conta com estratégia adaptativa que utiliza sinais de 10 sistemas de negociação

Figura 2. Curvas de igualdade na conta com estratégia adaptativa que utiliza sinais de 10 sistemas de negociação

Curvas de balanço que possuem dinâmica similar (figura 3):

Figura 3. Curvas de balanço da estratégia adaptativa que utilizam sinais de 10 sistemas de negociação

Figura 3. Curvas de balanço da estratégia adaptativa que utilizam sinais de 10 sistemas de negociação

Se nenhuma das estratégias é rentável no momento, os sistemas adaptativos não devem realizar operações de negociação. O exemplo de tal caso é mostrado na figura 4 (período de 4 a 22 de janeiro 2010).

Figura 4. O período de tempo quando a estratégia adaptativa parou de abrir novas posições devido a ausência de estratégias rentáveis.

Figura 4. O período de tempo quando a estratégia adaptativa parou de abrir novas posições devido a ausência de estratégias rentáveis.

Começando a partir de janeiro de 2010 a melhor eficácia é mostrada pela estratégia MA_3. Já que MA_3 (azul) possuía a quantidade máxima de dinheiro adquirida naquele momento, a estratégia adaptativa (vermelha) seguiu seus sinais. No período de 8 a 20 de janeiro todas as estratégias consideradas tiveram um resultado negativo, é por isso que a estratégia adaptativa não abriu novas posições de negociação.

Se todas as estratégias possuírem um resultado negativo, é melhor não se envolver com negociações. Essa é a coisa significante que permite parar negociações não rentáveis e manter o seu dinheiro a salvo.


2. Implementação da estratégia de negociação adaptativa

Nessa seção, nós vamos considerar a estrutura de uma estratégia adaptativa que realiza a negociação "virtual" utilizando diversas estratégias de negociação simultaneamente, e escolher a mais rentável para negociação real de acordo com os seus sinais. Observe que o uso da abordagem orientada a objeto torna a solução desse problema significativamente mais fácil.

Primeiramente vamos investigar o código do conselheiro especialista adaptativo e, então, vamos olhar detalhadamente para a estratégia CAdaptiveStrategy onde a funcionalidade do sistema adaptativo é implementada e, então, mostraremos a estrutura da classe CSampleStrategy - a classe base das estratégias de negociação em que a funcionalidade da negociação virtual é implementada.

Adicionalmente, vamos considerar o código de dois de seus filhos - as classes CStrategyMA e CStrategyStoch que representam as estratégias de negociação por médias móveis e o oscilador estocástico. Após analisar a estrutura delas você será capaz de facilmente escrever e adicionar as suas próprias classes que realizam suas estratégias.

2.1. Código do conselheiro especialista

O código do conselheiro especialista parece muito simples: 

//+------------------------------------------------------------------+
//|                                       Adaptive_Expert_Sample.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <CAdaptiveStrategy.mqh>

CAdaptiveStrategy Adaptive_Expert;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   return(Adaptive_Expert.Expert_OnInit());
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Adaptive_Expert.Expert_OnDeInit(reason);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   Adaptive_Expert.Expert_OnTick();
  }
//+------------------------------------------------------------------+

As primeiras três linhas definem as propriedades do programa, então vem a #include directive que diz ao processador para incluir o arquivo CAdaptiveStrategy.mqh. Colchetes especificam que o arquivo deve ser tomado do diretório padrão (normalmente, é terminal_folder\MQL5\Include).

A próxima linha contém a declaração do objeto Adaptive_Expert (instância da classe CAdaptiveStrategy); e o código das funções OnInit, OnDeinit e OnTick do conselheiro especialista consistem de chamadas das funções correspondentes Expert_OnInit, Expert_OnDeInit e Expert_OnTick e do objeto Adaptive_Expert.

2.2. A classe CAdaptiveStrategy

A classe do conselheiro especialista adaptativo (classe CAdaptiveStrategy) está localizada no arquivo CAdaptiveStrategy.mqh. Vamos começar com os arquivos incluídos:

#include <Arrays\ArrayObj.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <CStrategyMA.mqh>
#include <CStrategyStoch.mqh>

A razão de incluirmos o arquivo ArrayObj.mqh é a conveniência de trabalhar com classes de estratégias diferentes utilizando o objeto da classe CArrayObj, que representa um arranjo dinâmico de apontadores para as instâncias das classes gerados pela classe base CObject e seus filhos. Esse objeto será o arranjo m_all_strategies, ele será utilizado como "recipiente" de estratégias de negociação.

Cada estratégia é representada como uma classe. Nesse caso, nós incluímos os arquivos que contém as classes CStrategyMA e CStrategyStoch, que representam as estratégias de negociação por médias móveis e negociação pelo oscilador estocástico.

Para solicitar as propriedades das posições atuais e para realizar operações de negociação, nós iremos utilizar as classes CPositionInfo e CTrade da biblioteca padrão, é por isso que nós incluímos os arquivos PositionInfo.mqh e Trade.mqh.

Vamos dar uma olhada a estrutura da classe CAdaptiveStrategy.

//+------------------------------------------------------------------+
//| Class CAdaptiveStrategy                                          |
//+------------------------------------------------------------------+
class CAdaptiveStrategy
  {
protected:
   CArrayObj        *m_all_strategies;   // objects of trade strategies

   void              ProceedSignalReal(int state,double trade_volume);
   int               RealPositionDirection();

public:
   // initialization of the adaptive strategy
   int               Expert_OnInit();
   // deinitialization of the adaptive strategy
   int               Expert_OnDeInit(const int reason);
   // check of trade conditions and opening of virtual positions
   void              Expert_OnTick();
  };

Para implementar a abordagem unificada aos objetos de diferentes classes, as estratégias de negociação (ou melhor as instâncias de suas classes) são armazenadas no arranjo dinâmico m_all_strategies (do tipo CArrayObj), que é utilizado como um "recipiente" de classes das estratégias. Essa é a razão de a classe de estratégias de negociação SampleStrategy ser gerada da classe CObject.

A função ProceedSignalReal implementa a "sincronização" da direção e volume de uma posição real com a dada direção e volume:

//+------------------------------------------------------------------+
//| This method is intended for "synchronization" of current         |
//| real trade position with the value of the 'state' state          |
//+------------------------------------------------------------------+
void CAdaptiveStrategy::ProceedSignalReal(int state,double trade_volume)
  {
   CPositionInfo posinfo;
   CTrade trade;

   bool buy_opened=false;
   bool sell_opened=false;

   if(posinfo.Select(_Symbol)) // if there are open positions
     {
      if(posinfo.Type()==POSITION_TYPE_BUY) buy_opened=true;    // a buy position is opened
      if(posinfo.Type()==POSITION_TYPE_SELL) sell_opened=true;  // a sell position is opened

      // if state = 0, then we need to close open positions
      if((state==POSITION_NEUTRAL) && (buy_opened || sell_opened))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
        }
      //reverse: closing buy position and opening sell position
      if((state==POSITION_SHORT) && (buy_opened))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0))
            Print(trade.ResultRetcodeDescription());
        }
      //reverse: close sell position and open buy position
      if(((state==POSITION_LONG) && (sell_opened)))
        {
         if(!trade.PositionClose(_Symbol,200))
            Print(trade.ResultRetcodeDescription());
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0))
            Print(trade.ResultRetcodeDescription());
        }
     }
   else // if there are no open positions
     {
      // open a buy position
      if(state==POSITION_LONG)
        {
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0))
            Print(trade.ResultRetcodeDescription());
        }
      // open a sell position
      if(state==POSITION_SHORT)
        {
         if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,0.1,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0))
            Print(trade.ResultRetcodeDescription());
        }
     }
  }

Observe que é mais fácil trabalhar com a posição de negociação utilizando as classes de negociação. Nós utilizamos os objetos das classes CPositionInfo e CTrade para solicitar as propriedades da posição do mercado e para realizar operações de negociação respectivamente.

A função RealPositionDirection solicita os parâmetros da posição aberta real e retorna sua direção:

//+------------------------------------------------------------------+
//| Returns direction (0,+1,-1) of the current real position         |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::RealPositionDirection()
  {
   int direction=POSITION_NEUTRAL;
   CPositionInfo posinfo;

   if(posinfo.Select(_Symbol)) // if there are open positions
     {
      if(posinfo.Type()==POSITION_TYPE_BUY) direction=POSITION_LONG;    // a buy position is opened
      if(posinfo.Type()==POSITION_TYPE_SELL) direction=POSITION_SHORT;  // a short position is opened
     }
   return(direction);
  }

Agora nós vamos dar uma olhada nas funções principais da classe СAdaptiveStrategy.

Vamos começar com a função Expert_OnInit:

//+------------------------------------------------------------------+
//| Function of initialization of the Adaptive Expert Advisor        |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::Expert_OnInit()
  {
//--- Create array of objects m_all_strategies
//--- we will put our object with strategies in it 
   m_all_strategies=new CArrayObj;
   if(m_all_strategies==NULL)
     {
      Print("Error of creation of the object m_all_strategies"); return(-1);
     }

// create 10 trading strategies CStrategyMA (trading by moving averages)
// initialize them, set parameters
// and add to the m_all_strategies container 
   for(int i=0; i<10; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialize strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //t_StrategyMA.Set_Stops(3500,1000);

      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      CSampleStrategy *t_SampleStrategy;
      t_SampleStrategy=m_all_strategies.At(i);
      Print(i," Strategy name:",t_SampleStrategy.StrategyName(),
              " Strategy ID:",t_SampleStrategy.StrategyID(),
              " Virtual trading:",t_SampleStrategy.IsVirtualTradeAllowed());
     }
//---
   return(0);
  }

O conjunto de estratégias de negociação é preparado pela função Expert_OnInit. Primeiramente, o objeto do arranjo dinâmico m_all_strategies é criado.

Nesse caso, criamos dez instâncias da classe CStrategyMA. Cada uma delas foi inicializada (nesse caso, nós configuramos diferentes períodos e permitimos negociações "virtuais") utilizando a função inicialização.

Então, utilizando a função SetStrategyInfo nós configuramos o instrumento financeiro, nome da estratégia e comentário.

Se necessário, utilizando a função Set_Stops(TP,SL) nós podemos especificar um valor (em pontos) de take profit e stop loss, que serão executados durante a negociação "virtual". Nós temos essa linha comentada.

Uma vez que a classe da estratégia está criada e ajustada, nós adicionamos ela ao recipiente m_all_strategies.

Todas as estratégias de negociação devem possuir a função CheckTradeConditions() que realiza as verificações das condições de negociação. Na classe da estratégia adaptativa essa função é chamada no início de cada barra nova, assim fornecemos às estratégias a possibilidade de verificar os valores dos indicadores e para fazer as operações de negociação "virtuais".

Ao invés de dez médias móveis especificadas (3, 13, 23...93) nós podemos adicionar centenas de médias móveis (instâncias da classe CStrategyMA):

  for(int i=0; i<100; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialization of strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

Ou podemos adicionar as classes de estratégia que funcionam pelos sinais do oscilados estocástico (instâncias da classe CStrategyStoch):

  for(int i=0; i<5; i++)
     {
      CStrategyStoch *t_StrategyStoch;
      t_StrategyStoch=new CStrategyStoch;
      if(t_StrategyStoch==NULL)
        {
         delete m_all_strategies;
         printf("Error of creation of object of the CStrategyStoch type");
         return(-1);
        }
      //set period for each strategy
      int Kperiod=2+i*5;
      int Dperiod=2+i*5;
      int Slowing=3+i;
      // initialization of strategy
      t_StrategyStoch.Initialization(Kperiod,Dperiod,Slowing,true);
      // set details of the strategy
      string s=IntegerToString(Kperiod)+"/"+IntegerToString(Dperiod)+"/"+IntegerToString(Slowing);
      t_StrategyStoch.SetStrategyInfo(_Symbol,"[Stoch_"+s+"]",100+i," Stochastic "+s);
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyStoch);
     }

Nessa classe o recipiente inclui 10 estratégias de médias móveis e 5 estratégias do oscilador estocástico.

As instâncias das classes de estratégias de negociação devem ser os filhos da classe CObject e devem conter a função CheckTradeConditions(). É melhor herdar elas da classe CSampleStrategy. Classes que implementam estratégias de negociação podem ser diferentes e seu número não é limitado.

A função Expert_OnInit termina com a lista de estratégias que estão presentes no recipiente m_all_strategies. Observe que todas as estratégias no recipiente são consideradas como os filhos da classe CSampleStrategy. As classes de estratégias de negociação CStrategyMA e CStrategyStoch são também seus filhos.

O mesmo truque é utilizado na função Expert_OnDeInit. No recipiente, nós chamamos a função SaveVirtualDeals para cada estratégia; ela armazena o histórico dos acordos virtuais realizados.

Utilizamos o nome de estratégia para o nome do arquivo que é passado como parâmetro. Então nós desinicializamos as estratégias chamando a função Deinitialization() e deletando o recipiente m_all_strategies:

//+------------------------------------------------------------------+
//| Function of deinitialization the adaptive Expert Advisor         |
//+------------------------------------------------------------------+
int CAdaptiveStrategy::Expert_OnDeInit(const int reason)
  {
   // deinitialize all strategies
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      CSampleStrategy *t_Strategy;
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.SaveVirtualDeals(t_Strategy.StrategyName()+"_deals.txt");
      t_Strategy.Deinitialization();
     }
   //delete the array of object with strategies 
   delete m_all_strategies;
   return(0);
  }

Se você precisa saber sobre os acordos virtuais realizados pelas estratégias, remova a linha onde tStrategy.SaveVirtualDeals é chamado. Observe que quando utilizando o verificador de estratégia os arquivos são salvos no diretório /tester_directory/Files/.

Vamos considerar a função Expert_OnTick da classe CAdaptiveStrategy que é chamada cada vez que uma nova variação chega:

//+------------------------------------------------------------------+
//| Function of processing ticks of the adaptive strategy            |
//+------------------------------------------------------------------+
void CAdaptiveStrategy::Expert_OnTick()
  {
   CSampleStrategy *t_Strategy;

   // recalculate the information about positions for all strategies
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.UpdatePositionData();
     }

   // the expert advisor should check the conditions of making trade operations only when a new bar comes
   if(IsNewBar()==false) { return; }

   // check trading conditions for all strategies 
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      t_Strategy.CheckTradeConditions();
     }

   //search for the best position
   //prepare the array performance[] 
   double performance[];
   ArrayResize(performance,m_all_strategies.Total());
   
   //request the current effectiveness for each strategy,
   //each strategy returns it in the Strategyperformance() function
   for(int i=0; i<m_all_strategies.Total(); i++)
     {
      t_Strategy=m_all_strategies.At(i);
      performance[i]=t_Strategy.StrategyPerformance();
     }
   //find the strategy (or rather its index in the m_all_strategies container)
   //with maximum value of Strategyperformance()
   int best_strategy_index=ArrayMaximum(performance,0,WHOLE_ARRAY);

   //this strategy is - t_Strategy
   t_Strategy=m_all_strategies.At(best_strategy_index);
   //request the direction of its current position
   int best_direction=t_Strategy.PositionDirection();

   string s=s+" "+t_Strategy.StrategyName()+" "+DoubleToString(t_Strategy.GetVirtualEquity())+" "+IntegerToString(best_direction);
   Print(TimeCurrent()," TOTAL=",m_all_strategies.Total(),
                       " BEST IND=",best_strategy_index,
                       " BEST STRATEGY="," ",t_Strategy.StrategyName(),
                       " BEST=",performance[best_strategy_index],"  =",
                       " BEST DIRECTION=",best_direction,
                       " Performance=",t_Strategy.StrategyPerformance());

   //if the best strategy has a negative result and doesn't have open positions, it's better to stay away from trading
   if((performance[best_strategy_index]<0) && (RealPositionDirection()==POSITION_NEUTRAL)) {return;}

   if(best_direction!=RealPositionDirection())
     {
      ProceedSignalReal(best_direction,t_Strategy.GetCurrentLotSize());
     }
  }

O código é muito simples. Cada estratégia, localizada no recipiente deve ser capaz de recalcular o resultado financeiro atual de suas posições virtuais utilizando os preços atuais. Isso é feito chamando a função UpdatePositionData(). Aqui, mais uma vez, nós chamamos as estratégias de herdeiros da classe CSampleStrategy.

Todas as operações de negociação são realizadas no inicio de uma nova barra (a função IsNewBar() permitem determinar esse momento assim como os outros métodos de verificar uma nova barra). Nesse caso, o fim das barras em formação significa que todos os dados da barra anterior (valores de preços e indicador) não serão mais modificados, então ele pode ser analisado em correspondência às condições de negociação. Para todas as estratégias nós fornecemos a oportunidade de realizar essa verificação e de realizar suas operações de negociação virtual chamando a sua função CheckTradeConditions.

Agora devemos encontrar a estratégia mais bem sucedida entre todas as estratégias no arranjo m_all_strategies. Para fazer isso, utilizamos o arranjo Performance[], valores que são devolvidos pela função StrategyPerformance() de cada estratégia não depositados nela. A classe base CSampleStrategy contém essa função como a diferença entre os valores atuais de balanço e igualdade "virtual".

A procura do índice da estratégia mais bem sucedida é realizada utilizando a função ArrayMaximum. Se a melhor estratégia possui um lucro negativo no momento e ela não possui posições abertas reais, então é melhor não negociar, essa é a razão de sairmos da função (ver a seção 1).

Após, solicitamos a direção da posição virtual dessa estratégia (best_direction). Se ela difere da direção atual da posição real, então a direção atual da posição real será corrigida (utilizando a função ProceedSignalReal) de acordo com a direção best_direction.

2.3. Classe CSampleStrategy

Estratégias colocadas no recipiente m_all_strategies foram consideradas como herdeiras da classe CSampleStrategy.

Essa classe é a base um para estratégias de negociação; ela contém a implementação da negociação virtual. Nesse artigo iremos considerar um caso simplificado de implementação de negociação virtual, as trocas não são tomadas em consideração. As classes de estratégias de negociamento devem ser herdadas da classe CSampleStrategy.

Vamos mostrar a estrutura dessa classe.

//+------------------------------------------------------------------+
//|                                              CSampleStrategy.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <Object.mqh>

#define POSITION_NEUTRAL   0     // no position
#define POSITION_LONG      1     // long position
#define POSITION_SHORT    -1     // short position

#define SIGNAL_OPEN_LONG    10   // signal to open a long position
#define SIGNAL_OPEN_SHORT  -10   // signal to open a short position
#define SIGNAL_CLOSE_LONG   -1   // signal to close a long position
#define SIGNAL_CLOSE_SHORT   1   // signal to close a short position
//+------------------------------------------------------------------+
//| Structure for storing the parameters of virtual position         |
//+------------------------------------------------------------------+
struct virtual_position
  {
   string            symbol;            // symbol
   int               direction;         // direction of the virtual position (0-no open position,+1 long,-1 short)
   double            volume;            // volume of the position in lots
   double            profit;            // current profit of the virtual position on points
   double            stop_loss;         // Stop Loss of the virtual position
   double            take_profit;       // Take Profit of the virtual position
   datetime          time_open;         // date and time of opening the virtual position
   datetime          time_close;        // date and time of closing the virtual position
   double            price_open;        // open price of the virtual position
   double            price_close;       // close price of the virtual position
   double            price_highest;     // maximum price during the life of the position
   double            price_lowest;      // minimal price during the lift of the position
   double            entry_eff;         // effectiveness of entering
   double            exit_eff;          // effectiveness of exiting
   double            trade_eff;         // effectiveness of deal
  };
//+------------------------------------------------------------------+
//| Class CSampleStrategy                                            |
//+------------------------------------------------------------------+
class CSampleStrategy: public CObject
  {
protected:
   int               m_strategy_id;            // Strategy ID
   string            m_strategy_symbol;        // Symbol 
   string            m_strategy_name;          // Strategy name
   string            m_strategy_comment;       // Comment

   MqlTick           m_price_last;             // Last price
   MqlRates          m_rates[];                // Array for current quotes
   bool              m_virtual_trade_allowed;  // Flag of allowing virtual trading 
   int               m_current_signal_state;   // Current state of strategy
   double            m_current_trade_volume;   // Number of lots for trading
   double            m_initial_balance;        // Initial balance (set in the constructor, default value is 10000)
   int               m_sl_points;              // Stop Loss
   int               m_tp_points;              // Take Profit

   virtual_position  m_position;               // Virtual position
   virtual_position  m_deals_history[];        // Array of deals
   int               m_virtual_deals_total;    // Total number of deals

   double            m_virtual_balance;           // "Virtual" balance
   double            m_virtual_equity;            // "Virtual" equity
   double            m_virtual_cumulative_profit; // cumulative "virtual" profit
   double            m_virtual_profit;            // profit of the current open "virtual" position

   //checks and closes the virtual position by stop levels if it is necessary
   bool              CheckVirtual_Stops(virtual_position &position);
   // recalculation of position and balance
   void              RecalcPositionProperties(virtual_position &position);
   // recalculation of open virtual position in accordance with the current prices 
   void              Position_RefreshInfo(virtual_position &position);
   // open virtual short position
   void              Position_OpenShort(virtual_position &position);
   // closes virtual short position  
   void              Position_CloseShort(virtual_position &position);
   // opens virtual long position
   void              Position_OpenLong(virtual_position &position);
   // closes the virtual long position
   void              Position_CloseLong(virtual_position &position);
   // closes open virtual position  
   void              Position_CloseOpenedPosition(virtual_position &position);
   // adds closed position to the m_deals_history[] array (history of deals)
   void              AddDealToHistory(virtual_position &position);
   //calculates and returns the recommended volume that will be used in trading
   virtual double    MoneyManagement_CalculateLots(double trade_volume);
public:
   // constructor
   void              CSampleStrategy();
   // destructor
   void             ~CSampleStrategy();

   //returns the current size of virtual balance
   double            GetVirtualBalance() { return(m_virtual_balance); }
   //returns the current size of virtual equity
   double            GetVirtualEquity() { return(m_virtual_equity); }
   //returns the current size of virtual profit of open position
   double            GetVirtualProfit() { return(m_virtual_profit); }

   //sets Stop Loss and Take Profit in points
   void              Set_Stops(int tp,int sl) {m_tp_points=tp; m_sl_points=sl;};
   //sets the current volume in lots
   void              SetLots(double trade_volume) {m_current_trade_volume=trade_volume;};
   //returns the current volume in lots
   double            GetCurrentLots() { return(m_current_trade_volume); }

   // returns strategy name
   string            StrategyName() { return(m_strategy_name); }
   // returns strategy ID
   int               StrategyID() { return(m_strategy_id); }
   // returns the comment of strategy
   string            StrategyComment() { return(m_strategy_comment); }
   // sets the details of strategy (symbol, name and ID of strategy)
   void              SetStrategyInfo(string symbol,string name,int id,string comment);

   // set the flag of virtual trading (allowed or not)
   void              SetVirtualTradeFlag(bool pFlag) { m_virtual_trade_allowed=pFlag; };
   // returns flag of allowing virtual trading
   bool              IsVirtualTradeAllowed() { return(m_virtual_trade_allowed); };

   // returns the current state of strategy
   int               GetSignalState();
   // sets the current state of strategy (changes virtual position if necessary)
   void              SetSignalState(int state);
   // changes virtual position in accordance with the current state 
   void              ProceedSignalState(virtual_position &position);

   // sets the value of cumulative "virtual" profit
   void              SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_profit; };

   //returns the effectiveness of strategy ()
   double            StrategyPerformance();

   //updates position data
   void              UpdatePositionData();
   //closes open virtual position
   void              CloseVirtualPosition();
   //returns the direction of the current virtual position
   int               PositionDirection();
   //virtual function of initialization
   virtual int       Initialization() {return(0);};
   //virtual function of checking trade conditions
   virtual bool      CheckTradeConditions() {return(false);};
   //virtual function of deinitialization
   virtual int       Deinitialization() {return(0);};

   //saves virtual deals to a file
   void              SaveVirtualDeals(string file_name);
  };

Não analisaremos sua descrição detalhada, informações adicionais são encontradas no arquivo CSampleStrategy.mqh. Lá você também encontra a função de verificar a nova barra - IsNewBar.


3. Classes de estratégias de negociação

Essa seção é devotada à estrutura das classes de estratégias de negociação que são utilizadas no conselheiro especialista adaptativo.

3.1. Classe CStrategyMA - Estratégia de negociação por médias móveis

//+------------------------------------------------------------------+
//|                                                  CStrategyMA.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <CSampleStrategy.mqh>
//+------------------------------------------------------------------+
//| Class CStrategyMA for implementation of virtual trading          |
//| by the strategy based on moving average                          |
//+------------------------------------------------------------------+
class CStrategyMA : public CSampleStrategy
  {
protected:
   int               m_handle;     // handle of the Moving Average (iMA) indicator
   int               m_period;     // period of the Moving Average indicator
   double            m_values[];   // array for storing values of the indicator
public:
   // initialization of the strategy
   int               Initialization(int period,bool virtual_trade_flag);
   // deinitialization of the strategy
   int               Deinitialization();
   // checking trading conditions and opening virtual positions
   bool              CheckTradeConditions();
  };

A classe CStrategyMA é um filho da classe CSampleStrategy onde toda a funcionalidade da negociação virtual é implementada.

A seção virtual contém variáveis internas que serão utilizadas na classe de estratégia. Essas são: m_handle - cotação do indicador iMA, m_period - período da média móvel, m_values[] - arranjo que será utilizado na função CheckTradeConditions para conseguir os valores atuais do indicador.

A seção pública contém três funções que fornecem implementação da estratégia de negociação.

  • Inicialização da função. A estratégia é inicializada aqui. Se você precisa criar indicadores, crie-os aqui.
  • Desinicialização da função. A estratégia é desinicializada aqui. As cotações dos indicadores são realizadas aqui.
  • Função СheckTradeConditions. Aqui a estratégia verifica as condições de negociação e geram sinais de negociação que são utilizados para a negociação virtual. Para realizar operações de negociação virtual, a função SetSignalState da classe progenitora CStrategy é chamada; um de quatro dos sinais de negociação seguintes são passados para ela.
  1. O sinal para abrir uma posição de compra (SIGNAL_OPEN_LONG)
  2. O sinal para abrir uma posição de venda (SIGNAL_OPEN_SHORT)
  3. O sinal para fechar uma posição de compra (SIGNAL_CLOSE_LONG)
  4. O sinal para fechar uma posição de venda (SIGNAL_CLOSE_SHORT)
//+------------------------------------------------------------------+
//| Strategy Initialization Method                                   |
//+------------------------------------------------------------------+
int CStrategyMA::Initialization(int period,bool virtual_trade_flag)
  {
   // set period of the moving average
   m_period=period;
   // set specified flag of virtual trading
   SetVirtualTradeFlag(virtual_trade_flag);

   //set indexation of arrays like the one of timeseries
   ArraySetAsSeries(m_rates,true);
   ArraySetAsSeries(m_values,true);
   
   //create handle of the indicator
   m_handle=iMA(_Symbol,_Period,m_period,0,MODE_EMA,PRICE_CLOSE);
   if(m_handle<0)
     {
      Alert("Error of creation of the MA indicator - error number: ",GetLastError(),"!!");
      return(-1);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| Strategy Deinitialization Method                                 |
//+------------------------------------------------------------------+
int CStrategyMA::Deinitialization()
  {
   Position_CloseOpenedPosition(m_position);
   IndicatorRelease(m_handle);
   return(0);
  };
//+------------------------------------------------------------------+
//| Checking trading conditions and opening virtual positions        |
//+------------------------------------------------------------------+
bool CStrategyMA::CheckTradeConditions()
  {
   RecalcPositionProperties(m_position);
   double p_close;

   // get history data of the last three bars
   if(CopyRates(_Symbol,_Period,0,3,m_rates)<0)
     {
      Alert("Error of copying history data - error:",GetLastError(),"!!");
      return(false);
     }
   // Copy the current price of closing of the previous bar (it is bar 1)
   p_close=m_rates[1].close;  // close price of the previous bar          

   if(CopyBuffer(m_handle,0,0,3,m_values)<0)
     {
      Alert("Error of copying buffers of the Moving Average indicator - error number:",GetLastError());
      return(false);
     }

   // buy condition 1: MA rises
   bool buy_condition_1=(m_values[0]>m_values[1]) && (m_values[1]>m_values[2]);
   // buy condition 2: previous price is greater than the MA
   bool buy_condition_2=(p_close>m_values[1]);

   // sell condition 1: // MA falls
   bool sell_condition_1=(m_values[0]<m_values[1]) && (m_values[1]<m_values[2]);
   // sell condition 2: // previous price is lower than the MA   
   bool sell_condition_2=(p_close<m_values[1]);

   int new_state=0;

   if(buy_condition_1  &&  buy_condition_2) new_state=SIGNAL_OPEN_LONG;
   if(sell_condition_1 && sell_condition_2) new_state=SIGNAL_OPEN_SHORT;

   if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition_1 || buy_condition_2)) new_state=SIGNAL_CLOSE_SHORT;
   if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition_1 || sell_condition_2)) new_state=SIGNAL_CLOSE_LONG;

   if(GetSignalState()!=new_state)
     {
      SetSignalState(new_state);
     }

   return(true);
  };

O conceito é simples - na base dos estados e preços do indicador, o tipo de sinal (new_state) é determinado, então o estado atual da negociação virtual é solicitado (utilizando a função GetSignalState); e se eles não forem os mesmos, a função SetSignalState é chamada para "corrigir" a posição virtual.

3.2. Classe CStrategyStoch - a estratégia de negociação por estocástico

O código da classe que realiza negociação na base da interseção das linhas principal e de sinal do oscilador iStochastic é dado abaixo:

//+------------------------------------------------------------------+
//|                                               CStrategyStoch.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#include <CSampleStrategy.mqh>
//+------------------------------------------------------------------+
//| Class CStrategyStoch for implementation of virtual trading by    |
//| the strategy of intersection of lines of stochastic oscillator   |
//+------------------------------------------------------------------+
class CStrategyStoch : public CSampleStrategy
  {
protected:
   int               m_handle;          // handle of the Stochastic Oscillator (iStochastic)
   int               m_period_k;        // K-period (number of bars for calculations)
   int               m_period_d;        // D-period (period of primary smoothing)
   int               m_period_slowing;  // final smoothing
   double            m_main_line[];     // array for storing indicator values
   double            m_signal_line[];   // array for storing indicator values
public:
   // initialization of strategy
   int               Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag);
   // deinitialization of strategy
   int               Deinitialization();
   // checking trading conditions and opening virtual positions
   bool              CheckTradeConditions();
  };
//+------------------------------------------------------------------+
//| Strategy Initialization Method                                   |
//+------------------------------------------------------------------+
int CStrategyStoch::Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag)
  {
   // Set period of the oscillator
   m_period_k=period_k;
   m_period_d=period_d;
   m_period_slowing=period_slowing;

   // set specified flag of the virtual trading
   SetVirtualTradeFlag(virtual_trade_flag);

   // set indexation of arrays like the one of timeseries
   ArraySetAsSeries(m_rates,true);
   ArraySetAsSeries(m_main_line,true);
   ArraySetAsSeries(m_signal_line,true);

   // create handle of the indicator
   m_handle=iStochastic(_Symbol,_Period,m_period_k,m_period_d,m_period_slowing,MODE_SMA,STO_LOWHIGH);
   if(m_handle<0)
     {
      Alert("Error of creating the Stochastic indicator - error number: ",GetLastError(),"!!");
      return(-1);
     }

   return(0);
  }
//+------------------------------------------------------------------+
//| Strategy Deinitialization Method                                 |
//+------------------------------------------------------------------+
int CStrategyStoch::Deinitialization()
  {
   // close all open positions
   Position_CloseOpenedPosition(m_position);
   // release handle of the indicator
   IndicatorRelease(m_handle);
   return(0);
  };
//+------------------------------------------------------------------+
//| Checking Trading Conditions and Opening Virtual Positions        |
//+------------------------------------------------------------------+
bool CStrategyStoch::CheckTradeConditions()
  {
   // call the functions of recalculation of position parameters
   RecalcPositionProperties(m_position);
   double p_close;

   // get history  data of the last 3 bars 
   if(CopyRates(_Symbol,_Period,0,3,m_rates)<0)
     {
      Alert("Error of copying history data - error:",GetLastError(),"!!");
      return(false);
     }
   // copy the current close price of the previous bar (it is bar 1)
   p_close=m_rates[1].close;  // close price of the previous bar          

   if((CopyBuffer(m_handle,0,0,3,m_main_line)<3) || (CopyBuffer(m_handle,1,0,3,m_signal_line)<3))
     {
      Alert("Error of copying buffers of the Stochastic indicator - error number:",GetLastError());
      return(false);
     }

   // buy condition: crossing the signal line by the main one from bottom up
   bool buy_condition=((m_signal_line[2]<m_main_line[2]) && (m_signal_line[1]>m_main_line[1]));
   // sell condition: crossing the signal line by the main one from top downwards
   bool sell_condition=((m_signal_line[2]>m_main_line[2]) && (m_signal_line[1]<m_main_line[1]));

   int new_state=0;

   if(buy_condition) new_state=SIGNAL_OPEN_LONG;
   if(sell_condition) new_state=SIGNAL_OPEN_SHORT;

   if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition)) new_state=SIGNAL_CLOSE_SHORT;
   if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition)) new_state=SIGNAL_CLOSE_LONG;

   if(GetSignalState()!=new_state)
     {
      SetSignalState(new_state);
     }

   return(true);
  };

Como você vê, as únicas diferenças entre a estrutura da classe CStrategyStoch e a da CStrategyMA são a função de inicialização (parâmetros diferentes, o tipo do indicador utilizado e os sinais de negociação.

Assim, para utilizar as suas estratégias no conselheiro especialista adaptativo, você deveria reescrever elas na forma de classes de tal tipo e carregá-las no recipiente m_all_strategies.


4. Resultados da análise das estratégias de negociação adaptativas

Nessa seção nós vamos discutir diversos aspectos do uso prático das estratégias adaptativas e os métodos de melhorá-las.

4.1. Melhorando o sistema com estratégias que utilizam sinais inversos

Médias móveis não são boas quando não existem tendências. Já encontramos esse tipo de situação - na figura 3 você pode ver que não havia tendência dentro do período de 8 a 20 de janeiro; então todas as 10 estratégias que utilizam médias móveis em negociação tiveram uma perda virtual. O sistema adaptativo parou de negociar como resultado da ausência de uma estratégia com quantidade positiva de dinheiro adquirida. Há uma forma de evitar tal efeito negativo?

Vamos adicionar às nossas 10 estratégias (MA_3, MA_13, ... MA_93) outras 10 classes CStrategyMAinv, cujos sinais de negociação são reversos (as condições são as mesmas mas SIGNAL_OPEN_LONG/SIGNAL_OPEN_SHORT e SIGNAL_CLOSE_LONG/SIGNAL_CLOSE_SHORT trocaram seus lugares). Assim, além de dez estratégias de tendência (instâncias da classe CStrategyMA), nós possuímos outras dez estratégias contra tendência (instâncias da classe CStrategyMAinv).

O resultado de utilizar o sistema adaptativo que consiste em vinte estratégias é mostrado na figura 5.

Figura 5. Diagramas de igualdade na conta da estratégia adaptativa que utiliza 20 sinais de negociação: 10 médias móveis CAdaptiveMA e 10

Figura 5. Diagramas de igualdade na conta da estratégia adaptativa que utiliza 20 sinais de negociação: 10 médias móveis CAdaptiveMA e 10 "espelhadas" CAdaptiveMAinv

Como você pode ver na figura 5, durante o período que todas as estratégias CAdaptiveMA obtiveram um resultado negativo, seguir as estratégias CAdaptiveMAinv permitiu o conselheiro especialista evitar rebaixamentos não desejados no inicio da negociação.

Figura 6. Período de tempo quando a estratégia adaptativa utilizava os sinais das estratégias CAdaptiveMAinv

Figura 6. Período de tempo quando a estratégia adaptativa utilizou os sinais das estratégias CAdaptiveMAinv "contra tendência"

Esse tipo de abordagem pode parecer inaceitável, uma vez que perder o depósito é apenas uma questão de tempo quando utilizando uma estratégia contra tendência. No entanto, em nosso caso, não somos limitados a uma única estratégia. O mercado sabe melhor quais estratégias são efetivas no momento.

O lado forte de sistemas adaptativos é que o mercado sugere por si próprio qual estratégia deve ser utilizada e quando ela deve ser utilizada.

Ele fornece a possibilidade de abstrair da lógica das estratégias - se uma estratégia é efetiva, então a forma que ela funciona é de nenhuma significância. A abordagem adaptativa utiliza apenas o critério de sucesso de uma estratégia - sua efetividade.

4.2. Vale a pena inverter os sinais da pior estratégia?

O truque com inversão mostrado acima leva a um pensamento sobre o potencial possivelmente de utilizar os sinais da pior estratégia. Se uma estratégia é não rentável (e a pior nisso), então conseguimos lucro agindo de forma reversa?

Podemos tornar uma estratégia de perda em uma estratégia rentável simplesmente mudando seus sinais? Para responder essa pergunta, precisamos mudar ArrayMaximum com ArrayMinimum na função Expert_OnTick() da classe CAdaptiveStrategy, assim como implementar a mudança de direções ao multiplicar o valor da variável BestDirection por -1.

Adicionalmente, precisamos comentar a limitação da negociação virtual em caso de efetividade negativa (já que iremos analisar o resultado da pior estratégia):

//if((Performance[BestStrategyIndex]<0) && (RealPositionDirection()==0)) {return;}

O diagrama de igualdade do conselheiro especialista adaptativo que utiliza os sinais reversos da pior estratégia é mostrado na figura 7:

Figura 7. Diagramas de igualdade das contas de dez estratégias e o sistema adaptativo que utiliza sinais reversos do pior sistema

Figura 7. Diagramas de igualdade das contas de dez estratégias e o sistema adaptativo que utiliza sinais reversos do pior sistema

Nesse caso, a estratégia menos bem sucedida por maior parte do tempo foi a baseada na interseção de médias móveis com período 3 (MA_3). Como você pode ver na figura 7, a correlação reversa entre MA_3 (de cor azul) e a estratégia adaptativa (cor vermelha) existe, mas o resultado financeiro do sistema adaptativo não impressiona.

Copiar (e reverter) os sinais da pior estratégia não leva a melhorar a efetividade da negociação.

4.2. Por que o bando de médias móveis não é tão efetivo quanto parece?

Em vez de 10 médias móveis você pode utilizar lotes delas adicionando outra centena de estratégias CStrategyMA com diferentes períodos ao recipiente m_all_strategies.

Para fazer isso, modifique levemente o código na classe CAdaptiveStrategy:

   for(int i=0; i<100; i++)
     {
      CStrategyMA *t_StrategyMA;
      t_StrategyMA=new CStrategyMA;
      if(t_StrategyMA==NULL)
        {
         delete m_all_strategies;
         Print("Error of creation of object of the CStrategyMA type");
         return(-1);
        }
      //set period for each strategy
      int period=3+i*10;
      // initialization of strategy
      t_StrategyMA.Initialization(period,true);
      // set details of the strategy
      t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period));
      //add the object of the strategy to the array of objects m_all_strategies
      m_all_strategies.Add(t_StrategyMA);
     }

No entanto, você deve entender que médias móveis próximas inevitavelmente intercederão; a líder mudará continuamente; e o sistema adaptativo trocará seus estados e posições de aberto/fechado mais frequentemente do que é necessário. Como resultado, as características do sistema adaptativo se tornarão piores. Você pode se certificar disso sozinho ao comparar as características estatísticas do sistema (a aba "resultados" do verificador de estratégia).

É melhor não fazer sistemas adaptativos baseados em muitas estratégias com parâmetros próximos.


5. O que deve ser considerado

O recipiente m_all_strategies pode possuir milhares de instâncias de estratégias sugeridas inclusas, você pode até adicionar todas as estratégias com diferentes parâmetros; no entanto, para ganhar o Campeonato de negociação automatizada 2010, você precisa desenvolver o sistema de gerenciamento de dinheiro avançado. Observe que utilizamos o volume de negociação igual a 0,1 lotes para testar nos dados do histórico (e no código das classes).

5.1 Como aumentar a rentabilidade do conselheiro especialista adaptativo?

A classe CSampleStrategy possui a função virtual MoneyManagement_CalculateLots:

//+------------------------------------------------------------------+
//| The function returns the recommended volume for a strategy       |
//| Current volume is passed to it as a parameter                    |
//| Volume can be set depending on:                                  |
//| current m_virtual_balance and m_virtual_equity                   |
//| current statistics of deals (located in m_deals_history)         |
//| or any other thing you want                                      |
//| If a strategy doesn't require change of volume                   |
//| you can return the passed value of volume:  return(trade_volume);|
//+------------------------------------------------------------------+ 
double CSampleStrategy::MoneyManagement_CalculateLots(double trade_volume)
  {
   //return what we've got 
   return(trade_volume);
  }

Para gerenciar o volume para negociação, você pode utilizar a informação estatística sobre os resultados e características de acordos virtuais que são gravadas no arranjo m_deals_history[].

Se você precisa aumentar o volume (por exemplo, para dobrar ele se os últimos acordos virtuais em m_deals_history[] são rentáveis; ou para diminuir ele), você deveria mudar o valor devolvido na forma correspondente.

Utilizando as estatísticas dos acordos para cálculo da estratégia de desempenho

A função StrategyPerformance(), implementada na classe CSampleStrategy foi concebida para o cálculo do desempenho da estratégia,

//+-----------------------------------------------------------------------+
//| Function StrategyPerformance - the function of strategy effectiveness |
//+-----------------------------------------------------------------------+ 
double CSampleStrategy::StrategyPerformance()
  {
   //returns effectiveness of a strategy
   //in this case it's the difference between the amount
   //of equity at the moment and the initial balance, 
   //i.e. the amount of assets earned by the strategy
   double performance=(m_virtual_equity-m_initial_balance);
   return(performance);
  }

A fórmula de efetividade de uma estratégia pode ser mais complexa e, por exemplo, incluir efetividade de entrar, sair, a efetividade dos acordos, lucros, rebaixamentos, etc.

O cálculo da efetividade de entrar, sair e a efetividade dos acordos (os campos de estruturas entry_eff, exit_eff e trade_eff fields do arranjo m_deals_history[]) é realizada automaticamente durante a negociação virtual (ver a classe CSampeStrategy). Essa informação estatística pode ser utilizada para fazer as suas próprias, mais complexas taxas de efetividade de estratégia.

Por exemplo, como uma característica de efetividade você pode utilizar o lucro das últimas três negociações (utilizar o campo pos_Profit do arquivo de acordos m_deals_history[]):

double CSampleStrategy::StrategyPerformance()
  {
  //if there are deals, multiply this value by the result of three last deals
   if(m_virtual_deals_total>0)
     {
      int avdeals=MathRound(MathMin(3,m_virtual_deals_total));
      double sumprofit=0;
      for(int j=0; j<avdeals; j++)
        {
         sumprofit+=m_deals_history[m_virtual_deals_total-1-j].profit;
        }
      double performance=sumprofit/avdeals;
     }
     return(performance);

  }

Se você quer mudar essa função, modifique ela apenas na classe CSampleStrategy, ela deve ser a mesma para todas as estratégias de negociação do sistema adaptativo. No entanto, você deve lembrar que a diferença entre igualdade e balanço também é um bom fator de efetividade.

5.3 Utilizando take profit e stop loss

Você pode modificar a efetividade de sistemas de negociação configurando níveis fixos de parada (pode ser feito chamando a função Set_Stops; ela permite configurar os níveis de parada em pontos para negociação virtual). Se os níveis são especificados, o fechamento de posições virtuais será feito automaticamente; essa funcionalidade é implementada na classe CSampleStrategy.

Em nosso exemplo (ver 2.2 a função das classes de médias móveis), a função configurando os níveis de stop é comentada.

5.4. Zeroismo periódico do lucro virtual cumulativo

A abordagem adaptativa possui a mesma desvantagem que as estratégias comuns possuem. Se a estratégia liderante começa a perder, o sistema adaptativo começa a perder também. Essa é a razão porque algumas vezes você precisa "zeroizar" os resultados do trabalho de todas as estratégias e fechar todas as suas posições virtuais.

Para fazer isso, as seguintes funções são implementadas na classe CSampleStrategy:

// sets a value for cumulative "virtual profit"
 void              SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_perofit; };
//closes an open virtual position
 void              CloseVirtualPosition();

Um ponto de verificação desse tipo pode ser utilizado de tempo em tempo, por exemplo após cada N barras.

5.5. Sem milagres

Você deve se lembrar que o sistema adaptativo não é um graal (USDJPY H1, 4.01.2010-20.08.2010):

Figura 8. Curvas de balanço e igualdade do sistema adaptativo que utiliza sinais das melhores das 10 estratégias (USDJPY H1)

Figura 8. Curvas de balanço e igualdade do sistema adaptativo que utiliza sinais das melhores das 10 estratégias (USDJPY H1)

Curvas de igualdade de todas as estratégias são mostradas na figura 9.

Figura 9. Curvas de igualdade na conta com o sistema adaptativo baseado em 10 estratégias (USDJPY H1)

Figura 9. Curvas de igualdade na conta com o sistema adaptativo baseado em 10 estratégias(USDJPY H1)

Se não há estratégias rentáveis no sistema adaptativo, utilizá-las não é efetivo. Utilize estratégias rentáveis.

Nós devemos considerar outra coisa importante e interessante. Preste atenção ao comportamento da estratégia adaptativa no início da negociação:

Figura 10. Curvas de igualdade na conta com 10 estratégias da estratégia adaptativa

Figura 10. Curvas de igualdade na conta com 10 estratégias da estratégia adaptativa

À primeira vista, todas as estratégias tiveram resultados negativos e a estratégia adaptativa parou a negociação; então ela começou a trocar entre as estratégias que possuíam um resultado positivo; e, então, todas as estratégias se tornaram não rentáveis novamente.

Todas as estratégias possuem o mesmo balanço no início. E apenas depois de um tempo, uma ou outra estratégia se torna uma líder; assim é recomendado configurar uma limitação na estratégia adaptativa para evitar negociação nas primeiras barras. Para fazer isso, suplemente a função Expert_OnTick da classe CAdaptiveStrategy com uma variável, cujo valor é aumentado toda vez que uma nova barra aparece.

No começo, até o mercado escolher a melhor estratégia, você deveria se manter longe de negociações reais.


Conclusões

Nesse artigo nós consideramos um exemplo de sistema adaptativo que consiste em várias estratégias, cada uma das quais faz suas operações de negociação "virtual". Negociações reais são realizadas de acordo com os sinais da estratégia mais rentável no momento.

Obrigado por utilizar a abordagem orientada a objeto, classes para trabalhar com dados e classes de negociação da biblioteca padrão, a arquitetura do sistema pareceu ser simples e escalável; agora você pode facilmente criar e analisar os sistemas adaptativos que incluem centenas de estratégias de negociação.

P.S. Para conveniência da análise do comportamento dos sistemas adaptativos, a versão de depuração da classe CSampleStrategy está anexa (o arquivo adaptive-systems-mql5-sources-debug-en.zip). A diferença dessa versão é a criação de arquivos de texto durante o seu trabalho; eles contém os relatórios de resumo sobre a dinâmica de modificação do balanço/igualdade virtual das estratégias inclusas no sistema.

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

Guia para testes e otimização de Expert Advisors no MQL5 Guia para testes e otimização de Expert Advisors no MQL5
Este artigo explica o processo passo-a-passo de identificação e solução de erros de código, assim como os passos para testar e otimizar os parâmetros de entrada do Expert Advisor. Você aprenderá como utilizar o Strategy Tester do terminal do cliente MetaTrader 5 para descobrir o melhor símbolo e definição dos parâmetros de entrada para seu Expert Advisor.
OOP no MQL5 por exemplo: Processando os avisos e os códigos de erro OOP no MQL5 por exemplo: Processando os avisos e os códigos de erro
O artigo descreve um exemplo de criação de classe para trabalho com os códigos de retorno do servidor de negócio e todos os erros que ocorrem durante a execução do programa MQL. Leia o artigo e você aprenderá como trabalhar com classes e objetos no MQL5. Ao mesmo tempo, esta é uma ferramenta conveniente para manipular erros; e você ainda pode mudar esta ferramenta de acordo com suas necessidades específicas.
Ordens, posições e negócios no MetaTrader 5 Ordens, posições e negócios no MetaTrader 5
A criação robusta de um robô de negócio não pode ser feita sem um entendimento dos mecanismos do sistema de negócio do MetaTrader 5. O terminal do cliente recebe as informações sobre as posições, ordens e negócios a partir do servidor de negócio. Para manipular estes dados adequadamente utilizando o MQL5, é necessário ter um bom entendimento da interação entre o programa MQL5 e o terminal do cliente.
Aplicação prática de bancos de dados para análise de mercado Aplicação prática de bancos de dados para análise de mercado
Trabalhar com dados se tornou a tarefa principal para o software moderno - tanto para aplicativos autônomos quanto para os de rede. Para solucionar esse problema um software especializado foi criado. São sistemas de gerenciamento de banco de dados (DBMS) que podem estruturar, sistematizar e organizar dados para seu armazenamento e processamento. Quanto aos negócios, a maioria dos analistas não utiliza bancos de dados em seu trabalho. Mas existem tarefas para as quais essa solução teria que ser útil. Este artigo fornece um exemplo de indicadores que podem salvar e carregar dados da partir de bancos de dados com ambas arquiteturas cliente-servidor ou arquivo-servidor.