English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
preview
Ordini, Posizioni e Deal in MetaTrader 5

Ordini, Posizioni e Deal in MetaTrader 5

MetaTrader 5Trading | 9 dicembre 2021, 14:03
943 0
MetaQuotes
MetaQuotes

Termini di trading

L'obiettivo finale di un trader è quello di ricavare profitti attraverso i mezzi di operazioni di trading sui mercati finanziari. Questo articolo descrive i termini e i processi della piattaforma di trading MetaTrader 5, la cui conoscenza è necessaria per una corretta comprensione del lavoro delle funzioni di trading del linguaggio MQL5.

  • Gli Ordini — sono le richieste di operazioni di trading, ricevute dal server di trading, formulate in conformità ai requisiti della piattaforma MetaTrader 5. Se la richiesta non è corretta, non apparirà sulla piattaforma di trading sotto forma di ordine. Gli ordini possono essere di esecuzione immediata, come comprare o vendere un certo volume, al prezzo di mercato corrente su uno strumento finanziario specificato. Un altro tipo di ordini - sono gli ordini in sospeso, che contengono un ordine per eseguire un'operazione di trading in presenza di determinate condizioni. Gli ordini in sospeso possono anche contenere una limitazione temporale delle loro azioni: la data di scadenza dell'ordine.

    Ordini e posizioni nel terminale MetaTrader 5

    Gli ordini effettuati (in sospeso), che sono in attesa delle condizioni della loro esecuzione o cancellazione, sono mostrati nel tab "Trade" nel terminale. Questi ordini possono essere modificati o annullati. L'inserimento, la cancellazione e la modifica degli ordini vengono eseguite utilizzando la funzione OrderSend()). Se l'ordine è stato annullato o ha raggiunto la scadenza, o se l'ordine è stato eseguito, viene spostato nella cronologia degli ordini. Gli ordini eseguiti e annullati sono mostrati nel tab "History" del client terminal. Gli ordini dalla cronologia non sono disponibili per la modifica.

  • Deal: sono il risultato dell'esecuzione di un ordine (un comando per eseguire l'operazione). Ogni deal si basa su un ordine particolare, ma un singolo ordine può generare una serie di deal. Ad esempio, un ordine di acquisto di 10 lotti può essere eseguito da più deal successivi con riempimento parziale. I deal sono sempre memorizzate nella cronologia di trading e non possono essere modificate. Nel terminale, i deal vengono visualizzate nel tab "Cronologia".

    Transazioni nel terminale MetaTrader 5

  • Le Posizioni sono i contratti, acquistati o venduti su uno strumento finanziario. Una posizione lunga (Long) si forma a seguito di acquisti in previsione di un aumento di prezzo, una posizione corta (Short) è il risultato della vendita del bene, in previsione di un futuro calo di prezzo. Per ogni account, per ogni strumento finanziario, può esistere una sola posizione. Per ogni simbolo, in un dato momento, può esserci una sola posizione aperta, lunga o corta.

    Ordini storici nel terminale MetaTrader 5

    Il volume della posizione può aumentare a seguito di una nuova operazione di trading nella stessa direzione. Ciò significa che il volume delle posizioni lunghe sarà aumentato dopo il nuovo acquisto (Buy deal) e sarà diminuito dopo la vendita (Sell deal). La posizione viene chiusa se il volume degli impegni diventa pari a zero a seguito dell'operazione di trading. Tale operazione è denominata chiusura della posizione.

Nota: Gli ordini e le posizioni attive sono sempre visualizzati nel tab "Trade" e le operazioni e gli ordini della cronologia vengono sempre riportati nel tab "History". L'ordine attivo del tab "Trade" non deve essere confuso con gli ordini storici del tab "History".


Come il terminale riceve e memorizza le informazioni di trading dal server

Il terminale memorizza lo storico del trading in una base speciale e riceve solo lo storico mancante dei deal e degli ordini completati sul conto di trading, ad ogni connessione al server di trading. Questo viene fatto per risparmiare sul traffico. Quando si chiude il client terminal MetaTrader 5 o si cambia l'account attivo corrente, l'intera cronologia viene registrata sul disco rigido e letta al momento del successivo avvio del terminale.

Tutti i database sono registrati sul disco in forma crittografata e la chiave di crittografia dipende dal computer su cui è installato il terminale. Ciò protegge l'utente del terminale dall'accesso non autorizzato ai suoi dati, in caso di copia.

Durante la connessione all’account, il terminale carica la base dell’account salvato, con lo storico dell’account e invia al server di trading una richiesta di sincronizzazione del proprio database storico con lo storico dell’account sul server di trading. Inoltre, dopo una connessione riuscita all’account, il server di trading invia al terminale un rapporto sugli eventi di trading in corso, relativi a questo account.

Evento di trading sono le seguenti modifiche nell’account:

  • operazioni di prelievo e saldo.
  • addebito di commissioni, permute e tasse.
  • inserimento, cancellazione e modifica degli ordini.
  • l'esecuzione di operazioni basate su ordini.
  • apertura e chiusura di posizioni.
  • cambiare il volume e la direzione delle posizioni.

In caso di cessazione della connessione con il server di trading, il terminale cerca periodicamente di riconnettersi. Dopo la riconnessione con il server, il terminale richiede tutte le modifiche recenti nella cronologia di trading per mantenere l'integrità dei dati nel proprio database della cronologia.

La cronologia di trading, visualizzata nel tab "History" del terminale, è presa dalla base della cronologia del terminale e le modifiche del periodo, visualizzate nella cronologia del terminale possono solo aumentare l'intervallo della cronologia, memorizzata in questo database. La diminuzione del periodo della cronologia visualizzata non comporta la rimozione fisica della cronologia dalla base del terminale.

Installazione dell'intervallo della cronologia di trading visualizzata

Ciò significa che l'installazione di un intervallo più breve della cronologia visualizzata non riduce la profondità della cronologia di trading memorizzata. Tuttavia, se specifichiamo un range più ampio, per la visualizzazione nel tab "History", allora tale azione potrebbe portare a una richiesta, da parte del server di trading, di una cronologia più profonda, se la propria base del terminale non ha ancora il dati richiesti per quel periodo.

Lo schema generale di interazione tra il terminale e il server di trading MetaTrader 5 viene mostrato nella Figura seguente:

Il client terminal invia una richiesta di sincronizzazione alla propria base storica di trading, durante l'avvio del terminale, durante la riconnessione con il server dopo un errore di connessione, durante il passaggio da un account all'altro e durante la richiesta diretta per la cronologia di trading mancante.

A sua volta, il server di trading in modo autonomo, senza alcuna richiesta da parte del terminale, invia al cliente messaggi sugli eventi di trading che si verificano sull’account: i cambiamenti dello stato degli ordini e delle posizioni, la conduzione delle operazioni basate sugli ordini, la addebito di commissioni, saldo e prelievo di denaro, e così via.


Accesso alla cronologia di trading dal programma MQL5

Il terminale può funzionare contemporaneamente con una serie di indicatori, script e EA e tutti questi programmi possono richiedere le informazioni di cui hanno bisogno sul trading: ordini, operazioni e posizioni. Il lavoro diretto del programma mql5 con il database del terminale è escluso, per considerazioni di stabilità, sicurezza e prestazioni complessive.

Ogni programma mql5 su richiesta riceve per il suo lavoro un "modello" dell'ambiente di trading nella sua cache. Una cache è un'area speciale di memoria per un rapido accesso ai dati. Ad esempio, prima di iniziare l'elaborazione dell'ordine, è necessario ottenere l'ordine necessario nella cache del programma mql5. Tutto il lavoro successivo, riferito all'ordine, sarà effettuato con la copia cache di quell'ordine.

Il lavoro con le posizioni, le operazioni e gli ordini della cronologia viene eseguito in modo simile. Lo schema generale per ottenere le informazioni di trading dal programma MQL5 è mostrato in figura:

Prima che i dati sulla cronologia di trading diventino disponibili per l'elaborazione del programma mql5, devono essere richiesti dal database del terminale. Dopo la richiesta, i dati ottenuti verranno inseriti nella propria cache del programma mql5.

Nota: i dati nella cache non vengono sincronizzati automaticamente con il database del terminale e, pertanto, devono essere costantemente aggiornati per mantenere uno stato appropriato dei dati nella cache.

Esiste la possibilità di conseguenze se la cache viene utilizzata in modo improprio.

  • se non è stato possibile ottenere i dati richiesti, la cache sarà vuota e non conterrà i dati necessari.
  • se i dati nella cache richiedono aggiornamenti, ma l'aggiornamento non è stato richiesto, lavorare con tali dati può portare a risultati imprevedibili. Ad esempio, i dati sulla posizione attuale non sono stati aggiornati e il programma non sa nulla della posizione aperta per il dato simbolo e della crescente perdita per esso.


La funzione per lavorare con la cache

La cronologia di trading può contenere migliaia di ordini eseguiti e operazioni che non sono necessari per il lavoro corrente del programma mql5. Pertanto, il lavoro con la cache è costruito sul principio delle richieste, la cache contiene sempre le informazioni che sono state caricate all'ultima connessione al database del terminale. Se hai bisogno di ottenere l'intero storico degli ordini e delle operazioni, devi richiederlo esplicitamente specificando l'intervallo desiderato.

Per ogni tipo di informazione, viene formata una cache indipendente. I dati sugli ordini sono archiviati nella cache dell'ordine, le informazioni sulle posizioni sono archiviate nella cache della posizione, i dati sulle operazioni e sugli ordini sono memorizzati nelle rispettive istanze della cronologia della cache.

Prima di richiedere le informazioni dalla cache, è necessario riempirle.

Nota: Qualsiasi richiesta di riempimento della cache la cancella in precedenza, indipendentemente dal risultato dell'esecuzione delle richieste.

Le funzioni di trading possono essere suddivise in due categorie: le funzioni per il riempimento della cache e le funzioni per la lettura delle informazioni dalla cache.


La funzione per riempire la cache

Per elaborare la cronologia di trading, deve prima essere ottenuta e posizionata nella cache appropriata. Le funzioni che formano una cache possono essere divise in due sottogruppi.

La funzione per riempire la cache di trading (ordini e posizioni attivi):

  • L’OrderSelect(ticket) - copia l'ordine attivo dal suo ticket (dalla base del terminale) nella cache dell'ordine corrente per l'ulteriore richiesta delle sue proprietà utilizzando le funzioni OrderGetDouble(), OrderGetInteger() e OrderGetString().
  • L’OrderGetTicket(index) - copia, dalla base del terminale dell'ordine attivo, dal suo l suo indice nella lista degli ordini della base del terminale degli ordini nella cache degli ordini correnti per ulteriore richiesta alle proprietà utilizzando OrderGetDouble(), OrderGetInteger() e le funzioni OrderGetString(). Il numero totale di ordini nella base del terminale può essere ottenuto utilizzando la funzione OrdersTotal().
  • Il PositionSelect(symbol) - copia la posizione aperta con il nome del simbolo (dalla base del terminale) nella cache per l'ulteriore richiesta delle sue proprietà utilizzando le funzioni PositionGetDouble(), PositionGetInteger() e PositionGetString().
  • Il PositionGetSymbol(index) - copia la posizione aperta tramite il suo indice nell'elenco delle posizioni (dalla base del terminale) della base del terminale nella cache per l'ulteriore richiesta delle sue proprietà utilizzando PositionGetDouble(), PositionGetInteger() e PositionGetString () funzioni. Il numero totale di posizioni nella base del terminale può essere ottenuto dalla funzione PositionsTotal().

La funzione di riempire la cache della cronologia:

  • L’HistoryOrderSelect(ticket) - copia l'ordine della cronologia dal suo ticket nella cache degli ordini della cronologia (dalla base del terminale) per le ulteriori chiamate alle sue proprietà da parte delle funzioni HistoryOrderGetDouble(), HistoryOrderGetInteger() e HistoryOrderGetString().
  • L’ HistoryDealSelect(ticket) - copia il deal dal suo ticket nella cache dei deal (dalla base del terminale) per le ulteriori chiamate alle sue proprietà dalle funzioni HistoryDealGetDouble(), HistoryDealGetInteger() e HistoryDealGetString().

Dobbiamo considerare separatamente le due funzioni, che influiscono sulla disponibilità, nella cache, della cronologia di trading in generale:

  • L’HistorySelect (start, end) - riempie la cache della cronologia con deal e ordini per l'intervallo specificato del server. Dai risultati dell'esecuzione di questa funzione, dipendono i valori che vengono restituiti da HistoryDealsTotal() e HistoryOrdersTotal().
  • L’HistorySelectByPosition (position_ID) - riempie la cache della cronologia con deal e ordini, con la posizione dell'identificatore specificata. Il risultato dell'esecuzione di questa funzione influisce anche su HistoryDealsTotal() e HistoryOrdersTotal().


OrderSelect e OrderGetTicket

Le funzioni generali OrderSelect(ticket) e OrderGetTicket() funzionano allo stesso modo: riempiono la cache degli ordini attivi con un unico ordine. L’OrderSelect(ticket) è inteso per il caso in cui un ordine del ticket è noto in anticipo. OrderGetTicket(), insieme a OrdersTotal() consente l'esame di tutti gli ordini disponibili nel terminale di base degli ordini.

Dopo una chiamata a una di queste funzioni, la cache degli ordini attivi contiene le informazioni di un solo ordine, se l'ordine è stato selezionato con successo. In caso contrario, non c'è nulla nella cache degli ordini attivi. Il risultato dell'esecuzione della funzione OrdersTotal() non cambia: restituisce sempre il numero effettivo di ordini attivi nella base del terminale, indipendentemente dal fatto che la cache sia piena.


PositionSelect e PositionGetSymbol

Proprio come per gli ordini, anche queste due funzioni lavorano allo stesso modo per le posizioni: riempiono la cache delle posizioni con una singola posizione. Il PositionGetSymbol(index) richiede il numero nell'elenco delle posizioni base, come parametro e il PositionSelect(symbol) riempie la cache in base al nome del simbolo, su cui viene aperta la posizione. Il nome del simbolo, a sua volta, può essere ottenuto dalla funzione PositionGetSymbol(index).

Dopo aver eseguito una di queste funzioni, la cache delle posizioni contiene dati solo su una posizione, se la funzione viene eseguita correttamente. Altrimenti, non c'è nulla nella cache delle posizioni. Il risultato dell'esecuzione della funzione PositionsTotal() non dipende dal fatto che la cache sia piena, - restituisce sempre il numero effettivo di posizioni aperte nel terminale di base per tutti i simboli.


HistoryOrderSelect

L'HistoryOrderSelect(ticket) sceglie nella cache l'ordine storico dalla base del terminale tramite il suo ticket. La funzione è destinata ad essere utilizzata quando si conosce in anticipo il ticket dell'ordine richiesto.

Se l'esecuzione ha esito positivo, la cache conterrà un singolo ordine e la funzione HistoryOrdersTotal() restituirà una singola unità. In caso contrario, la cache degli ordini storici sarà vuota e la funzione HistoryOrdersTotal() restituirà uno zero.


HistoryDealSelect

L’HistoryDealSelect(ticket seleziona il deal dal terminale di base in base al suo ticket. La funzione è pensata per essere utilizzata quando il ticket dell'operazione è noto in anticipo.

Se l'esecuzione ha esito positivo, la cache conterrà un singolo deal e la funzione HistoryDealsTotal() restituirà 1. Altrimenti, la cache dell'affare sarà vuota e la funzione HistoryDealsTotal() restituirà uno zero.


La funzione per ottenere informazioni dalla cache

Prima di richiedere informazioni sulle proprietà della posizione, deal o ordine, è necessario aggiornare la cache corrispondente del programma mql5. Ciò è dovuto al fatto che le informazioni richieste potrebbero essere già state aggiornate, e ciò significa che la copia, archiviata nella cache, è già obsoleta.

  • Ordini

    Per ottenere informazioni sugli ordini attivi è necessario prima copiarlo nella cache degli ordini attivi di una delle due funzioni: OrderGetTicket() o OrderSelect(). È per l'ordine, che è memorizzato nella cache, che verranno dati i valori delle proprietà, quando vengono chiamate le funzioni corrispondenti:

    1. OrderGetDouble(type_property)
    2. OrderGetInteger(type_property)
    3. OrderGetString(type_property)

Queste funzioni ottengono tutti i dati dalla cache, pertanto, per garantire l'ottenimento di dati precisi per l'ordine, si consiglia di chiamare la funzione che riempie la cache.

  • Posizioni

    Per ottenere le informazioni su una posizione, questa deve essere precedentemente selezionata e copiata nella cache, utilizzando una delle due funzioni: PositionGetSymbol o PositionSelect. È da questa cache che verranno emessi i valori delle proprietà di posizione, quando vengono chiamate le funzioni corrispondenti:

    1. PositionGetDouble(type_property)
    2. PositionGetInteger(type_property)
    3. PositionGetString(type_property)

Poiché queste funzioni ricevono tutti i loro dati dalla cache, quindi per garantire l'ottenimento di dati precisi per la posizione, si consiglia di chiamare la funzione che riempie la cache di posizioni.

  • Ordini storici

    Per ottenere informazioni su un ordine dallo storico, è necessario creare prima la cache degli ordini storici, utilizzando una delle tre funzioni: HistorySelect(start, end), HistorySelectByPosition() o HistoryOrderSelect(ticket). Se l'implementazione ha successo, la cache memorizzerà il numero di ordini, restituito dalla funzione HistoryOrdersTotal(). L'accesso alle proprietà di questi ordini viene effettuato da ciascun elemento del ticket, utilizzando l'apposita funzione:

    1. HistoryOrderGetDouble(ticket_order, type_property)
    2. HistoryOrderGetInteger(ticket_order, type_property)
    3. HistoryOrderGetString(ticket_order, type_property)

Il ticket dell'ordine storico può essere individuato utilizzando la funzione HistoryOrderGetTicket(index), tramite il suo indice nella cache degli ordini storici. Per avere una ricezione garantita di dati precisi sull'ordine, si consiglia di chiamare la funzione che riempie la cache degli ordini storici.

  • Deal

    Per ottenere informazioni su una specifica operazione nella cronologia, è necessario prima creare la cache dei deal, utilizzando una delle tre funzioni: HistorySelect (start, end), HistorySelectByPosition() o HistoryDealSelect (ticket). Se l'implementazione della funzione ha esito positivo, la cache memorizzerà il deal nell'importo restituito dalla funzione HistoryDealsTotal(). L'accesso alle proprietà di questi deal viene effettuato, in base al ticket, utilizzando le apposite funzioni:

    1. HistoryDealGetDouble(ticket_deals, type_property)
    2. HistoryDealGetInteger(ticket_deals, type_property)
    3. HistoryDealGetString(ticket_deals, type_property)

Il ticket delle trattative può essere ottenuto, tramite la funzione HistoryDealGetTicket(index), dal suo indice nella cache dei deal. Per avere una ricezione garantita di dati precisi sui deal, si consiglia di chiamare la funzione che riempie la cache delle offerte.


La funzione per ottenere il ticket dalla cronologia della cache

L'HistoryOrderGetTicket (index) restituisce il ticket dell'ordine storico, dal suo indice dalla cache degli ordini storici (non dalla base del terminale!). Il ticket ottenuto può essere utilizzato nella funzione HistoryOrderSelect (ticket), che svuota la cache e la riempie nuovamente con un solo ordine, in caso di successo. Ricordiamo che il valore, restituito da HistoryOrdersTotal(), dipende dal numero di ordini nella cache.

HistoryDealGetTicket(index) restituisce il ticket dal deal in base al suo indice dalla cachedei deal. Il ticket dell'operazione può essere utilizzato dalla funzione HistoryDealSelect(ticket), che svuota la cache e, in caso di successo, la riempie nuovamente con una sola operazione. Il valore, restituito dalla funzione HistoryDealsTotal(), dipende dal numero di deal nella cache.

Nota: Prima di chiamare le funzioni HistoryOrderGetTicket (index) e HistoryDealGetTicket (index), è necessario riempire la cache della cronologia con ordini e deal storici in un volume sufficiente. Per fare ciò, utilizzare una delle funzioni: HistorySelect (start, end), HistorySelectByPosition (position_ID), HistoryOrderSelect (ticket) e HistoryDealSelect (ticket).


Ottenere informazioni utilizzando ordini attivi

Il controllo degli ordini attualmente attivi è una procedura standard. Se è necessario ottenere informazioni su un ordine specifico, allora, conoscendo il suo ticket, questo può essere fatto utilizzando la funzione OrderSelect(ticket).

bool selected=OrderSelect(ticket);
if(selected)
  {
   double price_open=OrderGetDouble(ORDER_PRICE_OPEN);
   datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP);
   string symbol=OrderGetString(ORDER_SYMBOL);
   PrintFormat("Ордер #%d for %s was set at %s",ticket,symbol,TimeToString(time_setup));
  }
else
  {
   PrintFormat("Error selecting order with ticket %d. Error %d",ticket, GetLastError());
  }

Nell'esempio sopra, si presume che il ticket dell'ordine sia noto in anticipo, ad esempio si ottiene dalla variabile globale. In casi generali, però, l'informazione del ticket è assente e, quindi, bisogna ricorrere all'aiuto della funzione OrderGetTicket(index) che seleziona anche un ordine e lo inserisce nella cache, ma solo il numero dell'ordine nella lista degli ordini correnti deve essere specificato come parametro.

L'algoritmo generale per lavorare con gli ordini (analogo a offerte e posizioni) è il seguente:

  1. Ottieni il numero totale di ordini, utilizzando la funzione OrdersTotal().
  2. Organizza il ciclo attraverso una ricerca di tutti gli ordini, in base ai loro indici nell'elenco.
  3. Copia, uno per uno, ogni ordine nella cache, usando la funzione OrderGetTicket().
  4. Ottenere i dati dell'ordine corretti dalla cache, utilizzando le funzioni OrderGetDouble(), OrderGetInteger() e OrderGetString(). Se necessario, analizzare i dati ottenuti e intraprendere le azioni appropriate.

Ecco un breve esempio di tale algoritmo:

input long my_magic=555;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- obtain the total number of orders
   int orders=OrdersTotal();
//--- scan the list of orders
   for(int i=0;i<orders;i++)
     {
      ResetLastError();
      //--- copy into the cache, the order by its number in the list
      ulong ticket=OrderGetTicket(i);
      if(ticket!=0)// if the order was successfully copied into the cache, work with it
        {
         double price_open  =OrderGetDouble(ORDER_PRICE_OPEN);
         datetime time_setup=OrderGetInteger(ORDER_TIME_SETUP);
         string symbol      =OrderGetString(ORDER_SYMBOL);
         long magic_number  =OrderGetInteger(ORDER_MAGIC);
         if(magic_number==my_magic)
           {
            //  process the order with the specified ORDER_MAGIC
           }
         PrintFormat("Order #%d for %s was set out %s, ORDER_MAGIC=%d",ticket,symbol,TimeToString(time_setup),magic_number);
        }
      else         // call OrderGetTicket() was completed unsuccessfully
        {
         PrintFormat("Error when obtaining an order from the list to the cache. Error code: %d",GetLastError());
        }
     }
  }


Ottenere le informazioni sulle posizioni aperte

Il monitoraggio costante delle posizioni aperte non è solo una procedura standard, ma dovrebbe certamente essere implementato in ogni caso. Per ottenere informazioni su posizioni specifiche è sufficiente conoscere il nome dello strumento con cui è aperto. Per fare ciò, utilizzare la funzione PositionSelect(symbol). Per quei casi, in cui l'EA sta lavorando su un solo simbolo (sul simbolo del grafico, a cui è associato), il nome del simbolo può essere ottenuto da una funzione Symbol() o da una variabile predefinita _Symbol.

//--- we will look for the position by the symbol of the chart, on which the EA is working
   string symbol=Symbol();
//--- attempt to get the position
   bool selected=PositionSelect(symbol);
   if(selected) // if the position is selected
     {
      long pos_id            =PositionGetInteger(POSITION_IDENTIFIER);
      double price           =PositionGetDouble(POSITION_PRICE_OPEN);
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      long pos_magic         =PositionGetInteger(POSITION_MAGIC);
      string comment         =PositionGetString(POSITION_COMMENT);
      PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s",
                 pos_id, symbol, pos_magic, price,EnumToString(type), comment);
     }

   else        // if selecting the position was unsuccessful
     {
      PrintFormat("Unsuccessful selection of the position by the symbol %s. Error",symbol,GetLastError());
     }
  }

In un caso generale, le informazioni sul simbolo possono essere ottenute, utilizzando la funzione PositionGetSymbol (index), che seleziona una posizione e la inserisce nella cache. Come parametro, è necessario specificare l'indice di posizione nella lista delle posizioni aperte. Questo è meglio farlo attraverso una ricerca di tutte le posizioni nel ciclo.

L'algoritmo generale per lavorare con le posizioni:

  1. Ottieni il numero totale di posizioni, utilizzando la funzione PositionsTotal().
  2. Organizza il ciclo cercando tutte le posizioni in base ai loro indici nell'elenco.
  3. Copia, una per una, ogni posizione nella cache, usando la funzione PositionGetSymbol().
  4. Ottieni i dati della posizione richiesti dalla cache utilizzando le funzioni PositionGetDouble(), PositionGetInteger() e PositionGetString(). Se necessario, analizzare i dati ottenuti e intraprendere le azioni appropriate.

Un esempio di questo algoritmo:

#property script_show_inputs

input long my_magic=555;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- obtain the total number of positions
   int positions=PositionsTotal();
//--- scan the list of orders
   for(int i=0;i<positions;i++)
     {
      ResetLastError();
      //--- copy into the cache, the position by its number in the list
      string symbol=PositionGetSymbol(i); //  obtain the name of the symbol by which the position was opened
      if(symbol!="") // the position was copied into the cache, work with it
        {
         long pos_id            =PositionGetInteger(POSITION_IDENTIFIER);
         double price           =PositionGetDouble(POSITION_PRICE_OPEN);
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         long pos_magic         =PositionGetInteger(POSITION_MAGIC);
         string comment         =PositionGetString(POSITION_COMMENT);
         if(pos_magic==my_magic)
           {
           //  process the position with a specified POSITION_MAGIC
           }
         PrintFormat("Position #%d by %s: POSITION_MAGIC=%d, price=%G, type=%s, commentary=%s",
                     pos_id,symbol,pos_magic,price,EnumToString(type),comment);
        }
      else           // call to PositionGetSymbol() was unsuccessful
        {
         PrintFormat("Error when receiving into the cache the position with index %d."+
                     " Error code: %d", i, GetLastError());
        }
     }
  }


Regole per lavorare con la cache della cronologia

Spesso, il codice per lavorare con la cache della cronologia viene scritto dal programmatore in modo tale che funzioni senza problemi solo se la cronologia contiene 5-10 deal e ordini. Un tipico esempio di approccio sbagliato: caricare l'intera cronologia di trading nella cache ed elaborarla in un ciclo, cercando tra tutti gli ordini e le operazioni:

//---
   datetime start=0;           // initial time set to 1970 year
   datetime end=TimeCurrent();  // the ending time set to the current server time
//--- request into the cache of the program the entire trading history
   HistorySelect(start,end);
//--- obtain the number of all of the orders in the history
   int history_orders=HistoryOrdersTotal();
//--- now scan through all of the orders
   for(int i=0;i<history_orders;i++)
     {
     //  processing each order in the history
     }   

    ...
       
//--- obtain the number of all deals in the history
   int deals=HistoryDealsTotal();
//--- now scan through all of the deals
   for(int i=0;i<deals;i++)
     {
     //  process each deal in the history
     }

Il tentativo di gestire tutta la cronologia di trading, nella maggior parte dei casi, è sbagliato. Quando il numero di deal/ordini elaborati si aggira intorno alle migliaia e decine di migliaia, il lavoro del programma rallenta drasticamente.

Nota: fare sempre riferimento con cautela a tutti i casi di chiamata della funzione HistorySelect()! Il caricamento sconsiderato ed eccessivo di tutta la cronologia di trading disponibile nella cache del programma mql5 ne peggiora le prestazioni.

Questo è importante soprattutto per i test: l'utente scopre che il tester diventa improvvisamente accurato ed inizia a cercarne le ragioni nel client terminal. Pertanto, in primo luogo, pensa sempre all'ottimizzazione del codice del programma MQL5 (EA ed indicatori, che vengono chiamati dall'EA). Non fare affidamento sul fatto che il computer è fatto di ferro e ha molti kernel.

Per il corretto funzionamento dell'EA e dell'indicatore online, questo è altrettanto importante. Un codice non ottimale del programma può paralizzare il lavoro anche del computer più potente.

L'algoritmo corretto per lavorare con la cronologia di trading:

  1. Determinare la necessità di richiedere la cronologia di trading nella cache. Se ciò non è necessario, non eseguire le seguenti azioni.
  2. Determina la data finale della cronologia di trading (forse la cronologia fino a quel momento non è necessaria).
  3. Calcola la data iniziale della cronologia di trading, a partire dalla data di fine. Di solito, gli EA richiedono la cronologia di trading, non più profonda di un singolo giorno o di una settimana.
  4. Ottieni i ticket dei deal e degli ordini storici per l'ottenimento delle proprietà, dai ticket conosciuti:
    • HistoryOrderGetDouble()
    • HistoryOrderGetInteger()
    • HistoryOrderGetString()
    • HistoryDealGetDouble()
    • HistoryDealGetInteger()
    • HistoryDealGetString()
  5. Se i ticket non sono noti, e se è necessario, organizzare un ciclo di smistamento.
  6. Nel ciclo, ottieni il ticket per ogni operazione/ordine dalla cache della cronologia di trading, dall'indice (HistoryOrderGetTicket(Index) e HistoryDealGetTicket(Index)).
  7. Ottieni le proprietà necessarie di ordini e deal tramite il ticket noto (vedi punto 4).

Un esempio di codice per questo algoritmo:

//--- the variable, which is set in true only during the change in the trading history
   bool TradeHistoryChanged=false;
//--- here we check for the changes in the history and put out the TradeHistoryChanged=true if needed
//... the needed code

//--- check  if there are changes in the trading history or not
   if(!TradeHistoryChanged) return;

//--- if the history has changed, then it makes sense to load it into the cache 
//--- the ending time set for the current server time
   datetime end=TimeCurrent();
//--- the beginning time is set to 3 days ago
   datetime start=end-3*PeriodSeconds(PERIOD_D1);
//--- request in the cache of the program, the trading history for the last 3 days
   HistorySelect(start,end);
//--- obtain the number of orders in the cache of the history
   int history_orders=HistoryOrdersTotal();
//--- now scan through the orders
   for(int i=0;i<history_orders;i++)
     {
      //--- obtain the ticket of the historical order
      ulong ticket=HistoryOrderGetTicket(i);
      //--- work with this order - receive its problems
      long order_magic=HistoryOrderGetInteger(ticket,ORDER_MAGIC);
      // obtain the rest of the properties for the order by the ticket
      // ...
     }

L'idea di base presentata da questo esempio è che prima devi verificare il fatto dei cambiamenti che si verificano nella storia del trading. Una delle opzioni è quella di, all'interno della funzione OnTrade(), impostare per la variabile globale TradeHistoryChanged il valore true, poiché l'evento Trade ritorna sempre con qualsiasi tipo di evento di trading.

Se la cronologia del trading non è cambiata, non è necessario caricare nuovamente la cronologia del trading nella cache e sprecare risorse della CPU. Questo è logico e non richiede alcuna spiegazione. Se la cronologia di trading è cambiata, ne carichiamo solo la parte necessaria e esaminiamo ogni transazione/ordine solo una volta. Evitare cicli ripetuti non necessari.

Nota:ogni richiesta alla cache dell'intera cronologia di trading, eseguita dalla funzione HistorySelect() e ogni ciclo di elaborazione di transazioni e ordini dalla cronologia devono essere radicati. Altrimenti, le risorse del tuo computer verranno spese in modo inefficiente.

Esempi di lavoro corretto e non corretto con la cronologia di trading sono allegati a questo articolo, come file WrongWorkWithHistory.mq5 e RightWorkWithHistory.mq5.


Ottenere informazioni per ordini dalla cronologia

Lavorare con gli ordini storici non è così diverso da lavorare con gli ordini attivi, con una sola eccezione. Se il numero di ordini attivi nella cache del programma mql5 non può essere maggiore di uno, allora il risultato HistoryOrdersTotal() e il numero di ordini storici nella cache dipendono da quanta cronologia di trading è stata caricata da HistorySelect (start, end), HistorySelectByPosition() o HistoryOrderSelection().

Nota: Se la cronologia di trading non è stata caricata nella cache del programma mql5 da una delle funzioni HistorySelect(), HistorySelectByPosition() o HistoryOrderSelect(), non è possibile lavorare con ordini e transazioni storici. Assicurati di richiedere la cronologia richiesta di operazioni e ordini prima di ricevere i dati sulla cronologia di trading.

Ad esempio, forniamo uno script che cerca l'ultimo ordine dell'ultimo giorno e ne visualizza le informazioni.

// --- determining the time intervals of the required trading history
   datetime end=TimeCurrent();                // current server time
   datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago
//--- request in the cache of the program the trading history for a day
   HistorySelect(start,end);
//--- receive the number of orders in the history
   int history_orders=HistoryOrdersTotal();
//--- obtain the ticket of the order, which has the last index in the list, from the history
   ulong order_ticket=HistoryOrderGetTicket(history_orders-1);
   if(order_ticket>0) // obtain in the cache the historical order, work with it
     {
      //--- order status
      ENUM_ORDER_STATE state=(ENUM_ORDER_STATE)HistoryOrderGetInteger(order_ticket,ORDER_STATE);
      long order_magic      =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC);
      long pos_ID           =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID);
      PrintFormat("Order #%d: ORDER_MAGIC=#%d, ORDER_STATE=%d, ORDER_POSITION_ID=%d",
                  order_ticket,order_magic,EnumToString(state),pos_ID);
     }
   else              // unsuccessful attempt to obtain the order
     {
      PrintFormat("In total, in the history of %d orders, we couldn't select the order"+
                  " with the index %d. Error %d",history_orders,history_orders-1,GetLastError());
     }

In casi più generali, è necessario ordinare gli ordini nel ciclo dalla cache e analizzarli. L'algoritmo generale sarà il seguente:

  1. Determinare i range della cronologia sufficiente, se la cronologia viene caricata dalla funzione HistorySelect() - non è consigliabile caricare l'intera cronologia di trading nella cache.
  2. Carica nella cache del programma le funzioni HistorySelect(), HistorySelectByPosition() o HistoryOrderSelect (ticket) della cronologia di trading.
  3. Ottieni il numero totale di ordini nella cache, utilizzando HistoryOrdersTotal().
  4. Organizza il ciclo effettuando una ricerca in tutti gli ordini in base ai loro indici nell'elenco.
  5. Ottieni un ticket degli ordini nella cache, utilizzando la funzione HistoryOrderGetTicket() .
  6. Ottenere i dati dell'ordine dalla cache utilizzando le funzioni HistoryOrderGetDouble(), HistoryOrderGetInteger() e HistoryOrderGetString(). Se necessario, analizzare i dati ottenuti e intraprendere le azioni appropriate.

Un esempio di questo algoritmo:

#property script_show_inputs

input long my_magic=999;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
// --- setting the time intervals of the required trading history
   datetime end=TimeCurrent();                // the current server time
   datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago
//--- request into the cache of the program the needed interval of the trading history
   HistorySelect(start,end);
//--- obtain the number of orders in history
   int history_orders=HistoryOrdersTotal();
//--- now scroll through all of the orders
   for(int i=0;i<history_orders;i++)
     {
      //--- obtain the ticket of the order by its number in the list
      ulong order_ticket=HistoryOrderGetTicket(i);
      if(order_ticket>0) //  obtain in the cache, the historical order, and work with it
        {
         //--- time of execution
         datetime time_done=HistoryOrderGetInteger(order_ticket,ORDER_TIME_DONE);
         long order_magic  =HistoryOrderGetInteger(order_ticket,ORDER_MAGIC);
         long pos_ID       =HistoryOrderGetInteger(order_ticket,ORDER_POSITION_ID);
         if(order_magic==my_magic)
           {
           //  process the position with the set ORDER_MAGIC
           }
         PrintFormat("Order #%d: ORDER_MAGIC=#%d, time_done %s, ORDER_POSITION_ID=%d",
                     order_ticket,order_magic,TimeToString(time_done),pos_ID);
        }
      else               // unsuccessful attempt to obtain the order from the history
        {
         PrintFormat("we were not able to select the order with the index %d. Error %d",
                     i,GetLastError());
        }
     }
  }
Nota: fare sempre riferimento con cautela a tutti i casi di chiamata della funzione HistorySelect()! Il caricamento sconsiderato ed eccessivo di tutta la cronologia di trading disponibile nella cache del programma mql5 ne peggiora le prestazioni.


Ottenere informazioni sulle operazioni dalla cronologia

L'elaborazione delle operazioni ha le stesse caratteristiche dell'elaborazione degli ordini storici. Il numero di operazioni nella cronologia di trading e il risultato dell'esecuzione di HistoryDealsTotal(), dipende da quanta parte della cronologia di trading è stata caricata nella cache dalla funzione HistorySelect(start, end) o HistorySelectByPosition().

Per riempire la cache con una sola operazione in base al suo ticket, usa la funzione HistoryDealSelect(ticket).

// --- determining the time intervals of the required trading history
   datetime end=TimeCurrent();                // current sever time
   datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning for 24 hours ago
//--- request in the cache of the program the needed interval of the trading history
   HistorySelect(start,end);
//--- obtain the number of deals in history
   int deals=HistoryDealsTotal();
//--- obtain the ticket for the deal, which has the last index in the list
   ulong deal_ticket=HistoryDealGetTicket(deals-1);
   if(deal_ticket>0) // we obtained in the cache of the deal, and work with it
     {
      //--- the ticket order, based on which the deal was made
      ulong order     =HistoryDealGetInteger(deal_ticket,DEAL_ORDER);
      long order_magic=HistoryDealGetInteger(deal_ticket,DEAL_MAGIC);
      long pos_ID     =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID);
      PrintFormat("Deal #%d for the order #%d with the ORDER_MAGIC=%d  that participated in the position",
                  deals-1,order,order_magic,pos_ID);
     }
   else              // unsuccessful attempt of obtaining a deal
     {
      PrintFormat("In total, in the history %d of deals, we couldn't select a deal"+
                  " with the index %d. Error %d",deals,deals-1,GetLastError());
     }

In casi più generali, è necessario cercare nel ciclo dell’operazione dalla cache e farli analizzare. L'algoritmo generale sarà il seguente:

  1. Determina i limiti della cronologia sufficiente, se la cronologia viene caricata dalla funzione HistorySelect (start, end), non è consigliabile caricare l'intera cronologia di trading nella cache.
  2. Carica nella cache del programma la cronologia di trading delle funzioni HistorySelect() o HistorySelectByPosition().
  3. Ottieni il numero totale di operazioni nella cronologia, utilizzando la funzione HistoryDealsTotal().
  4. Organizza il ciclo cercando tra tutte le operazioni, in base ai loro numeri nell'elenco.
  5. Determina il ticket della prossima operazione nella cache, usando HistoryDealGetTicket().
  6. Ottieni le informazioni sull'operazione dalla cache, utilizzando le funzioni HistoryDealGetDouble(), HistoryDealGetInteger() e HistoryDealGetString(). Se necessario, analizzare i dati ottenuti e intraprendere le azioni appropriate.

Un esempio di questo algoritmo per il calcolo dei profitti e delle perdite:

input long my_magic=111;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
// --- determine the time intervals of the required trading history
   datetime end=TimeCurrent();                 // current server time
   datetime start=end-PeriodSeconds(PERIOD_D1);// set the beginning time to 24 hours ago

//--- request in the cache of the program the needed interval of the trading history
   HistorySelect(start,end);
//--- obtain the number of deals in the history
   int deals=HistoryDealsTotal();

   int returns=0;
   double profit=0;
   double loss=0;
//--- scan through all of the deals in the history
   for(int i=0;i<deals;i++)
     {
      //--- obtain the ticket of the deals by its index in the list
      ulong deal_ticket=HistoryDealGetTicket(i);
      if(deal_ticket>0) // obtain into the cache the deal, and work with it
        {
         string symbol             =HistoryDealGetString(deal_ticket,DEAL_SYMBOL);
         datetime time             =HistoryDealGetInteger(deal_ticket,DEAL_TIME);
         ulong order               =HistoryDealGetInteger(deal_ticket,DEAL_ORDER);
         long order_magic          =HistoryDealGetInteger(deal_ticket,DEAL_MAGIC);
         long pos_ID               =HistoryDealGetInteger(deal_ticket,DEAL_POSITION_ID);
         ENUM_DEAL_ENTRY entry_type=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);

         //--- process the deals with the indicated DEAL_MAGIC
         if(order_magic==my_magic)
           {
            //... necessary actions
           }

         //--- calculate the losses and profits with a fixed results
         if(entry_type==DEAL_ENTRY_OUT)
          {
            //--- increase the number of deals 
            returns++;
            //--- result of fixation
            double result=HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
            //--- input the positive results into the summarized profit
            if(result>0) profit+=result;
            //--- input the negative results into the summarized losses
            if(result<0) loss+=result;
           }
        }
      else // unsuccessful attempt to obtain a deal
        {
         PrintFormat("We couldn't select a deal, with the index %d. Error %d",
                     i,GetLastError());
        }
     }
   //--- output the results of the calculations
   PrintFormat("The total number of %d deals with a financial result. Profit=%.2f , Loss= %.2f",
               returns,profit,loss);
  }
Nota: fare sempre riferimento con cautela a tutti i casi di chiamata della funzione HistorySelect()! Il caricamento sconsiderato ed eccessivo di tutta la cronologia di trading disponibile nella cache del programma mql5 ne peggiora le prestazioni.


Ottenere nella cache della cronologia tramite l'identificatore della posizione (POSITION_IDENTIFIER)

La funzione HistorySelectByPosition (position_ID) proprio come la funzione HistorySelect (start, end) riempie la cache con deal e ordini dalla cronologia, ma solo a una condizione: devono avere l'identificatore specificato della posizione (POSITION_IDENTIFIER). L'identificatore della posizione - è un numero univoco, che viene assegnato automaticamente a ciascuna posizione riaperta e non cambia per tutta la sua vita. Nel frattempo va tenuto presente che il cambio della posizione (spostamento del tipo della posizione da POSITION_TYPE_BUY una POSITION_TYPE_SELL) non cambia l'identificatore della posizione.

Ogni posizione aperta è il risultato di una o più operazioni su quello strumento. Pertanto, per analizzare i cambiamenti di posizione, durante il suo ciclo di vita, a ciascuna operazione e ordine, in base alla quale è stata eseguita l'operazione, viene assegnato un identificatore alla posizione, a cui questa operazione ha partecipato. Quindi, conoscendo l'identificatore delle attuali posizioni aperte, possiamo ricostruire l'intera storia - trovare tutti gli ordini e le operazioni che l'hanno cambiata.

La funzione HistorySelectByPosition(position_ID) serve a evitare che il programmatore debba scrivere il proprio codice per scorrere l'intera cronologia di trading alla ricerca di tali informazioni. Un tipico algoritmo per lavorare con questa funzione:

  1. Ottieni l'identificatore di posizione corretto.
  2. Ottenere, tramite la funzione HistorySelectByPosition(), nella cache della cronologia di trading tutti gli ordini e le operazioni il cui identificatore è uguale all'identificativo della posizione corrente.
  3. Elabora la cronologia di trading secondo l'algoritmo.


Conclusione

L'intera piattaforma del sottosistema di trading MetaTrader 5 è ben congegnata e di facile utilizzo. Inoltre, l'abbondanza di funzioni di trading, ci consente di risolvere ogni problema specifico nel modo più efficiente.

Ma nonostante il fatto che le classi di trading specializzate dalla libreria standard ci permettano di non preoccuparci di troppe sfumature e di scrivere programmi ad alto livello, senza entrare nell'implementazione, la comprensione delle basi ci consentirà di creare più EA di trading affidabili ed efficienti.

Tutti gli esempi forniti possono essere trovati nei file allegati a questo articolo.

Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/211

Eventi di Trade in MetaTrader 5 Eventi di Trade in MetaTrader 5
Un monitoraggio dello stato corrente di un account di trading implica il controllo delle posizioni e degli ordini aperti. Prima che un segnale di trading diventi un deal, deve essere inviato dal client terminal come richiesta al server di trading, dove verrà inserito nella coda degli ordini in attesa di essere elaborato. Accettando una richiesta dal server di trading, cancellandola mentre scade o conducendo un deal sulla sua base - tutte queste azioni vengono seguite da eventi di trading, e il server di trading informa il terminale su di essi.
Guida al Test all'Ottimizzazione degli Expert Advisor in MQL5 Guida al Test all'Ottimizzazione degli Expert Advisor in MQL5
Questo articolo spiega il processo step by step per identificare e risolvere gli errori di codice, nonché i passaggi per testare e ottimizzare i parametri di input dell’Expert Advisor. Imparerai come utilizzare lo Strategy Tester del client terminal MetaTrader 5 per trovare il miglior simbolo e set di parametri di input per il tuo Expert Advisor.
I Fondamenti dei Testing in MetaTrader 5 I Fondamenti dei Testing in MetaTrader 5
Quali sono le differenze tra le tre modalità di testing in MetaTrader 5 e cosa dovremmo cercare in particolare? Come si svolge il testing di un EA, facendo trading simultaneamente su più strumenti? Quando e in che modo vengono calcolati i valori degli indicatori durante il testing e in che modo vengono gestiti gli eventi? Come sincronizzare le barre di diversi strumenti durante il testing in modalità "solo prezzi di apertura"? Questo articolo si propone di fornire risposte a queste e a molte altre domande.
Sistemi di Trading Adattivi e loro utilizzo nel Client MetaTrader 5 Sistemi di Trading Adattivi e loro utilizzo nel Client MetaTrader 5
Questo articolo suggerisce una variante di un sistema adattivo che consiste in molte strategie, ognuna delle quali esegue le proprie operazioni di trading "virtuali". Il trading reale viene eseguito in conformità con i segnali di una strategia più redditizia al momento. Grazie all'utilizzo dell'approccio orientato agli oggetti, le classi per lavorare con i dati e le classi di trading della libreria Standard, l'architettura del sistema è apparsa semplice e scalabile; ora puoi facilmente creare e analizzare i sistemi adattivi che includono centinaia di strategie di trading.