
Sistemi di Trading Adattivi e loro utilizzo nel Client MetaTrader 5
Introduzione
Centinaia di migliaia di trader in tutto il mondo utilizzano le piattaforme di trading sviluppate da MetaQuotes Software Corp. Il fattore chiave che porta al successo è la superiorità tecnologica basata sull'esperienza di molti anni e sulle migliori soluzioni software.
Molte persone hanno valutato nuove opportunità che sono ora disponibili con il nuovo linguaggio MQL5. Le sue caratteristiche principali sono le alte prestazioni e la possibilità di utilizzare la programmazione orientata agli oggetti. Inoltre, con la comparsa dello strategy tester multi-valuta nel client terminal MetaTrader 5, molti trader hanno acquisito strumenti unici per lo sviluppo, l'apprendimento e l'utilizzo di sistemi di trading complessi.
Automated Trading Championship 2010 inizia questo autunno; migliaia di robot di trading scritti in MQL5 vi parteciperanno. Vincerà un Expert Advisor che guadagna il massimo profitto durante la competizione. Ma quale strategia sembrerà la più efficace?
Lo strategy tester del terminale MetaTrader 5 consente di trovare il miglior set di parametri, utilizzando il quale il sistema guadagna la massima quantità di profitto durante un determinato periodo di tempo. Ma può essere fatto in tempo reale? L'idea del trading virtuale utilizzando diverse strategie in un Expert Advisor è stata considerata nell'articolo "Contest di Expert Advisor all’interno di un Expert Advisor" che contiene la sua implementazione in MQL4.
In questo articolo, mostreremo che la creazione e l'analisi di strategie adattive è diventata significativamente più semplice in MQL5 a causa dell'uso della programmazione orientata agli oggetti, classi per lavorare con dati e classi di trading della Libreria Standard.
1. Strategie di Trading Adattive
I mercati cambiano costantemente. Le strategie di trading devono essere aggiornate alle attuali condizioni di mercato.
I valori dei parametri che danno la massima redditività della strategia possono essere trovati senza utilizzare l'ottimizzazione attraverso il cambiamento sequenziale dei parametri e l'analisi dei risultati dei test.
La Figura 1 illustra le curve di equità per dieci Expert Advisor (MA_3,... MA_93); ognuno di essi è stato scambiato secondo la strategia delle medie mobili ma con periodi diversi (3,13,.. 93). Il test è stato eseguito a EURUSD H1, il periodo di test è 4.01.2010-20.08.2010.
Figura 1. Diagrammi delle curve di equità di dieci Expert Advisor sull’account
Come si può vedere nella Figura 1, gli Expert Advisor hanno avuto quasi gli stessi risultati durante le prime due settimane di lavoro, ma ulteriormente i loro profitti hanno iniziato a divergere in modo significativo. Al termine del periodo di test, gli Expert Advisor hanno mostrato i migliori risultati di trading con i periodi 63, 53 e 43.
Il mercato ha scelto i migliori. Perché non dovremmo seguire la sua scelta? Cosa succede se combiniamo tutte e dieci le strategie in un unico Expert Advisor, forniamo la possibilità di trading "virtuale" per ogni strategia e periodicamente (ad esempio, all'inizio di ogni nuova barra) determiniamo la migliore strategia per il trading reale e il trading in base ai suoi segnali?
I risultati della strategia adattiva ottenuta sono mostrati nella Figura 2. La curva di equità dell’account con trading adattivo è mostrata con il colore rosso. Si noti che per più di metà periodo la forma della curva di equità per la strategia adattiva è la stessa di quella della strategia MA_63 che è sembrata essere la vincitrice finale.
Figura 2. Curve di equità sull’account con la strategia adattiva che utilizza i segnali di 10 sistemi di trading
Le curve di saldo hanno dinamiche simili (Fig. 3):
Figura 3. Curve di saldo della strategia adattiva che utilizza i segnali di 10 sistemi di trading
Se nessuna delle strategie è redditizia al momento, i sistemi adattivi non dovrebbero eseguire operazioni di trading. L'esempio di questo caso è mostrato nella fig. 4 (periodo dal 4 al 22 gennaio 2010).
Figura 4. Il periodo di tempo in cui la strategia adattiva ha smesso di aprire nuove posizioni a causa dell'assenza di strategie redditizie
A partire da gennaio 2010, la migliore efficacia è dimostrata dalla strategia MA_3. Poiché la MA_3 (blu) aveva la massima quantità di denaro guadagnata in quel momento, la strategia adattiva (rosso) seguiva i suoi segnali. Nel periodo dall'8 al 20 gennaio tutte le strategie considerate hanno avuto un risultato negativo, ecco perché la strategia adattiva non ha aperto nuove posizioni di trading.
Se tutte le strategie hanno un risultato negativo, è meglio stare lontano dal trading. Questa è la cosa significativa che consente di interrompere il trading non redditizio e di salvare il tuo denaro.
2. Implementazione della Strategia di Trading Adattivo
In questa sezione, considereremo la struttura della strategia adattiva che esegue il trading "virtuale" utilizzando più strategie di trading contemporaneamente e sceglie quella più redditizia per il trading reale in base ai suoi segnali. Si noti che l'uso dell'approccio orientato agli oggetti rende la soluzione di questo problema significativamente più semplice.
Prima di tutto, studieremo il codice dell'Expert Advisor adattivo, quindi daremo uno sguardo dettagliato alla CAdaptiveStrategy in cui è implementata la funzionalità del sistema adattivo, quindi mostreremo la struttura della classe CSampleStrategy - la classe base delle strategie di trading in cui viene implementata la funzionalità del trading virtuale.
Inoltre, considereremo il codice di due dei suoi figli: le classi CStrategyMA e CStrategyStoch che rappresentano le strategie di trading delle medie mobili e dell'oscillatore stocastico. Dopo aver analizzato la loro struttura, sarai in grado di scrivere e aggiungere facilmente le tue classi che realizzano le tue strategie.
2.1. Codice dell'Expert Advisor
Il codice dell'Expert Advisor sembra molto semplice:
//+------------------------------------------------------------------+ //| Adaptive_Expert_Sample.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #include <CAdaptiveStrategy.mqh> CAdaptiveStrategy Adaptive_Expert; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(Adaptive_Expert.Expert_OnInit()); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Adaptive_Expert.Expert_OnDeInit(reason); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { Adaptive_Expert.Expert_OnTick(); } //+------------------------------------------------------------------+
Le prime tre righe definiscono le proprietà del programma,, poi c’è la direttiva #include che dice al preprocessore di includere il file CAdaptiveStrategy.mqh. Le parentesi angolari specificano che il file deve essere preso dalla directory standard (in genere, è terminal_folder\MQL5\Include).
La riga successiva contiene la dichiarazione dell'oggetto Adaptive_Expert (istanza della classe CAdaptiveStrategy); e il codice delle funzioni OnInit, OnDeinit e OnTick dell'Expert Advisor è costituito dalle chiamate delle funzioni corrispondenti Expert_OnInit, Expert_OnDeInit e Expert_OnTick e l'oggetto Adaptive_Expert.
2.2. Classe CAdaptiveStrategy
La classe di thr adaptive Expert Advisor (classe CAdaptiveStrategy) si trova nel file CAdaptiveStrategy.mqh. Iniziamo con i file di inclusione:
#include <Arrays\ArrayObj.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\Trade.mqh> #include <CStrategyMA.mqh> #include <CStrategyStoch.mqh>
Il motivo per cui includiamo il file ArrayObj.mqh è la comodità di lavorare con classi di strategie diverse utilizzando l'oggetto della classe CArrayObj, che rappresenta un array dinamico di puntatori alle istanze di classe generate dalla classe base CObject e dai suoi figli. Questo oggetto sarà l'array m_all_strategies , verrà utilizzato un "contenitore" di strategie di trading.
Ogni strategia è rappresentata come una classe. In questo caso, abbiamo incluso i file che contengono le classi CStrategyMA e CStrategyStoch che rappresentano le strategie di trading con medie mobili e trading da parte dell'oscillatore stocastico.
Per richiedere le proprietà delle posizioni correnti e per eseguire operazioni di trading, utilizzeremo le classi CPositionInfo e CTrade della libreria Standard: ecco perché includiamo i file PositionInfo.mqh e Trade.mqh.
Diamo un'occhiata alla struttura della classe CAdaptiveStrategy.
//+------------------------------------------------------------------+ //| Class CAdaptiveStrategy | //+------------------------------------------------------------------+ class CAdaptiveStrategy { protected: CArrayObj *m_all_strategies; // objects of trade strategies void ProceedSignalReal(int state,double trade_volume); int RealPositionDirection(); public: // initialization of the adaptive strategy int Expert_OnInit(); // deinitialization of the adaptive strategy int Expert_OnDeInit(const int reason); // check of trade conditions and opening of virtual positions void Expert_OnTick(); };
Per implementare un approccio unito agli oggetti di classi diverse, le strategie di trading (o meglio le istanze delle loro classi) sono memorizzate nell'array dinamico m_all_strategies (del tipo CArrayObj) che viene utilizzato come "contenitore" di classi delle strategie. Questo è il motivo per cui la classe di strategie di trading SampleStrategy viene generata dalla classe CObject.
La funzione ProceedSignalReal implementa la "sincronizzazione" della direzione e del volume di una posizione reale con la direzione e il volume dati:
//+------------------------------------------------------------------+ //| This method is intended for "synchronization" of current | //| real trade position with the value of the 'state' state | //+------------------------------------------------------------------+ void CAdaptiveStrategy::ProceedSignalReal(int state,double trade_volume) { CPositionInfo posinfo; CTrade trade; bool buy_opened=false; bool sell_opened=false; if(posinfo.Select(_Symbol)) // if there are open positions { if(posinfo.Type()==POSITION_TYPE_BUY) buy_opened=true; // a buy position is opened if(posinfo.Type()==POSITION_TYPE_SELL) sell_opened=true; // a sell position is opened // if state = 0, then we need to close open positions if((state==POSITION_NEUTRAL) && (buy_opened || sell_opened)) { if(!trade.PositionClose(_Symbol,200)) Print(trade.ResultRetcodeDescription()); } //reverse: closing buy position and opening sell position if((state==POSITION_SHORT) && (buy_opened)) { if(!trade.PositionClose(_Symbol,200)) Print(trade.ResultRetcodeDescription()); if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0)) Print(trade.ResultRetcodeDescription()); } //reverse: close sell position and open buy position if(((state==POSITION_LONG) && (sell_opened))) { if(!trade.PositionClose(_Symbol,200)) Print(trade.ResultRetcodeDescription()); if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,trade_volume,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0)) Print(trade.ResultRetcodeDescription()); } } else // if there are no open positions { // open a buy position if(state==POSITION_LONG) { if(!trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,0.1,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0)) Print(trade.ResultRetcodeDescription()); } // open a sell position if(state==POSITION_SHORT) { if(!trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,0.1,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0)) Print(trade.ResultRetcodeDescription()); } } }
Si noti che è più facile lavorare con la posizione di trading utilizzando le classi di trading. Abbiamo utilizzato gli oggetti delle classi CPositionInfo e CTrade per richiedere, rispettivamente, le proprietà della posizione di mercato e per eseguire operazioni di trading.
La funzione RealPositionDirection richiede i parametri della posizione aperta reale e ne restituisce la direzione:
//+------------------------------------------------------------------+ //| Returns direction (0,+1,-1) of the current real position | //+------------------------------------------------------------------+ int CAdaptiveStrategy::RealPositionDirection() { int direction=POSITION_NEUTRAL; CPositionInfo posinfo; if(posinfo.Select(_Symbol)) // if there are open positions { if(posinfo.Type()==POSITION_TYPE_BUY) direction=POSITION_LONG; // a buy position is opened if(posinfo.Type()==POSITION_TYPE_SELL) direction=POSITION_SHORT; // a short position is opened } return(direction); }
A questo punto, daremo un'occhiata alle principali funzioni della classe СAdaptiveStrategy.
Iniziamo con la funzione Expert_OnInit:
//+------------------------------------------------------------------+ //| Function of initialization of the Adaptive Expert Advisor | //+------------------------------------------------------------------+ int CAdaptiveStrategy::Expert_OnInit() { //--- Create array of objects m_all_strategies //--- we will put our object with strategies in it m_all_strategies=new CArrayObj; if(m_all_strategies==NULL) { Print("Error of creation of the object m_all_strategies"); return(-1); } // create 10 trading strategies CStrategyMA (trading by moving averages) // initialize them, set parameters // and add to the m_all_strategies container for(int i=0; i<10; i++) { CStrategyMA *t_StrategyMA; t_StrategyMA=new CStrategyMA; if(t_StrategyMA==NULL) { delete m_all_strategies; Print("Error of creation of object of the CStrategyMA type"); return(-1); } //set period for each strategy int period=3+i*10; // initialize strategy t_StrategyMA.Initialization(period,true); // set details of the strategy t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period)); //t_StrategyMA.Set_Stops(3500,1000); //add the object of the strategy to the array of objects m_all_strategies m_all_strategies.Add(t_StrategyMA); } for(int i=0; i<m_all_strategies.Total(); i++) { CSampleStrategy *t_SampleStrategy; t_SampleStrategy=m_all_strategies.At(i); Print(i," Strategy name:",t_SampleStrategy.StrategyName(), " Strategy ID:",t_SampleStrategy.StrategyID(), " Virtual trading:",t_SampleStrategy.IsVirtualTradeAllowed()); } //--- return(0); }
L'insieme delle strategie di trading è preparato nella funzione Expert_OnInit. Prima di tutto, viene creato l'oggetto dell'array dinamico m_all_strategies.
In questo caso, sono stati creati dieci istanze della classe CStrategyMA. Ognuno di essi è stato inizializzato (in questo caso, abbiamo impostato periodi diversi e consentito il trading "virtuale") utilizzando la funzione di Inizializzazione.
Quindi, utilizzando la funzione SetStrategyInfo, impostiamo lo strumento finanziario, il nome della strategia e il commento.
Se necessario, utilizzando la funzione Set_Stops(TP,SL) possiamo specificare un valore (in punti) di Take Profit e Stop Loss che verrà eseguito durante il trading "virtuale". Abbiamo commentato questa linea.
Una volta creata e regolata la classe di strategia, la aggiungiamo al contenitore m_all_strategies.
Tutte le classi di strategie di trading dovrebbero avere la funzione CheckTradeConditions() che esegue i controlli delle condizioni di trading. Nella classe della strategia adattiva questa funzione è chiamata all'inizio di ogni nuova barra, quindi diamo alle strategie la possibilità di controllare i valori degli indicatori e di effettuare le operazioni di trading "virtuali".
Invece di dieci medie mobili specificate (3, 13, 23...93), possiamo aggiungere centinaia di medie mobili (istanze se la classe CStrategyMA):
for(int i=0; i<100; i++) { CStrategyMA *t_StrategyMA; t_StrategyMA=new CStrategyMA; if(t_StrategyMA==NULL) { delete m_all_strategies; Print("Error of creation of object of the CStrategyMA type"); return(-1); } //set period for each strategy int period=3+i*10; // initialization of strategy t_StrategyMA.Initialization(period,true); // set details of the strategy t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period)); //add the object of the strategy to the array of objects m_all_strategies m_all_strategies.Add(t_StrategyMA); }
Oppure possiamo aggiungere le classi di strategia che funzionano dai segnali dell'oscillatore stocastico (istanze della classe CStrategyStoch):
for(int i=0; i<5; i++) { CStrategyStoch *t_StrategyStoch; t_StrategyStoch=new CStrategyStoch; if(t_StrategyStoch==NULL) { delete m_all_strategies; printf("Error of creation of object of the CStrategyStoch type"); return(-1); } //set period for each strategy int Kperiod=2+i*5; int Dperiod=2+i*5; int Slowing=3+i; // initialization of strategy t_StrategyStoch.Initialization(Kperiod,Dperiod,Slowing,true); // set details of the strategy string s=IntegerToString(Kperiod)+"/"+IntegerToString(Dperiod)+"/"+IntegerToString(Slowing); t_StrategyStoch.SetStrategyInfo(_Symbol,"[Stoch_"+s+"]",100+i," Stochastic "+s); //add the object of the strategy to the array of objects m_all_strategies m_all_strategies.Add(t_StrategyStoch); }
In questo caso, il contenitore include 10 strategie di medie mobili e 5 strategie dell'oscillatore stocastico.
Le istanze di classi di strategie di trading dovrebbero essere figlie della classe CObject e dovrebbero contenere la funzione CheckTradeConditions(). È meglio ereditarli dalla classe CSampleStrategy. Le classi che implementano strategie di trading possono essere diverse e il loro numero non è limitato.
La funzione Expert_OnInit termina con l'elenco delle strategie presenti nel contenitore m_all_strategies. Si noti che tutte le strategie nel contenitore sono considerate come figli della classe CSampleStrategy. Le classi di strategie commerciali CStrategyMA e CStrategyStoch sono anche i suoi figli.
Lo stesso trucco viene utilizzato nella funzione Expert_OnDeInit. Nel contenitore, chiamiamo la funzione SaveVirtualDeals per ogni strategia; memorizza la cronologia delle operazioni virtuali eseguite.
Usiamo il nome della strategia per il nome del file passato come parametro. Quindi reinizializziamo le strategie chiamando la funzione Deinitialization() ed eliminando il contenitore m_all_strategies:
//+------------------------------------------------------------------+ //| Function of deinitialization the adaptive Expert Advisor | //+------------------------------------------------------------------+ int CAdaptiveStrategy::Expert_OnDeInit(const int reason) { // deinitialize all strategies for(int i=0; i<m_all_strategies.Total(); i++) { CSampleStrategy *t_Strategy; t_Strategy=m_all_strategies.At(i); t_Strategy.SaveVirtualDeals(t_Strategy.StrategyName()+"_deals.txt"); t_Strategy.Deinitialization(); } //delete the array of object with strategies delete m_all_strategies; return(0); }
Se non hai bisogno di conoscere le operazioni virtuali eseguite dalle strategie, rimuovi la riga in cui viene chiamato tStrategy.SaveVirtualDeals. Si noti che quando si utilizza lo strategy tester i file vengono salvati nella directory /tester_directory/Files/.
Consideriamo la funzione Expert_OnTick della classe CAdaptiveStrategy che viene chiamata ogni volta che arriva un nuovo tick:
//+------------------------------------------------------------------+ //| Function of processing ticks of the adaptive strategy | //+------------------------------------------------------------------+ void CAdaptiveStrategy::Expert_OnTick() { CSampleStrategy *t_Strategy; // recalculate the information about positions for all strategies for(int i=0; i<m_all_strategies.Total(); i++) { t_Strategy=m_all_strategies.At(i); t_Strategy.UpdatePositionData(); } // the expert advisor should check the conditions of making trade operations only when a new bar comes if(IsNewBar()==false) { return; } // check trading conditions for all strategies for(int i=0; i<m_all_strategies.Total(); i++) { t_Strategy=m_all_strategies.At(i); t_Strategy.CheckTradeConditions(); } //search for the best position //prepare the array performance[] double performance[]; ArrayResize(performance,m_all_strategies.Total()); //request the current effectiveness for each strategy, //each strategy returns it in the Strategyperformance() function for(int i=0; i<m_all_strategies.Total(); i++) { t_Strategy=m_all_strategies.At(i); performance[i]=t_Strategy.StrategyPerformance(); } //find the strategy (or rather its index in the m_all_strategies container) //with maximum value of Strategyperformance() int best_strategy_index=ArrayMaximum(performance,0,WHOLE_ARRAY); //this strategy is - t_Strategy t_Strategy=m_all_strategies.At(best_strategy_index); //request the direction of its current position int best_direction=t_Strategy.PositionDirection(); string s=s+" "+t_Strategy.StrategyName()+" "+DoubleToString(t_Strategy.GetVirtualEquity())+" "+IntegerToString(best_direction); Print(TimeCurrent()," TOTAL=",m_all_strategies.Total(), " BEST IND=",best_strategy_index, " BEST STRATEGY="," ",t_Strategy.StrategyName(), " BEST=",performance[best_strategy_index]," =", " BEST DIRECTION=",best_direction, " Performance=",t_Strategy.StrategyPerformance()); //if the best strategy has a negative result and doesn't have open positions, it's better to stay away from trading if((performance[best_strategy_index]<0) && (RealPositionDirection()==POSITION_NEUTRAL)) {return;} if(best_direction!=RealPositionDirection()) { ProceedSignalReal(best_direction,t_Strategy.GetCurrentLotSize()); } }
Il codice è molto semplice. Ogni strategia, situata nel contenitore, deve essere in grado di ricalcolare il risultato finanziario corrente delle sue posizioni virtuali utilizzando i prezzi correnti. Viene eseguito chiamando la funzione UpdatePositionData(). Qui, ancora una volta, chiamiamo le strategie come eredi della classe CSampleStrategy.
Tutte le operazioni di trading vengono eseguite all'inizio di una nuova barra (la funzione IsNewBar() consente di determinare questo momento e gli altri metodi di controllo della nuova barra). In questo caso, la fine della formazione di una barra significa che tutti i dati della barra precedente (prezzi e valori degli indicatori) non cambieranno più, quindi possono essere analizzati sulla corrispondenza alle condizioni di trading. Diamo a tutte le strategie l'opportunità di eseguire questo controllo e di eseguire le loro operazioni di trading virtuale chiamando la loro funzione CheckTradeConditions.
Ora dovremmo trovare la strategia di maggior successo tra tutte le strategie nell’array m_all_strategies. Per farlo, abbiamo usato l’array Performance[], i valori restituiti dalla funzione StrategyPerformance() di ogni strategia vengono inseriti in esso. La classe base CSampleStrategy contiene questa funzione come differenza tra i valori correnti di Equity e Balance "virtuali".
La ricerca dell'indice della strategia di maggior successo viene eseguita utilizzando la funzione ArrayMaximum. Se la migliore strategia ha un profitto negativo al momento e non ha posizioni aperte reali, allora è meglio non fare trading, questo è il motivo per cui usciamo dalla funzione (vedi sezione 1).
Inoltre, chiediamo la direzione della posizione virtuale di questa strategia (best_direction). Se differisce dalla direzione corrente della posizione reale, la direzione corrente della posizione reale verrà corretta (utilizzando la funzione ProceedSignalReal) in base alla direzione best_direction.
2.3. Classe CSampleStrategy
Le strategie collocate nel contenitore m_all_strategies sono state considerate come gli eredi della classe CSampleStrategy.
Questa classe è la base per le strategie di trading; contiene l'implementazione del trading virtuale. In questo articolo,analizzeremo un caso semplificato di implementazione del trading virtuale, gli swap non vengono presi in considerazione. Le classi di strategie di trading devono essere ereditate dalla classe CSampleStrategy.
Mostriamo la struttura di questa classe.
//+------------------------------------------------------------------+ //| CSampleStrategy.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #include <Object.mqh> #define POSITION_NEUTRAL 0 // no position #define POSITION_LONG 1 // long position #define POSITION_SHORT -1 // short position #define SIGNAL_OPEN_LONG 10 // signal to open a long position #define SIGNAL_OPEN_SHORT -10 // signal to open a short position #define SIGNAL_CLOSE_LONG -1 // signal to close a long position #define SIGNAL_CLOSE_SHORT 1 // signal to close a short position //+------------------------------------------------------------------+ //| Structure for storing the parameters of virtual position | //+------------------------------------------------------------------+ struct virtual_position { string symbol; // symbol int direction; // direction of the virtual position (0-no open position,+1 long,-1 short) double volume; // volume of the position in lots double profit; // current profit of the virtual position on points double stop_loss; // Stop Loss of the virtual position double take_profit; // Take Profit of the virtual position datetime time_open; // date and time of opening the virtual position datetime time_close; // date and time of closing the virtual position double price_open; // open price of the virtual position double price_close; // close price of the virtual position double price_highest; // maximum price during the life of the position double price_lowest; // minimal price during the lift of the position double entry_eff; // effectiveness of entering double exit_eff; // effectiveness of exiting double trade_eff; // effectiveness of deal }; //+------------------------------------------------------------------+ //| Class CSampleStrategy | //+------------------------------------------------------------------+ class CSampleStrategy: public CObject { protected: int m_strategy_id; // Strategy ID string m_strategy_symbol; // Symbol string m_strategy_name; // Strategy name string m_strategy_comment; // Comment MqlTick m_price_last; // Last price MqlRates m_rates[]; // Array for current quotes bool m_virtual_trade_allowed; // Flag of allowing virtual trading int m_current_signal_state; // Current state of strategy double m_current_trade_volume; // Number of lots for trading double m_initial_balance; // Initial balance (set in the constructor, default value is 10000) int m_sl_points; // Stop Loss int m_tp_points; // Take Profit virtual_position m_position; // Virtual position virtual_position m_deals_history[]; // Array of deals int m_virtual_deals_total; // Total number of deals double m_virtual_balance; // "Virtual" balance double m_virtual_equity; // "Virtual" equity double m_virtual_cumulative_profit; // cumulative "virtual" profit double m_virtual_profit; // profit of the current open "virtual" position //checks and closes the virtual position by stop levels if it is necessary bool CheckVirtual_Stops(virtual_position &position); // recalculation of position and balance void RecalcPositionProperties(virtual_position &position); // recalculation of open virtual position in accordance with the current prices void Position_RefreshInfo(virtual_position &position); // open virtual short position void Position_OpenShort(virtual_position &position); // closes virtual short position void Position_CloseShort(virtual_position &position); // opens virtual long position void Position_OpenLong(virtual_position &position); // closes the virtual long position void Position_CloseLong(virtual_position &position); // closes open virtual position void Position_CloseOpenedPosition(virtual_position &position); // adds closed position to the m_deals_history[] array (history of deals) void AddDealToHistory(virtual_position &position); //calculates and returns the recommended volume that will be used in trading virtual double MoneyManagement_CalculateLots(double trade_volume); public: // constructor void CSampleStrategy(); // destructor void ~CSampleStrategy(); //returns the current size of virtual balance double GetVirtualBalance() { return(m_virtual_balance); } //returns the current size of virtual equity double GetVirtualEquity() { return(m_virtual_equity); } //returns the current size of virtual profit of open position double GetVirtualProfit() { return(m_virtual_profit); } //sets Stop Loss and Take Profit in points void Set_Stops(int tp,int sl) {m_tp_points=tp; m_sl_points=sl;}; //sets the current volume in lots void SetLots(double trade_volume) {m_current_trade_volume=trade_volume;}; //returns the current volume in lots double GetCurrentLots() { return(m_current_trade_volume); } // returns strategy name string StrategyName() { return(m_strategy_name); } // returns strategy ID int StrategyID() { return(m_strategy_id); } // returns the comment of strategy string StrategyComment() { return(m_strategy_comment); } // sets the details of strategy (symbol, name and ID of strategy) void SetStrategyInfo(string symbol,string name,int id,string comment); // set the flag of virtual trading (allowed or not) void SetVirtualTradeFlag(bool pFlag) { m_virtual_trade_allowed=pFlag; }; // returns flag of allowing virtual trading bool IsVirtualTradeAllowed() { return(m_virtual_trade_allowed); }; // returns the current state of strategy int GetSignalState(); // sets the current state of strategy (changes virtual position if necessary) void SetSignalState(int state); // changes virtual position in accordance with the current state void ProceedSignalState(virtual_position &position); // sets the value of cumulative "virtual" profit void SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_profit; }; //returns the effectiveness of strategy () double StrategyPerformance(); //updates position data void UpdatePositionData(); //closes open virtual position void CloseVirtualPosition(); //returns the direction of the current virtual position int PositionDirection(); //virtual function of initialization virtual int Initialization() {return(0);}; //virtual function of checking trade conditions virtual bool CheckTradeConditions() {return(false);}; //virtual function of deinitialization virtual int Deinitialization() {return(0);}; //saves virtual deals to a file void SaveVirtualDeals(string file_name); };
Non analizzeremo la sua descrizione dettagliata, ulteriori informazioni possono essere trovate nel file CSampleStrategy.mqh. Lì puoi anche trovare la funzione di controllo della nuova barra - IsNewBar.
3. Classi di Strategie di Trading
Questa sezione è dedicata alla struttura delle classi di strategie di trading utilizzate nell'Expert Advisor adattivo.
3.1. Classe CStrategyMA - Strategia di Trading da Medie Mobili
//+------------------------------------------------------------------+ //| CStrategyMA.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #include <CSampleStrategy.mqh> //+------------------------------------------------------------------+ //| Class CStrategyMA for implementation of virtual trading | //| by the strategy based on moving average | //+------------------------------------------------------------------+ class CStrategyMA : public CSampleStrategy { protected: int m_handle; // handle of the Moving Average (iMA) indicator int m_period; // period of the Moving Average indicator double m_values[]; // array for storing values of the indicator public: // initialization of the strategy int Initialization(int period,bool virtual_trade_flag); // deinitialization of the strategy int Deinitialization(); // checking trading conditions and opening virtual positions bool CheckTradeConditions(); };
La classe CStrategyMA è un figlio della classe CSampleStrategy in cui è implementata l'intera funzionalità del trading virtuale.
La sezione protetta contiene variabili interne che verranno utilizzate nella classe della strategia. Questi sono: m_handle - handle dell'indicatore iMA, m_period - periodo della media mobile, m_values [] - array che verrà utilizzato nella funzione CheckTradeConditionsper ottenere i valori correnti dell'indicatore.
La sezione pubblica contiene tre funzioni che forniscono l'attuazione della strategia di trading.
- Inizializzazione della Funzione. La strategia viene inizializzata qui. Se è necessario creare indicatori, crearli qui.
- Reinizializzazione delle Funzioni. La strategia viene reinizializzata qui. Gli handle degli indicatori vengono rilasciati qui.
- Funzione СheckTradeConditions. Qui, la strategia controlla le condizioni di trading e genera segnali di trading che vengono utilizzati per il trading virtuale. Per eseguire operazioni di trading virtuale, viene chiamata la funzione SetSignalState della classe padre CStrategy; gli viene passato uno dei quattro seguenti segnali commerciali:
- Il segnale per l'apertura di una posizione lunga (SIGNAL_OPEN_LONG)
- Il segnale per l'apertura di una posizione corta (SIGNAL_OPEN_SHORT)
- Il segnale per la chiusura di una posizione lunga (SIGNAL_CLOSE_LONG)
- Il segnale per la chiusura di una posizione corta (SIGNAL_CLOSE_SHORT)
//+------------------------------------------------------------------+ //| Strategy Initialization Method | //+------------------------------------------------------------------+ int CStrategyMA::Initialization(int period,bool virtual_trade_flag) { // set period of the moving average m_period=period; // set specified flag of virtual trading SetVirtualTradeFlag(virtual_trade_flag); //set indexation of arrays like the one of timeseries ArraySetAsSeries(m_rates,true); ArraySetAsSeries(m_values,true); //create handle of the indicator m_handle=iMA(_Symbol,_Period,m_period,0,MODE_EMA,PRICE_CLOSE); if(m_handle<0) { Alert("Error of creation of the MA indicator - error number: ",GetLastError(),"!!"); return(-1); } return(0); } //+------------------------------------------------------------------+ //| Strategy Deinitialization Method | //+------------------------------------------------------------------+ int CStrategyMA::Deinitialization() { Position_CloseOpenedPosition(m_position); IndicatorRelease(m_handle); return(0); }; //+------------------------------------------------------------------+ //| Checking trading conditions and opening virtual positions | //+------------------------------------------------------------------+ bool CStrategyMA::CheckTradeConditions() { RecalcPositionProperties(m_position); double p_close; // get history data of the last three bars if(CopyRates(_Symbol,_Period,0,3,m_rates)<0) { Alert("Error of copying history data - error:",GetLastError(),"!!"); return(false); } // Copy the current price of closing of the previous bar (it is bar 1) p_close=m_rates[1].close; // close price of the previous bar if(CopyBuffer(m_handle,0,0,3,m_values)<0) { Alert("Error of copying buffers of the Moving Average indicator - error number:",GetLastError()); return(false); } // buy condition 1: MA rises bool buy_condition_1=(m_values[0]>m_values[1]) && (m_values[1]>m_values[2]); // buy condition 2: previous price is greater than the MA bool buy_condition_2=(p_close>m_values[1]); // sell condition 1: // MA falls bool sell_condition_1=(m_values[0]<m_values[1]) && (m_values[1]<m_values[2]); // sell condition 2: // previous price is lower than the MA bool sell_condition_2=(p_close<m_values[1]); int new_state=0; if(buy_condition_1 && buy_condition_2) new_state=SIGNAL_OPEN_LONG; if(sell_condition_1 && sell_condition_2) new_state=SIGNAL_OPEN_SHORT; if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition_1 || buy_condition_2)) new_state=SIGNAL_CLOSE_SHORT; if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition_1 || sell_condition_2)) new_state=SIGNAL_CLOSE_LONG; if(GetSignalState()!=new_state) { SetSignalState(new_state); } return(true); };
Il concetto è semplice: sulla base degli stati degli indicatori e dei prezzi, viene determinato il tipo di segnale (new_state), quindi viene richiesto lo stato corrente del trading virtuale (utilizzando la funzione GetSignalState); se non sono gli stessi, viene chiamata la funzione SetSignalState per "correggere" la posizione virtuale.
3.2. Classe CStrategyStoch - la Strategia di Trading di Stochastic
Il codice della classe che esegue il trading sulla base dell'intersezione delle linee principali e del segnale dell'oscillatore iStocastico viene riportato di seguito:
//+------------------------------------------------------------------+ //| CStrategyStoch.mqh | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #include <CSampleStrategy.mqh> //+------------------------------------------------------------------+ //| Class CStrategyStoch for implementation of virtual trading by | //| the strategy of intersection of lines of stochastic oscillator | //+------------------------------------------------------------------+ class CStrategyStoch : public CSampleStrategy { protected: int m_handle; // handle of the Stochastic Oscillator (iStochastic) int m_period_k; // K-period (number of bars for calculations) int m_period_d; // D-period (period of primary smoothing) int m_period_slowing; // final smoothing double m_main_line[]; // array for storing indicator values double m_signal_line[]; // array for storing indicator values public: // initialization of strategy int Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag); // deinitialization of strategy int Deinitialization(); // checking trading conditions and opening virtual positions bool CheckTradeConditions(); }; //+------------------------------------------------------------------+ //| Strategy Initialization Method | //+------------------------------------------------------------------+ int CStrategyStoch::Initialization(int period_k,int period_d,int period_slowing,bool virtual_trade_flag) { // Set period of the oscillator m_period_k=period_k; m_period_d=period_d; m_period_slowing=period_slowing; // set specified flag of the virtual trading SetVirtualTradeFlag(virtual_trade_flag); // set indexation of arrays like the one of timeseries ArraySetAsSeries(m_rates,true); ArraySetAsSeries(m_main_line,true); ArraySetAsSeries(m_signal_line,true); // create handle of the indicator m_handle=iStochastic(_Symbol,_Period,m_period_k,m_period_d,m_period_slowing,MODE_SMA,STO_LOWHIGH); if(m_handle<0) { Alert("Error of creating the Stochastic indicator - error number: ",GetLastError(),"!!"); return(-1); } return(0); } //+------------------------------------------------------------------+ //| Strategy Deinitialization Method | //+------------------------------------------------------------------+ int CStrategyStoch::Deinitialization() { // close all open positions Position_CloseOpenedPosition(m_position); // release handle of the indicator IndicatorRelease(m_handle); return(0); }; //+------------------------------------------------------------------+ //| Checking Trading Conditions and Opening Virtual Positions | //+------------------------------------------------------------------+ bool CStrategyStoch::CheckTradeConditions() { // call the functions of recalculation of position parameters RecalcPositionProperties(m_position); double p_close; // get history data of the last 3 bars if(CopyRates(_Symbol,_Period,0,3,m_rates)<0) { Alert("Error of copying history data - error:",GetLastError(),"!!"); return(false); } // copy the current close price of the previous bar (it is bar 1) p_close=m_rates[1].close; // close price of the previous bar if((CopyBuffer(m_handle,0,0,3,m_main_line)<3) || (CopyBuffer(m_handle,1,0,3,m_signal_line)<3)) { Alert("Error of copying buffers of the Stochastic indicator - error number:",GetLastError()); return(false); } // buy condition: crossing the signal line by the main one from bottom up bool buy_condition=((m_signal_line[2]<m_main_line[2]) && (m_signal_line[1]>m_main_line[1])); // sell condition: crossing the signal line by the main one from top downwards bool sell_condition=((m_signal_line[2]>m_main_line[2]) && (m_signal_line[1]<m_main_line[1])); int new_state=0; if(buy_condition) new_state=SIGNAL_OPEN_LONG; if(sell_condition) new_state=SIGNAL_OPEN_SHORT; if((GetSignalState()==SIGNAL_OPEN_SHORT) && (buy_condition)) new_state=SIGNAL_CLOSE_SHORT; if((GetSignalState()==SIGNAL_OPEN_LONG) && (sell_condition)) new_state=SIGNAL_CLOSE_LONG; if(GetSignalState()!=new_state) { SetSignalState(new_state); } return(true); };
Come vedi, le uniche differenze tra la struttura della classe CStrategyStoch e quella di CStrategyMA sono la funzione di inizializzazione (parametri diversi), il tipo di indicatore utilizzato e i segnali di trading.
Pertanto, per utilizzare le strategie nell'Expert Advisor adattivo, è necessario riscriverle sotto forma di classi di tale tipo e caricarle nel contenitore m_all_strategies.
4. Risultati dell'Analisi delle Strategie di Trading Adattive
In questa sezione, discuteremo diversi aspetti dell'uso pratico delle strategie adattive e dei metodi per migliorarle.
4.1. Migliorare il Sistema con Strategie che Utilizzano Segnali Inversi
Le Medie Mobili non sono buone quando non ci sono tendenze. Abbiamo già incontrato questo tipo di situazione - nella figura 3, puoi vedere che non c'è stata alcuna tendenza nel periodo dall'8 al 20 gennaio; quindi tutte e 10 le strategie che utilizzano medie mobili nel trading hanno avuto una perdita virtuale. Il sistema adattivo ha smesso di fare trading a causa dell'assenza di una strategia con una quantità positiva di denaro guadagnato. Esiste un modo per evitare questo effetto negativo?
Aggiungiamo alle nostre 10 strategie (MA_3, MA_13, ... MA_93) altre 10 classi CStrategyMAinv i cui segnali di trading sono invertiti (le condizioni sono le stesse ma SIGNAL_OPEN_LONG / SIGNAL_OPEN_SHORT e SIGNAL_CLOSE_LONG / SIGNAL_CLOSE_SHORT si sono scambiati i loro posti). Pertanto, oltre a dieci strategie di tendenza (istanze della classe CStrategyMA), abbiamo altre dieci strategie di controtendenza (istanze della classe CStrategyMAinv).
Il risultato dell'utilizzo del sistema adattivo, che è composto di venti strategie, è mostrato nella figura 5.
Figura 5. Diagrammi di equità nell’account della strategia adattiva che utilizza 20 segnali di trading: 10 medie mobili CAdaptiveMA e 10CAdaptiveMAinv "speculari".
Come si può vedere nella figura 5, durante il periodo in cui tutte le strategie CAdaptiveMA hanno avuto un risultato negativo, seguire le strategie CAdaptiveMAinv ha permesso all'Expert Advisor di evitare drawdown indesiderati proprio all'inizio del trading.
Figura 6. Periodo di tempo in cui la strategia adattiva ha utilizzato i segnali delle strategie di "controtendenza"CAdaptiveMAinv
Questo tipo di approccio può sembrare inaccettabile, dal momento in cui perdere il deposito è solo una questione di tempo quando si utilizza una strategia di controtendenza. Tuttavia, nel nostro caso, non siamo limitati da un'unica strategia. Il mercato sa meglio quali strategie sono efficaci al momento.
Il punto forte dei sistemi adattivi è che il mercato suggerisce da solo quale strategia utilizzare e quando utilizzarla.
Dà la possibilità di astrarre dalla logica delle strategie: se una strategia è efficace, il modo in cui funziona non ha alcun significato. L'approccio adattivo utilizza l'unico criterio di successo di una strategia: la sua efficacia.
4.2. Vale la Pena Invertire i Segnali della Peggiore Strategia?
Il trucco con inversione mostrato sopra porta a pensare alla potenziale possibilità di utilizzare i segnali della peggiore strategia. Se una strategia non è redditizia (e la peggiore), allora possiamo ottenere un profitto agendo al contrario?
Possiamo trasformare una strategia in perdita in una redditizia con un semplice cambiamento dei suoi segnali? Per rispondere a questa domanda, è necessario modificare ArrayMaximum con ArrayMinimum nella funzione Expert_OnTick() della classe CAdaptiveStrategy, nonché implementare il cambiamento di direzione moltiplicando il valore della variabile BestDirection per -1.
Inoltre, dobbiamo commentare la limitazione del trading virtuale in caso di efficacia negativa (poiché analizzeremo il risultato della peggiore strategia):
//if((Performance[BestStrategyIndex]<0) && (RealPositionDirection()==0)) {return;}
Il diagramma di equità dell'Expert Advisor adattivo che utilizza i segnali invertiti della peggiore strategia è mostrato nella figura 7:
Figure 7. Diagrammi di equità negli account con dieci strategie e il sistema adattivo che utilizza i segnali invertiti del sistema peggiore
In questo caso, la strategia meno efficace per la maggior parte del tempo è stata quella basata sull'intersezione delle medie mobili con il periodo 3 (MA_3). Come si può vedere nella figura 7, la correlazione inversa tra MA_3 (di colore blu) e la strategia adattiva (di colore rosso) esiste, ma il risultato finanziario del sistema adattivo non colpisce.
Copiare (e invertire) i segnali della peggiore strategia non porta a migliorare l'efficacia del trading.
4.2. Perché il Gruppo di Medie Mobili non è così Efficace come Sembra?
Invece di 10 medie mobili, puoi usarne molte aggiungendo un altro centinaio di strategie CStrategyMA con periodi diversi al contenitore m_all_strategies.
Per farlo, modifica leggermente il codice nella classe CAdaptiveStrategy:
for(int i=0; i<100; i++) { CStrategyMA *t_StrategyMA; t_StrategyMA=new CStrategyMA; if(t_StrategyMA==NULL) { delete m_all_strategies; Print("Error of creation of object of the CStrategyMA type"); return(-1); } //set period for each strategy int period=3+i*10; // initialization of strategy t_StrategyMA.Initialization(period,true); // set details of the strategy t_StrategyMA.SetStrategyInfo(_Symbol,"[MA_"+IntegerToString(period)+"]",period,"Moving Averages "+IntegerToString(period)); //add the object of the strategy to the array of objects m_all_strategies m_all_strategies.Add(t_StrategyMA); }
Tuttavia, dovresti capire che le medie mobili vicine si intersecheranno inevitabilmente; il leader cambierà costantemente; e il sistema adattivo cambierà i suoi stati e aprirà/chiuderà le posizioni più frequentemente di quanto non sia necessario. Di conseguenza, le caratteristiche del sistema adattivo peggioreranno. Puoi assicurartene da solo confrontando le caratteristiche statistiche del sistema (il tab "Results" dello strategy tester).
È meglio non creare sistemi adattivi basati su molte strategie con parametri vicini.
5. Cosa Dovrebbe Essere Considerato
Il contenitore m_all_strategies può avere migliaia di istanze di strategie suggerite incluse, puoi persino aggiungere tutte le strategie con parametri diversi; tuttavia, per vincere l’Automated Trading Championship 2010è necessario sviluppare il sistema avanzato di gestione del denaro. Si noti che abbiamo utilizzato il volume di trading pari a 0,1 lotti per i test sui dati storici (e nel codice delle classi) .
5.1 Come Aumentare la Redditività dell'Expert Advisor Adattivo?
La classe CSampleStrategy ha la funzione virtuale MoneyManagement_CalculateLots:
//+------------------------------------------------------------------+ //| The function returns the recommended volume for a strategy | //| Current volume is passed to it as a parameter | //| Volume can be set depending on: | //| current m_virtual_balance and m_virtual_equity | //| current statistics of deals (located in m_deals_history) | //| or any other thing you want | //| If a strategy doesn't require change of volume | //| you can return the passed value of volume: return(trade_volume);| //+------------------------------------------------------------------+ double CSampleStrategy::MoneyManagement_CalculateLots(double trade_volume) { //return what we've got return(trade_volume); }
Per gestire il volume per il trading, puoi utilizzare le informazioni statistiche sui risultati e le caratteristiche delle operazioni virtuali registrate nell’array m_deals_history[].
Se hai bisogno di aumentare il volume (ad esempio, raddoppiarlo se le ultime operazioni virtuali in m_deals_history[] sono redditizie; o diminuirlo), dovresti modificare il valore restituito nel modo corrispondente.
5.2 Utilizzo delle Statistiche sulle Operazioni per il Calcolo della Performance della Strategia
La funzione StrategyPerformance(), implementata nella classe CSampleStrategy, è destinata al calcolo delle prestazioni della strategia.
//+-----------------------------------------------------------------------+ //| Function StrategyPerformance - the function of strategy effectiveness | //+-----------------------------------------------------------------------+ double CSampleStrategy::StrategyPerformance() { //returns effectiveness of a strategy //in this case it's the difference between the amount //of equity at the moment and the initial balance, //i.e. the amount of assets earned by the strategy double performance=(m_virtual_equity-m_initial_balance); return(performance); }
La formula di efficacia di una strategia può essere più complessa e, ad esempio, includere l'efficacia in entrata, uscita, l'efficacia nelle operazioni, profitti, drawdown, ecc.
Il calcolo dell'efficacia in entrata, in uscita e dell'efficacia delle operazioni (i campi entry_eff, exit_eff e trade_eff delle strutture dell'array m_deals_history[]) viene eseguito automaticamente durante il trading virtuale (vedi la classe CSampeStrategy). Queste informazioni statistiche possono essere utilizzate per rendere i propri tassi più complessi dell'efficacia della strategia.
Ad esempio, come caratteristiche di efficacia è possibile utilizzare il profitto delle ultime tre operazioni (utilizzare il campo pos_Profit dall'archivio delle operazioni m_deals_history []):
double CSampleStrategy::StrategyPerformance() { //if there are deals, multiply this value by the result of three last deals if(m_virtual_deals_total>0) { int avdeals=MathRound(MathMin(3,m_virtual_deals_total)); double sumprofit=0; for(int j=0; j<avdeals; j++) { sumprofit+=m_deals_history[m_virtual_deals_total-1-j].profit; } double performance=sumprofit/avdeals; } return(performance); }
Se vuoi cambiare questa funzione, cambiala solo nella classe CSampleStrategy, deve essere la stessa per tutte le strategie di trading del sistema adattivo. Tuttavia, dovresti ricordare che la differenza tra Equity e Balance è anche un buon fattore di efficacia.
5.3 Utilizzo di Take Profit e Stop Loss
È possibile modificare l'efficacia dei sistemi di trading impostando livelli di stop fissi (puoi fare ciò chiamando la funzione Set_Stops; consente di impostare i livelli di stop in punti per il trading virtuale). Se i livelli sono specificati, la chiusura delle posizioni virtuali verrà eseguita automaticamente; questa funzionalità è implementata nella classe CSampleStrategy.
Nel nostro esempio (vedi 2.2, la funzione delle classi di medie mobili), viene commentata la funzione di impostazione dei livelli di stop.
5.4. Azzeramento Periodico del Profitto Virtuale Cumulativo
L'approccio adattivo ha lo stesso svantaggio delle strategie comuni. Se la strategia principale inizia a perdere, anche il sistema adattivo inizia a perdere. Questo è il motivo per cui a volte è necessario "azzerare" i risultati del lavoro di tutte le strategie e chiudere tutte le loro posizioni virtuali.
A tale riguardo, nella classe CSampleStrategy sono implementate le seguenti funzioni:
// sets a value for cumulative "virtual profit" void SetVirtualCumulativeProfit(double cumulative_profit) { m_virtual_cumulative_profit=cumulative_perofit; }; //closes an open virtual position void CloseVirtualPosition();
CheckPoint di questo tipo può essere utilizzato di volta in volta, ad esempio dopo ogni N barre.
5.5. Nessun miracolo
Dovresti ricordare che il sistema adattivo non è un graal (USDJPY H1, 4.01.2010-20.08.2010):
Figura 8. Curve di saldo e di equità del sistema adattivo che utilizza i segnali della migliore delle 10 strategie (USDJPY H1)
Le curve di equità di tutte le strategie sono mostrate nella figura 9.
Figura 9. Curve di equità sull’account con il sistema adattivo basato su 10 strategie (USDJPY H1)
Se non ci sono strategie redditizie nel sistema adattivo, usarle non è efficace. Usa strategie redditizie.
Dovremmo considerare un'altra cosa importante ed interessante. Presta attenzione al comportamento della strategia adattiva fin dall'inizio del trading:
Figura 10. Curve di equità sull’account con 10 strategie della strategia adattiva
All'inizio, tutte le strategie hanno avuto risultati negativi e la strategia adattiva ha smesso di fare trading; poi ha iniziato a passare da una strategia all'altra che ha avuto un risultato positivo; e poi tutte le strategie sono diventate di nuovo non redditizie.
Tutte le strategie hanno lo stesso saldo all'inizio. E solo dopo un po’ di tempo, l'una o l'altra strategia diventa un leader; quindi si consiglia di impostare una limitazione nella strategia adattiva per evitare il trading alle prime barre. Per fare ciò, integrare la funzione Expert_OnTick della classe CAdaptiveStrategy con una variabile, il cui valore viene aumentato ogni volta che arriva una nuova barra.
All'inizio, fino a quando il mercato non sceglie la strategia migliore, dovresti stare lontano dal trading reale.
Conclusioni
In questo articolo, abbiamo considerato un esempio del sistema adattivo che consiste in molte strategie, ognuna delle quali effettua le proprie operazioni di trading "virtuali". Il trading reale viene eseguito in conformità con i segnali di una strategia più redditizia al momento.
Grazie all'utilizzo dell'approccio orientato agli oggetti, alle classi per lavorare con i dati e alle classi di trading della libreria Standard, l'architettura del sistema sembrava essere semplice e scalabile; ora è puoi creare e analizzare facilmente i sistemi adattivi che includono centinaia di strategie di trading.
P.S. Per l'analisi del comportamento dei sistemi adattivi, viene allegata la versione di debug della classe CSampleStrategy (l'archivio adaptive-systems-mql5-sources-debug-en.zip). La differenza di questa versione è la creazione di file di testo durante il suo funzionamento; contengono i report di sintesi sulle dinamiche di cambiamento del saldo/equità virtuale delle strategie incluse nel sistema.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/143





- App di trading gratuite
- VPS Forex gratuito per 24 ore
- 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