English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Crie o seu próprio robô de negociação em 6 passos!

Crie o seu próprio robô de negociação em 6 passos!

MetaTrader 5Exemplos | 21 janeiro 2014, 13:53
67 103 3
MetaQuotes
MetaQuotes

Mais uma vez sobre o Assistente MQL5

O mundo ao nosso redor está mudando rapidamente e tentamos acompanhá-lo. Não temos tempo para aprender algo novo e isso é uma atitude normal de um ser humano. Traders são pessoas como todo o mundo, eles querem resultados máximos com o mínimo esforço. Especialmente para traders, o MetaEditor 5 oferece um maravilhoso Assistente MQL5. Há muitos artigos que descrevem como criar um sistema de negociação automática utilizando o assistente, incluindo uma "versão light" Assistente MQL5 Wizard para leigos e uma "versão de desenvolvedores " - Assistente MQL5: Nova Versão.

Tudo parece bom - um robô de negociação é criado em 5 cliques de mouse, você pode testar sua estratégia no testador de estratégia e melhorar os parâmetros de um sistema de negociação, você pode deixar o robô resultante explorar sua conta, sem a necessidade de fazer qualquer outra coisa manualmente. Mas o problema surge quando um trader/desenvolvedor MQL5 deseja criar algo próprio, algo único que nunca tenha sido descrito em nenhum lugar e vai escrever seu próprio módulo de sinais de negociação. O negociador abre a documentação do MQL5, vai até a Biblioteca padrão e se assusta ao ver...


Cinco classes terríveis

É verdade que o Assistente MQL5 simplifica bastante a criação de Expert Advisors, mas primeiro você precisa aprender o que será usado como entrada para ele. Para criar automaticamente um Expert Advisor utilizando o Assistente MQL5, certifique-se que seus componentes sejam fiéis às cinco classes básicas da seção Classes básicas de Expert Advisors:

  • CExpertBase é uma classe de base para quatro outras classes.
  • CExpert é a classe para criação de um robô de negociação; essa é a classe que negocia.
  • CExpertSignal é a classe para de um módulo de sinais de negociação; o artigo é sobre esta classe.
  • CExpertTrailing é uma classe para rastrear um Stop Loss de proteção.
  • CExpertMoney é a classe de gerenciamento de dinheiro.

Aqui está todo o poder da abordagem "ótima e terrível" que é chamada de programação orientada a objetos (OOP). Mas não tenha receio, agora quase todo o mundo possui um telefone celular com muitas funções e quase ninguém sabe como funciona. Não precisamos estudar tudo isso, vamos discutir apenas algumas funções da classe CExpertSignal.


Neste artigo iremos através de estágios de criação de um módulo de sinais de negociação e você verá como fazer isso sem ter que aprender a OOP (POO) ou as classes. Mas se desejar, você pode ir um pouco mais além.


1. Criação de uma Classe a partir do nada

Não alteraremos nenhum módulo existente de sinais de negociação para nossas necessidades, porque é a forma de ficar confuso. Portanto, simplesmente escreveremos nossa própria classe, mas primeiro usaremos o Navegador para criar uma nova pasta para armazenar nossos sinais em MQL5/Include/Expert/.



Dê duplo clique com o botão direito do mouse na pasta que criamos, selecione "novo arquivo" e crie uma nova classe para nosso módulo de sinais de negociação.


Preencha nos campos:

  • Nome da classe - o nome da classe. Esse será o módulo para gerenciar sinais no cruzamento de duas médias móveis, então vamos chamá-la MA_Cross;
  • Nome de base é a classe na qual nossa classe é derivada. E devemos derivá-la a partir da classe de base CExpertSignal.

Clique "terminar" e um projeto do nosso modelo estará pronto. Está tudo fácil até agora. Nós só precisamos adicionar a declaração #include ao arquivo resultante para que o compilador saiba onde encontrar a classe de base CExpertSignal:

#include "..\ExpertSignal.mqh"   // CExpertSignal is in the file ExpertSignal

O resultado:

//+------------------------------------------------------------------+
//|                                                     MA_Cross.mqh |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include "..\ExpertSignal.mqh"   // CExpertSignal is in the file ExpertSignal
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class MA_Cross : public CExpertSignal
  {
private:

public:
                     MA_Cross();
                    ~MA_Cross();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MA_Cross::MA_Cross()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
MA_Cross::~MA_Cross()
  {
  }
//+------------------------------------------------------------------+

Verifique a classe resultante (deve estar livre de erros de compilação) e clique em F7. Não há erros e podemos prosseguir.


2. Um identificador para o módulo

Nossa classe está completamente vazia, não há nenhum erro e podemos testá-la - vamos tentar criar um novo Expert Advisor no Assistente MQL5 baseado nela. Chegamos ao passo de selecionar um módulo de sinais de negociação e ver... que nosso módulo não está lá.


E como pode estar lá? Não adicionamos nenhuma indicação para o Assistente MQL5 entender que a nossa classe poderia ser algo útil. Vamos arrumar isso. Se você olhar para os módulos do pacote padrão, você verá que cada um deles contém um cabeçalho no início do arquivo. Este é o identificador do módulo compilado de acordo com certas regras. E as regras são muito simples.

Abra, por exemplo, o código-fonte do módulo de AMA com base nos sinais de negociação (veja a descrição da lógica em Sinais da Média móvel adaptativa). Execute o Assistente MQL5 escolhendo este módulo. Compare:

O último bloco no identificador refere-se aos parâmetros do módulo, a primeira linha contém o nome do módulo a ser exibido no Assistente MQL5. Como você pode ver, não há nada de complicado. Assim, o identificador de cada módulo contém as seguintes entradas:

  • Título - o nome do módulo a ser mostrado no Assistente MQL5;
  • Tipo - a versão do módulo de sinais. Deve ser sempre SignalAdvanced;
  • Nome - o nome do módulo após seu é selecionado no Assistente MQL5 e é usado em comentários para descrever parâmetros internos do Expert Advisor gerado (de preferência especificado);
  • ShortName - um prefixo para nomeação automática de parâmetros externos no Expert Advisor gerado (na forma de Signal_ _);
  • Classe - o nome do, que está contido no módulo;
  • Página - um parâmetro para obter Ajuda para este módulo (apenas para módulos de envio padrão).

Em seguida, chega a descrição dos parâmetros na forma de parâmetro=list_of_values, em que a seguir é especificado (separados por vírgula):

  1. O nome da função para definir o valor do parâmetro ao iniciar o Expert Advisor.
  2. O tipo de parâmetro pode ser enumeração.
  3. O valor padrão para o parâmetro, por exemplo, o valor que será definido para o parâmetro, se você não alterá-lo no Assistente de MQL5.
  4. A descrição do parâmetro, que você vê ao iniciar o Expert Advisor gerado no Assistente MQL5.

Agora, sabendo de tudo isso, vamos criar o identificador do nosso módulo de sinais de negociação. Então, escrevemos um módulo para obter sinais de negociação no cruzamento de duas médias móveis. Precisamos definir pelo menos quatro parâmetros externos:

  • FastPeriod - o período da média móvel rápida;
  • FastMethod - o tipo de suavização da média móvel rápida;
  • SlowPeriod - o período da média móvel lenta;
  • SlowMethod - o tipo de suavização da média móvel lenta.

Você também pode adicionar uma mudança e o tipo de preços para calcular cada uma das médias móveis, mas isso não muda nada fundamentalmente. Assim, a versão atual é a seguinte:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals at the intersection of two MAs                     |
//| Type=SignalAdvanced                                              |
//| Name=My_MA_Cross                                                 |
//| ShortName=MaCross                                                |
//| Class=MA_Cross                                                   |
//| Page=Not needed                                                  |
//| Parameter=FastPeriod,int,13,Period of fast MA                    |
//| Parameter=FastMethod,ENUM_MA_METHOD,MODE_SMA,Method of fast MA   |
//| Parameter=SlowPeriod,int,21,Period of slow MA                    |
//| Parameter=SlowMethod,ENUM_MA_METHOD,MODE_SMA,Method of slow MA   |
//+------------------------------------------------------------------+
// wizard description end

O identificador de módulo está pronto e nós descrevemos o seguinte nele:

  1. O nome exibido no Assistente MQL5 - "Sinais na intersecção de duas médias móveis".
  2. Quatro parâmetros externos para configurar os sinais de negociação.
    • FastPeriod - o período da média móvel rápida com o valor padrão de 13;
    • FastMethod - o tipo de suavização da média móvel rápida, suavização simples por padrão;
    • SlowPeriod - o período da média móvel rápida com o valor padrão de 21;
    • SlowMethod - o tipo de suavização da média móvel lenta, suavização simples por padrão.

Salve as alterações e compile. Não deve haver nenhum erro. Execute o Assistente MQL5 para verificar. Veja bem, nosso módulo está agora disponível para seleção e mostra todos os nossos parâmetros!


Parabéns, nosso módulo de sinais de negociação parece ótimo agora!


3. Métodos para configurar parâmetros

Agora é hora de trabalhar com parâmetros externos. Devido ao nosso módulo de negócio ser representado pela classe MA_Cross, então, seus parâmetros devem ser armazenados dentro da mesma classe que os membros privados. Vamos adicionar quatro linhas (iguais ao número de parâmetros) à declaração de classe. Nós já descrevemos o parâmetro no identificador e sabemos o seguinte:

class MA_Cross : public CExpertSignal
  {
private:
   //--- Configurable module parameters
   int               m_period_fast;    // Period of the fast MA
   int               m_period_slow;    // Period of the slow MA
   ENUM_MA_METHOD    m_method_fast;    // Type of smoothing of the fast MA
   ENUM_MA_METHOD    m_method_slow;    // Type of smoothing of the slow MA

Mas como os valores dos parâmetros externos do módulo aparecem nos membros apropriados da nossa classe MA_Cross? É tudo muito simples, você precisa apenas declarar os métodos públicos de mesmo nome na classe, em outras palavras, adicionar quatro linhas à seção pública:

class MA_Cross : public CExpertSignal
  {
private:
   //--- Configurable module parameters
   int               m_period_fast;    // Period of the fast MA
   int               m_period_slow;    // Period of the slow MA
   ENUM_MA_METHOD    m_method_fast;    // Type of smoothing of the fast MA
   ENUM_MA_METHOD    m_method_slow;    // Type of smoothing of the slow MA

public:
   //--- Constructor of class
                     MA_Cross();
   //--- Destructor of class
                    ~MA_Cross();
   //--- Methods for setting
   void              FastPeriod(int value)               { m_period_fast=value;        }
   void              FastMethod(ENUM_MA_METHOD value)    { m_method_fast=value;        }
   void              SlowPeriod(int value)               { m_period_slow=value;        }
   void              SlowMethod(ENUM_MA_METHOD value)    { m_method_slow=value;        }
   };

Quando você gera um Expert Advisor com base neste módulo usando o Assistente MQL5 e executa-o no gráfico, estes quatro métodos são chamados automaticamente ao inicializar o Expert Advisor. Então aqui está uma regra simples:

A regra de criação de parâmetro no módulo - para cada parâmetro que declaramos no identificador, devemos criar um membro privado na classe para armazenar o seu valor e um membro público para definir um valor a ele. O nome do método deve ser compatível com o nome do parâmetro.

E o último momento é definir valores padrão para os nossos parâmetros que serão utilizados no caso dos métodos de definição de valor não forem chamados. Cada variável declarada ou membro de classe deve ser inicializado. Esta técnica permite evitar muitos erros difíceis de se encontrar.

Para a inicialização automática, o mais apropriado é o construtor de classe, é sempre o primeiro a ser chamado ao criar um objeto. Para valores padrão, usaremos aqueles escritos no identificador de módulo.

class MA_Cross : public CExpertSignal
  {
private:
   //--- Configurable module parameters
   int               m_period_fast;    // Period of the fast MA
   ENUM_MA_METHOD    m_method_fast;     // Type of smoothing of the fast MA
   int               m_period_slow;    // Period of the slow MA
   ENUM_MA_METHOD    m_method_slow;     // Type of smoothing of the slow MA

public:
   //--- Constructor of class
                     MA_Cross(void);
   //--- Destructor of class
                    ~MA_Cross(void);
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
MA_Cross::MA_Cross(void) : m_period_fast(13),          // Default period of the fast MA is 3
                           m_method_fast(MODE_SMA),    // Default smoothing method of the fast MA
                           m_period_slow(21),          // Default period of the slow MA is 21
                           m_method_slow(MODE_SMA)     // Default smoothing method of the slow MA
  {
  }

Aqui os membros de classe são inicializados usando a lista de inicialização.

Como você pode ver, não usamos indicadores de média móveis ainda. Encontramos uma regra simples - como muitos parâmetros são declarados no identificador do módulo, então muitos métodos e os membros devem estar na classe que implementa o módulo. Não há nada complicado! No entanto, não se esqueça de estabelecer valores predeterminados de parâmetros no construtor.


4. Verifique a exatidão de parâmetros de entrada

Criamos parâmetros para nosso módulo de negociação, métodos escritos para estabelecer valores a eles e agora chega a fase mais importante - a exatidão de parâmetros deve ser verificada. No nosso caso, devemos verificar os períodos de médias móveis e o tipo de suavização para o cálculo das mesmas. Para este propósito você deve escrever o seu próprio método ValidationSettings() na classe. Este método é definido na classe de pais CExpertBase, e em todos as suas filhas redefinidos de forma obrigatória.

Mas se você não sabe nada sobre programação orientada a objetos, apenas lembre-se - na nossa classe, devemos escrever a função ValidationSettings(), que não necessita de nenhum parâmetro e retorna verdadeiro ou falso.

class MA_Cross : public CExpertSignal
  {
...
   //--- Constructor of class
                     MA_Cross(void);
   //--- Destructor of class
                    ~MA_Cross(void);
   //--- Checking correctness of input data
   bool              ValidationSettings();
...
   };
//+------------------------------------------------------------------+
//| Checks input parameters and returns true if everything is OK     |
//+------------------------------------------------------------------+
bool MA_Cross:: ValidationSettings()
  {
   //--- Call the base class method
   if(!CExpertSignal::ValidationSettings())  return(false);
   //--- Check periods, number of bars for the calculation of the MA >=1
   if(m_period_fast<1 || m_period_slow<1)
     {
      PrintFormat("Incorrect value set for one of the periods! FastPeriod=%d, SlowPeriod=%d",
                  m_period_fast,m_period_slow);
      return false;
     }
//--- Slow MA period must be greater that the fast MA period
   if(m_period_fast>m_period_slow)
     {
      PrintFormat("SlowPeriod=%d must be greater than FastPeriod=%d!",
                  m_period_slow,m_period_fast);
      return false;
     }
//--- Fast MA smoothing type must be one of the four values of the enumeration
   if(m_method_fast!=MODE_SMA && m_method_fast!=MODE_EMA && m_method_fast!=MODE_SMMA && m_method_fast!=MODE_LWMA)
     {
      PrintFormat("Invalid type of smoothing of the fast MA!");
      return false;
     }
//--- Show MA smoothing type must be one of the four values of the enumeration
   if(m_method_slow!=MODE_SMA && m_method_slow!=MODE_EMA && m_method_slow!=MODE_SMMA && m_method_slow!=MODE_LWMA) 
     {
      PrintFormat("Invalid type of smoothing of the slow MA!");
      return false;
     }
//--- All checks are completed, everything is ok
   return true;
  }
Como você pode ver, na parte pública da classe MA_Cross, adicionamos declaração do método ValidationSettings() e então adicionamos o corpo do método no formulário a seguir:
bool MA_Cross:: ValidationSettings()

Primeiro chega o tipo de retorno, em seguida o nome de classe e, então, o operador de resolução de escopo e tudo isso é seguido pelo nome do método anteriormente declarado. Não se esqueça que o nome e o tipo de parâmetros devem ser compatíveis na declaração e descrição do método de classe. Entretanto, o compilador lhe avisará de tal erro.

Observe que primeiro o método de classe de base é chamado, e, em seguida, os parâmetros de entrada são verificados.

//--- Call the base class method
   if(!CExpertSignal::ValidationSettings())  return(false);
//--- Our code to check the values of parameters

Se você não adicionar essa linha, o Expert Advisor gerado não será capaz de inicializar o módulo de sinais de negociação.


5. Onde estão nossos indicadores?

É hora de trabalhar com os indicadores, uma vez que todo o trabalho preparatório com os parâmetros para eles já foram concluídos. Cada módulo dos sinais de negócio contém o método InitIndicators(), que é automaticamente chamado quando você executa o Expert Advisor gerado. Neste método, devemos fornecer indicadores de médias móveis para o nosso módulo.

Primeiro, declare os métodos InitIndicators() na classe e cole seu projeto:

public:
   //--- Constructor of class
                     MA_Cross(void);
   //--- Destructor of class
                    ~MA_Cross(void);
   //--- Methods for setting
   void              FastPeriod(int value)               { m_period_fast=value;        }
   void              FastMethod(ENUM_MA_METHOD value)    { m_method_fast=value;        }
   void              SlowPeriod(int value)               { m_period_slow=value;        }
   void              SlowMethod(ENUM_MA_METHOD value)    { m_method_slow=value;        }
   //--- Checking correctness of input data
   bool              ValidationSettings();
   //--- Creating indicators and timeseries for the module of signals
   bool              InitIndicators(CIndicators *indicators);
  };
...
//+------------------------------------------------------------------+
//| Creates indicators                                               |
//| Input:  a pointer to a collection of indicators                  |
//| Output: true if successful, otherwise false                      |
//+------------------------------------------------------------------+
bool MA_Сross::InitIndicators(CIndicators* indicators)
  {
//--- Standard check of the collection of indicators for NULL
   if(indicators==NULL)                           return(false);
//--- Initializing indicators and timeseries in additional filters
   if(!CExpertSignal::InitIndicators(indicators)) return(false);
//--- Creating our MA indicators
   ... Some code here
//--- Reached this part, so the function was successful, return true
   return(true);
  }

Então, não há nada de complicado, nós declaramos o método e, em seguida, basta criar o corpo do método, como fizemos para o método ValidationSettings(). Além de tudo, não esqueça de inserir o nome de classe e do operador: na definição da função. Temos um projeto no qual podemos inserir um código para criar médias móveis. Vamos fazer isso adequadamente - para cada indicador, criamos uma função separada na classe, que retorne verdadeira, se bem sucedida. A função pode ter qualquer nome, mas deixe-a refletir sua finalidade, então, vamos chamar as funções CreateFastMA() e CreateSlowMA().

protected:
   //--- Creating MA indicators
   bool              CreateFastMA(CIndicators *indicators);
   bool              CreateSlowMA(CIndicators *indicators);
  };
//+------------------------------------------------------------------+
//| Creates indicators                                               |
//| Input:  a pointer to a collection of indicators                  |
//| Output: true if successful, otherwise false                      |
//+------------------------------------------------------------------+
bool MA_Cross::InitIndicators(CIndicators *indicators)
  {
//--- Standard check of the collection of indicators for NULL
   if(indicators==NULL) return(false);
//--- Initializing indicators and timeseries in additional filters
   if(!CExpertSignal::InitIndicators(indicators)) return(false);
//--- Creating our MA indicators
   if(!CreateFastMA(indicators))                  return(false);
   if(!CreateSlowMA(indicators))                  return(false);
//--- Reached this part, so the function was successful, return true
   return(true);
  }
//+------------------------------------------------------------------+
//| Creates the "Fast MA" indicator                                  |
//+------------------------------------------------------------------+
bool MA_Cross::CreateFastMA(CIndicators *indicators)
  {
... Some code
//--- Reached this part, so the function was successful, return true
   return(true);
  }
//+------------------------------------------------------------------+
//| Creates the "Slow MA" indicator                                  |
//+------------------------------------------------------------------+
bool MA_Cross::CreateSlowMA(CIndicators *indicators)
  {
... Some code
//--- Reached this part, so the function was successful, return true
   return(true);
  }

Isso é tudo, só precisamos escrever o código que gera os indicadores MA e que de alguma forma integra os identificadores destes indicadores no módulo de negociação, para que o módulo possa usar os valores os valores destes indicadores. Por isso que um ponteiro à uma variável de tipo CIndicators é transmitida como um parâmetro. O seguinte é escrito em Documentação sobre o assunto:

CIndicators é uma classe para a coleta de instâncias de classes de séries temporais e indicadores técnicos. A classe CIndicators fornece criação de instâncias de classes de indicadores técnicos, seu armazenamento e gerenciamento (sincronização, identificador e gerenciamento de memória de dados).

Isto significa que devemos criar nossos indicadores e colocá-los nesta coleção. Uma vez que apenas os indicadores da forma CIndicator e suas filhas podem ser armazenados na coleção, devemos usar este fato. Usaremos CiCustom, que é a filha acima mencionada. Para cada média móvel anunciamos um objeto de tipo CiCustom na parte privada da classe:

class MA_Cross : public CExpertSignal
  {
private:
   CiCustom          m_fast_ma;            // The indicator as an object
   CiCustom          m_slow_ma;            // The indicator as an object
   //--- Configurable module parameters
   int              m_period_fast;   // Period of the fast MA
   ENUM_MA_METHOD    m_method_fast;    // Type of smoothing of the fast MA
   int              m_period_slow;   // Period of the slow MA
   ENUM_MA_METHOD    m_method_slow;    // Type of smoothing of the slow MA

Claro, você pode criar sua própria classe de indicador, que será derivada do CIndicator, e implementar todos os métodos necessários para usar com o Assistente MQL5. Mas no caso de desejarmos mostrar como você pode usar qualquer indicador personalizado no módulo de sinais de negociação utilizando CiCustom.

Aqui está como parece no código:

//+------------------------------------------------------------------+
//| Creates the "Fast MA" indicator                                  |
//+------------------------------------------------------------------+
bool MA_Cross::CreateFastMA(CIndicators *indicators)
  {
//--- Checking the pointer
   if(indicators==NULL) return(false);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_fast_ma)))
     {
      printf(__FUNCTION__+": Error adding an object of the fast MA");
      return(false);
     }
//--- Setting parameters of the fast MA
   MqlParam parameters[4];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="Examples\\Custom Moving Average.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_period_fast;      // Period
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=0;                  // Shift
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_method_fast;      // Averaging method
//--- Object initialization  
   if(!m_fast_ma.Create(m_symbol.Name(),m_period,IND_CUSTOM,4,parameters))
     {
      printf(__FUNCTION__+": Error initializing the object of the fast MA");
      return(false);
     }
//--- Number of buffers
   if(!m_fast_ma.NumBuffers(1)) return(false);
//--- Reached this part, so the function was successful, return true
   return(true);
  }

No método CreateFastMA(), primeiro verifique o ponteiro da coleção de indicadores e então adicione um ponteiro do MA rápido m_fast_ma à esta coleção. Em seguida, declare a estrutura MqlParam, que é especialmente criada para armazenar parâmetros dos indicadores personalizados, e a preencha com valores.

Usamos Média móvel personalizada do pacote de entrega do terminal padrão como indicador MA personalizado. O nome do indicador deve ser indicado relativamente à pasta data_folder/MQL5/Indicators/. Devido à Custom Moving Average.mq5 do pacote padrão estar localizado em data_folder/MQL5/Indicators/Examples/, especificamos seu caminho incluindo a pasta Examples:

parameters[0].string_value="Examples\\Custom Moving Average.ex5";

Se você olhar o código para este indicador, você consegue ver todos os dados necessários:

//--- input parameters
input int            InpMAPeriod=13;       // Period
input int            InpMAShift=0;         // Shift
input ENUM_MA_METHOD InpMAMethod=MODE_SMMA;  // Method

Os valores da estrutura contêm os pares de valores do tipo:

  1. Tipo de parâmetro - cadeia (para transferir o nome do indicador).
  2. O nome do arquivo executável do indicador personalizado - "Custom Moving Averages.exe" (médias móveis personalizadas).
  3. Tipo de parâmetro - int (valor do período).
  4. Período da média móvel.
  5. Tipo de parâmetro - int (valor do deslocamento).
  6. Deslocamento horizontal da média em barras.
  7. Tipo de parâmetro - int (valor de enumeração é um número inteiro).
  8. Método da média.

Após preencher a estrutura, o indicador é inicializado pelo método Create() de todos os parâmetros necessários: nome do símbolo e o período de tempo no qual é calculado, o tipo do indicador a partir da enumeração ENUM INDICATOR, o número de parâmetros de indicador e a estrutura MqlParam com valores de parâmetro. E o último passo é especificar o número de buffers de indicador utilizando o método NumBuffers().

O método CreateSlowMA() para criar a média móvel lenta é simples. Ao utilizar indicadores personalizados no módulo, não se esqueça que o Expert Advisor gerado pelo Assistente MQL5 também será executado no testador. Assim, no início do nosso arquivo, adicionamos #property tester_indicator que comunica ao testador a localização de indicadores necessários:

#include "..\ExpertSignal.mqh"   // The CExpertSignal class is in the file ExpertSignal
#property tester_indicator "Examples\\Custom Moving Average.ex5"

Se usarmos vários indicadores diferentes, devemos adicionar esta linha para cada um deles. Então, adicionamos os indicadores. Para maior comodidade, vamos fornecer dois métodos de receber valores MA:

   //--- Checking correctness of input data
   bool              ValidationSettings(void);
   //--- Creating indicators and timeseries for the module of signals
   bool              InitIndicators(CIndicators *indicators);
   //--- Access to indicator data
   double            FastMA(const int index)             const { return(m_fast_ma.GetData(0,index)); }
   double            SlowMA(const int index)             const { return(m_slow_ma.GetData(0,index)); }

Como você pode ver, os métodos são muito simples, eles usaram o método GetData() da classe pai, que retorna um valor a partir do buffer de indicador especificado na posição especificada.

Se você precisar de classes para trabalhar com indicadores clássicos do pacote padrão, elas estão disponíveis na seção Classes para trabalhar com indicadores. Estamos prontos para prosseguir para o estágio final.


6. Defina os métodos de LongCondition e de ShortCondition

Tudo está pronto para fazer nosso módulo e gerar sinais de negociação. Esta funcionalidade é fornecida por dois métodos que devem ser descritos em cada filha do CExpertSignal:

  • LongCondition() verifica as condições de compra e retorna a força de sinal Longo de 0 a 100;
  • ShortCondition() - verifica a condição de venda e retorna a força do sinal Curto de 0 a 100.

Se a função retorna um valor nulo, significa que não há um sinal de negociação. Se há condições para o sinal, então você pode estimar a força do sinal e retornar qualquer valor que seja inferior a 100. A avaliação da força do sinal permite que você construa de forma flexível sistemas de negociação com base em vários módulos e modelos de mercado. Leia mais sobre isso no Assistente MQL5: Nova Versão.

Uma vez que estamos escrevendo um simples módulo de sinais de negociação, podemos concordar que os sinais de compra e venda são avaliados igualmente (100). Vamos adicionar métodos necessários na declaração de classe.

   ...
   bool              InitIndicators(CIndicators *indicators);
   //--- Access to data of the indicators
   double            FastMA(const int index)             const { return(m_fast_ma.GetData(0,index)); }
   double            SlowMA(const int index)             const { return(m_slow_ma.GetData(0,index)); }
   //--- Checking buy and sell conditions
   virtual int       LongCondition();
   virtual int       ShortCondition();

Além disso, vamos criar a descrição de funções. É assim que o sinal de compra é verificado (é tudo igual com o sinal de venda):

//+------------------------------------------------------------------+
//| Returns the strength of the buy signal                           |
//+------------------------------------------------------------------+
int MA_Cross::LongCondition()
  {
   int signal=0;
//--- For operation with ticks idx=0, for operation with formed bars idx=1
   int idx=StartIndex();
//--- Values of MAs at the last formed bar
   double last_fast_value=FastMA(idx);
   double last_slow_value=SlowMA(idx);
//--- Values of MAs at the last but one formed bar
   double prev_fast_value=FastMA(idx+1);
   double prev_slow_value=SlowMA(idx+1);
//---If the fast MA crossed the slow MA from bottom upwards on the last two closed bars
   if((last_fast_value>last_slow_value) && (prev_fast_value<prev_slow_value))
     {
      signal=100; // There is a signal to buy
     }
//--- Return the signal value
   return(signal);
  }

Observe que declaramos a variável idx, na qual o valor retornado pela função StartIndex() da classe pai CExpertBase está determinado. A função StartIndex() retorna 0, se o Expert Advisor estiver determinado para trabalhar em todos ticks, nesse caso a análise começa com a barra atual. Se o Expert Advisor estiver determinado para trabalhar em preços abertos, StartIndex() retorna 1 e a análise começa com a última barra formada.

Por padrão, o StartIndex() retorna 1, o que significa que o Expert Advisor gerado pelo Assistente MQL5 só será executado na abertura de uma nova barra e ignorará ticks recebidos durante a formação da barra atual.

Como ativar este modo e como ele pode ser utilizado será descrito mais tarde no toque final.

O módulo está pronto para uso, então vamos criar um robô de negociação no Assistente MQL5 com base neste módulo.


Verificação de um Expert Advisor no Testador

Para testar a eficiência do nosso módulo, vamos gerar um Expert Advisor baseado nele no Assistente MQL5 e executá-lo no gráfico. A aba "Entradas" da janela de início que apareceu contém os parâmetros do módulo MA_Cross.

Todos os outros parâmetros também foram adicionados pelo Assistente MQL5 ao gerar o EA com base no módulo de gerenciamento de dinheiro selecionado e módulo de manutenção de posição (Trailing Stop). Assim, nós só tivemos que escrever um módulo de sinais de negociação e recebemos uma solução pronta. Esta é a principal vantagem de usar o Assistente MQL5!

Agora vamos testar o robô de negociação no Testador de estratégia do MetaTrader 5. Vamos tentar executar uma otimização rápida de parâmetros-chave.

Nessas configurações de parâmetros de entrada, mais de meio milhão de transmissões são necessárias para otimização completa. Portanto, escolhemos otimização rápida (algoritmo genético) e utilizamos adicionalmente MQL5 Cloud Network para acelerar a otimização. A otimização foi feita em 10 minutos e temos os resultados.


Como você pode ver, a criação de um robô de negociação no MQL5 e otimização de parâmetros de entrada levaram muito menos tempo do que seria necessário para escrever a lógica de serviço de gerenciamento de posição, depurar e procurar pelos melhores algoritmos.


Toque final

Você pode pular este item ou voltar a ele mais tarde, quando você estiver completamente confortável com a técnica de escrever um módulo de sinais de negociação.

Se você abrir o código-fonte do Expert Advisor gerado pelo Assistente MQL5, você vai encontrar a variável global Expert_EveryTick com o valor falso. Baseado nessa variável, a função StartIndex() retorna o seu valor. Ela comunica ao Expert Advisor o modo que ele deve executar. 

//+------------------------------------------------------------------+
//|                                                 TestMA_Cross.mq5 |
//|                        Copyright 2012, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2012, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include                                                          |
//+------------------------------------------------------------------+
#include <Expert\Expert.mqh>
//--- available signals
#include <Expert\MySignals\MA_Cross.mqh>
//--- available trailing
#include <Expert\Trailing\TrailingNone.mqh>
//--- available money management
#include <Expert\Money\MoneyFixedLot.mqh>
//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string         Expert_Title             ="TestMA_Cross";  // Document name
ulong               Expert_MagicNumber       =22655;          // Expert Advisor ID
bool                  Expert_EveryTick             =false;          // Work of the EA inside the bar
//--- inputs for main signal
input int            Signal_ThresholdOpen     =10;             // Signal threshold value to open [0...100]
input int            Signal_ThresholdClose    =10;             // Signal threshold value to close [0...100]

Se você definir Expert_EveryTick como verdadeiro e compilar o código, o robô de negociação analisará cada tick de entrada e, desta forma, tomar decisões sobre os valores da barra incompleta atualmente. Faça isso somente se você entender como funciona. Nem todos os sistemas de negociação são projetados para trabalhar no interior da barra.

Você pode também adicionar uma entrada no teclado para o parâmetro Expert_EveryTick e então você terá um novo parâmetro de entrada do Expert Advisor, que você pode estabelecer na inicialização do EA em um gráfico ou no testador:

input bool          Expert_EveryTick         =false;          // Work of the EA inside the bar

E agora é hora de resumir o que fizemos.


6 passos para criar um módulo de sinais de negociação

Se você dominou o MQL5, então você não precisa mais escrever um Expert Advisor a partir do zero. Basta criar um módulo de sinais de negociação e, com base neste módulo, gerar automaticamente um robô de negociação com rastreamento ativado e módulos de gerenciamento de volume de negociação. E mesmo se você não estiver familiarizado com OOP (POO) ou não deseja se aprofundar muito na estrutura de classes de negociação, você pode simplesmente passar por seis etapas:

  1. Crie uma nova classe utilizando o Assistente MQL5 em um arquivo separado MQL5/Include/MySignals/. Nosso módulo de sinais de negociação será armazenado lá.
  2. Crie um identificador de módulo que descreve os parâmetros, valores padrão e de tipo.
  3. Declare parâmetros de módulo na classe e adicione métodos para inicialização no construtor.
  4. Verifique os parâmetros de entrada e não esqueça de chamar ValidationSettings() da classe de base CExpertSignal.
  5. Crie indicador-objeto e adicione um método de inicialização predeterminado InitIndicators().
  6. Identifique condições de sinais de negociação nos métodos LongCondition() e ShortCondition().

Cada passo é simples e requer pouca habilidade na programação MQL5. Você só precisa escrever o seu módulo uma vez, seguindo as instruções e a verificação posterior de qualquer ideia de negociação não levará mais de uma hora, sem horas exaustivas de codificação e depuração.


Do simples ao complexo

Lembre-se que a estratégia de negociação implementada pelo seu robô de negociação criado utilizando o Assistente MQL5, é tão complexa quanto o módulo de sinais de negociação que ele utiliza. Mas antes de começar a construir um sistema de negociação complexo baseado em um conjunto de regras para a entrada e saída, divida-o em vários sistemas simples e verifique cada um separadamente.

Baseado em módulos simples, você pode criar estratégias de negociação complexas, utilizando os módulos prontos para uso de sinais de negociação, mas isso é assunto para um outro artigo!

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

Arquivos anexados |
ma_cross.mqh (11.57 KB)
testma_cross.mq5 (7.14 KB)
Últimos Comentários | Ir para discussão (3)
F. Spyna
F. Spyna | 20 mar 2014 em 20:49

Se eu mandar rodar este exemplo no strategy tester do mt5, e escolher o ativo como pex. Vale5, algoritmo genético, d1, ohlc 1 minuto, max balance, vai dar erro!

Se eu executar em um par de forex, a mesma otimização parece ser concluída (não esperei concluir pq demora muito no agente local).

O erro que aparece no diário do testador, neste caso de Vale5, tem alguma coisa a ver com OnInit. Alguém aí detectou o mesmo problema? Se sim chegou a alguma solução e/ou conclusão?

Agradeço se alguém puder ajudar! 

Rodrigo Malacarne
Rodrigo Malacarne | 21 mar 2014 em 11:07
fspyna:

Se eu mandar rodar este exemplo no strategy tester do mt5, e escolher o ativo como pex. Vale5, algoritmo genético, d1, ohlc 1 minuto, max balance, vai dar erro!

Se eu executar em um par de forex, a mesma otimização parece ser concluída (não esperei concluir pq demora muito no agente local).

O erro que aparece no diário do testador, neste caso de Vale5, tem alguma coisa a ver com OnInit. Alguém aí detectou o mesmo problema? Se sim chegou a alguma solução e/ou conclusão?

Agradeço se alguém puder ajudar! 

Olá, por favor coloque informações adicionais, como log de erros ou screenshots, pra podermos tentar analisar melhor o problema.

Uma descrição simples como a que você fez acima não ajuda muito na identificação do problema.

Abraços,
Malacarne 

caehbf
caehbf | 4 jul 2017 em 23:21

Boa noite,

Está dando erro abaixo quando tenta testar o robo.

2017.07.04 18:20:27.404 tester stopped because OnInit failed

Estou fazendo alguma coisa errada ou tem algum ajuste para fazer no robo?

Abraço

Carlos F.

Visualizar uma estratégia no Tester do MetaTrader 5 Visualizar uma estratégia no Tester do MetaTrader 5
Todos conhecemos o ditado "é melhor ver uma vez do que ouvir cem vezes". Você pode ler diversos livros sobre Paris ou Veneza, mas com base nas imagens mentais, você não teria os mesmos sentimentos do que se estivesse caminhando à noite por essas cidades fabulosas. A vantagem da visualização pode ser facilmente projetada em qualquer aspecto de nossas vidas, incluindo trabalho no mercado, por exemplo, a análise de preço em gráficos utilizando indicadores e, é evidente, a visualização de teste de estratégia. Este artigo contém descrições de todos os recursos de visualização do Strategy Tester do MetaTrader 5.
Sistema de negociação simples com o uso de indicadores semáforo Sistema de negociação simples com o uso de indicadores semáforo
Se examinarmos por completo qualquer sistema de negócio complexo, veremos que é baseado em um conjunto simples de sinais de negócio. Consequentemente, não há necessidade para que novos desenvolvedores comecem imediatamente a escrever algoritmos complexos. Este artigo fornece um exemplo de um sistema de negócio que utiliza indicadores semáforo para realizar negócios.
Algoritmos que empregam limite móvel para fazer dinheiro Algoritmos que empregam limite móvel para fazer dinheiro
O objetivo deste artigo é estudar a rentabilidade dos algoritmos com diferentes entradas em negócios e saídas usando um limite móvel. Os tipos de entrada a serem usados são entradas aleatórias e entradas reversas. As ordens de parada a serem usadas são limite móvel e tomada móvel. O artigo demonstra os algoritmos para fazer dinheiro com uma rentabilidade de cerca de 30% por ano.
Abordagem orientada a objetos para construção de painéis de múltiplos períodos de tempo e múltiplas moedas Abordagem orientada a objetos para construção de painéis de múltiplos períodos de tempo e múltiplas moedas
Este artigo descreve como a programação orientada a objetos pode ser usada para criar painéis de múltiplos períodos de tempo múltiplas moedas para o MetaTrader 5. O principal objetivo é construir um painel universal, que pode ser utilizado para exibição de diversos tipos diferentes de dados, tal como preços, variação de preços, valores de indicador ou condições personalizadas de compra/venda, sem a necessidade de modificar o código do painel em si.