Início Negociação Sistemática Postagem

Média Móvel: Como Usar o EA no MetaTrader 5 para Maximizar seus Lucros

Anexo
1921.zip (1.81 KB, Baixar 0 vezes)

O EA de Média Móvel está incluído no pacote padrão do MetaTrader 5 e serve como um exemplo prático de como operar utilizando o indicador de Média Móvel.

O arquivo do EA, chamado Moving Average.mq5, pode ser encontrado na pasta "terminal_data_folder\MQL5\Experts\Examples\Moving Average". Este EA é um exemplo de uso de indicadores técnicos, funções de histórico de operações e classes de negociação da Biblioteca Padrão. Além disso, o EA inclui um sistema de gestão de risco baseado nos resultados das operações.

Vamos explorar a estrutura do Expert Advisor e como ele funciona.

1. Propriedades do EA

//+------------------------------------------------------------------+
//|                                              Moving Averages.mq5 |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2009-2013, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

As cinco primeiras linhas contêm um comentário e as três seguintes definem as propriedades do programa MQL5 (direitos autorais, link e versão) utilizando as diretivas do pré-processador #property.

Quando você executar o Expert Advisor, essas informações aparecerão na aba "Comum":


Figura 1. Parâmetros Comuns do EA de Média Móvel

1.2. Arquivos Inclusos

A diretiva #include informa ao compilador para incluir o arquivo "Trade.mqh".

Esse arquivo é parte da Biblioteca Padrão e contém a classe CTrade para facilitar o acesso às funções de negociação.

#include <Trade\Trade.mqh>

O nome do arquivo incluído aparece entre colchetes "<>;", então o caminho é definido em relação ao diretório: "terminal_data_folder\Include".

1.3 Entradas

Em seguida, são definidos o tipo, nome, valores padrão e um comentário. O papel deles é mostrado na figura 2.

input double MaximumRisk        = 0.02;    // Risco Máximo em porcentagem
input double DecreaseFactor     = 3;       // Fator de Redução
input int    MovingPeriod       = 12;      // Período da Média Móvel
input int    MovingShift        = 6;       // Deslocamento da Média Móvel

Os parâmetros MaximumRisk e DecreaseFactor serão utilizados para a gestão de risco, enquanto MovingPeriod e MovingShift definem o período e o deslocamento do indicador Média Móvel que será usado para verificar as condições de negociação.

O texto do comentário na linha do parâmetro de entrada, juntamente com os valores padrão, aparecem na aba "Opções" em vez do nome do parâmetro de entrada:


Figura 2. Parâmetros de Entrada do EA de Média Móvel

1.4. Variáveis Globais

A variável global ExtHandle é declarada e será usada para armazenar o identificador do indicador Média Móvel.

//---
int   ExtHandle=0;

Em seguida, temos seis funções. O propósito de cada uma delas é descrito no comentário antes do corpo da função:

  1. TradeSizeOptimized() - Calcula o tamanho ótimo do lote;
  2. CheckForOpen() - Verifica as condições para abrir uma posição;
  3. CheckForClose() - Verifica as condições para fechar uma posição;
  4. OnInit() - Função de inicialização do Expert;
  5. OnTick() - Função de execução em cada tick;
  6. OnDeinit() - Função de desinicialização do Expert;

As últimas três funções são funções de tratamento de eventos; as três primeiras são chamadas em seu código.

2. Funções de Tratamento de Eventos

2.1. A função OnInit()

A função OnInit() é chamada uma vez durante a primeira execução do Expert Advisor. Normalmente, no manipulador de eventos OnInit(), o EA é preparado para operação: os parâmetros de entrada são verificados, indicadores e parâmetros são inicializados, etc. Em caso de erros críticos, quando o funcionamento posterior é sem sentido, a função é encerrada com o código de retorno INIT_FAILED.

//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   ExtHandle=iMA(_Symbol,_Period,MovingPeriod,MovingShift,MODE_SMA,PRICE_CLOSE);
   if(ExtHandle==INVALID_HANDLE)
     {
      printf("Erro ao criar indicador MA");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Como a negociação do EA se baseia no indicador Média Móvel, ao chamar iMA(), o indicador de Média Móvel é criado e seu identificador é salvo na variável global ExtHandle.

Em caso de erro, a função OnInit() é encerrada com o código de retorno INIT_FAILED - essa é a maneira correta de finalizar a operação do EA/indicador em caso de inicialização malsucedida.

2.2. A função OnTick()

A função OnTick() é chamada sempre que uma nova cotação é recebida para o símbolo do gráfico em que o EA está rodando.

//+------------------------------------------------------------------+
//| Função de execução em cada tick                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(PositionSelect(_Symbol))
      CheckForClose();
   else
      CheckForOpen();
//---
  }

A função PositionSelect() é utilizada para verificar se existe uma posição aberta para o símbolo atual.

Se houver posições abertas, a função CheckForClose() é chamada, que analisa o estado atual do mercado e fecha a posição aberta; caso contrário, a função CheckForOpen() é chamada, que verifica as condições de entrada no mercado e abre uma nova posição se tais condições ocorrerem.

2.3. A função OnDeInit()

A função OnDeInit() é chamada quando um EA é removido do gráfico. Se um programa colocar objetos gráficos durante a operação, eles podem ser removidos do gráfico.

//+------------------------------------------------------------------+
//| Função de desinicialização do Expert                                   |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

Neste caso, nenhuma ação é executada durante a desinicialização do Expert Advisor.

3. Funções de Serviço

3.1. Função TradeSizeOptimized()

Essa função calcula e retorna o valor do tamanho ótimo do lote para abertura de posição com um nível de risco especificado e resultados de negociação.

//+------------------------------------------------------------------+
//| Calcular o tamanho ótimo do lote                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- Calcular o tamanho do lote
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_FREEMARGIN)*MaximumRisk/margin,2);
//--- calcular a série de perdas consecutivas
   if(DecreaseFactor>0)
     {
      //--- solicitar todo o histórico de negociações
      HistorySelect(0,TimeCurrent());
      //--
      int    orders=HistoryDealsTotal();  // total de negócios
      int    losses=0                    // número de negócios com perdas na série

      for(int i=orders-1;i>=0;i--)
        {
         ulong ticket=HistoryDealGetTicket(i);
         if(ticket==0)
           {
            Print("HistoryDealGetTicket falhou, sem histórico de negociações");
            break;
           }
         //--- verificando o símbolo do negócio
         if(HistoryDealGetString(ticket,DEAL_SYMBOL)!=_Symbol)
            continue;
         //--- verificando o lucro
         double profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);
         if(profit>0.0)
            break;
         if(profit<0.0)
            losses++;
        }
      //---
      if(losses>1)
         lot=NormalizeDouble(lot-lot*losses/DecreaseFactor,1);
     }
//--- normalizando e verificando os valores permitidos do volume de negociação
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- retornar o valor do volume de negociação
   return(lot);
  }

A função SymbolInfoDouble() é utilizada para verificar a disponibilidade de preços para o símbolo atual; em seguida, a função OrderCalcMargin() é usada para solicitar a margem necessária para colocar uma ordem (neste caso, uma ordem de compra). O tamanho inicial do lote é determinado a partir do valor da margem necessária para a colocação de uma ordem, a margem livre da conta (AccountInfoDouble(ACCOUNT_FREEMARGIN)) e o valor máximo de risco permitido especificado no parâmetro de entrada MaximumRisk.

Se o valor do parâmetro de entrada DecreaseFactor for positivo, negócios no histórico são analisados e o tamanho do lote é ajustado levando em consideração informações sobre a série máxima de operações perdedoras: o tamanho inicial do lote é multiplicado pelo tamanho (1-losses/DecreaseFactor).

Em seguida, o volume da operação é "arredondado" para um valor que é múltiplo do passo mínimo permitido de volume (stepvol) para o símbolo atual. Também são solicitados os valores mínimo (minvol) e máximo (maxvol) do volume de negociação, e se o valor do lote exceder os limites permitidos, ele é ajustado. Como resultado, a função retorna o valor calculado do volume de negociação.

3.2. Função CheckForOpen()

CheckForOpen() é utilizada para verificar as condições de abertura da posição e abri-la quando as condições de negociação ocorrerem (neste caso, quando o preço cruza a média móvel).

//+------------------------------------------------------------------+
//| Verificar condições para abrir posição                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- copiar os valores de preço
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates de ",_Symbol," falhou, sem histórico");
      return;
     }
//--- Negociar apenas no primeiro tick da nova barra
   if(rt[1].tick_volume>1)
      return;
//--- Obter o valor atual do indicador Média Móvel 
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer de iMA falhou, sem dados");
      return;
     }
//--- verificar os sinais
   ENUM_ORDER_TYPE signal=WRONG_VALUE;

   if(rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=ORDER_TYPE_SELL    // condição de venda
   else
       {
      if(rt[0].open<ma[0] && rt[0].close>ma[0])
         signal=ORDER_TYPE_BUY  // condição de compra
     }
//--- verificações adicionais
   if(signal!=WRONG_VALUE)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
                               SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                               0,0);
           }
//---
  }

Ao negociar utilizando a média móvel, você precisa verificar se o preço cruza a média móvel. Utilizando a função CopyRates(), dois valores dos preços atuais são copiados na estrutura de array rt[], rt[1] corresponde à barra atual, enquanto rt[0] - barra concluída.

Uma nova barra é iniciada verificando o volume de ticks da barra atual; se for igual a 1, então uma nova barra foi iniciada. Vale ressaltar que esse método de detectar uma nova barra pode falhar em alguns casos (quando as cotações chegam em lotes), então o fato de iniciar a formação de uma nova barra deve ser feito salvando e comparando o tempo da cotação atual (veja IsNewBar).

O valor atual do indicador de Média Móvel é solicitado usando a função CopyBuffer() e é salvo no array ma[] que contém apenas um valor. O programa então verifica se o preço cruzou a média móvel e realiza verificações adicionais (se a negociação utilizando o EA é possível e a presença de barras no histórico). Se for bem-sucedido, uma posição apropriada para o símbolo é aberta chamando o método PositionOpen() do objeto de negociação (uma instância da CTrade).

O preço de abertura da posição é definido utilizando a função SymbolInfoDouble() que retorna o preço Bid ou Ask dependendo do valor da variável signal. O volume da posição é determinado chamando TradeSizeOptimized() descrito acima.

3.3. Função CheckForClose()

CheckForClose() verifica as condições para fechamento de posição e a fecha se as condições para fechamento ocorrerem.

//+------------------------------------------------------------------+
//| Verificar condições para fechar posição                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- Copiar valores de preço
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates de ",_Symbol," falhou, sem histórico");
      return;
     }
//--- Negociar apenas no primeiro tick da nova barra
   if(rt[1].tick_volume>1)
      return;
//--- obter o valor atual do indicador Média Móvel
   double   ma[1];
   if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)
     {
      Print("CopyBuffer de iMA falhou, sem dados");
      return;
     }
//--- obter o tipo da posição selecionada anteriormente usando PositionSelect()
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);

   if(type==(long)POSITION_TYPE_BUY   && rt[0].open>ma[0] && rt[0].close<ma[0])
      signal=true;
   if(type==(long)POSITION_TYPE_SELL  && rt[0].open<ma[0] && rt[0].close>ma[0])
      signal=true;
//--- verificações adicionais
   if(signal)
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         if(Bars(_Symbol,_Period)>100)
           {
            CTrade trade;
            trade.PositionClose(_Symbol,3);
           }
//---
  }

O algoritmo da função CheckForClose() é semelhante ao algoritmo da CheckForOpen(). Dependendo da direção das posições abertas atuais, as condições de fechamento são verificadas (preço cruzando a MA para baixo para compras ou para cima para vendas). Uma posição aberta é fechada chamando o método PositionClose() do objeto de negociação (instância da CTrade).

4. Teste de Estratégia

Os melhores valores dos parâmetros podem ser encontrados utilizando o Teste de Estratégia do terminal MetaTrader 5.

Por exemplo, ao otimizar o parâmetro MovingPeriod no intervalo de 01/01/2012 a 01/08/2013, os melhores resultados são obtidos com MovingPeriod=45:

Resultados do Teste de Backtesting do Expert Advisor de Média Móvel

Resultados do Teste de Backtesting do Expert Advisor de Média Móvel

Conclusões:

O Expert Advisor de Média Móvel incluído no pacote padrão do MetaTrader 5 é um exemplo de uso de indicadores técnicos, funções de histórico de operações e classes de negociação da Biblioteca Padrão. Além disso, o EA inclui um sistema de gestão de risco baseado nos resultados das operações.

Publicações relacionadas

Comentário (0)