Assistente MQL5: como criar um módulo de gerenciamento de risco e dinheiro

MetaQuotes | 11 fevereiro, 2014

Introdução

MetaTrader 5 fornece uma ferramenta poderosa que permite que você verifique rapidamente várias ideias de negociação. Esta é a geração de Expert Advisors usando o Assistente MQL5 com base em estratégias de negociação prontas.

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

  1. A classe CExpert (ou sua classe secundária) é o principal "motor" de um Expert Advisor. Uma instância de CExpert contém uma cópia de cada classe: CExpertSignal, CExpertMoney e CExpertTrailing (ou suas classes secundárias).
  2. CExpertSignal é a base do gerador de sinais de negociação. Uma instância da classe derivada CExpertSignal, 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. O Expert Advisor decide se deve ou não entrar no mercado. Mais detalhes da classe CExpertSignal e do processo de se trabalhar com ela são descritos no artigo "Assistente MQL5: Como criar um módulo de sinais de negociação".
  3. A classe CExpertMoney é a base do mecanismo de risco e de gestão do dinheiro. Uma instância da classe derivada CExpertMoney, incluída no CExpert, fornece um Expert Advisor com informações sobre possíveis volumes para abertura de posições e colocação de ordens pendentes, com base em algoritmos internos. O Expert Advisor faz uma decisão sobre o volume.
  4. A classe CExpertTrailing é a base do mecanismo de apoio de posição aberta. Uma instância da classe derivada CExpertTrailing, incluída no CExpert, fornece uma EA com informações sobre a possibilidade de modificar ordens de proteção da posição, com base em algoritmos internos. O Expert Advisor faz uma decisão sobre a modificação de ordens. Uma descrição mais detalhada da classe CExpertTrailing e do processo de trabalhar com ele será abordado em um artigo separado.

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.

Uma descrição mais detalhada do CExpert e do processo de se trabalhar com ele será abordado em um artigo separado.


1. Classe base CExpertMoney

Como foi mencionado acima, a classe CExpertMoney é a base do mecanismo de risco e de gestão do dinheiro. Para comunicação com o "mundo exterior" a classe CExpertMoney possui 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

Percentual

Definindo o valor do parâmetro "Percentual de risco"

virtual ValidationSettings

Validando os parâmetros definidos

virtual InitIndicators

Criando e inicializando todos os indicadores e timeseries necessários para o funcionamento do mecanismo de risco e gestão de dinheiro

Métodos para verificar a necessidade de abrir/virar/fechar uma posição

CheckOpenLong virtual

Determinando o volume para abrir uma posição longa

CheckOpenShort virtual

Determinando o volume para abrir uma posição curta

CheckReverse virtual

Determinando o volume para abrir uma posição de reversão

CheckClose virtual

Determinando o volume de fechar uma posição


Descrição de métodos:


1.1. Métodos de inicialização

1.1.1 Init

O método Init() é chamado automaticamente logo depois que uma instância de classe é adicionada ao expert. Método de substituição não é necessário.

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

1.1.2 Percentual

O método Percent() é chamado para configurar o parâmetro apropriado. O seu valor pode inclusive ser de 0.0 a 100.0. O valor padrão é 100.0. Método de substituição não é necessário.

void Percent(double percent);

1.1.3 ValidationSettings

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

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). O método substituído deve chamar o método da classe base com a verificação do resultado.

A classe base CExpertMoney tem o parâmetro percentual e consequentemente, o método da classe base, tendo realizado a validação de parâmetros, retorna verdadeiro se o valor está dentro da faixa permitida, caso contrário, retorna falso.

1.1.4 InitIndicators

O método InitIndicators() implementa a criação e inicialização de todos os indicadores e timeseries necessários. Ele é chamado do expert após todos os parâmetros estarem estabelecidos e sua exatidão ser verificada com sucesso. O método deve ser substituído se o mecanismo de risco e gerenciamento de dinheiro utilizar 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 de base CExpertMoney não utiliza indicadores e séries temporais, então, o método de classe de base retorna sempre autêntico sem desempenhar ação nenhuma.

1.2. Métodos para determinar o volume de uma posição

1.2.1 CheckOpenLong

O método CheckOpenLong() calcula o volume para a abertura de uma posição longa. Ele é chamado por um expert para determinar o volume para a abertura de uma posição longa. O método deve ser substituído, se você pretende calcular o volume de abertura de posição longa usando o algoritmo que difere daquele implementado na classe base.

\virtual double CheckOpenLong(double price, double sl);

O método deve implementar o algoritmo para calcular o volume para abrir uma posição longa. O método deve retornar o volume calculado.

A classe base CExpertMoney na verdade tem nenhum algoritmo interno para calcular o volume de abertura de posições longas. O método da classe base sempre retorna o volume mínimo possível para um instrumento financeiro.

1.2.2 CheckOpenShort

O método CheckOpenShort() calcula o volume para abrir uma posição curta. Ele é chamado por um expert para determinar o volume para a abertura de uma posição curta. O método deve ser substituído, se você pretende calcular o volume de abertura de posição curta usando o algoritmo que difere daquele implementado na classe base.

virtual double CheckOpenShort(double price, double sl);

O método deve implementar o algoritmo para calcular o volume para abrir uma posição curta. O método deve retornar o volume calculado.

A classe base CExpertMoney tem nenhum algoritmo interno para calcular o volume de abertura de posições curtas. O método da classe base sempre retorna o volume mínimo possível para um instrumento financeiro.

1.2.3 CheckReverse

O método CheckReverse() calcula o volume de reversão de uma posição. Ele é chamado por um expert para determinar o volume de uma operação de comércio para reverter a posição. O método deve ser substituído, se você pretende calcular a posição de inversão do volume usando o algoritmo que difere daquele implementado na classe base (por exemplo, reversão com um volume duplo).

virtual double CheckReverse(CPositionInfo* position, double sl);

O método deve implementar o algoritmo para calcular o volume para inverter uma posição, informação que pode ser obtida pela posição do ponteiro. O método deve retornar o volume calculado para a posição de reversão.

A classe base CExpertMoney tem o seguinte algoritmo para calcular o volume para a inversão da posição - inverter a posição de tal maneira que o resultado é uma posição oposta com o menor volume possível.

1.2.4 CheckClose

Os métodos CheckClose() verificam se é necessário fechar uma posição (em termos de gestão de dinheiro e gestão de riscos). Ele é chamado por um expert para determinar se é necessário fechar uma posição. O método deve ser substituído, se você pretende fechar uma posição usando o algoritmo que difere daquele implementado na classe base (por exemplo, o fechamento parcial).

virtual double CheckClose(CPositionInfo* position);

O método deve implementar o algoritmo para definir a necessidade de fechar a posição, informação que pode ser obtida pela posição do ponteiro. O método deve retornar o volume calculado para a posição de fechamento.

CExpertMoney tem o seguinte algoritmo para determinar se é necessário fechar a posição: o método da classe base oferece para fechar uma posição inteiramente, se a perda atual da posição for maior do que a percentagem especificada do depósito.


2. Criando um mecanismo de gerenciamento de risco e dinheiro

Agora, depois de ter revisto a estrutura da classe base CExpertMoney, você pode começar a criar o seu próprio mecanismo de gerenciamento de risco e dinheiro. Daqui em diante, o mecanismo de risco e gerenciamento de dinheiro será referido como "gerente-de-dinheiro".

Como mencionado acima, a classe CExpertMoney é um conjunto de "cordas" virtuais públicas - métodos, utilizados nos quais o expert pode saber a opinião do gerente-de-dinheiro sobre o volume de mercado entrando em uma direção ou outra.

Portanto, o nosso principal objetivo é criar nossa própria classe de gerente-de-dinheiro, derivando-o da classe CExpertMoney 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 gerente-de-dinheiro, ele deve ser criado na pasta Include\Expert.

A fim de não danificar a Biblioteca Padrão, criar a nossa própria pasta Include\Expert\Money\MyMoneys, em que devemos criar o arquivo SampleMoney.mqh, especificando os parâmetros no 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:

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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". Retire as partes desnecessárias e adicione o que é necessário - o arquivo de inclusão ExpertMoney.mqh da Biblioteca Padrão com uma descrição vazia de classe.

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Class CSampleMoney.                                              |
//| Purpose: Class for risk and money management.                    |
//|             It is derived from the CExpertMoney class.           |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
  };
//+------------------------------------------------------------------+

Agora é necessário escolher os algoritmos.

Como base para o nosso gerente-de-dinheiro tomamos o seguinte algoritmo: Em condições "normais" se propõe usar um volume de negócio predeterminado e fixo. Mas se a posição anterior foi fechada com uma perda, é proposto abrir uma posição com um volume duplicado.

Reflita isso em nosso arquivo.

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Class CSampleMoney.                                              |
//| Purpose: Class for risk and money management                     |
//|             doubling the volume after a loss deal.               |
//|             It is derived from the CExpertMoney class.           |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
  };
//+------------------------------------------------------------------+

Defina uma lista de configurações para o nosso gerente-de-dinheiro. Na verdade, não haverá lista. Todas as configurações estão incluídas em um único parâmetro que vai determinar o volume de uma transação em condições "normais".

O parâmetro será armazenado num elemento de dados protegido da classe. O acesso ao parâmetro será implementado através de um método público apropriado. No construtor da classe, o parâmetro será inicializado por um valor padrão. Para verificar os parâmetros, vamos substituir o método virtual ValidationSettings de acordo com a descrição da classe base.

Vamos incluir estas mudanças em nosso arquivo:

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
//+------------------------------------------------------------------+
//| Class CSampleMoney.                                              |
//| Purpose: Class for risk and money management                     |
//|             doubling the volume after a loss deal.               |
//|             It is derived from the CExpertMoney class.           |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- setup parameters
   double            m_lots;   // deal volume for "normal" conditions

public:
                     CSampleMoney();
   //--- methods to set the parameters
   void              Lots(double lots) { m_lots=lots; }
  };
//+------------------------------------------------------------------+
//| Constructor CSampleMoney.                                        |
//| INPUT:  no.                                                      |
//| OUTPUT: no.                                                      |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
void CSampleMoney::CSampleMoney()
  {
//--- setting the default values
   m_lots=0.1;
  }
//+------------------------------------------------------------------+

Separadamente, vamos considerar como implementar o método ValidationSettings(). A questão é que a classe base já tem um parâmetro de configuração, que também requer verificação.

Portanto, no método substituído ValidationSettings(), devemos chamar ValidationSettings() da classe base com a verificação dos resultados de execução.

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 CSampleMoney::ValidationSettings()
  {
//--- Call the base class method
   if(!CExpertMoney::ValidationSettings()) return(false);
//--- Validation of parameters
   if(m_lotsm_symbol.LotsMax())
     {
      printf(__FUNCTION__+": the deal volume must be in the range %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
      return(false);
     }
   if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
     {
      printf(__FUNCTION__+": the volume of the deal must be multiple of %f",m_symbol.LotsStep());
      return(false);
     }
//--- Successful completion
   return(true);
  }

As configurações estão prontas, agora vamos continuar com a operação do gerente de dinheiro. Precisamos de um método que irá determinar se o negócio anterior estava perdendo e, se necessário, definir o seu volume. Declare o na descrição da classe:

class CSampleMoney : public CExpertMoney
  {
protected:
   //--- Setup parameters
   double            m_lots;  // deal volume for "normal" conditions

public:
                    CSampleMoney();
   //--- Methods to set parameters
   void             Lots(double lots) { m_lots=lots; }
   //--- Methods to validate parameters
   virtual bool      ValidationSettings();

protected:
   double            CheckPrevLoss();
  };

Implementação do método:

//+------------------------------------------------------------------+
//| Defines whether the prev. deal was losing.                       |
//| INPUT:  no.                                                      |
//| OUTPUT: volume of the prev. deal if it's losing, otherwise 0.0   |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
double CSampleMoney::CheckPrevLoss()
  {
   double lot=0.0;
//--- Request the history of deals and orders
   HistorySelect(0,TimeCurrent());
//--- variables
   int       deals=HistoryDealsTotal();  // Total number of deals in the history
   CDealInfo deal;
//--- Find the previous deal
   for(int i=deals-1;i>=0;i--)
     {
      if(!deal.SelectByIndex(i))
        {
         printf(__FUNCTION__+": Error of deal selection by index");
         break;
        }
      //--- Check the symbol
      if(deal.Symbol()!=m_symbol.Name()) continue;
      //--- Check the profit
      if(deal.Profit()<0.0) lot=deal.Volume();
      break;
     }
//--- Return the volume
   return(lot);
  }

Vamos considerar nossos algoritmos novamente com mais detalhes (embora já seja detalhado).

Sem entrar em nuances, notamos que o nosso gerente-de-dinheiro irá propor para aumentar o volume de um negócio mediante o recebimento de perda no negócio anterior. Se não houve perda no negócio anterior, nós vamos oferecer para abrir uma posição com um volume fixo, que é definida por um determinado parâmetro.

Para isso, nós desativamos os métodos virtuais CheckOpenLong e CheckOpenShort, e o preenchemos com a funcionalidade correspondente.

Descrição da classe:

//+------------------------------------------------------------------+
//| Class CSampleMoney.                                              |
//| Purpose: Class for risk and money management                     |
//|             doubling the volume after a loss deal.               |
//|             It is derived from the CExpertMoney class.           |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- Setup parameters
   double            m_lots;  // Deal volume for "normal" conditions

public:
                    CSampleMoney();
   //--- Methods to set the parameters
   void             Lots(double lots) { m_lots=lots; }
   //--- Methods to validate the parameters
   virtual bool      ValidationSettings();
   //--- Methods to define the volume
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            CheckPrevLoss();
  };

Implementações de CheckOpenLong e CheckOpenShort são praticamente idênticos. Ambos os métodos determinam a necessidade de aumentar o volume chamando o método CheckPrevLoss anteriormente implementado.

Em seguida é preciso levar em conta que não podemos aumentar o volume comercial indefinidamente. Existem duas limitações no volume de posição:

  1. O volume máximo para um negócio para o símbolo, especificado nas configurações do servidor (SYMBOL_VOLUME_MAX).
  2. Disponibilidade da quantidade necessária de recursos livres no depósito.

Implementação dos métodos CheckOpenLong e CheckOpenShort:

//+------------------------------------------------------------------+
//| Defining the volume to open a long position.                     |
//| INPUT:  no.                                                      |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: not.                                                     |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenLong(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- Select the lot size
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- Check the limits
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- Check the margin requirements
   if(price==0.0) price=m_symbol.Ask();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- Return the trade volume
   return(lot);
  }
//+------------------------------------------------------------------+
//| Defining the volume to open a short position.                    |
//| INPUT:  no.                                                      |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenShort(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- Select the lot size
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- Check the limits
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- Check the margin requirements
   if(price==0.0) price=m_symbol.Bid();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- Return the trade volume
   return(lot);
  }

Então nós resolvemos o primeiro problema. O código acima é um "código-fonte" da classe gerente-de-dinheiro que satisfaz a nossa principal tarefa.


2.2. Criando uma descrição da classe gerente-de-dinheiro gerado para o Assistente MQL5

Vamos agora para a parte de resolver o segundo problema. Nosso gerente-de-dinheiro 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=Trade with a doubling of lot after a loss                  |

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

Escrever:

//| Type=Money                                                       |

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=CSampleMoney                                               |

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=Lots,double,0.1                                        |
//| Parameter=Percent,double,100.0                                   |

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

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

2-7 Precisamos dar mais explicações aos itens 2-7. Seções do descritor de classe contem palavras-chave (Título, Tipo, Nome, Classe, Página, Parâmetros). Infelizmente, o Assistente MQL5 não pode interpretar todas as combinações possíveis de caracteres como parte da descrição da classe.

Portanto, para evitar erros desnecessários, escreva-o assim:
[Slash][Slash][VerticalLine][Space][EqualitySign];

Pode conter espaços apenas para a palavra-chave Título. Parágrafos 1 e 8 devem ser copiados "como são".

O descritor de classe (primeira linha) deve ser encontrada no arquivo o mais tardar até a linha 20.

Vamos adicionar o descritor ao código de origem.

//+------------------------------------------------------------------+
//|                                                  SampleMoney.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\ExpertMoney.mqh>
#include <Trade\DealInfo.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trading with lot doubling after a loss                     |
//| Type=Money                                                       |
//| Name=Sample                                                      |
//| Class=CSampleMoney                                               |
//| Page=                                                            |
//| Parameter=Lots,double,0.1                                        |
//| Parameter=Percent,double,100.0                                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSampleMoney.                                              |
//| Purpose: Class for risk and money management                     |
//|             doubling the volume after a loss deal.               |
//|             It is derived from the CExpertMoney class.           |
//+------------------------------------------------------------------+
class CSampleMoney : public CExpertMoney
  {
protected:
   //--- Setup parameters
   double            m_lots;  // Deal volume for "normal" conditions

public:
                     CSampleMoney();
   //--- Methods to set the parameters
   void              Lots(double lots) { m_lots=lots; }
   //--- Methods to validate the parameters
   virtual bool      ValidationSettings();
   //--- Methods to define the volume
   virtual double    CheckOpenLong(double price,double sl);
   virtual double    CheckOpenShort(double price,double sl);

protected:
   double            CheckPrevLoss();
  };
//+------------------------------------------------------------------+
//| Constructor CSampleMoney.                                        |
//| INPUT:  no.                                                      |
//| OUTPUT: no.                                                      |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
void CSampleMoney::CSampleMoney()
  {
//--- Setting default values
   m_lots=0.1;
  }
//+------------------------------------------------------------------+
//| Validation of the setup parameters.                              |
//| INPUT:  no.                                                      |
//| OUTPUT: true if the settings are correct, otherwise false.       |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
bool CSampleMoney::ValidationSettings()
  {
//--- Call the base class method
   if(!CExpertMoney::ValidationSettings()) return(false);
//--- Validating the parameters
   if(m_lots<m_symbol.LotsMin() || m_lots>m_symbol.LotsMax())
     {
      printf(__FUNCTION__+": The deal volume must be in the range %f to %f",m_symbol.LotsMin(),m_symbol.LotsMax());
      return(false);
     }
   if(MathAbs(m_lots/m_symbol.LotsStep()-MathRound(m_lots/m_symbol.LotsStep()))>1.0E-10)
     {
      printf(__FUNCTION__+": The deal volume must be multiple of  %f",m_symbol.LotsStep());
      return(false);
     }
//--- Successful completion
   return(true);
  }
//+------------------------------------------------------------------+
//| Defining the volume to open a long position.                     |
//| INPUT:  no.                                                      |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenLong(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- Select the lot size
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- Check the limits
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- Check the margin requirements
   if(price==0.0) price=m_symbol.Ask();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_BUY,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- Return the trade volume
   return(lot);
  }
//+------------------------------------------------------------------+
//|Defining the volume to open a short position.                     |
//| INPUT:  no.                                                      |
//| OUTPUT: lot-if successful, 0.0 otherwise.                        |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
double CSampleMoney::CheckOpenShort(double price,double sl)
  {
   if(m_symbol==NULL) return(0.0);
//--- Select the lot size
   double lot=2*CheckPrevLoss();
   if(lot==0.0) lot=m_lots;
//--- Check the limits
   double maxvol=m_symbol.LotsMax();
   if(lot>maxvol) lot=maxvol;
//--- Check the margin requirements
   if(price==0.0) price=m_symbol.Bid();
   maxvol=m_account.MaxLotCheck(m_symbol.Name(),ORDER_TYPE_SELL,price,m_percent);
   if(lot>maxvol) lot=maxvol;
//--- Return the trade volume
   return(lot);
  }
//+------------------------------------------------------------------+
//| Defines whether the prev. deal was losing.                       |
//| INPUT:  no.                                                      |
//| OUTPUT: Volume of the prev. deal if it's losing, otherwise 0.0   |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
double CSampleMoney::CheckPrevLoss()
  {
   double lot=0.0;
//--- Request the history of deals and orders
   HistorySelect(0,TimeCurrent());
//--- variables
   int       deals=HistoryDealsTotal();  // Total number of deals in the history
   CDealInfo deal;
//--- Find the previous deal
   for(int i=deals-1;i>=0;i--)
     {
      if(!deal.SelectByIndex(i))
        {
         printf(__FUNCTION__+": Error of deal selection by index");
         break;
        }
      //--- Check the symbol
      if(deal.Symbol()!=m_symbol.Name()) continue;
      //---Check the profit
      if(deal.Profit()<0.0) lot=deal.Volume();
      break;
     }
//--- Return the volume
   return(lot);
  }
//+------------------------------------------------------------------+

Bem, isso é tudo. O gerente-de-dinheiro está pronto para uso.

Para o gerador de estratégias de negociação do Assistente MQL5 ser capaz de usar o nosso gerente-de-dinheiro, devemos reiniciar o MetaEditor (Assistente MQL5 escaneia a pasta Include\Expert somente na inicialização).

Após reiniciar o MetaEditor, o módulo criado de gerente-de-dinheiro pode ser utilizado no Assistente MQL5:

Figura 5. O gerente-de-dinheiro criado no Assistente de MQL5

Figura 5. O gerente-de-dinheiro criado no Assistente de MQL5

Os parâmetros de entrada especificados na seção de descrição de parâmetros do gerente-de-dinheiro estão agora disponíveis:

Figura 6. Os parâmetros de entrada do gerente-de-dinheiro criado no Assistente de MQL5

Figura 6. Os parâmetros de entrada do gerente-de-dinheiro criado no Assistente de MQL5

Os melhores valores dos parâmetros de entrada da estratégia de negociação implementada podem ser encontrados usando o Strategy Tester do terminal MetaTrader 5.

A Figura 7 mostra os resultados dos testes do Expert Advisor que comercializa de acordo com este sistema de gestão de dinheiro (EURUSD H1, o período de teste: 01.01.2010-05.01.2011).

Figura 7. Resultados dos testes sobre o histórico de estratégia com o módulo de gestão de dinheiro com o dobro depois de uma perda

Figura 7. Resultados dos testes sobre o histórico de estratégia com o módulo de gestão de dinheiro com o dobro depois de uma perda

Ao criar um Expert Advisor, foi utilizado o módulo de sinais de negociação implementados no artigo "Assistente MQL5: Como criar um módulo de sinais de negociação". Os parâmetros do Expert Advisor: (PeriodMA=12, ShiftMA=0, MethodMA=MODE_EMA, AppliedMA=PRICE_CLOSE, Limit=-70, StopLoss=145, TakeProfit=430, Expiration=10, Lots=0.1, Percent=100).


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 descreve como desenvolver um módulo personalizado de risco e gerenciamento de dinheiro e habilitá-lo no Assistente MQL5. Como exemplo consideramos um algoritmo de gestão de dinheiro, em que o tamanho do volume de negócio é determinado pelos resultados do negócio anterior. A estrutura e o formato da descrição da classe criada para o Assistente MQL5 também são descritas.