English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Criando um Expert Advisor multissistema e multimoeda

Criando um Expert Advisor multissistema e multimoeda

MetaTrader 5Exemplos | 28 março 2014, 15:12
2 456 0
Maxim Khrolenko
Maxim Khrolenko

Introdução

Eu acredito que existam pouquíssimos traders que operem mais que um símbolo e que usem várias estratégias. Essa abordagem não só permite que você, potencialmente, aumente o seu lucro, mas também minimiza o risco de perdas significativas. Ao criar um Expert Advisor, o primeiro passo natural para a verificação da eficiência da estratégia do programa é a otimização, a fim de determinar os melhores parâmetros de entrada.

Com os valores dos parâmetros identificados, os Expert Advisors estariam tecnicamente prontos para negociação. No entanto, isso deixaria uma importante questão sem resposta. Quais seriam os resultados dos testes se um trader pudesse colocar todas as suas estratégias juntas em um único Expert Advisor? A percepção de que os rebaixamentos em vários símbolos ou estratégias podem, em algum ponto, se sobrepor resultado em um rebaixamento geral terrível ou mesmo em uma chamada de margem pode, por vezes, chegar como uma surpresa desagradável.

Este artigo introduz um conceito de criação de Expert Advisor multissistema e multimoeda que nos permitirá encontrar uma resposta a esta importante questão.


1. Estrutura do Expert Advisor

Em termos gerais, a estrutura do Expert Advisor é como a seguir:

Estrutura do Expert Advisor multissistema e multimoeda

Fig. 1. Estrutura do Expert Advisor multissistema e multimoeda

Como você pode ver, o programa é baseado em um ciclo for. Cada estratégia é organizada em um ciclo onde cada iteração é responsável pela negociação de cada símbolo separadamente. Aqui, você pode organizar em ciclos um número ilimitado de estratégias. O importante para o seu computador é ter recursos suficientes para processar tal programa.

Você deve ter em mente que pode haver apenas uma posição para cada símbolo negociado no MetaTrader 5. Essa posição representa a soma de muitas compras e vendas executadas anteriormente. Por conseguinte, o resultado do teste multiestratégia para um símbolo não será idêntico à soma dos resultados de testes separados das mesmas estratégias para o mesmo símbolo.

Para uma análise mais aprofundada da estrutura do Expert Advisor tomaremos duas estratégias cada uma das quais negociará dois símbolos:

Estratégia A:

  • Compra: preço Ask atingindo a banda inferior do indicador Bollinger Bands calculado com base no preço Low.
    Fechamento: preço Bid atingindo a banda inferior do indicador Bollinger Bands calculado com base no preço High.
  • Venda: preço Bid atingindo a banda superior do indicador Bollinger Bands calculado com base no preço High.
    Fechamento: preço Ask atingindo a banda superior do indicador Bollinger Bands calculado com base no preço Low.
  • Restrição: em cada barra apenas pode ser executado um negócio.

Estratégia B:

  • Compra: barra anterior baixista (close < open) e preço Ask atingindo o High da barra anterior.
    Fechamento: por Stop Loss ou Take Profit.
  • Venda: barra anterior altista (close > open) e preço Bid atingindo o Low da barra anterior.
    Fechamento: por Stop Loss ou Take Profit.
  • Restrição: em cada barra apenas pode ser executado um negócio.

A fim de não depender dos novos ticks do símbolo em que será testado ou que operará o Expert Advisor, é aconselhável usar a função OnTimer() para negociação no modo multimoeda.

Para fazer isso, ao inicializar o Expert Advisor, especificamos - com a ajuda da função EventSetTimer() - a frequência com que será gerado o evento para chamar o cálculo do programa, enquanto, se a função EventKillTimer() for desinicializada, indicamos ao terminal que suspenda a geração de eventos:

// Conectamos as bibliotecas padrão
// Criamos parâmetros externos
// Criamos matrizes, variáveis, indicadores de indicador, etc.

//--- Inicializando o Expert Advisor
int OnInit()
  {
   //--- Definimos a periodicidade da geração do evento
   EventSetTimer(1); // 1 segundo
   // ...
   return(0);
  }
void OnTimer()
  {
   // ...
  }
//--- Desinicializando o Expert Advisor
void OnDeinit(const int reason)
  {
   //--- Parando a geração de eventos
   EventKillTimer();
   // ...
  }

Em vez de EventSetTimer(), você também pode usar EventSetMillisecondTimer(), a fim de definir a frequência em milissegundos, mas não abuse muito dela chamando o cálculo do programa frequentemente.

Para acessar as configurações da conta, das posições, dos símbolos, bem como das funções de negociação, usaremos as classes CAccountInfo, CPositionInfo, CSymbolInfo e CTrade, respectivamente. Vamos incluí-las no Expert Advisor:

//--- Conectamos as bibliotecas padrão
#include <Trade\AccountInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\Trade.mqh>

Como o Expert Advisor é baseado em ciclos for, precisaremos criar matrizes para seus parâmetros externos. Vamos primeiro criar constantes iguais ao número de símbolos para cada estratégia:

//--- Número de símbolos negociados para cada estratégia
#define Strategy_A 2
#define Strategy_B 2

Nós, então, criamos parâmetros externos. Usando constantes, determinamos o tamanho das matrizes para as quais serão copiados. Além disso, criamos identificadores de indicadores e outras variáveis globais.

Um exemplo de um símbolo de estratégia А é fornecido abaixo:

//------------------- Parâmetros externos da estratégia A
input string          Data_for_Strategy_A="Strategy A -----------------------";
//--- Símbolo 0
input string          Symbol_A0      = "EURUSD";   // Símbolo
input bool            IsTrade_A0     = true;       // Permissão para negociar
//--- Parâmetros do Bollinger Bands (BB)
input ENUM_TIMEFRAMES Period_A0      = PERIOD_H1;  // Período do ВВ
input uint            BBPeriod_A0    = 20;         // Período de cálculo da linha média do BB
input int             BBShift_A0     = 0;          // Deslocamento horizontal do ВВ
input double          BBDeviation_A0 = 2.0;        // Número de desvios padrão do BB
//...
//--- Parâmetros gerais da estratégia А
input double          DealOfFreeMargin_A = 1.0;    // Porcentagem de fundos disponíveis para o negócio
input uint            MagicNumber_A      = 555;    // Número mágico
input uint            Slippage_A         = 100;    // Slippage admissível para o negócio
//...
//------------- Definimos as variáveis da estratégia A -----
//--- Matrizes para parâmetros externos
string          Symbol_A[Strategy_A];
bool            IsTrade_A[Strategy_A];
ENUM_TIMEFRAMES Period_A[Strategy_A];
int             BBPeriod_A[Strategy_A];
int             BBShift_A[Strategy_A];
double          BBDeviation_A[Strategy_A];
//--- Matrizes para variáveis ​​globais
double          MinLot_A[Strategy_A],MaxLot_A[Strategy_A];
double          Point_A[Strategy_A],ContractSize_A[Strategy_A];
uint            DealNumber_A[Strategy_A];
datetime        Locked_bar_time_A[Strategy_A],time_arr_A[];
//--- Identificadores de indicador
int             BB_handle_high_A[Strategy_A];
int             BB_handle_low_A[Strategy_A];
//--- Matrizes para os valores dos indicadores
double          BB_upper_band_high[],BB_lower_band_high[];
double          BB_upper_band_low[],BB_lower_band_low[];
//--- Classe
CTrade          Trade_A;
//...
//--- Definimos variáveis ​​globais para todas as estratégias
long            Leverage;
//--- Classes
CAccountInfo    AccountInfo;
CPositionInfo   PositionInfo;
CSymbolInfo     SymbolInfo;

A fim de ter a possibilidade de desativar negociação para um determinado símbolo, criamos uma variável booliana IsTrade_A0 que será colocada bem no início dos ciclos for.


2. Inicialização do Expert Advisor

Primeiro, vamos obter os valores necessários para todas as estratégias, por exemplo, o tamanho de alavancagem. Uma vez que a alavancagem é aplicada à conta de negociação e não depende de uma estratégia ou de um símbolo, não há necessidade de copiar o seu valor para as matrizes:

//--- Obtemos o tamanho da alavancagem da conta
   Leverage=AccountInfo.Leverage();

Copiamos as variáveis externas para matrizes.

//--- Copiamos os parâmetros externos para as matrizes
   Symbol_A[0]     =Symbol_A0;
   IsTrade_A[0]    =IsTrade_A0;
   Period_A[0]     =Period_A0;
   BBPeriod_A[0]   =(int)BBPeriod_A0;
   BBShift_A[0]    =BBShift_A0;
   BBDeviation_A[0]=BBDeviation_A0;

Se o tipo a ser convertido para um outro definir um parâmetro externo, essa conversão poderá ser feita mais convenientemente durante a cópia para matrizes.

Nesse caso, podemos ver que BBPeriod_A0 foi criado como uint, para impedir que o usuário defina um valor negativo. Neste lugar, nós o convertemos em int e copiamos para matriz que também foi criada como int. Caso contrário, o compilador dará o aviso de que você está tentando inserir parâmetro do tipo uint no identificador de indicador.

Vamos ainda ver se o símbolo negociado está disponível na 'Observação do Mercado' e se ele foi usado mais de uma vez dentro de uma estratégia:

//--- Verificamos a presença de símbolo na 'Observação do mercado'
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      if(IsSymbolInMarketWatch(Symbol_A[i])==false)
        {
         Print(Symbol_A[i]," não encontrado no servidor!");
         ExpertRemove();
        }
     }

//--- Verificamos se o símbolo é usado mais de uma vez
   if(Strategy_A>1)
     {
      for(int i=0; i<Strategy_A-1; i++)
        {
         if(IsTrade_A[i]==false) continue;
         for(int j=i+1; j<Strategy_A; j++)
           {
            if(IsTrade_A[j]==false) continue;
            if(Symbol_A[i]==Symbol_A[j])
              {
               Print(Symbol_A[i]," é usado mais de uma vez!");
               ExpertRemove();
              }
           }
        }
     }
//--- Função IsSymbolInMarketWatch()
bool IsSymbolInMarketWatch(string f_Symbol)
  {
   for(int s=0; s<SymbolsTotal(false); s++)
     {
      if(f_Symbol==SymbolName(s,false))
         return(true);
     }
   return(false);
  }

Se os símbolos foram selecionados corretamente, verifique se há erros nos parâmetros de entrada para cada um deles, crie identificadores de indicadores, obtenha os dados necessários para o cálculo de lote, e, se necessário, faça outras coisas, conforme estabelecido pela estratégia fornecida.

Implementaremos as ações acima mencionadas dentro de um ciclo for.

//--- Ações gerais
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      //--- Verificamos se há erros nos parâmetros de entrada
      //...
      //--- Definimos o identificador dos indicadores
      BB_handle_high_A[i]=iBands(Symbol_A[i],Period_A[i],BBPeriod_A[i],BBShift_A[i],BBDeviation_A[i],
                                 PRICE_HIGH);
      if(BB_handle_high_A[i]<0)
        {
         Print("Erro ao criar o identificador do Bollinger Bands baseado em preços High para ",Symbol_A[i],". Identificador=",INVALID_HANDLE,
               "\n Erro=",GetLastError());
         ExpertRemove();
        }
      //...
      //--- Calculamos os dados para o Lote
      //--- Definimos o nome do símbolo para o qual será recebida a informação
      SymbolInfo.Name(Symbol_A[i]);
      //--- tamanhos mínimo e máximo do volume nas operações de negociação
      MinLot_A[i]=SymbolInfo.LotsMin();
      MaxLot_A[i]=SymbolInfo.LotsMax();
      //--- tamanho do ponto
      Point_A[i]=SymbolInfo.Point();
      //--- tamanho do contrato
      ContractSize_A[i]=SymbolInfo.ContractSize();

      //--- Definimos alguns parâmetros adicionais
     }

Em seguida, definimos os parâmetros para operações de negociação da estratégia A usando o objeto Trade_A da classe CTrade.

//--- Definimos os parâmetros para operações de negociação
//--- Definimos o número mágico
   Trade_A.SetExpertMagicNumber(MagicNumber_A);
//--- Definimos a derrapagem admissível em pontos ao fazer um negócio
   Trade_A.SetDeviationInPoints(Slippage_A);
//--- Modo de preenchimento da ordem, é preciso usar o modo que é permitido pelo servidor
   Trade_A.SetTypeFilling(ORDER_FILLING_RETURN);
//--- Modo logging, é melhor não chamar esse método, a própria classe irá definir o modo ideal
   Trade_A.LogLevel(1);
//--- Função a usar para negociação: true - OrderSendAsync(), false - OrderSend().
   Trade_A.SetAsyncMode(true);

O mesmo procedimento é repetido para cada uma das estratégias, por exemplo.

  1. Copie variáveis externas para matrizes;
  2. Verifique se os símbolos são selecionados corretamente;
  3. Verifique os erros, defina identificadores de indicadores, calcule dados para o lote e para tudo o que for necessário para uma determinada estratégia;
  4. Defina parâmetros para as operações de negociação.

Finalmente, seria bom verificar se um e o mesmo símbolo é usado em várias estratégias (um exemplo para duas estratégias é fornecidos abaixo):

//--- Verificamos se o mesmo símbolo é usado em várias estratégias
   for(int i=0; i<Strategy_A; i++)
     {
      if(IsTrade_A[i]==false) continue;
      for(int j=0; j<Strategy_B; j++)
        {
         if(IsTrade_B[j]==false) continue;
         if(Symbol_A[i]==Symbol_B[j])
           {
            Print(Symbol_A[i]," usado em várias estratégias!");
            ExpertRemove();
           }
        }
     }

3. Ciclos de negociação "for"

A estrutura dos ciclos for dentro da função OnTimer() é como a seguir:

void OnTimer()
  {
//--- Verificamos se o terminal está conectado ao servidor de negociação
   if(TerminalInfoInteger(TERMINAL_CONNECTED)==false) return;

//--- Seção A: Ciclo principal do operador FOR para a estratégia A -----------
   for(int A=0; A<Strategy_A; A++)
     {
      //--- A.1: Verificamos se a negociação é permitida para o símbolo
      if(IsTrade_A[A]==false)
         continue; // suspender a iteração FOR atual

     }

//--- Seção B: Ciclo principal do operador FOR para a estratégia B -----------
   for(int B=0; B<Strategy_B; B++)
     {
      //--- B.1: Verificamos se a negociação é permitida para o símbolo
      if(IsTrade_B[B]==false)
         continue; // suspender a iteração FOR atual

     }
  }

Se um Expert Advisor 'monoestratégia' e 'monosímbolo' tiver uma condição em que todos os cálculos posteriores precisam ser interrompidos, usamos o operador return. No nosso caso, só precisamos terminar a iteração atual e prosseguir para a próxima iteração de símbolo. Por esse motivo, é melhor utilizar o operador continue.

Se você deseja melhorar seu Expert Advisor multiestratégia com a adição de uma estratégia com ciclo for contendo uma condição para interromper todos os cálculos posteriores, você pode usar o seguinte esquema:

//--- Seção N: Ciclo principal do operador FOR para a estratégia N -----------
for(int N=0; N<Strategy_N; N++)
  {

   //...
   bool IsInterrupt=false;
   for(int i=0; i<Number; i++)
     {
      if(...) // interromper todos os cálculos
        {
         IsInterrupt=true;
         break;
        }
     }
   if(IsInterrupt=true)
      continue; // interromper a iteração FOR atual
   //...

  }

Depois de criar a estrutura do ciclo for, simplesmente inserimos nele os códigos de outros EAs e, em seguida, substituímos algumas variáveis por elementos de matriz.

Por exemplo, alteramos a variável predefinida _Symbol para Symbol_A[i] ou _Point para Point_A[i]. Os valores dessas variáveis​ são típicos do símbolo fornecido e, portanto, foram copiados para matrizes na inicialização.

Por exemplo, vamos encontrar o valor do indicador:

 //--- A.3: Banda inferior do BB calculada com base no preço High
 if(CopyBuffer(BB_handle_high_A[A],LOWER_BAND,BBShift_A[A],1,BB_lower_band_high)<=0)
    continue; // suspendemos a iteração FOR atual
 ArraySetAsSeries(BB_lower_band_high,true);

Para implementar fechamento de uma posição de compra, escreveremos o seguinte código:

 //--- A.7.1: Calculamos os preços Ask e Bid atuais
 SymbolInfo.Name(Symbol_A[A]);
 SymbolInfo.RefreshRates();
 double Ask_price=SymbolInfo.Ask();
 double Bid_price=SymbolInfo.Bid();

 if(PositionSelect(Symbol_A[A]))
   {
    //--- A.7.2: Fechamos a posição BUY
    if(PositionInfo.PositionType()==POSITION_TYPE_BUY)
      {
       if(Bid_price>=BB_lower_band_high[0] || DealNumber_A[A]==0)
         {
          if(!Trade_A.PositionClose(Symbol_A[A]))
            {
             Print("Erro ao fechar a posição Buy ",Symbol_A[A],". Código=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // suspendemos a iteração FOR atual
            }
          else
            {
             Print("Fechamento da posição Buy ",Symbol_A[A]," bem-sucedido. Código=",Trade_A.ResultRetcode(),
                   " (",Trade_A.ResultRetcodeDescription(),")");
             continue; // suspendemos a iteração FOR atual
            }
         }
      }

    //...
   }

Abertura de uma posição de Compra:

 //--- A.9.1: para Compra
 if(Ask_price<=BB_lower_band_low[0])
   {
    //...

    //--- A.9.1.3: Executamos o negócio
    if(!Trade_A.Buy(OrderLot,Symbol_A[A]))
      {
       Print("Compra de ",Symbol_A[A]," falhou. Código=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // suspendemos a iteração FOR atual
      }
    else
      {
       Print("Compra de ",Symbol_A[A]," bem-sucedida. Código=",Trade_A.ResultRetcode(),
             " (",Trade_A.ResultRetcodeDescription(),")");
       continue; // suspendemos a iteração FOR atual
      }
   }

Durante desinicialização, lembre-se de encerrar a geração de eventos do temporizador e excluir o identificador de indicador.

void OnDeinit(const int reason)
  {
//--- Parando a geração de eventos
   EventKillTimer();
//--- Removemos os identificadores de indicador
   for(int i=0; i<Strategy_A; i++)
     {
      IndicatorRelease(BB_handle_high_A[i]);
      IndicatorRelease(BB_handle_low_A[i]);
     }
  }


4. Resultados do teste

Quando o Expert Advisor estiver pronto, testamos cada estratégia e cada símbolo separadamente, e comparamos com os resultados de teste no modo de negociação com todas as estratégias e símbolos simultaneamente.

Supõe-se que o usuário já tenha identificado os melhores valores dos parâmetros de entrada.


Abaixo estão as configurações do Testador de Estratégia:

Configurando o testador

Fig. 2. Configurando o Testador de Estratégia

Resultado para a estratégia A, símbolo EURUSD:

Resultado de teste para a estratégia A, símbolo EURUSD

Fig.3. Resultado de teste para a estratégia A, símbolo EURUSD

Resultado para a estratégia A, símbolo GBPUSD:

Resultado de teste para a estratégia A, símbolo GBPUSD

Fig.4. Resultado de teste para a estratégia A, símbolo GBPUSD

Resultado para a estratégia B, símbolo AUDUSD:

Resultado de teste para a estratégia B, símbolo AUDUSD

Fig. 5. Resultado de teste para a estratégia B, símbolo AUDUSD

Resultado para a estratégia B, símbolo EURJPY:

Resultado de teste para a estratégia B, símbolo EURJPY

Fig. 6. Resultado de teste para a estratégia B, símbolo EURJPY

Resultado de teste para todas as estratégias e símbolos:

Resultado de teste para todas as estratégias e símbolos

Fig. 7. Resultado de teste para todas as estratégias e símbolos


Fim do artigo

Como resultado, temos uma estrutura simples e conveniente de Expert Advisor multissistema e multimoeda que pode ser usada para colocar praticamente qualquer uma de suas estratégias.

Esse EA permitirá que você avalie melhor a eficiência da negociação utilizando todas as suas estratégias. Ele pode também ser útil no caso de apenas um Expert Advisor estar autorizado a trabalhar em uma determinada conta. O código fonte do Expert Advisor está anexo ao artigo para facilitar o estudo do material acima.


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

Arquivos anexados |
2multi_en.mq5 (30.27 KB)
Indicador para representação de gráfico Kagi Indicador para representação de gráfico Kagi
O artigo propõe o indicador de gráfico Kagi com várias opções e funções adicionais. Além disso, o princípio de tracejar gráficos e seus recursos de implementação MQL5 são considerados. Os casos mais populares de sua implementação em negociação são exibidos - estratégia de troca de Yin/Yang, afastando para longe a partir da linha de evolução gráfica e aumentando sistematicamente "ombros" e diminuindo "cinturas".
Guia prático do MQL5: Desenvolvimento de um indicador de símbolos múltiplos no MQL5 Guia prático do MQL5: Desenvolvimento de um indicador de símbolos múltiplos no MQL5
Neste artigo, vamos considerar o desenvolvimento de um indicador de volatilidade de símbolos múltiplos. O desenvolvimento de indicadores de símbolos múltiplos pode apresentar algumas dificuldades para os desenvolvedores novatos do MQL5, as quais este artigo ajuda a esclarecer. As principais questões que surgem no curso do desenvolvimento de um indicador de símbolos múltiplos têm a ver com sincronização de dados de outros símbolos em relação ao símbolo atual, a falta de alguns dados de indicadores e a identificação de início de barras 'reais' de um determinado período de tempo. Todas essas questões serão atentamente consideradas no artigo.
Vídeo tutorial: serviço de sinais do MetaTrader Vídeo tutorial: serviço de sinais do MetaTrader
Em apenas 15 minutos, este vídeo tutorial explica do que se trata o serviço de sinais do MetaTrader e demonstra com riqueza de detalhes como se inscrever para sinais de negociação e como se tornar um provedor de sinal em nosso serviço. Ao observar este tutorial, você será capaz de se inscrever para qualquer sinal de negociação ou publicar e promover seus próprios sinais em nosso serviço.
Guia prático do MQL5: Controles da sub-janela indicadora - barra de rolagem Guia prático do MQL5: Controles da sub-janela indicadora - barra de rolagem
Vamos continuar a explorar vários controles e desta vez a nossa atenção é para a barra de rolagem. Assim como no artigo anterior intitulado"Guia prático do MQL5: Os controles da sub-janela indicadora - botões", todas as operações serão realizadas na sub-janela indicadora. Tome um tempo para ler o artigo acima mencionado, uma vez que ele fornece uma descrição detalhada do trabalho com eventos na função OnChartEvent(), enquanto este ponto somente será casualmente abordado neste artigo. Para fins ilustrativos, desta vez vamos criar uma barra de rolagem vertical para uma grande lista de todas as propriedades de instrumentos financeiros que possam ser obtidas usando recursos do MQL5.