
Événements de trade dans MetaTrader 5
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.
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.
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 :
- une demande de changement de position (changement de son Stop Loss et/ou Take Profit).
- 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 :
- l'apparition d'une transaction qui s'inscrit dans l'historique de trade.
- 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).
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 :
- la transaction de 5 lots,
- le changement de volume,
- 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().
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.
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.
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 :
- déclarer les compteurs d'ordre, les positions et les transactions globalement.
- 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.
- initialiser les compteurs d'ordres, de positions et de transactions dans la fonction OnInit.
- déterminer les fonctions du gestionnaire dans lesquelles une demande de l'historique des trades sera envoyée vers le cache.
- 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





- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation