
Systèmes de trading adaptatifs et leur utilisation dans le terminal client MetaTrader 5
Introduction
Des centaines de milliers de traders dans le monde entier utilisent les plateformes de trading développées par MetaQuotes Software Corp. Le facteur clé du succès est la supériorité technologique basée sur l’expérience de nombreuses années et les meilleures solutions logicielles.
Beaucoup de gens ont déjà évalué les nouvelles opportunités qui sont devenues disponibles avec le nouveau langage MQL5. Ses principales caractéristiques sont la haute performance et la possibilité d’utiliser la programmation orientée objet. En plus de cela, avec l’apparition du testeur de stratégie multi-devises dans le terminal client MetaTrader 5, de nombreux traders ont acquis des outils uniques pour développer, apprendre et utiliser des systèmes de trading complexes.
Automated Trading Championship 2010 commence cet automne ; des milliers de robots de trading écrits en MQL5 vont y participer. Le gagnant sera l’Expert Advisor qui gagnera le maximum de bénéfice lors du concours. Mais quelle stratégie apparaîtra la plus efficace ?
Le testeur de stratégie du terminal MetaTrader 5 permet de trouver la meilleure gamme de paramètres de système à utiliser pour gagner le maximum de bénéfice pendant une période de temps spécifiée. Mais peut-on le faire en temps réel ? L’idée du trading virtuel utilisant plusieurs stratégies dans un Expert Advisor a été envisagée dans l’article « Concours d’Expert Advisors dans un Expert Advisor », qui contient sa mise en application dans MQL4.
Dans cet article, nous allons montrer que la création et l’analyse de stratégies adaptatives sont devenues beaucoup plus faciles dans MQL5 en raison de l’utilisation de la programmation orientée objet, des classes pour travailler avec les données et les classes de trading de la Bibliothèque standard.
1. Stratégies de trading adaptatives
Les marchés sont en constante évolution. Les stratégies de trading doivent être adaptées aux conditions actuelles du marché.
Les valeurs des paramètres qui donnent la rentabilité maximale de la stratégie peuvent être trouvées sans utiliser l’optimisation par le changement séquentiel des paramètres et l’analyse des résultats des tests.
La Figure 1 illustre les courbes d’actions de dix Expert Advisors (MA_3,... MA_93) ; chacun d’eux ont tradé selon la stratégie des moyennes mobiles mais avec des périodes différentes (3,13,.. 93). Les tests ont été effectués avec EURUSD H1, la période de test est 4.01.2010-20.08.2010.
Figure 1. Graphiques des courbes d’actions de dix Expert Advisors à terme
Comme vous pouvez le voir sur la figure 1, les Expert Advisors ont eu presque les mêmes résultats au cours des deux premières semaines de travail, mais leurs bénéfices ont commencé à diverger de manière significative. À la fin de la période de test, les meilleurs résultats de trading ont été montrés par les Expert Advisors avec les périodes 63, 53 et 43.
Le marché a choisi les meilleurs. Pourquoi ne devrions-nous pas suivre son choix ? Que se passe-t-il si nous combinons les dix stratégies dans un seul Expert Advisor, fournissons la possibilité de trading « virtuel » pour chaque stratégie et déterminons périodiquement (par exemple, au début de chaque nouvelle barre) la meilleure stratégie pour le trading et le trade réels en fonction de ses signaux ?
Les résultats de la stratégie adaptative obtenue sont présentés à la Figure 2. La courbe des actions du compte avec trading adaptatif est affichée avec la couleur rouge. Notez que pendant plus de la moitié de la période, la forme de la courbe des actions pour la stratégie adaptative est la même que celle de la stratégie MA_63, qui a semblé être la gagnante finalement.
Figure 2. Courbes des actions à terme avec la stratégie adaptative qui utilise les signaux de 10 systèmes de trading
Les courbes d’équilibre ont la même dynamique (Fig. 3) :
Figure 3. Courbes d’équilibre de la stratégie adaptative qui utilise les signaux de 10 systèmes de trading
Si aucune des stratégies n’est rentable pour le moment, les systèmes adaptatifs devraient s’abstenir de trader. L’exemple d’un tel cas est illustré à la fig. 4 (période du 4 au 22 janvier 2010).
Figure 4. La période pendant laquelle la stratégie adaptative a cessé d’ouvrir de nouvelles positions en raison de l’absence de stratégies rentables
À partir de janvier 2010, la meilleure efficacité est démontrée par la stratégie MA_3. Étant donné que la MA_3 (bleu) a eu le gain maximum à ce moment-là, la stratégie adaptative (rouge) a suivi ses signaux. Dans la période du 8 au 20 janvier, toutes les stratégies considérées ont eu un résultat négatif, c’est pourquoi la stratégie adaptative n’a pas ouvert de nouvelles positions de trading.
Si toutes les stratégies ont un résultat négatif, il est préférable de s’abstenir de toutes les opérations de trading. C’est la chose importante vous permettant d’arrêter le trading non rentable et d’économiser votre argent.
2. Mise en œuvre de la stratégie de trading adaptative
Dans cette section, nous allons examiner la structure de la stratégie adaptative qui effectue le trading « virtuel » en utilisant plusieurs stratégies de trading simultanément, et choisit la plus rentable pour le trading réel en fonction de ses signaux. Notez que l’utilisation de l’approche orientée-objet rend la solution de ce problème beaucoup plus facile.
Tout d’abord, nous allons sonder le code de l’Expert Advisor adaptatif, puis nous allons examiner en détail la CAdaptiveStrategy où la fonctionnalité du système adaptatif est implémentée, puis nous montrerons la structure de la classe CSampleStrategy - la classe de base des stratégies de trading où la fonctionnalité du trading virtuel est implémentée.
En outre, nous allons considérer le code de deux de ses enfants - les classes CStrategyMA et CStrategyStoch qui représentent les stratégies de trading par les moyennes mobiles et l’oscillateur stochastique. Après avoir analysé leur structure, vous serez en mesure d’écrire et d’ajouter facilement vos propres classes qui réalisent vos stratégies.
2.1. Code de l’Expert Advisor
Le code de l’Expert Advisor semble très simple :
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Les trois premières lignes définissent les propriétés du programme, suivies de la directive #include qui instruit au préprocesseur d’inclure le fichier CAdaptiveStrategy.mqh. Les crochets spécifient que le fichier doit être extrait du répertoire standard (généralement, il s’agit de terminal_folder\MQL5\Include).
La ligne suivante contient la déclaration de l’objet Adaptive_Expert (instance de la classe CAdaptiveStrategy) ; et le code des fonctions OnInit, OnDeinit et OnTick de l’Expert Advisor qui se compose des appels des fonctions correspondantes Expert_OnInit, Expert_OnDeInit et Expert_OnTick ainsi que de l’objet Adaptive_Expert.
2.2. La classe CAdaptiveStrategy
La classe de l’Expert Advisor adaptif (classe CAdaptiveStrategy) se trouve dans le fichier CAdaptiveStrategy.mqh. Commençons par les fichiers d’inclusion :
#include <Arrays\ArrayObj.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\Trade.mqh> #include <CStrategyMA.mqh> #include <CStrategyStoch.mqh>
La raison pour laquelle nous incluons le fichier ArrayObj.mqh réside dans la facilité de travailler avec des classes de différentes stratégies en utilisant l’objet de la classe CArrayObj, qui représente un tableau dynamique de pointeurs vers les instances de classe engendrées par la classe de base CObject et ses enfants. Cet objet sera le tableau m_all_strategies, il sera utilisé comme un « conteneur » de stratégies de trading.
Chaque stratégie est représentée sous la forme d’une classe. Dans ce cas, nous avons inclus les fichiers qui contiennent les classes CStrategyMA et CStrategyStoch, qui représentent les stratégies de trading par moyennes mobiles et de trading par l’oscillateur stochastique.
Pour demander les propriétés des positions actuelles et pour effectuer des opérations de trading, nous utiliserons les classes CPositionInfo et CTrade de la bibliothèque Standard, c’est pourquoi nous incluons les fichiers PositionInfo.mqh et Trade.mqh.
Jetons un coup d’œil à la structure de la 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(); };
Pour implémenter une approche unie des objets de différentes classes, les stratégies de trading (ou plutôt les instances de leurs classes) sont stockées dans le tableau dynamique m_all_strategies (du type CArrayObj), qui est utilisé comme un « conteneur » de classes des stratégies. C’est la raison pour laquelle la classe de stratégies de trading SampleStrategy est engendrée à partir de la classe CObject.
La fonction ProceedSignalReal implémente la « synchronisation » de la direction et du volume d’une position réelle avec la direction et le volume donnés :
//+------------------------------------------------------------------+ //| 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()); } } }
Notez qu’il est plus facile de travailler avec la position de trade en utilisant les classes de trading. Nous avons utilisé les objets des classes CPositionInfo et CTrade pour demander respectivement les propriétés de la position Market et effectuer des opérations de trading.
La fonction RealPositionDirection demande les paramètres de la position ouverte réelle et retourne sa direction :
//+------------------------------------------------------------------+ //| 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); }
Nous allons maintenant examiner les principales fonctions de la classe СAdaptiveStrategy.
Commençons par la fonction 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’ensemble des stratégies de trading est préparé dans la fonction Expert_OnInit. Tout d’abord, l’objet du tableau dynamique m_all_strategies est créé.
Dans ce cas, nous avons créé dix instances de la classe CStrategyMA. Chacune d’elles a été initialisée (dans ce cas, nous avons défini différentes périodes et autorisé le trading « virtuel ») à l’aide de la fonction Initialisation.
Ensuite, à l’aide de la fonction SetStrategyInfo, nous définissons l’instrument financier, le nom de la stratégie et le commentaire.
Si nécessaire, en utilisant la fonction Set_Stops (TP, SL), nous pouvons spécifier une valeur (en points) de Take Profit et Stop Loss, qui sera exécutée pendant le trading « virtuel ». Nous avons cette ligne en commentaire.
Une fois la classe de stratégie créée et ajustée, nous l’ajoutons au conteneur m_all_strategies.
Toutes les classes de stratégies de trading doivent avoir la fonction CheckTradeConditions() qui effectue les contrôles des conditions de trading. Dans la classe de la stratégie adaptative, cette fonction est appelée au début de chaque nouvelle barre, nous donnons donc aux stratégies la possibilité de vérifier les valeurs des indicateurs et de trader « virtuellement ».
Au lieu de dix moyennes mobiles spécifiées (3, 13, 23...93), nous pouvons ajouter des centaines de moyennes mobiles (exemples de 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); }
Ou nous pouvons ajouter les classes de stratégie qui fonctionnent par les signaux de l’oscillateur stochastique (exemples de la 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); }
Dans ce cas, le conteneur comprend 10 stratégies de moyennes mobiles et 5 stratégies de l’oscillateur stochastique.
Les instances de classes de stratégies de trading doivent être les enfants de la classe CObject et doivent contenir la fonction CheckTradeConditions(). Il est préférable de les hériter de la classe CSampleStrategy. Les classes qui mettent en œuvre des stratégies de trading peuvent être différentes et leur nombre n’est pas limité.
La fonction Expert_OnInit se termine par la liste des stratégies présentes dans le conteneur m_all_strategies. Notez que toutes les stratégies du conteneur sont considérées comme les enfants de la classe CSampleStrategy. Les classes de stratégies de trading CStrategyMA et CStrategyStoch sont aussi ses enfants.
La même astuce est utilisée dans la fonction Expert_OnDeInit. Dans le conteneur, nous appelons la fonction SaveVirtualDeals pour chaque stratégie ; elle stocke l’historique des transactions virtuelles effectuées.
Nous utilisons le nom de stratégie pour le nom de fichier qui est passé comme paramètre. Ensuite, nous dé-initialisons les stratégies en appelant la fonction Deinitialization() et en supprimant le conteneur 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); }
Si vous n’avez pas besoin de connaître les transactions virtuelles effectuées par les stratégies, supprimez la ligne où tStrategy.SaveVirtualDeals est appelé. Notez que lors de l’utilisation du testeur de stratégie, les fichiers sont enregistrés dans le répertoire /tester_directory/Files/.
Considérons la fonction Expert_OnTick de la classe CAdaptiveStrategy qui est appelée chaque fois qu’un nouveau trait fait son apparition :
//+------------------------------------------------------------------+ //| 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()); } }
Le code est très simple. Chaque stratégie, située dans le conteneur doit pouvoir recalculer le résultat financier actuel de ses positions virtuelles en utilisant les prix actuels. Cela se fait en appelant la fonction UpdatePositionData(). Ici, une fois de plus, nous appelons les stratégies en tant qu’héritiers de la classe CSampleStrategy.
Toutes les opérations de trade sont effectuées au début d’une nouvelle barre (la fonction IsNewBar(), ce qui permet de déterminer ce moment ainsi que les autres méthodes de contrôle de la nouvelle barre). Dans ce cas, la fin de la formation d’une barre signifie que toutes les données de la barre précédente (prix et valeurs des indicateurs) ne changeront plus, de sorte qu’elles peuvent être analysées en fonction de la correspondance avec les conditions de trading. À toutes les stratégies, nous donnons la possibilité d’effectuer ce contrôle et de trader virtuellement en appelant leur fonction CheckTradeConditions.
Maintenant, nous devrions trouver la stratégie la plus réussie parmi toutes les stratégies dans le tableau m_all_strategies. Pour ce faire, nous avons utilisé le tableau Performance[]. Les valeurs renvoyées par la fonction StrategyPerformance() de chaque stratégie y ont été placées. La classe de base CSampleStrategy contient cette fonction comme la différence entre les valeurs actuelles des capitaux propres « virtuels » et du solde.
La recherche de l’indice de la stratégie la plus réussie est effectuée à l’aide de la fonction ArrayMaximum. Si la meilleure stratégie a un profit négatif pour le moment et qu’elle n’a pas de vraies positions ouvertes, alors il est préférable de ne pas trader, c’est la raison pour laquelle nous quittons la fonction (voir section 1).
De plus, nous demandons la direction de la position virtuelle de cette stratégie (best_direction). Si elle diffère de la direction actuelle de la position réelle, la direction actuelle de la position réelle sera corrigée (à l’aide de la fonction ProceedSignalReal) en fonction de la direction best_direction.
2.3. Class CSampleStrategy
Les stratégies placées dans le conteneur m_all_strategies ont été considérées comme les héritières de la classe CSampleStrategy.
Cette classe est la base des stratégies de trading ; elle contient la mise en œuvre du trading virtuel. Dans cet article, nous examinerons un cas simplifié de la mise en œuvre de trading virtuel. Les swaps ne sont pas pris en considération. Les classes de stratégies de trading doivent être héritées de la classe CSampleStrategy.
Montrons la structure de cette 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); };
Nous n’analyserons pas sa description détaillée. Des informations supplémentaires peuvent être trouvées dans le fichier CSampleStrategy.mqh. Vous y trouverez également la fonction de vérification de la nouvelle barre - IsNewBar.
3. Catégories de stratégies de trading
Cette section est consacrée à la structure des classes de stratégies de trading utilisées dans l’Expert Advisor adaptatif.
3.1. Classe CStrategyMA - Stratégie de trading par moyennes mobiles
//+------------------------------------------------------------------+ //| 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 est un enfant de la classe CSampleStrategy où toutes les fonctionnalités du trading virtuel sont implémentées.
La section protégée contient des variables internes qui seront utilisées dans la classe de la stratégie. Il s’agit de: m_handle - descripteur de l’indicateur iMA, m_period - période de la moyenne mobile, m_values[] - tableau qui sera utilisé dans la fonction CheckTradeConditions pour obtenir les valeurs actuelles de l’indicateur.
La section publique contient trois fonctions qui assurent la mise en œuvre de la stratégie de trading.
- Initialisation de la fonction. La stratégie est initialisée ici. Si vous devez créer des indicateurs, créez-les ici.
- Dé-initialisation des fonctions. La stratégie est désinitialisée ici. Les descripteurs des indicateurs sont publiés ici.
- Fonction СheckTradeConditions. Ici, la stratégie vérifie les conditions de trading et génère des signaux de trading qui sont utilisés pour le trading virtuel. Pour effectuer des opérations de trading virtuel, la fonction SetSignalState de la classe parente CStrategy est appelée ; l’un des quatre signaux de trade suivants lui est transmis :
- Le signal d’ouverture d’une position longue (SIGNAL_OPEN_LONG)
- Le signal d’ouverture d’une position courte (SIGNAL_OPEN_SHORT)
- Le signal de clôture d’une position longue (SIGNAL_CLOSE_LONG)
- Le signal de clôture d’une position courte (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); };
Le concept est simple - sur la base des états des indicateurs et des prix, le type de signal (new_state) est déterminé, puis l’état actuel du trading virtuel est demandé (à l’aide de la fonction GetSignalState) ; et s’ils ne sont pas les mêmes, la fonction SetSignalState est appelée pour « corriger » la position virtuelle.
3.2. Class CStrategyStoch - la stratégie de trading par Stochastique
Le code de la classe qui effectue le trading en fonction de l’intersection des lignes de base et de signal de l’oscillateur iStochastic est donné ci-dessous :
//+------------------------------------------------------------------+ //| 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); };
Comme vous le voyez, les seules différences entre la structure de la classe CStrategyStoch et celle de CStrategyMA sont la fonction d’initialisation (différents paramètres), le type d’indicateur utilisé et les signaux de trading.
Ainsi, pour utiliser vos stratégies dans l’Expert Advisor adaptatif, vous devez les réécrire sous la forme de classes de ce type et les charger dans le conteneur m_all_strategies.
4. Résultats de l’analyse des stratégies de trading adaptatives
Dans cette section, nous allons discuter de plusieurs aspects de l’utilisation pratique des stratégies adaptatives et des méthodes pour les améliorer.
4.1. Amélioration du système avec des stratégies qui utilisent des signaux inversés
Les moyennes mobiles ne sont pas bonnes lorsqu’il n’y a pas de tendances. Nous avons déjà rencontré ce genre de situation - dans la figure 3, vous pouvez voir qu’il n’y avait pas de tendance dans la période du 8 au 20 janvier. Ainsi, les 10 stratégies qui utilisent des moyennes mobiles dans le trading ont eu une perte virtuelle. Le système adaptatif a cessé de trader en raison de l’absence d’une stratégie avec un montant positif de gain d’argent. Existe-t-il un moyen d’éviter un tel effet négatif ?
Ajoutons à nos 10 stratégies (MA_3, MA_13, ... MA_93) 10 autres classes CStrategyMAinv, dont les signaux de trades sont inversés (les conditions sont les mêmes mais SIGNAL_OPEN_LONG/SIGNAL_OPEN_SHORT et SIGNAL_CLOSE_LONG/SIGNAL_CLOSE_SHORT y sont plutôt tradés). Ainsi, en plus de dix stratégies de tendance (instances de la classe CStrategyMA), nous avons dix autres stratégies de contre-tendance (instances de la classe CStrategyMAinv).
Le résultat de l’utilisation du système adaptatif qui se compose de vingt stratégies est illustré à la Figure 5.
Figure 5. Graphiques des capitaux propres à terme de la stratégie adaptative qui utilise 20 signaux de trades : 10 moyennes mobiles CAdaptiveMA et 10 moyennes « miroirs » CAdaptiveMAinv
Comme vous pouvez le voir sur la figure 5, pendant la période où toutes les stratégies CAdaptiveMA ont eu un résultat négatif, les stratégies CAdaptiveMAinv a permis à l’Expert Advisor d’éviter les encaissements indésirables au tout début du trading.
Figure 6. Période pendant laquelle la stratégie adaptative a utilisé les signaux des stratégies « contre-tendance » CAdaptiveMAinv
Ce type d’approche peut sembler inacceptable, car la perte de dépôt n’est qu’une question de temps lors de l’utilisation d’une stratégie de contre-tendance. Cependant, dans notre cas, nous ne sommes pas limités par une seule stratégie. Le marché sait mieux quelles stratégies sont efficaces en ce moment.
Le côté fort des systèmes adaptatifs est que le marché suggère automatiquement quelle stratégie devrait être utilisée et quand elle devrait être utilisée.
Cela donne la possibilité de faire abstraction de la logique des stratégies - si une stratégie est efficace, alors la façon dont elle fonctionne n’a aucune importance. L’approche adaptative utilise le seul critère de succès d’une stratégie - son efficacité.
4.2. Vaut-il la peine d’inverser les signaux de la pire stratégie ?
L’astuce avec inversion montrée ci-dessus conduit à une réflexion sur la possibilité potentielle d’utiliser les signaux de la pire stratégie. Si une stratégie n’est pas rentable (et la pire), alors pouvons-nous obtenir un profit en l’inversant ?
Peut-on transformer une stratégie perdante en une stratégie rentable par un simple changement de ses signaux ? La réponse à cette question est qu’il nous faudra changer ArrayMaximum avec ArrayMinimum dans la fonction Expert_OnTick() de la classe CAdaptiveStrategy, et procéder tout à la fois à la mise en œuvre du changement de direction en multipliant la valeur de la variable BestDirection par -1.
En outre, nous devons commenter la limitation du trading virtuel en cas d’efficacité négative (puisque nous allons analyser le résultat de la pire stratégie) :
//if((Performance[BestStrategyIndex]<0) && (RealPositionDirection()==0)) {return;}
Le diagramme des capitaux propres de l’Expert Advisor adaptatif qui utilise les signaux inversés de la pire stratégie est illustré dans la figure 7 :
Figure 7. Diagrammes des capitaux propres à terme de dix stratégies et du système adaptatif qui utilise les signaux inversés du pire système
Dans ce cas, la stratégie la moins réussie la plupart du temps était celle basée sur l’intersection des moyennes mobiles avec la période 3 (MA_3). Comme vous pouvez le voir sur la figure 7, la corrélation inverse entre MA_3 (de couleur bleue) et la stratégie adaptative (de couleur rouge) existe, mais le résultat financier du système adaptatif n’impressionne pas.
Copier (et inverser) les signaux de la pire stratégie ne conduit pas à améliorer l’efficacité du trading.
4.2. Pourquoi le paquet de moyennes mobiles n’est-il pas aussi efficace qu’il en a l’air ?
Au lieu de 10 moyennes mobiles, vous pouvez en utiliser beaucoup en ajoutant une centaine de stratégies CStrategyMA avec différentes périodes au conteneur m_all_strategies.
Pour ce faire, modifiez légèrement le code dans la 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); }
Cependant, vous devez comprendre que les moyennes mobiles proches se croiseront inévitablement ; le leader changera constamment ; et le système adaptatif changera d’état et de position ouverte/fermée plus fréquemment que nécessaire. En conséquence, les caractéristiques du système adaptatif s’aggraveront. Vous pouvez vous y assurer vous-même en comparant les caractéristiques statistiques du système (l’onglet « Résultats » du testeur de stratégie).
Il est préférable de ne pas créer de systèmes adaptatifs basés sur de nombreuses stratégies avec des paramètres clos.
5. Ce qui devrait être pris en compte
Le conteneur m_all_strategies peut avoir des milliers d’instances de stratégies suggérées incluses, vous pouvez même ajouter toutes les stratégies avec des paramètres différents ; Cependant, pour gagner le Championnat de trading automatisé de 2010, vous devez développer le système avancé de gestion d’argent. Notez que nous avons utilisé le volume de trading égal à 0,1 lot pour tester les données de l’historique (et dans le code des classes).
5.1 Comment augmenter la rentabilité de l’Expert Advisor adaptif ?
La classe CSampleStrategy possède la fonction virtuelle 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); }
Pour gérer le volume de trading, vous pouvez utiliser les informations statistiques sur les résultats et les caractéristiques des transactions virtuelles enregistrées dans le tableau m_deals_history[].
Si vous devez augmenter le volume (par exemple, le doubler si les dernières transactions virtuelles dans m_deals_history[] sont rentables ; ou le diminuer), vous devez modifier la valeur retournée de la manière correspondante.
5.2 Utilisation des statistiques des transactions pour le calcul de la performance de stratégie
La fonction StrategyPerformance(), implémentée dans la classe CSampleStrategy, est destinée au calcul de la performance de stratégie,
//+-----------------------------------------------------------------------+ //| 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 formule d’efficacité d’une stratégie peut être plus complexe et, par exemple, inclure l’efficacité de l’entrée, de la sortie, l’efficacité des transactions, des profits, des encaissements, etc.
Le calcul de l’efficacité de l’entrée, de la sortie et de l’efficacité des transactions (les champs entry_eff, exit_eff et trade_eff des structures du tableau m_deals_history[]) est effectué automatiquement pendant le trading virtuel (voir la classe CSampeStrategy). Ces informations statistiques peuvent être utilisées pour créer vos propres taux plus complexes d’efficacité de la stratégie.
Par exemple, comme caractéristique d’efficacité, vous pouvez utiliser le bénéfice des trois dernières transactions (utilisez le champ pos_Profit de l’archive des transactions 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); }
Si vous souhaitez modifier cette fonction, modifiez-la uniquement dans la classe CSampleStrategy, elle doit être la même pour toutes les stratégies de trading du système adaptatif. Cependant, vous devez vous rappeler que la différence entre les capitaux propres et le solde est également un bon facteur d’efficacité.
5.3 Utilisation du Take Profit et du Stop Loss
Vous pouvez modifier l’efficacité des systèmes de trading en configurant des niveaux d’arrêt fixes (cela peut être fait en appelant la fonction Set_Stops ; elle permet de configurer les niveaux d’arrêt en points pour le trading virtuel). Si les niveaux sont spécifiés, la fermeture des positions virtuelles sera effectuée automatiquement ; cette fonctionnalité est implémentée dans la classe CSampleStrategy.
Dans notre exemple (voir 2.2, la fonction des classes de moyennes mobiles), il est commenté la fonction de configuration des niveaux d’arrêt.
5.4. Remise à zéro périodique du profit virtuel cumulé
L’approche adaptative présente le même inconvénient que les stratégies communes. Si la stratégie principale commence à perdre, le système adaptatif commence également à perdre. C’est la raison pour laquelle vous devez parfois « réinitialiser » les résultats du travail de toutes les stratégies et fermer toutes leurs positions virtuelles.
Pour ce faire, les fonctions suivantes sont implémentées dans la classe CSampleStrategy :
// 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();
Le point de contrôle de ce type peut être utilisé de temps en temps, par exemple après chaque barre N.
5.5. Pas de miracles
N’oubliez pas que le système adaptatif n’est pas un Graal (USDJPY H1, 4.01.2010-20.08.2010) :
Figure 8. Courbes de solde et de capitaux propres du système adaptatif utilisant les signaux de la meilleure des 10 stratégies (USDJPY H1)
Les courbes des capitaux propres de toutes les stratégies sont illustrées à la figure 9.
Figure 9. Courbes des capitaux propres à terme avec le système adaptatif basé sur 10 stratégies (USDJPY H1)
S’il n’y a pas de stratégies rentables dans le système adaptatif, leur utilisation n’est pas efficace. Utilisez des stratégies rentables.
Nous devrions considérer une autre chose importante et intéressante. Faites attention au comportement de la stratégie adaptative au tout début du trading :
Figure 10. Courbes des capitaux propres à terme avec 10 stratégies de la stratégie adaptative
Au début, toutes les stratégies ont eu des résultats négatifs et la stratégie adaptative a cessé de trader ; puis elle a commencé à passer d’une stratégie à l’autre, ce qui a produit un résultat positif ; et puis toutes les stratégies sont redevenues non rentables.
Toutes les stratégies ont le même équilibre au début. Et ce n’est qu’après un certain temps que l’une ou l’autre stratégie devient un leader ; il est donc recommandé de configurer une limitation dans la stratégie adaptative pour éviter de trader aux premières barres. Pour ce faire, complétez la fonction Expert_OnTick de la classe CAdaptiveStrategy par une variable, dont la valeur est augmentée chaque fois qu’une nouvelle barre arrive.
Au début, jusqu’à ce que le marché choisisse la meilleure stratégie, vous devez vous abstenir du trading réel.
Conclusions
Dans cet article, nous avons examiné un exemple du système adaptatif qui se compose de nombreuses stratégies, chacune faisant ses propres opérations de trading « virtuelles ». Le trading réel est effectué en fonction de signaux de la plus rentable stratégie du moment.
Grâce à l’utilisation de l’approche orientée objet, des classes pour travailler avec les données et des classes de trading de la bibliothèque Standard, l’architecture du système semblait simple et évolutive ; maintenant vous pouvez facilement créer et analyser les systèmes adaptatifs qui incluent des centaines de stratégies de trading.
P.S. Pour l’analyse pratique du comportement des systèmes adaptatifs, vous trouverez ci-jointe la version de débogage de la classe CSampleStrategy (l’archive adaptive-systems-mql5-sources-debug-en.zip). La différence de cette version est la création de fichiers texte pendant son fonctionnement ; ils contiennent les rapports de synthèse sur la dynamique du changement des capitaux propres/solde virtuels des stratégies intégrées dans le système.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/143





- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation
Un nouvel article Systèmes de trading adaptatifs et leur utilisation dans le terminal client MetaTrader 5 a été publié :
Auteur : MetaQuotes