English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Guide étape par étape pour rédiger un conseiller expert en MQL5 pour les débutants

Guide étape par étape pour rédiger un conseiller expert en MQL5 pour les débutants

MetaTrader 5Systèmes de trading | 22 décembre 2021, 16:24
2 586 0
Samuel Olowoyo
Samuel Olowoyo

Introduction

Cet article s'adresse aux débutants qui souhaitent apprendre à rédiger des Expert Advisors simples dans le nouveau langage MQL5. Nous commencerons d'abord par définir ce que nous voulons que notre EA (Expert Advisor) fasse, puis passerons à la façon dont nous voulons que l'EA le fasse.


1. Stratégie de trading

Ce que notre EA fera :

  • Il surveillera un indicateur particulier, et lorsqu'une certaine condition est remplie (ou certaines conditions sont remplies), il passera un trade (soit un Short/Sell ou Long/Buy), en fonction de la condition actuelle qui a été remplie.

Ce qui précède est appelé une stratégie de trading. Avant de pouvoir rédiger une évaluation environnementale, vous devez d'abord développer la stratégie que vous souhaitez automatiser dans l'EA. Donc, dans ce cas, modifions la déclaration ci-dessus afin qu'elle reflète la stratégie que nous voulons développer en EA.

  • Nous utiliserons un indicateur appelé moyenne mobile avec une période de 8 (vous pouvez choisir n'importe quelle période, mais pour les besoins de notre stratégie, nous utiliserons 8)

  • Nous voulons que notre EA place un trade Long (Buy) lorsque la moyenne mobile-8 (pour les besoins de notre discussion, je l'appellerai MA-8) va à la hausse et que le prix est clos au-dessus de lui et il se placera a Short (Sell) lorsque MA-8 baisse et que le prix est clos au-dessous de lui.
  • Nous allons également utiliser un autre indicateur appelé Mouvement directionnel moyen (ADX) à période 8 également pour nous aider à déterminer si le marché affiche une tendance à la hausse ou non. Nous faisons cela parce que c’est notre stratégie de ne trader que lorsque le marché affiche une tendance à la hausse et nous prenons une pause lorsque le marché est loin d’être stable (c'est-à-dire sans tendance haussière). Pour y parvenir, nous ne placerons notre trade (Acheter ou Vendre) que lorsque les conditions ci-dessus sont remplies et que la valeur ADX est supérieure à 22. Si l'ADX est supérieur à 22 mais décroissant, ou si l'ADX est inférieur à 22, nous ne traderons pas, même si la condition B a été remplie.
  • Nous voulons également nous protéger en fixant un Stop loss de 30 pips, et pour notre objectif de Profit ; nous visons un profit de 100 pips.
  • Nous voulons également que notre EA recherche des opportunités d'achat/vente uniquement lorsqu'une nouvelle barre a été formée et nous nous assurerons également d'ouvrir une position d'achat si les conditions d'achat sont remplies et que nous n'en avons pas déjà une ouverte, et d'ouvrir une position de vente lorsque les conditions de vente sont remplies et que nous n'en avons pas déjà ouvert.

Nous avons maintenant développé notre stratégie ; il est maintenant temps de commencer à écrire notre code.


2. Rédaction d'un Expert Advisor

2.1 Assistant MQL5

Commencez par lancer l'éditeur de langage MetaQuotes 5. Appuyez ensuite sur Ctrl+N ou cliquez sur le bouton New dans la barre de menu

Figure 1. Démarrage d'un nouveau document MQL5

Figure 1. Commencer un nouveau document MQL5

 Dans la fenêtre de l'assistant MQL5, sélectionnez Expert Advisor et cliquez sur le bouton « Suivant » comme indiqué sur la figure 2 :

Figure 2. Sélection du type de document

Figure 2. Sélection du type de programme

Dans la fenêtre suivante, tapez le nom que vous voulez donner à votre EA dans la case Nom. Dans ce cas, j'ai tapé My_First_EA. Vous pouvez ensuite taper votre nom dans la case Auteur ainsi que l'adresse de votre site Web ou adresse e-mail dans la case Lien (si vous en avez un).

Figure 3. Propriétés générales de l'Expert Advisor

Figure 3. Propriétés générales de l'Expert Advisor

Puisque nous voulons changer certains des paramètres de notre EA afin de voir laquelle des valeurs peut nous donner le meilleur résultat, nous les ajouterons en cliquant sur le bouton « Ajouter ».

Figure 4. Définition des paramètres d'entrée EA

Figure 4. Configuration EA paramètres d’entrée

Dans notre EA, nous voulons être en mesure d’expérimenter nos paramètres Stop Loss, Take Profit, ADX Period et Moving Average Mobile, afin de les définir à ce stade.

Double-cliquez sous la section Name et tapez sur le nom du paramètre, puis double-cliquez sous le Type pour sélectionner le type de données pour le paramètre, et double-cliquez sous la section Valeur initiale et tapez sur la valeur initiale du paramètre.

Une fois que vous avez terminé, cela devrait ressembler à ce qui suit :

Figure 5. Types de données des paramètres d'entrée EA

Figure 5. Types de données des paramètres d’entrée EA

Comme vous pouvez le voir ci-dessus, j'ai sélectionné un type de données entier (int) pour tous les paramètres. Parlons un peu des types de données.

  • char: Le type char prend 1 octet de mémoire (8 bits) et permet l'expression dans la notation binaire des valeurs 2^8=256. Le type char peut contenir à la fois des valeurs positives et des valeurs négatives. La plage de valeurs va de -128 à 127.
  • uchar : Le uchar comme type entier occupe également 1 octet de mémoire, ainsi que le type char, mais par contre, uchar n'est destiné qu'aux valeurs positives. La valeur minimale est zéro, la valeur maximale est 255. La première lettre u du nom du type uchar est l'abréviation desans signature.
  • short: La taille du type short est de 2 octets (16 bits) et, par conséquent, il permet d'exprimer la plage de valeurs égales à 2 à la puissance 16 : 2^16 = 65 536. Comme le type short est un signe un et contient à la fois des valeurs positives et négatives, la plage de valeurs est comprise entre -32 768 et 32 767.
  • ushort: Le type sans signature short est le type ushort, qui a également une taille de 2 octets. La valeur minimale est 0, la valeur maximale est 65 535.
  • int : La taille du type int est de 4 octets (32 bits). La valeur minimale est -2 147 483 648, la valeur maximale est 2 147 483 647.
  • uint :  Le type entier sans signature est uint. Il prend 4 octets de mémoire et permet l’expression des nombres entiers de 0 à 4 294 967 295.
  • long : La taille du type long est de 8 octets (64 bits). La valeur minimale est de -9 223 372 036 854 775 808, la valeur maximale est de 9 223 372 036 854 775 807.
  • ulong : Le type ulong occupe également 8 octets et peut stocker des valeurs de 0 à 18 446 744 073 709 551 615.

Partant de la description ci-haut de différents types de données, les types entiers sans signature ne sont pas conçu pour stocker des valeurs négatives, toute tentative de définition d'une valeur négative peut entraîner des conséquences inattendues. Par exemple, si vous souhaitez stocker des valeurs de données négatives, vous ne pouvez pas les stocker dans les types sans signature (c'est-à-dire uchar, uint, ucourt, ulong).

Retour à notre EA. En regardant les types de données, vous conviendrez avec moi que nous sommes supposés utiliser des types de données char ou uchar, puisque les données que nous avons voulons stocker dans ces les paramètres sont inférieurs à 127  ou 255 respectivement. Pour une bonne gestion de la mémoire, c'est la meilleure chose à faire. Toutefois pour les besoins de notre discussion, nous nous en tiendrons au type int.

Une fois que vous avez terminé de configurer tous les paramètres nécessaires, cliquez sur le bouton Terminé et l'éditeur MetaQuotes créera le squelette du code pour vous comme le montre la figure suivante.


Décomposons le code en plusieurs rubriques pour une meilleure compréhension.

La partie supérieure (En-tête) du code est le poste où la propriété de l'EA est définie. Vous pouvez découvrir que c’est ici où vous trouverez les valeurs que vous avez remplies dans l'Assistant MQL5 de la figure 3. 

Dans cette section du code, vous pouvez définir des paramètres supplémentaires comme la description (brève description textuelle de l'EA), la déclaration des constantes, l’inclusion des fichiers supplémentaires ou des fonctions d'importation. 


Lorsqu'une déclaration commence par un symbole #, cela s'appelle une directive de préprocesseur et ne se termine pas avec un point-virgule ';' un autre exemple de directives de préprocesseur comprend :

#define : 

La directive #define est utilisée pour une déclaration de constantes. Elle est écrite sous la forme

#define identifier token_string

Cela remplace chaque occurrence d’ identifiant dans votre code avec la valeur token_string.

Exemple :

#define ABC               100
#define COMPANY_NAME      "MetaQuotes Software Corp."

Chaque occurrence de COMPANY_NAME sera remplacée par la chaîne "MetaQuotes Software Corp." ou remplacée par celle de ABC avec le char (ou l’entier) 100 dans votre code.

Vous pouvez lire plus de détails concernant les directives du préprocesseur dans le manuel MQL5. Continuons maintenant notre discussion.

La seconde partie de l'en-tête de notre code est la section des paramètres d’entrée :

 

Nous préciserons tous les paramètres, qui seront utilisés dans notre EA au niveau de cette section. De ce nombre figurent toutes les variables qui seront utilisées par toutes les fonctions que nous écrirons dans notre EA.

Les variables déclarées à ce niveau sont appelées variables globales car elles sont accessible par toutes les fonctions de notre EA qui peuvent en avoir besoin. Les paramètres d’entrée sont des paramètres qui ne peuvent être modifiés qu'en dehors de notre EA. Nous pouvons également déclarer d'autres variables que nous manipulerons lors de notre EA mais ne seront pas disponibles en dehors de notre EA dans cette section. 

Vient ensuite la fonction d'initialisation EA. Il s’agit de la première fonction qui est appelée lorsque l'EA est lancé ou attaché à un graphique et il n'est appelé qu'une seule fois. 


Cette section est le meilleur endroit pour effectuer quelques vérifications importantes afin de s'assurer que notre EA fonctionne très bien.

Nous pouvons décider de savoir si le graphique a suffisamment de barres pour que notre EA fonctionne, etc.

C'est aussi le meilleur endroit pour obtenir les descripteurs que nous utiliserons pour nos indicateurs (ADX et indicateurs de moyenne mobile).

 
 La fonctio n OnDeinitest appelée lorsque l’ EA est supprimé du graphique.

Pour notre EA, nous libérerons les descripteurs créés pour nos Indicateurs lors de l'initialisation dans cette section.


Cette fonction traite les événements NewTick ce qui est généré lorsqu'une nouvelle cotation est reçue pour un symbole. 

Notez bien, cet Expert Advisor ne peut pas effectuer des opérations de trading si l'utilisation des Expert Advisors dans le terminal client n'est pas autorisée (Bouton « Auto Trading »).

Figure 6. Autotrading est activé

Figure 6. Le trading automatique est activé

La plupart de nos codes qui mettront en œuvre notre La stratégie de trading, développée plus tôt, sera écrite dans cette section.

Maintenant que nous avons examiné les différentes sections du code de notre EA, commençons à ajouter de la chair au squelette.

2.2 SECTION PARAMÈTRES D’ENTRÉE

//--- input parameters
input int      StopLoss=30;      // Stop Loss
input int      TakeProfit=100;   // Take Profit
input int      ADX_Period=8;     // ADX Period
input int      MA_Period=8;      // Moving Average Period
input int      EA_Magic=12345;   // EA Magic Number
input double   Adx_Min=22.0;     // Minimum ADX Value
input double   Lot=0.1;          // Lots to Trade
//--- Other parameters
int adxHandle; // handle for our ADX indicator
int maHandle;  // handle for our Moving Average indicator
double plsDI[],minDI[],adxVal[]; // Dynamic arrays to hold the values of +DI, -DI and ADX values for each bars
double maVal[]; // Dynamic array to hold the values of Moving Average for each bars
double p_close; // Variable to store the close value of a bar
int STP, TKP;   // To be used for Stop Loss & Take Profit values

Comme vous pouvez le voir, nous avons ajouté plus de paramètres. Avant de continuer à discuter des nouveaux paramètres, discutons de quelque chose que vous pouvez voir maintenant. Les deux barres obliques ‘//’ nous permettent de mettre des commentaires dans nos codes. Avec des commentaires, nous sommes en mesure de savoir ce que représentent nos variables, ou ce que nous faisons à ce moment-là dans notre code. Cela donne aussi une meilleure compréhension de notre code. Il existe deux manières de rédiger des commentaires :

// Autres paramètres …

Ceci est un commentaire d'une seule ligne

/*

  Ceci est un commentaire sur plusieurs lignes

*/

Ceci est un commentaire sur plusieurs lignes. Les commentaires multilignes commencent par la paire de symboles /* et se terminent par */.

Le compilateur ignore tous les commentaires lors de la compilation de votre code.

Utilisation de commentaires sur une seule ligne pour les paramètres d’entrée est un bon moyen de faire comprendre à nos utilisateurs EA ce que ces paramètres représentent. Sur les propriétés d'entrée EA, nos utilisateurs ne verront pas le paramètre lui-même, au contraire, ils verront les commentaires comme indiqué ci-dessous :

Figure 7. Paramètres d'entrée de l'Expert Advisor

Figure 7. Paramètres d'entrée de l'Expert Advisor

Maintenant, revenons à notre code…

Nous avons décidé d'ajouter d'autres paramètres pour notre EA. Le EA_Magic est le nombre magique pour tous les ordres de notre EA.  La valeur minimale ADX (Adx_Min) est déclarée comme un type de données double. Un double est utilisé pour stocker les constances de la virgule flottante, qui contiennent une partie d’un nombre entier, une virgule décimale et une partie fractionnaire.

Exemple :

double mysum = 123.5678;

double b7 = 0.09876;

The Lot to trade (Lot) represente le volume de l'instrument financier que nous voulons trader. Ensuite, nous avons déclaré d'autres paramètres que nous utiliserons :

The adxHandle doit être utilisé pour stocker le descripteur de l'indicateur ADX, tandis que maHandle stockera le descripteur de l’ indicateur de la moyenne mobile. Les plsDI[], minDI[], adxVal[] sont des tableaux dynamiques qui contiendront les valeurs de +DI, -DI et ADX principal (de l'indicateur ADX) pour chaque barre du graphique. Le maVal[] est un tableau dynamique qui maintiendra les valeurs de l'indicateur de moyenne mobile pour chaque barre sur le graphique.

Au fait, que sont les tableaux dynamiques ? Un tableau dynamique est un tableau déclaré sans dimension. En d'autres termes, aucune valeur n’est spécifiée dans la paire de crochets. Un tableau statique, d'autre part a ses dimensions définies au point de déclaration.

Exemple :

double allbars[20]; // cela prendra 20 éléments

p_close est une variable que nous utiliserons pour stocker le prix de clôture de la barre que nous allons surveiller pour vérifier nos trades Achat/ Vente.

STP et TKP vont être utilisées pour stocker les valeurs Stop Loss et Take Profit dans notre EA.

2.3. SECTION INITIALISATION EA

int OnInit()
  {
//--- Get handle for ADX indicator
   adxHandle=iADX(NULL,0,ADX_Period);
//--- Get the handle for Moving Average indicator
   maHandle=iMA(_Symbol,_Period,MA_Period,0,MODE_EMA,PRICE_CLOSE);
//--- What if handle returns Invalid Handle
   if(adxHandle<0 || maHandle<0)
     {
      Alert("Error Creating Handles for indicators - error: ",GetLastError(),"!!");
     }

C’est ici que nous obtenons le descripteurs de notre indicateur en utilisant les fonctions d'indicateur respectives.

Le descripteur de l’indicateur ADX est obtenu au moyen de la fonction iADX. Cela demande le symbole de graphique (NULL signifie aussi le symbole actuel sur le graphique actuel), la chart period/timeframe (0 signifie également la période actuelle sur le graphique actuel), la période de moyenne ADX pour le calcul de l'indice (que nous avons défini précédemment dans la section des paramètres d’entrée) sous forme de paramètres ou d’arguments.  

int  iADX(
   symbole de           chaîne,         // nom de symbole
   période  ENUM_TIMEFRAMES,         // période
   int              adx_period      // période de moyenne
   );

Le descripteur de l’indicateur Moving Average est obtenu en utilisant la fonction iMA. Il a les arguments suivants :

  • le symbole graphique (qui est obtenu au moyen de _symbol, symbol() ou NULL pour le symbole courant sur le graphique courant),
  • the chart period/timeframe (qui est obtenu au moyen de _period, period(), ou 0 pour le calendrier courant sur le graphique actuel),
  • la période moyenne Moving Average (que nous avons définie précédemment sous la section des paramètres d’entrée),
  • le décalage de l’indicateur relatif au tableau des prix (le décalage est ici de 0),
  • le type Moving average smoothing (peut être l'une des méthodes de moyenne suivantes : Simple Averaging-MODE_SMA, Exponential Averaging-MODE_EMA, Smoothed Averaging-MODE_SMMA ou Linear-Weighted Averaging-MODE_LWMA), et
  • le prix utilisé pour la moyenne (ici nous utilisons le prix de clôture).

int  iMA(
   string               symbol,            // nom de symbole
   ENUM_TIMEFRAMES      period,            // période
   int                  ma_period,         // période moyenne
   int                  ma_shift,          // décalage horizontal
   ENUM_MA_METHOD       ma_method,         // type lisse
   ENUM_APPLIED_PRICE   applied_price      // type de prix ou descripteur
   );

Veuillez lier le manuel MQL5 pour obtenir plus de détails sur ces fonctions d'indicateur. Il vous permettra de mieux comprendre comment utiliser chaque indicateur.

Nous essayons à nouveau de vérifier toute erreur au cas où la fonction n'aurait pas réussi le renvoi du descripteur, nous obtiendrons une erreur INVALID_HANDLE. Nous utilisons la fonction Alerte pour afficher l'erreur à l'aide de GetlastError fonction.

//--- Let us handle currency pairs with 5 or 3 digit prices instead of 4
   STP = StopLoss;
   TKP = TakeProfit;
   if(_Digits==5 || _Digits==3)
     {
      STP = STP*10;
      TKP = TKP*10;
     }

Nous décidons de stocker les valeurs Stop Loss et Take Profit dans les variables STP et TKP que nous avons déclaré plus tôt. Pourquoi faisons-nous cela ?

C'est parce que les valeurs stockées dans les paramètres INPUT sont en lecture seule, ils ne peuvent pas être modifiés. Ici, nous voulons nous assurer que notre EA fonctionne très bien avec tous les courtiers. Chiffres ou Digits() returns le nombre de chiffres décimaux déterminant l'exactitude du prix du symbole graphique courant. Pour un graphique de prix à 5 ou 3 chiffres, nous multiplions à la fois le Stop Loss et le Take Profit par 10.

2.4. SECTION DÉINITIALISATION EA

 

Puisque cette fonction est appelée chaque fois que l'EA est désactivé ou supprimé d'un graphique, nous publierons tous les descripteurs d’indicateurs qui ont été créés pendant le processus d'initialisation ici. Nous avons créé deux descripteurs, un pour l'indicateur ADX et un autre pour l’indicateur de la moyenne mobile

Nous utiliserons la fonction IndicatorRelease() pour y parvenir. Cela ne demande qu’un seul argument (le descripteur de l’indicateur)

bool  IndicatorRelease(
   int       indicator_handle,     // descripteur de l’indicateur
   );

La fonction supprime un descripteur d'indicateur et relâche le bloc de calcul de l'indicateur, s'il n’a pas été utilisé.

2.5 LA SECTION ONTIC EA

La première chose que nous devons faire ici est de vérifier si nous avons suffisamment de barres sur le graphique actuel. Nous pouvons obtenir le total des barres dans l'historique de n'importe quel graphique à l'aide de la fonction Barres. Cela demande deux paramètres, le symbole (peut être obtenu en utilisant _Symbol or Symbol(). Ces deux renvoient le symbole courant pour le graphique actuel sur lequel notre EA est attaché) et la période ou le délai du graphique actuel (peut être obtenu en utilisant Period or Period(). Ces deux renverront le délai du graphique actuel auquel l'EA est joint).

Si le total des barres disponibles est inférieur à 60, nous voulons que notre EA se relaxe jusqu'à ce que nous ayons suffisamment de barres disponibles sur le graphique.  La fonction Alerte affiche un message dans une fenêtre séparée. Cela demande des valeurs séparées par des virgules sous forme de paramètres/arguments. Dans ce cas, nous n’avons qu’ une seule valeur de chaîne. Le retour sort de l'initialisation de notre EA.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Do we have enough bars to work with
   if(Bars(_Symbol,_Period)<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }
// We will use the static Old_Time variable to serve the bar time.
// At each OnTick execution we will check the current bar time with the saved one.
// If the bar time isn't equal to the saved time, it indicates that we have a new tick.
   static datetime Old_Time;
   datetime New_Time[1];
   bool IsNewBar=false;

// copying the last bar time to the element New_Time[0]
   int copied=CopyTime(_Symbol,_Period,0,1,New_Time);
   if(copied>0) // ok, the data has been copied successfully
     {
      if(Old_Time!=New_Time[0]) // if old time isn't equal to new bar time
        {
         IsNewBar=true;   // if it isn't a first call, the new bar has appeared
         if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("We have new bar here ",New_Time[0]," old time was ",Old_Time);
         Old_Time=New_Time[0];            // saving bar time
        }
     }
   else
     {
      Alert("Error in copying historical times data, error =",GetLastError());
      ResetLastError();
      return;
     }

//--- EA should only check for new trade if we have a new bar
   if(IsNewBar==false)
     {
      return;
     }
 
//--- Do we have enough bars to work with
   int Mybars=Bars(_Symbol,_Period);
   if(Mybars<60) // if total bars is less than 60 bars
     {
      Alert("We have less than 60 bars, EA will now exit!!");
      return;
     }

//--- Define some MQL5 Structures we will use for our trade
   MqlTick latest_price;     // To be used for getting recent/latest price quotes
   MqlTradeRequest mrequest;  // To be used for sending our trade requests
   MqlTradeResult mresult;    // To be used to get our trade results
   MqlRates mrate[];         // To be used to store the prices, volumes and spread of each bar
   ZeroMemory(mrequest);     // Initialization of mrequest structure

L'Expert Advisor effectuera des opérations de trades au début d'une nouvelle barre, il est donc nécessaire de résoudre le problème en identifiant la nouvelle barre. En d'autres termes, nous voulons être sûrs que notre EA ne vérifie pas les configurations Long/Short sur chaque trait, nous voulons seulement que notre EA vérifie les positions Long/Short lorsqu'il y a une nouvelle barre. 

Nous commençons par déclarer une variable datetime statique Old_Time, qui stockera l'heure de la barre. Nous l'avons déclaré statique car nous voulons que la valeur soit conservée en mémoire jusqu'au prochain appel de la fonction OnTick. Ensuite, nous pourrons comparer sa valeur avec la variable New_Time (également de type de données datetime), qui est un tableau d'un seul élément pour le maintien du temps de la barre new(current). Nous avons également déclaré une variable de type de données bool IsNewBar et paramétré sa valeur sur false. C'est parce que nous voulons que sa valeur soit TRUE uniquement lorsque nous avons une nouvelle barre.

Nous utilisons la fonction CopyTime pour obtenir l'heure de la barre actuelle. Elle copie l'heure de la barre dans le tableau New_Time à un seul élément ; s'il réussit, nous comparons le temps d'une nouvelle mesure avec le temps de la mesure précédente. Si les temps ne sont pas égaux, cela signifie que nous avons une nouvelle barre, et nous définissons la variable IsNewBar sur TRUE et sauvegardons la valeur de l'heure actuelle de la barre dans la variable Old_Time.

La variable IsNewBar indique que nous avons une nouvelle barre. En cas de FALSE, nous terminons l'exécution de la fonction OnTick.  

Considérons le code

if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("We have new bar here ",New_Time[0]," old time was ",Old_Time);

il vérifie l'exécution du mode de débogage, il imprimera le message sur les temps de barre en mode de débogage, nous l'examinerons plus loin.

La prochaine chose que nous voulons faire ici est de vérifier si nous avons suffisamment de barres pour les utiliser. Pourquoi le répéter ? Nous voulons juste nous assurer que notre EA fonctionnera correctement. Il convient de noter que si la fonction OnInit n'est appelée qu'une seule fois lorsque l'EA est lié à un graphique, que OnTick, en opérant, est appelé à chaque fois qu'il y a un nouveau trait (cotation de prix).

Vous constatez que nous l’avons fait encore différemment ici. Nous décidons de stocker le total des barres dans l'historique qui nous avons obtenu de l'expression

int Mybars=Bars(_Symbol,_Period);

dans une nouvelle variable, Mybars, déclarée dans la fonction OnTick. Ce type de variable est une variable locale, contrairement à la variable que nous avons déclaré dans la section INPUT PARAMETERS de notre code. Alors que les variables, déclarées dans la section Paramètres d'entrée de notre code, sont disponibles pour toutes les fonctions, dans notre code qui peut en avoir besoin, les variables déclarées dans une  fonction unique est limitée et disponible pour cette seule fonction. Cela ne peut pas être utilisé en dehors de cette fonction.

Ensuite, nous avons déclaré quelques variables de types de structure MQL5 qui seront utilisés dans cette section de notre EA. MQL5 a un certain nombre de structures intégrées qui rend les choses assez faciles pour les développeurs EA. Prenons les Structures un après L'autre.

MqlTick

Il s'agit d'une structure utilisée pour stocker les derniers prix des symboles.

struct MqlTick
  {
   datetime     time;          // Temps de la dernière mise à jour des prix
   double       bid;           // prix de l’offre courante
   double       ask;           // prix Ask courant
   double       last;          // Prix de la dernière transaction (Last)
   ulong        volume;        // Volume du dernier prix courant
  };

Toute variable déclarée de type MqlTick peut facilement être utilisée pour obtenir les valeurs courantes de Ask, Bid, Last et Volume une fois que vous appelez SymbolInfoTick() en exécution.

Nous avons donc déclaré latest_price comme un type MqlTick afin que nous puissions l’utiliser pour obtenir les prix Ask et Bid

MqlTradeRequest

Cette structure est utilisée pour effectuer toutes les demandes de trades en trading. Elle contient, dans sa structure, tous les champs nécessaires à la réalisation d'une transaction de trade.

struct MqlTradeRequest
  {
   ENUM_TRADE_REQUEST_ACTIONS    action;       // Type d’opération de trade
   ulong                         magic;        // Expert Advisor ID (magic number)
   ulong                         order;        // Ticket d’ordre
   string                        symbol;       // Symbole de trade
   double                        volume;       // Volume requis pour une transaction en lots
   double                        price;        // Prix
   double                        stoplimit;    // Niveau StopLimit de l’ordre
   double                        sl;           // Niveau Stop Loss de l’ordre
   double                        tp;           // Niveau Take Profit de l’ordre
   ulong                         deviation;    // Écart maximal possible par rapport au prix demandé
   ENUM_ORDER_TYPE               type;          // Type d’ordre
   ENUM_ORDER_TYPE_FILLING       type_filling;  // Type d’exécution d’ordre
   ENUM_ORDER_TYPE_TIME          type_time;     // Temps d’exécution de l’ordre
   datetime                      expiration;    // Temps d’expiration de l’ordre (pour les ordres de type ORDER_TIME_SPECIFIED)
   string                        comment;       // Commentaire sur ordres
  };

Toute variable déclarée de type MqlTradeRequest peut être utilisée afin d’ envoyer des ordres pour nos opérations de trade. Nous avons déclaré ici mrequest comme type de MqlTradeRequest.

MqlTradeResult

Le résultat de toute opération de trade est renvoyé sous forme de structure prédéfinie de type MqlTradeResult spéciale. Toute variable déclarée de type MqlTradeResult pourra accéder aux résultats de la demande de trade.

struct MqlTradeResult
  {
   uint     retcode;          // Code retour d’opération
   ulong    deal;             // Ticket de transaction, si elle est exécutée
   ulong    order;            // Ticket d’ordre, s’il est placé
   double   volume;           // Volume de transaction, confirmé par un courtier
   double   price;            // Prix de transaction, confirmé par un courtier
   double   bid;              // Prix Offre courante
   double   ask;              // Prix Ask courant
   string   comment;          // Commentaire du courtier sur l'opération (par défaut, il est rempli par la description de l'opération)
  };

Ici, nous avons déclaré mresult comme un type de MqlTradeResult.

MqlRates

Le prix (Open, Close, High, Low), l'Heure, les Volumes de chaque barre et le spread pour un symbole est stocké dans cette structure.  Tout tableau déclaré de type MqlRates peut être utilisé pour stocker l’historique de prix, de volumes et de spread d'un symbole.

struct MqlRates
  {
   datetime time;         // Temps du début de période
   double   open;         // Prix d’ouverture
   double   high;         // Le prix le plus élevé de la période
   double   low;          // Le prix le plus bas de la période
   double   close;        // Prix de clôture
   long     tick_volume;  // Volume de traits
   int      spread;       // Spread
   long     real_volume;  // Volume de trades
  };

Nous avons ici déclaré un tableau mrate[]   qui sera utilisé pour stocker ces informations.

/*
     Let's make sure our arrays values for the Rates, ADX Values and MA values 
     is store serially similar to the timeseries array
*/
// the rates arrays
   ArraySetAsSeries(mrate,true);
// the ADX DI+values array
   ArraySetAsSeries(plsDI,true);
// the ADX DI-values array
   ArraySetAsSeries(minDI,true);
// the ADX values arrays
   ArraySetAsSeries(adxVal,true);
// the MA-8 values arrays
   ArraySetAsSeries(maVal,true);

Ensuite, nous décidons de définir tous les tableaux que nous utiliserons pour stocker les détails des barres en séries. Cela permet de s'assurer que les valeurs qui seront copiées dans les tableaux seront indexées comme séries temporelles, c'est-à-dire 0, 1, 2, 3, (pour correspondre à l'indice des barres. Nous utilisons alors la fonction ArraySetAsSeries().

bool  ArraySetAsSeries(
   
void  array[],     // tableau par référence
   bool  set          // true indique l'ordre inverse de l'indexation
   );

Il serait bon de noter que cela peut également être fait une fois pour toutes dans la section d'initialisation de notre code Cependant, j'ai décidé de le montrer à ce stade à titre explicatif.

//--- Get the last price quote using the MQL5 MqlTick Structure
   if(!SymbolInfoTick(_Symbol,latest_price))
     {
      Alert("Error getting the latest price quote - error:",GetLastError(),"!!");
      return;
     }

Nous utilisons maintenant la fonction SymbolInfoTick pour obtenir la dernière cotation. Cette fonction prend deux arguments - graphique symbole et la variable MqlTick structurelle (latest_price). Encore une fois, s'il y a erreur, nous l'avons signalée.

//--- Get the details of the latest 3 bars
   if(CopyRates(_Symbol,_Period,0,3,mrate)<0)
     {
      Alert("Error copying rates/history data - error:",GetLastError(),"!!");
      return;
     }

Ensuite, nous avons copié les informations sur les trois dernières barres dans notre tableau de type Mqlrates à l'aide de la fonction CopyRates . La fonction CopyRates est utilisée pour obtenir les données historiques de la structure MqlRates d'une période de symbole spécifiée en quantité spécifiée dans un tableau de type MqlRates. 

int  CopyRates(
   string           symbol_name,       // nom de symbole
   ENUM_TIMEFRAMES  timeframe,         // période
   int              start_pos,         // position d’ouverture
   int              count,             // nombre de données à copier
   MqlRates         rates_array[]      // tableau cible à copier
   );

Le nom du symbole est obtenu en utilisant ‘_symbol’, le current period/timeframe est obtenu en utilisant ‘_period’. Pour la position d’ouverture, nous commencerons à partir de la barre actuelle, Barre 0 et nous compterons seulement trois barres, Barres 0, 1, et 2. Le résultat sera stocké dans notre tableau, mrate[].

Le tableau mrate[] contient maintenant toutes les informations sur le prix, l'heure, les volumes et le spread pour les barres 0 , 1 et 2.  Par conséquent, pour obtenir les détails d'une barre, nous utiliserons ce qui suit :

mrate[bar_number].bar_property

par exemple, nous pouvons avoir les informations suivantes sur chaque barre :

mrate[1].time    // Barre 1 Temps d’ouverture
mrate[1].open   // Barre 1 Prix d’ouverture
mrate[0].high   // Barre 0 (barre courante) prix High, etc.

Ensuite, nous avons copié toutes les valeurs de l'indicateur dans les tableaux dynamiques que nous avons déclarés à l'aide de la fonction CopyBuffer.

int  CopyBuffer(
   int       indicator_handle,     // descripteur d’indicateur
   int       buffer_num,           // nombre Tampon indicateur
   int       start_pos,            // position d’ouverture
   int       count,                // quantité à copier
   double    buffer[]              // tableau cible à copier
   );

Le descripteur d’indicateur est le descripteur que nous avons créé dans la section OnInit. Concernant le nombre des tampons, l'indicateur ADX a trois (3) tampons :

  • 0 - MAIN_LINE,
  • 1 - PLUSDI_LINE,
  • 2 - MINUSDI_LINE.

L’ indicateur de moyenne mobile n'a qu'un (1) tampon :

  • 0 – MAIN_LINE.

Nous copions de la barre actuelle (0) sur les deux dernières barres. Donc, le nombre de dossiers à copier est de 3 (barres 0, 1 et 2). Le buffer[] consiste dans les tableaux dynamiques cibles que nous avions précédemment déclarés – adxVal, plsDI, minDI et maVal.

Comme vous pouvez le voir ici encore, nous essayons de capturer toute erreur pouvant survenir lors de la copie. S'il y a erreur, inutile de continuer.

Il est important de noter que les fonctions CopyBuffer() et CopyRates() renvoient le nombre total de dossiers copiés en cas de succès alors qu'il renvoie -1 en cas d'erreur. C'est pourquoi nous recherchons une valeur inférieure à 0 (zéro) dans les fonctions de la vérification des erreurs, ici.

//--- Copy the new values of our indicators to buffers (arrays) using the handle
   if(CopyBuffer(adxHandle,0,0,3,adxVal)<0 || CopyBuffer(adxHandle,1,0,3,plsDI)<0
      || CopyBuffer(adxHandle,2,0,3,minDI)<0)
     {
      Alert("Error copying ADX indicator Buffers - error:",GetLastError(),"!!");
      return;
     }
   if(CopyBuffer(maHandle,0,0,3,maVal)<0)
     {
      Alert("Error copying Moving Average indicator buffer - error:",GetLastError());
      return;
     }

À ce stade, nous voulons vérifier si nous avons déjà une position d'achat ou de vente ouverte, en d'autres termes, nous voulons nous assurer que nous n'avons qu'UNE seule transaction de vente ou d'achat ouverte à la fois. Nous ne voulons pas ouvrir un nouvel Achat si nous en avons déjà un, et nous ne voulons pas ouvrir une nouvelle Vente si nous en avons déjà une ouverte.

Pour y parvenir, nous allons tout d'abord déclarer deux variables de type de données bool (Buy_opened et Sell_opened) qui contiendront une valeur TRUE si nous avons déjà une position ouverte pour Buy ou Sell.

//--- we have no errors, so continue
//--- Do we have positions opened already?
    bool Buy_opened=false;  // variable to hold the result of Buy opened position
    bool Sell_opened=false; // variable to hold the result of Sell opened position
    
    if (PositionSelect(_Symbol) ==true)  // we have an opened position
    {
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         {
            Buy_opened = true;  //It is a Buy
         }
         else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
         {
            Sell_opened = true; // It is a Sell
         }
    }

Nous utilisons la fonction de trading PositionSelect pour savoir si nous avons une position ouverte. Cette fonction renvoie TRUE si nous avons déjà une position ouverte et FALSE si nous n'en avons pas.

bool  PositionSelect(
   string  symbol      // Symbol name 
 );

Elle prend, comme argument/paramètre principal, le symbole (paire de devises) que nous voulons vérifier. Ici, nous utilisons _symbol car nous vérifions le symbole actuel (paire de devises).

Si cette expression renvoie VRAI, alors nous voulons vérifier si la position d’ouverture est un Buy ou Sell. Nous utilisons pour cela la fonction PositionGetInteger . elle nous donne le type de position ouverte lorsque nous l'utilisons avec le modificateur POSITION_TYPE. Elle renvoie l'identifiant du type de position qui peut être POSITION_TYPE_BUY ou POSITION_TYPE_SELL

long  PositionGetInteger(
   ENUM_POSITION_PROPERTY  property_id      // Property identifier
   );

Dans notre cas, nous l'avons utilisé pour déterminer laquelle des positions nous avons déjà ouvert. S'il s'agit d'une Sell, nous stockons une valeur TRUE dans Sell_opened et s'il s'agit d'une Buy, nous stockons une valeur TRUE dans Buy_opened. Nous pourrons utiliser ces deux variables plus tard lorsque nous vérifierons les conditions Sell ou Buy plus tard dans notre code.

Il est maintenant temps de stocker le prix de clôture pour la barre que nous utiliserons pour notre configuration Buy/Sell. N'oubliez pas que nous avons déclaré une variable pour cela plus tôt

// Copy the bar close price for the previous bar prior to the current bar, that is Bar 1

   p_close=mrate[1].close;  // bar 1 close price

Ainsi, nous allons maintenant passer à l'étape suivante.

/*
    1. Check for a long/Buy Setup : MA-8 increasing upwards, 
    previous price close above it, ADX > 22, +DI > -DI
*/
//--- Declare bool type variables to hold our Buy Conditions
   bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[1]>maVal[2]); // MA-8 Increasing upwards
   bool Buy_Condition_2 = (p_close > maVal[1]);         // previuos price closed above MA-8
   bool Buy_Condition_3 = (adxVal[0]>Adx_Min);          // Current ADX value greater than minimum value (22)
   bool Buy_Condition_4 = (plsDI[0]>minDI[0]);          // +DI greater than -DI

//--- Putting all together   
   if(Buy_Condition_1 && Buy_Condition_2)
     {
      if(Buy_Condition_3 && Buy_Condition_4)
        {
         // any opened Buy position?
         if (Buy_opened) 
         {
            Alert("We already have a Buy Position!!!"); 
            return;    // Don't open a new Buy Position
         }
         mrequest.action = TRADE_ACTION_DEAL;                                // immediate order execution
         mrequest.price = NormalizeDouble(latest_price.ask,_Digits);          // latest ask price
         mrequest.sl = NormalizeDouble(latest_price.ask - STP*_Point,_Digits); // Stop Loss
         mrequest.tp = NormalizeDouble(latest_price.ask + TKP*_Point,_Digits); // Take Profit
         mrequest.symbol = _Symbol;                                         // currency pair
         mrequest.volume = Lot;                                            // number of lots to trade
         mrequest.magic = EA_Magic;                                        // Order Magic Number
         mrequest.type = ORDER_TYPE_BUY;                                     // Buy Order
         mrequest.type_filling = ORDER_FILLING_FOK;                          // Order execution type
         mrequest.deviation=100;                                            // Deviation from current price
         //--- send order
         OrderSend(mrequest,mresult);

Il est maintenant temps de commencer à rechercher une opportunité Buy.

Analysons l'expression ci-dessus, vu qu'elle représente la stratégie que nous avons conçue plus tôt. Nous déclarons une variable de type bool pour chacune de nos conditions qui doivent être remplies avant qu'un ordre puisse être passé. Une variable de type bool ne peut contenir que TRUE ou FALSE. Ainsi, notre stratégie Buy a été décomposée en quatre conditions.  Si l'une des conditions est remplie ou satisfaite, alors une valeur TRUE est stockée dans notre variable de type bool, sinon, une valeur FALSE sera stockée. Examinons-les une par une.

bool Buy_Condition_1 = (maVal[0]>maVal[1]) && (maVal[1]>maVal[2]);

Ici, nous examinons les valeurs MA-8 sur Barres 0, 1 et 2. Si la valeur de MA-8 sur la barre actuelle est supérieure à sa valeur sur la Barre 1 précédente et aussi la valeur MA-8 sur Barre 1 est supérieure à sa valeur sur Barre 2, cela signifie que MA-8 a une tendance haussière. Cela satisfait l'une des nos conditions pour une configuration Buy.

bool Buy_Condition_2 = (p_close > maVal[1]); 

Cette expression vérifie si le prix de clôture Barre 1 est supérieur à la valeur de MA-8 à la même période (période de la barre 1). Si le prix est plus élevé, alors notre deuxième condition a également été satisfaite, alors nous pouvons vérifier d'autres conditions. Cependant, si les deux conditions que nous venons de considérer n'étaient pas remplies, alors il n'y aura pas besoin de vérifier d'autres conditions. C'est pourquoi nous décidons d'inclure les expressions suivantes dans ces deux conditions initiales (expressions).

bool Buy_Condition_3 = (adxVal[0]>Adx_Min);

Maintenant, nous voulons vérifier si la valeur actuelle de l'ADX (valeur ADX sur la barre 0) est supérieure à la valeur minimale ADX déclarée dans les paramètres d’entrée. Si cette expression est vraie, c'est-à-dire la valeur actuelle de l'ADX est supérieure à la valeur minimale requise ; Nous voudrions aussi nous assurer que la valeur plusDI est supérieure à minusDI en valeur. C'est ce que nous avons obtenu dans l'expression suivante

bool Buy_Condition_4 = (plsDI[0]>minDI[0]);

Si toutes ces conditions sont remplies, c'est-à-dire si elles retournent vrai, alors nous nous assurerons de ne pas ouvrir une nouvelle position Buy si nous en avons déjà une. Il est maintenant temps de vérifier la valeur de la variable Buy_opened que nous avons déclarée précédemment dans notre code.

// any opened Buy position?
if (Buy_opened) 
   {
      Alert("We already have a Buy Position!!!"); 
      return;    // Don't open a new Buy Position
   }

Si Buy_opened est vrai, nous ne voudrions pas ouvrir une autre position Buy, nous affichons donc une alerte pour nous en informer puis revenons afin que notre EA attende maintenant le prochain Trait. Cependant, si Buy_opened est FALSE, alors nous préparons nos dossiers en utilisant la variable MqlTradeRequest de type (mrequest) que nous avons déclarée précédemment pour envoyer notre ordre.

  • L'action ici, qui est le type d'opération de trade, est TRADE_ACTION_DEAL car nous sommes en train de passer un ordre de trade pour exécution immédiate. Si nous modifions un ordre, alors nous utiliserons TRADE_ACTION_MODIFY. Pour supprimer un ordre, nous utiliserons TRADE_ACTION_MODIFY.  Nous avons utilisé notre type MqlTick latest_price pour obtenir le dernier prix Ask.  Le prix de l’ordre Stop Loss est obtenu en soustrayant notre StopLoss en termes de points du prix Ask tandis que le prix de l’ordre take profit est obtenu en ajoutant notre TakeProfit en termes de points au prix Ask Vous remarquerez également que nous avons utilisé la fonction NormalizeDouble pour le prix Ask, les valeurs StopLoss et TakeProfit, il est de bonne pratique de toujours normaliser ces prix au nombre de chiffres de la paire de devises avant de l'envoyer au serveur de trading.
  • Le symbole est le symbole courant (_Symbol ou Symbol()). L’ordre type est le type d’ordre que nous passons, ici nous passons un ordre buy ORDER_TYPE_BUY. Pour un ordre Sell, ce sera ORDER_TYPE_SELL.
  • L’ordre type_filling est le type de l'exécution de l’ordre ; ORDER_FILLING_FOK signifie que la transaction peut être exécutée exclusivement avec un volume spécifié à un prix égal ou supérieur au prix spécifié dans l'ordre. S'il n'y a pas suffisamment de volume d'offres sur le symbole de l'ordre, l'ordre ne sera pas exécuté.

La fonction OrderSend() prend deux arguments, la variable type MqlTradeRequest et la variable de type MqlTradeResult.

bool  OrderSend(
   MqlTradeRequest&  request      // query structure
   MqlTradeResult&   result       // structure of the answer
   );

Comme vous pouvez le voir, nous avons utilisé notre variable type MqlTradeRequest et la variable type MqlTradeResult en passant notre ordre via OrderSend.

         // get the result code
         if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
           {
            Alert("A Buy order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
         else
           {
            Alert("The Buy order request could not be completed -error:",GetLastError());
            ResetLastError();           
            return;
           }

Après avoir envoyé notre ordre, nous allons maintenant utiliser la variable de type MqlTradeResult pour vérifier le résultat de notre ordre. Si notre ordre est exécuté avec succès, nous sommes intéressés à le savoir, et si non, nous voulons également le savoir. Avec la variable de type MqlTradeResultmresult’ nous pouvons accéder au code retour de l'Opération ainsi qu'au numéro du ticket d’ordre si l’ordre est passé.

Le code retour 10009 indique que la demande OrderSend s’est clôturée avec succès, tandis que 10008 montre que notre ordre a été passé. C'est pourquoi nous avons vérifié l'un de ces deux codes retour. Si nous avons l’un d’entre eux, nous sommes sûrs que notre ordre s’est clôturé ou qu’il a été passé.

Pour vérifier une opportunité Sell, nous vérifions le contraire de ce que nous avons fait pour l’opportunité Buy sauf pour notre ADX qui doit être supérieur à la valeur Minimum précisée.

/*
    2. Check for a Short/Sell Setup : MA-8 decreasing downwards, 
    previous price close below it, ADX > 22, -DI > +DI
*/
//--- Declare bool type variables to hold our Sell Conditions
   bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal[1]<maVal[2]);  // MA-8 decreasing downwards
   bool Sell_Condition_2 = (p_close <maVal[1]);                         // Previous price closed below MA-8
   bool Sell_Condition_3 = (adxVal[0]>Adx_Min);                         // Current ADX value greater than minimum (22)
   bool Sell_Condition_4 = (plsDI[0]<minDI[0]);                         // -DI greater than +DI
   
 //--- Putting all together
   if(Sell_Condition_1 && Sell_Condition_2)
       {
         if(Sell_Condition_3 && Sell_Condition_4)
           {
            // any opened Sell position?
            if (Sell_opened) 
            {
                Alert("We already have a Sell position!!!"); 
                return;    // Don't open a new Sell Position
            }
            mrequest.action = TRADE_ACTION_DEAL;                                 // immediate order execution
            mrequest.price = NormalizeDouble(latest_price.bid,_Digits);          // latest Bid price
            mrequest.sl = NormalizeDouble(latest_price.bid + STP*_Point,_Digits); // Stop Loss
            mrequest.tp = NormalizeDouble(latest_price.bid - TKP*_Point,_Digits); // Take Profit
            mrequest.symbol = _Symbol;                                         // currency pair
            mrequest.volume = Lot;                                            // number of lots to trade
            mrequest.magic = EA_Magic;                                        // Order Magic Number
            mrequest.type= ORDER_TYPE_SELL;                                     // Sell Order
            mrequest.type_filling = ORDER_FILLING_FOK;                          // Order execution type
            mrequest.deviation=100;                                           // Deviation from current price
            //--- send order
            OrderSend(mrequest,mresult);

Tout comme nous l'avons fait dans la section acheter, nous déclarons une variable de type bool pour chacune de nos conditions qui doit être remplie avant qu'un ordre puisse être passé. Une variable de type bool ne peut contenir que TRUE ou FALSE. Ainsi, notre stratégie Sell a été décomposée en quatre conditions.  Si l'une des conditions est remplie ou satisfaite, alors une valeur TRUE est stockée dans notre variable de type bool, sinon, une valeur FALSE sera stockée. Examinons-les une par une comme nous l'avons fait pour la section Buy

   bool Sell_Condition_1 = (maVal[0]<maVal[1]) && (maVal[1]<maVal[2]);

Ici, nous examinons les valeurs MA-8 sur Barres 0, 1 et 2. Si la valeur de MA-8 sur la barre actuelle est inférieure à sa valeur sur la Bar 1 précédente et aussi la valeur MA-8 sur la Bar 1 est inférieure à sa valeur sur Bar 2, cela signifie que MA-8 accuse une tendance baissière. Cela satisfait l'une de nos conditions pour une configuration Sell.

   bool Sell_Condition_2 = (p_close <maVal[1]); 

Cette expression vérifie si le prix de Clôture Bar 1 est inférieur à la valeur de MA-8 à la même période (Bar 1 period) Si le prix est inférieur, alors notre deuxième condition a également été satisfaite, alors nous pouvons vérifier d'autres conditions. Cependant, si les deux conditions que nous venons de considérer n'étaient pas remplies, il n'y aura pas lieu de vérifier les autres conditions. C'est pourquoi nous décidons d'inclure les expressions suivantes dans ces deux conditions (expressions) initiales.

   bool Sell_Condition_3 = (adxVal[0]>Adx_Min); 

Maintenant, nous voulons vérifier si la valeur actuelle de l'ADX (valeur ADX sur la barre 0) est supérieure à la valeur minimale ADX déclarée dans les paramètres d’entrée. Si cette expression est vraie, c'est-à-dire la valeur actuelle de l'ADX est supérieure à la valeur minimale requise ; Nous voudrions veulent être sûrs que la valeur MinusDI est supérieure à plusDI en valeur. C'est ce que nous avons obtenu dans l'expression suivante

bool Sell_Condition_4 = (plsDI[0]<minDI[0]);

Si ces conditions sont remplies, c'est-à-dire si elles retournent True, alors nous voulons être sûrs de ne pas ouvrir une nouvelle position Buy si nous en avons déjà une. Il est maintenant temps de vérifier la valeur de la variable Buy_opened que nous avons déclarée précédemment dans notre code.

// any opened Sell position?
            if (Sell_opened) 
            {
                Alert("We already have a Sell position!!!"); 
                return;    // Don't open a new Sell Position
            }

Si Sell_opened est True, nous ne voulons pas ouvrir une autre position Sell, nous affichons donc une alerte pour nous en informer, puis revenons afin que notre EA attende maintenant le prochain Trait. Cependant, si Sell_opened est FALSE, alors nous configurons notre demande de trade Sell comme nous l'avons fait pour l'ordre Buy.

La principale différence ici est la façon dont nous avons calculé notre prix stop loss et take profit. Aussi puisque nous sommes dans le processus de vente, nous vendons au prix Bid ; c'est pourquoi nous avons utilisé notre variable type MqlTick latest_price pour obtenir le dernier prix bid. L'autre type ici, comme expliqué précédemment, est ORDER_TYPE_SELL.

Ici aussi, nous avons utilisé la fonction NormalizeDouble pour le prix Bid, les valeurs StopLoss et TakeProfit, il est recommandé de toujours normaliser ces prix par rapport au nombre de chiffres de la paire de devises avant de l'envoyer au serveur de trading.

Tout comme nous l'avons fait pour notre ordre Buy, nous devons vérifier également si notre ordre Sell est réussi ou non. Nous avons donc utilisé la même expression comme dans notre ordre Sell.

         if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
           {
            Alert("A Sell order has been successfully placed with Ticket#:",mresult.order,"!!");
           }
         else
           {
            Alert("The Sell order request could not be completed -error:",GetLastError());
            ResetLastError();
            return;
           }
        }


3. Débogage et test de notre Expert Advisor

À ce stade, nous devons tester notre EA pour savoir si notre stratégie fonctionne ou non. Aussi, il est possible qu'il y ait une ou deux erreurs dans notre code EA. Cela sera découvert à l'étape suivante.

3.1 DÉBOGAGE

Le débogage de notre code nous aide à voir comment notre code s’exécute ligne par ligne (si nous définissons des points d'arrêt) et à ce moment-là nous pouvons constater toute erreur ou bogue dans notre code et apporter rapidement les corrections nécessaires avant d'utiliser notre code dans un trade réel.

Ici, nous allons passer par le processus étape par étape de débogage de notre Expert Advisor, tout d'abord, en définissant des points d'arrêt et ensuite, sans points d'arrêt. Pour ce faire assurez-vous que vous n'avez pas fermé l'éditeur. Tout d'abord, sélectionnons le graphique que nous voulons utiliser pour tester notre EA. Dans la barre de menu de l'éditeur, cliquez sur Tools et cliquez sur Options comme indiqué ci-dessous :

Figure 8. Définition des options de débogage

Figure 8. Définition des options de débogage 

Une fois la fenêtre Options affichée, sélectionnez la paire de devises et la période/délai à utiliser et cliquez sur le bouton OK :

Figure 9. Fenêtre des options du débogueur

Avant de démarrer le débogueur, configurons les points d'arrêt. Les Breakpoints nous permettent de surveiller le comportement/performance de notre code à certains emplacements ou lignes sélectionnés. Plutôt que de parcourir tout le code à la fois, le débogueur s'arrêtera chaque fois qu'il verra un point d'arrêt, dans l’attente de votre action spécifique. Grâce à cela, nous pourrons analyser notre code et surveiller son comportement lorsqu'il atteint tous les points d'arrêt définis. Nous pourrons également évaluer les valeurs de certaines de nos variables pour voir si les choses se déroulent effectivement comme nous l’avons envisagé.

Pour insérer un point d'arrêt, accédez à la ligne de votre code où vous souhaitez configurer le point d'arrêt. À gauche, sur le champ gris au bord de la ligne de code, double-cliquez et vous verrez un petit bouton bleu rond avec un carré blanc à l'intérieur. Vous pouvez également placer le curseur de votre souris n'importe où sur la ligne de code où vous voulez que le point d'arrêt apparaisse et vous appuyez sur F9. Pour supprimer le point d'arrêt, appuyez à nouveau sur F9 ou double-cliquez dessus.

Figure 10. Configuration d'un point d'arrêt

Figure 10. Configuration d’un point d'arrêt

Pour notre code, nous allons configurer le point d'arrêt sur cinq lignes différentes. 

Je vais aussi étiqueter les formulaires 1 à 5 à titre explicatif.

Pour continuer, configurez le point d'arrêt aux sept lignes de code, comme indiqué dans la figure ci-dessous. Le point d'arrêt 1  est celui que nous avons créé ci-dessus.

Figure 11. Configuration de points d'arrêt supplémentaires

Figure 11. Configuration de points d'arrêt supplémentaires

Une fois que nous avons fini la configuration de notre points d'arrêt, nous sommes maintenant prêts à commencer à déboguer notre code.

Pour démarrer le débogueur, appuyez sur F5 ou cliquez sur le bouton vert de la barre d'outils de MetaEditor :

 Figure 12. Démarrage du débogueur

Figure 12. Démarrage du débogueur

La première chose que fait l'éditeur est de compiler le code, s'il y a une erreur à ce point, il l'affichera, sinon il vous informera que le code a été compilé avec succès.

Figure 13. Rapport de compilation

Figure 13. Rapport de compilation

Veuillez noter que le fait que le code compilé avec succès ne signifie pas qu'il ne peut pas y avoir d'erreurs dans votre code. Selon la façon dont votre code est écrit, il peut y avoir des erreurs d'exécution. Par exemple, si l'une de nos expressions ne s'évalue pas correctement en raison d'un petit oubli, le code compilera correctement mais risque de ne pas s'exécuter correctement. Trop de discours, voyons-le en action…

Une fois que le débogueur a fini de compiler le code, il vous achemine vers le terminal de trading, et attache l'EA au graphique que vous avez spécifié dans les paramètres des options de MetaEditor. En même temps, il vous affiche la section Paramètres d'entrée de l'EA. Puisque rien n’a pas encore été configuré, cliquez simplement sur le bouton OK.

Figure 14. Paramètres de l'entrée d'Expert Advisor pour débogage

Figure 14. Paramètres d'entrée de l'Expert Advisor pour débogage

Vous verrez maintenant s’afficher clairement l'EA au coin supérieur droit du graphique.

Une fois qu'il démarre le OnTick(), il ne s'arrêtera que lorsqu’il aura atteint notre point d'arrêt 1.

Figure 15. Le débogueur s'arrête au premier point d'arrêt

Figure 15. Le débogueur s'arrête au premier point d'arrêt

Vous remarquerez une flèche verte à cette ligne de code. Cela vous indique que la ligne de code précédente a été exécutée ; nous sommes maintenant prêt à exécuter la ligne courante.

Permettez-moi de donner quelques explications avant d’aller plus loin. Si vous regardez la barre d'outils de l'éditeur, vous remarquerez que les trois les boutons avec des flèches courbes, celles qui étaient auparavant grisés, sont maintenant activés. C'est parce que nous exécutons maintenant le débogueur. Ces boutons/commandes sont utilisé pour parcourir notre code (Step into, Step over ou Step out)

Figure 16. Contrôle des commandes

Figure 16. Contrôle des commandes

Le Step Into est utilisé pour naviguer d'une étape de l'exécution du programme à l'étape suivante, tout en entrant dans toutes les fonctions appelées dans cette ligne de code. Cliquez sur le bouton ou appuyez sur F11 pour actionner la commande. (Nous utiliserons cette commande dans notre débogage graduel de notre code.)

Figure 17. Commande Step over

Figure 17. Commande graduelle

Le Step over, en revanche, n’ entre pas dans n'importe quelle fonction appelée dans cette ligne de code. Cliquez sur le bouton ou appuyez sur F10 pour actionner la commande

Figure 18. Commande Step out

Figure 18. Commande Step out

Pour exécuter une étape de programme d’un niveau supérieur, vous cliquez sur ce bouton ou appuyez sur Shift+F11.

Aussi, dans la partie inférieure de l'éditeur, vous verrez la fenêtre Boîte à outils. L'onglet Déboguer dans cette fenêtre a les titres suivants :

  • Fichier : Cela affiche le nom du fichier appelé
  • Fonction : Cela affiche la fonction courante du fichier qui est appelé
  • Ligne : Cela affiche le numéro de la ligne de code dans le fichier à partir duquel la fonction est appelée.
  • Expression : C'est ici que vous pouvez taper le nom de toute expression/variable pour laquelle vous souhaiteriez assurer le suivi dans notre code. 
  • Valeur : Cela affichera la valeur de la variable/expression que nous avons tapé au niveau de la zone Expression.
  • Type : Cela affichera le type de données de la variable/expression pour laquelle on assure le suivi.

Retour à notre processus de débogage…

La prochaine chose que nous voulons faire est maintenant de taper les variables/expressions de notre code qui nous intéressent à suivre. Assurez-vous de ne suivre que les variables/expressions qui importe dans votre code. Pour notre exemple, nous ferons le suivi de ce qui suit :

  • Old_Time (ancienne heure de la barre)
  • New_Time[0] (heure de la barre actuelle)
  • IsNewBar (drapeau indiquant la nouvelle barre)
  • Mybars (Total des barres dans l'historique) - Notre EA en dépend

Vous pouvez en rajouter comme par exemple, les valeurs ADX, les valeurs MA-8, etc.

Pour ajouter l'expression/variable, double-cliquez sous la zone Expressions ou cliquez sur le bouton droit sous la zone Expressions et sélectionnez Ajouter comme indiqué dans la figure ci-dessus.

Tapez sur l'expression/variable à suivre ou surveiller.

Figure 19. La fenêtre de visualisation des expressions

Figure 19. La fenêtre de visualisation des expressions

Tapez sur l’ensemble des variables/expressions nécessaires…

Figure 20. Ajout d'expressions ou de variables à surveiller

Figure 20. Ajout d'expressions ou de variables à surveiller

Si la variable n'a pas encore été déclarée, son type est "Identifiant inconnu" (sauf les variables statiques).

Maintenant, passons à autre chose…

Figure 21. Actionnement de la commande Step into

Figure 21. Actionnement de la commande Step into

Cliquez sur le bouton Step into ou appuyez sur F11  et observez ce qui se passe. Continuez à appuyer sur ce bouton ou sur F11 jusqu'à ce que vous arriviez au point d'arrêt n° 2, continuez jusqu'à ce que vous arriviez au point d'arrêt n ° 4 comme indiqué ci-dessous et observez en expressions la fenêtre de visualisation.


Figure 22. Visualisation des expressions ou des variables

Figure 22. Visualisations des expressions ou des variables

Figure 23. Visualisation des expressions ou des variables

Figure 23. Visualisation des expressions ou des variables

Figure 24. Visualisation des expressions ou des variables

Figure 24. Visualisation des expressions ou des variables

Une fois qu'il y a un nouveau trait, il y aura un retour à la première ligne de code de la fonction OnTick(). Et toutes les valeurs de nos variables/expressions seront alors réinitialisées car il s'agit d'un nouveau trait, sauf si l'une d'elles est déclarée comme une variable statique. Dans notre cas, nous avons une variable statique Old_Time.

Figure 25. Valeurs des variables sur l'événement NewTick

Figure 25. Valeurs des variables sur l'événement NewTick

Pour relancer le processus, continuez à appuyer sur la touche  F11 et continuer à surveiller les variables dans la fenêtre de visualisation des expressions. Vous pouvez arrêter le débogueur, puis supprimer l’ensemble des points d'arrêt.

Comme nous le voyons, en mode Debug, le message qui s’affiche est le suivant « Nous avons une nouvelle barre ici... ».

Figure 26. Expert Advisor imprime le message en mode Debug

Figure 26. Expert Advisor imprime le message en mode Debug

Redémarrez le processus de débogage ; mais cette fois sans points d'arrêt. Continuez à surveiller chaque trait et si l'une de nos conditions Buy/Sell est remplie, un trade sera placé et puisque nous avons instruit notre code pour nous signaler si un ordre est passé avec succès ou non, nous verrons une alerte.

Figure 27. Expert Advisor effectue des transactions pendant le débogage

Figure 27. Expert Advisor place le trade durant le débogage

Je pense que vous pouvez laisser l'EA travailler encore quelques minutes pendant que vous prenez un café. Une fois que vous êtes de retour et que vous avez fait un peu d'argent (juste une blague), cliquez alors sur le bouton STOP (rouge) du MetaEditor pour arrêter le débogage.

Figure 28. Arrêt du débogueur

Figure 28. Arrêt du débogueur

En fait, ce que nous avons fait ici, c'est de voir que notre EA ne vérifie un trade qu'à l'ouverture d'une nouvelle barre et que notre EA fonctionne effectivement. Il y a encore tant d’opportunités d’aménagement dans le paquet des ajustements de notre code EA.

Permettez-moi de préciser, à ce stade, que, le terminal de trading doit être connecté à Internet, sinon, le débogage ne fonctionnera pas, car le terminal ne saura pas trader.

3.2 TESTER NOTRE STRATÉGIE EA

À ce stade, nous voudrions maintenant tester notre EA en utilisant le Testeur de Stratégie intégré au Terminal de Trading.  Pour démarrer le Testeur de stratégie, appuyez sur CONTROL+R ou cliquez sur le menu View dans la barre de menus du terminal et cliquez sur Testeur de stratégie comme indiqué ci-dessous

Figure 26. Démarrage du test de stratégie

Figure 26. Lancement du test de stratégie

Le testeur (testeur de stratégie) est affiché dans la partie inférieure du terminal. Pour que vous puissiez voir tous les paramètres du testeur, il vous faut l'agrandir/redimensionner. Pour ce faire, déplacez le pointeur de votre souris vers le point indiqué par la flèche rouge (comme indiqué ci-dessous)

Figure 27. La fenêtre du Testeur de stratégie

Figure 27. La fenêtre du Testeur de stratégie

Le pointeur de la souris se transforme en une fenêtre à deux extrémités extrémités, maintenez la souris enfoncée et faites glisser la ligne vers le haut. Arrêtez-vous quand vous découvrez que vous pouvez tout voir dans l'onglet Paramètres. 

Figure 28. L'onglet Paramètres du testeur de stratégie

Figure 28. L'onglet Paramètres du testeur de stratégie

  1. Sélectionnez l'EA que vous souhaitez tester
  2. Sélectionnez la paire de devises à utiliser pour le test
  3. Sélectionnez la période/délai à utiliser pour le test
  4. Sélectionnez Période personnalisée et configurez les dates dans 5
  5. Configurez les dates de la période personnalisée à utiliser pour le test
  6. L'exécution est normale
  7. Sélectionnez le montant du dépôt en USD à utiliser pour le test
  8. Configurez l'optimisation sur Désactiver (nous n'optimisons pas maintenant, nous voulons juste tester)
  9. Cliquez sur ce bouton lorsque vous êtes prêt à commencer le test.

Avant de cliquer sur le bouton Démarrer, vérifiez les autres onglets sur le testeur

Onglet Agents

Le processeur utilisé par le testeur pour le test selon le type de processeur de votre ordinateur. Le mien n'est qu'un (1) processeur One Core.

Figure 29. L'onglet Strategy Tester Agents

Figure 29. L'onglet Agents du testeur de stratégie

Une fois que l'agent boucle, vous verrez quelque chose similaire à la figure ci-dessous

Figure 30. L'onglet Strategy Tester Agents pendant un test

Figure 30. L'onglet Strategy Tester Agents pendant un test

Onglet Journal

Tous les événements se déroulant pendant la période de test sont affichés ici

Figure 31. L'onglet Strategy Tester Journal affichant les activités de trade

Figure 31. L'onglet Strategy Tester Journal affichant les activités de trade

Onglet Entrées

C'est ici que vous pouvez spécifier les paramètres d’entrée pour l'EA.

Figure 32. L'onglet Strategy Tester Inputs

Figure 32. L'onglet Entrées du testeur de stratégie

Si nous optimisons notre EA, nous devrons alors configurer les valeurs dans la zone encerclée.

  • The Start représente valeurs par lesquelles le testeur doit commencer.
  • The Step représente le taux d'incrémentation de la valeur sélectionnée, et
  • The Stop représente la valeur à laquelle le testeur cesse d'incrémenter la valeur de ce paramètre.

Cependant, dans notre cas, il ne s’agit pas d’une optimisation de notre EA, nous n'aurons donc pas besoin d'y toucher pour l'instant. 

Une fois que tout est réglé, nous revenons maintenant à l'onglet Paramètres pour cliquer sur le bouton Démarrer Alors, le testeur commence son travail. Tout ce que vous devez faire maintenant est d'aller prendre une autre tasse de café si vous le souhaitez, ou, si vous êtes comme moi, vous pouvez vouloir surveiller chaque événement, pour en fin de compte vous acheminer vers le Journal dans l’onglet. 

Onglet Graphique

Une fois que vous commencez à voir les messages concernant les ordres envoyés dans l'onglet Journal, vous pouvez alors vous tourner vers un NOUVEL onglet nommé Graph qui vient d'être créé. Une fois que vous avez navigué vers l’onglet Graph, vous verrez le graphique continuer à monter ou à descendre selon le cas en fonction du résultat de vos trades.

Figure 33. Le résultat du graphique pour le test Expert Advisor

Figure 33. Le résultat du graphique pour le test Expert Advisor

Onglet Résultats

Une fois le test terminé, vous verrez un autre onglet appelé Résultats. Passez à l'onglet Résultats et vous verrez le résumé du test que nous venons d'effectuer.

Figure 34. L'onglet Strategy Tester Results affichant le résumé des résultats du test

 Figure 34. L'onglet Strategy Tester Results affichant le résumé des résultats du test

Vous pouvez voir le bénéfice brut total, le bénéfice net, le total des transactions, les pertes totales et bien d'autres choses. C'est vraiment intéressant de voir que nous avons environ 1 450,0 dollars américains dans la période que nous avons sélectionnée pour notre test. Au moins, nous avons des bénéfices.

Permettez-moi de vous dire quelque chose de très clair ici. Vous découvrirez que la configuration des paramètres EA que vous voyez dans le testeur de stratégie est différente de la configuration initiale dans les paramètres d'entrée de l'EA. Je viens de vous démontrer que vous pouvez modifier n'importe lequel de ces paramètres d'entrée pour tirer le meilleur parti de votre EA. Au lieu d'utiliser une période de 8 chacune pour la moyenne mobile et l'ADX, je l'ai changée en 10 pour la moyenne mobile et 14 pour l'ADX. Je change également le Stop Loss de 30 à 35. Dernier point mais non le moindre, j'ai décidé d'utiliser un délai de 2 heures. N'oubliez pas qu'il s'agit du testeur de stratégie.

Si vous souhaitez consulter un rapport complet du test, alors effectuez un clic droit n'importe où dans l'onglet Résultats, vous verrez un menu. Dans ce menu, sélectionnez 'Enregistrer sous forme de Rapport’.

Figure 35. Enregistrement du résultat du test

Figure 35. Enregistrement du résultat du test

La fenêtre de dialogue d'enregistrement apparaîtra, saisissez un nom pour votre rapport (si vous le souhaitez, sinon laissez le nom par défaut) et cliquez sur le bouton Enregistrer. L'ensemble du rapport sera enregistré au format HTML pour vous.

Pour afficher le graphique du test qui a été effectué, cliquez sur Ouvrir le graphique et vous verrez le graphique affiché

Figure 36. Le graphique affichant le test 

Figure 36. Le graphique affichant le test

Ça y est, nous avons écrit et testé avec succès notre EA et nous avons maintenant un résultat avec lequel travailler. Vous pouvez maintenant revenir à l'onglet Paramètres du testeur de stratégie et effectuer le test pour d'autres délais/périodes.

Devoir

Je veux que vous effectuiez le test en utilisant différentes paires de devises, différents délais, différents Stop Loss, différents Take profit pour voir comment l'EA fonctionne. Vous pouvez même essayer de nouvelles valeurs de moyenne mobile et d'ADX. Comme je l'ai dit plus tôt, c'est l'essence du testeur de stratégie. J'aimerai aussi que vous partagiez vos résultats avec moi.

Conclusion

Dans ce guide étape par étape, nous avons pu examiner les étapes de base nécessaires à la rédaction d'un simple Expert Advisor sur la base d'une stratégie de trading développée. Nous avons également examiné comment nous vérifions notre EA pour détecter les erreurs à l'aide du débogueur. Nous avons également discuté de la façon de tester les performances de notre EA à l'aide du Testeur de stratégie. Avec cela, nous avons pu constater la puissance et la robustesse du nouveau langage MQL5. Notre EA n'est pas encore parfait ou complet car de nombreux autres ajustements doivent encore être effectués afin de l'utiliser pour le trading réel.

Il y a encore plus à apprendre et je veux que vous relisiez l'article avec le manuel MQL5 et que vous essayiez tout ce que vous avez appris dans cet article, je peux vous assurer que vous deviendrez un grand développeur EA dans un avenir proche.

Bon codage.


Traduit de l’anglais par MetaQuotes Ltd.
Article original : https://www.mql5.com/en/articles/100

Fichiers joints |
my_first_ea.mq5 (11.86 KB)
Création d'un panneau d'information à l'aide des classes de bibliothèque standard et de l'API Google Chart Création d'un panneau d'information à l'aide des classes de bibliothèque standard et de l'API Google Chart
Le langage de programmation MQL5 cible principalement la création de systèmes de trading automatisés et d'instruments complexes d'analyses techniques. Mais en dehors de cela, cela nous permet de créer des systèmes d'information intéressants pour suivre les situations de marché, et fournit une connexion retour avec le trader. L'article décrit les composants de la bibliothèque standard MQL5 et montre des exemples de leur utilisation pratique pour atteindre ces objectifs. Il montre également un exemple d'utilisation de l'API Google Chart pour la création de graphiques.
Nouvelles opportunités avec MetaTrader 5 Nouvelles opportunités avec MetaTrader 5
MetaTrader 4 a gagné en popularité auprès des traders du monde entier, et il semblait que rien de plus ne pouvait être souhaité. Avec sa vitesse de traitement élevée, sa stabilité, son large éventail de possibilités d'écriture d'indicateurs, d'Expert Advisors et de systèmes de trading informatifs, et la possibilité de choisir parmi plus d'une centaine de courtiers différents, le terminal s'est grandement distingué des autres. Mais le temps ne s'arrête pas et nous nous trouvons face à un choix de MetaTrade 4 ou MetaTrade 5. Dans cet article, nous décrirons les principales différences du terminal de 5ème génération par rapport à notre actuel favori.
Fonctions de gestion monétaire dans un Expert Advisor Fonctions de gestion monétaire dans un Expert Advisor
Le développement de stratégies de trading se concentre principalement sur la recherche de modèles d’entrée et de sortie du marché, ainsi que sur le maintien des positions. Si nous sommes en mesure de formaliser certains modèles dans des règles de trading automatisé, alors le trader est confronté à la question de calculer le volume des positions, la taille des marges, ainsi que de maintenir un niveau sûr de fonds hypothécaires pour assurer des positions ouvertes en mode automatisé. Dans cet article, nous utiliserons le langage MQL5 pour construire des exemples simples de réalisation de ces calculs.
Création d'indicateurs à graduations dans MQL5 Création d'indicateurs à graduations dans MQL5
Dans cet article, nous allons envisager la création de deux indicateurs : l'indicateur à graduations, qui trace le graphique à graduations de l’indicateur de prix et de graduation bougie, qui trace des bougies avec le nombre de graduations spécifié. Chacun des indicateurs écrit les prix entrants dans un fichier, et utilise les données sauvegardées après le redémarrage de l'indicateur (ces données peuvent également être utilisées par les autres programmes)