Le MQL5 Cookbook : Traitement de l'événement de TradeTransaction
Introduction
Dans cet article, je voudrais présenter l'un des moyens de contrôler les événements de trade à l'aide de MQL5. Je dois mentionner que quelques articles ont déjà été consacrés à ce sujet. « Traitement des événements de trade dans Expert Advisor à l'aide de la fonction OnTrade() » en fait partie. Je ne vais pas répéter d'autres auteurs et utiliserai un autre gestionnaire - OnTradeTransaction().
Je voudrais attirer l'attention des lecteurs sur le point suivant. La version actuelle du langage MQL5 compte formellement 14 gestionnaires d'événements du Terminal Client. De plus, un programmeur a la possibilité de créer des événements personnalisés avec EventChartCustom() et de les traiter avec OnChartEvent(). Cependant, le terme « programmation par événement » (EDP) n'est pas du tout mentionné dans la documentation. Ceci est étrange, étant donné le fait, que tout programme en MQL5 est créé sur la base des principes EDP. Par exemple, il est proposé à l'utilisateur de faire un choix à l'étape « Gestionnaire d'événements pour l'Expert » dans un modèle de n'importe quel Expert Advisor.
Il est évident que le mécanisme de la programmation par événement est utilisé dans MQL5 d'une manière ou d'une autre. Le langage peut contenir des blocs de programme constitués de deux parties : sélection et traitement d'un événement. De plus, si l'on parle d'événements du Terminal Client, un programmeur n'a de contrôle que sur la deuxième partie, c'est-à-dire le gestionnaire d'événements. Pour être juste, il existe des exceptions pour certains événements. La minuterie et l'événement personnalisé en font partie. Le contrôle de ces événements est entièrement laissé au programmeur.
1. Événement de TradeTransaction
Avant d'approfondir notre sujet, renvoyons-nous aux informations officielles.
Selon la documentation, l'événement TradeTransaction est le résultat de certaines opérations avec un compte de trading. Une opération elle-même se compose d'un certain nombre d'étapes déterminées par des transactions. Par exemple, l'ouverture d'une position avec un ordre boursier, l'une des opérations les plus populaires avec un compte de trading, se déroule selon les étapes suivantes :
- Faire une demande de trade ;
- Vérifier la demande de trade ;
- Envoyer la demande de trade au serveur ;
- Recevoir une réponse sur l'exécution de l'ordre de trade sur le serveur.
Une telle séquence, cependant, ne montre que la logique de travail de la paire terminal-serveur qui se reflète dans les chaînes du code de l’EA. Du point de vue de l'événement de trade de TradeTransaction, l'ouverture d'une position sur le marché se fait de la manière suivante :
- Le programme MQL5 reçoit une notification du serveur sur le résultat de la demande terminée ;
- La demande sous forme d’ordre avec un ticket unique est incluse dans la liste des ordres ouverts ;
- L'ordre est supprimé de la liste des ordres ouverts après exécution ;
- Ensuite, l’ordre passe à l'historique du compte ;
- L'historique du compte contient également des données sur la transaction résultant de l'exécution de l'ordre.
Ainsi, l'ouverture d'une position nécessite cinq appels pour le gestionnaire OnTradeTransaction().
Nous discuterons du code du programme en détail un peu plus tard et maintenant nous allons examiner de près l'en-tête de la fonction. Il a trois paramètres d'entrée.
void OnTradeTransaction( const MqlTradeTransaction& trans, // structure of the trade transaction const MqlTradeRequest& request, // structure of the request const MqlTradeResult& result // structure of the response );
Ces paramètres sont décrits en détail dans la Documentation. Je voudrais noter qu'un paramètre de la structure de la transaction du trade est une sorte de transtypage des informations que le gestionnaire reçoit lors de l'appel en cours.
Je dois aussi dire quelques mots sur le type de transaction de trade car nous allons en rencontrer beaucoup.
Dans MQL5, ENUM_TRADE_TRANSACTION_TYPE est une énumération spéciale qui est responsable du type de transaction de trade. Pour savoir à quel type appartient une transaction de trade, nous devons nous référer à la constante de paramètre du type MqlTradeTransaction.
struct MqlTradeTransaction { ulong deal; // Ticket of the deal ulong order; // Ticket of the order string symbol; // Trade symbol ENUM_TRADE_TRANSACTION_TYPE type; // Type of the trade transaction ENUM_ORDER_TYPE order_type; // Type of the order ENUM_ORDER_STATE order_state; // Status of the order ENUM_DEAL_TYPE deal_type; // Type of the deal ENUM_ORDER_TYPE_TIME time_type; // Order expiration type datetime time_expiration; // Order expiration time double price; // Price double price_trigger; // Price that triggers the Stop Limit order double price_sl; // Level of Stop Loss double price_tp; // Level of Take Profit double volume; // Volume in lots };
Le quatrième champ de la structure est l'énumération même que nous recherchons.
2. Traitement des positions
Pratiquement toutes les opérations de trade qui concernent le traitement des positions impliquent cinq appels du gestionnaire OnTradeTransaction(). Parmi elles se trouvent :
- l’ouverture d'une position ;
- la position ;
- l’inversion de la position ;
- l’ajoute des lots à la position ;
- la fermeture partielle d'une position.
La modification d'une position est la seule opération de trade qui appelle deux fois le gestionnaire d'événements TradeTransaction.
Puisqu'il n'y a aucune information sur les types de transactions responsables de certaines opérations de trade, nous allons le découvrir par essais et par erreurs.
Avant cela, nous devrons créer un modèle de l'Expert qui contiendra le gestionnaire d'événements TradeTransaction. J'ai nommé ma version du modèle TradeProcessor.mq5. J'ai ajouté une fonctionnalité qui permet d'afficher des informations sur les valeurs des champs de structure dans le journal. Ces valeurs sont les paramètres de l'événement - gestionnaire. L'analyse de ces enregistrements prendra du temps, mais en fin de compte, elle paiera en présentant une image complète des événements.
Nous devons lancer l'Expert en mode débogage sur l'un des graphiques du terminal MetaTrader 5.
Ouvrez une position manuellement et jetez un coup d’œil sur le code. Le premier appel du gestionnaire sera comme ceci (Fig. 1).
Fig.1. Le champ du type est égal à TRADE_TRANSACTION_REQUEST
Les entrées suivantes apparaîtront dans le journal :
IO 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Transaction===--- NK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 0 JS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED JN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY FD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price: 0.0000 FN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 HF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Trade symbol: HD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC DN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the trade transaction TRADE_TRANSACTION_REQUEST FK 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volume in lots: 0.00
Dans ce bloc, seul l'enregistrement concernant le type de transaction nous intéresse. Comme on peut le voir, ce type appartient à la demande (TRADE_TRANSACTION_REQUEST).
Des informations sur les détails de la demande peuvent être obtenues dans le bloc « Demande ».
QG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Request===--- HL 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the trade operation: TRADE_ACTION_DEAL EE 0 17:37:53.233 TradeProcessor (EURUSD,H1) Comment to the order: JP 0 17:37:53.233 TradeProcessor (EURUSD,H1) Deviation from the requested price: 0 GS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Order expiration time: 1970.01.01 00:00 LF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Magic number of the EA: 0 FM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price: 1.3137 QR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Stop Loss level of the order: 0.0000 IJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Take Profit level of the order: 0.0000 KK 0 17:37:53.233 TradeProcessor (EURUSD,H1) StopLimit level of the order: 0.0000 FS 0 17:37:53.233 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD RD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY
Les données sur le résultat de l'exécution de la requête seront transmises au bloc « Réponse ».
KG 0 17:37:53.233 TradeProcessor (EURUSD,H1) ---===Response===--- JR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Code of the operation result: 10009 GD 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the deal: 15258202 NR 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EF 0 17:37:53.233 TradeProcessor (EURUSD,H1) Volume of the deal: 0.11 MN 0 17:37:53.233 TradeProcessor (EURUSD,H1) Price of the deal: 1.3137 HJ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Bid: 1.3135 PM 0 17:37:53.233 TradeProcessor (EURUSD,H1) Ask: 1.3137 OG 0 17:37:53.233 TradeProcessor (EURUSD,H1) Comment to the operation: RQ 0 17:37:53.233 TradeProcessor (EURUSD,H1) Request ID: 1
Après avoir analysé d'autres paramètres du gestionnaire tels que les structures de la demande et de la réponse, vous pouvez obtenir des informations supplémentaires sur la demande lors du premier appel.
Le deuxième appel concerne l'ajout de l’ordre à la liste des ordres ouverts (Fig. 2).
Fig.2. Le champ du type est égal à TRADE_TRANSACTION_ORDER_ADD
Le bloc « Transaction » est le seul dont nous avons besoin dans le journal.
MJ 0 17:41:12.280 TradeProcessor (EURUSD,H1) ---===Transaction===--- JN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 FG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY LM 0 17:41:12.280 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 LI 0 17:41:12.280 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED LP 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY QN 0 17:41:12.280 TradeProcessor (EURUSD,H1) Price: 1.3137 PD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 NL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 PG 0 17:41:12.280 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 DL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD JK 0 17:41:12.280 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 QD 0 17:41:12.280 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC IQ 0 17:41:12.280 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD PL 0 17:41:12.280 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
L’ordre, comme on peut le voir, a déjà reçu son ticket et d'autres paramètres (symbole, prix et volume) et est inclus dans la liste des ordres ouverts.
Le troisième appel du gestionnaire d'événements est lié à la suppression de l’ordre de la liste des ordres ouverts (Fig. 3).
Fig.3. Le champ du type est égal à TRADE_TRANSACTION_ORDER_DELETE
Le bloc « Transaction » est le seul dont nous avons besoin dans le journal.
PF 0 17:52:36.722 TradeProcessor (EURUSD,H1) ---===Transaction===--- OE 0 17:52:36.722 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 KL 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY EH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 QM 0 17:52:36.722 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED QK 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY HS 0 17:52:36.722 TradeProcessor (EURUSD,H1) Price: 1.3137 MH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 OP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 EJ 0 17:52:36.722 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 IH 0 17:52:36.722 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD KP 0 17:52:36.722 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 LO 0 17:52:36.722 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC HG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_DELETE CG 0 17:52:36.722 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
Il n'y a aucune nouvelle information dans ce bloc sauf le type de transaction.
Le gestionnaire est appelé pour la quatrième fois lorsqu'un nouvel ordre historique apparaît dans l'historique (Fig. 4).
Fig.4. Le champ du type est égal à TRADE_TRANSACTION_HISTORY_ADD
Nous pouvons obtenir les informations pertinentes à partir du bloc « Transaction ».
QO 0 17:57:32.234 TradeProcessor (EURUSD,H1) ---===Transaction==--- RJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 NS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DQ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 EH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_FILLED RL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY KJ 0 17:57:32.234 TradeProcessor (EURUSD,H1) Price: 1.3137 NO 0 17:57:32.234 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 PI 0 17:57:32.234 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 JS 0 17:57:32.234 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD LG 0 17:57:32.234 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 KP 0 17:57:32.234 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC OL 0 17:57:32.234 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_HISTORY_ADD JH 0 17:57:32.234 TradeProcessor (EURUSD,H1) Volume in lots: 0.00
À ce stade, nous pouvons voir que l'ordre a été exécuté.
Enfin, le dernier (le cinquième) appel a lieu lorsqu'une transaction est ajoutée à l'historique (Fig. 5).
Fig.5. Le champ du type est égal à TRADE_TRANSACTION_DEAL_ADD
Dans le journal, encore une fois, nous ne nous intéressons qu'au bloc « Transaction ».
OE 0 17:59:40.718 TradeProcessor (EURUSD,H1) ---===Transaction===--- MS 0 17:59:40.718 TradeProcessor (EURUSD,H1) Ticket of the deal: 15258202 RJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY HN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Ticket of the order: 22535869 LK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED LE 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY MM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Price: 1.3137 PF 0 17:59:40.718 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 NN 0 17:59:40.718 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 PI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 DJ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Trade symbol: EURUSD JM 0 17:59:40.718 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 QI 0 17:59:40.718 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC CK 0 17:59:40.718 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_DEAL_ADD RQ 0 17:59:40.718 TradeProcessor (EURUSD,H1) Volume in lots: 0.11
La chaîne importante dans ce bloc est le ticket de la transaction.
Je vais présenter un schéma de la transaction. Pour les postions il n'y en aura que deux. Le premier ressemble à celui de la Fig. 6.
Fig.6. Le premier schéma du processus de transaction
Toutes les opérations de trade liées au traitement des positions se déroulent conformément à ce schéma. La seule exception ici est l'opération de modification d'une position. La dernière opération comprend le traitement des deux transactions suivantes (Fig. 7).
Fig.7. Le deuxième schéma du processus de transaction
Ainsi, la modification d'une position ne peut pas être retracée dans l'historique des transactions et des ordres.
C'est à peu près tout sur les positions.
3. Types des ordres en attente
En ce qui concerne les ordres en attente, il est à noter que les opérations avec elles prennent moins de transactions. Dans le même temps, il existe davantage de combinaisons de types de transactions lorsque vous travaillez avec des ordres.
Pour modifier un ordre, le gestionnaire est appelé deux fois, comme pour modifier une position. Passer et supprimer un ordre prend trois appels. L'événement TradeTransaction se produit quatre fois lors de la suppression de l'ordre ou de son exécution.
Nous allons maintenant passer un ordre en attente. Nous devons lancer l'Expert en mode débogage sur l'un des graphiques du terminal MetaTrader 5 à nouveau.
Le premier appel du gestionnaire sera lié à la demande (Fig. 8).
Fig.8. Le champ du type est égal à TRADE_TRANSACTION_REQUEST
Le journal contiendra les entrées suivantes :
IO 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Transaction===--- NK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY DE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 0 JS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY FD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price: 0.0000 FN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 HF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 FQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Trade symbol: HD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 GS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC DN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_REQUEST FK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume in lots: 0.00 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) QG 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Request==--- IQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the trade operation: TRADE_ACTION_PENDING OE 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order comment: PQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Deviation from the requested price: 0 QS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration time: 1970.01.01 00:00 FI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Magic number of the EA: 0 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 PK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price: 1.6500 KR 0 18:13:33.195 TradeProcessor (EURUSD,H1) Stop Loss level of the order: 0.0000 OI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Take Profit level of the order: 0.0000 QK 0 18:13:33.195 TradeProcessor (EURUSD,H1) StopLimit level of the order: 0.0000 QQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD RD 0 18:13:33.195 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT LS 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order execution type: ORDER_FILLING_RETURN MN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC IK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume in lots: 0.14 NS 0 18:13:33.195 TradeProcessor (EURUSD,H1) CD 0 18:13:33.195 TradeProcessor (EURUSD,H1) ---===Response===--- RQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Code of the operation result: 10009 JI 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 GM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 LF 0 18:13:33.195 TradeProcessor (EURUSD,H1) Volume of the deal: 0.14 JN 0 18:13:33.195 TradeProcessor (EURUSD,H1) Price of the deal: 0.0000 MK 0 18:13:33.195 TradeProcessor (EURUSD,H1) Bid: 0.0000 CM 0 18:13:33.195 TradeProcessor (EURUSD,H1) Ask: 0.0000 IG 0 18:13:33.195 TradeProcessor (EURUSD,H1) Comment to the operation: DQ 0 18:13:33.195 TradeProcessor (EURUSD,H1) Request ID: 1
Le deuxième appel du gestionnaire ajoutera l'ordre à la liste des ouverts (Fig. 9).
Fig.9. Le champ du type est égal à TRADE_TRANSACTION_ORDER_ADDED
Dans le journal, nous devons voir uniquement le bloc « Transaction ».
HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) ---===Transaction===--- GQ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 CH 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY RL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 II 0 18:17:02.886 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_STARTED OG 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT GL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Price: 1.6500 IE 0 18:17:02.886 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 CO 0 18:17:02.886 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 IF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 PL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD OL 0 18:17:02.886 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 HJ 0 18:17:02.886 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC LF 0 18:17:02.886 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_ADD FR 0 18:17:02.886 TradeProcessor (EURUSD,H1) Volume in lots: 0.14
Le troisième appel du gestionnaire renouvellera les données en fonction de l’ordre passé (Fig. 10).
En particulier, le statut de l’ordre recevra la valeur ORDER_STATE_PLACED.
Fig.10. Le champ du type est égal à TRADE_TRANSACTION_ORDER_ADD
Dans le journal, nous devons voir les enregistrements du bloc « Transaction ».
HS 0 18:21:27.004 TradeProcessor (EURUSD,H1) ---===Transaction==--- GF 0 18:21:27.004 TradeProcessor (EURUSD,H1) Ticket of the deal: 0 CO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the deal: DEAL_TYPE_BUY RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Ticket of the order: 22535983 KM 0 18:21:27.004 TradeProcessor (EURUSD,H1) Status of the order: ORDER_STATE_PLACED QH 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the order: ORDER_TYPE_BUY_LIMIT EG 0 18:21:27.004 TradeProcessor (EURUSD,H1) Price: 1.6500 GL 0 18:21:27.004 TradeProcessor (EURUSD,H1) Level of Stop Loss: 0.0000 ED 0 18:21:27.004 TradeProcessor (EURUSD,H1) Level of Take Profit: 0.0000 GO 0 18:21:27.004 TradeProcessor (EURUSD,H1) Price that triggers the Stop Limit order: 0.0000 RE 0 18:21:27.004 TradeProcessor (EURUSD,H1) Trade symbol: GBPUSD QS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Pending order expiration time: 1970.01.01 00:00 JS 0 18:21:27.004 TradeProcessor (EURUSD,H1) Order expiration type: ORDER_TIME_GTC RD 0 18:21:27.004 TradeProcessor (EURUSD,H1) Type of the trade transaction: TRADE_TRANSACTION_ORDER_UPDATE JK 0 18:21:27.004 TradeProcessor (EURUSD,H1) Volume in lots: 0.14
La chaîne la plus importante ici est le statut de l’ordre.
Contrairement au traitement des positions, le traitement des ordres en attente ne peut pas être mis en œuvre par un schéma. Chaque opération de trade liée à un ordre en attente sera unique du point de vue des types de transactions de trading.
Passer un ordre en attente nécessitera trois transactions (Fig. 11).
Fig.11. Transactions, traitement de la passation d'un ordre en attente
La modification d'un ordre en attente générera deux transactions (Fig. 12).
Fig.12. Transactions, traitement de la modification d'un ordre en attente
Si l'ordre en attente doit être supprimé, le gestionnaire OnTradeTransaction() sera appelé quatre fois (Fig. 13).
Fig.13. Transactions, traitement de la suppression d'un ordre en attente
La suppression d'un ordre en attente est définie par le schéma suivant (Fig. 14).
Fig.14. Transactions, traitement d'une suppression d'un ordre en attente
Le déclenchement d’un ordre en attente, la dernière opération de trade, induira quatre transactions différentes (Fig. 15).
Fig.15. Transactions, traitement de l’activation d'un ordre en attente
Je ne vais pas apporter les entrées du journal pour chaque combinaison de transactions. Si le lecteur le souhaite, il peut les étudier en exécutant le code.
4. Gestionnaire universel
Jetons un coup d'œil sur le programme qui peut fonctionner avec l'événement TradeTransaction à travers les yeux de l'utilisateur final. L'utilisateur final a très probablement besoin d'un programme capable de fonctionner parfaitement à la fois avec les ordres et les positions. Un programmeur doit écrire le code pour OnTradeTransaction() de la manière qui lui permettra d'identifier toutes les transactions et leurs combinaisons, indépendamment de ce qui a été traité - une position ou un ordre. Idéalement, le programme devrait être capable d'indiquer quelle opération a été exécutée à la fin du traitement de la série de transactions.
Dans l'exemple ci-dessous, un traitement séquentiel de transaction est utilisé. Le développeur de MQL5 déclare cependant ce qui suit :
Ainsi, si l'exigence est d'écrire un programme fonctionnant près de l'idéal, vous pouvez améliorer l'exemple suggéré et rendre le traitement des transactions indépendant de l'ordre d'arrivée des transactions.
En général, les positions et les ordres peuvent avoir des types de transactions communs. Il existe 11 types de transactions. Seuls quatre de ceux-ci ont quelque chose à voir avec le trading depuis le terminal :
- TRADE_TRANSACTION_DEAL_UPDATE ;
- TRADE_TRANSACTION_DEAL_DELETE ;
- TRADE_TRANSACTION_HISTORY_UPDATE ;
- TRADE_TRANSACTION_HISTORY_DELETE.
Nous n'allons pas les aborder dans cet article. Ces types, selon le développeur, ont été conçus pour étendre les fonctionnalités du côté du serveur de trading. Je dois admettre que je n'ai jamais traité de tels types auparavant.
Cela nous laisse avec sept types complets qui sont traités le plus souvent dans OnTradeTransaction().
Dans le corps du gestionnaire, le segment, définissant le type de transaction courant, aura un rôle important.
//--- ========== Types of transaction [START] switch(trans_type) { //--- 1) if it is a request case TRADE_TRANSACTION_REQUEST: { //--- break; } //--- 2) if it is an addition of a new open order case TRADE_TRANSACTION_ORDER_ADD: { //--- break; } //--- 3) if it is a deletion of an order from the list of open ones case TRADE_TRANSACTION_ORDER_DELETE: { //--- break; } //--- 4) if it is an addition of a new order to the history case TRADE_TRANSACTION_HISTORY_ADD: { //--- break; } //--- 5) if it is an addition of a deal to history case TRADE_TRANSACTION_DEAL_ADD: { //--- break; } //--- 6) if it is a modification of a position case TRADE_TRANSACTION_POSITION: { //--- break; } //--- 7) if it is a modification of an open order case TRADE_TRANSACTION_ORDER_UPDATE: { //--- break; } } //--- ========== Types of transactions [END]
Nous essaierons de définir quelle opération de trade nous traitons par le type de transaction actuel. Pour savoir sur quoi on travaille - une position ou un ordre, on va déléguer la mémorisation du type d'opération de trade au cas-module de traitement de la demande.
Le module lui-même ressemblera à ceci :
//--- 1) if it is a request case TRADE_TRANSACTION_REQUEST: { //--- last_action=request.action; string action_str; //--- what is the request for? switch(last_action) { //--- а) on market case TRADE_ACTION_DEAL: { action_str="place a market order"; trade_obj=TRADE_OBJ_POSITION; break; } //--- б) place a pending order case TRADE_ACTION_PENDING: { action_str="place a pending order"; trade_obj=TRADE_OBJ_ORDER; break; } //--- в) modify position case TRADE_ACTION_SLTP: { trade_obj=TRADE_OBJ_POSITION; //--- StringConcatenate(action_str,request.symbol,": modify the levels of Stop Loss", " and Take Profit"); //--- break; } //--- г) modify order case TRADE_ACTION_MODIFY: { action_str="modify parameters of the pending order"; trade_obj=TRADE_OBJ_ORDER; break; } //--- д) delete order case TRADE_ACTION_REMOVE: { action_str="delete pending order"; trade_obj=TRADE_OBJ_ORDER; break; } } //--- if(InpIsLogging) Print("Request received: "+action_str); //--- break; }
Changer quelques variables n'est pas difficile dans ce cas.
static ENUM_TRADE_REQUEST_ACTIONS last_action; // market operation at the first pass
La variable last_action mémorisera la raison pour laquelle le gestionnaire d'événements a été lancé.
static ENUM_TRADE_OBJ trade_obj; // specifies the trade object at the first pass
La variable trade_obj gardera en mémoire ce qui a été traité - une position ou un ordre. Pour cela nous allons créer l'énumération ENUM_TRADE_OBJ.
Après cela, nous allons passer au module qui traitera les transactions de type TRADE_TRANSACTION_ORDER_ADD :
//--- 2) if it is an addition of a new open order case TRADE_TRANSACTION_ORDER_ADD: { if(InpIsLogging) { if(trade_obj==TRADE_OBJ_POSITION) Print("Open a new market order: "+ EnumToString(trans.order_type)); //--- else if(trade_obj==TRADE_OBJ_ORDER) Print("Place a new pending order: "+ EnumToString(trans.order_type)); } //--- break; }
Ce module est assez simple. Étant donné que la position a été traitée à la première étape, une entrée de journal « Ouvrir un nouvel ordre boursier » apparaîtra au niveau de l'actuelle, sinon « Passer un nouvel ordre en attente ». Il n'y a plus d'actions autres qu'informatives dans ce bloc.
C'est maintenant au tour du troisième module qui traite le type TRADE_TRANSACTION_ORDER_DELETE :
//--- 3) if it is a deletion of an order from the list of open ones case TRADE_TRANSACTION_ORDER_DELETE: { if(InpIsLogging) PrintFormat("Order deleted from the list of open ones: #%d, "+ EnumToString(trans.order_type),trans.order); //--- break; }
Ce module n'a également qu'un rôle informatif.
Le quatrième cas-module traite le type TRADE_TRANSACTION_HISTORY_ADD :
//--- 4) if it is an addition of a new order to the history case TRADE_TRANSACTION_HISTORY_ADD: { if(InpIsLogging) PrintFormat("Order added to the history: #%d, "+ EnumToString(trans.order_type),trans.order); //--- if a pending order is being processed if(trade_obj==TRADE_OBJ_ORDER) { //--- if it is the third pass if(gTransCnt==2) { //--- if the order was canceled, check the deals datetime now=TimeCurrent(); //--- request the history of orders and deals HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- attempt to find a deal for the order CDealInfo myDealInfo; int all_deals=HistoryDealsTotal(); //--- bool is_found=false; for(int deal_idx=all_deals;deal_idx>=0;deal_idx--) if(myDealInfo.SelectByIndex(deal_idx)) if(myDealInfo.Order()==trans.order) is_found=true; //--- if the deal was not found if(!is_found) { is_to_reset_cnt=true; //--- PrintFormat("Order canceled: #%d",trans.order); } } //--- if it is the fourth pass if(gTransCnt==3) { is_to_reset_cnt=true; PrintFormat("Order deleted: #%d",trans.order); } } //--- break; }
En plus de l'enregistrement selon lequel l’ordre a été ajouté à l'historique, ce module vérifie si nous avons initialement travaillé avec un ordre en attente. Dans le cas où nous l'avons fait, nous devons découvrir le numéro de la passe actuelle du gestionnaire. Le fait est que ce type de transaction peut apparaître au troisième passage lors du travail avec l’ordre, si un ordre en attente a été annulé. Au quatrième passage, ce type peut apparaître lorsqu'un ordre en attente a été supprimé.
Aux niveau des chaînes du module vérifiant la troisième passe, nous devons nous référer à nouveau à l'historique des transactions. Si un accord pour l’ordre en attente n'est pas trouvé, nous considérerons un tel ordre comme annulé.
Le cinquième cas-module traite le type TRADE_TRANSACTION_DEAL_ADD. C'est le plus gros bloc du programme par la taille des chaînes.
La transaction est vérifiée dans ce bloc. Il est important de choisir une transaction par ticket pour accéder à ses propriétés. Un type de transaction peut fournir des informations si la position était ouverte, fermée, etc. Des informations sur le déclenchement d'un ordre en attente peuvent également y être récupérées. C'est le seul cas où un ordre en attente pourrait générer une transaction dans le contexte de travail du gestionnaire d'événements TradeTransaction.
//--- 5) if it is an addition of a deal to history case TRADE_TRANSACTION_DEAL_ADD: { is_to_reset_cnt=true; //--- ulong deal_ticket=trans.deal; ENUM_DEAL_TYPE deal_type=trans.deal_type; //--- if(InpIsLogging) PrintFormat("Deal added to history: #%d, "+EnumToString(deal_type),deal_ticket); if(deal_ticket>0) { datetime now=TimeCurrent(); //--- request the history of orders and deals HistorySelect(now-PeriodSeconds(PERIOD_H1),now); //--- select a deal by the ticket if(HistoryDealSelect(deal_ticket)) { //--- check the deal CDealInfo myDealInfo; myDealInfo.Ticket(deal_ticket); long order=myDealInfo.Order(); //--- parameters of the deal ENUM_DEAL_ENTRY deal_entry=myDealInfo.Entry(); double deal_vol=0.; //--- if(myDealInfo.InfoDouble(DEAL_VOLUME,deal_vol)) if(myDealInfo.InfoString(DEAL_SYMBOL,deal_symbol)) { //--- position CPositionInfo myPos; double pos_vol=WRONG_VALUE; //--- if(myPos.Select(deal_symbol)) pos_vol=myPos.Volume(); //--- if the market was entered if(deal_entry==DEAL_ENTRY_IN) { //--- 1) opening of a position if(deal_vol==pos_vol) PrintFormat("\n%s: new position opened",deal_symbol); //--- 2) addition to the open position else if(deal_vol<pos_vol) PrintFormat("\n%s: addition to the current position",deal_symbol); } //--- if the market was exited else if(deal_entry==DEAL_ENTRY_OUT) { if(deal_vol>0.0) { //--- 1) closure of a position if(pos_vol==WRONG_VALUE) PrintFormat("\n%s: position closed",deal_symbol); //--- 2) partial closure of the open position else if(pos_vol>0.0) PrintFormat("\n%s: partial closing of the current position",deal_symbol); } } //--- if position was reversed else if(deal_entry==DEAL_ENTRY_INOUT) { if(deal_vol>0.0) if(pos_vol>0.0) PrintFormat("\n%s: position reversal",deal_symbol); } } //--- order activation if(trade_obj==TRADE_OBJ_ORDER) PrintFormat("Pending order activation: %d",order); } } //--- break; }
Le type de transaction TRADE_TRANSACTION_POSITION est unique et n'est traité que lorsqu'une position est modifiée :
//--- 6) if it is a modification of a position case TRADE_TRANSACTION_POSITION: { is_to_reset_cnt=true; //--- PrintFormat("Modification of a position: %s",deal_symbol); //--- if(InpIsLogging) { PrintFormat("New price of stop loss: %0."+ IntegerToString(_Digits)+"f",trans.price_sl); PrintFormat("New price of take profit: %0."+ IntegerToString(_Digits)+"f",trans.price_tp); } //--- break; }
Le dernier module de cas est activé lors du traitement du type TRADE_TRANSACTION_ORDER_UPDATE.
Ce type n'apparaît que pour le travail avec un ordre en attente. Il se lance au déclenchement de toute opération de trade, concernant les ordres en attente, cependant le stade peut varier.
//--- 7) if it is a modification of an open order case TRADE_TRANSACTION_ORDER_UPDATE: { //--- if it was the first pass if(gTransCnt==0) { trade_obj=TRADE_OBJ_ORDER; PrintFormat("Canceling the order: #%d",trans.order); } //--- if it was the second pass if(gTransCnt==1) { //--- if it is an order modification if(last_action==TRADE_ACTION_MODIFY) { PrintFormat("Pending order modified: #%d",trans.order); //--- clear counter is_to_reset_cnt=true; } //--- if it is deletion of the order if(last_action==TRADE_ACTION_REMOVE) { PrintFormat("Delete pending order: #%d",trans.order); } } //--- if it was the third pass if(gTransCnt==2) { PrintFormat("A new pending order was placed: #%d, "+ EnumToString(trans.order_type),trans.order); //--- clear counter is_to_reset_cnt=true; } //--- break; }
En résumé, si ce type apparaissait au premier déclenchement de OnTradeTransaction(), alors l'ordre était soit annulé, soit exécuté.
Si le type apparaissait au deuxième lancement du gestionnaire d'événements, alors l’ordre était soit supprimé, soit modifié. Pour savoir exactement à quoi a abouti l'ordre, reportez-vous à la variable statique last_action qui contient les données sur la dernière opération de trading.
Le troisième lancement du gestionnaire d'événements est le dernier cas où ce type peut apparaître. Le troisième lancement termine la procédure de passation d'un ordre en attente.
Une variable booléenne is_to_reset_cnt est également utilisée dans le code. Il a un rôle d’indicateur pour effacer un compteur des passes du gestionnaire OnTradeTransaction().
C'est à peu près tout sur le traitement de l'événement TradeTransaction. J'ajouterais également une pause au début de l'appel au gestionnaire. Cela minimisera le risque qu'une transaction ou un ordre soit retardé dans l'accès à l'historique.
Conclusion
Dans cet article, j'ai essayé d'illustrer comment différentes opérations de trade peuvent être utilisées et comment récupérer des informations sur les événements qui se produisent dans le terminal.
Le plus grand avantage de cette approche est que le programme peut recevoir des informations sur la mise en œuvre progressive d'une opération de trade. À mon avis, une telle approche peut être utilisée pour copier des transactions d'un terminal à un autre.
Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/1111
- 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