English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Comment créer votre propre Trailing Stop

Comment créer votre propre Trailing Stop

MetaTrader 5Indicateurs | 22 décembre 2021, 16:40
923 0
Dmitry Fedoseev
Dmitry Fedoseev

Introduction

Avant de commencer avec le sujet de l'article, je pense que c'est une bonne idée de mettre les points sur les i. Encore une fois, nous définissons les termes « position » et « ordre » :

  • Position - est une action de trade, c'est à dire le nombre de contrats achetés ou vendus d'un instrument financier. Il ne peut y avoir qu'une seule position par instrument.
  • Ordre - est une instruction donnée à un courtier d'acheter ou de vendre un instrument financier. Il existe plusieurs types d'ordres : Market et en attente, ainsi que les ordres stop (Stop Loss et Take Profit).

Figure 1. Positions et ordres.

Figure 1. Positions et ordres

Cet article se concentre sur le niveau de Stop Loss final des positions. Pour les ordres en attente, cette opération n'a pas de sens, car vous pouvez passer directement au prix de l’ordre. Et quand il se met en position (ou sa partie), alors ce matériel devient pratique.

La position de trade ne peut se fermer qu’en appuyant sur le bouton « Fermer » dans la boîte de dialogue de position (Figure 2).

Figure 2. Fermeture d'une position à l'aide du bouton « Fermer » dans la boîte de dialogue de position.

Figure 2. Fermeture d'une position à l'aide du bouton « Fermer » dans la boîte de dialogue de position. 1 - ouvrir le menu contextuel de la position, 2 - sélectionner « Fermer la position » 
3 - cliquer sur le bouton « Fermer ».

De plus, la position peut être fermée automatiquement lorsque le prix atteint un niveau de bénéfice (Take Profit) ou de perte (Stop Loss) prédéterminé. Contrairement à la position de clôture à l'aide du bouton « Fermer », la clôture par Stop Loss et Take Profit se fait non pas depuis le terminal (par le trader ou l'expert), mais par le courtier. Ainsi, la position de fermeture est entièrement garantie, indépendamment de la connexion et de l'alimentation énergétique. Cela fait de l'utilisation du Stop Loss un élément pratiquement obligatoire dans le travail du trader.

La seule action que le trader doit faire est de donner un ordre au courtier pour définir le niveau du stop de protection. En d'autres termes, vous devez définir un Stop Loss sur la position (ou position ouverte avec ce niveau configuré). La configuration du Stop Loss se fait à l'aide de la commande du menu contextuel « Modifier » dans le terminal. Dans la liste des positions, sélectionnez un poste, faites un clic droit et choisissez « Modifier ou Supprimer ». Ensuite, dans la boîte de dialogue de position, vous devez entrer le niveau de Stop Loss nécessaire et cliquer sur « Modifier » (Figure 3).

Figure 3. Configuration du niveau de Stop Loss de la position.

Figure 3. Configuration du niveau de Stop Loss de la position. 1 - ouvrir le menu contextuel de la position, 2 - cliquer sur « Modifier ou Supprimer », 3 - Configurer la valeur, 4 - cliquer sur « Modifier ». 

Le niveau de la position Stop Loss est indiqué sur le graphique des prix avec le niveau de son ouverture (Figure 4).

Figure 4. Position avec Stop Loss. Le niveau est marqué d'une ligne pointillée rouge étiquetée avec sl à son bord gauche.

Figure 4. Position avec Stop Loss. Le niveau est marqué d'une ligne pointillée rouge étiquetée avec sl à son bord gauche.

Vous pouvez non seulement installer Stop Loss pour la position, mais aussi modifier périodiquement sa valeur. Par exemple, vous pouvez le tirer vers le haut lorsque le prix change en direction de la rentabilité, réduisant ainsi la perte potentielle. Une telle pulsion du niveau de protection est connue sous le nom de trailing stop.

Il existe de nombreuses variantes de trailing stop : vous pouvez simplement tirer le Stop Loss suite au cours à une distance donnée. Vous pouvez commencer à déplacer le Stop Loss non immédiatement, mais lorsque la position atteint une certaine rentabilité, il est immédiatement déplacé vers le seuil de rentabilité. Cette variante est standard et est intégrée au terminal client MetaTrader 5. Utilisation de la position standard du clic droit sur trailing stop pour choisir « Trailing Stop » (Figure 5).

Figure 5. Activation du trailing stop standard dans le terminal.

Figure 5. Activation du trailing stop standard dans le terminal. 1 - ouvrir le menu contextuel de la position, 2 - cliquer sur « Trailing Stop », 3 - sélectionner la valeur (ou configurez la valeur).
La commande de configuration de la valeur (Personnalisé)
est au bas du menu contextuel et n'est pas affichée sur l'image.

En plus du suivi direct des prix, le trailing stop peut fonctionner sur la base d'un indicateur technique. Par exemple, basé sur des moyennes mobiles, cela permet de ne pas réagir aux variations de prix à court terme, basé sur l'indicateur Ichimoku ou plus approprié ; et même sur l'indicateur Parabolic SAR (Stop et Reverse) qui n'est pas initialement conçu à cet effet. Voir Figure 6.  

Figure 6. Indicateur SAR parabolique.

Figure 6. Indicateur SAR parabolique. 

Dans la programmation procédurale de MQL4, un trailing stop a généralement été créé en tant que fonction distincte ou a été intégré à d'autres fonctions. Par exemple, dans l'expert MACD Sample, inclus dans MetaTrader 4, la fonction trailing stop est intégrée à la fonction de clôture des ordres sur le marché :

for(cnt=0;cnt<total;cnt++)
  {
   OrderSelect(cnt,SELECT_BY_POS,MODE_TRADES);
   if(OrderType()<=OP_SELL &&         // check for opened position 
      OrderSymbol()==Symbol())        // check for symbol
     {
      if(OrderType()==OP_BUY)         // long position is opened
        {
         // should it be closed?
         if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
            MacdCurrent>(MACDCloseLevel*Point))
           {
            OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position
            return(0); // exit
           }
         // check for trailing stop
         if(TrailingStop>0) 
           {
             
            if(Bid-OrderOpenPrice()>Point*TrailingStop)
              {
               if(OrderStopLoss()<Bid-Point*TrailingStop)
                 {
                  OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                  return(0);
                 }
              }
           }
        }
      else // go to short position
        {
         // should it be closed?
         if(MacdCurrent<0 && MacdCurrent>SignalCurrent && 
            MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point))
           {
            OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // close position
            return(0); // exit
           }
         // check for trailing stop
         if(TrailingStop>0) 
           {
             
            if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
              {
               if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
                 {
                  OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                  return(0);
                 }
              }
           }
        }
     }
  }

MQL5 en tant que langage orienté objet offre beaucoup plus de possibilités dans la conception d'experts. Il vous permet de créer des classes polyvalentes et multifonctionnelles qui peuvent ensuite être rapidement et facilement intégrées à presque tous les experts. Dans cet article, nous allons développer une telle classe.


1. Création d'une classe de base trailing stop

Comme mentionné ci-dessus, il existe un grand nombre de trailing stops, mais ils ont tous des aspects fonctionnels communs :

  • Détermination du type (direction) de position
  • Détermination du niveau actuel de Stop Loss de position
  • Calcul du nouveau niveau de Stop Loss
  • Vérification de la nécessité de modifier le niveau actuel du Stop Loss
  • Modification niveau Stop Loss de position

Le type de trailing stop déterminera uniquement la valeur du niveau de Stop Loss calculé. Ainsi, la fonctionnalité de base du trailing stop sera incluse dans la classe de base. En matière fonctionnelle, dépendant du type de trailing stop, il sera créé des sous-classes. L'application aux méthodes de ces sous-classes se fera via les méthodes virtuelles de la classe de base.

Étant donné que nous prévoyons d'utiliser des indicateurs techniques, pour assurer leur fonctionnement stable, il est nécessaire de leur fournir un dispositif périodique. À cette fin, nous utiliserons le minuteur. Nous prévoyons également d'activer/désactiver le trailing stop (lors de l'utilisation de la classe dans le cadre d'un système de trading mécanique) et de l'activer/désactiver à l'aide d'un objet graphique - bouton (lors de l'utilisation de la classe dans le cadre d'experts auxiliaires). Selon ces exigences fonctionnelles, la classe de base aura l'ensemble de méthodes suivant :

class CTrailingStop
  {
protected:
public:
   void CTrailingStop(){};
   void ~CTrailingStop(){};
   void Init(){};                   // Initialization of class
   bool StartTimer(){};             // Start timer
   void StopTimer(){};              // Stop timer
   void On(){};                     // Turn on trailing stop
   void Off(){};                    // Turn off trailing stop
   bool DoStoploss(){};             // Main method of controlling level of Stop Loss position
   void EventHandle(){};            // Method of processing chart events (pressing button to turn on trailing stop)
   void Deinit(){};                 // Deinitialization
   virtual bool Refresh(){};        // Refresh indicator
   virtual void Setparameters(){};  // Setting parameters and loading indicator
   virtual int Trend(){};           // Trend shown by indicator
   virtual double BuyStoploss(){};  // Stop Loss value for the Buy position
   virtual double SellStoploss(){}; // Stop Loss value for the Sell position
  };

Lors de l'appel de la méthode Init(), elle accepte les paramètres généraux qui ne dépendent pas du type de trailing stop utilisé. La méthode configurera le mode de trailing stop et préparera des variables avec certains paramètres de marché.

  • StartTimer() - sera utilisé pour démarrer le minuteur, requis pour l'adressage périodique des indicateurs et pour leur maintien forcé dans le cache du terminal.
  • Stoptimer() - sera utilisé pour arrêter le chronomètre à la fin du travail de l'expert.
  • On() - permet d'activer le trailing stop et de configurer le bouton en mode enfoncé (si le bouton est utilisé).
  • Off () - désactivation de trailing stop et configuration du bouton en mode enfoncé (si le bouton est utilisé).
  • DoStoploss () - Méthode principale de contrôle du niveau de la position Stop Loss
  • EventHandle() - utilisé pour le traitement des événements de graphique, en particulier dans la réponse du clic sur le bouton et de l'activation/désactivation de trailing stop, en fonction de la position du bouton.
  • Deinit() - s'exécute lorsque l'expert termine son travail, assure la libération du descripteur de l'indicateur.
  • Refresh() - fournit le rafraîchissement des valeurs des indicateurs. Cette méthode est nécessaire pour déterminer les valeurs actuelles de l'indicateur avant de calculer les valeurs Stop Loss. En outre, cette méthode est utilisée en autonome - elle est appelée périodiquement par le minuteur pour maintenir les indicateurs en état de fonctionnement.
  • SetParameters() - lorsque vous appelez cette méthode, elle accepte les paramètres d'indicateur, l'indicateur est chargé avec les paramètres spécifiés.
  • Trend() - méthode de recherche de tendance, affichée via l’indicateur. Si l'indicateur montre la direction vers le haut, il renvoie la valeur 1, si c’est vers le bas - il renvoie -1.
  • Les méthodes BuyStoploss() et SellStoploss() renverront les nouvelles valeurs de Stop Loss pour les positions d'achat et de vente, calculées via l’indicateur. 

1.1. Méthode Init()

La méthode Init() est la première méthode, appelée après avoir créé une instance de classe. Elle accepte des paramètres généraux, indépendants du type de trailing stop : symbole, période, mode trailing stop (par traits ou par barres), d’attacher ou non l'indicateur au graphique, de créer ou non le bouton. Ensuite, elle accepte les propriétés du bouton : Coordonnée X du bouton, coordonnée Y du bouton, couleur du bouton, couleur de la légende du bouton.

Les paramètres, nécessaires à la poursuite du travail, sont stockés dans des variables de classe. De plus, lorsque la méthode Init() fonctionne, elle détermine les principaux paramètres de marché immuables, requis pour le trailing stop : le nombre de chiffres après la virgule et la valeur du point. Enfin, selon le type de trailing stop, le nom du bouton et son libellé sont formés. Il est créé s'il est configuré pour utiliser un bouton. 

Dans la section « protégé », déclarons toutes les variables nécessaires :

protected:
string m_symbol;             // symbol
ENUM_TIMEFRAMES m_timeframe; // timeframe
bool m_eachtick;             // work on each tick
bool m_indicator;            // show indicator on chart
bool m_button;               // show "turn on/turn off" button
int m_button_x;              // x coordinate of button
int m_button_y;              // y coordinate of button
color m_bgcolor;             // button color
color m_txtcolor;            // button caption color
int m_shift;                 // bar shift
bool m_onoff;                // turned on/turned off
int m_handle;                // indicator handle
datetime m_lasttime;         // time of trailing stop last execution
MqlTradeRequest m_request;   // trade request structure
MqlTradeResult m_result;     // structure of trade request result
int m_digits;                // number of digits after comma for price
double m_point;              // value of point
string m_objname;            // button name
string m_typename;           // name of trailing stop type
string m_caption;            // button caption

Écrivons maintenant la méthode Init() elle-même :

//--- Trailing stop initialization method
void Init(string             symbol,
          ENUM_TIMEFRAMES timeframe,
          bool   eachtick  =   true,
          bool   indicator =  false,
          bool   button    =  false,
          int    button_x  =      5,
          int    button_y  =     15,
          color  bgcolor   = Silver,
          color  txtcolor  =   Blue)
  {
//--- set parameters
   m_symbol    = symbol;    // symbol
   m_timeframe = timeframe; // timeframe
   m_eachtick  = eachtick;  // true - work on each tick, false - false - work once per bar 
//--- set bar, from which indicator value is used
   if(eachtick)
     {
      m_shift=0; // created bar in per tick mode
     }
   else
     {
      m_shift=1; // created bar in per bar mode
     }
   m_indicator = indicator; // true - attach indicator to chart
   m_button    = button;    // true - create button to turn on/turn off trailing stop
   m_button_x  = button_x;  // x coordinate of button
   m_button_y  = button_y;  // y coordinate of button
   m_bgcolor   = bgcolor;   // button color
   m_txtcolor  = txtcolor;  // button caption color 
//--- get unchanged market history 
   m_digits=(int)SymbolInfoInteger(m_symbol,SYMBOL_DIGITS); // number of digits after comma for price
   m_point=SymbolInfoDouble(m_symbol,SYMBOL_POINT);         // value of point 
//--- creating button name and button caption
   m_objname="CTrailingStop_"+m_typename+"_"+symbol;        // button name
   m_caption=symbol+" "+m_typename+" Trailing";             // button caption 
//--- filling the trade request structure
   m_request.symbol=m_symbol;                               // preparing trade request structure, setting symbol
   m_request.action=TRADE_ACTION_SLTP;                      // preparing trade request structure, setting type of trade action
//--- creating button
   if(m_button)
     {
      ObjectCreate(0,m_objname,OBJ_BUTTON,0,0,0);                 // creating
      ObjectSetInteger(0,m_objname,OBJPROP_XDISTANCE,m_button_x); // setting x coordinate
      ObjectSetInteger(0,m_objname,OBJPROP_YDISTANCE,m_button_y); // setting y coordinate
      ObjectSetInteger(0,m_objname,OBJPROP_BGCOLOR,m_bgcolor);    // setting background color
      ObjectSetInteger(0,m_objname,OBJPROP_COLOR,m_txtcolor);     // setting caption color
      ObjectSetInteger(0,m_objname,OBJPROP_XSIZE,120);            // setting width
      ObjectSetInteger(0,m_objname,OBJPROP_YSIZE,15);             // setting height
      ObjectSetInteger(0,m_objname,OBJPROP_FONTSIZE,7);           // setting font size
      ObjectSetString(0,m_objname,OBJPROP_TEXT,m_caption);        // setting button caption 
      ObjectSetInteger(0,m_objname,OBJPROP_STATE,false);          // setting button state, turned off by default
      ObjectSetInteger(0,m_objname,OBJPROP_SELECTABLE,false);     // user can't select and move button, only click it
      ChartRedraw();                                              // chart redraw 
     }
//--- setting state of trailing stop
   m_onoff=false;                                                 // state of trailing stop - turned on/turned off, turned off by default 
  };

Vous pouvez voir que lors de la création du nom et de la légende du bouton, la variable m_typename est utilisée, elle n'a été initialisée avec aucune valeur. L'attribution d'une valeur se fera dans les constructeurs de la sous-classe. Ainsi, lorsque vous utilisez différentes méthodes de trailing stop, il aura une valeur différente, correspondant au type de trailing stop utilisé. 

1.2. Méthode StartTimer()

La méthode StartTimer() démarre le minuteur standard de l'expert.  

//--- Start timer
bool StartTimer()
  {
   return(EventSetTimer(1));
  };

Lorsque vous utilisez le minuteur, vous devez ajouter l'appel de la méthode Refresh () dans la fonction OnTimer() pour que l'indicateur soit périodiquement actualisé.

1.3. Méthode StopTimer()

La méthode StartTimer() arrête le minuteur d'un expert.  

//--- Stop timer
void StopTimer()
  {
   EventKillTimer();
  };

Lorsque l'expert termine son travail, cette méthode arrête le minuteur, si vous l'avez utilisé. Cette méthode sera appelée lors de l'exécution de la méthode Deinit() d'une classe.  

1.4. Méthode On()

La méthode On() active trailing stop. L'activation se fait en assignant à la variable m_onoff la valeur true. Si le bouton est configuré pour être utilisé dans l'initialisation de la classe, il est alors enfoncé. 

//--- Turn on trailing stop
void On()
  {
   m_onoff=true; 
   if(m_button)
     { // if button is used, it is "pressed"
      if(!ObjectGetInteger(0,m_objname,OBJPROP_STATE))
        {
         ObjectSetInteger(0,m_objname,OBJPROP_STATE,true);
        }
     }
  }

1.5. Méthode Off()

La méthode Off() désactive trailing stop. La désactivation se fait en assignant à la variable m_onoff la valeur false. Si le bouton est configuré pour être utilisé dans l'initialisation de la classe, il est alors enfoncé. 

//--- Turn off trailing stop
void Off()
  {
   m_onoff=false;
   if(m_button)
     { // if button is used, it is "depressed"
      if(ObjectGetInteger(0,m_objname,OBJPROP_STATE))
        {
         ObjectSetInteger(0,m_objname,OBJPROP_STATE,false);
        }
     }
  }

1.6. Méthode EventHandle()

La méthode EventHandle() sera appelée à partir de la fonction OnChartEvent() et, par conséquent, elle acceptera tous les paramètres transmis à la fonction OnChartEvent().

//--- Method of tracking button state - turned on/turned off
void EventHandle(const int id,const long  &lparam,const double &dparam,const string &sparam)
  {
   if(id==CHARTEVENT_OBJECT_CLICK && sparam==m_objname)
     { // there is an event with button
      if(ObjectGetInteger(0,m_objname,OBJPROP_STATE))
        { // check button state
         On(); // turn on
        }
      else
        {
         Off(); // turn off
        }
     }
  }

Si l'événement CHARTEVENT_OBJECT_CLICK se produit et que cet événement se produit avec un bouton qui a le nom m_objname (le nom de l'objet, avec lequel l'événement s'est produit, est transmis vers la variable sparam), alors selon l'état du bouton soit la méthode On() soit Off() est exécutée.

1.7. Méthode Deinit()

La méthode Deinit() doit être appelée lorsque l'expert termine son travail. Cette méthode arrête le minuteur, libère le descripteur de l'indicateur et supprime le bouton, s'il a été utilisé. 

//--- Method of deinitialization
void Deinit()
  {
   StopTimer();                  // stop timer
   IndicatorRelease(m_handle);   // release indicator handle
   if(m_button)
     {
      ObjectDelete(0,m_objname); // delete button
      ChartRedraw();             // chart redraw
     }
  }

Les méthodes virtuelles Refresh(), SetParameters(), Trend(), BuyStoploss() et SellStoploss() seront discutées plus tard - lorsque nous créerons des sous-classes trailing stop. Considérons maintenant la méthode principale de la classe de base - la méthode DoStoploss().

1.8. Méthode DoStoploss()

La méthode DoStoploss() est la principale méthode de travail, qui doit être appelée depuis la fonction OnTick() à chaque trait. Si la valeur de la variable m_onoff est false (trailing stop désactivé), alors la méthode termine immédiatement son travail.  

if(!m_onoff)
  {
   return(true);// if trailing stop is turned off
  }

De plus, si trailing stop fonctionne en mode par barre, l'heure est cochée - en comparant l'heure de la barre créée avec l'heure de la dernière exécution réussie de la fonction. Si le temps correspond, alors la méthode termine son travail.

datetime tm[1];
// get the time of last bar in per bar mode 
if(!m_eachtick)
  { 
   // if unable to copy time, finish method, repeat on next tick 
   if(CopyTime(m_symbol,m_timeframe,0,1,tm)==-1)
     {
      return(false); 
     }
   // if the bar time is equal to time of method's last execution - finish method
   if(tm[0]==m_lasttime)
     { 
      return(true);
     }
  }

Si trailing stop est activé et que le contrôle de l'heure a été une réussite, alors la partie principale de la méthode est exécutée - les valeurs des indicateurs sont actualisées (la méthode Refresh() est appelée).

if(!Refresh())
  { // get indicator values
   return(false);
  }

Ensuite, en fonction de la valeur renvoyée par la méthode Trend(), le trailing stop pour la position d'achat ou de vente est exécuté.

// depending on trend, shown by indicator, do various actions
switch (Trend())
  {
   // Up trend
   case 1: 
      // code of trailing stop for the buy position
      break;
   // Down trend
   case -1: 
      // code of trailing stop for the sell position
      break;
  }

Considérez son travail sur base de l'exemple de la position d'achat.

if(PositionSelect(m_symbol,1000))
  {   //--- select position. if succeeded, then position exists
   if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
     {//--- if position is buy

      //--- get Stop Loss value for the buy position
      sl=BuyStoploss(); 
      //--- find out allowed level of Stop Loss placement for the buy position
      double minimal=SymbolInfoDouble(m_symbol,SYMBOL_BID)-m_point*SymbolInfoInteger(m_symbol,SYMBOL_TRADE_STOPS_LEVEL);
      //--- value normalizing
      sl=NormalizeDouble(sl,m_digits); 
      //--- value normalizing
      minimal=NormalizeDouble(minimal,m_digits); 
      //--- if unable to place Stop Loss on level, obtained from indicator, 
      //    this Stop Loss will be placed on closest possible level
      sl=MathMin(sl,minimal); 
      //--- value of Stop Loss position
      double possl=PositionGetDouble(POSITION_SL); 
      //--- value normalizing
      possl=NormalizeDouble(possl,m_digits); 
      if(sl>possl)
        {//--- if new value of Stop Loss if bigger than current value of Stop Loss, 
         //    an attempt to move Stop Loss on a new level will be made
         //--- filling request structure
         m_request.sl=sl; 
         //--- filling request structure
         m_request.tp=PositionGetDouble(POSITION_TP); 
         //--- request
         OrderSend(m_request,m_result); 
         if(m_result.retcode!=TRADE_RETCODE_DONE)
           {//--- check request result
            //--- log error message
            printf("Unable to move Stop Loss of position %s, error #%I64u",m_symbol,m_result.retcode); 
            //--- unable to move Stop Loss, finishing
            return(false); 
           }
        }
     }
  }

Si la position peut être sélectionnée, son type est coché. Si le type de position correspond à la tendance, alors, en utilisant la méthode BuyStoploss(), nous obtenons la valeur requise de Stop Loss (dans la variable sl). Ensuite, déterminez le niveau autorisé sur lequel le Stop Loss peut être configuré. Si le niveau calculé est plus proche que permis, ajustez la valeur de la variable sl. Ensuite, nous obtenons la valeur actuelle de la position Stop Loss (dans la variable possl) et comparons les valeurs des variables sl et possl. Si la nouvelle valeur de Stop Loss est meilleure que la valeur actuelle, modifiez la position.

Avant modification, remplissez les champs sl and tp de la structure MqlTradeRequest. La variable m_request.sl est affectée avec la valeur requise de Stop Loss, la variable m_request.tp - avec la valeur existante de Take Profit (laissez-la inchangée). Les autres champs sont remplis lorsque la méthode Init() est exécutée. Après avoir rempli la structure, la fonction OrderSend() est appelée.

À la fin de son travail, la valeur de la variable m_result.retcode est cochée. Si la valeur n'est pas égale à TRADE_RETCODE_DONE, alors, pour une raison quelconque, il n'a pas pu effectuer l'action demandée par la fonction OrderSend(). Dans le même temps, un message de journal avec le nombre d'erreurs et l'achèvement de la méthode est exécuté. Lorsque la fonction OrderSend() est terminée avec succès, veuillez vous souvenir de l'heure de la barre sur laquelle le dernier travail de la méthode DoStoploss() a été effectué. En cas d'erreur, même en mode par barre, au prochain trait, il sera effectué un autre essai de la méthode. Ces essais se poursuivront jusqu’à ce que son travail réalisera un plein succès.

Vous trouverez ci-dessous le code complet de la méthode DoStopLoss().

bool DoStoploss()
  {
//--- if trailing stop is turned off
   if(!m_onoff)
     {
      return(true);
     }
   datetime tm[1];
//--- get the time of last bar in per bar mode
   if(!m_eachtick)
     {
      //--- if unable to copy time, finish method, repeat on next tick 
      if(CopyTime(m_symbol,m_timeframe,0,1,tm)==-1)
        {
         return(false);
        }
      //--- if the bar time is equal to time of method's last execution - finish method
      if(tm[0]==m_lasttime)
        {
         return(true);
        }
     }
//--- get indicator values
   if(!Refresh())
     {
      return(false);
     }
   double sl;
//--- depending on trend, shown by indicator, do various actions
   switch(Trend())
     {
      //--- Up trend
      case 1:
         //--- select position. if succeeded, then position exists
         if(PositionSelect(m_symbol))
           {
            //--- if position is buy
            if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
              {
               //--- get Stop Loss value for the buy position
               sl=BuyStoploss();
               //--- find out allowed level of Stop Loss placement for the buy position
               double minimal=SymbolInfoDouble(m_symbol,SYMBOL_BID)-m_point*SymbolInfoInteger(m_symbol,SYMBOL_TRADE_STOPS_LEVEL);
               //--- value normalizing
               sl=NormalizeDouble(sl,m_digits);
               //--- value normalizing
               minimal=NormalizeDouble(minimal,m_digits);
               //--- if unable to place Stop Loss on level, obtained from indicator, 
               //    this Stop Loss will be placed on closest possible level
               sl=MathMin(sl,minimal);
               //--- value of Stop Loss position
               double possl=PositionGetDouble(POSITION_SL);
               //--- value normalizing
               possl=NormalizeDouble(possl,m_digits);
               //--- if new value of Stop Loss if bigger than current value of Stop Loss, 
               //    an attempt to move Stop Loss on a new level will be made
               if(sl>possl)
                 {
                  //--- filling request structure
                  m_request.sl=sl;
                  //--- filling request structure
                  m_request.tp=PositionGetDouble(POSITION_TP);
                  //--- request
                  OrderSend(m_request,m_result);
                  //--- check request result
                  if(m_result.retcode!=TRADE_RETCODE_DONE)
                    {
                     //--- log error message
                     printf("Unable to move Stop Loss of position %s, error #%I64u",m_symbol,m_result.retcode);
                     //--- unable to move Stop Loss, finishing
                     return(false);
                    }
                 }
              }
           }
         break;
         //--- Down trend
      case -1:
         if(PositionSelect(m_symbol))
           {
            if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
              {
               sl=SellStoploss();
               //--- adding spread, since Sell is closing by the Ask price
               sl+=(SymbolInfoDouble(m_symbol,SYMBOL_ASK)-SymbolInfoDouble(m_symbol,SYMBOL_BID));
               double minimal=SymbolInfoDouble(m_symbol,SYMBOL_ASK)+m_point*SymbolInfoInteger(m_symbol,SYMBOL_TRADE_STOPS_LEVEL);
               sl=NormalizeDouble(sl,m_digits);
               minimal=NormalizeDouble(minimal,m_digits);
               sl=MathMax(sl,minimal);
               double possl=PositionGetDouble(POSITION_SL);
               possl=NormalizeDouble(possl,m_digits);
               if(sl<possl || possl==0)
                 {
                  m_request.sl=sl;
                  m_request.tp=PositionGetDouble(POSITION_TP);
                  OrderSend(m_request,m_result);
                  if(m_result.retcode!=TRADE_RETCODE_DONE)
                    {
                     printf("Unable to move Stop Loss of position %s, error #%I64u",m_symbol,m_result.retcode);
                     return(false);
                    }
                 }
              }
           }
         break;
     }
//--- remember the time of method's last execution
   m_lasttime=tm[0];
   return(true);
  }

Notez les différences de code pour les positions d'achat et de vente. Pour la position de vente, la valeur renvoyée par SellStoploss() augmente de la valeur de spread, car la position de vente est fermée par le prix Ask. En conséquence, le compte à rebours du niveau minimal Stop Loss pour l'achat se fait à partir du prix Bid, pour la vente - à partir du prix Ask.

Pour l'instant, nous avons terminé avec la création de la classe de base trailing stop. Procédons à la création de sous-classes. 

2. Sous-classe trailing stop pour indicateur SAR parabolique

Les méthodes virtuelles de la classe CTrailingStop vous indiquent déjà le contenu d'une sous-classe - les méthodes SetParameters(), Refresh(), Trend(), BuyStoploss(), SellStoploss() et le constructeur de classe pour configurer le nom du trailing stop. La classe sera nommée CParabolicStop. Puisque cette classe est une sous-classe de CTrailingStop, cela sera mentionné dans sa déclaration.

class CParabolicStop: public CTrailingStop

Avec cette déclaration, l'appel des méthodes virtuelles de la classe CParabolicStop exécutera les méthodes héritées de la classe de base.  

Considérons en détail toutes les méthodes de sous-classe.

2.1. Méthode CParabolicStop()

Cette méthode a le même nom que la classe elle-même, cette méthode est appelée un constructeur. Il est exécuté automatiquement lors du chargement de la classe, avant toute autre méthode de la classe. Dans la méthode CParabolicStop(), le nom du trailing stop est assigné à la variable m_typename. Cette variable est utilisée pour créer le nom et la légende du bouton (dans la méthode Init() de la classe de base).

void CParabolicStop()
  {
   m_typename="SAR"; // setting name of trailing stop type
  };

2.2. Méthode SetParameters()

Lors de l'appel de la méthode SetParameters(), elle accepte les paramètres d'indicateur et l'indicateur est chargé avec ces paramètres. Si le paramètre m_indicator est configuré sur la méthode Init() de la classe de base, alors l'indicateur est attaché au graphique (fonction ChartIndicatorAdd()).

// Method of setting parameters and loading the indicator
bool SetParameters(double sarstep=0.02,double sarmaximum=0.2)
  {
   m_handle=iSAR(m_symbol,m_timeframe,sarstep,sarmaximum); // loading indicator
   if(m_handle==-1)
     {
      return(false); // if unable to load indicator, method returns false
     }
   if(m_indicator)
     {
      ChartIndicatorAdd(0,0,m_handle); // attach indicator to chart
     }
    
   return(true);
  }

2.3. Méthode Refresh()

La méthode Refresh() fournit un nouveau prix et actualise les valeurs de l’indicateur. Dans la section "protégée" de la classe, il y a le tableau pricebuf pour la valeur du prix et le tableau indbuf - pour les valeurs de l’indicateur. Les deux tableaux ont la taille d'un élément - ne devraient être qu'une valeur de prix et une valeur d'indicateur de la barre de formation ou formée (selon le paramètre m_shift, configuré lors de l'initialisation de la classe de base).

// Method of getting indicator values
bool Refresh()
  {
   if(CopyBuffer(m_handle,0,m_shift,1,indbuf)==-1)
     {
      return(false); // if unable to copy value to array, return false
     }
    
   if(CopyClose(m_symbol,m_timeframe,m_shift,1,pricebuf)==-1)
     {
      return(false); // if unable to copy value to array, return false
     }    
   return(true); 
  }

2.4. Méthode Trend()

La méthode Trend() vérifie l'emplacement du prix par rapport à la ligne de l'indicateur. Si le prix est au-dessus de la ligne, il s'agit de la tendance haussière et la méthode renvoie la valeur 1. Si le prix est inférieur à la ligne de l'indicateur, il s'agit de la tendance baissière et la méthode renvoie la valeur -1. Pas exclu le cas (rare, mais possible), où le prix est égal à la ligne de l’indicateur. Dans ce cas, la valeur 0 sera retournée.  

// Method of finding trend
int Trend()
  {
   if(pricebuf[0]>indbuf[0])
     { // price is higher than indicator line, up trend
      return(1);
     }
   if(pricebuf[0]<indbuf[0])
     { // price is lower than indicator line, down trend
      return(-1);
     }    
   return(0);
  }

2.5. Méthodes BuyStoploss() et SellStoploss()

Étant donné que l'indicateur Parabolic SAR n'a qu'une seule ligne, les deux méthodes sont identiques. Elles renvoient la valeur obtenue à partir de la méthode Refresh().

// Method of finding out Stop Loss level for buy
virtual double BuyStoploss()
  {
   return(indbuf[0]);
  };
// Method of finding out Stop Loss level for sell
virtual double SellStoploss()
  {
   return(indbuf[0]);
  };

Pour l'instant, le trailing stop est prêt. Il n'a encore qu'une classe, mais il peut déjà être utilisé. Enregistrez-le en tant que fichier d'inclusion distinct dans le dossier .\MQL5\Include sous le nom Sample_TrailingStop.mqh (le fichier est joint à l'article). 

3. Ajout de Trailing Stop pour Parabolic dans Expert

Essayons d'ajouter un trailing stop dans certains experts, tels que My_First_EAdu article.

3.1. Ouvrez l'expert My_First_EA dans MetaEditor et enregistrez-le sous My_First_EA_SARTrailing.

3.2. Inclure le fichier trailing stop. Dans la partie supérieure du code expert (de préférence avant déclaration des variables externes) ajouter la ligne : 

#include <Sample_TrailingStop.mqh> // include Trailing Stop class

3.3. Après la création des variables externes, créez une instance de la classe CParabolicStop, nommée Trailing.

CParabolicStop Trailing; // create class instance 

 3.4. Dans la fonction OnInit(), initialisez la classe et configurez ses paramètres. Tout d'abord, déclarez des variables externes avec des paramètres d'indicateur :

input double TrailingSARStep=0.02;
input double TrailingSARMaximum=0.2;

Ajoutez ensuite du code à la fonction OnInit().

Trailing.Init(_Symbol,PERIOD_CURRENT,true,true,false); // Initialize (set basic parameters)
if(!trailing.setparameters(TrailingSARStep,TrailingSARMaximum))
  { // Set parameters of used trailing stop type
   Alert("trailing error");
   return(-1);
  } 
Trailing.StartTimer(); // Start timer
Trailing.On();         // Turn on

3.5. Dans le code expert, trouvez la fonction OnTimer(). La fonction OnTimer() n'est pas utilisée dans My_First_EA, alors ajoutez-la et ajoutez-y l'appel de Refresh(). 

void OnTimer()
  {
   Trailing.Refresh();
  }

3.6. En haut de la fonction OnTick(), ajoutez l'appel de la méthode DoStoploss().

3.7. Compilez l'expert et essayez de le tester. Les résultats des tests de l'expert sont présentés sur la Figure 7 (sans trailing stop) et sur la Figure 8 (avec trailing stop).

Figure 7. Résultats du test de l'Expert sans Trailing Stop.

Figure 7. Résultats du test de l'Expert sans Trailing Stop.   

Figure 8. Résultats du test de l'Expert avec Trailing Stop.

Figure 8. Résultats du test de l'Expert avec Trailing Stop. 

L'efficacité de l'utilisation du trailing stop est évidente.

Le fichier My_First_EA_SARTrailing.mq5 est joint à l'article.

4. Sous-classe de trailing stop pour NRTR

L'indicateur NRTR (Nick Rypock Trailing Reverse) par son nom et son apparence (Figure 9) présente un intérêt pour tenter de créer un trailing stop dessus.

Figure 9. Indicateur NRTR.

Figure 9. Indicateur NRTR.

L'indicateur trace la ligne de base (la ligne de support ou de résistance) et la ligne cible. Lorsque le prix dépasse la ligne cible, la ligne de base est transférée dans le sens du mouvement des prix, les oscillations mineures du prix sont ignorées. Lorsque le prix croise la ligne de base, cela est considéré comme un changement de tendance, modifiant ainsi l'emplacement de la ligne de base et de la ligne cible par rapport au prix. La ligne de support et la ligne cible dans la tendance haussière sont peintes en bleu, dans la tendance baissière - en rouge.

Créez maintenant un trailing stop pour l'indicateur NRTR.

Déclarez une autre classe CNRTRStop incluse dans la classe de base CNRTRStop. 

class CNRTRStop: public CTrailingStop

La sous-classe Trailing Stop pour NRTR aura exactement le même ensemble de méthodes que Trailing Stop pour Parabolic, à l'exception du constructeur - il sera désormais nommé CNRTRStop().  

4.1. Méthode CNRTRStop()

Maintenant, dans le constructeur de classe, la variable m_typename est assignée à la valeur NRTR, en fonction de l'indicateur utilisé.

void CNRTRStop()
  {
   m_typename="NRTR"; // setting name of trailing stop type
  };

4.2. Méthode SetParameters()

Lors de l'appel de la méthode SetParameters(), elle accepte les paramètres d'indicateur et elle est chargée. Ensuite, en fonction des paramètres de base du trailing stop, l'indicateur sera attaché au graphique.

// Method of setting parameters and loading the indicator
bool SetParameters(int period,double k)
  {
   m_handle=iCustom(m_symbol,m_timeframe,"NRTR",period,k); // loading indicator
   if(m_handle==-1)
     { // if unable to load indicator, method returns false
      return(false); 
     }
   if(m_indicator)
     {
       
      ChartIndicatorAdd(0,0,m_handle); // attach indicator to chart
     }
   return(true);
  }

4.3. Méthode Refresh()

La méthode Refresh() copie deux tampons de l'indicateur NRTR - le tampon de ligne de support et le tampon de ligne de résistance.  

 // Method of getting indicator values
bool Refresh()
  {
   if(CopyBuffer(m_handle,0,m_shift,1,sup)==-1)
     {
      return(false); // if unable to copy value to array, return false
     }
    
   if(CopyBuffer(m_handle,1,m_shift,1,res)==-1)
     {
      return(false); // if unable to copy value to array, return false
     }
    
   return(true);
  }

Dans la section « protected » de la classe, il y a deux tableaux déclarés : double sup[] et double res[].

protected:
double sup[1]; // value of support level
double res[1]; // value of resistance level

4.4. Méthode Trend()

La méthode Trend() vérifie laquelle des lignes existe actuellement. S'il s'agit de la ligne de support, cela signifie que l'indicateur montre la tendance haussière. La méthode elle-même renvoie la valeur 1. S'il s'agit de la ligne de résistance, la méthode renvoie -1. 

// Method of finding trend
int Trend()
  {
   if(sup[0]!=0)
     { // there is support line, then it is up trend
      return(1);
     }
   if(res[0]!=0)
     { // there is resistance line, then it is down trend
      return(-1);
     }
    
   return(0);
  }

4.5. Méthode BuyStoploss()

La méthode BuyStoploss() renvoie la valeur de la ligne de support. 

// Method of finding out Stop Loss level for buy
double BuyStoploss()
  {
   return(sup[0]);
  }

4.6. Méthode SellStoploss()

La méthode SellStoploss() renvoie la valeur de la ligne de résistance.  

// Method of finding out Stop Loss level for sell
double SellStoploss()
  {
   return(res[0]);
  }

La classe trailing stop est maintenant terminée. 

5. Ajout de Trailing Stop pour NRTR dans Expert

Tout comme pour le trailing stop Parabolic, ajoutons le trailing stop My_First_EA pour NRTR dans expert.

5.1. Ouvrez l'expert My_First_EA_SARTrailing dans MetaEditor et enregistrez-le sous My_First_EA_NRTRTrailing.

5.2. Remplacez les paramètres externes de trailing stop pour Parabolic par des paramètres de trailing stop pour NRTR.

input int TrailingNRTRPeriod = 40;
input double TrailingNRTRK   =  2;

5.3. Au lieu de créer une instance de la classe CParabolicStop, créez une instance de la classe CNRTRStop. L’emplacement du code vient après les variables externes. 

CNRTRStop Trailing; // create class instance 

5.4. Dans la fonction OnInit(), remplacez les paramètres de l'appel de la méthode SetParameters() par les paramètres NRTR.

Trailing.SetParameters(TrailingNRTRPeriod,TrailingNRTRK)

5.5. Compilez l'expert et essayez de le tester. 

Figure 10. Résultats du test de l'Expert avec Trailing Stop pour NRTR.

Figure 10. Résultats du test de l'expert avec Trailing Stop pour NRTR.

Les résultats de travail de l'Expert Advisor (Figure 10) avec une stratégie trailing stop par rapport au travail d'un expert sans celui-ci (Fig. 7) sont presque inchangés. L'utilisation du trailing stop Parabolic s'est avérée plus efficace pour cet expert. On peut en conclure que l'arsenal d'un certain nombre de trailing stop peut être très utile lors du développement d'experts - pour faire des expériences et sélectionner le type de trailing stop le plus adapté.  

Le fichier My_First_EA_NRTRTrailing.mq5 est joint à l'article.

6. Expert-Assistant

Lorsqu'une classe de base de trailing stop a été créée, elle était destinée à contrôler l'activation/la désactivation du trailing stop via le bouton. Créons un expert-assistant pour suivre les positions sur les différents symboles avec différents types de trailing stop. L'expert n'ouvrira aucune position, mais suivra uniquement les positions ouvertes.

6.1. Dans MetaEditor, créer un nouvel expert nommé Sample_TrailingStop.

6.2. Inclure le fichier Sample_TrailingStop.mqh. 

#include <Sample_TrailingStop.mqh> // include Trailing Stop class

6.3. Déclarer des paramètres externes pour les indicateurs.

input double SARStep=0.02;     // Step of Parabolic
input double SARMaximum=0.02;  // Maximum of Parabolic
input int NRTRPeriod=40;       // NRTR period
input double NRTRK=2;          // NRTR factor

6.4. Déclarer un tableau de symboles, sur lequel l'expert pourra travailler.

string Symbols[]={"EURUSD","GBPUSD","USDCHF","USDJPY"};

6.5. Déclarer des tableaux pour charger des classes.

CParabolicStop *SARTrailing[];
CNRTRStop *NRTRTrailing[];

6.6. Dans la fonction OnInit(), redimensionnez les tableaux pour charger les classes, en fonction de la taille du tableau Symbols. 

ArrayResize(SARTrailing,ArraySize(Symbols));  // resize according to number of used symbols
ArrayResize(NRTRTrailing,ArraySize(Symbols)); // resize according to number of used symbols 

6.7. Dans la loop pour chaque élément de l'instance de classe de chargement de tableau.

for(int i=0;i<ArraySize(Symbols);i++)
  { // for all symbols
   SARTrailing[i]=new CParabolicStop(); // create CParabolicStop class instance
   SARTrailing[i].Init(Symbols[i],PERIOD_CURRENT,false,true,true,5,15+i*17,Silver,Blue);    // initialization of CParabolicStop class instance 
   if(!SARTrailing[i].SetParameters(SARStep,SARMaximum))
     { // setting parameters of CParabolicStop class instance 
      Alert("trailing error");
      return(-1);
     }
   SARTrailing[i].StartTimer();         // start timer
//----
   NRTRTrailing[i]=new CNRTRStop();     // create CNRTRStop class instance
   NRTRTrailing[i].Init(Symbols[i],PERIOD_CURRENT,false,true,true,127,15+i*17,Silver,Blue); // initialization of CNRTRStop class instance
   if(!NRTRTrailing[i].SetParameters(NRTRPeriod,NRTRK))
     { // setting parameters of CNRTRcStop class instance 
      Alert("trailing error");
      return(-1);
     }
   NRTRTrailing[i].StartTimer();        // start timer 
  }

Remarque : lors de l'appel des boutons des méthodes Init(), les coordonnées sont calculées. Sur la gauche, il y aura des boutons d'alimentation de trailing stop pour Parabolic, à droite - pour NRTR.  

6.8. Dans la fonction OnTick(), ajoutez l'appel de la méthode DoStoploss() pour chaque instance de trailing stop.

for(int i=0;i<ArraySize(Symbols);i++)
  {
   SARTrailing[i].DoStoploss();
   NRTRTrailing[i].DoStoploss();
  }

6.9. Ajout de la gestion des événements de graphique. 

void OnChartEvent(const int         id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam 
                  )
  {
   for(int i=0;i<ArraySize(Symbols);i++)
     {
      SARTrailing[i].EventHandle(id,lparam,dparam,sparam);
      NRTRTrailing[i].EventHandle(id,lparam,dparam,sparam);
     }
    
  }

6.10. Dans la fonction Deinit(), désinitialisez toutes les instances de classe pour les supprimer.

for(int i=0;i<ArraySize(Symbols);i++)
  {
   SARTrailing[i].Deinit(); 
   NRTRTrailing[i].Deinit();
   delete(SARTrailing[i]);  // delete object
   delete(NRTRTrailing[i]); // delete object
  }

Compilez, attachez l'expert au graphique. Des indicateurs et des boutons apparaissent sur le graphique (Figure 11) - L’Expert Advisor est prêt à travailler.  

Figure 11. Boutons et indicateurs sur le graphique après le démarrage de Sample_TrailingStop.

Figure 11. Boutons et indicateurs sur le graphique après le démarrage de Sample_TrailingStop. 

Il suffit d'appuyer sur le bouton pour suivre la position correspondante lorsqu'elle est ouverte.

Le fichier Sample_TrailingStop.mq5 est joint à l'article.

Conclusion

Passons en revue l'ordre d'utilisation de la classe CTrailingStop lors de la création d'un système de trading mécanique :

1. Inclure le fichier Sample_TrailingStop.mqh.

2. Déclarer les variables externes avec les paramètres indicateurs trailing stop utilisé.

3. Créer l'instance de classe.

4. Ajout de l'appel des méthodes Init(), SetParameters(), StartTimer() et On() à partir de la fonction OnInit().

5. Ajout de l'appel de la méthode Refresh() depuis la fonction OnTimer().

6. Ajout de l’appel de la méthode DoStopLoss() depuis la fonction OnTick().

7. Ajout de l'appel de la méthode Deinit() depuis la fonction OnDeinit(). 


Sept étapes, moins de 5 minutes, et votre Expert Advisor est équipé d’une fonction de trailing stop !

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/134

Création d'indicateurs multicolores dans MQL5 Création d'indicateurs multicolores dans MQL5
Dans cet article, nous verrons comment créer des indicateurs multicolores ou convertir les indicateurs existants en multicolores. MQL5 permet de représenter les informations sous une forme pratique. Désormais, il n'est plus nécessaire de regarder une douzaine de graphiques avec des indicateurs et d'effectuer des analyses du RSI ou des niveaux stochastiques, il est mieux simplement de peindre les bougies avec des couleurs différentes selon les valeurs des indicateurs.
Le prototype du robot de trading Le prototype du robot de trading
Cet article résume et systématise les principes de création d'algorithmes et d'éléments de systèmes de trading. L'article considère la conception d'algorithmes experts. À titre d'exemple, la classe CExpertAdvisor est considérée, qui peut être utilisée pour le développement rapide et facile de systèmes de trading.
Plusieurs modes de recherche de tendance dans MQL5 Plusieurs modes de recherche de tendance dans MQL5
Tout trader ferait tout ce qui est en son pouvoir pour réussir à détecter avec précision une tendance à un moment donné. C’est peut-être sans doute cela le Saint-Graal que tout le monde recherche. Dans cet article, nous examinerons plusieurs modes de détection de tendance. Pour être plus précis - comment programmer plusieurs modes classiques pour détecter une tendance au moyen de MQL5.
20 signaux de trade en MQL5 20 signaux de trade en MQL5
Cet article vous apprendra comment recevoir les signaux de trade nécessaires au fonctionnement d'un système de trading. Les exemples de formation de 20 signaux de trade sont donnés ici en tant que fonctions personnalisées distinctes qui peuvent être utilisées lors du développement d'Expert Advisors. Pour votre aisance, toutes les fonctions utilisées dans l'article sont regroupées dans un seul fichier d'inclusion mqh qui peut être facilement connecté à un futur Expert Advisor.