Manuale MQL5: Utilizzo degli indicatori per impostare le condizioni di trading in Expert Advisor
Introduzione
In questo articolo, l'Expert Advisor sarà arricchito con indicatori i cui valori saranno utilizzati per verificare le condizioni di apertura della posizione. Per ravvivarlo, creeremo un elenco a discesa nei parametri esterni per poter selezionare uno su tre indicatori di trading.
Si prega di ricordare, per ogni evenienza: continuiamo a modificare l'Expert Advisor su cui abbiamo lavorato in tutti gli articoli precedenti della serie Manuale MQL5. L'ultima versione dell'Expert Advisor può essere scaricata dall'articolo intitolato "Manuale MQL5: La cronologia delle offerte e della libreria di funzioni per ottenere proprietà di posizione".
Inoltre, questo articolo presenterà una funzione che creeremo per verificare se le operazioni di trading possono o non possono essere eseguite. La funzione di apertura della posizione verrà modificata in modo da consentire all'Expert Advisor di determinare la modalità di negoziazione (Instant Execution e Market Execution).
Poiché il codice dell'Expert Advisor, seguendo tutti i miglioramenti e i miglioramenti apportati negli articoli precedenti, supera già le 1.500 righe, diventerà sempre meno conveniente con ogni nuova funzionalità aggiunta. Quindi, la soluzione logica è dividerlo in diverse categorie come file di libreria separati. Ora che gli obiettivi sono stati fissati, iniziamo.
Sviluppo di Expert Advisor
Inseriamo il codice sorgente di Expert Advisor (*.mq5) dall'articolo precedente in una cartella separata, TestIndicatorConditions, in cui dobbiamo creare la sottocartella Include. Questa è la cartella in cui creeremo i file include (*.mqh). Possono essere generati utilizzando la procedura guidata MQL5 (Ctrl+N) o creati manualmente nella directory richiesta come file di testo standard (*.txt) e ulteriormente rinominati in *.mqh.
Di seguito sono riportati i nomi e i commenti a tutti i file di include creati:
- Enums.mqh conterrà tutte le enumerazioni;
- InfoPanel.mqh sarà dotato di funzioni per l'impostazione del pannello informativo, la creazione e l'eliminazione di oggetti grafici;
- Errors.mqh coprirà tutte le funzioni che restituiscono codici di errore e motivi di deinitializzazione;
- TradeSignals.mqh sarà caratterizzato da funzioni che riempiono gli array con prezzi e valori di indicatori, nonché blocchi di segnale;
- TradeFunctions.mqh conterrà funzioni di trading;
- ToString.mqh coprirà le funzioni che convertono i valori numerici in valori stringa;
- Auxiliary.mqh verrà utilizzato per altre funzioni ausiliarie.
Per includere queste librerie nel file principale, utilizziamo la direttiva #include. Poiché il file principale di Expert Advisor e la cartella include file (Include) si trovano nella stessa cartella, il codice per l'inclusione dei file sarà il seguente:
//--- Include custom libraries #include "Include\Enums.mqh" #include "Include\InfoPanel.mqh" #include "Include\Errors.mqh" #include "Include\TradeSignals.mqh" #include "Include\TradeFunctions.mqh" #include "Include\ToString.mqh" #include "Include\Auxiliary.mqh"
Quindi, saremo in grado di aprirli e modificarli e spostare una parte del codice sorgente dal file principale di Expert Advisor.
Per navigare correttamente nel codice, i riferimenti ai file di intestazione adiacenti e al file principale di Expert Advisor verranno aggiunti a ciascun file di intestazione. Ad esempio, per la nostra libreria di funzioni di trading, TradeFunctions.mqh, questo assomiglierà a:
//--- Connection with the main file of the Expert Advisor #include "..\TestIndicatorConditions.mq5" //--- Include custom libraries #include "Enums.mqh" #include "InfoPanel.mqh" #include "Errors.mqh" #include "TradeSignals.mqh" #include "ToString.mqh" #include "Auxiliary.mqh"
Per i file allo stesso livello di nidificazione, è sufficiente specificare semplicemente il nome. Per salire di un livello, è necessario mettere due punti prima della barra posteriore nel percorso.
Aggiungiamo l'enumerazione per gli indicatori nel file Enums.mqh. A scopo illustrativo, in questo Expert Advisor utilizzeremo due indicatori standard (Moving Average e Commodity Channel Index) e un indicatore personalizzato ( MultiRange_PCH ). L'enumerazione sarà la seguente:
//--- Indicators enum ENUM_INDICATORS { MA = 0, // Moving Average CCI = 1, // CCI PCH = 2 // Price Channel };
I parametri esterni vengono modificati come segue:
//--- External parameters of the Expert Advisor sinput long MagicNumber=777; // Magic number sinput int Deviation=10; // Slippage input ENUM_INDICATORS Indicator=MA; // Indicator input int IndicatorPeriod=5; // Indicator period input int IndicatorSegments=2; // Number of one direction indicator segments input double Lot=0.1; // Lot input double VolumeIncrease=0.1; // Position volume increase input double VolumeIncreaseStep=10; // Step for volume increase input double StopLoss=50; // Stop Loss input double TakeProfit=100; // Take Profit input double TrailingStop=10; // Trailing Stop input bool Reverse=true; // Position reversal sinput bool ShowInfoPanel=true; // Display of the info panel
Come accennato in precedenza, sarà possibile selezionare uno dei tre indicatori nell'elenco a discesa del parametro Indicatore.
Esiste un solo parametro applicabile a tutti gli indicatori in cui è possibile impostare il periodo dell'indicatore: IndicatorPeriod. Il parametro NumberOfBars della versione precedente di Expert Advisor è stato rinominato in IndicatorSegments e ora indica il numero di barre durante le quali un determinato indicatore deve salire/scendere per soddisfare la condizione di apertura della posizione.
Inoltre, abbiamo aggiunto un altro parametro esterno, VolumeIncreaseStep, che può essere utilizzato per impostare il passo per l'aumento del volume in punti.
Il valore della variabile AllowedNumberOfBars (ora AllowedNumberOfSegments)veniva regolato nella funzione personalizzata GetBarsData(). Ora verrà inserito in una funzione separata e chiamato solo all'inizializzazione.
Poiché la condizione di apertura della posizione verrà ora controllata utilizzando i valori dell'indicatore, il valore da assegnare sarà sempre maggiore di due. In altre parole, se alla variabile esterna IndicatorSegments viene assegnato il valore di 1, alla variabile AllowedNumberOfSegments verrà assegnato il valore di 3, poiché per soddisfare la condizione (ad esempio per un BUY), il valore dell'indicatore sulla barra completata deve essere maggiore di quello sulla barra precedente. A tal fine, dobbiamo ottenere gli ultimi tre valori dell'indicatore.
Di seguito è riportato il codice funzione CorrectInputParameters():
//+------------------------------------------------------------------+ //| Adjusting input parameters | //+------------------------------------------------------------------+ void CorrectInputParameters() { //--- Adjust the number of bars for the position opening condition if(AllowedNumberOfSegments<=0) { if(IndicatorSegments<=1) AllowedNumberOfSegments=3; // At least three bars are required if(IndicatorSegments>=5) AllowedNumberOfSegments=5; // but no more than 7 else AllowedNumberOfSegments=IndicatorSegments+1; // and always greater by two } }
Prima di iniziare a gestire gli indicatori, creiamo una funzione che verificherà se il trading è consentito - CheckTradingPermission(). Se il trading non è consentito per uno dei motivi elencati nella funzione, verrà restituito il valore zero. Ciò significa che il prossimo tentativo dovrà essere fatto sulla barra successiva.
//+------------------------------------------------------------------+ //| Checking if trading is allowed | //+------------------------------------------------------------------+ bool CheckTradingPermission() { //--- For real-time mode if(IsRealtime()) { //--- Checking server connection if(!TerminalInfoInteger(TERMINAL_CONNECTED)) return(1); //--- Permission to trade at the running program level if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED)) return(2); //--- Permission to trade at the terminal level if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return(3); //--- Permission to trade for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return(4); //--- Permission to trade automatically for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) return(5); } //--- return(0); }
Passiamo ora al punto principale dell'articolo. Per ottenere l'accesso ai valori dell'indicatore, dobbiamo prima ottenere la sua maniglia. Questo viene fatto usando funzioni speciali i cui nomi sono fatti del nome breve dell'indicatore e del simbolo 'i' che lo precede.
Ad esempio, l'indicatore della media mobile ha la funzione corrispondente iMA(). Tutte le maniglie standard degli indicatori nel terminale MetaTrader 5 possono essere ottenute utilizzando queste funzioni. L'elenco completo è disponibile nella sezione MqL5 Reference chiamata Indicatori tecnici. Se è necessario ottenere una maniglia di un indicatore personalizzato, utilizzare la funzione iCustom().
Implementeremo la funzione GetIndicatorHandle() in cui, a seconda dell'indicatore selezionato nel parametro Indicator, il valore handle dell'indicatore corrispondente verrà assegnato alla variabile globale indicator_handle. Il codice funzione può essere trovato nella nostra libreria di funzioni del segnale di trading (il file \Include\TradeSignals.mqh), mentre la variabile con l'handle dell'indicatore si trova nel file principale dell'Expert Advisor.
//+------------------------------------------------------------------+ //| Getting the indicator handle | //+------------------------------------------------------------------+ void GetIndicatorHandle() { //--- If the Moving Average indicator is selected if(Indicator==MA) indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); //--- If the CCI indicator is selected if(Indicator==CCI) indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE); //--- If the MultiRange_PCH indicator is selected if(Indicator==PCH) indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod); //--- If the indicator handle could not be obtained if(indicator_handle==INVALID_HANDLE) Print("Failed to get the indicator handle!"); }
Inoltre, creiamo la funzione GetDataIndicators() in cui utilizzando le maniglie degli indicatori ottenuti, possiamo ottenere i loro valori. Questo viene fatto usando la funzione CopyBuffer() in modo simile a ottenere i valori della barra usando le funzioni CopyTime(), CopyClose(), CopyOpen(), CopyHigh() e CopyLow() considerate nell'articolo chiamato "Manuale MQL5: Analisi delle proprietà di posizione nel MetaTrader 5 Strategy Tester".
Poiché l'indicatore può avere diversi buffer (righe di valori), l'indice del buffer viene passato alla funzione CopyBuffer() come secondo parametro. Gli indici buffer per gli indicatori standard sono disponibili in MQL5 Reference. Per gli indicatori personalizzati, gli indici del buffer sono disponibili nel codice, a condizione che il codice sorgente sia disponibile. Se non c'è codice, dovrai trovare l'indice tramite esperimento, osservando come le condizioni sono soddisfatte nella modalità di visualizzazione dello Strategy Tester.
Prima di ciò, dobbiamo creare matrici dinamiche per i valori del buffer degli indicatori nel file principale di Expert Advisor:
//--- Arrays for indicator values double indicator_buffer1[]; double indicator_buffer2[];
Il codice di GetIndicatorsData() è fornito di seguito:
//+------------------------------------------------------------------+ //| Getting indicator values | //+------------------------------------------------------------------+ bool GetIndicatorsData() { //--- If the indicator handle has been obtained if(indicator_handle!=INVALID_HANDLE) { //--- For the Moving Average or CCI indicator if(Indicator==MA || Indicator==CCI) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- For the MultiRange_PCH indicator if(Indicator==PCH) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); ArraySetAsSeries(indicator_buffer2,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- return(true); } //--- If the indicator handle has not been obtained, retry else GetIndicatorHandle(); //--- return(false); }
La funzione GetTradingSignal() è stata sostanzialmente modificata. Le condizioni sono diverse in assenza della posizione e dove esiste la posizione. Per gli indicatori della media mobile e del CCI, le condizioni sono le stesse. Per MultiRange_PCH, sono disposti in un blocco separato. Per rendere il codice più leggibile ed evitare ripetizioni, creiamo una funzione ausiliaria, GetSignal(), che restituisce un segnale per l'apertura o l'inversione della posizione, a condizione che tale posizione esista e che l'azione pertinente sia consentita dal parametro esterno.
Di seguito è riportato il codice della funzione GetSignal():
//+------------------------------------------------------------------+ //| Checking the condition and returning a signal | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetSignal() { //--- Check conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]<indicator_buffer1[2]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5] && indicator_buffer1[5]<indicator_buffer1[6]) return(ORDER_TYPE_SELL); //--- A Buy signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]>indicator_buffer1[2]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5] && indicator_buffer1[5]>indicator_buffer1[6]) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- A Buy signal if(close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); } //--- No signal return(WRONG_VALUE); }
Il codice della funzione GetTradingSignal() è ora il seguente:
//+------------------------------------------------------------------+ //| Determining trading signals | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetTradingSignal() { //--- If there is no position if(!pos.exists) { //--- A Sell signal if(GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- A Buy signal if(GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); } //--- If the position exists if(pos.exists) { //--- Get the position type GetPositionProperties(P_TYPE); //--- Get the last deal price GetPositionProperties(P_PRICE_LAST_DEAL); //--- Block that checks conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } } //--- No signal return(WRONG_VALUE); }
Ora, abbiamo solo bisogno di vedere nelle modalità Instant Execution e Market Execution che fanno parte delle proprietà dei simboli e di modificare di conseguenza il codice della funzione di apertura della posizione OpenPosition(). Le modalità i cui nomi sono autoesplicativi si trovano anche in MQL5 Reference:
- Instant Execution (Esecuzione Istantanea)
- Market Execution (Esecuzione a Mercato)
Si ricorda che quando si ha a che fare con la modalità Market Execution, non è possibile aprire una posizione con i livelli di Stop Loss e Take Profit impostati: è necessario prima aprire una posizione e poi modificarla, impostando i livelli.
Aggiungiamo la modalità di esecuzione alla struttura delle proprietà dei simboli:
//--- Symbol properties struct symbol_properties { int digits; // Number of decimal places in the price int spread; // Spread in points int stops_level; // Stops level double point; // Point value double ask; // Ask price double bid; // Bid price double volume_min; // Minimum volume for a deal double volume_max; // Maximum volume for a deal double volume_limit; // Maximum permissible volume for a position and orders in one direction double volume_step; // Minimum volume change step for a deal double offset; // Offset from the maximum possible price for a transaction double up_level; // Upper Stop level price double down_level; // Lower Stop level price ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode };
Di conseguenza, è necessario modificare l'enumerazione ENUM_SYMBOL_PROPERTIES
//--- Enumeration of position properties enum ENUM_SYMBOL_PROPERTIES { S_DIGITS = 0, S_SPREAD = 1, S_STOPSLEVEL = 2, S_POINT = 3, S_ASK = 4, S_BID = 5, S_VOLUME_MIN = 6, S_VOLUME_MAX = 7, S_VOLUME_LIMIT = 8, S_VOLUME_STEP = 9, S_FILTER = 10, S_UP_LEVEL = 11, S_DOWN_LEVEL = 12, S_EXECUTION_MODE = 13, S_ALL = 14 };
e la funzione GetSymbolProperties():
case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //--- case S_ALL : symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD); symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits); symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits); symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT); symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits); symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits); symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits); symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //---
Di conseguenza, il codice della funzione OpenPosition() è ora il seguente:
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Set the magic number in the trading structure trade.SetExpertMagicNumber(MagicNumber); //--- Set the slippage in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); //--- The Instant Execution mode // A position can be opened with the Stop Loss and Take Profit levels set if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- The Market Execution mode // First open a position and only then set the Stop Loss and Take Profit levels // *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If there is no position, first open a position and then set Stop Loss and Take Profit if(!pos.exists) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); //--- Get the flag of presence/absence of the position pos.exists=PositionSelect(_Symbol); //--- If the position exists if(pos.exists) { //--- Set Stop Loss and Take Profit if(!trade.PositionModify(_Symbol,sl,tp)) Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged else { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } }
Dobbiamo ancora aggiungere il tocco finale e molto importante alle funzioni di gestione degli eventi:
- OnInit
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Adjust the input parameters CorrectInputParameters(); //--- Get indicator handles GetIndicatorHandle(); //--- Initialize the new bar CheckNewBar(); //--- Get the properties GetPositionProperties(P_ALL); //--- Set the info panel SetInfoPanel(); //--- return(0); }
- OnDeinit
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) { //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); //--- Delete the indicator handle IndicatorRelease(indicator_handle); } }
- OnTick
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If the bar is not new, exit if(!CheckNewBar()) { if(IsVisualMode() || IsRealtime()) { //--- Get the properties and update the values on the panel GetPositionProperties(P_ALL); //--- Set/update the info panel SetInfoPanel(); } return; } //--- If there is a new bar else { //--- If trading is allowed if(CheckTradingPermission()==0) { if(!GetIndicatorsData()) return; GetBarsData(); // Get bar data TradingBlock(); // Check the conditions and trade ModifyTrailingStop(); // Modify the Trailing Stop level } } //--- Get the properties GetPositionProperties(P_ALL); //--- Update the info panel SetInfoPanel(); }
Ora che tutte le funzioni sono pronte, possiamo ottimizzare i parametri. Tieni presente che è necessario compilare il codice dal file di programma principale.
Ottimizzazione dei parametri e test expert advisor
Il tester strategico deve essere impostato come mostrato di seguito:
Fig. 1. Impostazioni di Strategy Tester.
Inoltre, impostiamo i parametri di Expert Advisor per l'ottimizzazione (vedere anche il file *.set allegato con le impostazioni):
Fig. 2. Impostazioni dell'Expert Advisor.
L'ottimizzazione ha richiesto circa 40 minuti su un processore dual-core. Il grafico di ottimizzazione consente di valutare in parte la qualità di un sistema di trading in base ai risultati nella zona di profitto:
Fig. 3. Grafico di ottimizzazione.
I risultati del test del fattore di recupero massimo sono i seguenti:
Fig. 4. Risultati del test del fattore di recupero massimo.
Conclusione
Allegato all'articolo è l'archivio scaricabile con i codici sorgente dell'Expert Advisor. Una volta estratto, è necessario inserire la cartella del file \TestIndicatorConditions nel terminale <Metatrader 5>\MQL5\Experts. Per garantire il corretto funzionamento dell'Expert Advisor, l'indicatore MultiRange_PCH deve essere scaricato e inserito nel terminale <Metatrader 5 Terminal>\MQL5\Indicators.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/645
- 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