English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Assistant MQL5 : Exécuter des ordres, des stop-loss et des prises de bénéfices sur les prix calculés. Extension de la bibliothèque standard

Assistant MQL5 : Exécuter des ordres, des stop-loss et des prises de bénéfices sur les prix calculés. Extension de la bibliothèque standard

MetaTrader 5Exemples | 13 janvier 2022, 14:47
470 0
Andrey Shpilev
Andrey Shpilev

Introduction

La bibliothèque standard MQL5 est une aide utile dans le développement de grands projets nécessitant une architecture stricte. L'assistant MQL5 permet d'assembler des parties prêtes à l'emploi dans un schéma étendu en mode dialogue en quelques minutes, ce qui ne peut pas être surestimé. L'assistant MQL5 automatise le rassemblement de toutes les parties de l'Expert et déclare automatiquement les paramètres du module dans l'Expert en fonction de leurs descripteurs. Lorsqu'il y a un grand nombre de modules différents impliqués, une telle automatisation permet d'économiser beaucoup de temps et d'opérations de routine.

Cela semble bien, mais il y a un inconvénient évident - les capacités des systèmes de trading créés avec l'assistant basés sur des classes standard sont limitées. Cet article considère une méthode universelle permettant d'étendre de manière significative les fonctionnalités des Experts créés. Lorsque cette méthode est implémentée, la compatibilité avec l'assistant et les modules standards reste la même.

L'idée de la méthode est d'utiliser des mécanismes d'héritage et de polymorphisme en Programmation orientée sur l’objet ou de créer des classes pour substituer des classes standard dans le code des Experts générés. De cette façon, tous les avantages de l'assistant et de la bibliothèque standard sont utilisés, ce qui permet de développer un expert avec les capacités requises. Pour y arriver cependant, le code doit être réduit un peu, seulement de quatre séries.

Le but pratique de cet article est d'ajouter aux Experts générés la possibilité de passer des ordres, des Stop Loss et des Take Profits aux niveaux de prix requis, et pas seulement à la distance spécifiée du prix actuel.

Une idée similaire a été discutée dans l'article «Assistant MQL5 : Comment apprendre à un EA à ouvrir des ordres en attente à n’importe quel prix». L'inconvénient important de la solution suggérée est le changement « forcé » du paramètre du module de signal de trading du filtre subordonné. Cette approche n'encourage pas à travailler avec beaucoup de modules et l'utilisation de l'assistant pour l'optimisation des processus n'a aucun sens.

La mise en œuvre d’exécution des ordres ainsi que des Stop Losses et Take Profits à n'importe quel prix dans des classes héritées des classes standard est examinée en détail plus loin. Cela dit, tout conflit entre modules est impossible. J'espère que cet article servira d'exemple et inspirera les lecteurs à écrire leurs propres améliorations du cadre standard et permettra également aux utilisateurs d'implémenter l'extension Bibliothèque développée.


1. Algorithme standard de prise de décision

Les experts générés dans l'assistant MQL5 sont basés sur l'instance de classe CExpert. Le pointeur vers l'objet de la classe CExpertSignal est déclaré dans cette classe. Plus loin dans l'article, cet objet est appelé le signal principal par souci de concision. Le signal principal contient des pointeurs vers les filtres subordonnés (les modules de signal sont les héritiers de la classe CExpertSignal).

S'il n'y a pas de positions et d'ordres ouverts, l'Expert se réfère au signal principal pour rechercher une opportunité d'ouvrir une position sur un nouveau tick. Le signal principal interroge les filtres subordonnés un par un et calcule la prévision moyenne pondérée (direction) sur la base de la prévision obtenue. Si sa valeur dépasse le seuil (valeur du paramètre m_threshold_open dans le signal principal), les paramètres de commande et les résultats de vérification des conditions de type bool sont transmis à l'Expert. Si ces conditions sont remplies, soit une position sur le prix du marché est ouverte, soit un ordre en attente à une certaine distance de celui-ci (voir Fig. 1). Les Stop Loss ne peuvent être exécutés qu'à une distance fixe. Les indentations de prix d'ouverture, Les Stop Loss et Take Profit du prix du marché sont spécifiés dans les paramètres Expert et stockés dans le signal principal, dans les variables m_price_level, m_stop_level et m_take_level respectivement.

Ainsi, actuellement, deux conditions doivent être remplies pour qu'une commande soit passée :

  1. Aucune position ouverte pour le symbole actuel ;
  2. La valeur absolue de la prévision moyenne pondérée dépasse la valeur seuil, ce qui signifie qu'une tendance est plutôt forte).

Fig. 1. Modèle de prise de décision lors de l'entrée sur le marché

Fig. 1. Modèle de prise de décision lors de l'entrée sur le marché

Le modèle actuel de prise de décision sur la figure 1 limite considérablement le domaine d'application de l'assistant MQL5. Les stratégies avec une valeur fixe de Stop Loss sont rarement efficaces dans le trading à long terme en raison de la volatilité variable. Les systèmes utilisant des ordres en attente nécessitent généralement de les exécuter sur des niveaux calculés dynamiquement.


2. Algorithme modifié de prise de décision

Du point de vue du calcul des niveaux et du placement des ordres, il s'agit d'une situation sans issue car les modules de signaux ne peuvent générer autre chose qu'une valeur prévisionnelle et le signal principal n'a pas été conçu pour fonctionner avec des niveaux. À cet égard, les éléments suivants sont suggérés :

  • Introduire un nouveau type de modules de signaux (nous allons les appeler modules de prix) capables de générer des paramètres d’ordre ;
  • Entraînez le signal principal à gérer ces paramètres, c'est-à-dire sélectionnez les meilleurs et transmettez-les à l'Expert.

L'algorithme modifié (Fig. 2) permet de travailler avec d'autres requêtes en plus des ordres en attente. L'essence de cet algorithme est qu'il sépare le point d'entrée (prix) de la définition d'une tendance (prévision moyenne pondérée). Cela signifie que pour prendre une décision, la direction préférée du trading avec des filtres est définie et un ensemble de paramètres d'ordre avec une direction appropriée obtenue à partir des modules de prix est sélectionné. S'il existe plusieurs ensembles similaires disponibles, l'ensemble reçu du module avec le plus grand poids (la valeur du paramètre m_poids est choisie). Si la direction a été déterminée mais qu'aucun point d'entrée n'est actuellement disponible, l'Expert est inactif.

Fig. 2. Modèle modifié de prise de décision lors de l'entrée sur le marché

Fig. 2. Modèle modifié de prise de décision lors de l'entrée sur le marché

Pour exécuter un nouvel ordre, les conditions suivantes doivent être remplies :

  1. Pas de positions ouvertes et d'ordres pour le symbole actuel ;
  2. La valeur absolue de la prévision moyenne pondérée dépasse la valeur seuil ;
  3. Au moins un prix d'ouverture de l'ordre a été trouvé.

L'algorithme de la figure 2 permet de gérer de nombreux points d'entrée possibles, de les filtrer par direction et de choisir le meilleur dans un Expert.


3. Développement de Classes Modifiées de l'Expert et du Module Signal

L'extension de la Bibliothèque s'articule autour de deux classes : CExpertSignalAdvanced and CExpertAdvanced, hérités de CExpertSignal et CExpert respectivement.

Toutes les mesures sur l'ajout de nouvelles capacités visant à modifier les interfaces utilisées pour l'échange de données entre les différents blocs de l'Expert. Par exemple, pour implémenter l'algorithme par le modèle de la Fig.2, il est nécessaire d'organiser l'interaction du signal principal (classe CExpertSignalAdvanced) avec les modules de prix (descendants de cette classe). La mise à jour des commandes déjà passées lorsque les données changent, implique une interaction de l'Expert (classe CExpertAdvanced) avec le signal principal.

Nous allons donc à ce stade implémenter le schéma de la figure 2 pour ouvrir des positions et organiser la mise à jour des ordres déjà exécutés lorsque les paramètres changent (par exemple, lorsqu'un point d'entrée plus favorable apparaît). Considérons la classe CExpertSignalAdvanced.

3.1. CExpertSignalAdvanced

Cette classe va substituer son ascendant dans le rôle du signal principal et devenir celle de base pour les modules de prix de la même manière que son ascendant est fondamental pour les modules de signaux.

class CExpertSignalAdvanced : public CExpertSignal
  {
protected:
   //---data members for storing parameters of the orders being placed
   double            m_order_open_long;         //opening price of the order to buy
   double            m_order_stop_long;         //Stop Loss of the order to buy
   double            m_order_take_long;         //Take Profit of the order to buy
   datetime          m_order_expiration_long;   //expiry time of the order to buy
   double            m_order_open_short;        //opening price of the order to sell
   double            m_order_stop_short;        //Stop Loss of the order to sell
   double            m_order_take_short;        //Take Profit of the order to sell
   datetime          m_order_expiration_short;  //expiry time of the order to sell
   //---             
   int               m_price_module;            //index of the first price module in the m_filters array
public:
                     CExpertSignalAdvanced();
                    ~CExpertSignalAdvanced();
   virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}
   virtual bool      CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
   virtual double    Direction(void);		//calculating weighted average forecast based on the data received from signal modules
   virtual double    Prices(void);		//updating of parameters of the orders being placed according to the data received from price modules
   virtual bool      OpenLongParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      OpenShortParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   virtual bool      CheckUpdateOrderShort(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   double            getOpenLong()              { return m_order_open_long;         }
   double            getOpenShort()             { return m_order_open_short;        }
   double            getStopLong()              { return m_order_stop_long;         }
   double            getStopShort()             { return m_order_stop_short;        }
   double            getTakeLong()              { return m_order_take_long;         }
   double            getTakeShort()             { return m_order_take_short;        }
   datetime          getExpLong()               { return m_order_expiration_long;   }
   datetime          getExpShort()              { return m_order_expiration_short;  }
   double            getWeight()                { return m_weight;                  }
  };

Les membres de données pour le stockage des paramètres d’ordre ont été déclarés dans la classe CExpertSignalAdvanced. Les valeurs de ces variables sont mises à jour dans la méthode Prix(). Ces variables agissent comme un tampon.

Ensuite, le paramètre m_price_module est déclaré. Il stocke l'indice du premier module de prix dans le tableau m_filters déclaré dans CExpertSignal. Ce tableau contient les pointeurs vers les modules de signaux inclus. Les pointeurs vers les modules standard (filtres) sont stockés au début du tableau. Ensuite, à partir de l'indice m_price_module, viennent les modules de prix. Pour éviter la nécessité de changer les méthodes d'initialisation des indicateurs et des séries temporelles, il a été décidé de tout stocker dans un seul tableau. De plus, il est possible d'inclure 64 modules dans un seul tableau et cela suffit généralement.

De plus, des méthodes d'assistance ont été déclarées dans la classe CExpertSignalAdvanced pour obtenir les valeurs des membres de données protégés. Leurs noms commencent par get (voir la déclaration de classe).

3.1.1. Constructeur

Le constructeur CExpertSignalAdvanced initialise les variables déclarées à l'intérieur de la classe :

CExpertSignalAdvanced::CExpertSignalAdvanced()
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   m_price_module=-1;
  }

3.1.2. CalcPriceModuleIndex()

La méthode CalcPriceModuleIndex() affecte dans m_price_module le nombre actuel d'éléments du tableau, qui est égal à l'index du module ajouté suivant. Cette méthode est appelée avant d'ajouter le premier module de prix. Le corps de la fonction se trouve dans la déclaration de classe.

virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}

3.1.3. CheckOpenLong(...) et CheckOpenShort(...)

La méthode CheckOpenLong(...) est appelée à partir de l'instance de classe CExpert et fonctionne comme décrit ci-dessous :

  1. Vérifiez les modules de prix inclus. S'il n'y en a pas, appelez la méthode éponyme de la classe parente ;
  2. Recevez une prévision moyenne pondérée (direction) de la méthode Direction ();
  3. Vérifiez si les conditions d'entrée sont remplies en comparant la direction avec EMPTY_VALUE et la valeur seuil de m_threshold_open ;
  4. Renouveler les valeurs des paramètres d’ordre par la méthode Prix(), et les transmettre à l'Expert avec la fonction OpenLongParams(...). Enregistrez le résultat de cette fonction ;
  5. Renvoyez le résultat enregistré.
bool CExpertSignalAdvanced::CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration)
  {
//--- if price modules were not found, call the method of the basic class CExpertSignal
   if(m_price_module<0)
      return(CExpertSignal::CheckOpenLong(price,sl,tp,expiration));

   bool   result   =false;
   double direction=Direction();
//--- prohibitive signal
   if(direction==EMPTY_VALUE)
      return(false);
//--- check for exceeding the threshold
   if(direction>=m_threshold_open)
     {
      Prices();
      result=OpenLongParams(price,sl,tp,expiration);//there's a signal if m_order_open_long!=EMPTY_VALUE
     }
//--- return the result
   return(result);
  }

CheckOpenShort(...) a le même principe de fonctionnement et s'utilise de la même manière, c'est pourquoi nous n'allons pas le considérer.

3.1.4 Direction()

La méthode Direction() interroge les filtres et calcule la prévision moyenne pondérée. Cette méthode est très similaire à une méthode éponyme de la classe parent CExpertSignal à l'exception du fait que dans la boucle nous ne faisons pas référence à tous les éléments du tableau m_filters mais uniquement à ceux ayant un indice qui varie de 0 à celui inférieur à m_price_module. Tout le reste est similaire à CExpertSignal::Direction().

double CExpertSignalAdvanced::Direction(void)
  {
   long   mask;
   double direction;
   double result=m_weight*(LongCondition()-ShortCondition());
   int    number=(result==0.0)? 0 : 1;      // number of queried modules
//--- loop by filters
   for(int i=0;i<m_price_module;i++)
     {
      //--- mask for bitmaps (variables, containing flags)
      mask=((long)1)<<i;
      //--- checking for a flag of ignoring a filter signal
      if((m_ignore&mask)!=0)
         continue;
      CExpertSignal *filter=m_filters.At(i);
      //--- checking for a pointer
      if(filter==NULL)
         continue;
      direction=filter.Direction();
      //--- prohibitive signal
      if(direction==EMPTY_VALUE)
         return(EMPTY_VALUE);
      if((m_invert&mask)!=0)
         result-=direction;
      else
         result+=direction;
      number++;
     }
//--- averaging the sum of weighted forecasts
   if(number!=0)
      result/=number;
//--- return the result
   return(result);
  }

3.1.5. Prix()

La méthode Price() itère sur la deuxième partie du tableau m_filters en partant de l'indice m_price_module jusqu'à la fin. Cela interroge les modules de prix et renouvelle les valeurs des variables de classe avec les fonctions OpenLongParams(...) et OpenShortParams(...). Avant le cycle, les valeurs des paramètres sont effacées.

Au cours du cycle, les valeurs des paramètres sont écrasées si le poids du module de prix actuel (m_weight) est supérieur à celui des modules précédemment interrogés, qui ont fourni les valeurs. En conséquence, soit des paramètres vides sont laissés (si rien n'a été trouvé) soit des paramètres avec le meilleur poids disponible au moment de l'appel d'une méthode.

double CExpertSignalAdvanced::Prices(void)
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int    total=m_filters.Total();
   double last_weight_long=0;
   double last_weight_short=0;
//--- cycle for price modules
   for(int i=m_price_module;i<total;i++)
     {   
      CExpertSignalAdvanced *prm=m_filters.At(i);
      if(prm==NULL)
         continue;
//--- ignore the current module if it has returned EMPTY_VALUE
      if(prm.Prices()==EMPTY_VALUE)continue;
      double weight=prm.getWeight();
      if(weight==0.0)continue;
//--- select non-empty values from modules with the greatest weight
      if(weight>last_weight_long && prm.getExpLong()>TimeCurrent())
         if(prm.OpenLongParams(m_order_open_long,m_order_stop_long,m_order_take_long,m_order_expiration_long))
            last_weight_long=weight;
      if(weight>last_weight_short && prm.getExpShort()>TimeCurrent())
         if(prm.OpenShortParams(m_order_open_short,m_order_stop_short,m_order_take_short,m_order_expiration_short))
            last_weight_short=weight;
     }
   return(0);
  }

3.1.6. OpenLongParams(...) et OpenShortParams(...)

À l’intérieur de la classe CExpertSignalAdvanced, la méthode OpenLongParams(...) transmet les valeurs des paramètres de l’ordre d'achat par référence des variables de classe aux paramètres d'entrée.

Le rôle de cette méthode dans la classe parente était légèrement différent. Il s'agissait de calculer les paramètres requis sur la base du prix du marché et des indentations spécifiées dans le signal principal. Maintenant, cela ne transmet que les paramètres prêts. Si le prix d'ouverture est correct (non égal à EMPTY_VALUE), la méthode renvoie vraie, sinon faux.

bool CExpertSignalAdvanced::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration)
  {
   if(m_order_open_long!=EMPTY_VALUE)
     {
      price=m_order_open_long;
      sl=m_order_stop_long;
      tp=m_order_take_long;
      expiration=m_order_expiration_long;
      return(true);
     }
   return(false);
  }

Nous n'allons pas considérer OpenShortParams(...) car son principe de fonctionnement est le même et il est utilisé de manière similaire.

3.1.7. CheckUpdateOrderLong(...) et CheckUpdateOrderShort(...)

Les méthodes CheckUpdateOrderLong(...) et CheckUpdateOrderShort(...) sont appelées la classe CExpertAdvanced. Elles servent à mettre à jour les ordres en attente déjà exécutés en fonction des derniers niveaux de prix.

Nous allons examiner de plus près la méthode CheckUpdateOrderLong(...). Dans un premier temps, les niveaux de prix sont mis à jour lors de l'appel de la méthode Prix(...), puis une vérification des mises à jour des données est effectuée pour exclure d'éventuelles erreurs de modification. Enfin, la méthode OpenLongParams(...) est appelée pour transmettre les données mises à jour et renvoyer le résultat.

bool CExpertSignalAdvanced::CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex)
  {
   Prices();   //update prices
//--- check for changes
   double point=m_symbol.Point();
   if(   MathAbs(order_ptr.PriceOpen() - m_order_open_long)>point
      || MathAbs(order_ptr.StopLoss()  - m_order_stop_long)>point
      || MathAbs(order_ptr.TakeProfit()- m_order_take_long)>point
      || order_ptr.TimeExpiration()!=m_order_expiration_long)
      return(OpenLongParams(open,sl,tp,ex));
//--- update is not required   
   return (false);
  }

CheckUpdateOrderShort (...) ne sera pas prise en compte car elle fonctionne de la même manière et s'applique de la même manière.

3.2. CExpertAdvanced

Les changements dans la classe des Experts concernent uniquement la modification des ordres déjà exécutés en fonction des données mises à jour sur les prix dans le signal principal. La déclaration de classe CExpertAdvanced est présentée ci-dessous.

class CExpertAdvanced : public CExpert
  {
protected:
   virtual bool      CheckTrailingOrderLong();
   virtual bool      CheckTrailingOrderShort();
   virtual bool      UpdateOrder(double price,double sl,double tp,datetime ex);
public:
                     CExpertAdvanced();
                    ~CExpertAdvanced();
  };

Comme on peut le voir, les méthodes sont peu nombreuses, le constructeur et le destructeur sont vides.

3.2.1. CheckTrailingOrderLong() et CheckTrailingOrderShort()

La méthode CheckTrailingOrderLong() neutralise une méthode éponyme de la classe de base et appelle la méthode CheckUpdateOrderLong(...) du signal principal pour comprendre la nécessité de modifier l'ordre. Si une modification est requise, la méthode UpdateOrder(...) est appelée et le résultat est renvoyé.

bool CExpertAdvanced::CheckTrailingOrderLong(void)
  {
   CExpertSignalAdvanced *signal_ptr=m_signal;
//--- check for the opportunity to modify the order to buy
   double price,sl,tp;
   datetime ex;
   if(signal_ptr.CheckUpdateOrderLong(GetPointer(m_order),price,sl,tp,ex))
      return(UpdateOrder(price,sl,tp,ex));
//--- return with no actions taken
   return(false);
  }

La méthode CheckTrailingOrderShort() est similaire et s'utilise de la même manière.

3.2.2. UpdateOrder()

La fonction UpdateOrder() commence par la vérification d'un prix pertinent (pas EMPTY_VALUE). S'il n'y en a pas, l’ordre est supprimé, dans le cas contraire l’ordre est modifié en fonction des paramètres reçus.

bool CExpertAdvanced::UpdateOrder(double price,double sl,double tp,datetime ex)
  {
   ulong  ticket=m_order.Ticket();
   if(price==EMPTY_VALUE)
      return(m_trade.OrderDelete(ticket));
//--- modify the order, return the result
   return(m_trade.OrderModify(ticket,price,sl,tp,m_order.TypeTime(),ex));
  }

Le développement des héritiers des classes standard est terminé.


4. Développement de modules de prix

Nous avons déjà la base pour créer des Experts qui exécutent des ordres et des Stop Loss à des niveaux calculés. Pour être précis, nous avons des classes prêtes à l'emploi pour travailler avec des niveaux de prix. Maintenant, seuls les modules pour générer ces niveaux sont à écrire.

Le processus de développement de modules de prix est similaire à l'écriture de modules de signaux de trading. La seule différence entre eux est que c'est le Prix(), la méthode responsable de la mise à jour des prix dans le module, qui doit être remplacée, pas LongCondition(), ShortCondition() ou Direction() comme dans les modules de signaux. Idéalement, le lecteur doit avoir une idée claire du développement des modules de signaux. Les articles «Créez votre propre robot de trading en 6 étapes !» et «Générateur de signaux de trading basé sur un indicateur personnalisé» peuvent être utiles à cet égard.

Le code de plusieurs modules de prix va servir d'exemple.

4.1. Module de prix basé sur l'indicateur « Delta ZigZag »

L'indicateur Delta ZigZag dessine les niveaux par le nombre spécifié de plusieurs derniers pics. Si le prix franchit ces niveaux, cela signifie un renversement de tendance probable.

L'objectif du module de prix est de prendre le niveau d'entrée du tampon de l'indicateur, de trouver l'extremum local le plus proche pour exécuter le Stop Loss, de calculer le Take Profit en multipliant le Stop Loss par le coefficient spécifié dans les paramètres.

Fig. 3. Illustration du fonctionnement du module de prix sur l'indicateur Delta ZigZag en utilisant l'ordre d'achat comme exemple

Fig. 3. Illustration du fonctionnement du module de prix sur l'indicateur Delta ZigZag en utilisant l'ordre d'achat comme exemple

La figure 3. représente les niveaux générés par le module de prix. Avant que l'ordre ne se déclenche, le Stop Loss et le Take Profit changent en conséquence suite aux mises à jour du minimum.

4.1.1. Descripteur de module

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=DeltaZZ Price Module                                       |
//| Type=SignalAdvanced                                              |
//| Name=DeltaZZ Price Module                                        |
//| ShortName=DeltaZZ_PM                                             |
//| Class=CPriceDeltaZZ                                              |
//| Page=not used                                                    |
//| Parameter=setAppPrice,int,1, Applied price: 0 - Close, 1 - H/L   |
//| Parameter=setRevMode,int,0, Reversal mode: 0 - Pips, 1 - Percent |
//| Parameter=setPips,int,300,Reverse in pips                        |
//| Parameter=setPercent,double,0.5,Reverse in percent               |
//| Parameter=setLevels,int,2,Peaks number                           |
//| Parameter=setTpRatio,double,1.6,TP:SL ratio                      |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//+------------------------------------------------------------------+
// wizard description end

Les cinq premiers paramètres du descripteur sont nécessaires à la configuration de l'indicateur utilisé. Viennent ensuite le coefficient de calcul du Take Profit basé sur le Stop Loss et le temps d'expiration dans les barres pour les ordres du module de prix actuel.

4.1.2. Déclaration de classe

class CPriceDeltaZZ : public CExpertSignalAdvanced
  {
protected:
   CiCustom          m_deltazz;           //object of the DeltaZZ indicator
   //--- module settings
   int               m_app_price;
   int               m_rev_mode;
   int               m_pips;
   double            m_percent;
   int               m_levels;
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   //--- method of indicator initialization
   bool              InitDeltaZZ(CIndicators *indicators);
   //--- helper methods
   datetime          calcExpiration() { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
   double            getBuySL();          //function for searching latest minimum of ZZ for buy SL
   double            getSellSL();         //function for searching latest maximum of ZZ for sell SL
public:
                     CPriceDeltaZZ();
                    ~CPriceDeltaZZ();
   //--- methods of changing module settings
   void              setAppPrice(int ap)           { m_app_price=ap; }
   void              setRevMode(int rm)            { m_rev_mode=rm;  }
   void              setPips(int pips)             { m_pips=pips;    }
   void              setPercent(double perc)       { m_percent=perc; }
   void              setLevels(int rnum)           { m_levels=rnum;  }
   void              setTpRatio(double tpr)        { m_tp_ratio=tpr; }
   void              setExpBars(int bars)          { m_exp_bars=bars;}
   //--- method of checking correctness of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating indicators
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- main method of price module updating the output data
   virtual double    Prices();
  }; 

Données protégées - l’objet de l'indicateur de type CiCustom et les paramètres selon les types spécifiés dans le descripteur sont déclarés dans le module.

4.1.3. Constructeur

Le constructeur initialise les paramètres de classe avec les valeurs par défaut. Plus tard, ces valeurs sont réinitialisées lorsque le module est inclus dans le signal principal en fonction des paramètres d'entrée de l'Expert.

CPriceDeltaZZ::CPriceDeltaZZ() : m_app_price(1),
                                 m_rev_mode(0),
                                 m_pips(300),
                                 m_percent(0.5),
                                 m_levels(2),
                                 m_tp_ratio(1),
                                 m_exp_bars(10)
  {
  }

4.1.4. ValidationSettings()

ValidationSettings() est une méthode importante pour vérifier les paramètres d'entrée. Si les valeurs des paramètres du module ne sont pas valides, le résultat faux est renvoyé et un message d'erreur est imprimé dans le journal.

bool CPriceDeltaZZ::ValidationSettings(void)
  {
//--- checking for settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
   if(m_app_price<0 || m_app_price>1)
     {
      printf(__FUNCTION__+": Applied price must be 0 or 1");
      return(false);
     }
   if(m_rev_mode<0 || m_rev_mode>1)
     {
      printf(__FUNCTION__+": Reversal mode must be 0 or 1");
      return(false);
     }
   if(m_pips<10)
     {
      printf(__FUNCTION__+": Number of pips in a ray must be at least 10");
      return(false);
     }
   if(m_percent<=0)
     {
      printf(__FUNCTION__+": Percent must be greater than 0");
      return(false);
     }
   if(m_levels<1)
     {
      printf(__FUNCTION__+": Ray Number must be at least 1");
      return(false);
     }
   if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- parameter check passed
   return(true);
  } 

4.1.5. InitIndicators(...)

La méthode InitIndicators(...) appelle une méthode éponyme de la classe de base et initialise l'indicateur du module courant par la méthode InitDeltaZZ(...).

bool CPriceDeltaZZ::InitIndicators(CIndicators *indicators)
  {
//--- initialization of indicator filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- creating and initializing of custom indicator
   if(!InitDeltaZZ(indicators))
      return(false);
//--- success
   return(true);
  }

4.1.6. InitDeltaZZ(...)

La méthode InitDeltaZZ(...) ajoute l'objet de l'indicateur personnalisé à la collection et crée le nouvel indicateur « Delta ZigZag ».

bool CPriceDeltaZZ::InitDeltaZZ(CIndicators *indicators)
  {
//--- adds to collection
   if(!indicators.Add(GetPointer(m_deltazz)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- specifies indicator parameters
   MqlParam parameters[6];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="deltazigzag.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_app_price;
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_rev_mode;
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_pips;
   parameters[4].type=TYPE_DOUBLE;
   parameters[4].double_value=m_percent;
   parameters[5].type=TYPE_INT;
   parameters[5].integer_value=m_levels;
//--- object initialization
   if(!m_deltazz.Create(m_symbol.Name(),m_period,IND_CUSTOM,6,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- number of the indicator buffers
   if(!m_deltazz.NumBuffers(5)) return(false);
//--- ок
   return(true);
  }

Après avoir terminé avec succès les méthodes ValidationSettings(), InitDeltaZZ(...) et InitIndicators(...), le module est initialisé et prêt à fonctionner.

4.1.7. Prix()

Cette méthode est basique pour le module de prix. C'est l'endroit même où les paramètres de l’ordre sont mis à jour. Leurs valeurs sont transmises au signal principal. Cette méthode renvoie le résultat de l'opération de type double. Cela a été mis en œuvre principalement pour le développement futur. Le résultat de la méthode Prix() peut coder certaines situations et événements particuliers afin que le signal principal puisse les gérer en conséquence. Actuellement, seul le traitement de la valeur renvoyée EMPTY_VALUE est prévu. À la réception de ce résultat, le signal principal ignorera les paramètres suggérés par le module.

Algorithme de fonctionnement de la méthode Prix() dans ce module :

  1. Prenez les prix d'ouverture des ordres des indicateurs tampons 3 et 4 pour l'achat et la vente respectivement ;
  2. Mettre à zéro les paramètres finaux des ordres ;
  3. Vérifiez le prix d'achat. S'il y en a un, identifiez le niveau pour exécuter le Stop Loss par la méthode getBuySL(), calculez le niveau de Take Profit par la valeur du Stop Loss et le prix d'ouverture et calculez le délai d'expiration de l'ordre ;
  4. Vérifiez le prix de vente. S'il est détecté, trouvez le niveau pour exécuter le Stop Loss par la méthode getSellSL(), calculez le niveau de Take Profit par la valeur Stop Loss et le prix d'ouverture et calculez le délai d'expiration de l'ordre ;
  5. Sortir.
Les conditions de présence des prix d'achat et de vente s'excluent mutuellement en raison de certains aspects opérationnels de l'indicateur « Delta ZigZag ». Les tampons 3 et 4 sont dessinés sous forme de points par défaut (voir Fig. 3).

double CPriceDeltaZZ::Prices(void)
  {
   double openbuy =m_deltazz.GetData(3,0);//receive the last value from buffer 3
   double opensell=m_deltazz.GetData(4,0);//receive the last value from buffer 4
//--- clear parameter values
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int digits=m_symbol.Digits();
//--- check for the prices to buy
   if(openbuy>0)//if buffer 3 is not empty
     {
      m_order_open_long=NormalizeDouble(openbuy,digits);
      m_order_stop_long=NormalizeDouble(getBuySL(),digits);
      m_order_take_long=NormalizeDouble(m_order_open_long + m_tp_ratio*(m_order_open_long - m_order_stop_long),digits);
      m_order_expiration_long=calcExpiration();
     }
//--- check for the prices to sell
   if(opensell>0)//if buffer 4 is not empty
     {
      m_order_open_short=NormalizeDouble(opensell,digits);
      m_order_stop_short=NormalizeDouble(getSellSL(),digits);
      m_order_take_short=NormalizeDouble(m_order_open_short - m_tp_ratio*(m_order_stop_short - m_order_open_short),digits);
      m_order_expiration_short=calcExpiration();
     }
   return(0);
  }

4.1.8. getBuySL() et getSellSL()

Les méthodes getBuySL() et getSellSL() recherchent des minimums et maximums locaux respectifs pour exécuter des Stop Loss. La dernière valeur non nulle dans un tampon pertinent - le niveau de prix du dernier extremum local est recherché dans chaque méthode.

double CPriceDeltaZZ::getBuySL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(0,i);
      i++;
     }
   return(sl);
  }
double CPriceDeltaZZ::getSellSL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(1,i);
      i++;
     }
   return(sl);
  }

4.2. Module de prix basé sur la barre intérieure

La barre intérieure est l'un des modèles ou modèles largement utilisés dans le trade sans indicateurs appelés Price action. Une barre intérieure est une barre ayant un haut et un bas dans les extrema de la barre précédente. Une barre intérieure indique le début de la consolidation ou l'inversion possible du mouvement des prix.

Sur la figure 4, les barres intérieures sont à l'intérieur des ellipses rouges. Lorsqu'une barre intérieure est détectée, le module de prix génère les prix d'ouverture des ordres buystop et sellstop sur les extrema de la barre précédant la barre intérieure.

Les prix d'ouverture sont les niveaux Stop Loss pour les ordres opposés. Le Take Profit est calculé de la même manière que dans le module discuté ci-dessus - en multipliant le niveau du Stop Loss par le coefficient spécifié dans les paramètres. Les prix d'ouverture et les Stop Loss sont marqués par des lignes horizontales rouges et les Take Profits par des lignes vertes.

Fig. 4. Illustration des barres intérieures et des niveaux du module de prix

Fig. 4. Illustration des barres intérieures et des niveaux du module de prix

Sur la figure 4, les ordres de vente ne sont pas exécutés car la tendance est à venir. Néanmoins, le module de prix génère des niveaux d'entrée dans les deux sens. Certains niveaux de Take Profit sont en dehors du graphique.

Contrairement au module précédent, l'algorithme de ce module est simple et ne nécessite pas d'initialisation d'indicateurs. Il y a peu de code dans le module, il est présenté ci-dessous dans son intégralité. Cependant, nous n'allons pas analyser chaque fonction séparément.

#include <Expert\ExpertSignalAdvanced.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Inside Bar Price Module                                    |
//| Type=SignalAdvanced                                              |
//| Name=Inside Bar Price Module                                     |
//| ShortName=IB_PM                                                  |
//| Class=CPriceInsideBar                                            |
//| Page=not used                                                    |
//| Parameter=setTpRatio,double,2,TP:SL ratio                        |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//| Parameter=setOrderOffset,int,5,Offset for open and stop loss     |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CPriceInsideBar                                            |
//| Purpose: Class of the generator of price levels for orders based |
//|          on the "inside bar" pattern.                            |
//| Is derived from the CExpertSignalAdvanced class.                 |
//+------------------------------------------------------------------+
class CPriceInsideBar : public CExpertSignalAdvanced
  {
protected:
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   double            m_order_offset;      //shift of the opening and Stop Loss levels
   datetime          calcExpiration()  { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
public:
                     CPriceInsideBar();
                    ~CPriceInsideBar();
   void              setTpRatio(double ratio){ m_tp_ratio=ratio; }
   void              setExpBars(int bars)    { m_exp_bars=bars;}
   void              setOrderOffset(int pips){ m_order_offset=m_symbol.Point()*pips;}
   bool              ValidationSettings();
   double            Prices();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::~CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//| Validation of protected settings                                 |
//+------------------------------------------------------------------+
bool CPriceInsideBar::ValidationSettings(void)
  {
//--- verification of the filter parameters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
  if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- check passed
   return(true);
  }
//+------------------------------------------------------------------+
//| Price levels refreshing                                          |
//+------------------------------------------------------------------+
double CPriceInsideBar::Prices(void)
  {
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check for inside bar      
   if(h[0] >= h[1] && l[0] <= l[1])
     {
      m_order_open_long=h[0]+m_order_offset;
      m_order_stop_long=l[0]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
     }
   return(EMPTY_VALUE);
  }  
//+------------------------------------------------------------------+

Dans la méthode Prix() de ce module, le retour du résultat EMPTY_VALUE est utilisé pour démontrer au signal principal qu'il n'y a pas de niveaux de prix disponibles.

4.3. Module de prix basé sur la barre extérieure

La barre extérieure est un autre modèle populaire d'action sur les prix, également appelé « absorption ». La barre extérieure est appelée ainsi parce que ses Haut et Bas chevauchent les Haut et Bas de la barre précédente. L'apparition d'une barre extérieure est une indication de l'augmentation de la volatilité suivie d'un mouvement de prix dirigé.

Sur la figure 5, les barres extérieures sont marquées par des ellipses rouges. Lors de la détection d'une barre extérieure, le module de prix génère les prix d'ouverture des ordres buystop et sellstop sur ses extrema.

Les prix d'ouverture sont les niveaux Stop Loss pour les ordres opposés. Le Take Profit est calculé de la même manière que dans le module discuté ci-dessus - en multipliant le niveau du Stop Loss par le coefficient spécifié dans les paramètres. Les prix d'ouverture et les Stop Loss sont marqués par des lignes horizontales rouges et les Take Profits par des lignes vertes.

Fig. 5. Illustration des barres extérieures et des niveaux des modules de prix

Fig. 5. Illustration des barres extérieures et des niveaux des modules de prix

Sur la figure 5, les barres extérieures sont marquées par des ellipses rouges. Les lignes horizontales reflètent les prix d'ouverture des ordres en attente générés par le module de prix.

Dans ce cas, seuls les ordres de vente sont ouverts car il y a une tendance baissière. Le fonctionnement de ce module est essentiellement similaire au précédent. La seule différence entre son code est uniquement la méthode Prix(), les autres parties sont exactement les mêmes et ont les mêmes noms. Vous trouverez ci-dessous le code des Prix ().

double CPriceOutsideBar::Prices(void)
{
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check of outside bar
   if(h[0] <= h[1] && l[0] >= l[1])
   {
      m_order_open_long=h[1]+m_order_offset;
      m_order_stop_long=l[1]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
   }
   return(EMPTY_VALUE);
} 

4.4. Test de performance des modules

Dans la section suivante, trois exemples de modules sont testés pour vérifier leur travail individuel puis joint dans un expert et s'assurer que le système fonctionne comme prévu. En conséquence, quatre experts sont générés. Le module de signal de trading basé sur l'indicateur Awesome Oscillator travaillant sur la période H12 est utilisé comme filtre dans chacun des Experts générés. Les modules de prix fonctionnent sur H6.

Gestion de l'argent : le lot fixe et le Trailing Stop ne sont pas utilisés. Tous les tests sont effectués sur les cotations EURUSD du compte démo du serveur MetaQuotes-Demo pour la période du 01.01.2013 au 01.06.2014 Version terminale : 5.00, build 965 (27 juin 2014).

Pour résumer, les résultats des tests ne sont représentés que par des graphiques d'équilibre. Ils sont suffisants pour obtenir le comportement de l'Expert dans chaque cas particulier.

4.4.1. Test du module basé sur l'indicateur Delta ZigZag

Fig. 6. Graphique d'équilibre dans le test du module de prix basé sur Delta ZigZag

Fig. 6. Graphique d'équilibre dans le test du module de prix basé sur l'indicateur « Delta ZigZag »

4.4.2. Test du module basé sur le modèle « Barre intérieure »

Fig. 7. Graphique d'équilibre en testant le module de prix basé sur la barre intérieure

Fig. 7. Graphique d'équilibre lors du test du module de prix basé sur la barre intérieure

En regardant la figure 7., il faut garder à l'esprit que le but des tests à ce stade est de vérifier les performances du code, pas d'obtenir une stratégie gagnante.

4.4.3. Test du module basé sur le modèle « Barre extérieure »

Fig. 8. Graphique d'équilibre lors du test du module de prix basé sur la barre extérieure

Fig. 8. Graphique d'équilibre lors du test du module de prix basé sur la barre extérieure

4.4.4. Tester le travail conjoint des modules de prix développés

Compte tenu des résultats des tests précédents, les modules de prix basés sur le DeltaZigZag, la barre intérieure et la barre extérieure ont reçu des coefficients de poids de 1, 0,5 et 0,7 respectivement. Les coefficients de pondération définissent les priorités des modules de prix.

Fig. 9. Graphique d'équilibre lors du test de l'Expert avec trois modules de prix

Fig. 9. Graphique d’équilibre du test de l'Expert avec trois modules de prix

À chaque étape des tests, toutes les opérations effectuées sur les graphiques de prix ont été soigneusement analysées. Les erreurs et écarts de stratégie n'ont pas été décelés. Tous les programmes suggérés sont joints à cet article et vous pouvez les tester vous-même.


5. Mode d'emploi

Nous allons considérer les étapes du développement de l'Expert en utilisant l'extension développée sur l'exemple d'Expert avec trois modules de prix et Awesome Oscillator comme filtre.

Avant le début de la génération, assurez-vous que les fichiers d'en-tête « CExpertAdvanced.mqh » et « CExpertSignalAdvanced.mqh » sont dans le catalogue du terminal MetaTrader 5 dans le dossier MQL5/Include/Expert et les fichiers des modules de prix sont dans le dossier MQL5 /Inclure/Expert/MonSignal. Avant de lancer l'Expert, assurez-vous que les indicateurs compilés se trouvent dans le dossier MQL5/Indicators. Dans ce cas, il s'agit du fichier « DeltaZigZag.ex5 ». Dans l'archive jointe, tous les fichiers sont à leur place. Il suffit de décompresser cette archive dans un dossier avec le terminal MetaTrader 5 et de confirmer la fusion des catalogues.

5.1. Génération de l'Expert

Pour démarrer la génération de l’Expert, sélectionnez « Fichier »->« Nouveau » dans le MetaEditor.

Fig. 10. Création d'un nouvel Expert à l'aide de l’assistant MQL5

Fig. 10. Création d'un nouvel expert à l'aide de l'assistant MQL5

Dans la nouvelle fenêtre, sélectionnez « Expert Advisor (générer) » puis appuyez sur « Suivant ».


Fig. 11. Génération d'un expert à l'aide de l’assistant MQL5

Fig. 11. Génération d'un Expert à l'aide de l'assistant MQL5

Cela fera apparaître une fenêtre dans laquelle vous pourrez spécifier le nom. Dans cet exemple particulier, le nom de l'Expert est «TEST_EA_AO_DZZ_IB_OB», les paramètres Symbol et TimeFrame ont des valeurs par défaut. Cliquez ensuite sur « Suivant ».

Fig. 12. Paramètres communs de l'Expert Advisor


Fig. 12. Propriétés générales de l'Expert Advisor

Dans la fenêtre qui apparaît, ajoutez les modules un par un en appuyant sur « Ajouter ». L'ensemble du processus est présenté ci-dessous.

VEUILLEZ NOTER ! Lorsque vous ajoutez des modules, incluez d'abord tous les modules de signaux (héritiers CExpertSignal), puis les modules de prix (héritiers CExpertSignalAdvanced). Le résultat de la perturbation de cet ordre d'inclusion des modules va être imprévisible.

Nous commençons donc par inclure des modules de signaux à partir de Awesome Oscillator. C'est le seul filtre dans cet exemple.

Fig. 13. Inclure le module de signaux à partir de Awesome Oscillator

Fig. 13. Inclure le module de signaux à partir de Awesome Oscillator

Incluez les modules de prix requis dans un ordre aléatoire une fois que tous les modules de signaux ont été inclus. Il y en a trois dans cet exemple.

Fig. 14. Inclure le module de signaux à partir du module de prix DeltaZZ

Fig. 14. Inclure le module de signaux à partir du module de prix DeltaZZ


Fig. 15. Inclure le module de signaux à partir du module de prix de la barre intérieure

Fig. 15. Inclure le module de signaux à partir du module de prix de la barre intérieure


Fig. 16. Inclure le module de signaux à partir du module de prix de la barre extérieure

Fig. 16. Inclure le module de signaux à partir du module de prix de la barre extérieure

Une fois tous les modules ajoutés, la fenêtre se présentera comme suit :

Fig. 17. Liste des modules inclus de signaux de trading

Fig. 17. Liste des modules inclus de signaux de trading

La valeur du paramètre « Poids » du module de prix définit sa priorité.

Après avoir appuyé sur le bouton « Suivant », l'assistant propose de sélectionner les modules de gestion de l'argent et les modules Trailing Stop. Sélectionnez-en un ou laissez-le tel quel en appuyant sur « Suivant » ou « Prêt ».

En appuyant sur « Prêt », nous recevrons le code généré de Advisor.

5.2. Modification du code généré

Donc, nous avons le code.

1. Trouver la chaîne au tout début

#include <Expert\Expert.mqh>

et modifiez-la pour qu'elle ressemble

#include <Expert\ExpertAdvanced.mqh>

Il est obligatoire d'inclure les fichiers des classes développées.

2. Trouvez ensuite la chaîne

CExpert ExtExpert;

et changez en

CExpertAdvanced ExtExpert;

Cela changera la classe standard Expert pour son descendant avec les fonctions requises.

3. Trouvez maintenant la chaîne

CExpertSignal *signal=new CExpertSignal;

et changez en

CExpertSignalAdvanced *signal=new CExpertSignalAdvanced;

C'est le moyen de changer la classe standard du signal principal pour son descendant avec les fonctions requises.

4. Trouvez la chaîne mettant en œuvre l'ajout du premier module de prix au tableau m_filters du signal principal. Dans cet exemple, cela ressemble à :

signal.AddFilter(filter1);

Avant cela, nous insérons la chaîne

signal.CalcPriceModuleIndex();

Ceci est nécessaire pour que le signal principal reconnaisse jusqu'à quel indice dans le tableau m_filters il y a des pointeurs de module de signal et à partir duquel il y a des pointeurs de module de prix.

Trouver la bonne position pour insérer la chaîne spécifiée peut entraîner des difficultés. Utilisez le numéro après le mot « filtre » comme point de référence. Cela simplifiera la recherche et permettra de ne pas rater la bonne position. L'assistant MQL5 nomme les modules automatiquement dans leur ordre. Le premier module s'appelle filter0, le deuxième - filter1, le troisième - filter2 etc. Dans notre cas, il n'y a qu'un seul module de signal. Par conséquent, le premier module de prix inclus est le numéro deux et nous devons rechercher la chaîne «signal.AddFilter(filter1);» pour ajouter le filtre car la numérotation dans le code commence par zéro. L'illustration est sur la Fig. 18 :

Fig. 18. Noms des modules dans le code selon l'ordre d'inclusion

Fig. 18. Noms des modules dans le code selon l'ordre d'inclusion

5. Cette partie n'est pas obligatoire. À cause des changements introduits, les paramètres d'Expert responsables des indentations de prix d'ouverture, des Stop Loss, des Take Profits et du délai d'expiration des commandes ont perdu leur utilité. Pour rendre le code plus compact, vous pouvez supprimer les chaînes suivantes :

input double Signal_PriceLevel            =0.0;                    // Price level to execute a deal
input double Signal_StopLevel             =50.0;                   // Stop Loss level (in points)
input double Signal_TakeLevel             =50.0;                   // Take Profit level (in points)
input int    Signal_Expiration            =4;                      // Expiration of pending orders (in bars)

L'erreur de compilation rencontrée après la suppression des chaînes ci-dessus nous amène au prochain groupe de chaînes à supprimer :

   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);

Une fois ces derniers supprimés, la compilation va réussir.

Les commentaires et explications d'édition se trouvent dans le code joint de l'Expert « TEST_EA_AO_DZZ_IB_OB ». Les chaînes du code qui pourraient être supprimées sont accompagnées de commentaires.


Conclusion

Dans cet article, nous avons considérablement élargi le domaine d'application de l'assistant MQL5. Maintenant, il peut être utilisé pour l'optimisation du développement de systèmes de trading automatiques qui nécessitent d’exécuter des ordres, des Stop Loss et des Take Profits à différents niveaux de prix, quel que soit le prix actuel.

Les Experts générés peuvent inclure un ensemble de modules de prix calculant les paramètres des ordres envoyés. Le jeu de paramètres le plus approprié est sélectionné parmi ceux disponibles. Les préférences sont spécifiées dans les paramètres. Cela permet d'utiliser de nombreux points d'entrée différents avec une efficacité maximale. Cette approche rend les Experts sélectifs. Si la direction est connue mais que le point d'entrée n'est pas défini, alors l'Expert attendra qu'elle apparaisse.

L'introduction de modules compatibles standard chargés de la recherche des niveaux de prix est un avantage significatif et vise à simplifier le développement des Experts. Bien qu'il n'y ait actuellement que trois modules, leur nombre augmentera sans aucun doute à l'avenir. Si vous avez trouvé cet article utile, veuillez suggérer des algorithmes de fonctionnement des modules de prix dans les commentaires. Des idées intéressantes seront implémentées dans le code.

Cet article présente également une méthode d'extension supplémentaire des capacités d’Expert développées dans l'Assistant. L'héritage est le moyen optimal d'introduire des changements.

Les utilisateurs n'ayant aucune compétence en programmation, mais capables de modifier le code en suivant les instructions, auront la possibilité de créer des Experts plus avancés sur la base des modèles disponibles.

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

Comment préparer un compte de trading pour la migration vers l'hébergement virtuel Comment préparer un compte de trading pour la migration vers l'hébergement virtuel
Le terminal client MetaTrader est parfait pour automatiser les stratégies de trading. Il dispose de tous les outils nécessaires pour les développeurs de robots de trading, notamment un puissant langage de programmation MQL4/MQL5 basé sur le langage C++, un environnement de développement MetaEditor pratique et un testeur de stratégie multithread qui prend en charge l'informatique distribuée dans le réseau cloud MQL5. Dans cet article, vous découvrirez comment déplacer votre terminal client vers l'environnement virtuel avec tous les éléments personnalisés.
Comment accéder à la base de données MySQL à partir de MQL5 (MQL4) Comment accéder à la base de données MySQL à partir de MQL5 (MQL4)
L'article décrit le développement d'une interface entre MQL et la base de données MySQL. Il traite des solutions pratiques existantes et offre un moyen plus pratique d'implémenter une bibliothèque pour travailler avec des bases de données. L'article contient une description détaillée des fonctions, la structure de l'interface, des exemples et certaines des fonctionnalités spécifiques de l'utilisation de MySQL. Comme pour les solutions logicielles, les pièces jointes des articles incluent les fichiers de bibliothèques dynamiques, de la documentation et des exemples de scripts pour les langages MQL4 et MQL5.
Conseils pour une présentation efficace des produits sur le marché Conseils pour une présentation efficace des produits sur le marché
Vendre efficacement des programmes aux traders ne nécessite pas seulement d'écrire un produit efficace et utile, puis de le publier sur le marché. Il est essentiel de fournir une description complète et détaillée et de bonnes illustrations. Un logo de qualité et des captures d'écran correctes sont tout aussi importants que le « vrai codage ». Gardez à l'esprit une formule simple : pas de téléchargements = pas de ventes.
Construire une start-up de technologie sociale, Première partie Envoyez des Tweets sur vos signaux MetaTrader 5 Construire une start-up de technologie sociale, Première partie Envoyez des Tweets sur vos signaux MetaTrader 5
Aujourd’hui, nous allons apprendre à lier un terminal MetaTrader 5 à Twitter afin de pouvoir tweeter les signaux de trading de vos EA. Nous développons un système d’aide à la décision sociale en PHP basé sur un service Web RESTful. Cette idée vient exceptionnellement d’une conception du trading automatique appelée trading assisté par ordinateur. Nous voulons que les capacités cognitives des traders humains filtrent les signaux de trading qui, autrement, seraient automatiquement mis sur le marché par les Experts Advisors.