Assistente MQL5: como criar um módulo de sinais de comércio

MetaQuotes Software Corp. | 11 fevereiro, 2014

Introdução

MetaTrader 5 fornece uma ferramenta poderosa para a verificação rápida de ideias comerciais. Este é o gerador de estratégias comerciais do Assistente MQL5. O uso do Assistente MQL5 para criação automática de códigos do Expert Advisor é descrito no artigo "Assistente MQL5: Criação de Expert Advisors sem programação". A abertura do sistema de geração de código permite que você adicione suas próprias classes de sinais de comércio, sistemas de gerenciamento de dinheiro e módulos de rastreamento aos padrões.

Este artigo descreve os princípios de escrita de módulos de sinais de comércio para usá-los na criação de Expert Advisors com o Assistente MQL5.

Um Expert Advisor criado com o Assistente MQL5 é baseado em quatro pilares - quatro classes base:

Figura 1. A estrutura da classe base CExpert

Figura 1. A estrutura da classe base CExpert

A classe CExpert (ou sua subclasse) é o principal "motor" de um robô de comércio. Um exemplo de CExpert contém uma cópia de cada classe: CExpertSignal, CExpertMoney e CExpertTrailing (ou suas subclasses):

  1. CExpertSignal é a base do gerador de sinais de comércio. Um exemplo da classe CExpertSignal derivada, inclusa no CExpert, fornece um Expert Advisor com informações sobre a possibilidade de entrar no mercado, os níveis de entrada e de colocação de ordens de proteção, com base em algoritmos internos. A decisão final sobre a execução de operações comerciais é feita pelo EA.
  2. CExpertMoney é a base do dinheiro e dos sistemas de gerenciamento de risco. Um exemplo de classe derivada CExpertMoney calcula volumes para a abertura de posições e colocação de ordens pendentes. A decisão final sobre a execução de operações comerciais é feita pelo EA.
  3. CExpertTrailing - é a base do módulo de suporte de posições abertas. Um exemplo da classe derivada CExpertTrailing informa um EA sobre a necessidade de modificar ordens de proteção de uma posição. A decisão final sobre a modificação da ordem é feita pelo EA.

Além disso, os membros da classe CExpert são exemplos das seguintes classes:

Daqui em diante, em "expert" queremos dizer uma instância de CExpert ou sua subclasse.

Mais detalhes do CExpert e trabalho com ele será descrito em um artigo separado.


1. Classe base CExpertSignal

CExpertSignal é a base do gerador de sinais de comércio. Para comunicação com o "mundo exterior", o CExpertSignal tem um conjunto de método virtual público:

Inicialização

Descrição

virtual Init

A inicialização da instância de classe fornece sincronização de dados do módulo com dados da EA

virtual ValidationSettings

Validação de parâmetros definidos

virtual InitIndicators

Criação e inicialização de todos os indicadores e séries temporais necessários para operação do gerador de sinais de comércio

Sinais de posição abertura/reversão/encerramento

CheckOpenLong virtual

Geração do sinal de abertura de posição longa, definição dos níveis de entrada e colocação de ordens de proteção

CheckOpenShort virtual

Geração do sinal de abertura de posição curta, definição dos níveis de entrada e colocação de ordens de proteção

CheckCloseLong virtual

Geração do sinal de fechamento posição longa, definindo o nível de saída

CheckCloseShort virtual

Geração do sinal de fechamento posição curta, definindo o nível de saída

CheckReverseLong virtual

Geração do sinal de reversão de posição longa, definição dos níveis de reversão e colocação de ordens de proteção

CheckReverseShort virtual

Geração do sinal de reversão de posição curta, definição dos níveis de reversão e colocação de ordens de proteção

Gerenciando ordens pendentes

CheckTrailingOrderLong virtual

Geração do sinal de modificação de uma ordem de Compra pendente, definindo o novo preço da ordem

CheckTrailingOrderShort virtual

Geração do sinal de modificação de uma ordem de Venda pendente, definindo o novo preço da ordem

Descrição dos métodos:

1.1. Métodos de inicialização:

1.1.1 Init

O método Init() é automaticamente chamado logo após uma instância de classe ser adicionado ao especialista. Método de substituição não é necessário.

virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);

1.1.2 ValidationSettings

O método ValidationSettings() é chamado diretamente do expert depois que todos os parâmetros são definidos. Você deve sobrescrever o método se existem quaisquer parâmetros de configuração.

virtual bool ValidationSettings();

O método substituído deve retornar autêntico se todas as opções são válidas (utilizável). Se pelo menos um dos parâmetros estiver incorreto, o mesmo deve retornar falso (trabalho posterior não será possível).

Classe base CExpertSignal não tem parâmetros ajustáveis​, portanto, o método da classe base sempre retorna autêntico sem realizar qualquer verificação.

1.1.3 InitIndicators

O método InitIndicators () implementa a criação e inicialização de todos os indicadores e séries temporais necessários. Ele é chamado do expert após todos os parâmetros serem definidos e sua exatidão verificada com sucesso. O método deve ser substituído se o gerador de sinal de comércio usar pelo menos um indicador ou série temporal.

virtual bool InitIndicators(CIndicators* indicators);

Indicadores e/ou séries temporais devem ser usados através de classes correspondentes da Biblioteca padrão. Ponteiros de todos os indicadores e/ou de séries temporais devem ser adicionados à coleção de indicadores de um expert (um ponteiro para o qual é transmitido como um parâmetro).

O método substituído deve retornar autêntico, se todas as manipulações com os indicadores e/ou séries temporais foram bem sucedidas (elas são adequados para uso). Se pelo menos uma operação com os indicadores e/ou séries temporais falhou, o método deve retornar inválido (mais trabalho é impossível).

Classe base CExpertSignal não utiliza indicadores e séries temporais, então, o método da classe base sempre retorna autêntico, sem realizar nenhuma ação.


1.2. Métodos de verificação do sinal da posição de abertura:

1.2.1 CheckOpenLong

O método CheckOpenLong() gera um sinal de abertura de uma posição longa, definindo o nível de entrada e níveis de colocação de ordens de proteção. Ele é chamado por um expert para determinar se é necessário modificar uma posição longa. O método deve ser substituído, se é esperado que um sinal de uma posição de abertura longa será gerado.

virtual bool CheckOpenLong(double& price, double& sl, double& tp, datetime& expiration);

O método deve implementar o algoritmo de verificação da condição de uma posição de abertura longa. Se a condição for atendida, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) devem ser atribuídos valores apropriados e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de um sinal de abertura de posição longa, assim o método da classe base sempre retorna falso.

1.2.2 CheckOpenShort

O método CheckOpenShort() gera um sinal de abertura de uma posição curta, definindo o nível de entrada e níveis de colocação de ordens de proteção. Ele é chamado por um expert para determinar se é necessário abrir uma posição curta. O método deve ser substituído, se é esperado que um sinal de uma posição de abertura curta será gerado.

virtual bool CheckOpenShort(double& price, double& sl, double& tp, datetime& expiration);

O método deve implementar o algoritmo de verificação da condição de abrir uma posição curta. Se a condição for satisfeita, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) devem ser atribuídos valores apropriados e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de um sinal de abertura de posição curta, assim o método da classe base sempre retorna falso.


1.3. Métodos de verificação do sinal da posição de fechamento:

1.3.1 CheckCloseLong

O método CheckCloseLong() gera um sinal de fechamento de uma posição longa, definindo o nível de saída. Ele é chamado por um expert para determinar se é necessário fechar uma posição longa. O método deve ser substituído, se é esperado que um sinal de uma posição de fechamento longa será gerado.

virtual bool CheckCloseLong(double& price);

O método deve implementar o algoritmo de verificação da condição de fechar uma posição longa. Se a condição for satisfeita, o preço variável (a referência que é passada como um parâmetro) deve ser atribuído valor apropriado e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de um sinal de fechamento de posição longa, assim o método da classe base sempre retorna falso.

1.3.2 CheckCloseShort

O método CheckCloseShort() gera um sinal de fechamento de uma posição curta, definindo o nível de saída. Ele é chamado por um expert para determinar se é necessário fechar uma posição curta. O método deve ser substituído, se é esperado que um sinal de uma posição de fechamento curta será gerado.

virtual bool CheckCloseShort(double& price);

O método deve implementar o algoritmo de verificação da condição de fechar uma posição curta. Se a condição for satisfeita, o preço variável (a referência que é passada como um parâmetro) deve ser atribuído valor apropriado e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de um sinal de fechamento de posição curta, assim o método da classe base sempre retorna falso.


1.4. Métodos de verificação do sinal da posição de reversão:

1.4.1 CheckReverseLong

O método CheckReverseLong gera um sinal de reversão de uma posição longa, definindo o nível de reversão e níveis de colocação de ordens de proteção. Ele é chamado por um expert para determinar se é necessário reverter uma posição longa. O método deve ser substituído, se é esperado que um sinal de uma posição de reversão longa será gerado.

virtual bool CheckReverseLong(double& price, double& sl, double& tp, datetime& expiration);

O método deve implementar o algoritmo de verificação da condição de uma posição de reversão longa. Se a condição for satisfeita, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) devem ser atribuídos valores apropriados e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Na classe base CExpertSignal, o seguinte algoritmo para gerar um sinal de reversão da posição longa é implementado:

  1. Verificação de um sinal para fechar uma posição longa.
  2. Verificação de um sinal para fechar uma posição curta.
  3. Se ambos os sinais são ativos (as condições são cumpridas) e os preços de fechamento e abertura correspondem, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) são atribuídos os valores apropriados e o método retorna válido.
Se a condição não for cumprida, o método retorna falso.

1.4.2 CheckReverseShort

O método CheckReverseShort gera um sinal de reversão de uma posição curta, definindo o nível de reversão e níveis de colocação de ordens de proteção. Ele é chamado por um expert para determinar se é necessário reverter uma posição curta. O método deve ser substituído, se é esperado que um sinal de uma de reversão posição longa vai ser gerado de acordo com o algoritmo que difere do que foi implementada na classe base.

virtual bool CheckReverseShort(double& price, double& sl, double& tp, datetime& expiration);

O método deve implementar o algoritmo de verificação da condição de uma posição de reversão curta. Se a condição for satisfeita, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) devem ser atribuídos valores apropriados e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Na classe base CExpertSignal, o seguinte algoritmo para gerar um sinal de reversão da posição curta é implementado:

  1. Verificação de um sinal para fechar uma posição curta.
  2. Verificação de um sinal para fechar uma posição longa.
  3. Se ambos os sinais são ativos (as condições são cumpridas) e os preços de fechamento e abertura correspondem, os preços variáveis, sl, tp, e expiração (referências que são passadas como parâmetros) são atribuídos os valores apropriados e o método retorna válido.

Se a condição não for cumprida, o método retorna falso.


1.5. Métodos de verificação do sinal de modificação da ordem pendente:

1.5.1 CheckTrailingOrderLong

O método CheckTrailingOrderLong() gera o sinal de modificação de uma ordem de Compra pendente, definindo o novo preço da ordem. Ele é chamado por um expert para determinar se é necessário modificar uma ordem de Compra pendente. O método deve ser substituído, se é esperado que um sinal de modificação de uma ordem de Compra pendente será gerado.

virtual bool CheckTrailingOrderLong(COrderInfo* order, double& price)

O método deve implementar o algoritmo de verificação da condição de modificação de uma ordem de Compra pendente. Se a condição for satisfeita, o preço variável (a referência que é passada como um parâmetro) deve ser atribuído valor apropriado e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de uma modificação de uma ordem de Compra pendente, assim o método da classe base sempre retorna falso.

1.5.2 CheckTrailingOrderShort

O método CheckTrailingOrderShort() gera o sinal de modificação de uma ordem de Venda pendente, definindo o novo preço da ordem Ele é chamado por um expert para determinar se é necessário modificar uma ordem de Venda pendente. O método deve ser substituído, se é esperado que um sinal de modificação de uma ordem de Venda pendente será gerado.

virtual bool CheckTrailingOrderShort(COrderInfo* order, double& price)

O método deve implementar o algoritmo de verificação da condição de modificação de uma ordem de Venda pendente. Se a condição for satisfeita, o preço variável (a referência que é passada como um parâmetro) deve ser atribuído valor apropriado e o método deve retornar autêntico. Se a condição não for cumprida, o método deve retornar falso.

Classe base CExpertSignal não possui um algoritmo embutido para geração de uma modificação de uma ordem de Venda pendente, assim o método da classe base sempre retorna falso.


2. Desenvolva seu próprio gerador de sinais de comércio

Agora, depois de ter revisto a estrutura da classe de base CExpertSignal, você pode começar a criar o seu próprio gerador de sinais de comércio.

Como mencionado acima, a classe CExpertSignal é um conjunto de "cordas" virtuais públicas - métodos utilizados nos quais o expert pode saber a opinião do gerador de sinais de comércio sobre a entrada no mercado em uma direção ou outra.

Portanto, o nosso principal objetivo é criar a nossa própria classe de gerador de sinais de comércio, derivando-o da classe CExpertSignal e substituindo os métodos virtuais adequados, implementando os algoritmos necessários.

Nosso segundo problema (e não menos importante) - para tornar a nossa classe "visível" para o Assistente MQL5. Mas, as primeiras coisas primeiro.

2.1. Criando a classe do gerador de sinais de negociação

Vamos iniciar.

Primeiro, nós criamos (por exemplo, utilizando o mesmo Assistente MQL5) um arquivo incluso com a extensão mqh.

No menu do arquivo selecione "Criar" (ou pressione teclas combinadas Ctrl+N) e indique a criação de um arquivo incluso:

Figura 2. Crie um arquivo incluso utilizando o Assistente MQL5.

Figura 2. Crie um arquivo incluso utilizando o Assistente MQL5

Deve notar-se que, para que o arquivo seja então "detectado" pelo Assistente MQL5 como um módulo de rastreamento de posições abertas, ele deve ser criado na pasta Include\Expert\Signal\.

Para não entulhar na Biblioteca Padrão, crie nossa própria pasta Include\Expert\Signal\MySignals, em que criamos arquivo SampleSignal.mqh, especificando esses parâmetros em Assistente MQL5:

Figura 3. Configuração do local do arquivo incluso

Figura 3. Configuração do local do arquivo incluso

Como resultado da operação do Assistente MQL5 temos o seguinte padrão:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
//+------------------------------------------------------------------+
//| DLL imports                                                      |
//+------------------------------------------------------------------+
// #import "user32.dll"
//   int      SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
//   int      ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports                                                      |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
//   string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+

O seguinte é apenas trabalho "manual". Remova as partes desnecessárias e adicione o que é necessário (incluindo arquivo ExpertSignal.mqh da Biblioteca padrão e uma descrição de classe, que agora está vazia).

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator.                      |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Agora, é necessário escolher os algoritmos.

Como base para o nosso gerador de sinais de negociação, tomamos o modelo generalizado "preço cruza a média móvel". Mas nós fazer mais uma suposição: "Depois de cruzar a média móvel, o preço recua, e só então vai na direção certa." Reflita isso em nosso arquivo.

Geralmente, quando você está escrevendo algo, não economize nos comentários. Depois de algum tempo, a leitura de um código cuidadosamente comentado será muito confortável.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| Class CSampleSignal.                                             |
//| Purpose: Class of trading signal generator when price            |
//|          crosses moving average,                                 |
//|          entering on the subsequent back movement.               |
//|          It is derived from the CExpertSignal class.             |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
  };
//+------------------------------------------------------------------+

Agora vamos definir quais dados são necessários para a tomada de decisões sobre a geração de sinais de comércio. No nosso caso, este é o preço de abertura e o preço de fechamento da barra anterior, e o valor da média móvel na mesma barra anterior.

Para ter acesso a esses dados, podemos usar as classes da biblioteca padrão CiOpen, CiClose e CiMA. Vamos discutir indicadores e séries temporais mais tarde.

Enquanto isso, vamos definir uma lista de configurações para o nosso gerador. Primeiro, é preciso configurar a média móvel. Esses parâmetros incluem o período, a mudança ao longo do eixo do tempo, o método de média e objeto de média. Em segundo lugar, é preciso configurar o nível de entrada e os níveis de colocação de ordens de proteção, e o tempo de vida de uma ordem pendente, porque estamos indo trabalhar com as ordens pendentes.

Todas as configurações do módulo serão armazenadas em membros de dados protegidos da classe. O acesso às configurações será implementado através de métodos públicos apropriados.

Vamos incluir estas mudanças em nosso arquivo:

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
//+------------------------------------------------------------------+
//| The CSampleSignal class.                                         |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;           // level to place a pending order relative to the MA
   double             m_stop_loss;       // level to place a stop loss order relative to the open price
   double             m_take_profit;     // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
  };
//+------------------------------------------------------------------+

Como estamos usando membros de dados protegidos, precisamos adicionar um construtor de classe, em que vamos inicializar esses dados por valores padrões.

Para verificar os parâmetros, vamos substituir o método virtual ValidationSettings de acordo com a descrição da classe base.

Descrição da classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;   }
   void               ShiftMA(int value)                  { m_shift_ma=value;    }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;   }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;  }
   void               Limit(double value)                 { m_limit=value;       }
   void               StopLoss(double value)              { m_stop_loss=value;   }
   void               TakeProfit(double value)            { m_take_profit=value; }
   void               Expiration(int value)               { m_expiration=value;  }
   //--- Methods to validate the parameters
   virtual bool       ValidationSettings();
  };
    

Implementação do método ValidationSettings () (configurações de validação):


//+------------------------------------------------------------------+
//| Validation of the setup parameters.                              |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+

Agora que nós terminamos a maior parte do trabalho de preparação, vamos falar mais sobre indicadores e séries temporais.

Indicadores e séries temporais são a principal fonte de informação para a tomada de decisões (certamente você pode usar o sorteio, ou fases da lua, mas eles são muito difíceis de formalizar).

Como já definido anteriormente, para tomar decisões precisamos das seguintes informações: o preço de abertura da barra anterior, o preço de fechamento da barra anterior, e o valor da média móvel da mesma barra anterior.

Para ter acesso a esses dados, vamos usar as seguintes classes da biblioteca padrão:

Você pode perguntar: "Por que usar o indicador ou séries temporais," envolto "em uma classe, a fim de obter um único número"?

Há um significado oculto, que vamos revelar agora.

Como usar os dados de um indicador ou série temporal?

Em primeiro lugar, precisamos criar um indicador.

Em segundo lugar, precisamos copiar a quantidade necessária de dados em um buffer intermediário.

Em terceiro lugar, é preciso verificar se a cópia está concluída.

Somente após essas etapas, você pode usar os dados.

Usando as classes da biblioteca padrão, você evita a necessidade de criar um indicador, de se preocupar com a disponibilidade de buffers intermediários e sobre o carregamento de dados ou a liberação de um identificador. O objeto de uma classe adequada vai fazer isso por você. Todos os indicadores necessários serão gerados pelo nosso gerador de sinal durante a fase de inicialização, e todos os indicadores serão fornecidos com o buffer temporário necessário. E além disso, uma vez que adicionarmos um indicador ou série temporal de objeto na coleção (o objeto de uma classe especial), você pode parar de se preocupar com a relevância dos dados (os dados serão atualizados automaticamente pelo expert).

Vamos colocar os objetos dessas classes nos membros de dados protegidos. Para cada objeto, criamos um método de inicialização e método de acesso a dados.

Vamos substituir o método virtual InitIndicators (de acordo com a descrição da classe base).

Descrição da classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values om the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;      // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
    

Implementação dos métodos InitIndicators, InitMA, InitOpen, InitClose:

//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+

Todos os trabalhos preparatórios estão concluídos. Como você pode ver, a nossa classe tem crescido significativamente.

Mas agora estamos prontos para gerar sinais de comércio.

Figura 4. Sinais de comércio para o preço cruzar a média móvel

Figura 4. Sinais de comércio para o preço cruzar a média móvel

Vamos considerar nossos algoritmos novamente com mais detalhes.

1. O sinal para compra aparece quando as seguintes condições foram cumpridas na barra anterior:

Neste caso, oferecemos para colocar uma ordem de Compra pendente com os parâmetros definidos pelas configurações. Para isso, nós substituímos o método virtual CheckOpenLong e o preenchemos com a funcionalidade correspondente.

2. O sinal para venda aparece quando as seguintes condições foram cumpridas na barra anterior:

Neste caso, oferecemos para colocar uma ordem de Venda pendente com os parâmetros definidos pelas configurações. Para isso, nós substituímos o método virtual CheckOpenShort e o preenchemos com a funcionalidade correspondente.

3. Nós não geraremos sinais para fechar posições. Deixe as posições serem fechadas pelo Stop Loss/Take Profit ордерам.

Assim, não vamos substituir métodos virtuais CheckCloseLong e CheckCloseShort.

4. Vamos propor a modificação de uma ordem pendente ao longo da média móvel na "distância" especificado pelas configurações.

Para isso, nós substituímos o método virtual CheckTrailingOrderLong e CheckTrailingOrderShort, e o preenchemos com a funcionalidade correspondente.

Descrição da classe:

class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;              // object to access the values of the moving average
   CiOpen             m_open;            // object to access the bar open prices
   CiClose            m_close;           // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;       // averaging period of the MA
   int                m_shift_ma;        // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;       // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;      // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters

   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //--- Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
    

Implementação de métodos CheckOpenLong, CheckOpenShort, CheckTrailingOrderLong, CheckTrailingOrderShort:

//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Então nós resolvemos o primeiro problema. O código acima é um código-fonte da classe de sinais de comércio gerador que atende a nossa principal tarefa.


2.2. Preparando uma descrição da classe criada dos sinais de negociação para o Assistente MQL5

Vamos agora para a parte de resolver o segundo problema. Nosso sinal deve ser "reconhecido" pelo gerador de estratégias de negociação do Assistente MQL5.

Nós fizemos a primeira condição necessária: colocamos o arquivo onde ele será "encontrado" pelo Assistente MQL5. Mas não é suficiente. O Assistente MQL5 não deve apenas "encontrar" o arquivo, mas também "reconhecê-lo". Para fazermos isso, temos que acrescentar ao texto original do descritor de classe para o Assistente MQL5.

Um descritor de classe é um bloco de comentários compostos de acordo com certas regras.

Vamos considerar estas regras.

1. O bloco de comentários deve iniciar com as linhas a seguir:

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |

2. A próxima linha é um descritor de texto (o que veremos no Assistente MQL5 ao escolhermos o sinal) no formato "//| Title= |". Se o texto é muito grande para uma linha, você pode adicionar mais uma linha (mas não mais) depois dele.

No nosso caso, temos o seguinte:

//| Title=Signal on the crossing of a price and the MA               |
//| entering on its back movement                                    |
    

3. Então chega uma linha com o tipo de classe especificado no formato "//| Type= |". O campo deve ter o valor de sinal (além de sinais, o Assistente MQL5 conhece outros tipos de classes).

Escrever:

//| Type=Signal                                                      |

4. A próxima linha no formato "//| Name= |" é o nome curto do sinal (é utilizada pelo Assistente MQL5 para gerar os nomes das variáveis globais do especialista).

Obtemos o seguinte:

//| Name=Sample                                                      |

5. O nome de uma classe é um elemento importante da descrição. Na linha de formato "//| Class= |", o parâmetro deve ser compatível com o nome da nossa classe:

//| Class=CSampleSignal                                              |

6. Nós não preenchemos essa linha, mas deve estar presente (isto é um link para a seção referência da linguagem):

//| Page=                                                            |

7. Além disso, há descrições dos parâmetros de configuração de sinal.

Este é um conjunto de fileiras (o número de fileiras é igual ao número de parâmetros).

O formato de cada linha é "//| Parameter=,, |".

Aqui está nosso conjunto de parâmetros:

//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |

8. O bloco de comentário deve terminar com as linhas a seguir:

//+------------------------------------------------------------------+
// wizard description end
    

Vamos adicionar o descritor ao código de origem.

//+------------------------------------------------------------------+
//|                                                 SampleSignal.mqh |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| include files                                                    |
//+------------------------------------------------------------------+
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signal on crossing of the price and the MA                 |
//| entering on the back movement                                    |
//| Type=Signal                                                      |
//| Name=Sample                                                      |
//| Class=CSampleSignal                                              |
//| Page=                                                            |
//| Parameter=PeriodMA,int,12                                        |
//| Parameter=ShiftMA,int,0                                          |
//| Parameter=MethodMA,ENUM_MA_METHOD,MODE_EMA                       |
//| Parameter=AppliedMA,ENUM_APPLIED_PRICE,PRICE_CLOSE               |
//| Parameter=Limit,double,0.0                                       |
//| Parameter=StopLoss,double,50.0                                   |
//| Parameter=TakeProfit,double,50.0                                 |
//| Parameter=Expiration,int,10                                      |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| CSampleSignal class.                                             |
//| Purpose: Class of trading signal generator when price            |
//|             crosses moving average,                              |
//|             entering on the subsequent back movement.            |
//|             It is derived from the CExpertSignal class.          |
//+------------------------------------------------------------------+
class CSampleSignal : public CExpertSignal
  {
protected:
   CiMA               m_MA;               // object to access the values of the moving average
   CiOpen             m_open;             // object to access the bar open prices
   CiClose            m_close;            // object to access the bar close prices
   //--- Setup parameters
   int                m_period_ma;        // averaging period of the MA
   int                m_shift_ma;         // shift of the MA along the time axis
   ENUM_MA_METHOD     m_method_ma;        // averaging method of the MA
   ENUM_APPLIED_PRICE m_applied_ma;       // averaging object of the MA
   double             m_limit;            // level to place a pending order relative to the MA
   double             m_stop_loss;        // level to place a stop loss order relative to the open price
   double             m_take_profit;      // level to place a take profit order relative to the open price
   int                m_expiration;       // lifetime of a pending order in bars

public:
                      CSampleSignal();
   //--- Methods to set the parameters
   void               PeriodMA(int value)                 { m_period_ma=value;              }
   void               ShiftMA(int value)                  { m_shift_ma=value;               }
   void               MethodMA(ENUM_MA_METHOD value)      { m_method_ma=value;              }
   void               AppliedMA(ENUM_APPLIED_PRICE value) { m_applied_ma=value;             }
   void               Limit(double value)                 { m_limit=value;                  }
   void               StopLoss(double value)              { m_stop_loss=value;              }
   void               TakeProfit(double value)            { m_take_profit=value;            }
   void               Expiration(int value)               { m_expiration=value;             }
   //---Method to validate the parameters
   virtual bool       ValidationSettings();
   //--- Method to validate the parameters
   virtual bool       InitIndicators(CIndicators* indicators);
   //--- Methods to generate signals to enter the market
   virtual bool      CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration);
   virtual bool      CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration);
   //--- Methods to generate signals of pending order modification
   virtual bool      CheckTrailingOrderLong(COrderInfo* order,double& price);
   virtual bool      CheckTrailingOrderShort(COrderInfo* order,double& price);

protected:
   //--- Object initialization method
   bool               InitMA(CIndicators* indicators);
   bool               InitOpen(CIndicators* indicators);
   bool               InitClose(CIndicators* indicators);
   //--- Methods to access object data
   double             MA(int index)                       { return(m_MA.Main(index));       }
   double             Open(int index)                     { return(m_open.GetData(index));  }
   double             Close(int index)                    { return(m_close.GetData(index)); }
  };
//+------------------------------------------------------------------+
//| CSampleSignal Constructor.                                       |
//| INPUT:  No.                                                      |
//| OUTPUT: No.                                                      |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
void CSampleSignal::CSampleSignal()
  {
//--- Setting the default values
   m_period_ma  =12;
   m_shift_ma   =0;
   m_method_ma  =MODE_EMA;
   m_applied_ma =PRICE_CLOSE;
   m_limit      =0.0;
   m_stop_loss  =50.0;
   m_take_profit=50.0;
   m_expiration =10;
  }
//+------------------------------------------------------------------+
//| Validation of parameters.                                        |
//| INPUT:  No.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::ValidationSettings()
  {
//--- Validation of parameters
   if(m_period_ma<=0)
     {
      printf(__FUNCTION__+": the MA period must be greater than zero");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of indicators and timeseries.                     |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitIndicators(CIndicators* indicators)
  {
//--- Validation of the pointer
   if(indicators==NULL)       return(false);
//--- Initialization of the moving average
   if(!InitMA(indicators))    return(false);
//--- Initialization of the timeseries of open prices
   if(!InitOpen(indicators))  return(false);
//--- Initialization of the timeseries of close prices
   if(!InitClose(indicators)) return(false);
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the moving average                             |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitMA(CIndicators* indicators)
  {
//--- Initialization of the MA object
   if(!m_MA.Create(m_symbol.Name(),m_period,m_period_ma,m_shift_ma,m_method_ma,m_applied_ma))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
   m_MA.BufferResize(3+m_shift_ma);
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_MA)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of open prices.                 |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitOpen(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_open.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_open)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialization of the timeseries of close prices.                |
//| INPUT:  indicators - pointer to the object - collection of       |
//|                      indicators and timeseries.                  |
//| OUTPUT: true in case of success, otherwise false.                |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::InitClose(CIndicators* indicators)
  {
//--- Initialization of the timeseries object
   if(!m_close.Create(m_symbol.Name(),m_period))
     {
      printf(__FUNCTION__+": object initialization error");
      return(false);
     }
//--- Adding an object to the collection
   if(!indicators.Add(GetPointer(m_close)))
     {
      printf(__FUNCTION__+": object adding error");
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether a Buy condition is fulfilled                       |
//| INPUT:  price      - variable for open price                     |
//|         sl         - variable for stop loss price,               |
//|         tp         - variable for take profit price              |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenLong(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double spread=m_symbol.Ask()-m_symbol.Bid();
   double ma    =MA(1);
   double unit  =PriceLevelUnit();
//--- Checking the condition
   if(Open(1)<ma && Close(1)>ma && ma>MA(2))
     {
      price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
      sl   =m_symbol.NormalizePrice(price-m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price+m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether a Sell condition is fulfilled.                     |
//| INPUT:  price      - variable for open price,                    |
//|         sl         - variable for stop loss,                     |
//|         tp         - variable for take profit                    |
//|         expiration - variable for expiration time.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckOpenShort(double& price,double& sl,double& tp,datetime& expiration)
  {
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
//--- Checking the condition
   if(Open(1)>ma && Close(1)<ma && ma<MA(2))
     {
      price=m_symbol.NormalizePrice(ma+m_limit*unit);
      sl   =m_symbol.NormalizePrice(price+m_stop_loss*unit);
      tp   =m_symbol.NormalizePrice(price-m_take_profit*unit);
      expiration+=m_expiration*PeriodSeconds(m_period);
      //--- Condition is fulfilled
      return(true);
     }
//--- Condition is not fulfilled
   return(false);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//|  of a Buy order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderLong(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double spread   =m_symbol.Ask()-m_symbol.Bid();
   double ma       =MA(1);
   double unit     =PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma-m_limit*unit+spread);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+
//| Check whether the condition of modification                      |
//| of a Sell order is fulfilled.                                    |
//| INPUT:  order - pointer at the object-order,                     |
//|         price - a variable for the new open price.               |
//| OUTPUT: true if the condition is fulfilled, otherwise false.     |
//| REMARK: No.                                                      |
//+------------------------------------------------------------------+
bool CSampleSignal::CheckTrailingOrderShort(COrderInfo* order,double& price)
  {
//--- Checking the pointer
   if(order==NULL) return(false);
//--- Preparing the data
   double ma  =MA(1);
   double unit=PriceLevelUnit();
   double new_price=m_symbol.NormalizePrice(ma+m_limit*unit);
//--- Checking the condition
   if(order.PriceOpen()==new_price) return(false);
   price=new_price;
//--- Condition is fulfilled
   return(true);
  }
//+------------------------------------------------------------------+

Bem, isso é tudo. O sinal está pronto para uso.

Para as estratégias comerciais gerador Assistente MQL5 serem capaz de usar o nosso sinal, devemos reiniciar MetaEditor (Assistente MQL5 escaneia a pasta Include\Expert somente na inicialização).

Após reiniciar o MetaEditor, o módulo criado de sinais de comércio pode ser usado no Assistente MQL5:

Figura 5. O gerador de sinais de comércio criado no Assistente de MQL5

Figura 5. O gerador de sinais de comércio criado no Assistente de MQL5

Os parâmetros de entrada especificados na seção de descrição de parâmetros do gerador de sinais de negociação estão agora disponíveis:

Figura 6. Os parâmetros de entrada do gerador de sinais de comércio criado no Assistente de MQL5

Figura 6. Os parâmetros de entrada do gerador de sinais de comércio criado no Assistente de MQL5

Os melhores valores dos parâmetros de entrada da estratégia comercial implementada podem ser encontrados usando o Testador de estratégia do terminal MetaTrader 5.


Conclusão

O gerador de estratégias de negociação do Assistente MQL5 simplifica extremamente o teste de ideias de negociação. O código de especialista gerado é baseado nas classes de estratégias de negociação da biblioteca padrão, os quais são utilizados para criar certas implementações de classes de sinal de negociação, classes de gerenciamento de risco e dinheiro e classes de suporte de posição.

O artigo discute como escrever sua própria classe de sinais de comércio com a implementação de sinais no cruzamento do preço e da média móvel, e como incluí-lo ao gerador de estratégias de comércio do Assistente MQL5, bem como descreve a estrutura e o formato da descrição da classe gerada para o Assistente MQL5.