MetaTrader 5 / Experts

Média Móvel - expert para MetaTrader 5

15221
(53)

O EA de média móvel está incluído no pacote padrão do terminal do cliente MetaTrader 5 e é um exemplo da EA que negocia com o indicador de Média Móvel.

O arquivo EA Moving Average.mq5 está localizado na pasta "terminal_data_folder\MQL5\Experts\Examples\Moving Average\". Este EA é um exemplo da utilização de indicadores técnicos, histórico de negociações e funções classes de negociação da biblioteca padrão. Além disso, o AE inclui um sistema de gestão de dinheiro que é baseado nos resultados das negociações

Vamos considerar 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 primeiras 5 linhas contêm um comentário, as três linhas seguintes definem as propriedades do programa MQL5 (copyright, link, versão) utilizando as diretivas de pré-processamento #Property.

Quando você executa o Expert Advisor eles são exibidos na aba "Common":

Propriedades da EA Média Móvel

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


1.2. Arquivos de include

Em seguida, a diretiva #Include diz ao compilador para incluir o arquivo "Trade.mqh".

Este arquivo é parte da Biblioteca Padrão, que contém a classe CTrade para facilitar o acesso as funções de negociação.

#include <Trade\Trade.mqh>

O nome do arquivo de inclusão é mostrado entre parênteses "<>;", de modo que o caminho está definido em relação ao diretório: "terminal_data_folder\Include\".

1.3 Entradas

Vai-se o tipo, nome, valores padrão e um comentário. O seu papel é mostrado na fig. 2.

input double MaximumRisk        = 0.02;    // Risco máximo em porcentagem input double DecreaseFactor     = 3;       // Fator de rebaixamento 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 o gerenciamento de dinheiro, MovingPeriod e MovingShift definem o período e o deslocamento do indicador técnico Média Móvel que será usado ou verificará as condições de negociação.

O texto no comentário na linha de parâmetro de entrada, juntamente com os valores padrão, são exibidos na aba "Options" em vez do nome do parâmetro de entrada:

Parâmetros de entrada do Expert Advisor Média Móvel

Fig. 2. Parâmetros de entrada do EA Média Móvel

1.4. Variáveis ​​globais

Em seguida, a variável global ExtHandle é declarada. Ela será usada para armazenar o manipulador do indicador Média Móvel.

//--- int   ExtHandle=0;

Ele é seguido por seis funções. A finalidade de cada um deles está descrito no comentário antes do corpo da função:

  1. TradeSizeOptimized() - Calcula o tamanho ideal do lote;
  2. CheckForOpen() - Verifica as condições para abertura de posição;
  3. CheckForClose() - Verifica as condições de fechamento da posição;
  4. OnInit() - função de inicialização do Expert;
  5. OnTick() - Função tick do Expert;
  6. OnDeinit() - Função de desinicialização do Expert;

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


2. Funções de manipulação de eventos

2.1. A função de inicialização OnInit()

A função OnInit() é chamada uma vez durante a inicialização do Expert Advisor. Geralmente no manipulador de eventos OnInit() a EA está preparada para a operação: os parâmetros de entrada são verificados, os indicadores e parâmetros são inicializados, etc No caso de erros críticos, quando o funcionamento não faz sentido, a função é encerrada com um código de retorno INIT_FAILED.

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

Desde que a negociação do EA é baseada no indicador de média móvel, chama-se IMA() e o indicador de Média Móvel é criado e seu manipulador é salvo na variável global ExtHandle.

No caso de um erro, OnInit() é encerrado com um código de retorno INIT_FAILED - É uma maneira correta para completar a operação EA/indicador no caso de uma inicialização mal sucedida.


2.2. A função OnTick()

A função OnTick() é chamada cada vez que uma nova cotação é recebida para o símbolo do gráfico, em que a EA é executada.

//+------------------------------------------------------------------+ //| Expert tick function                                             | //+------------------------------------------------------------------+ void OnTick(void)   { //---    if(PositionSelect(_Symbol))       CheckForClose();    else       CheckForOpen(); //---   }

A função PositionSelect() é usada para definir se existe uma posição em aberto para o símbolo atual.

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


2.3. A função de desinicialização OnDeInit()

OnDeInit () é chamada quando um EA é removido a partir do gráfico. Se um programa coloca os objectos gráficos durante a operação, eles podem ser removidos a partir do gráfico.

//+------------------------------------------------------------------+ //| Expert deinitialization function                                 | //+------------------------------------------------------------------+ void OnDeinit(const int reason)   {   } //+------------------------------------------------------------------+

Neste caso, não há a realização de nenhuma ação durante a desinicialização do Expert Advisor.


3. Funções de serviço

3.1. Função TradeSizeOptimized()

Esta função calcula e retorna o valor do tamanho do lote ideal para a posição de abertura com o nível de risco especificado e os resultados das negociações.

//+------------------------------------------------------------------+ //| Calcular o tamanho ideal do lote                                 | //+------------------------------------------------------------------+ double TradeSizeOptimized(void)   {    double price=0.0;    double margin=0.0; //--- Calcula 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 o comprimento da série de operações consecutivas de perda    if(DecreaseFactor>0)      {       //--- Pedido de todo o histórico de negociação       HistorySelect(0,TimeCurrent());       //--       int    orders=HistoryDealsTotal();  // O número total de ofertas       int    losses=0;                    // O número de ofertas de perda na série       for(int i=orders-1;i>=0;i--)         {          ulong ticket=HistoryDealGetTicket(i);          if(ticket==0)            {             Print("HistoryDealGetTicket failed, no trade history");             break;            }          //--- verificando o símbolo de negociação          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 para o volume de negociações    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; //--- retorna 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 seguinda, a função OrderCalcMargin() é utilizada 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 requerida para colocar uma ordem, a margem livre da conta (AccountInfoDouble(ACCOUNT_FREEMARGIN)) e o valor máximo permitido de risco especificadas no parâmetro de entrada MaximumRisk.

Se o valor do parâmetro de entrada DecreaseFactor é positivo, as ordens históricas são analisadas ​e o tamanho do lote é ajustado tendo em conta as informações sobre a série máxima de negócios com perda: o tamanho inicial do lote é multiplicado pelo tamanho (1-perdas/DecreaseFactor).

Em seguida, o volume de negociação é "arredondado" para o valor que é múltiplo do passo mínimo permitido do volume (stepvol) para o símbolo atual. Além disso, os valores máximos (maxvol) e mínimos (minvol) possíveis do volume de negociação são solicitados, e se o valor do lote sair dos limites desejados, ele é ajustado. Como resultado, a função retorna o valor calculado do volume de negóciação.


3.2. Função CheckForOpen()

CheckForOpen() é usado para verificar as condições das posições de abertura ela abre-a quando ocorrem as condições de negociação (neste caso, quando o preço cruza a média móvel).

//+------------------------------------------------------------------+ //| Verificar a existência das condições de abertura de posição      | //+------------------------------------------------------------------+ void CheckForOpen(void)   {    MqlRates rt[2]; //--- Copia os valores do preço    if(CopyRates(_Symbol,_Period,0,2,rt)!=2)      {       Print("CopyRates of ",_Symbol," failed, no history");       return;      } //--- Negocia somento no primeiro tick da barra    if(rt[1].tick_volume>1)       return; //--- Obtém o valor atual do indicador de média móvel     double   ma[1];    if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)      {       Print("CopyBuffer from iMA failed, no data");       return;      } //--- verifica 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 usando o movimento, você precisa verificar se o preço cruza a média móvel. Usando a função CopyRates(), dois valores dos preços atuais são copiados no array de estruturas rt[], rt[1] corresponde à barra atual, rt[0] - barra completa.

Um nova barra é iniciada através da verificação do volume de escala da barra atual se ele for igual a 1, uma nova barra se iniciou Deve-se notar que este método de detecção de um nova barra pode falhar em alguns casos (quando as cotações vêm em pacotes), então o fato do início da formação de uma nova barra deve ser feita através do armazenamento e da comparação do tempo da cotação atual (ver IsNewBar).

O valor atual do indicador de média móvel é solicitado usando a função CopyBuffer() e ela é salva no array ma[] que contém apenas um valor. O programa verifica se o preço cruzou a média móvel e faz verificações adicionais (se a negociação com o EA é possível e se há a presença de barras no histórico). Se for bem sucedido, uma posição adequada para o símbolo é aberto chamando o método PositionOpen() do objeto de negociação (uma instância de CTrade).

O preço da abertura da posição é definida através da função SymbolInfoDouble() que retorna o preço de Bid ou Ask, dependendo do valor da variável de sinal. O volume da posição é determinada pela chamada de TradeSizeOptimized() descrito acima.


3.3. Função CheckForClose()

CheckForClose() verifica as condições para o fechamento da posição e fecha se as condições para fechamento ocorrer.

//+------------------------------------------------------------------+ //| Verifica a existência de condições de fechamento da posição      | //+------------------------------------------------------------------+ void CheckForClose(void)   {    MqlRates rt[2]; //--- Copy price values    if(CopyRates(_Symbol,_Period,0,2,rt)!=2)      {       Print("CopyRates of ",_Symbol," failed, no history");       return;      } //--- Negocia somento no primeiro tick da nova barra    if(rt[1].tick_volume>1)       return; //--- Obtêm o valor atual do indicador Média Móvel    double   ma[1];    if(CopyBuffer(ExtHandle,0,0,1,ma)!=1)      {       Print("CopyBuffer from iMA failed, no data");       return;      } //--- Obter o tipo de 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 CheckForOpen(). Dependendo da direção das posições atuais em aberto, as condições de seus fechamento são verificadas novamente (o preço cruza a MA para baixo para comprar ou para cima, para vender). Uma posição em aberto é fechada chamando o método PositionClose() do objeto de negociação (instância CTrade).


4. Backtesting

Os melhores valores dos parâmetros podem ser encontrados usando o Strategy Tester do terminal MetaTrader 5.

Por exemplo, quando se otimizar o parâmetro MovingPeriod no intervalo 2012.01.01-2013.08.01, os melhores resultados são obtidos com MovingPeriod = 45:

Resultados do Backtesting do Expert Advisor da média móvel

Resultados do Backtesting do Expert Advisor da média móvel

Conclusões:

O Expert Advisor de média móvel está incluído no pacote padrão do terminal MetaTrader 5 é um exemplo da utilização de indicadores técnicos, histórico de negociação, funções classes de negociação da biblioteca padrão. Além disso, o AE inclui um sistema de gestão de dinheiro que é baseado nos resultados das negociações


Traduzido do russo pela MetaQuotes Ltd.
Publicação original: https://www.mql5.com/ru/code/1921