Eventi di Trade in MetaTrader 5
Introduzione
Tutti i comandi per eseguire operazioni di trading vengono passati al server di trading dal client terminal MetaTrader 5 tramite l'invio di richieste. Ogni richiesta deve essere correttamente compilata in base all'operazione richiesta; altrimenti non passerà la convalida primaria e non sarà accettata dal server per ulteriori elaborazioni.
Le richieste accettate dal server di trading vengono archiviate sotto forma di ordini che possono essere in sospeso o eseguiti istantaneamente dal prezzo di mercato. Gli ordini vengono archiviati sul server fino a quando non vengono evasi o annullati. Il risultato dell'esecuzione di un ordine è un deal.
Un del cambia la posizione di trading di un dato simbolo, può aprire, chiudere, aumentare, diminuire o invertire la posizione. Pertanto, una posizione aperta è sempre il risultato dell'esecuzione di uno o più deal. Informazioni più dettagliate sono fornite nell'articolo Ordini, Posizioni e Deal in MetaTrader 5.
Questo articolo descrive il concetto, i termini e i processi che fluiscono nel periodo dall'invio di una richiesta al suo spostamento nella cronologia di trading dopo che è stata elaborata.
Passaggio della Richiesta dal Client Terminal al Server di Trading.
Per eseguire un'operazione di trading, è necessario inviare un ordine al sistema di trading. Una richiesta viene sempre inviata al server di trading tramite l'invio di un ordine dal client terminal. La struttura di una richiesta deve essere compilata correttamente, indipendentemente da come fai trading, manualmente o utilizzando un programma MQL5.
Per eseguire manualmente un'operazione di trading, devi aprire la finestra di dialogo per compilare una richiesta di trading premendo il tasto F9. Quando si fa trading automaticamente tramite MQL5, le richieste vengono inviate utilizzando la funzione OrderSend(). Poiché molte richieste errate possono causare un sovraccarico indesiderato del server di trading, ogni richiesta deve essere verificata prima di essere inviata utilizzando la funzione OrderCheck(). Il risultato del controllo di una richiesta viene inserito in una variabile descritta dalla struttura MqlTradeCheckresult.
Una volta che una richiesta arriva al trade server, passa il controllo primario:
- se hai abbastanza risorse per eseguire l'operazione di trading.
- se il prezzo specificato è corretto: prezzi di apertura, Stop Loss, Take Profit, ecc.
- se il prezzo specificato è presente nel flusso del prezzo per l'esecuzione istantanea.
- se i livelli di Stop Loss e Take Profit sono assenti nella modalità Market Execution.
- se il volume è corretto: volume minimo e massimo, step, volume massimo della posizione (SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, SYMBOL_VOLUME_STEP e SYMBOL_VOLUME_LIMIT).
- stato del simbolo: quotazione o sessione trade, possibilità di trading dal simbolo, una specifica modalità di trading (es. solo chiusura di posizioni), ecc.
- stato dell’account di trading: limitazioni diverse per specifiche tipologie di account.
- altri controlli, a seconda dell'operazione di trading richiesta.
Una richiesta errata che non supera il controllo primario sul server viene rifiutata. Il client terminal viene sempre informato dell'esito del controllo di una richiesta inviando una risposta. La risposta del server di trading può essere presa da una variabile di tipo MqlTradeResult che viene passata come secondo parametro nella funzione OrderSend() quando si invia una richiesta.
Se una richiesta supera il controllo primario di correttezza, verrà inserita nella richiesta in attesa di essere elaborata. Come risultato dell'elaborazione di una richiesta, viene creato un ordine (comando per eseguire un'operazione di trading) nella base del server di trading. Tuttavia, esistono due tipi di richieste che non comportano la creazione di un ordine:
- una richiesta di modifica di una posizione (cambia il suo Stop Loss e/o Take Profit).
- una richiesta di modifica di un ordine in sospeso (i suoi livelli di prezzo e tempo di scadenza.
Il client terminal riceve un messaggio che la richiesta è stata accettata e inserita nel sottosistema di trading della piattaforma MetaTrader 5. Il server inserisce la richiesta accettata nella coda delle richieste per un'ulteriore elaborazione che può comportare:
- piazzamento di un ordine in sospeso.
- esecuzione di un ordine istantaneo dal prezzo di mercato.
- modifica di un ordine o di una posizione.
La durata di una richiesta nella coda del server ha un limite di tre minuti. Una volta superato il periodo, la richiesta viene rimossa dalla coda delle richieste.
Invio di Eventi di Trading dal Trading Server al Client Terminal
Il modello di evento e le funzioni di gestione degli eventi sono implementati nel linguaggio MQL5. Significa che in risposta a qualsiasi evento predefinito l'ambiente di esecuzione MQL5 chiama la funzione appropriata - il gestore degli eventi. Per l'elaborazione degli eventi di trading c'è la funzione predefinita OnTrade(); al suo interno deve essere inserito il codice per lavorare con ordini, posizioni e deal. Questa funzione è chiamata solo per gli Expert Advisor, non verrà utilizzata negli indicatori e negli script anche se si aggiunge lì una funzione con lo stesso nome e tipo.
Gli eventi di trading sono generati dal server in caso di:
- cambio di ordini attivi,
- cambio di posizione,
- cambio di deal,
- cambiamento della storia di trading.
Si noti che un'operazione può causare il verificarsi di diversi eventi. Ad esempio, l'attivazione di un ordine in sospeso porta al verificarsi di due eventi:
- la comparsa di un deal che è scritto nella storia di trading.
- lo spostamento dell'ordine in sospeso dalla lista di quelli attivi alla lista degli ordini storici (l'ordine viene spostato nello storico).
Un altro esempio di più eventi è l'esecuzione di più operazioni sulla base di un unico ordine, nel caso in cui il volume richiesto non possa essere ottenuto da un'unica offerta opposta. Il server di trading crea e invia i messaggi su ciascun evento al client terminal. Ecco perché la funzione OnTrade() può essere chiamata più volte per un evento apparentemente singolo. Questo è un semplice esempio della procedura di elaborazione dell'ordine nel sottosistema di trading della piattaforma MetaTrader 5.
Ecco un esempio: mentre un ordine in sospeso per l'acquisto di 10 lotti di EURUSD attende di essere eseguito, compaiono offerte opposte per la vendita di 1, 4 e 5 lotti. Queste tre richieste insieme danno il volume richiesto di 10 lotti, quindi vengono eseguite una per una, se la politica di riempimento consente di eseguire operazioni di trading in parti.
A seguito dell'esecuzione di 4 ordini, il server eseguirà 3 operazioni di 1, 4 e 5 lotti sulla base delle richieste opposte esistenti. Quanti eventi di trading verranno generati in questo caso? La prima richiesta contraria di vendita di un lotto comporterà l'esecuzione dell'operazione di 1 lotto. Questo è il primo evento di Trading (1 lotto deal). Ma cambia anche l'ordine in sospeso per l'acquisto di 10 lotti; ora, è l'ordine per l'acquisto di 9 lotti di EURUSD. La variazione di volume dell'ordine in sospeso è il secondo evento di Trading (modifica del volume di un ordine in sospeso).
Per la seconda operazione di 4 lotti verranno generati gli altri due eventi Trade, su ciascuno di essi verrà inviato un messaggio al client terminal che ha avviato l'ordine iniziale in sospeso per l'acquisto di 10 lotti di EURUSD.
L'ultima offerta di 5 lotti porterà al verificarsi di tre eventi trade:
- il deal di 5 lotti,
- il cambio di volume,
- lo spostamento dell'ordine nella storia di trading.
Come risultato dell'esecuzione dell'operazione, il client terminal riceve 7 eventi Trade uno dopo l'altro (si presume che la connessione tra il client terminal e il server di trading sia stabile e nessun messaggio venga perso). Questi messaggi devono essere elaborati in un Expert Advisor utilizzando la funzione OnTrade().
Elaborazione degli Ordini da parte del Server di Trading.
Tutti gli ordini che attendono la loro esecuzione verranno spostati nella cronologia alla fine: la condizione per la loro esecuzione sarà soddisfatta o verranno annullati. Esistono diverse varianti di annullamento dell'ordine:
- esecuzione di un del sulla base dell'ordine.
- rifiuto dell'ordine da parte di un dealer.
- annullamento dell'ordine su richiesta del trader (richiesta manuale o automatica da programma MQL5).
- scadenza dell'ordine, che è determinata dal trader al momento dell'invio della richiesta o dalle condizioni di trading del dato sistema di trading.
- mancanza di risorse sull’account di trading per l'esecuzione dell'operazione nel momento in cui vengono soddisfatte le condizioni della sua esecuzione.
- l'ordine viene annullato a causa della politica di riempimento (un ordine parzialmente evaso viene annullato).
Indipendentemente dal motivo per cui un ordine attivo viene spostato nella cronologia, il messaggio relativo alla modifica viene inviato al client terminal. I messaggi sull'evento trade non sono anche su tutti i client terminal, ma quelli associati al relativo account.
Ecco perché la documentazione della funzione OrderSend() dice:
Valore restituito
In caso di successo del controllo di base di una richiesta, la funzione OrderSend() restituisce true - questo non è un segno di corretta esecuzione di un'operazione di trading. Per una descrizione più dettagliata del risultato dell'esecuzione della funzione, analizzare i campi della struttura MqlTradeResult.
Aggiornamento del Trade e della Cronologia nel Client Terminal
I messaggi sugli eventi trade e sui cambiamenti nella cronologia dei trade arrivano attraverso canali separati. Quando si invia una richiesta di acquisto utilizzando la funzione OrderSend(), è possibile ottenere il ticket dell'ordine, che viene creato a seguito della corretta convalida della richiesta. Allo stesso tempo, l'ordine stesso potrebbe non essere visualizzato nel client terminal e un tentativo di selezionarlo utilizzando OrderSelect() potrebbe non riuscire.
Nella figura sopra, puoi vedere come il server di trading comunica il ticket dell'ordine al programma MQL5, ma il messaggio sull'evento di trading Trade (comparsa di un nuovo ordine) non è ancora arrivato. Non è arrivato nemmeno il messaggio relativo al cambio della lista degli ordini attivi.
Ci può essere una situazione, quando il messaggio Trade sulla comparsa di un nuovo ordine arriva al programma quando un deal sulla sua base è già stato eseguito; quindi, l'ordine è già assente nell'elenco degli ordini attivi, è nella cronologia. Questa è una situazione reale, poiché la velocità di elaborazione delle richieste è molto più elevata rispetto all'attuale velocità di consegna di un messaggio attraverso una rete.
Gestione di Eventi Trade in MQL5
Tutte le operazioni sul server di trading e l'invio di messaggi sugli eventi trade vengono eseguite in modo asimmetrico. C'è solo un metodo sicuro per scoprire cosa è stato modificato esattamente sull’account di trading. Questo metodo consiste nel memorizzare lo stato del trading e la cronologia e,quindi, nel confrontarlo con il nuovo stato.
L'algoritmo di tracciamento degli eventi trade negli Expert Advisor è il seguente:
- dichiarare i contatori dell'ordine, delle posizioni e del deal nello scopo complessivo.
- determinare la profondità della cronologia di trading che verrà richiesta alla cache del programma MQL5. Più cronologia carichiamo nella cache, più risorse del terminale e del computer vengono consumate.
- inizializzare i contatori di ordini, posizioni e deal nella funzione OnInit.
- determinare le funzioni del gestore in cui richiederà la cronologia di trading alla cache.
- Lì, dopo aver caricato la cronologia di trading, scopriremo anche cosa è successo all’account di trading confrontando lo stato memorizzato e quello corrente.
Questo è l'algoritmo più semplice, permette di scoprire se il numero di posizioni aperte (ordine, deal) è stato modificato e qual è la direzione del cambiamento. Se ci sono cambiamenti, possiamo ottenere ulteriori informazioni più dettagliate. Se il numero di ordini non viene modificato, ma vengono modificati gli ordini stessi, è necessario un approccio diverso; pertanto, questa variante non viene trattata in questo articolo.
Le modifiche del contatore possono essere verificate nelle funzioni OnTrade() e OnTick() di un Expert Advisor.
Scriviamo un esempio di programma passo dopo passo.
1. Il contatore di ordini, del e posizioni in ambito globale.
int orders; // number of active orders int positions; // number of open positions int deals; // number of deals in the trade history cache int history_orders; // number of orders in the trade history cache bool started=false; // flag of initialization of the counters
2. La profondità della cronologia di trading da caricare nella cache è impostata nella variabile di input days (carica la cronologia dei trade per il numero di giorni specificato in questa variabile).
input int days=7; // depth of the trade history in days //--- set the limit of the trade history on the global scope datetime start; // start date of the trade history in cache datetime end; // end date of the trade history in cache
3. Inizializzazione dei contatori e limiti della cronologia di trading. Porta l'inizializzazione dei contatori alla funzione InitCounters() per una migliore leggibilità del codice:
int OnInit() { //--- end=TimeCurrent(); start=end-days*PeriodSeconds(PERIOD_D1); PrintFormat("Limits of the trade history to be loaded: start - %s, end - %s", TimeToString(start),TimeToString(end)); InitCounters(); //--- return(0); }
La funzione InitCounters() prova a caricare la cronologia dei trade nella cache e, in caso di successo, inizializza tutti i contatori. Inoltre, se la cronologia viene caricata correttamente, il valore della variabile globale 'started' è impostato su 'true', il che indica che i contatori sono stati inizializzati con successo.
//+------------------------------------------------------------------+ //| initialization of the counters of positions, orders and deals | //+------------------------------------------------------------------+ void InitCounters() { ResetLastError(); //--- load history bool selected=HistorySelect(start,end); if(!selected) { PrintFormat("%s. Failed to load the history from %s to %s to the cache. Error code: %d", __FUNCTION__,TimeToString(start),TimeToString(end),GetLastError()); return; } //--- get current values orders=OrdersTotal(); positions=PositionsTotal(); deals=HistoryDealsTotal(); history_orders=HistoryOrdersTotal(); started=true; Print("The counters of orders, positions and deals are successfully initialized"); }
4. Il controllo delle modifiche allo stato dell’account di trading viene eseguito nei gestori OnTick() e OnTrade(). La variabile 'started' viene controllata per prima - se il suo valore è 'true' viene chiamata la funzione SimpleTradeProcessor(), altrimenti viene chiamata la funzione di inizializzazione dei contatori InitCounters().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(started) SimpleTradeProcessor(); else InitCounters(); } //+------------------------------------------------------------------+ //| called when the Trade event occurs | //+------------------------------------------------------------------+ void OnTrade() { if(started) SimpleTradeProcessor(); else InitCounters(); }
5. La funzione SimpleTradeProcessor() verifica se il numero di ordini, operazioni e posizioni è stato modificato. Dopo aver eseguito tutti i controlli, chiamiamo la funzione CheckStartDateInTradeHistory() che sposta il valore 'start' più vicino al momento corrente se necessario.
//+------------------------------------------------------------------+ //| simple example of processing changes in trade and history | //+------------------------------------------------------------------+ void SimpleTradeProcessor() { end=TimeCurrent(); ResetLastError(); //--- load history bool selected=HistorySelect(start,end); if(!selected) { PrintFormat("%s. Failed to load the history from %s to %s to the cache. Error code: %d", __FUNCTION__,TimeToString(start),TimeToString(end),GetLastError()); return; } //--- get current values int curr_orders=OrdersTotal(); int curr_positions=PositionsTotal(); int curr_deals=HistoryDealsTotal(); int curr_history_orders=HistoryOrdersTotal(); //--- check whether the number of active orders has been changed if(curr_orders!=orders) { //--- number of active orders is changed PrintFormat("Number of orders has been changed. Previous number is %d, current number is %d", orders,curr_orders); /* other actions connected with changes of orders */ //--- update value orders=curr_orders; } //--- change in the number of open positions if(curr_positions!=positions) { //--- number of open positions has been changed PrintFormat("Number of positions has been changed. Previous number is %d, current number is %d", positions,curr_positions); /* other actions connected with changes of positions */ //--- update value positions=curr_positions; } //--- change in the number of deals in the trade history cache if(curr_deals!=deals) { //--- number of deals in the trade history cache has been changed PrintFormat("Number of deals has been changed. Previous number is %d, current number is %d", deals,curr_deals); /* other actions connected with change of the number of deals */ //--- update value deals=curr_deals; } //--- change in the number of history orders in the trade history cache if(curr_history_orders!=history_orders) { //--- the number of history orders in the trade history cache has been changed PrintFormat("Number of orders in the history has been changed. Previous number is %d, current number is %d", history_orders,curr_history_orders); /* other actions connected with change of the number of order in the trade history cache */ //--- update value history_orders=curr_history_orders; } //--- check whether it is necessary to change the limits of trade history to be requested in cache CheckStartDateInTradeHistory(); }
La funzione CheckStartDateInTradeHistory() calcola la data di inizio della richiesta della cronologia per il momento corrente (curr_start) e la confronta con la variabile 'start'. Se la differenza tra loro è maggiore di 1 giorno, allora viene corretto 'start' e vengono aggiornati i contatori degli ordini e dei deal della cronologia.
//+------------------------------------------------------------------+ //| Changing start date for the request of trade history | //+------------------------------------------------------------------+ void CheckStartDateInTradeHistory() { //--- initial interval, as if we started working right now datetime curr_start=TimeCurrent()-days*PeriodSeconds(PERIOD_D1); //--- make sure that the start limit of the trade history period has not gone //--- more than 1 day over intended date if(curr_start-start>PeriodSeconds(PERIOD_D1)) { //--- we need to correct the date of start of history loaded in the cache start=curr_start; PrintFormat("New start limit of the trade history to be loaded: start => %s", TimeToString(start)); //--- now load the trade history for the corrected interval again HistorySelect(start,end); //--- correct the counters of deals and orders in the history for further comparison history_orders=HistoryOrdersTotal(); deals=HistoryDealsTotal(); } }
Il codice completo dell'Expert Advisor DemoTradeEventProcessing.mq5 è allegato all'articolo.
Conclusione
Tutte le operazioni nella piattaforma di trading online MetaTrader 5 vengono eseguite in modo asincrono e i messaggi su tutte le modifiche su un account di trading vengono inviati indipendentemente l'uno dall'altro. Pertanto, non ha senso cercare di tenere traccia di singoli eventi in base alla regola "Una richiesta - un evento trade". Se hai bisogno di determinare con precisione cosa viene cambiato esattamente quando arriva anche un Trade, allora dovresti analizzare tutte le tue operazioni, posizioni e ordini ad ogni chiamata del gestore OnTrade confrontando il loro stato attuale con quello precedente.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/232
- 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