Manuale MQL5: Elaborazione dell'evento TradeTransaction
Introduzione
In questo articolo vorrei introdurre uno dei modi per controllare gli eventi di trading utilizzando i mezzi di MQL5. Devo dire che alcuni articoli sono già stati dedicati a questo argomento. "Elaborazione di eventi di trading in Expert Advisor utilizzando la funzione OnTrade()" è uno di questi. Non ripeterò altri autori e userò un altro gestore: OnTradeTransaction().
Vorrei attirare l'attenzione dei lettori sul punto seguente. L'attuale versione del linguaggio MQL5 conta formalmente 14 gestori di eventi del Terminale Cliente. Inoltre, un programmatore ha la possibilità di creare eventi personalizzati con EventChartCustom() ed elaborarli con OnChartEvent(). Tuttavia, il termine "programmazione guidata dagli eventi" (EDP) non è affatto menzionato nella documentazione. È strano, visto che qualsiasi programma in MQL5 è creato sulla base dei principi EDP. Ad esempio, all'utente viene offerto di effettuare una scelta al passaggio "Gestore di eventi per l'Expert" in un modello di qualsiasi Expert Advisor.
È ovvio che il meccanismo della Programmazione guidata dagli eventi viene utilizzato in MQL5 in un modo o nell'altro. Il linguaggio può contenere blocchi di programma composti da due parti: selezione ed elaborazione di un evento. Inoltre, se si tratta di eventi del Terminale Cliente, un programmatore ha il controllo solo sulla seconda parte, ovvero l'event handler. Per essere onesti, ci sono eccezioni per alcuni eventi. Timer ed evento personalizzato sono tra questi. Il controllo di questi eventi è lasciato interamente al programmatore.
1. TradeTransaction Event
Prima di approfondire il nostro argomento, facciamo riferimento alle informazioni ufficiali.
Secondo la documentazione, l'evento TradeTransaction è il risultato di determinate operazioni con un conto di trading. Un'operazione stessa consiste in una serie di fasi determinate dalle transazioni. Ad esempio, l'apertura di una posizione con un ordine di mercato, una delle operazioni più popolari con un conto di trading, viene implementata nelle seguenti fasi:
- //--- invia una richiesta di trade
- Verificare la richiesta di scambio;
- Invia la richiesta di scambio al server;
- Ricevi una risposta sull'esecuzione dell'ordine di trading sul server.
Tale sequenza, però, mostra solo la logica di lavoro della coppia terminale-server che si riflette nelle stringhe del codice EA. Dal punto di vista dell'evento di trading TradeTransaction, l'apertura di una posizione sul mercato avviene nel seguente modo:
- Il programma MQL5 riceve una notifica dal server sul risultato della richiesta completata;
- La richiesta sotto forma di ordine con ticket univoco viene inserita nella lista degli ordini aperti;
- L'ordine viene cancellato dalla lista degli ordini aperti dopo l'esecuzione;
- Quindi, l'ordine passa alla cronologia dell'account;
- La cronologia dell'account contiene anche i dati sul deal in cui risulta l'esecuzione dell'ordine.
Quindi, l'apertura di una posizione richiede cinque chiamate per il gestore OnTradeTransaction().
Discuteremo il codice del programma in dettaglio un po' più tardi e ora daremo un'occhiata da vicino all'intestazione della funzione. Ha tre parametri di input.
void OnTradeTransaction( const MqlTradeTransaction& trans, // structure of the trade transaction const MqlTradeRequest& request, // structure of the request const MqlTradeResult& result // structure of the response );
Questi parametri sono descritti in dettaglio nella documentazione. Vorrei sottolineare che un parametro della struttura della transazione di trading è una sorta di cast delle informazioni che il gestore riceve durante la chiamata in corso.
Devo anche dire alcune parole sul tipo di transazione di trading poiché la incontreremo spesso.
In MQL5, ENUM_TRADE_TRANSACTION_TYPE è un'enumerazione speciale responsabile del tipo di transazione di trading. Per scoprire a quale tipo appartiene una transazione di trading, dobbiamo fare riferimento al parametro-costante del tipo 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 };
Il quarto campo della struttura è proprio l'enumerazione che stiamo cercando.
2. Elaborazione delle posizioni
Praticamente tutte le operazioni di trading che riguardano l'elaborazione delle posizioni comportano cinque chiamate del gestore OnTradeTransaction(). Tra questi ci sono:
- apertura di una posizione;
- Posizione:
- inversione di posizione;
- aggiungere lotti alla posizione;
- chiusura parziale di una posizione.
La modifica di una posizione è l'unica operazione di trading che chiama due volte il gestore dell'evento TradeTransaction.
Poiché non ci sono informazioni su quali tipi di transazione sono responsabili di determinate operazioni di trading, lo scopriremo attraverso tentativi ed errori.
Prima di ciò, dovremo creare un modello dell'Expert che conterrà il gestore dell'evento TradeTransaction. Ho chiamato la mia versione del modello TradeProcessor.mq5. Ho aggiunto una funzionalità che abilita la visualizzazione delle informazioni sui valori dei campi della struttura nel log. Questi valori sono i parametri dell'evento - gestore. L'analisi di questi record richiederà molto tempo, ma alla fine ripagherà presentando il quadro completo degli eventi.
Dobbiamo avviare l'Expert in modalità debug su uno qualsiasi dei grafici nel terminale MetaTrader 5.
Apri una posizione manualmente e dai un'occhiata al codice. La prima chiamata dell'handler sarà così (Fig. 1).
Fig.1. Il campo del tipo è uguale a TRADE_TRANSACTION_REQUEST
Nel registro appariranno le seguenti voci:
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
In questo blocco ci interessa solo il record relativo al tipo di transazione. Come possiamo vedere, questo tipo appartiene alla richiesta (TRADE_TRANSACTION_REQUEST).
Informazioni sui dettagli della richiesta possono essere ottenute nel blocco "Richiesta".
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
I dati sull'esito dell'esecuzione della richiesta arriveranno al blocco "Risposta".
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
Dopo aver analizzato altri parametri del gestore come le strutture della richiesta e della risposta, è possibile ottenere informazioni aggiuntive sulla richiesta alla prima chiamata.
Il secondo bando riguarda l'inserimento dell'ordine nella lista degli ordini aperti (Fig. 2).
Fig.2. Il campo del tipo è uguale a TRADE_TRANSACTION_ORDER_ADD
Il blocco "Transazione" è l'unico di cui abbiamo bisogno nel registro.
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'ordine, come possiamo vedere, ha già ricevuto il suo ticket e altri parametri (simbolo, prezzo e volume) ed è incluso nell'elenco degli ordini aperti.
La terza chiamata dell'event handler è connessa alla cancellazione dell'ordine dalla lista di quelli aperti (Fig. 3).
Fig.3. Il campo tipo è uguale a TRADE_TRANSACTION_ORDER_DELETE
Il blocco "Transazione" è l'unico di cui abbiamo bisogno nel registro.
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
Non ci sono nuove informazioni in questo blocco tranne il tipo di transazione.
Il conduttore viene chiamato per la quarta volta quando nella storia compare un nuovo ordine storico (Fig. 4).
Fig.4. Il campo del tipo è uguale a TRADE_TRANSACTION_HISTORY_ADD
Possiamo ottenere le informazioni rilevanti dal blocco "Transazione".
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
In questa fase, possiamo vedere che l'ordine è stato eseguito.
Infine, l'ultima (la quinta) chiamata avviene quando una mano viene aggiunta allo storico (Fig. 5).
Fig.5. Il campo del tipo è uguale a TRADE_TRANSACTION_DEAL_ADD
Nel log, ancora, ci interessa solo il blocco "Transazione".
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 stringa importante in questo blocco è il biglietto(ticket) del deal.
Presenterò uno schema della transazione. Per le posizioni ce ne saranno solo due. Il primo assomiglia a quello della Fig. 6.
Fig.6. Il primo schema del processo di transazione
Tutte le operazioni di trading connesse all'elaborazione delle posizioni avvengono secondo questo schema. L'unica eccezione qui è l'operazione di modifica di una posizione. L'ultima operazione include l'elaborazione delle due transazioni seguenti (Fig. 7).
Fig.7. Il secondo schema del processo di transazione
Quindi, la modifica di una posizione non può essere rintracciata nella cronologia delle trattative e degli ordini.
Questo è praticamente tutto quello che c’è da dire sulle posizioni.
3. Elaborazione di ordini in sospeso
Per quanto riguarda gli ordini pendenti, si segnala che le operazioni con gli stessi richiedono meno transazioni. Allo stesso tempo, ci sono più combinazioni di tipi di transazione quando si lavora con gli ordini.
Per modificare un ordine, il gestore viene chiamato due volte, in modo simile alla modifica di una posizione. Effettuare ed eliminare un ordine richiede tre chiamate. L'evento TradeTransaction si verifica quattro volte all'eliminazione dell'ordine o alla sua esecuzione.
Ora effettueremo un ordine in sospeso. Dobbiamo avviare nuovamente l'Expert in modalità debug su uno qualsiasi dei grafici nel terminale MetaTrader 5.
La prima chiamata dell'handler sarà collegata alla richiesta (Fig. 8).
Fig.8. Il campo del tipo è uguale a TRADE_TRANSACTION_REQUEST
Il registro conterrà le seguenti voci:
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
La seconda chiamata dell'handler aggiungerà l'ordine alla lista di quelli aperti (Fig. 9).
Fig.9. Il campo del tipo è uguale a TRADE_TRANSACTION_ORDER_ADDED
Nel registro dobbiamo vedere solo il blocco "Transazione".
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
La terza convocazione dell'handler rinnoverà i dati secondo l'ordine effettuato (Fig. 10).
In particolare, lo stato dell'ordine riceverà il valore di ORDER_STATE_PLACED.
Fig.10. Il campo del tipo è uguale a TRADE_TRANSACTION_ORDER_UPDATE
Nel registro, dobbiamo vedere i record per il blocco "Transazione".
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 stringa più importante qui è lo stato dell'ordine.
A differenza dell'elaborazione delle posizioni, l'elaborazione degli ordini in sospeso non può essere implementata da uno schema. Ogni operazione di trading connessa ad un ordine in sospeso sarà unica dal punto di vista dei tipi di transazioni di trading.
L'inserimento di un ordine in sospeso richiederà tre transazioni (Fig. 11).
Fig.11. Transazioni, elaborazione del posizionamento di un ordine in sospeso
La modifica di un ordine in sospeso genererà due transazioni (Fig. 12).
Fig.12. Transazioni, elaborazione della modifica di un ordine in sospeso
Se l'ordine in sospeso deve essere eliminato, il gestore OnTradeTransaction() verrà chiamato quattro volte (Fig. 13).
Fig.13. Transazioni, elaborazione della cancellazione di un ordine in sospeso
La cancellazione di un ordine in sospeso è definita dal seguente schema (Fig. 14).
Fig.14. Transazioni, elaborazione della cancellazione di un ordine in sospeso
L'attivazione di un ordine pendente, l'ultima operazione di trading, indurrà quattro diverse transazioni (Fig. 15).
Fig.15. Transazioni, elaborazione attivazione di un ordine in sospeso
Non porterò le voci di registro per ogni combinazione di transazioni. Se il lettore si sente così incline, può studiarli eseguendo il codice.
4. Gestore universale
Diamo un'occhiata al programma che può funzionare con l'evento TradeTransaction attraverso gli occhi dell'utente finale. È molto probabile che l'utente finale abbia bisogno di un programma in grado di funzionare perfettamente sia con gli ordini che con le posizioni. Un programmatore deve scrivere il codice per OnTradeTransaction() nel modo in cui gli consentirà di identificare tutte le transazioni e le loro combinazioni indipendentemente da ciò che è stato elaborato: una posizione o un ordine. Idealmente, il programma dovrebbe essere in grado di indicare quale operazione è stata eseguita al termine dell'elaborazione della serie di transazioni.
Nell'esempio seguente, viene utilizzata un'elaborazione sequenziale della transazione. Lo sviluppatore di MQL5 afferma però quanto segue:
Quindi, se il requisito è scrivere un programma che funzioni vicino all'ideale, è possibile migliorare l'esempio suggerito e rendere l'elaborazione delle transazioni indipendente dall'ordine di arrivo delle transazioni.
In generale, le posizioni e gli ordini possono avere tipi comuni di transazioni. Ci sono 11 tipi di transazioni. Solo quattro su quel numero hanno qualcosa a che fare con il trading dal terminale:
- TRADE_TRANSACTION_DEAL_UPDATE;
- TRADE_TRANSACTION_DEAL_DELETE;
- TRADE_TRANSACTION_HISTORY_UPDATE
- TRADE_TRANSACTION_HISTORY_DELETE.
Non li discuteremo in questo articolo. Questi tipi, secondo lo sviluppatore, sono stati progettati per estendere le funzionalità sul lato server di trading. Devo ammettere che non ho mai avuto a che fare con tali tipi prima.
Questo ci lascia con sette tipi completi che vengono elaborati più spesso in OnTradeTransaction().
Nel corpo del gestore, il segmento che definisce il tipo di transazione corrente, avrà un ruolo importante.
//--- ========== 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]
Cercheremo di definire quale operazione di trading stiamo elaborando in base al tipo di transazione corrente. Per sapere con cosa stiamo lavorando - una posizione o un ordine, delegheremo la memorizzazione del tipo di operazione di trading al modulo caso di elaborazione della richiesta.
Il modulo stesso avrà il seguente aspetto:
//--- 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; }
Cambiare alcune variabili non è difficile in questo caso.
static ENUM_TRADE_REQUEST_ACTIONS last_action; // market operation at the first pass
La variabile last_action memorizzerà il motivo per cui è stato lanciato il gestore di eventi.
static ENUM_TRADE_OBJ trade_obj; // specifies the trade object at the first pass
La variabile trade_obj manterrà in memoria ciò che è stato elaborato: una posizione o un ordine. Per questo creeremo l'enumerazione ENUM_TRADE_OBJ.
Successivamente, passeremo al modulo che elaborerà le transazioni del tipo 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; }
Questo modulo è piuttosto semplice. Poiché la posizione è stata elaborata al primo passaggio, in quella corrente apparirà una voce di registro "Apri un nuovo ordine di mercato", altrimenti "Inserisci un nuovo ordine in sospeso". Non ci sono altre azioni oltre a quelle informative in questo blocco.
Ora è il turno del terzo modulo che elabora il tipo 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; }
Questo modulo ha anche solo un ruolo informativo.
Il quarto modulo caso elabora il tipo 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; }
Oltre al record che l'ordine è stato aggiunto alla cronologia, questo modulo esegue un controllo se abbiamo lavorato inizialmente con un ordine in sospeso. Nel caso in cui lo abbiamo fatto, dobbiamo scoprire quale numero ha il passaggio corrente del conduttore. Il fatto è che questo tipo di transazione può apparire al terzo passaggio quando si lavora con l'ordine, se un ordine in sospeso è stato annullato. Al quarto passaggio questo tipo può apparire quando un ordine in sospeso è stato cancellato.
Alle stringhe del modulo che controlla il terzo passaggio, dobbiamo fare nuovamente riferimento allo storico delle trattative. Se non viene trovata un'offerta per l'ordine corrente, considereremo tale ordine annullato.
Il quinto modulo caso elabora il tipo TRADE_TRANSACTION_DEAL_ADD. È il blocco più grande del programma per la dimensione delle stringhe.
Il deal è verificato in questo blocco. È importante scegliere un deal dal biglietto(ticket) per accedere alle sue proprietà. Un tipo di deal può fornire informazioni se la posizione era aperta, chiusa, ecc. Anche le informazioni sull'attivazione di un ordine in sospeso possono essere recuperate lì. È l'unico caso in cui un ordine in sospeso potrebbe generare un accordo nel contesto di lavoro del gestore eventi 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; }
Il tipo di transazione TRADE_TRANSACTION_POSITION è unico e viene elaborato solo quando una posizione viene modificata:
//--- 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; }
L'ultimo modulo case viene abilitato all'elaborazione del tipo TRADE_TRANSACTION_ORDER_UPDATE.
Questo tipo viene visualizzato solo per il lavoro con un ordine in sospeso. Si avvia all'avvio di qualsiasi operazione di trading, riguardante gli ordini in sospeso, tuttavia la fase può variare.
//--- 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; }
Riassumendo, se questo tipo è apparso alla prima attivazione di OnTradeTransaction(), l'ordine è stato annullato o eseguito.
Se il tipo è apparso al secondo avvio del gestore eventi, l'ordine è stato eliminato o modificato. Per sapere esattamente cosa ha generato l'ordine, fare riferimento alla variabile statica last_action che contiene i dati sull'ultima operazione di trading.
Il terzo avvio del gestore eventi è l'ultimo caso in cui questo tipo può essere visualizzato. Il terzo lancio completa la procedura di immissione di un ordine in sospeso.
Nel codice viene utilizzata anche una variabile booleana is_to_reset_cnt. Ha un ruolo di flag per cancellare un contatore dei passaggi dell'handle OnTradeTransaction().
Questo è praticamente tutto sull'elaborazione dell'evento TradeTransaction. Aggiungerei anche una pausa all'inizio della chiamata per il gestore. Ridurrà al minimo la possibilità che un accordo o un ordine venga ritardato nell'accesso alla cronologia.
Conclusione
In questo articolo ho cercato di illustrare come è possibile lavorare con diverse operazioni di trading e come recuperare informazioni su ciò che accade nel terminale.
Il più grande vantaggio di questo approccio è che il programma può ricevere informazioni sull'attuazione graduale di un'operazione di trading. A mio parere, un tale approccio può essere utilizzato per copiare le offerte da un terminale all'altro.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/1111
- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso