![Ordres, positions et transactions dans MetaTrader 5](https://c.mql5.com/2/68/art-cover_600x314.jpg)
Ordres, positions et transactions dans MetaTrader 5
Termes de trading
Le but ultime d'un trader est de tirer des bénéfices par le biais d'opérations de trading sur les marchés financiers. Cet article décrit les termes et processus de la plateforme de trading MetaTrader 5, dont la connaissance est nécessaire pour une bonne compréhension du travail des fonctions de trading du langage MQL5.
-
Ordres — sont les demandes d’opérations de trading, reçues par le serveur de trading, formulées conformément aux exigences de la plate-forme MetaTrader 5. Si la demande est incorrecte, elle n'apparaîtra pas sur la plateforme de trading sous la forme d'un ordre. Les ordres peuvent être d'exécution immédiate, comme les achats ou ventes d’un certain volume, au taux du jour du marché sur un instrument financier spécifié. Un autre type d'ordres - sont les ordres en attente, qui contiennent un ordre de soumission d’une opération de trading sous certaines conditions. Les ordres en attente peuvent également contenir une restriction de temps sur leurs actions - la date d'expiration de l’ordre.
Les ordres passés (en attente), en attente des conditions de leur exécution ou de leur annulation, sont indiqués sur l'onglet « Trade » dans le terminal. Ces ordres peuvent être modifiés ou annulés. La passation, l'annulation et la modification des ordres se font à l'aide de la fonction OrderSend(). Si l’ordre a été annulé ou a atteint l'heure d'expiration de l’ordre, ou si l’ordre a été exécuté, il entre dans l'historique des ordres. Les ordres exécutés et annulés sont affichés dans l'onglet « Historique » du terminal client. Les ordres de l'historique ne sont pas modifiables.
-
Transactions - sont le résultat de l'exécution d'un ordre (un ordre pour valider la transaction). Chaque transaction est basée sur un ordre particulier, mais un seul ordre peut générer une série de transactions. Par exemple, un ordre d'achat de 10 lots peut être réalisé par plusieurs opérations successives avec remplissage partiel. Les transactions sont toujours stockées dans l'historique de trading et ne peuvent pas être modifiées. Dans le terminal, les offres sont affichées dans l'onglet « Historique ».
-
Les Positions sont les contrats, achetés ou vendus sur un instrument financier. Une position longue (Long) est formée à la suite d'achats en prévision d'une augmentation de prix, une position courte (Short) est le résultat de la vente d'un actif, en prévision d'une future baisse de prix. Pour chaque compte, pour chaque instrument financier, il ne peut y avoir qu'une seule position. Pour chaque symbole, à un moment donné, il ne peut y avoir qu'une seule position ouverte - longue ou courte.
Le volume de la position peut augmenter à la suite d'une nouvelle opération de trading dans la même direction. Cela signifie que le volume des positions longues sera augmenté après le nouvel achat (Buy deal) et sera diminué après la vente (Sell deal). La position est fermée, si le volume des engagements est devenu égal à zéro à la suite de l'opération de trading. Une telle opération est appelée clôture de la position.
Comment le terminal reçoit et stocke les informations de trading du serveur
Le terminal stocke l'historique de trading dans une base spéciale et ne reçoit que l'historique manquant des transactions et des ordres terminés sur le compte de trading, à chaque connexion au serveur de trading. Ceci est fait pour économiser sur le trafic. Lors de la fermeture du terminal client MetaTrader 5 ou de la modification du compte actif actuel, tout l'historique est enregistré sur le disque dur et lu lors du prochain lancement du terminal.
Toutes les bases de données sont enregistrées sur le disque sous une forme cryptée et la clé de cryptage dépend de l'ordinateur sur lequel le terminal est installé. Cela protège l'utilisateur du terminal contre l'accès non autorisé à ses données, en cas de copiage.
Lors de la connexion au compte, le terminal charge la base de compte sauvegardée, avec l'historique du compte, et envoie au serveur de trading une requête pour synchroniser sa propre base de données d'historique avec l'historique du compte sur le serveur de trading. De plus, après une connexion réussie au compte, le serveur de trading envoie au terminal un rapport sur les événements de trading en cours, liés à ce compte.
Les événements de trading sont les changements suivants dans le compte :
- opérations de retrait et de solde.
- charge de commissions, de swaps et de taxes.
- la passation, la suppression et la modification des ordres.
- l'exécution de transactions basées sur les ordres.
- Ouvrir et Fermer des positions
- changement dans le volume et la direction des positions.
En cas d’interruption de la connexion avec le serveur de trading, le terminal tente périodiquement de se reconnecter. Après la reconnexion avec le serveur, le terminal demande toutes les modifications récentes de l'historique des transactions pour maintenir l'intégrité des données dans sa propre base de données de l'historique.
L'historique de trading, affiché dans l'onglet « Historique » du terminal, est tiré de la base de l'historique du terminal, et les changements de période, affichés dans le terminal d'historique ne peuvent qu'augmenter la portée de l'historique, stocké dans cette base de données. La diminution de la période de l'historique affiché n'entraîne pas une suppression physique de l'historique de la base du terminal.
Cela signifie que l'installation d'un intervalle plus court de l'affichage de l’historique ne réduit pas la profondeur du stockage de l'historique de trading. Mais si nous spécifions une plage d'intervalle plus large, pour l'affichage dans l'onglet « Historique », alors une telle action pourrait conduire à une demande, de la part du serveur de trading, d'un historique plus approfondi, si la propre base du terminal n'a pas encore les données demandées pour cette période.
Le schéma général d'interaction entre le terminal et le serveur de trading MetaTrader 5 est illustré à la figure suivante :
Le terminal client envoie une demande de synchronisation à sa propre base d'historique de trading, lors du démarrage du terminal, lors de la reconnexion avec le serveur après un échec de connexion, lors d'un basculement d'un compte à un autre, et lors de la demande directe de l’historique de la transaction manquante.
A son tour, le serveur de trading de manière indépendante, sans aucune demande du terminal, envoie à un client des messages sur les événements de trading, ayant lieu sur le compte : les changements de l'état des ordres et des positions, la conduite des transactions basées sur les ordres, la facturation des commissions, le solde et le retrait d'argent, etc.
Accès à l'historique de trading depuis le programme MQL5
Le terminal peut fonctionner simultanément avec un certain nombre d'indicateurs, de scripts et d'EA, et tous ces programmes peuvent demander les informations dont ils ont besoin sur le trading : ordres, transactions et positions. Le travail direct du programme mql5 avec la base de données du terminal n’est pas permis, en raison de considérations de stabilité globale, de sécurité et de performances.
Chaque programme mql5 reçoit sur demande pour son travail un « modèle » de l'environnement de trading dans son cache. Un cache est une zone de mémoire spéciale pour un accès rapide aux données. Par exemple, avant de commencer le traitement de l’ordre, la commande nécessaire doit être obtenue dans le cache du programme mql5. Tout le travail ultérieur, en se référant à l’ordre, sera effectué avec la copie en cache de cette commande.
Le travail avec les positions, les transactions et les ordres de l'historique est effectué de la même manière. Le schéma général d'obtention des informations de trading à partir du programme MQL5 est illustré à la figure :
Avant que les données sur l'historique de trading ne soient disponibles pour le traitement du programme mql5, elles doivent être demandées dans la base de données du terminal. Après la demande, les données obtenues seront placées dans son propre cache du programme mql5.
Il y a des conséquences éventuelles susceptibles de se produire si le cache est mal utilisé.
- si les données demandées n'ont pu être obtenues, le cache sera vide et ne contiendra pas les données nécessaires.
- si les données du cache nécessitaient des mises à jour, mais que la mise à jour n'a pas été demandée, l'utilisation de telles données peut entraîner des résultats imprévisibles. Par exemple, les données sur la position actuelle n'ont pas été mises à jour et le programme ne sait rien de la position ouverte pour le symbole donné et de la perte croissante de celui-ci.
La fonction du travail avec le cache
L'historique de trading peut contenir des milliers d'ordres et de transactions exécutés qui ne sont pas nécessaires pour le travail en cours du programme mql5. Par conséquent, le travail avec le cache est construit sur le principe des demandes. Le cache contient toujours les informations qui ont été téléchargées lors de la dernière connexion à la base de données du terminal. Si vous avez besoin d'obtenir l'historique complet des ordres et des transactions, vous devez le demander explicitement en spécifiant l'intervalle souhaité.
Pour chaque type d'information, un cache indépendant est formé. Les données sur les ordres sont stockées dans le cache de l’ordre, les informations sur les positions sont stockées dans le cache de la position, les données sur les transactions et les ordres sont stockées dans les instances respectives de l'historique du cache.
Avant de demander les informations du cache, celui-ci doit être peuplé.
Les fonctions de trading peuvent être séparées en deux catégories : les fonctions de remplissage du cache et les fonctions de lecture des informations du cache.
La fonction de remplissage du cache
Pour traiter l'historique des transactions, il doit d'abord être obtenu et placé dans le cache approprié. Les fonctions qui forment un cache peuvent être divisées en deux sous-groupes.
La fonction de remplissage du cache de trading (ordres et positions actifs) :
- Le OrderSelect(ticket) - copie l’ordre actif via son ticket (depuis la base du terminal) dans le cache de l’ordre en cours pour la demande ultérieure de ses propriétés à l'aide des fonctions OrderGetDouble(), OrderGetInteger() et OrderGetString().
- Le OrderGetTicket(index) - copie, à partir de la base du terminal de l’ordre actif, via son indice dans la liste des ordres de la base du terminal des ordres sous le cache des ordres en cours pour une demande ultérieure aux propriétés à l'aide des fonctions OrderGetDouble(), OrderGetInteger() et OrderGetString(). Le nombre total des ordres dans la base du terminal peut être obtenu à l'aide de la fonction OrdersTotal().
- Le PositionSelect(symbol) - copie la position ouverte via le nom de symbole (à partir de la base du terminal) dans le cache pour la demande ultérieure de ses propriétés à l'aide des fonctions PositionGetDouble(), PositionGetInteger() et PositionGetString().
- Le PositionGetSymbol(index) - copie la position ouverte via son indice sous la liste de position (depuis la base du terminal) de la base du terminal dans le cache pour la demande ultérieure de ses propriétés à l'aide des fonctions PositionGetDouble(), PositionGetInteger() et PositionGetString (). Le nombre total de positions dans la base du terminal peut être obtenu par la fonction PositionsTotal().
La fonction de remplissage du cache historique :
- Le HistoryOrderSelect(ticket) - copie l'ordre de l'historique via son ticket dans le cache des ordres de l'historique (depuis la base du terminal) pour les appels ultérieurs à ses propriétés par les fonctions HistoryOrderGetDouble(), HistoryOrderGetInteger() et HistoryOrderGetString().
- Le HistoryDealSelect(ticket) - copie la transaction via son ticket dans le cache des transactions (à partir de la base du terminal) pour les appels ultérieurs à ses propriétés par les fonctions HistoryDealGetDouble(), HistoryDealGetInteger() et HistoryDealGetString() .
Nous devons considérer séparément les deux fonctions, qui affectent globalement l’historique du trading disponible, dans le cache :
- Le HistorySelect(start, end) - remplit le cache de l'historique avec les transactions et les commandes pour l'intervalle spécifié du temps de serveur. Des résultats de l'exécution de cette fonction dépendent les valeurs renvoyées par HistoryDealsTotal() et HistoryOrdersTotal().
- Le HistorySelectByPosition (position_ID) - remplit le cache de l'historique avec les transactions et les ordres, ayant la position d'identifiant spécifiée. Le résultat de l'exécution de cette fonction affecte également HistoryDealsTotal() et HistoryOrdersTotal().
OrderSelect et OrderGetTicket
Les fonctions générales OrderSelect(ticket) and OrderGetTicket() fonctionnent de la même manière, - elles remplissent le cache des ordres actifs avec un seul ordre. Le OrderSelect(ticket) est destiné au cas où un ordre de ticket est connu à l'avance. Le OrderGetTicket(), en conjonction avec OrdersTotal(), permet d'examiner toutes les commandes disponibles dans le terminal de base des ordres.
PositionSelect et PositionGetSymbol
Tout comme pour les ordres, ces deux fonctions opèrent également de la même manière pour les positions - elles remplissent le cache des positions avec une seule position. Le Position PositionGetSymbol(index) requiert le numéro dans la liste de la base des positions, comme paramètre, et le PositionSelect(symbol) remplit le cache en fonction du nom du symbole, sur lequel la position est ouverte. Le nom du symbole, à son tour, peut être obtenu par la fonction PositionGetSymbol(index).
HistoryOrderSelect
Le HistoryOrderSelect(ticket) choisit dans le cache l'ordre historique à partir de la base du terminal via son ticket. La fonction est destinée à être utilisée lorsque le ticket de l’ordre demandé est connu à l'avance.
Si l'exécution réussit, le cache contiendra une seule commande et la fonction HistoryOrdersTotal() retournera une seule unité. Sinon, le cache des ordres historiques sera vide et la fonction HistoryOrdersTotal() retournera un zéro.
HistoryDealSelect
Le HistoryDealSelect(ticket) sélectionne l'offre à partir du terminal de base en fonction de son ticket. La fonction est destinée à être utilisée lorsque le ticket de la transaction est connu à l'avance.
Si l'exécution réussit, le cache contiendra une seule transaction et la fonction HistoryDealsTotal() retournera 1. Sinon, le cache de transaction sera vide et la fonction HistoryDealsTotal() retournera un zéro.
La fonction pour obtenir des informations du cache
Avant de demander des informations sur les propriétés de la position, de la transaction ou de l'ordre, il est nécessaire de mettre à jour le cache correspondant du programme mql5. Cela est dû au fait que les informations demandées peuvent avoir déjà été mises à jour, ce qui signifie que la copie, stockée dans le cache, est déjà obsolète.
-
Ordres
Afin d'obtenir des informations sur les ordres actifs, il faut d'abord les copier dans le cache des ordres actifs de l'une des deux fonctions : OrderGetTicket() ou OrderSelect(). C'est pour l'ordre, qui est stocké dans le cache, que les valeurs des propriétés seront libérées, lors de l'appel des fonctions correspondantes :
- OrderGetDouble(type_property)
- OrderGetInteger(type_property)
- OrderGetString(type_property)
Ces fonctions obtiennent toutes les données du cache, par conséquent, afin de garantir l'obtention de données précises de l’ordre, il est recommandé d'appeler la fonction qui remplit le cache.
-
Positions
Pour obtenir les informations sur une position, celle-ci doit être préalablement sélectionnée et copiée dans le cache, à l'aide d'une des deux fonctions : PositionGetSymbol ou PositionSelect. C'est à partir de ce cache, que les valeurs des propriétés de position seront libérées, lorsque les fonctions correspondantes seront appelées :
- PositionGetDouble(type_property)
- PositionGetInteger(type_property)
- PositionGetString(type_property)
Puisque ces fonctions reçoivent toutes leurs données du cache, alors afin de garantir l'obtention de données précises pour la position, il est recommandé d'appeler la fonction qui remplit le cache des positions.
-
Ordres historiques
Pour obtenir des informations sur un ordre à partir de l'historique, il est nécessaire de créer au préalable le cache des ordres historiques, en utilisant l'une des trois fonctions : HistorySelect(début, fin), HistorySelectByPosition() ou HistoryOrderSelect(ticket). Si la mise en œuvre est réussie, le cache stockera le nombre des ordres, retourné par la fonction HistoryOrdersTotal(). L'accès aux propriétés de ces ordres s'effectue par chaque élément du ticket, à l'aide de la fonction appropriée :
- HistoryOrderGetDouble(ticket_order, type_property)
- HistoryOrderGetInteger(ticket_order, type_property)
- HistoryOrderGetString(ticket_order, type_property)
Le ticket de l'ordre historique peut être retrouvé à l'aide de la fonction HistoryOrderGetTicket(index), via son indice dans le cache des ordres historiques. Afin d'avoir une réception garantie de données précises sur l’ordre, il est recommandé d'appeler la fonction qui remplit le cache des ordres historiques.
-
Transactions
Pour obtenir des informations sur une transaction spécifique dans l'historique, il est nécessaire de créer d'abord le cache des transactions, en utilisant l'une des trois fonctions : HistorySelect (début, fin), HistorySelectByPosition() ou HistoryDealSelect (ticket). Si la mise en œuvre de la fonction réussit, le cache stockera la transaction dans la quantité renvoyée par la fonction HistoryDealsTotal(). L'accès aux propriétés de ces transactions s'effectue, sur la base du ticket, à l'aide des fonctions appropriées :
- HistoryDealGetDouble(ticket_deals, type_property)
- HistoryDealGetInteger(ticket_deals, type_property)
- HistoryDealGetString(ticket_deals, type_property)
Le ticket des transactions peut être obtenu, à l'aide de la fonction HistoryDealGetTicket(index), via son indice dans le cache des transactions. Afin d'avoir une réception garantie de données précises sur la transaction, il est recommandé d'appeler la fonction qui remplit le cache des transactions.
La fonction d'obtention du ticket via l'historique de la cache
Le HistoryOrderGetTicket (index) retourne le ticket de l’ordre historique, via son indice dans le cache des ordres historiques (non dans la base du terminal !). Le ticket obtenu peut être utilisé dans la fonction HistoryOrderSelect (ticket), ce qui vide le cache et ne le remplit qu’avec un seul ordre, en cas de succès. Rappelons que la valeur, retournée par HistoryOrdersTotal() dépend du nombre des ordres dans le cache.
L’HistoryDealGetTicket(index) retourne le ticket de la transaction par son indice à partir du cache des transactions. Le ticket de la transaction peut être utilisé par la fonction HistoryDealSelect(ticket), ce qui vide le cache, et ne remplit le cache qu’avec une seule transaction, en cas de succès. La valeur retournée par la fonction HistoryDealsTotal() dépend du nombre de transactions dans le cache.
Obtention d’informations à l'aide des ordres actifs
La vérification des ordres actifs en cours est une procédure standard. S'il est nécessaire d'obtenir des informations sur un ordre donné, lorsque son ticket est connu, cela se fera en utilisant la fonction OrderSelect(ticket).
bool selected=OrderSelect(ticket); if(selected) { double price_open=OrderGetDouble(ORDER_PRICE_OPEN); datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP); string symbol=OrderGetString(ORDER_SYMBOL); PrintFormat("Ордер #%d for %s was set at %s",ticket,symbol,TimeToString(time_setup)); } else { PrintFormat("Error selecting order with ticket %d. Error %d",ticket, GetLastError()); }
Dans l'exemple ci-dessus, on suppose que le ticket de l’ordre est connu à l'avance, par exemple, il est obtenu à partir d'une variable globale. Dans des cas généraux, cependant, les informations du ticket sont absentes, et nous devons donc recourir à la fonction OrderGetTicket(index), qui sélectionne également un ordre et le place dans le cache, mais uniquement le numéro d’ordre, dans la liste des ordres en cours, qui doit être spécifié comme paramètre.
L'algorithme global pour travailler avec les ordres (analogue aux transactions et aux positions) est le suivant :
- Obtenir le nombre total des ordres à l'aide de la fonction OrdersTotal().
- Organiser la boucle par une recherche de tous les ordres, via leurs indices dans la liste.
- Copier, un après l’autre, chaque ordre dans le cache, à l'aide de la fonction OrderGetTicket().
- Obtenir les données des ordres corrects à partir du cache, à l'aide des fonctions OrderGetDouble(), OrderGetInteger() et OrderGetString(). Si nécessaire, analyser les données obtenues et prendre les mesures appropriées.
Voici un bref exemple d'un tel algorithme :
input long my_magic=555; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtain the total number of orders int orders=OrdersTotal(); //--- scan the list of orders for(int i=0;i<orders;i++) { ResetLastError(); //--- copy into the cache, the order by its number in the list ulong ticket=OrderGetTicket(i); if(ticket!=0)// if the order was successfully copied into the cache, work with it { double price_open =OrderGetDouble(ORDER_PRICE_OPEN); datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP); string symbol =OrderGetString(ORDER_SYMBOL); long magic_number =OrderGetInteger(ORDER_MAGIC); if(magic_number==my_magic) { // process the order with the specified ORDER_MAGIC } PrintFormat("Order #%d for %s was set out %s, ORDER_MAGIC=%d",ticket,symbol,TimeToString(time_setup),magic_number); } else // call OrderGetTicket() was completed unsuccessfully { PrintFormat("Error when obtaining an order from the list to the cache. Error code: %d",GetLastError()); } } }
Obtenir les informations sur les positions ouvertes
Le suivi constant des positions ouvertes n'est pas seulement une procédure standard, mais elle doit certainement être mise en œuvre dans chaque cas. Pour obtenir des informations sur des positions spécifiques, il suffit de connaître le nom de l'instrument par lequel il est ouvert. Pour ce faire, utilisez la fonction PositionSelect(symbol). S’agissant de ces cas où l'EA travaille sur un seul symbole (sur le symbole du graphique auquel il est attaché), le nom du symbole peut être obtenu via une fonction Symbol() ou à partir d'une variable _Symbol prédéfinie.
//--- we will look for the position by the symbol of the chart, on which the EA is working string symbol=Symbol(); //--- attempt to get the position bool selected=PositionSelect(symbol); if(selected) // if the position is selected { long pos_id =PositionGetInteger(POSITION_IDENTIFIER); double price =PositionGetDouble(POSITION_PRICE_OPEN); ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); long pos_magic =PositionGetInteger(POSITION_MAGIC); string comment =PositionGetString(POSITION_COMMENT); PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s", pos_id, symbol, pos_magic, price,EnumToString(type), comment); } else // if selecting the position was unsuccessful { PrintFormat("Unsuccessful selection of the position by the symbol %s. Error",symbol,GetLastError()); } }
En cas général, les informations sur le symbole peuvent être obtenues, en utilisant la fonction PositionGetSymbol (index), qui sélectionne une position et la place dans le cache. En fait de paramètre, il est nécessaire de préciser l'indice de position dans la liste des positions ouvertes. Pour ce faire, il est préférable de rechercher toutes les positions dans la boucle.
L'algorithme général pour travailler avec les positions :
- Obtenir le nombre total de positions à l'aide de la fonction PositionsTotal().
- Organiser la boucle en recherchant toutes les positions par leurs indices dans la liste.
- Copier, une après l’autre, chaque position dans le cache, à l'aide de la fonction PositionGetSymbol().
- Obtenir les données de position requises à partir du cache à l'aide des fonctions PositionGetDouble(), PositionGetInteger() et PositionGetString(). Si nécessaire, analyser les données obtenues et prendre les mesures appropriées.
Un exemple d'un tel algorithme :
#property script_show_inputs input long my_magic=555; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- obtain the total number of positions int positions=PositionsTotal(); //--- scan the list of orders for(int i=0;i<positions;i++) { ResetLastError(); //--- copy into the cache, the position by its number in the list string symbol=PositionGetSymbol(i); // obtain the name of the symbol by which the position was opened if(symbol!="") // the position was copied into the cache, work with it { long pos_id =PositionGetInteger(POSITION_IDENTIFIER); double price =PositionGetDouble(POSITION_PRICE_OPEN); ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); long pos_magic =PositionGetInteger(POSITION_MAGIC); string comment =PositionGetString(POSITION_COMMENT); if(pos_magic==my_magic) { // process the position with a specified POSITION_MAGIC } PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s", pos_id,symbol,pos_magic,price,EnumToString(type),comment); } else // call to PositionGetSymbol() was unsuccessful { PrintFormat("Error when receiving into the cache the position with index %d."+ " Error code: %d", i, GetLastError()); } } }
Règles d'utilisation du cache de l'historique
Souvent, le code pour travailler avec le cache de l'historique est écrit par le programmeur de telle manière qu'il ne fonctionne correctement que si l'historique contient 5 à 10 transactions et ordres. Un exemple typique d'une mauvaise approche - charger l'historique entier de trading dans le cache et le traiter en boucle, en recherchant tous les ordres et tous les trades :
//--- datetime start=0; // initial time set to 1970 year datetime end=TimeCurrent(); // the ending time set to the current server time //--- request into the cache of the program the entire trading history HistorySelect(start,end); //--- obtain the number of all of the orders in the history int history_orders=HistoryOrdersTotal(); //--- now scan through all of the orders for(int i=0;i<history_orders;i++) { // processing each order in the history } ... //--- obtain the number of all deals in the history int deals=HistoryDealsTotal(); //--- now scan through all of the deals for(int i=0;i<deals;i++) { // process each deal in the history }
La tentative de manipuler tout le paquet de l'historique de trading, en majorité des cas, est fausse. Lorsque le nombre de transactions/ordres traités atteint des milliers et des dizaines de milliers, le travail du programme ralentit considérablement.
Ceci est principalement important pour les tests - l'utilisateur découvre que le testeur devient soudainement délicat et commence à rechercher les raisons de cela dans le terminal client. Par conséquent, pensez toujours d'abord à optimiser le code du programme MQL5 (EA et indicateurs, qui sont appelés depuis l'EA). Ne vous fiez pas au fait que l'ordinateur est en fer et contient de nombreux noyaux de système.
Pour le bon fonctionnement de l'EA et de l'indicateur en ligne, c'est tout aussi important. Un code non optimal du programme peut paralyser le travail même de l'ordinateur le plus puissant.
L'algorithme correct pour travailler avec l'historique de trading :
- Déterminer la nécessité de demander l'historique de trading dans le cache. Si cela n'est pas nécessaire, n'effectuez donc pas les actions suivantes.
- Déterminer la date finale de l'historique de trading (il se peut que l'historique jusqu'à ce moment ne soit pas nécessaire).
- Calculer la date initiale de l'historique des transactions, à partir de la date de fin. Habituellement, les EA nécessitent l'historique de trading, pas plus d'un jour ou d'une semaine.
- Obtenez les tickets des transactions et les ordres historiques pour l'obtention des propriétés, par les tickets connus :
- HistoryOrderGetDouble()
- HistoryOrderGetInteger()
- HistoryOrderGetString()
- HistoryDealGetDouble()
- HistoryDealGetInteger()
- HistoryDealGetString()
- Si les tickets ne sont pas connus, et si cela est nécessaire, organiser un cycle en triant.
- Dans la boucle, obtenir le ticket pour chaque transaction/ordre à partir du cache de l'historique de trading, via l'indice (HistoryOrderGetTicket(Index) et HistoryDealGetTicket(Index)).
- Obtenir les propriétés nécessaires des ordres et des transactions par le ticket connu (voir point 4).
Un exemple de code pour cet algorithme :
//--- the variable, which is set in true only during the change in the trading history bool TradeHistoryChanged=false; //--- here we check for the changes in the history and put out the TradeHistoryChanged=true if needed //... the needed code //--- check if there are changes in the trading history or not if(!TradeHistoryChanged) return; //--- if the history has changed, then it makes sense to load it into the cache //--- the ending time set for the current server time datetime end=TimeCurrent(); //--- the beginning time is set to 3 days ago datetime start=end-3*PeriodSeconds(PERIOD_D1); //--- request in the cache of the program, the trading history for the last 3 days HistorySelect(start,end); //--- obtain the number of orders in the cache of the history int history_orders=HistoryOrdersTotal(); //--- now scan through the orders for(int i=0;i<history_orders;i++) { //--- obtain the ticket of the historical order ulong ticket=HistoryOrderGetTicket(i); //--- work with this order - receive its problems long order_magic=HistoryOrderGetInteger(ticket,ORDER_MAGIC); // obtain the rest of the properties for the order by the ticket // ... }
L'idée de base présentée par cet exemple - est que vous devez d'abord vérifier le fait que des changements ont lieu dans l'historique de trading. L'une des options consiste, au sein de la fonction OnTrade(), à configurer pour la variable globale TradeHistoryChanged la valeur true, car l'événement Trade retourne toujours avec n'importe quel type d'événement de trading.
Si l'historique des transactions n'a pas changé, il n'est pas nécessaire de télécharger à nouveau l'historique des transactions dans le cache et de gaspiller les ressources du processeur. Cela est logique et ne nécessite aucune explication. Si l'historique de trading a changé, nous n'en téléchargeons que la partie nécessaire et ne parcourons chaque transaction/ordre qu'une seule fois. Évitez les cycles de répétition inutiles.
Des exemples de travail correct et incorrect avec l'historique de trading sont joints à cet article, sous forme de fichiers WrongWorkWithHistory.mq5 et RightWorkWithHistory.mq5.
Obtention d'informations via des ordres extraits de l'historique
Travailler avec des ordres historiques n'est presque pas différent de travailler avec des ordres actifs, à une exception près. Si le nombre d'ordres actifs dans le cache du programme mql5 ne peut pas être supérieur à un, le résultat HistoryOrdersTotal() et le nombre des ordres historiques dans le cache, dépendent de l'historique de trading chargé par la fonction HistorySelect (start, end), HistorySelectByPosition() ou HistoryOrderSelection().
Par exemple, nous fournissons un script qui recherche le dernier ordre du dernier jour et affiche les informations correspondantes.
// --- determining the time intervals of the required trading history datetime end=TimeCurrent(); // current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request in the cache of the program the trading history for a day HistorySelect(start,end); //--- receive the number of orders in the history int history_orders=HistoryOrdersTotal(); //--- obtain the ticket of the order, which has the last index in the list, from the history ulong order_ticket=HistoryOrderGetTicket(history_orders-1); if(order_ticket>0) // obtain in the cache the historical order, work with it { //--- order status ENUM_ORDER_STATE state=(ENUM_ORDER_STATE)HistoryOrderGetInteger(order_ticket,ORDER_STATE); long order_magic =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC); long pos_ID =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID); PrintFormat("Order #%d: ORDER_MAGIC=#%d, ORDER_STATE=%d, ORDER_POSITION_ID=%d", order_ticket,order_magic,EnumToString(state),pos_ID); } else // unsuccessful attempt to obtain the order { PrintFormat("In total, in the history of %d orders, we couldn't select the order"+ " with the index %d. Error %d",history_orders,history_orders-1,GetLastError()); }
Dans des cas plus généraux, il est nécessaire de trier les ordres de la boucle du cache, et de les analyser. L'algorithme général sera le suivant :
- Déterminer les plages de temps de l'historique acceptable, si l'historique est chargé par la fonction HistorySelect() - il n'est pas recommandé de charger tout l'historique de trading dans le cache.
- Charger dans le cache du programme et de l'historique de trading les fonctions HistorySelect(), HistorySelectByPosition() ou HistoryOrderSelect (ticket).
- Obtenir le nombre total des ordres dans le cache, en utilisant HistoryOrdersTotal().
- Organiser le cycle par une recherche dans tous les ordres via leurs indices dans la liste.
- Obtenir un ticket d’ordres dans le cache, à l'aide de la fonction HistoryOrderGetTicket() .
- Obtenir les données de l’ordre à partir du cache, en utilisant les fonctions HistoryOrderGetDouble(), HistoryOrderGetInteger() et HistoryOrderGetString(). Si nécessaire, analyser les données obtenues et prendre les mesures appropriées.
Un exemple d'un tel algorithme :
#property script_show_inputs input long my_magic=999; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // --- setting the time intervals of the required trading history datetime end=TimeCurrent(); // the current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request into the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of orders in history int history_orders=HistoryOrdersTotal(); //--- now scroll through all of the orders for(int i=0;i<history_orders;i++) { //--- obtain the ticket of the order by its number in the list ulong order_ticket=HistoryOrderGetTicket(i); if(order_ticket>0) // obtain in the cache, the historical order, and work with it { //--- time of execution datetime time_done=HistoryOrderGetInteger(order_ticket,ORDER_TIME_DONE); long order_magic =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC); long pos_ID =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID); if(order_magic==my_magic) { // process the position with the set ORDER_MAGIC } PrintFormat("Order #%d: ORDER_MAGIC=#%d, time_done %s, ORDER_POSITION_ID=%d", order_ticket,order_magic,TimeToString(time_done),pos_ID); } else // unsuccessful attempt to obtain the order from the history { PrintFormat("we were not able to select the order with the index %d. Error %d", i,GetLastError()); } } }
Obtenir des informations sur les transactions à partir de l'historique
Le traitement des transactions présente les mêmes caractéristiques que le traitement des ordres historiques. Le nombre de transactions dans l'historique de trading et le résultat de l'exécution de HistoryDealsTotal() dépendent de la quantité de l'historique de trading chargée dans le cache par la fonction HistorySelect(start, end) ou HistorySelectByPosition().
Pour remplir le cache avec une seule transaction par ticket, utilisez la fonction HistoryDealSelect(ticket).
// --- determining the time intervals of the required trading history datetime end=TimeCurrent(); // current sever time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago //--- request in the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of deals in history int deals=HistoryDealsTotal(); //--- obtain the ticket for the deal, which has the last index in the list ulong deal_ticket=HistoryDealGetTicket(deals-1); if(deal_ticket>0) // we obtained in the cache of the deal, and work with it { //--- the ticket order, based on which the deal was made ulong order =HistoryDealGetInteger(deal_ticket,DEAL_ORDER); long order_magic=HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); long pos_ID =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID); PrintFormat("Deal #%d for the order #%d with the ORDER_MAGIC=%d that participated in the position", deals-1,order,order_magic,pos_ID); } else // unsuccessful attempt of obtaining a deal { PrintFormat("In total, in the history %d of deals, we couldn't select a deal"+ " with the index %d. Error %d",deals,deals-1,GetLastError()); }
Dans des cas plus généraux, il faut chercher dans la boucle des transactions du cache, et de les faire analyser. L'algorithme général sera le suivant :
- Déterminer les limites de l'historique acceptable, si l'historique est chargé par la fonction HistorySelect(start, end) - il n'est alors pas recommandé de charger l'ensemble de l'historique de trading dans le cache.
- Charger dans le cache du programme, l'historique de trading des fonctions HistorySelect() ou HistorySelectByPosition().
- Obtenir le nombre total de transactions dans l'historique, à l'aide de la fonction HistoryDealsTotal().
- Organiser le cycle en recherchant toutes les transactions, par leurs numéros dans la liste.
- Déterminer le ticket de la prochaine transaction dans le cache, en utilisant HistoryDealGetTicket().
- Obtenir les informations sur la transaction à partir du cache, en utilisant les fonctions HistoryDealGetDouble(), HistoryDealGetInteger() et HistoryDealGetString(). Si nécessaire, analyser les données obtenues et prendre les mesures appropriées.
Un exemple d'un tel algorithme pour calculer les profits et les pertes :
input long my_magic=111; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { // --- determine the time intervals of the required trading history datetime end=TimeCurrent(); // current server time datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning time to 24 hours ago //--- request in the cache of the program the needed interval of the trading history HistorySelect(start,end); //--- obtain the number of deals in the history int deals=HistoryDealsTotal(); int returns=0; double profit=0; double loss=0; //--- scan through all of the deals in the history for(int i=0;i<deals;i++) { //--- obtain the ticket of the deals by its index in the list ulong deal_ticket=HistoryDealGetTicket(i); if(deal_ticket>0) // obtain into the cache the deal, and work with it { string symbol =HistoryDealGetString(deal_ticket,DEAL_SYMBOL); datetime time =HistoryDealGetInteger(deal_ticket,DEAL_TIME); ulong order =HistoryDealGetInteger(deal_ticket,DEAL_ORDER); long order_magic =HistoryDealGetInteger(deal_ticket,DEAL_MAGIC); long pos_ID =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID); ENUM_DEAL_ENTRY entry_type=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY); //--- process the deals with the indicated DEAL_MAGIC if(order_magic==my_magic) { //... necessary actions } //--- calculate the losses and profits with a fixed results if(entry_type==DEAL_ENTRY_OUT) { //--- increase the number of deals returns++; //--- result of fixation double result=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT); //--- input the positive results into the summarized profit if(result>0) profit+=result; //--- input the negative results into the summarized losses if(result<0) loss+=result; } } else // unsuccessful attempt to obtain a deal { PrintFormat("We couldn't select a deal, with the index %d. Error %d", i,GetLastError()); } } //--- output the results of the calculations PrintFormat("The total number of %d deals with a financial result. Profit=%.2f , Loss= %.2f", returns,profit,loss); }
Obtention dans le cache de l'historique par l'identifiant de la position (POSITION_IDENTIFIER)
La fonction HistorySelectByPosition (position_ID) tout comme la fonction HistorySelect (start, end) remplit le cache avec les transactions et les ordres de l'historique, mais à une seule condition - ils doivent avoir l'identifiant spécifié de la position (POSITION_IDENTIFIER). L'identifiant de position - est un numéro unique, qui est automatiquement attribué à chaque poste rouvert, et ne change pas toute sa vie durant. Pendant ce temps, il faut garder à l'esprit que le changement de position (déplacement du type de la position de POSITION_TYPE_BUY à POSITION_TYPE_SELL) ne change pas l'identifiant de la position.
Chaque position ouverte est le résultat d'une ou plusieurs transactions sur cet instrument. Par conséquent, pour analyser les changements de position, au cours de sa durée de vie, chaque transaction et chaque ordre, sur la base desquels la transaction a été effectuée, se voit attribuer un identifiant à la position à laquelle cette transaction a participé. Ainsi, connaissant l'identifiant des positions ouvertes actuelles, nous pouvons reconstruire tout l'historique - trouver tous les ordres et transactions qui l'ont modifié.
La fonction HistorySelectByPosition(position_ID) permet d'éviter au programmeur d'avoir à écrire son propre code pour parcourir tout l'historique de trading à la recherche de telles informations. Un algorithme typique pour travailler avec cette fonction :
- Obtenir le bon identifiant de position.
- Obtenir, à l'aide de la fonction HistorySelectByPosition(), dans le cache de l'historique de trading, tous les ordres et transactions dont l'identifiant est égal à l'identifiant de la position courante.
- Traitement de l'historique de trading selon l'algorithme.
Conclusion
L'ensemble de la plate-forme de sous-système de trading MetaTrader 5 est bien pensé et convivial. De plus, l'abondance de fonctions de trading nous permet de résoudre chaque problème spécifique de la manière la plus efficace.
Mais même en dépit du fait que les classes de trading spécialisées de la bibliothèque standard, nous permettent de ne pas nous soucier de trop de nuances et d'écrire des programmes à un niveau élevé, sans entrer dans la mise en œuvre, la compréhension des bases nous permettra de créer plus des EA de trading fiables et efficaces.
Tous les exemples donnés ont des fichiers joints à cet article.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/211
![Événements de trade dans MetaTrader 5](https://c.mql5.com/2/0/trade_events.png)
![Guide de test et d'optimisation des Expert Advisors en MQL5](https://c.mql5.com/2/0/Testing_Optimization_Guide_MQL5__1.png)
![Les principes fondamentaux de tests dans MetaTrader 5](https://c.mql5.com/2/0/tester_basis_Metatrader5__1.png)
![Systèmes de trading adaptatifs et leur utilisation dans le terminal client MetaTrader 5](https://c.mql5.com/2/0/Adaptive_Expert_Advisor_MQL5__2.png)
![MQL5 - Langage des stratégies de trading intégré au terminal client MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- 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