Exemplo de Expert Advisor

MetaQuotes | 29 abril, 2016

Este artigo exibe os princípios de desenvolvimento de programas em MQL4 mediante a criação de um sistema Expert Advisor simples de exemplo com base no indicador MACD padrão. Neste Expert Advisor, nós também veremos exemplos de implementação de tais características como a criação dos níveis de take profit com suporte ao stop móvel (trailing stop), bem como a maioria dos meios que garantam um funcionamento seguro. Em nosso exemplo, a negociação é feita através da abertura e gestão de uma única posição.

Princípios de negociação:

  • Entrada de compra (BUY) - Indicador MACD está abaixo de zero, vai para cima e cruza a linha de sinal que vai para baixo.

  • Entrada de venda (SELL) - Indicador MACD está acima de zero, vai para baixo e cruza a linha de sinal que vai para cima.

  • Encerramento da compra - pela execução do take profit, pela execução do trailing stop ou quando o MACD cruzar a linha de sinal (MACD está acima de zero, vai para baixo e cruza a linha de sinal que vai para cima).

  • Encerramento da venda - pela execução do take profit, pela execução do trailing stop ou quando o MACD cruzar a linha de sinal (MACD está abaixo de zero, vai para cima e cruza a linha de sinal que vai para baixo).

Notícia importante: para excluir alterações insignificantes do indicador MACD (pequenas 'colinas' no gráfico) de nossa análise, introduzimos uma medida adicional para controlar o tamanho das "colinas" plotadas como se segue: o tamanho do indicador deve ser de, pelo menos, 5 unidades do preço mínimo (5*Point, o que para USD/CHF = 0.0005 e para o USD/JPY = 0.05).


Passo 1 - Escrever a descrição do Expert Advisor


 Aponte o cursor do mouse na seção Expert Advisors da janela do navegador, pressione o botão direito do mouse e selecione o comando "Criar no MetaEditor" no menu que aparece. O Assistente de Inicialização do Expert Advisor irá pedir-lhe para introduzir determinados dados. Na janela que aparece, escreva o nome (Nome) do Expert Advisor - Exemplo MACD, o autor (Autor) - indique o seu nome, o link (Link) - um link para seu website, nas notas (Notas) - Exemplo de teste de um Expert Advisor baseado no MACD.


Passo 2 - Criar a estrutura primária do programa

O código-fonte do Expert Advisor só irá ocupar várias páginas, mas mesmo esse volume é muitas vezes difícil de entender, especialmente pelo fato de não sermos programadores profissionais - caso contrário, não teríamos necessidade de descrever tudo, não é mesmo? :)

Para se ter uma ideia da estrutura de um Expert Advisor padrão, vamos dar uma olhada na descrição dada abaixo:

  1. Variáveis de inicialização

  2. Verificação dos dados iniciais

    • consultar a tabela, número de barras no gráfico

    • verificar os valores das variáveis ​​externas: Lots, S/L, T/P, T/S

  3. Definir as variáveis ​​internas para acessar os dados de forma rápida

  4. Verificar o terminal de negociação - ele esta vazio? Se sim, então:

    • verificações: disponibilidade de saldo na conta etc ...

    • é possível abrir uma posição comprada (BUY)?

      • abrir uma posição comprada e encerrar

  5. é possível abrir uma posição vendida (SELL)?

    • abrir uma posição vendida e encerrar

encerrar o Expert Advisor...
                    • Controle das posições previamente abertas no ciclo

                      • se for uma posição comprada

                        • ela deve ser fechada?

                        • o stop móvel deve ser resetado?

                      • se for uma posição comprada

                        • ela deve ser fechada?

                        • o stop móvel deve ser resetado?

                    • Ele acaba por ser bastante simples, apenas 4 blocos principais.

                      Agora vamos tentar gerar pedaços do código passo a passo para cada seção da estrutura do esquema:

                      1. Variáveis de inicialização
                        Primeiramente, todas as variáveis ​​a serem utilizadas no programa Expert devem ser definidas de acordo com a sintaxe da linguagem MQL 4. É por isso que inserimos o bloco para inicializar as variáveis ​​no início do programa

                        extern double TakeProfit = 50;
                        extern double Lots = 0.1;
                        extern double TrailingStop = 30;
                        extern double MACDOpenLevel=3;
                        extern double MACDCloseLevel=2;
                        extern double MATrendPeriod=26;
                        

                        A linguagem MQL 4 é completada pelo termo "variáveis ​​externas". Variáveis ​​externas podem ser definidas por fora sem modificar o código fonte do programa. Ela fornece flexibilidade adicional. No nosso programa, a variável MATrendPeriod é definida como uma variável extern. Nós inserimos a definição dessa variável, no início do programa.

                        extern double MATrendPeriod=26;
                      2. Verificação dos dados iniciais
                        Esta parte do código é geralmente utilizado em qualquer Expert com pequenas modificações, porque é um bloco de verificação praticamente padrão:

                        // verificações dos dados iniciais
                        // ele é importante para se certificar de que o Expert trabalhe com um gráfico,
                        // normal e o usuário não cometa erros nas configurações externas 
                        // variáveis (Lots, StopLoss, TakeProfit, 
                        // TrailingStop) no nosso caso, vamos verificar o TakeProfit
                        // em um gráfico menor do que 100 barras
                           if(Bars<100)
                             {
                              Print("menor do que 100 barras");
                              return(0);  
                             }
                           if(TakeProfit<10)
                             {
                              Print("TakeProfit menor que 10");
                              return(0);  // verifica o TakeProfit
                             }
                        
                      3. Definindo as variáveis ​​internas para acesso rápido aos dados
                        No código-fonte, muitas vezes é necessário acessar os valores dos indicadores ou lidar com os valores calculados. Para simplificar a codificação e acelerar o acesso, os dados são colocados em variáveis ​​internas.

                        int start()
                          {
                           double MacdCurrent, MacdPrevious, SignalCurrent;
                           double SignalPrevious, MaCurrent, MaPrevious;
                           int cnt, ticket, total;
                        
                        // para simplificar a codificação e acelerar o acesso
                        // os dados são colocados em variáveis ​​internas
                           MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
                           MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
                           SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
                           SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
                           MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
                           MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
                        

                        Agora, em vez da notação monstruosa de IMACD (NULL, 0,12,26,9, PRICE_CLOSE, MODE_MAIN, 0), você pode usar MacdCurrent no código-fonte.

                      4. Verificar o terminal de negociação - ele está vazio? Se sim, então:
                        No nosso Expert Advisor, usamos apenas as posições que são abertas com ordens a mercado, nós não lidamos com as ordens pendentes. No entanto, para estar do lado seguro, vamos apresentar uma verificação do terminal de negociação para ordens colocadas anteriormente:

                         total=OrdersTotal();
                           if(total<1) 
                             {
                        
                        • verificações: disponibilidade de saldo na conta etc...
                          Antes de analisar a situação do mercado, é aconselhável verificar o estado de sua conta para se certificar de que existem recursos livres para ele abrir uma posição.

                                if(AccountFreeMargin()<(1000*Lots))
                                  {
                                   Print("Nós não temos dinheiro. Margem Livre = ", AccountFreeMargin());
                                   return(0);  
                                  }
                          
                        • é possível abrir uma posição comprada (BUY)?
                          Condição de entrada para a posição comprada: MACD estar abaixo de zero, vai para cima e cruza a linha de sinal que vai para baixo. Isto é como nós descrevemos ele em MQL4 (note que operamos sobre os valores dos indicadores que foram salvos anteriormente nas variáveis):

                                // verificar a possibilidade de abrir uma posição comprada (long)
                                if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
                                   MacdPrevious<SignalPrevious &&
                                   MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && 
                                   MaCurrent>MaPrevious)
                                  {
                                   ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,
                                                    "macd sample",16384,0,Green);
                                   if(ticket>0)
                                     {
                                      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
                                         Print("Ordem BUY aberta : ",OrderOpenPrice());
                                     }
                                   else Print("Erro ao abrir uma ordem BUY : ",GetLastError()); 
                                   return(0); 
                                  }
                          

                          Um controle adicional sobre o tamanho das 'colinas' já foi mencionado acima. A variável MACDOpenLevel é definida pelo usuário, podendo ser alterada, sem interferir com o código, para assegurar uma maior flexibilidade. No início do programa nós inserimos uma descrição desta variável (bem como a descrição da variável usado abaixo).

                        • é possível abrir uma posição vendida (SELL)?
                          Condição de entrada de uma posição vendida: MACD está acima de zero, vai para baixo e cruza a linha de sinal que vai para cima. A notação é como se segue:

                                    // verificar a possibilidade de abrir uma posição vendida (SELL)
                                    if(MacdCurrent>0 && MacdCurrentSignalPrevious && 
                                       MacdCurrent>(MACDOpenLevel*Point) && 
                                       MaCurrent<MaPrevious)
                                      {
                                       ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,
                                                        "macd sample",16384,0,Red);
                                       if(ticket>0)
                                         {
                                          if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
                                             Print("Ordem SELL aberta : ",OrderOpenPrice());
                                         }
                                       else Print("Erro ao abrir uma ordem SELL : ",GetLastError()); 
                                       return(0); 
                                      }
                          
                            return(0);
                           }
                          

                      5. Controle das posições previamente abertas no ciclo

                        // é importante entrar no mercado corretamente, 
                        // mas é mais importante sair corretamente...   
                        for(cnt=0;cnt
                          {
                           OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
                           if(OrderType()<=OP_SELL &&   // verifica posições em aberto 
                              OrderSymbol()==Symbol())  // verifica o símbolo
                             {
                        

                        "cnt" - "é uma variável contadora que deve ser definida no início do programa, tal como se segue:

                         int cnt = 0; 
                        • se for uma posição comprada

                          if(OrderType()==OP_BUY)   // está aberto uma posição comprada
                            {
                          
                          
                          • ela deve ser fechada?
                            Condição para sair de uma posição comprada: MACD cruza a linha de sinal, MACD estando acima de zero, indo para baixo e cruzando a linha de sinal que vai para cima.

                            if(MacdCurrent>0 && MacdCurrent<SignalPrevious &&
                               MacPrevious>SignalPrevious &&
                               MacdCurrent>(MACDCloseLevel*Point))
                              {
                               OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // fecha a posição
                               return(0); // exit
                              }
                            
                          • o stop móvel deve ser resetado?
                            Nós definimos o stop móvel apenas no caso da posição já tiver um lucro superior ao nível do stop móvel em pontos, e no caso do novo nível de stop for melhor do que o anterior.

                            // verificar o stop móvel
                            if(TrailingStop>0)  
                              {                 
                               if(Bid-OrderOpenPrice()>Point*TrailingStop)
                                 {
                                  if(OrderStopLoss()
                                    {
                                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,
                                                 OrderTakeProfit(),0,Green);
                                     return(0);
                                    }
                                 }
                              }
                            

                          Nós fechamos a chave do operador.

                             }
                      6. se for uma posição comprada

                        else // vai para uma posição vendida
                          {
                        
                        • ela deve ser fechada?
                          Condição para sair de uma posição venida: MACD cruza sua linha de sinal, MACD esta abaixo de zero, indo para cima e cruzando a linha de sinal que vai para baixo.

                          if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
                             MacdPrevious<SignalPrevious &&
                             MathAbs(MacdCurrent)>(MACDCloseLevel*Point))
                            {
                             OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // fecha a posição
                             return(0); // exit
                            }
                          
                        • o stop móvel deve ser resetado?
                          Nós definimos o stop móvel apenas no caso da posição já tiver um lucro superior ao nível do stop móvel em pontos, e no caso do novo nível de stop for melhor do que o anterior.

                          // verificar o stop móvel
                          if(TrailingStop>0)  
                            {                 
                             if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                               {
                                if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                                  {
                                   OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,
                                               OrderTakeProfit(),0,Red);
                                   return(0);
                                  }
                               }
                            }
                          

                        Fechando todos os colchetes que permaneceram abertos.

                                 }
                              }
                           }
                         return(0);
                        }
                        

                  Então, seguindo este procedimento passo-a-passo, nós escrevemos o nosso Expert Advisor...

                  Passo 3 - Montagem do código resultante do programa

                  Vamos abrir as configurações do Expert Advisor (usando um botão ou uma linha em "Propriedades ..." do menu). Nos é oferecido uma janela na qual temos que definir as configurações externas dos parâmetros de trabalho:



                  Vamos montar todo o código da seção anterior:

                  //+------------------------------------------------------------------+
                  //|                                                  MACD Sample.mq4 |
                  //|                      Copyright © 2005, MetaQuotes Software Corp. |
                  //|                                       https://www.metaquotes.net/ |
                  //+------------------------------------------------------------------+
                  extern double TakeProfit = 50;
                  extern double Lots = 0.1;
                  extern double TrailingStop = 30;
                  extern double MACDOpenLevel=3;
                  extern double MACDCloseLevel=2;
                  extern double MATrendPeriod=26;
                  
                  //+------------------------------------------------------------------+
                  //|                                                                  |
                  //+------------------------------------------------------------------+
                  int start()
                    {
                     double MacdCurrent, MacdPrevious, SignalCurrent;
                     double SignalPrevious, MaCurrent, MaPrevious;
                     int cnt, ticket, total;
                  // verificações dos dados iniciais
                  // ele é importante para se certificar de que o Expert trabalhe com um gráfico,
                  // normal e o usuário não cometa erros nas configurações externas 
                  // variáveis (Lots, StopLoss, TakeProfit, 
                  // TrailingStop) no nosso caso, vamos verificar o TakeProfit
                  // em um gráfico menor do que 100 barras
                     if(Bars<100)
                       {
                        Print("menor do que 100 barras");
                        return(0);  
                       }
                     if(TakeProfit<10)
                       {
                        Print("TakeProfit menor que 10");
                        return(0);  // verifica o TakeProfit
                       }
                  // para simplificar a codificação e acelerar o acesso
                  // os dados são colocados em variáveis ​​internas
                     MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
                     MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
                     SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
                     SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
                     MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
                     MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
                     total=OrdersTotal();
                     if(total<1) 
                       {
                        // não foi identificado nenhuma ordem aberta
                        if(AccountFreeMargin()<(1000*Lots))
                          {
                           Print("Nós não temos dinheiro. Margem Livre = ", AccountFreeMargin());
                           return(0);  
                          }
                        // verificar a possibilidade de abrir uma posição comprada (long)
                        if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
                           MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
                          {
                           ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
                           if(ticket>0)
                             {
                              if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Ordem BUY aberta : ",OrderOpenPrice());
                             }
                           else Print("Erro ao abrir uma ordem BUY : ",GetLastError()); 
                           return(0); 
                          }
                        // verificar a possibilidade de abrir uma posição vendida (SELL)
                        if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
                           MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)
                          {
                           ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
                           if(ticket>0)
                             {
                              if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("Ordem SELL aberta : ",OrderOpenPrice());
                             }
                           else Print("Erro ao abrir uma ordem SELL : ",GetLastError()); 
                           return(0); 
                          }
                        return(0);
                       }
                     // é importante entrar no mercado corretamente, 
                     // mas é mais importante sair corretamente...   
                     for(cnt=0;cnt<total;cnt++)
                       {
                        OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
                        if(OrderType()<=OP_SELL &&   // verifica posições em aberto 
                           OrderSymbol()==Symbol())  // verifica o símbolo
                          {
                           if(OrderType()==OP_BUY)   // está aberto uma posição comprada
                             {
                              // ela deve ser fechada?
                              if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
                                 MacdCurrent>(MACDCloseLevel*Point))
                                  {
                                   OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // fecha a posição
                                   return(0); // exit
                                  }
                              // verificar o stop móvel
                              if(TrailingStop>0)  
                                {                 
                                 if(Bid-OrderOpenPrice()>Point*TrailingStop)
                                   {
                                    if(OrderStopLoss()<Bid-Point*TrailingStop)
                                      {
                                       OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                                       return(0);
                                      }
                                   }
                                }
                             }
                           else // vai para uma posição vendida
                             {
                              // ela deve ser fechada?
                              if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
                                 MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point))
                                {
                                 OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // fecha a posição
                                 return(0); // exit
                                }
                              // verificar o stop móvel
                              if(TrailingStop>0)  
                                {                 
                                 if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
                                   {
                                    if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                                      {
                                       OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                                       return(0);
                                      }
                                   }
                                }
                             }
                          }
                       }
                     return(0);
                    }
                  // o fim.
                  

                  Para a configuração final de nosso Expert Advisor, basta especificar os valores das variáveis ​​externas "Lots = 1", "Stop Loss (S/L) = 0" (não utilizado), "Take Profit (T/P) = 120" ( apropriado para intervalos de uma hora), "Stop móvel (T/S) = 30". É claro que você pode definir os seus próprios valores. Pressione o botão "Compilar" e, se não houver nenhuma mensagem de erro (por sinal, você pode copiar o texto a partir da listagem acima no MetaEditor), pressione o botão "Salvar" para salvar o Expert Advisor.