English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position

MQL5 Cookbook : L'historique des transactions et la bibliothèque de fonctions pour obtenir les propriétés de position

MetaTrader 5Exemples | 13 janvier 2022, 10:41
116 0
Anatoli Kazharski
Anatoli Kazharski

Introduction

Il est temps de résumer brièvement les informations fournies dans les articles précédents sur les propriétés de position. Dans cet article, nous allons créer quelques fonctions supplémentaires pour obtenir les propriétés qui ne peuvent être obtenues qu'après avoir accédé à l'historique des transactions. Nous nous familiariserons également avec les structures de données qui nous permettront d'accéder aux propriétés de position et de symbole de manière plus pratique.

Les systèmes de trading où les volumes de positions restent les mêmes tout au long de leur existence ne nécessitent pas vraiment l'utilisation des fonctions qui seront fournies dans cet article. Mais si vous envisagez de mettre en œuvre un système de gestion de l'argent et de contrôler la taille d'un lot de position dans votre stratégie de trading à un stade ultérieur, ces fonctions seront indispensables.

Avant de commencer, je voudrais faire une suggestion aux lecteurs qui ont suivi un lien vers cet article, tout en étant les premiers visiteurs de ce site Web, ou qui viennent de commencer à apprendre la langue MQL5, pour commencer par les articles précédents du " Série "MQL5 Cookbook".


Développement d’Expert Advisor

Pour pouvoir voir le fonctionnement des nouvelles fonctions dans l'Expert Advisor modifié dans l'article précédent intitulé "MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trading", nous ajouterons la possibilité d'augmenter le volume de la position si un signal d'ouverture se produit à nouveau, alors que la position est déjà là.

Il peut y avoir plusieurs transactions dans l'historique des positions, et s'il y a eu des changements dans le volume de la position au cours du trading, il doit également y avoir eu des changements dans le prix de la position actuelle. Pour connaître le prix du premier point d'entrée, nous devons accéder à l'historique des transactions par rapport à cette position spécifique. La figure ci-dessous est une démonstration du cas où une position n'a qu'un seul deal (point d'entrée) :

Fig. 1. Première transaction dans la position

Fig. 1. Première transaction dans la position.

La figure suivante montre un changement dans le prix de la position après la deuxième transaction :

Fig. 2. Deuxième transaction dans la position

Fig. 2. Deuxième affaire dans la position.

Comme démontré dans les articles précédents, les identifiants standards permettent d'obtenir uniquement le prix de la position actuelle (POSITION_PRICE_OPEN) et le prix actuel d'un symbole (POSITION_PRICE_CURRENT) pour lequel une position est ouverte.

Cependant, dans certains systèmes de trading, nous avons besoin de connaître la distance parcourue par le prix depuis le premier point d'entrée, ainsi que le prix de la dernière transaction. Toutes ces informations sont disponibles dans l'historique des transactions/ordres du compte. Ci-dessous la liste des deals associés à la figure précédente :

Fig. 3. L'historique des transactions dans le compte

Fig. 3. L'historique des transactions dans le compte.

Je crois que la situation est maintenant claire et tous les objectifs sont fixés. Continuons à modifier l'Expert Advisor présenté dans les articles précédents. Tout d'abord, nous allons ajouter de nouveaux identifiants numérotés 0, 6, 9, 12 et 16 à l'énumération des propriétés de position :

//--- Enumeration of position properties
enum ENUM_POSITION_PROPERTIES
  {
   P_TOTAL_DEALS     = 0,
   P_SYMBOL          = 1,
   P_MAGIC           = 2,
   P_COMMENT         = 3,
   P_SWAP            = 4,
   P_COMMISSION      = 5,
   P_PRICE_FIRST_DEAL= 6,
   P_PRICE_OPEN      = 7,
   P_PRICE_CURRENT   = 8,
   P_PRICE_LAST_DEAL = 9,
   P_PROFIT          = 10,
   P_VOLUME          = 11,
   P_INITIAL_VOLUME  = 12,
   P_SL              = 13,
   P_TP              = 14,
   P_TIME            = 15,
   P_DURATION        = 16,
   P_ID              = 17,
   P_TYPE            = 18,
   P_ALL             = 19
  };

Les commentaires pour chacune des propriétés seront donnés dans une structure qui sera revue un peu ci-dessous.

Augmentons le nombre des paramètres externes. Maintenant, nous allons pouvoir préciser :

  • MagicNumber - un identifiant unique de l'Expert Advisor (numéro magique) ;
  • Déviation - dérapage ;
  • VolumeIncrease - une valeur par laquelle le volume de position sera augmenté ;
  • InfoPanel - un paramètre qui vous permet d'activer/désactiver l'affichage du panneau d'informations.

Voici comment il est mis en œuvre :

//--- External parameters of the Expert Advisor
sinput   long        MagicNumber=777;     // Magic number
sinput   int         Deviation=10;        // Slippage
input    int         NumberOfBars=2;      // Number of Bullish/Bearish bars for a Buy/Sell
input    double      Lot=0.1;             // Lot
input    double      VolumeIncrease=0.1;  // Position volume increase
input    double      StopLoss=50;         // Stop Loss
input    double      TakeProfit=100;      // Take Profit
input    double      TrailingStop=10;     // Trailing Stop
input    bool        Reverse=true;        // Position reversal
sinput   bool        ShowInfoPanel=true;  // Display of the info panel

Veuillez noter les paramètres dont les sinput modifier sont définies. Ce modificateur vous permet de désactiver l'optimisation dans le Strategy Tester. En fait, lorsque vous développez un programme pour votre propre usage, vous avez une parfaite compréhension des paramètres qui affecteront le résultat final, il vous suffit donc de les décocher de l'optimisation. Mais lorsqu'il s'agit d'un très grand nombre de paramètres, cette méthode permet de les séparer visuellement des autres au fur et à mesure qu'ils sont grisés :

Fig. 4. Les paramètres désactivés pour l'optimisation sont grisés

Fig. 4. Les paramètres désactivés pour l'optimisation sont grisés.

Remplaçons maintenant les variables globales qui stockaient les valeurs de propriété de position et de symbole par des structures de données (struct) :

//--- Position properties
struct position_properties
  {
   uint              total_deals;      // Number of deals
   bool              exists;           // Flag of presence/absence of an open position
   string            symbol;           // Symbol
   long              magic;            // Magic number
   string            comment;          // Comment
   double            swap;             // Swap
   double            commission;       // Commission   
   double            first_deal_price; // Price of the first deal in the position
   double            price;            // Current position price
   double            current_price;    // Current price of the position symbol      
   double            last_deal_price;  // Price of the last deal in the position
   double            profit;           // Profit/Loss of the position
   double            volume;           // Current position volume
   double            initial_volume;   // Initial position volume
   double            sl;               // Stop Loss of the position
   double            tp;               // Take Profit of the position
   datetime          time;             // Position opening time
   ulong             duration;         // Position duration in seconds
   long              id;               // Position identifier
   ENUM_POSITION_TYPE type;            // Position type
  };
//--- Symbol properties
struct symbol_properties
  {
   int               digits;        // Number of decimal places in the price
   int               spread;        // Spread in points
   int               stops_level;   // Stops level
   double            point;         // Point value
   double            ask;           // Ask price
   double            bid;           // Bid price
   double            volume_min;    // Minimum volume for a deal
   double            volume_max;    // Maximum volume for a deal
   double            volume_limit;  // Maximum permissible volume for a position and orders in one direction
   double            volume_step;   // Minimum volume change step for a deal
   double            offset;        // Offset from the maximum possible price for a transaction
   double            up_level;      // Upper Stop level price
   double            down_level;    // Lower Stop level price
  }

Maintenant, pour accéder à un certain élément de la structure, nous devons créer une variable de ce type de structure. La procédure est similaire à la création d'un objet pour une classe de commerce qui a été pris en compte dans l'article intitulé "MQL5 Cookbook : Analyse des propriétés de position dans le testeur de stratégie MetaTrader 5".

//--- variables for position and symbol properties
position_properties  pos;
symbol_properties    symb;

Vous pouvez accéder aux éléments de la même manière que pour les méthodes de classe. En d'autres termes, il suffit de mettre un point après le nom d'une variable de structure pour afficher la liste des éléments contenus dans cette structure spécifique. C'est très pratique. Dans le cas où des commentaires sur une seule ligne sont fournis pour les champs de la structure (comme dans notre exemple), ils seront affichés dans une info-bulle à droite.

Fig.5a. Liste des champs de structure pour les propriétés de positionFig. 5b. Liste des champs de structure pour les propriétés de symbole

Fig. 5. Liste des champs de structure.

Un autre point important. En modifiant l'Expert Advisor, nous avons changé pratiquement toutes ses variables globales utilisées dans de nombreuses fonctions, nous devons donc maintenant les remplacer par les champs de structure correspondants pour les propriétés de symbole et de position. Par exemple, la variable globale pos_open qui servait à stocker le drapeau de présence/absence d'un poste ouvert a été remplacée par le champ existe du type de structure position_properties. Par conséquent, partout où la variable pos_open a été utilisée, elle doit être remplacée par pos.exists.

Ce sera un processus long et épuisant si vous le faites manuellement. Il serait donc préférable d'automatiser la solution à cette tâche en utilisant les fonctionnalités de MetaEditor : Rechercher et remplacer -> Remplacer dans le menu Edit ou la combinaison de touches Ctrl+H :


Fig. 6. Recherche et remplacement du texte

Fig. 6. Recherche et remplacement du texte.

Nous devons rechercher et remplacer toutes les variables globales pour les propriétés de position et de symbole pour poursuivre un test, après avoir compilé le fichier. Si aucune erreur n'est détectée, cela signifie que nous avons tout fait correctement. Je ne fournirai pas le code ici pour ne pas rendre l'article inutilement long. En outre, un code source prêt à l'emploi est disponible à la fin de l'article en téléchargement.

Maintenant que nous avons réglé le problème avec les variables, passons à la modification des fonctions existantes et à la création de nouvelles.

Dans les paramètres externes, vous pouvez maintenant définir le nombre magique et le glissement en points. Nous devons donc également apporter les modifications pertinentes dans le code de l'Expert Advisor. Nous allons créer une fonction auxiliaire définie par l'utilisateur OpenPosition(), où ces propriétés seront définies à l'aide des fonctions de la classe CTrade avant d'envoyer un ordre d'ouverture de position.

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
   trade.SetExpertMagicNumber(MagicNumber); // Set the magic number in the trading structure
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Set the slippage in points
//--- If the position failed to open, print the relevant message
   if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
     { Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
  }

Nous n'avons qu'à apporter quelques petites modifications au code de la fonction de trading principale de l'Expert Advisor - TradingBlock(). Voici la partie du code de fonction qui a subi des modifications :

//--- If there is no position
   if(!pos.exists)
     {
      //--- Adjust the volume
      lot=CalculateLot(Lot);
      //--- Open a position
      OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
     }
//--- If there is a position
   else
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- If the position is opposite to the signal and the position reversal is enabled
      if(pos.type==opposite_position_type && Reverse)
        {
         //--- Get the position volume
         GetPositionProperties(P_VOLUME);
         //--- Adjust the volume
         lot=pos.volume+CalculateLot(Lot);
         //--- Reverse the position
         OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
         return;
        }
      //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume
      if(!(pos.type==opposite_position_type) && VolumeIncrease>0)
        {
         //--- Get the Stop Loss of the current position
         GetPositionProperties(P_SL);
         //--- Get the Take Profit of the current position
         GetPositionProperties(P_TP);
         //--- Adjust the volume
         lot=CalculateLot(Increase);
         //--- Increase the position volume
         OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment);
         return;
        }

Le code ci-dessus a été amélioré avec le bloc où la direction de la position actuelle est vérifiée par rapport à la direction du signal. Si leurs directions coïncident et que l'augmentation du volume de la position est activée dans les paramètres externes (la valeur du paramètre VolumeIncrease est supérieure à zéro), nous vérifions/ajustons un lot donné et envoyons l'ordre correspondant. Maintenant, tout ce que vous avez à faire pour envoyer un ordre pour ouvrir ou inverser une position ou pour augmenter le volume de la position est d'écrire une ligne de code.

Créons des fonctions pour obtenir des propriétés de position à partir de l'historique des transactions. Nous allons commencer par une fonction CurrentPositionTotalDeals() qui renvoie le nombre de transactions dans la position actuelle :

//+------------------------------------------------------------------+
//| Returning the number of deals in the current position            |
//+------------------------------------------------------------------+
uint CurrentPositionTotalDeals()
  {
   int    total       =0;  // Total deals in the selected history list
   int    count       =0;  // Counter of deals by the position symbol
   string deal_symbol =""; // symbol of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
            //--- If the symbol of the deal and the current symbol are the same, increase the counter
            if(deal_symbol==_Symbol)
               count++;
        }
     }
//---
   return(count);
  }

Le code ci-dessus est fourni avec des commentaires assez détaillés. Mais nous devrions dire quelques mots sur la façon dont l'historique est sélectionné. Dans notre cas, nous avons obtenu la liste à partir du point d'ouverture de la position actuelle déterminée par l'heure d'ouverture jusqu'au moment actuel à l'aide de la fonction HistorySelect(). Une fois l'historique sélectionné, nous pouvons connaître le nombre de transactions dans la liste à l'aide de la fonction HistoryDealsTotal(). Le reste devrait être clair dans les commentaires.

L'historique d'une position particulière peut également être sélectionné par son identifiant à l'aide de la fonction HistorySelectByPosition(). Ici, vous devez considérer que l'identifiant de position reste le même lorsque la position est inversée, comme cela arrive parfois dans notre Expert Advisor. Cependant, le temps d'ouverture de la position change lors de l'inversion, donc cette variante est plus facile à mettre en œuvre. Mais si vous devez gérer l'historique des transactions qui ne s'applique pas uniquement à la position actuellement ouverte, vous devez utiliser des identifiants. Nous reviendrons sur l'historique des transactions dans les prochains articles.

Continuons en créant une fonction CurrentPositionFirstDealPrice() qui renvoie le prix de la première transaction de la position, c'est-à-dire le prix de la transaction à laquelle la position a été ouverte.

//+------------------------------------------------------------------+
//| Returning the price of the first deal in the current position    |
//+------------------------------------------------------------------+
double CurrentPositionFirstDealPrice()
  {
   int      total       =0;    // Total deals in the selected history list
   string   deal_symbol ="";   // symbol of the deal
   double   deal_price  =0.0;  // Price of the deal
   datetime deal_time   =NULL; // Time of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Get the time of the deal
         deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME);
         //--- If the time of the deal equals the position opening time, 
         //    and if the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_time==pos.time && deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

Le principe est ici le même que dans la fonction précédente. Nous obtenons l'historique à partir du point d'ouverture de la position, puis vérifions l'heure de la transaction et l'heure d'ouverture de la position à chaque itération. En plus du prix de la transaction, nous obtenons le nom du symbole et l'heure de la transaction. La toute première transaction est identifiée lorsque l'heure de la transaction coïncide avec l'heure d'ouverture de la position. Comme son prix a déjà été affecté à la variable pertinente, nous n'avons qu'à retourner la valeur.

Continuons. Parfois, vous devrez peut-être obtenir le prix de la dernière transaction dans la position actuelle. Pour cela, nous allons créer une fonction CurrentPositionLastDealPrice() :

//+------------------------------------------------------------------+
//| Returning the price of the last deal in the current position     |
//+------------------------------------------------------------------+
double CurrentPositionLastDealPrice()
  {
   int    total       =0;   // Total deals in the selected history list
   string deal_symbol ="";  // Symbol of the deal 
   double deal_price  =0.0; // Price
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- If the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

Cette fois, la boucle a commencé avec la dernière transaction de la liste et il arrive souvent que la transaction requise soit identifiée lors de la première itération de la boucle. Mais si vous tradez sur plusieurs symboles, la boucle se poursuivra jusqu'à ce que le symbole de la transaction corresponde au symbole actuel.

Le volume de la position actuelle peut être obtenu à l'aide des POSITION_VOLUME identificateur standard. Pour connaître le volume de la position initiale (le volume de la première donne), nous allons créer une fonction CurrentPositionInitialVolume() :

//+------------------------------------------------------------------+
//| Returning the initial volume of the current position             |
//+------------------------------------------------------------------+
double CurrentPositionInitialVolume()
  {
   int             total       =0;           // Total deals in the selected history list
   ulong           ticket      =0;           // Ticket of the deal
   ENUM_DEAL_ENTRY deal_entry  =WRONG_VALUE; // Position modification method
   bool            inout       =false;       // Flag of position reversal
   double          sum_volume  =0.0;         // Counter of the aggregate volume of all deals, except for the first one
   double          deal_volume =0.0;         // Volume of the deal
   string          deal_symbol ="";          // Symbol of the deal 
   datetime        deal_time   =NULL;        // Deal execution time
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- If the order ticket by its position is obtained, then...
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- Get the volume of the deal
            deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            //--- Get the position modification method
            deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
            //--- Get the deal execution time
            deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
            //--- When the deal execution time is less than or equal to the position opening time, exit the loop
            if(deal_time<=pos.time)
               break;
            //--- otherwise calculate the aggregate volume of deals by the position symbol, except for the first one
            if(deal_symbol==_Symbol)
               sum_volume+=deal_volume;
           }
        }
     }
//--- If the position modification method is a reversal
   if(deal_entry==DEAL_ENTRY_INOUT)
     {
      //--- If the position volume has been increased/decreased
      //    I.e. the number of deals is more than one
      if(fabs(sum_volume)>0)
        {
         //--- Current volume minus the volume of all deals except for the first one
         double result=pos.volume-sum_volume;
         //--- If the resulting value is greater than zero, return the result, otherwise return the current position volume         
         deal_volume=result>0 ? result : pos.volume;
        }
      //--- If there are no more deals, other than the entry,
      if(sum_volume==0)
         deal_volume=pos.volume; // return the current position volume
     }
//--- Return the initial position volume
   return(NormalizeDouble(deal_volume,2));
  }

Cette fonction est sortie plus complexe que les précédentes. J'ai essayé de prendre en considération toutes les situations possibles pouvant entraîner une mauvaise valeur. Un test minutieux n'a révélé aucun problème. Les commentaires détaillés fournis dans le code devraient vous aider à comprendre.

Il sera également utile d'avoir une fonction qui retourne la durée de la position. Nous l'organiserons de manière à permettre à l'utilisateur de sélectionner le format approprié de la valeur renvoyée : secondes, minutes, heures ou jours. Pour cela, créons une autre énumération :

//--- Position duration
enum ENUM_POSITION_DURATION
  {
   DAYS     = 0, // Days
   HOURS    = 1, // Hours
   MINUTES  = 2, // Minutes
   SECONDS  = 3  // Seconds
  };

Vous trouverez ci-dessous le code de la fonction CurrentPositionDuration() responsable de tous les calculs pertinents :

//+------------------------------------------------------------------+
//| Returning the duration of the current position                   |
//+------------------------------------------------------------------+
ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode)
  {
   ulong     result=0;   // End result
   ulong     seconds=0;  // Number of seconds
//--- Calculate the position duration in seconds
   seconds=TimeCurrent()-pos.time;
//---
   switch(mode)
     {
      case DAYS      : result=seconds/(60*60*24);   break; // Calculate the number of days
      case HOURS     : result=seconds/(60*60);      break; // Calculate the number of hours
      case MINUTES   : result=seconds/60;           break; // Calculate the number of minutes
      case SECONDS   : result=seconds;              break; // No calculations (number of seconds)
      //---
      default        :
         Print(__FUNCTION__,"(): Unknown duration mode passed!");
         return(0);
     }
//--- Return result
   return(result);
  }

Créons une fonction CurrentPositionDurationToString() pour le panneau d'informations où les propriétés de position sont affichées. La fonction convertira la durée de la position en secondes dans un format facilement compréhensible par l'utilisateur. Le nombre de secondes sera passé à la fonction, et la fonction à son tour renverra une chaîne de caractères contenant la durée de la position en jours, heures, minutes et secondes :

//+------------------------------------------------------------------+
//| Converting the position duration to a string                     |
//+------------------------------------------------------------------+
string CurrentPositionDurationToString(ulong time)
  {
//--- A dash if there is no position
   string result="-";
//--- If the position exists
   if(pos.exists)
     {
      //--- Variables for calculation results
      ulong days=0;
      ulong hours=0;
      ulong minutes=0;
      ulong seconds=0;
      //--- 
      seconds=time%60;
      time/=60;
      //---
      minutes=time%60;
      time/=60;
      //---
      hours=time%24;
      time/=24;
      //---
      days=time;
      //--- Generate a string in the specified format DD:HH:MM:SS
      result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds);
     }
//--- Return result
   return(result);
  }

Tout est réglé et prêt maintenant. Je ne vais pas fournir les codes de fonction GetPositionProperties() et GetPropertyValue() qui doivent être modifiés conformément à tous les changements ci-dessus. Si vous avez lu tous les articles précédents de la série, vous ne devriez pas avoir de difficulté à le faire vous-même. Quoi qu'il en soit, le fichier de code source est joint à l'article.

Par conséquent, le panneau d'informations devrait apparaître comme indiqué ci-dessous :

Fig. 7. Démonstration de toutes les propriétés de position sur le panneau d'information

Fig. 7. Démonstration de toutes les propriétés de position sur le panneau d'information.

Ainsi, nous avons maintenant la bibliothèque de fonctions pour obtenir les propriétés de position et nous continuerons probablement à travailler dessus dans les futurs articles, au fur et à mesure des besoins.


Optimisation des paramètres et test Expert Advisor

A titre expérimental, essayons d'optimiser les paramètres de l'Expert Advisor. Bien que ce que nous avons actuellement ne puisse pas encore être qualifié de système de trading complet, le résultat que nous obtiendrons nous ouvrira les yeux sur certaines choses et améliorera notre expérience en tant que développeurs de systèmes de trading.

Nous allons définir les paramètres du testeur de stratégie comme indiqué ci-dessous :

Fig. 8. Paramètres du Strategy Tester pour l'optimisation des paramètres

Fig. 8. Paramètres du testeur de stratégie pour l'optimisation des paramètres.

Les réglages des paramètres externes de l'Expert Advisor doivent être les suivants :

Fig. 9. Réglages des paramètres de l'Expert Advisor pour l'optimisation

Fig. 9. Paramètres de l'Expert Advisor pour l'optimisation.

Suite à l'optimisation, nous trions les résultats obtenus par le facteur de récupération maximum :

Fig. 10. Résultats triés par facteur de récupération maximum

Fig. 10. Résultats triés par facteur de récupération maximum.

Testons maintenant le tout premier ensemble de paramètres, la valeur du facteur de récupération étant égale à 4,07. Même compte tenu du fait que l'optimisation a été effectuée pour l'EURUSD, nous pouvons voir les résultats positifs pour de nombreux symboles :

Résultats pour l’EURUSD :

Fig. 11. Résultats pour l’EURUSD

Fig. 11. Résultats pour l’EURUSD.

Résultats pour l’AUDUSD:

Fig. 12. Résultats pour l’AUDUSD

Fig. 12. Résultats pour l’AUDUSD.

Résultats pour le NZDUSD :

Fig. 13. Résultats pour le NZDUSD

Fig. 13. Résultats pour le NZDUSD.


Conclusion

Pratiquement n'importe quelle idée peut être développée et améliorée. Chaque système commercial doit être soigneusement testé avant d'être rejeté comme défectueux. Dans les prochains articles, nous examinerons divers mécanismes et schémas qui peuvent jouer un rôle très positif dans la personnalisation et l'adaptation de presque tous les systèmes de trading.

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

MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors MQL5 Cookbook : Utilisation d'indicateurs pour définir les conditions de trading dans les Expert Advisors
Dans cet article, nous continuerons à modifier l'Expert Advisor sur lequel nous avons travaillé tout au long des articles précédents de la série MQL5 Cookbook. Cette fois, l'Expert Advisor sera enrichi d'indicateurs dont les valeurs serviront à vérifier les conditions d'ouverture des positions. Pour le pimenter, nous allons créer une liste déroulante dans les paramètres externes pour pouvoir sélectionner un des trois indicateurs de trading.
MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade MQL5 Cookbook : Comment éviter les erreurs lors de la définition/modification des niveaux de trade
Dans la continuité de notre travail sur l'Expert Advisor de l'article précédent de la série intitulée "MQL5 Cookbook : Analyse des propriétés des positions dans le testeur de stratégie MetaTrader 5", nous l'améliorerons avec de nombreuses fonctions utiles, ainsi que d'améliorer et d'optimiser celles existantes. L'Expert Advisor aura cette fois des paramètres externes qui peuvent être optimisés dans le testeur de stratégie MetaTrader 5 et ressemblera à certains égards à un simple système de trading.
L'indicateur ZigZag : Approche novatrice et nouvelles solutions L'indicateur ZigZag : Approche novatrice et nouvelles solutions
L'article examine la possibilité de créer un indicateur ZigZag avancé. L'idée d'identifier les nœuds est basée sur l'utilisation de l'indicateur Enveloppes. Nous supposons que nous pouvons trouver une certaine combinaison de paramètres d'entrée pour une série d'enveloppes, où tous les nœuds ZigZag se trouvent dans les limites des bandes d'enveloppes. Par conséquent, nous pouvons essayer de prédire les coordonnées du nouveau nœud.
MQL5 Cookbook : Analyse des propriétés de position dans le testeur de stratégie MetaTrader 5 MQL5 Cookbook : Analyse des propriétés de position dans le testeur de stratégie MetaTrader 5
Nous vous présenterons une version modifiée de l'Expert Advisor de l'article précédent "MQL5 Cookbook : Propriétés de la position dans le panneau d'informations personnalisé". Certains des problèmes que nous aborderons incluent l'obtention de données à partir de barres, la vérification de nouveaux événements de barre sur le symbole actuel, y compris une classe de trade de la bibliothèque standard dans un fichier, la création d'une fonction pour rechercher des signaux de trading et une fonction pour exécuter des opérations de trading , ainsi que la détermination des événements de trade dans la fonction OnTrade().