Assistente MQL5: como criar um módulo de gerenciamento de risco e dinheiro
Introdução
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
- 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).
- 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".
- 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.
- 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:
- CExpertTrade (para negociação)
- CIndicators (para os indicadores de controle e séries temporais envolvidos no trabalho da EA)
- CSymbolInfo (para obter informações sobre o instrumento)
- CAccountInfo (para obter informações sobre os estado da conta de negociação)
- CPositionInfo (para obter informações sobre posições)
- COrderInfo (para obter informações sobre pedidos pendentes)
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 |
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
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);
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);
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.
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).
1.2. Métodos para determinar o volume de uma posição
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.
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.
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.
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.
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
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
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.
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:
- O volume máximo para um negócio para o símbolo, especificado nas configurações do servidor (SYMBOL_VOLUME_MAX).
- 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.
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: Pode conter espaços apenas para a palavra-chave Título. Parágrafos 1 e 8 devem ser copiados "como são".
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
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
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
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.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/230
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso