Il Wizard MQL5: Come creare un modulo di gestione del rischio e del denaro
Introduzione
MetaTrader 5 fornisce un potente strumento che ti consente di controllare rapidamente varie idee di trading. Questa è la generazione di Expert Advisor utilizzando il Wizard MQL5 sulla base di strategie di trading già pronte.
Un Expert Advisor creato con il MQL5 Wizard, si basa su quattro pilastri, ovvero quattro classi base:
Figura 1. La struttura della classe base CExpert
- La classe CExpert (o la sua sottoclasse) è il "motore" principale di un Expert Advisor. Un'istanza di CExpert contiene una copia di ogni classe: CExpertSignal, CExpertMoney e CExpertTrailing (o le loro sottoclassi):
- CExpertSignal è la base del generatore di segnali di trading. Un'istanza della classe derivata CExpertSignal, inclusa in CExpert, fornisce a un Expert Advisor informazioni sulla possibilità di entrare nel mercato, i livelli di ingresso e l'immissione di ordini protettivi sulla base di algoritmi incorporati. L'Expert Advisor decide se entrare nel mercato. Maggiori dettagli sulla classe CExpertSignal e sull'utilizzo di essa sono descritti nell'articolo "Il Wizard MQL5: Come creare un modulo di segnali di trading".
- La classe CExpertMoney è alla base del meccanismo di gestione del rischio e del denaro. Un'istanza della classe derivata CExpertMoney, inclusa in CExpert, fornisce a un Expert Advisor informazioni sui possibili volumi per l'apertura di posizioni e l'immissione di ordini in sospeso sulla base di algoritmi integrati. L'Expert Advisor prende una decisione sul volume.
- La classe CExpertTrailing è alla base del meccanismo di supporto delle posizioni aperte. Un'istanza della classe derivata CExpertTrailing, inclusa in CExpert, fornisce a un EA informazioni sulla possibilità di modificare gli ordini di protezione della posizione sulla base di algoritmi incorporati. L'Expert Advisor prende una decisione sulla modifica degli ordini. Maggiori dettagli sulla classe CExpertTrailing e sul lavoro con essa verranno descritti in un articolo separato.
Inoltre, i membri della classe CExpert sono istanze delle seguenti classi:
- CExpertTrade (per il trading)
- CIndicators (per il controllo degli indicatori e delle serie temporali coinvolte nell'attività dell'EA).
- CSymbolInfo (per ottenere informazioni sullo strumento)
- CAccountInfo (per ottenere informazioni sullo stato del conto di trading)
- CPositionInfo (per ottenere informazioni sulle posizioni)
- COrderInfo (per ottenere informazioni sugli ordini in sospeso)
Di seguito, con il termine "expert" si indicherà un'istanza di CExpert o una sua sottoclasse.
Maggiori dettagli su CExpert e sul suo lavoro saranno descritti in un articolo separato.
1. Classe base CExpertMoney
Come accennato in precedenza, la classe CExpertMoney è alla base del meccanismo di gestione del rischio e del denaro. Per la comunicazione con il "mondo esterno", la classe CExpertMoney ha un insieme di metodi virtuali pubblici:
Inizializzazione | Descrizione |
virtual Init | L'inizializzazione dell'istanza della classe fornisce la sincronizzazione dei dati del modulo con i dati dell'EA |
Impostazione del valore del parametro "Percentuale di rischio" | |
virtual ValidationSettings | Convalida dei parametri impostati |
virtual InitIndicators | Creazione e inizializzazione di tutti gli indicatori e delle serie temporali necessarie per il funzionamento del meccanismo di gestione del rischio e del denaro |
Metodi per verificare la necessità di aprire/modificare/chiudere una posizione |
|
virtual CheckOpenLong | Determinazione del volume per aprire una posizione long |
virtual CheckOpenShort | Determinazione del volume per aprire una posizione short |
virtual CheckReverse | Determinazione del volume per invertire una posizione |
virtual CheckClose | Determinazione della necessità di chiudere una posizione |
Descrizione dei metodi
1.1. Metodi di inizializzazione
1.1.1 Init
Il metodo Init() viene chiamato automaticamente subito dopo l'aggiunta di un'istanza di classe all'expert. L'override del metodo non è richiesto.
virtual bool Init(CSymbolInfo* symbol, ENUM_TIMEFRAMES period, double adjusted_point);
1.1.2 Percent
Il metodo Percent() viene chiamato per configurare il parametro appropriato. Il suo valore può essere compreso tra 0,0 e 100,0 inclusi. Il valore predefinito è 100,0. L'override del metodo non è richiesto.
void Percent(double percent);
1.1.3 ValidationSettings
Il metodo ValidationSettings() viene chiamato direttamente dall'expert dopo che tutti i parametri sono stati impostati. È necessario riscrivere il metodo se sono presenti parametri di configurazione aggiuntivi.
virtual bool ValidationSettings();
Il metodo riscritto deve restituire true se tutte le opzioni sono valide (utilizzabili). Se almeno uno dei parametri non è corretto, deve restituire false (ulteriori lavori sono impossibili). Il metodo riscritto deve chiamare il metodo della classe base con la verifica del risultato.
1.1.4 InitIndicators
Il metodo InitIndicators() implementa la creazione e l'inizializzazione di tutti gli indicatori e le serie temporali necessarie. Viene chiamato dall'expert dopo che tutti i parametri sono stati impostati e la loro correttezza è stata verificata con successo. Il metodo deve essere ignorato se il meccanismo di gestione del rischio e del denaro utilizza almeno un indicatore o delle serie temporali.
virtual bool InitIndicators(CIndicators* indicators);
Gli indicatori e/o le serie temporali devono essere utilizzati attraverso le classi appropriate della Libreria Standard. I puntatori di tutti gli indicatori e/o le serie temporali dovrebbero essere aggiunti alla raccolta di indicatori di un expert (un puntatore al quale viene passato come parametro).
Il metodo riscritto deve restituire true se tutte le manipolazioni con gli indicatori e/o le serie temporali hanno avuto esito positivo (sono idonei per l'uso). Se almeno un'operazione con gli indicatori e/o le serie temporali fallisce, il metodo deve restituire false (impossibile eseguire ulteriori lavori).
1.2. Metodi per determinare il volume di una posizione
1.2.1 CheckOpenLong
Il metodo CheckOpenLong() calcola il volume per l'apertura di una posizione long. Viene chiamato da un expert per determinare il volume per l'apertura di una posizione long. Il metodo deve essere riscritto se si prevede di calcolare il volume di apertura della posizione long utilizzando l'algoritmo che differisce da quello implementato nella classe base.
\virtual double CheckOpenLong(double price, double sl);
Il metodo deve implementare l'algoritmo per il calcolo del volume per l'apertura di una posizione long. Il metodo deve restituire il volume calcolato.
1.2.2 CheckOpenShort
Il metodo CheckOpenShort() calcola il volume per l'apertura di una posizione short. Viene chiamato da un expert per determinare il volume per l'apertura di una posizione short. Il metodo deve essere riscritto se si prevede di calcolare il volume di apertura della posizione short utilizzando l'algoritmo che differisce da quello implementato nella classe base.
virtual double CheckOpenShort(double price, double sl);
Il metodo deve implementare l'algoritmo per il calcolo del volume per l'apertura di una posizione short. Il metodo deve restituire il volume calcolato.
1.2.3 CheckReverse
Il metodo CheckReverse() calcola il volume per invertire una posizione. Viene chiamato da un expert per determinare il volume di un'operazione di trading per l'inversione di una posizione. Il metodo deve essere riscritto se si prevede di calcolare il volume di inversione di posizione utilizzando l'algoritmo diverso da quello implementato nella classe base (es. inversione con doppio volume).
virtual double CheckReverse(CPositionInfo* position, double sl);
Il metodo deve implementare l'algoritmo per il calcolo del volume per invertire una posizione le cui informazioni possono essere ottenute dal puntatore di posizione. Il metodo deve restituire il volume calcolato per l'inversione di posizione.
1.2.4 CheckClose
Il metodo CheckClose() verifica se è necessario chiudere una posizione (in termini di gestione del denaro e del rischio). Viene chiamato da un expert per determinare se è necessario chiudere una posizione. Il metodo deve essere scritto se si prevede di chiudere una posizione utilizzando un algoritmo diverso da quello implementato nella classe base (es. chiusura parziale).
virtual double CheckClose(CPositionInfo* position);
Il metodo deve implementare l'algoritmo per definire la necessità di chiudere una posizione le cui informazioni possono essere ottenute dal puntatore di posizione. Il metodo deve restituire il volume calcolato per la chiusura della posizione.
2. Creare un meccanismo di gestione del denaro e del rischio
Adesso, dopo aver esaminato la struttura della classe base CExpertMoney, puoi iniziare a creare il tuo meccanismo di gestione del rischio e del denaro. Da qui in poi il meccanismo di gestione del rischio e del denaro sarà denominato "money-manager".
Come accennato in precedenza, la classe CExpertMoney è un insieme di "ropes" virtuali pubbliche, ovvero metodi attraverso il cui uso l'expert può conoscere l'opinione del gestore del denaro sul volume del mercato che entra in una direzione o nell'altra.
Pertanto, il nostro obiettivo primario è creare la nostra classe del money-manager, derivandola dalla classe CExpertMoney e riscrivendo i metodi virtuali appropriati, implementando gli algoritmi richiesti.
Il nostro secondo problema (che non è meno importante) è rendere la nostra classe "visibile" al Wizard MQL5. Ma andiamo con ordine.
2.1. Creare la classe del generatore di segnali di trading
Cominciamo.
Wizard MQL5) un file include con l'estensione mqh.
Vai su File e seleziona "Create" (o digita Ctrl+N) e indica la creazione di un file include:
Figura 2. Crea un file di inclusione utilizzando il Wizard MQL5
Da notare che affinché il file venga poi "rilevato" dal Wizard MQL5 come money-manager, deve essere creato nella cartella Include\Expert.
Per non cestinarlo nella Libreria Standard, creiamo la nostra cartella Include\Expert\Money\MyMoneys, nella quale creiamo il file SampleMoney.mqh specificando questi parametri nel Wizard MQL5:
Figura 3. Impostare la posizione del file include
Come risultato dell'operazione Wizard MQL5 abbiamo il seguente schema:
//+------------------------------------------------------------------+ //| 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 //+------------------------------------------------------------------+
Quello che segue è soltanto un lavoro da svolgere "manualmente". Rimuovi le parti non necessarie e aggiungere ciò che ti occorre: il file include ExpertMoney.mqh della Libreria Standard con una descrizione della classe vuota.
//+------------------------------------------------------------------+ //| 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 { }; //+------------------------------------------------------------------+
Ora è necessario scegliere gli algoritmi.
Come base per il nostro money manager prendiamo il seguente algoritmo: In condizioni "normali" si propone di utilizzare un volume di operazioni fisso e predeterminato. Ma se la posizione precedente è stata chiusa con una perdita, si propone di aprire una posizione con un volume raddoppiato.
Rifletti ciò nel nostro file.
//+------------------------------------------------------------------+ //| 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 { }; //+------------------------------------------------------------------+
Definisci un elenco di impostazioni per il nostro money-manager. In realtà, non ci sarà nessun elenco. Tutte le impostazioni sono incluse in un unico parametro che determinerà il volume di una transazione in condizioni "normali".
Il parametro verrà archiviato in un membro dati protetto della classe. L'accesso al parametro sarà implementato attraverso un apposito metodo pubblico. Nel costruttore della classe, il parametro verrà inizializzato da un valore predefinito. Per controllare i parametri, riscriviamo il metodo virtuale ValidationSettings secondo la descrizione della classe base.
Includiamo queste modifiche nel nostro file:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Separatamente, consideriamo come implementare il metodo ValidationSettings(). Il punto è che la classe base ha già un parametro di configurazione, che richiede anche la verifica.
Implementazione del metodo ValidationSettings():
//+------------------------------------------------------------------+ //| 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_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 volume of the deal must be multiple of %f",m_symbol.LotsStep()); return(false); } //--- Successful completion return(true); }
Le impostazioni sono pronte. Adesso procediamo con il funzionamento del money manager. Abbiamo bisogno di un metodo che determina se l'operazione precedente era perdente e, se necessario, ne definisce il volume. Dichiaralo nella descrizione della 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(); };
Implementazione del metodo:
//+------------------------------------------------------------------+ //| 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); }
Consideriamo di nuovo i nostri algoritmi in modo più dettagliato (sebbene sia già dettagliato).
Senza entrare nei dettagli, notiamo che il nostro money manager proporrà di aumentare il volume di un operazione al ricevimento della perdita nell'operazione precedente. Se non ci sono state perdite nell'operazione precedente, offriremo l'apertura di una posizione con un volume fisso, definito da un determinato parametro.
A tal fine, riscriviamo i metodi virtuali CheckOpenLong e CheckOpenShort, compilandoli con le funzionalità corrispondenti.
Descrizione della 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(); };
Le implementazioni di CheckOpenLong e CheckOpenShort sono praticamente identiche. Entrambi i metodi determinano la necessità di aumentare il volume chiamando il metodo CheckPrevLoss implementato in precedenza.
Successivamente dobbiamo tenere conto del fatto che non possiamo aumentare il volume degli scambi indefinitamente. Ci sono due limitazioni al volume della posizione:
- Il volume massimo per un'operazione per il simbolo, specificato nelle impostazioni del server (SYMBOL_VOLUME_MAX).
- Disponibilità dell'importo richiesto di fondi gratuiti sul deposito.
Implementazione dei metodi 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); }
Quindi abbiamo risolto il primo problema. Il codice sopra è un "codice sorgente" della classe money manager che soddisfa il nostro compito principale.
2.2. Creazione di una descrizione della classe money manager generata per la procedura guidata MQL5
Passiamo ora alla risoluzione del secondo problema. Il nostro money manager dovrebbe essere "riconosciuto" dal generatore di strategie di trading del Wizard MQL5.
Abbiamo soddisfatto la prima condizione necessaria: abbiamo posizionato il file dove verrà "trovato" dal Wizard MQL5. Ma ciò non è sufficiente. La procedura guidata MQL5 non deve solo "trovare" il file, ma anche "riconoscerlo". Per fare ciò dobbiamo aggiungere al testo originale il descrittore di classe per il Wizard MQL5.
Prendiamo in considerazione queste regole.
1. Il blocco di commenti deve iniziare con le seguenti righe:
// wizard description start //+------------------------------------------------------------------+ //| Description of the class |
2. La riga successiva è un descrittore di testo (ciò che vedremo nel Wizard MQL5 quando si sceglie il segnale) nel formato "//| Title=<Text> |". Se il testo è troppo grande per una riga, dopo di quest’ultima puoi aggiungere un'altra riga (ma non di più).
Nel nostro caso abbiamo quanto segue:
//| Title=Trade with a doubling of lot after a loss |
3. Quindi arriva una riga con il tipo di classe specificato nel formato "//| Type=<Type> |". Il campo <Type> deve avere il valore Money (oltre ai money manager, il Wizard MQL5 conosce altri tipi di classi).
Scrivi:
//| Type=Money |
4. La riga seguente nel formato "//| Name=<Name> |" è il nome breve del segnale (viene utilizzato dal Wizard MQL5 per generare i nomi delle variabili globali dell'expert).
Otteniamo quanto segue:
//| Name=Sample |
5. Il nome di una classe è un elemento importante della descrizione. Nella riga con il formato "//| Class=<ClassNameа> |", il parametro <ClassName> deve corrispondere al nome della nostra classe:
//| Class=CSampleMoney |
6. Non compiliamo questa riga, ma deve essere presente (questo è un collegamento alla sezione di riferimento del linguaggio):
//| Page= |
7. Inoltre, ci sono le descrizioni dei parametri di configurazione del segnale.
Questo è un insieme di righe (il numero di righe è uguale al numero di parametri).
Il formato di ogni riga è "//| Parameter=<NameOfMethod>,<TypeOfParameter>,<DefaultValue> |".
Ecco il nostro set di parametri:
//| Parameter=Lots,double,0.1 | //| Parameter=Percent,double,100.0 |
8. Il blocco di commento deve terminare con le seguenti righe:
//+------------------------------------------------------------------+ // wizard description end
2-7 Dobbiamo dare ulteriori spiegazioni ai punti 2-7. Le sezioni del descrittore di classe contengono parole chiave (Title, Type, Name, Class, Page, Parameter). Sfortunatamente, Wizard MQL5 non può interpretare tutte le possibili combinazioni di caratteri come parte della descrizione della classe.
Pertanto, per evitare errori non necessari, scrivilo in questo modo:<Description> può contenere spazi solo per la parola chiave Title. I paragrafi 1 e 8 devono essere copiati "così come sono".
Aggiungiamo il descrittore al codice sorgente.
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Bene, questo è tutto. Il gestore di denaro è pronto per l'uso.
Affinché il generatore di strategie di trading del Wizard MQL5 sia in grado di utilizzare il nostro money manager, dobbiamo riavviare MetaEditor (il Wizard MQL5 scansiona la cartella Include\Expert solo all'avvio).
Dopo aver riavviato MetaEditor, il modulo money manager creato può essere utilizzato nel Wizard MQL5:
Figura 5. Il money manager creato nel Wizard MQL5
Sono ora disponibili i parametri di input specificati nella sezione di descrizione dei parametri money manager:
Figura 6. Parametri di input del money manager creato nel Wizard MQL5
I migliori valori dei parametri di input della strategia di trading implementata possono essere trovati utilizzando lo Strategy Tester del MetaTrader 5.
La Figura 7 mostra i risultati dei test dell'Expert Advisor che opera secondo questo sistema di gestione del denaro (EURUSD H1, il periodo di test: 01.01.2010-05.01.2011).
Figura 7. I risultati dei test sulla cronologia della strategia con il modulo di gestione del denaro con un raddoppio dopo una perdita
Durante la creazione di un Expert Advisor, abbiamo utilizzato il modulo dei segnali di trading implementato nell'articolo "Il Wizard MQL5: Come creare un modulo di segnali di trading". I parametri dell'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).
Conclusione
Il generatore di strategie di trading del Wizard MQL5 semplifica enormemente il test delle idee di trading. Il codice dell'expert generato si basa sulle classi di strategie di trading della Libreria Standard che vengono utilizzate per creare determinate implementazioni di classi di segnali di trading, classi di gestione del denaro e del rischio e classi di supporto della posizione.
L'articolo descrive come sviluppare un modulo personalizzato di gestione del rischio e del denaro e abilitarlo nella procedura guidata MQL5. Ad esempio, abbiamo considerato un algoritmo di gestione del denaro in cui la dimensione del volume degli scambi è determinata dai risultati dell'operazione precedente. Vengono inoltre descritti la struttura e il formato della descrizione della classe creata per il Wizard MQL5.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/230
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso