English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
preview
Événements de trade dans MetaTrader 5

Événements de trade dans MetaTrader 5

MetaTrader 5Trading | 22 décembre 2021, 16:48
296 0
MetaQuotes
MetaQuotes

Introduction

Toutes les commandes pour effectuer des opérations de trading sont transmises au serveur de trading depuis le terminal client de MetaTrader 5 par l'envoi de demandes. Chaque demande doit être correctement remplie en fonction de l'opération demandée ; sinon, elle ne passera pas la validation principale et ne sera pas acceptée par le serveur pour un traitement ultérieur.

Les demandes acceptées par le serveur de trading sont stockées sous la forme d'ordres qui peuvent être soit en attente, soit exécutés instantanément au taux du jour. Les ordres sont stockés sur le serveur jusqu'à ce qu'ils soient exécutés ou annulés. Le résultat d'une exécution d'ordre est une transaction.

Une transaction modifie la position de trade d'un symbole donné, elle peut ouvrir, fermer, augmenter, diminuer ou inverser la position. Par conséquent, une position ouverte est toujours le résultat de l'exécution d'une ou plusieurs transactions. Des informations plus détaillées sont fournies dans l'article Ordres, positions et transactions dans MetaTrader 5.

Cet article décrit le concept, les termes et les processus qui se déroulent entre l'envoi d'une demande et son déplacement dans l'historique de trade après son traitement.


Transmission de la demande du terminal client au serveur de trade

Pour effectuer une opération de trading, vous devez envoyer un ordre au système de trading. Une demande est toujours envoyée au serveur de trading en soumettant un ordre à partir du terminal client. La structure d'une demande doit être remplie correctement, quelle que soit la manière dont vous tradez - manuellement ou à l'aide d'un programme MQL5.

Pour effectuer une opération de trade manuellement, vous devez ouvrir la fenêtre de dialogue de remplissage d'une demande de trade en appuyant sur la touche F9. Lors du trading automatique via MQL5, les demandes sont envoyées à l'aide de la fonction OrderSend(). Étant donné que de nombreuses demandes incorrectes peuvent entraîner une surcharge indésirable du serveur de trading, chaque demande doit être vérifiée avant d'être envoyée à l'aide de la fonction OrderCheck(). Le résultat de la vérification d'une demande est placé dans une variable décrite par la structure MqlTradeCheckresult.

Important : L'exactitude de chaque demande est vérifiée dans le terminal client avant d'être envoyée au serveur de trade. Les demandes délibérément incorrectes (acheter un million de lots ou acheter à un prix négatif) ne sont pas transmises en dehors du terminal client. C’est fait pour protéger les serveurs de trade d'une masse de demandes incorrectes causées par une erreur dans un programme MQL5.

Une fois qu'une demande arrive au serveur de trade, elle passe le contrôle principal :

  • si vous avez suffisamment d'actifs pour effectuer l'opération de trade.
  • si les cours spécifiés sont corrects : open price, Stop Loss, Take Profit, etc.
  • si le prix spécifié est présent dans le flux de prix pour une exécution instantanée.
  • si les niveaux Stop Loss et Take Profit sont absents dans le mode d'exécution du marché.
  • si le volume est correct : volume minimum et maximum, step, volume maximum de la position (SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEP et SYMBOL_VOLUME_LIMIT).
  • Statut du symbole : séance cotation ou trade, possibilité de trader par le symbole, un mode de trading spécifique (par exemple rien d’autre que la clôture des positions), etc.
  • Statut du compte de trade : différentes limitations pour des types spécifiques de comptes.
  • d'autres contrôles, en fonction de l'opération de trade demandée.

Une demande incorrecte qui ne passe pas le contrôle principal sur le serveur est rejetée. Le terminal client est toujours informé du résultat de la vérification d'une demande lors de l'envoi d'une réponse. La réponse du serveur de trading peut être extraite d'une variable de type MqlTradeResult, qui est passée en second paramètre dans la fonction OrderSend() lors de l'envoi d'une demande.

Envoi de demandes de trade vers le serveur de trade à partir du terminal client

Si une demande réussit le contrôle d’exactitude préliminaire, elle sera placée dans le paquet des demandes en attente de traitement. À la suite du traitement d'une demande, un ordre (commande pour exécution d’une opération de trade) est créé dans la base du serveur de trading. Cependant, il existe deux types de demandes qui n'entraînent pas la création d'un ordre :

  1. une demande de changement de position (changement de son Stop Loss et/ou Take Profit).
  2. une demande de modification d'un ordre en attente (ses niveaux de prix et délai d'expiration).

Le terminal client reçoit un message indiquant que la demande est acceptée et placée dans le sous-système de trading de la plateforme MetaTrader 5. Le serveur place la demande acceptée dans la file d'attente des demandes pour un traitement ultérieur, ce qui peut entraîner ce qui suit :

  • placement d’un ordre en attente
  • exécution d'un ordre instantané au taux du jour.
  • modification d'un ordre ou d'une position.

La durée d'une demande dans la file d'attente du serveur est limitée à trois minutes. Une fois la période dépassée, la demande est supprimée de la file d'attente des demandes.


Envoi d'événements de trade du serveur de trade au terminal client

Le modèle événementiel et les fonctions de gestion des événements sont implémentés dans le langage MQL5. Cela signifie que dans une réponse à tout événement prédéfini, l'environnement d'exécution MQL5 appelle la fonction appropriée - le gestionnaire d'événements. Pour le traitement des événements de trade, il existe la fonction prédéfinie OnTrade() ; le code pour travailler avec les ordres, les positions et les transactions doit y être placé. Cette fonction n'est appelée que pour les Expert Advisors, elle ne sera pas utilisée dans les indicateurs et les scripts même si vous y ajoutez une fonction du même nom et du même type.

Les événements de trade sont générés par le serveur en cas de :

  • changement d’ordres actifs,
  • changement de position,
  • changement de transactions,
  • changement de l'historique de trade.

Notez qu'une opération peut provoquer plusieurs événements. Par exemple, le déclenchement d'un ordre en attente entraîne la survenance de deux événements :

  1. l'apparition d'une transaction qui s'inscrit dans l'historique de trade.
  2. déplacement de l’ordre en attente de la liste des ordres actifs vers la liste des ordres de l'historique (l’ordre est déplacé vers l'historique).

Un autre exemple d'événements multiples est la réalisation de plusieurs transactions sur la base d'un ordre unique, au cas où le volume requis ne peut être obtenu à partir d'une offre opposée unique. Le serveur de trade crée et envoie les messages sur chaque événement au terminal client. C'est pourquoi la fonction OnTrade() peut être appelée plusieurs fois pour un événement apparemment unique. Il s'agit d'un exemple simple de la procédure de traitement des ordres dans le sous-système de trade de la plateforme MetaTrader 5.

Voici un exemple : alors qu'un ordre en attente d'achat de 10 lots d'EURUSD attend d'être exécuté, des offres opposées de vente de 1, 4 et 5 lots apparaissent. Ces trois demandes réunies donnent le volume requis de 10 lots, elles sont donc exécutées une par une, si la politique de remplissage permet d'effectuer l'opération de trade partiellement.

A la suite de l'exécution de 4 ordres, le serveur effectuera 3 transactions de 1, 4 et 5 lots sur la base des demandes opposées existantes. Combien d'événements de trade seront générés dans ce cas ? La première demande opposée de vente d'un lot entraînera l'exécution d'une transaction sur 1 lot. C'est le premier événement de trade (1 lot). Mais l'ordre en attente d'achat de 10 lots est également modifié ; maintenant c'est l'ordre d'achat de 9 lots d'EURUSD. Le changement de volume de l'ordre en attente est le deuxième événement de trade (changement de volume d'un ordre en attente).

Génération d'événements de trade

Pour la deuxième transaction de 4 lots, les deux autres événements de trade seront générés, un message sur chacun d'eux sera envoyé au terminal client qui a initié l'ordre initial en attente d'achat de 10 lots d'EURUSD.

La dernière transaction de 5 lots entraînera la réalisation de trois événements de trade :

  1. la transaction de 5 lots,
  2. le changement de volume,
  3. le déplacement de l'ordre vers l'historique de trade.

À la suite de l'exécution de la transaction, le terminal client reçoit 7 événements de trading. Tradez l'un après l'autre (on suppose que la connexion entre le terminal client et le serveur de trading est stable et qu'aucun message n'est perdu). Ces messages doivent être traités dans un Expert Advisor à l'aide de la fonction OnTrade().

Important : Chaque message concernant un trade, même Trade, peut apparaître à la suite d'une ou plusieurs demandes. Chaque demande peut entraîner la survenance de plusieurs événements de trade. Vous ne pouvez pas vous fier à l'énoncé « Une demande - un événement de trade », car le traitement des événements peut être effectué en plusieurs étapes et chaque opération peut modifier le statut des ordres, des positions et de l'historique de trade.


Traitement des ordres via le serveur de trading

Tous les ordres qui attendent leur exécution seront finalement déplacés vers l'historique - soit la condition de leur exécution sera satisfaite, soit ils seront annulés. Il existe plusieurs variantes d'une annulation d’un ordre :

  • l'exécution d'une transaction sur la base de l’ordre.
  • le rejet de l’ordre par un courtier.
  • l’annulation de l’ordre à la demande du trader (demande manuelle ou automatique à partir d'un programme MQL5).
  • l'expiration de l'ordre, qui est déterminée soit par le trader lors de l'envoi de la demande, soit par les conditions de trade du système de trade donné.
  • le manque d'actifs sur le compte de trade pour réaliser la transaction au moment où les conditions de son exécution sont remplies.
  • l’ordre est annulé en raison de la politique de remplissage (un ordre partiellement rempli est annulé).

Quelle que soit la raison pour laquelle un ordre actif est déplacé vers l'historique, le message concernant le changement est envoyé au terminal client. Les messages sur l'événement de trade ne sont pas destinés à tous les terminaux clients, mais ceux connectés au compte correspondant.


Important : Le fait d'accepter une demande via le serveur de trading n'entraîne pas toujours l'exécution de l'opération demandée. Cela signifie que la demande a passé la validation après son arrivée sur le serveur de trading.

C'est pourquoi la documentation de la fonction OrderSend() dit :

Valeur renvoyée

En cas de vérification de base réussie d'une demande, la fonction OrderSend() renvoie true - ce qui n'est pas un signe d'exécution réussie d'une opération de trade. Pour une description plus détaillée du résultat de l'exécution des fonctions, analyser les champs de la structure MqlTradeResult.


Mise à jour de trades et de l'historique dans le terminal client

Les messages sur les événements de trade et les changements dans l'historique de trades passent par des canaux distincts. Lors de l'envoi d'une demande d'achat à l'aide de la fonction OrderSend(), vous pouvez obtenir le ticket de l’ordre, qui est créé à la suite d'une validation réussie de la demande. Dans le même temps, l’ordre lui-même peut ne pas apparaître dans le terminal client et une tentative de sélection à l'aide de OrderSelect() peut échouer.

Tous les messages du serveur de trading arrivent au terminal client indépendamment

Sur la figure ci-dessus, vous pouvez voir comment le serveur de trading transmet le ticket d’ordre au programme MQL5, mais le message concernant Trade, l'événement de trading, (apparition d'un nouvel ordre) n'est pas encore arrivé. Le message concernant le changement de la liste des ordres actifs n'est pas arrivé non plus.

Il peut arriver que le message de trade concernant l'apparition d'un nouvel ordre arrive au programme alors qu'une transaction sur sa base a déjà été effectuée, donc l'ordre est déjà absent de la liste des ordres actifs, il est dans l'historique. Il s'agit d'une situation réelle, car la vitesse de traitement des demandes est beaucoup plus élevée par rapport à la vitesse actuelle de livraison d'un message via un réseau.


Gestion des événements de trades dans MQL5

Toutes les opérations sur le serveur de trading et l'envoi de messages sur les événements de trading sont effectués de manière asymétrique. Il n'y a qu'une seule méthode sûre pour savoir exactement ce qui a été modifié sur le compte de trades. Cette méthode consiste à mémoriser le statut de trades et l'historique de trades, puis à le comparer au nouveau statut.

L'algorithme de suivi des événements de trades dans Expert Advisors est le suivant :

  1. déclarer les compteurs d'ordre, les positions et les transactions globalement.
  2. déterminer la profondeur de l'historique des trades qui sera demandée au cache du programme MQL5. Plus nous chargeons d'historique dans le cache, plus les ressources du terminal et de l'ordinateur sont consommées.
  3. initialiser les compteurs d'ordres, de positions et de transactions dans la fonction OnInit.
  4. déterminer les fonctions du gestionnaire dans lesquelles une demande de l'historique des trades sera envoyée vers le cache.
  5. Là, après le chargement de l'historique des trades, nous allons également trouver ce qui est arrivé au compte de trade en comparant le statut mémorisé et le statut actuel.

C'est l'algorithme le plus simple, il permet de découvrir si le nombre de positions ouvertes (ordre, transactions) a été modifié et quel est le sens du changement. S'il y a des changements, nous pouvons obtenir des informations plus détaillées. Si le nombre d’ordres n'est pas modifié, mais que les ordres eux-mêmes sont modifiés, une approche différente est nécessaire ; par conséquent, cette variante n'est pas couverte dans cet article.

Les modifications du compteur peuvent être vérifiées dans les fonctions OnTrade() et OnTick() d'un Expert Advisor.

Écrivons pas à pas un exemple de programme.

1. Le compteur d'ordre, les transactions et positions sur la portée globale.

int          orders;            // number of active orders
int          positions;         // number of open positions
int          deals;             // number of deals in the trade history cache
int          history_orders;    // number of orders in the trade history cache
bool         started=false;     // flag of initialization of the counters

2. La profondeur de l'historique des trades à charger dans le cache est définie selon le nombre de jours de la variable d'entrée (charger l'historique des trades pour le nombre de jours spécifié dans cette variable).

input    int days=7;            // depth of the trade history in days

//--- set the limit of the trade history on the global scope
datetime     start;             // start date of the trade history in cache
datetime     end;               // end date of the trade history in cache

3. Initialisation des compteurs et des limites de l'historique des trades. Récupérez l'initialisation des compteurs pour la fonction InitCounters() en vue d’une meilleure lisibilité du code :

int OnInit()
  {
//---
   end=TimeCurrent();
   start=end-days*PeriodSeconds(PERIOD_D1);
   PrintFormat("Limits of the trade history to be loaded: start - %s, end - %s",
               TimeToString(start),TimeToString(end));
   InitCounters();
//---
   return(0);
  }

La fonction InitCounters() essaie de charger l'historique des trades dans le cache, et en cas de succès, elle initialise tous les compteurs. De plus, si l'historique est chargé avec succès, la valeur de la variable globale « started » est configurée sur « true », ce qui indique que les compteurs ont été correctement initialisés.

//+------------------------------------------------------------------+
//|  initialization of the counters of positions, orders and deals   |
//+------------------------------------------------------------------+
void InitCounters()
  {
   ResetLastError();
//--- load history
   bool selected=HistorySelect(start,end);
   if(!selected)
     {
      PrintFormat("%s. Failed to load the history from %s to %s to the cache. Error code: %d",
                  __FUNCTION__,TimeToString(start),TimeToString(end),GetLastError());
      return;
     }
//--- get current values
   orders=OrdersTotal();
   positions=PositionsTotal();
   deals=HistoryDealsTotal();
   history_orders=HistoryOrdersTotal();
   started=true;
   Print("The counters of orders, positions and deals are successfully initialized");
  }

4. La vérification des changements sur le statut du compte de trade est effectuée dans les gestionnaires OnTick() et OnTrade(). La variable « started » est vérifiée en premier - si sa valeur est « true », la fonction SimpleTradeProcessor() est appelée, sinon la fonction d'initialisation des compteurs InitCounters() est appelée.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(started) SimpleTradeProcessor();
   else InitCounters();
  }
//+------------------------------------------------------------------+
//| called when the Trade event occurs                               |
//+------------------------------------------------------------------+
void OnTrade()
  {
   if(started) SimpleTradeProcessor();
   else InitCounters();
  }

5. La fonction SimpleTradeProcessor() vérifie si le nombre d'ordres, de transactions et de positions a été modifié. Après avoir effectué toutes les vérifications, nous appelons la fonction CheckStartDateInTradeHistory() qui déplace la valeur « start » plus près du moment actuel si nécessaire.

//+------------------------------------------------------------------+
//| simple example of processing changes in trade and history        |
//+------------------------------------------------------------------+
void SimpleTradeProcessor()
  {
   end=TimeCurrent();
   ResetLastError();
//--- load history
   bool selected=HistorySelect(start,end);
   if(!selected)
     {
      PrintFormat("%s. Failed to load the history from %s to %s to the cache. Error code: %d",
                  __FUNCTION__,TimeToString(start),TimeToString(end),GetLastError());
      return;
     }

//--- get current values
   int curr_orders=OrdersTotal();
   int curr_positions=PositionsTotal();
   int curr_deals=HistoryDealsTotal();
   int curr_history_orders=HistoryOrdersTotal();

//--- check whether the number of active orders has been changed
   if(curr_orders!=orders)
     {
      //--- number of active orders is changed
      PrintFormat("Number of orders has been changed. Previous number is %d, current number is %d",
                  orders,curr_orders);
     /*
       other actions connected with changes of orders
     */
      //--- update value
      orders=curr_orders;
     }

//--- change in the number of open positions
   if(curr_positions!=positions)
     {
      //--- number of open positions has been changed
      PrintFormat("Number of positions has been changed. Previous number is %d, current number is %d",
                  positions,curr_positions);
      /*
      other actions connected with changes of positions
      */
      //--- update value
      positions=curr_positions;
     }

//--- change in the number of deals in the trade history cache
   if(curr_deals!=deals)
     {
      //--- number of deals in the trade history cache has been changed
      PrintFormat("Number of deals has been changed. Previous number is %d, current number is %d",
                  deals,curr_deals);
      /*
       other actions connected with change of the number of deals
       */
      //--- update value
      deals=curr_deals;
     }

//--- change in the number of history orders in the trade history cache
   if(curr_history_orders!=history_orders)
     {
      //--- the number of history orders in the trade history cache has been changed
      PrintFormat("Number of orders in the history has been changed. Previous number is %d, current number is %d",
                  history_orders,curr_history_orders);
     /*
       other actions connected with change of the number of order in the trade history cache
      */
     //--- update value
     history_orders=curr_history_orders;
     }
//--- check whether it is necessary to change the limits of trade history to be requested in cache
   CheckStartDateInTradeHistory();
  }

La fonction CheckStartDateInTradeHistory() calcule la date de début de la demande de l'historique des trades pour le moment actuel (curr_start) et la compare à la variable « start ». Si la différence entre eux est supérieure à 1 jour, alors « start » est corrigé et les compteurs des ordres et des transactions historiques sont mis à jour.

//+------------------------------------------------------------------+
//|  Changing start date for the request of trade history            |
//+------------------------------------------------------------------+
void CheckStartDateInTradeHistory()
  {
//--- initial interval, as if we started working right now
   datetime curr_start=TimeCurrent()-days*PeriodSeconds(PERIOD_D1);
//--- make sure that the start limit of the trade history period has not gone 
//--- more than 1 day over intended date
   if(curr_start-start>PeriodSeconds(PERIOD_D1))
     {
      //--- we need to correct the date of start of history loaded in the cache
      start=curr_start;
      PrintFormat("New start limit of the trade history to be loaded: start => %s",
                  TimeToString(start));

      //--- now load the trade history for the corrected interval again
      HistorySelect(start,end);

      //--- correct the counters of deals and orders in the history for further comparison
      history_orders=HistoryOrdersTotal();
      deals=HistoryDealsTotal();
     }
  }

Le code complet de l'Expert Advisor DemoTradeEventProcessing.mq5 est joint à l'article.


Conclusion

Toutes les opérations de la plateforme de trading en ligne de MetaTrader 5 sont effectuées de manière asynchrone et les messages concernant tous les changements sur un compte de trading sont envoyés indépendamment les uns des autres. Par conséquent, il ne sert à rien d'essayer de suivre des événements uniques sur la base de la règle « Une demande - un événement de trade ». Si vous avez besoin de déterminer avec précision ce qui est modifié lorsqu'un trade survient, vous devez alors analyser toutes vos transactions, positions et ordres à chaque appel du gestionnaire OnTrade en comparant leur statut actuel avec le précédent.

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

Les principes fondamentaux de tests dans MetaTrader 5 Les principes fondamentaux de tests dans MetaTrader 5
Quelles sont les différences entre les trois modes de test dans MetaTrader 5, et que faut-il particulièrement rechercher ? Comment se déroule le test d'un EA, tradant simultanément sur plusieurs instruments ? Quand et comment les valeurs des indicateurs sont-elles calculées lors des tests, et comment les événements sont-ils gérés ? Comment synchroniser les barres de différents instruments lors des tests en mode « prix d’ouverture uniquement » ? Cet article vise à apporter des réponses à ces questions et à bien d'autres.
Ordres, positions et transactions dans MetaTrader 5 Ordres, positions et transactions dans MetaTrader 5
La création d'un robot de trading robuste ne peut se faire sans une compréhension des mécanismes du système de trading MetaTrader 5. Le terminal client reçoit les informations sur les positions, les ordres et les transactions du serveur de trading. Pour gérer correctement ces données en utilisant le MQL5, il est nécessaire d'avoir une bonne compréhension de l'interaction entre le programme MQL5 et le terminal client.
Utilisation des ressources en MQL5 Utilisation des ressources en MQL5
Les programmes MQL5 automatisent non seulement les calculs de routine, mais peuvent également créer un environnement graphique complet. Les fonctions de création de contrôles véritablement interactifs sont désormais pratiquement de la même richesse que celles des langages de programmation classiques. Si vous souhaitez écrire un programme autonome à part entière en MQL5, utilisez les ressources qu'il contient. Les programmes avec des ressources sont plus faciles à maintenir et à distribuer.
Guide de test et d'optimisation des Expert Advisors en MQL5 Guide de test et d'optimisation des Expert Advisors en MQL5
Cet article explique le processus étape par étape d'identification et de résolution des erreurs de code ainsi que les étapes de test et d'optimisation des paramètres d'entrée de l'Expert Advisor. Vous apprendrez à utiliser le Testeur de stratégie du terminal client MetaTrader 5 pour trouver le meilleur symbole et le meilleur ensemble de paramètres d'entrée pour votre Expert Advisor.