English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Systèmes de trading adaptatifs et leur utilisation dans le terminal client MetaTrader 5

Systèmes de trading adaptatifs et leur utilisation dans le terminal client MetaTrader 5

MetaTrader 5Systèmes de trading | 22 décembre 2021, 16:44
243 1
MetaQuotes
MetaQuotes


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

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 prises en compte avec la stratégie adaptative qui utilise les signaux de 10 systèmes de trading

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

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

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 :
  1. Le signal d’ouverture d’une position longue (SIGNAL_OPEN_LONG)
  2. Le signal d’ouverture d’une position courte (SIGNAL_OPEN_SHORT)
  3. Le signal de clôture d’une position longue (SIGNAL_CLOSE_LONG)
  4. 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. Diagrammes des capitaux propres à terme de la stratégie adaptative qui utilise 20 signaux de trades : 10 moyennes mobiles CAdaptiveMA et 10 moyennes « miroirs » CAdaptiveMAinv

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 CAdaptiveMAinv « contre-tendance »

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

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)

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)

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

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

Derniers commentaires | Aller à la discussion (1)
rmy082 jegouzo
rmy082 jegouzo | 7 août 2022 à 23:01
Hello sir I développe different good strategies mt5 multi symbols and with your system adaptatif with containers I should be very interesting if you could work for my on a mission work … do you think if it’s possible to work tou for my please ? Contact my if you are interesting ? Best regards yann
Guide de test et d'optimisation des Expert Advisors en MQL5 Guide de test et d'optimisation des Expert Advisors en MQL5
Cet article explique le processus étape par étape d'identification et de résolution des erreurs de code ainsi que les étapes de test et d'optimisation des paramètres d'entrée de l'Expert Advisor. Vous apprendrez à utiliser le Testeur de stratégie du terminal client MetaTrader 5 pour trouver le meilleur symbole et le meilleur ensemble de paramètres d'entrée pour votre Expert Advisor.
Expert Advisor basé sur les « Nouvelles dimensions en trading » livre écrit par Bill Williams Expert Advisor basé sur les « Nouvelles dimensions en trading » livre écrit par Bill Williams
Dans cet article, je vais discuter du développement de l'Expert Advisor, basé sur le livre intitulé « Nouvelles dimensions en trading : Comment tirer profit du chaos dans les changes, les actions et les matières premières » par Bill Williams. La stratégie elle-même est bien connue et son utilisation est encore controversée parmi les traders. L'article examine les signaux système en trading, les spécificités de sa mise en œuvre et les résultats des tests sur les données historiques.
Ordres, positions et transactions dans MetaTrader 5 Ordres, positions et transactions dans MetaTrader 5
La création d'un robot de trading robuste ne peut se faire sans une compréhension des mécanismes du système de trading MetaTrader 5. Le terminal client reçoit les informations sur les positions, les ordres et les transactions du serveur de trading. Pour gérer correctement ces données en utilisant le MQL5, il est nécessaire d'avoir une bonne compréhension de l'interaction entre le programme MQL5 et le terminal client.
Évaluation des systèmes de trading - l’efficacité d’ouverture, de clôture et de trades en général Évaluation des systèmes de trading - l’efficacité d’ouverture, de clôture et de trades en général
Il existe de nombreuses mesures qui permettent de déterminer l’efficacité et la rentabilité d’un système de trading. Cependant, les traders sont toujours prêts à soumettre n’importe quel système à un nouveau crash test. L’article explique comment les statistiques basées sur des mesures d’efficacité peuvent être utilisées pour la plateforme MetaTrader 5. Il contient la classe pour la transformation de l’interprétation des statistiques par les transactions à celle qui ne contredit pas la description donnée dans le livre de S.V. « Statistika dlya traderov » (« Statistiques destinées aux traders »). Bulashev. Il contient également un exemple de fonction personnalisée pour optimisation.