English Русский Deutsch 日本語 Türkçe
preview
MetaTrader 5 e il calendario economico di MQL5: Come Trasformare le Notizie in un Sistema di Trading Riproducibile

MetaTrader 5 e il calendario economico di MQL5: Come Trasformare le Notizie in un Sistema di Trading Riproducibile

MetaTrader 5Esempi |
20 8
MetaQuotes
MetaQuotes

Introduzione

I principali problemi del moderno trader di notizie sono la frammentazione degli strumenti a disposizione e la mancanza di un flusso di lavoro di trading algoritmico e sistematico. È difficile gestire contemporaneamente il browser con i siti di notizie e il terminale di trading mentre si aprono o si gestiscono posizioni.

Il flusso di lavoro di un trader di notizie si presenta così: Aprire rapidamente il calendario delle notizie nel proprio browser web e verificare eventuali modifiche agli eventi → Valutare rapidamente gli eventi imminenti e decidere su cosa e come operare → Spostarsi al terminale MetaTrader 5 - inserire ordini pendenti oppure rimanere al terminale e attendere la pubblicazione delle notizie per prendere una decisione. In questo scenario, il trader spesso perde il contesto, il che comporta ritardi nella reazione alle notizie e di conseguenza, perdite.

Desiderate che il trading di notizie funzioni come un problema di ingegneria - con regole chiare, risultati ripetibili e test automatizzati? Lo scopo di questo articolo è dimostrare l'architettura di funzionamento di un modulo dedicato alle notizie per MetaTrader 5: un'unica fonte di dati, l'uso corretto dell'API del calendario, un meccanismo di filtraggio e caching, l'esportazione degli eventi storici in una risorsa per il tester e il passaggio automatico tra Live e Tester - in modo che lo stesso codice produca risultati deterministici sia con dati in tempo reale che con dati storici.

Problemi Principali del Trader

Fig.1. Il problema principale di un trader manuale è la frammentazione degli strumenti di lavoro


Il trading manuale basato sulle notizie è obsoleto

Innanzitutto, una strategia sulle notizie che dipende da fattori esterni non può essere testata. Metà del successo nel trading è legato alla verifica delle prestazioni della strategia sui dati storici. L'impossibilità di testare una strategia porta alla soggettività nelle decisioni prese. La strategia rimarrà un'ipotesi e impiegherete molto tempo – mesi e persino anni – per testarla.

In secondo luogo, il trading manuale è molto difficile da scalare. Provate a far crescere un'attività instabile che genera profitti irregolari. Espanderla non farebbe altro che peggiorare i problemi. In assenza di una struttura chiara, di sistematizzazione e di ottimizzazione, pensare alla scalabilità è inutile.

In terzo luogo, i ritardi nella reazione alle notizie rappresentano uno dei principali punti critici del trading manuale. Immagina di essere un trader FOREX e di operare sui Non Farm Payrolls (NFP). I dati NFP vengono generalmente pubblicati una volta al mese. Vi siete distratti e avete perso l'uscita dei NFP, perdendo così l’opportunità di guadagnare. Si tratta di una situazione comune a molti trader.

Conclusione: l'automazione è l'unica strada per un trading sulle notizie riproducibile.

Confronto delle Reazioni

Fig.2. Un robot è sempre più veloce


Calendario economico integrato in MetaTrader 5: Un'unica fonte di informazione

Per trasformare il trading sulle notizie in un processo algoritmico e di conseguenza, rendere possibili i test su dati storici, utilizzate il prodotto esclusivo della nostra azienda - un calendario economico integrato in MetaTrader 5 con accesso alle notizie tramite l'API MQL5. È questo che trasformerà il vostro trading sulle notizie da un'improvvisazione in un processo algoritmico verificabile. Sia gli eventi attuali in tempo reale che gli eventi storici sono disponibili per i test offline.

Tabella 1:

Cosa rende unico il calendario integrato in MetaTrader 5?

Parametro
Velocità di accesso
<100 ms — dopo il caricamento delle notizie nel terminale
Integrazione Nativa — a livello del core del terminale + API MQL
Test Pienamente supportato - dopo aver scaricato le notizie sul terminale (accesso nel tester tramite file, risorse o SQLite)
Affidabilità Alta

MetaTrader 5 dispone di un eccellente strumento di test delle strategie - veloce, multi-asset e in grado di utilizzare computer su reti locali e globali per test e ottimizzazioni. Provate a far funzionare il vostro sistema di trading basato sulle notizie utilizzando dati storici. Questo potrebbe migliorare il vostro approccio al trading.


Funzioni del calendario economico di MetaTrader 5: Panoramica dell'API MQL5

La transizione dall'analisi manuale a quella algoritmica, inizia con la comprensione dell'architettura dei dati. In MQL5, il calendario economico non è solo una tabella, ma un database strutturato accessibile tramite un'API nativa. Esploreremo come interrogare correttamente gli eventi, la differenza tra Evento e Valore e perché la sincronizzazione temporale è essenziale per una strategia di successo.

Il cuore del calendario MQL5 è costituito da diverse funzioni chiave, ognuna delle quali svolge un compito specifico. È importante comprendere che non esiste una funzione universale in grado di fornire tutti i dati del calendario economico contemporaneamente. È necessario un approccio combinato.

  • CalendarValueHistory - strumento principale per il caricamento iniziale. Consente di ottenere un array dei valori degli eventi per un intervallo di tempo specificato. Si tratta dell'"artiglieria pesante" utilizzata durante l'inizializzazione dell'EA per riempire la cache con dati storici o con dati per la settimana successiva.
  • CalendarValueLast - funzione principale per gli Expert Advisor (EA) che operano in tempo reale. Restituisce solo i valori modificati o nuovi dall'ultima richiesta (tramite il meccanismo change_id ). Ciò consente di risparmiare traffico e risorse del server, evitando di richiedere l'intero array di dati a ogni tick.
  • CalendarEventByCountry — per ottenere le descrizioni di tutti gli eventi nel paese. Restituisce un elenco di descrizioni di eventi per un paese specifico, identificato da un codice conforme alla norma ISO 3166-1 alpha-2. Necessario per la creazione di filtri (ad esempio, per mostrare solo gli eventi del paese/codice "US" (USA), "RU" (Russia), "CA" (Canada), ecc.).
  • CalendarEventByCurrency — per ottenere la descrizione di tutti gli eventi in base alla valuta. Restituisce un elenco di descrizioni di eventi per una valuta specifica, indicata dal codice ("USD", "EUR", ecc.).
  • CalendarCountryById — per ottenere le proprietà del paese tramite 'id'.
  • CalendarEventById — recupera le proprietà dell'evento tramite 'id'.
  • CalendarValueById — per ottenere un valore specifico tramite 'id'.

Strutture dati: Quali informazioni restituisce l'API MQL5 del calendario?

Tutte le funzioni API del calendario economico restituiscono un array di strutture oppure una variabile con una singola struttura. Elenchiamo ora in dettaglio le strutture e i relativi campi.

Descrizioni degli eventi - utilizzate nelle funzioni CalendarEventById, CalendarEventByCountry e CalendarEventByCurrency:

struct MqlCalendarEvent
  {
   ulong                               id;                    // event ID
   ENUM_CALENDAR_EVENT_TYPE            type;                  // event type from the ENUM_CALENDAR_EVENT_TYPE enumeration
   ENUM_CALENDAR_EVENT_SECTOR          sector;                // sector an event is related to
   ENUM_CALENDAR_EVENT_FREQUENCY       frequency;             // event frequency (periodicity)
   ENUM_CALENDAR_EVENT_TIMEMODE        time_mode;             // event time mode
   ulong                               country_id;            // country ID
   ENUM_CALENDAR_EVENT_UNIT            unit;                  // economic indicator value's unit of measure
   ENUM_CALENDAR_EVENT_IMPORTANCE      importance;            // event importance
   ENUM_CALENDAR_EVENT_MULTIPLIER      multiplier;            // economic indicator value multiplier
   uint                                digits;                // number of decimal places
   string                              source_url;            // URL of a source where an event is published
   string                              event_code;            // event code
   string                              name;                  // event text name in the terminal language (in the current terminal encoding)
  };


Descrizioni dei paesi — utilizzate nelle funzioni CalendarCountryById e CalendarCountries:

struct MqlCalendarCountry
  {
   ulong                               id;                    // country ID (ISO 3166-1)
   string                              name;                  // country text name (in the current terminal encoding)
   string                              code;                  // country code name (ISO 3166-1 alpha-2)
   string                              currency;              // country currency code
   string                              currency_symbol;       // country currency symbol
   string                              url_name;              // country name used in the mql5.com website URL
  };


Valori degli eventi - utilizzati nelle funzioni CalendarValueById, CalendarValueHistoryByEvent, CalendarValueHistory, CalendarValueLastByEvent e CalendarValueLast.

struct MqlCalendarValue
  {
   ulong                               id;                    // value ID
   ulong                               event_id;              // event ID
   datetime                            time;                  // event date and time
   datetime                            period;                // event reporting period
   int                                 revision;              // revision of the published indicator relative to the reporting period
   long                                actual_value;          // actual value in ppm or LONG_MIN if the value is not set
   long                                prev_value;            // previous value in ppm or LONG_MIN if the value is not set
   long                                revised_prev_value;    // revised previous value in ppm or LONG_MIN if the value is not set
   long                                forecast_value;        // forecast value in ppm or LONG_MIN if the value is not set
   ENUM_CALENDAR_EVENT_IMPACT          impact_type;           // potential impact on the currency rate
   //--- functions for checking the values
   bool                         HasActualValue(void) const;   // returns 'true' if actual_value is set
   bool                         HasPreviousValue(void) const; // returns 'true' if prev_value is set
   bool                         HasRevisedValue(void) const;  // returns 'true' if revised_prev_value is set
   bool                         HasForecastValue(void) const; // returns 'true' if forecast_value is set
   //--- functions for getting values
   double                       GetActualValue(void) const;   // return actual_value or nan if the value is not set
   double                       GetPreviousValue(void) const; // return prev_value or nan if the value is not set
   double                       GetRevisedValue(void) const;  // returns revised_prev_value or nan if the value is not set
   double                       GetForecastValue(void) const; // returns forecast_value or nan if the value is not set
  };

Nota:

Da notare che la struttura MqlCalendarValue fornisce metodi per verificare e ottenere i valori dai campi actual_value, forecast_value, prev_value e revised_prev_value. I campi elencati potrebbero non avere valori - ad esempio, il campo actual_value potrebbe essere vuoto perché la notizia non è ancora stata rilasciata. Il modo migliore per ottenere i valori è eseguire il controllo e recuperare i valori utilizzando i metodi della struttura stessa.

Le strutture sono correlate tra loro dalle seguenti relazioni:

Relazioni del Calendario

Fig.3. Relazioni tra le strutture del calendario


La struttura MqlCalendarCountry è collegata a MqlCalendarEvent tramite un ID paese. La forma della relazione è "uno a molti" (1..*).

La struttura MqlCalendarEvent è collegata a MqlCalendarValue tramite un ID evento. La forma della relazione è "uno a molti" (1..*).


Ora di pubblicazione della notizia e ora del server

Tutte le funzioni per lavorare con il calendario economico utilizzano l'ora del server di trade TimeTradeServer(). Ciò significa che il timestamp nella struttura MqlCalendarValue e il timestamp di input nelle funzioni CalendarValueHistoryByEvent() e CalendarValueHistory() sono impostati nel fuso orario del server di trading, anziché nell'ora locale dell'utente.

Non è necessaria alcuna conversione: Il valore temporale di MqlCalendarValue::period può essere confrontato direttamente con il timestamp ottenuto quando si chiamano le funzioni TimeCurrent() o TimeTradeServer(). Nel tester, la funzione TimeTradeServer() restituisce un timestamp del modello identico all'orario presente nei dati storici. La logica alla base del lavoro con finestre temporali ("30 minuti prima delle notizie") funziona allo stesso modo sia in tempo reale che nei dati storici. Se il broker gestisce il passaggio tra ora legale e ora solare, il calendario si adegua automaticamente a tale transizione.


Esempio pratico - ottenere un elenco degli eventi di oggi (il giorno corrente):

//+------------------------------------------------------------------+
//| Get calendar values for the current day                          |
//+------------------------------------------------------------------+
void GetTodayUSD_Events()
 {
//--- define the period boundaries in server time
  datetime server_now = TimeTradeServer();
  datetime day_start  = server_now - (server_now % 86400);
  datetime day_end    = day_start + 86400;

  MqlCalendarValue    values[];
  MqlCalendarEvent    event;
  MqlCalendarCountry  country;

//--- request values only for USD
  if(CalendarValueHistory(values, day_start, day_end, NULL, "USD"))
   {
    Print("  Events received for USD: ", ArraySize(values));

    //--- iterate over the array of values
    for(int i = 0; i < ArraySize(values); i++)
     {
      //--- get event description
      if(CalendarEventById(values[i].event_id, event))
      {
        //--- get country description
        if(CalendarCountryById(event.country_id, country))
        {
          Print("✅ Event #", i);
          Print("Event ID:       ", values[i].event_id);

          Print("Event name: ", event.name);
          Print("Sector:           ", event.sector);
          Print("Source:         ", event.source_url);

          Print("Country name:  ", country.name);
          Print("Country URL:       ", country.url_name);

          Print("Time:            ", TimeToString(values[i].time, TIME_DATE | TIME_SECONDS));
          Print("Impact:          ", values[i].impact_type);

          // CHECK AND OUTPUT VALUES
          if(values[i].HasActualValue())
            Print("Actual:             ", values[i].GetActualValue());

          if(values[i].HasRevisedValue())
            Print("Revised:     ", values[i].GetRevisedValue());

          if(values[i].HasForecastValue())
            Print("Forecast:          ", values[i].GetForecastValue());

          if(values[i].HasPreviousValue())
            Print("Previous:       ", values[i].GetPreviousValue());
        }
      }
     }
   }
  else
   {
    int error = GetLastError();
    if(error == 0)
     {
      Print("❌ CalendarValueHistory: No Events");
     }
    else
     {
      Print("❌ Error CalendarValueHistory: ", error);
     }
   }
 }
//+------------------------------------------------------------------+

La funzione visualizza un elenco di eventi relativi alla valuta USD per il giorno corrente e il contenuto dei campi principali delle strutture recuperate tramite l'API MQL del calendario. Il codice sorgente completo dello script è contenuto nel file GetTodayEvents-S.mq5 allegato all'articolo.

I risultati delle operazioni della funzione sono visibili nella scheda Boxattrezzi\Expert del terminale MetaTrader 5. Notiamo che sono stati ricevuti due eventi per USD. Al momento della richiesta, questi eventi non si erano ancora verificati (la notizia non era stata ancora rilasciata). Pertanto, il campo MqlCalendarValue::actual_value non contiene alcun valore - la funzione HasActualValue() restituisce 'false'.

Per questi tipi di evento, il campo MqlCalendarValue::forecast_value controllato da HasForecastValue() è assente (non contiene alcun valore). Per gli altri eventi, tutti e quattro i campi (prev_value, actual_value, forecast_value e revised_prev_value) potrebbero mancare.

  Eventi ricevuti in USD: 2
✅ Event #0
Event ID:            840220005
Event name:      3-month treasury bills auction
Sector:              1
Source:              https://home.treasury.gov/
Country name:   USA
Country URL:     united-states
Time:                2026.04.20 18:30:00
Impact:             0
Previous:           3.62
✅ Event #1
Event ID:           840220006
Event name:      6-month treasury bills auction
Sector:              1
Source:              https://home.treasury.gov/
Country name:   USA
Country URL:     united-states
Time:                2026.04.20 18:30:00
Impact:             0
Previous:           3.61

Spiegazioni relative al codice fornito:

Innanzitutto, otteniamo un array di valori per tutti gli eventi in un dato intervallo di tempo con il filtro valuta "USD". In un ciclo, scorriamo l'array di valori e richiediamo la descrizione dell'evento tramite l'ID dell'evento MqlCalendarValue::event_id utilizzando la funzione CalendarEventById(). Quindi richiediamo una descrizione del paese tramite ID MqlCalendarEvent::country_id utilizzando la funzione CalendarCountryById().

Se la funzione CalendarValueHistory() restituisce 'false', ma GetLastError() restituisce zero (nessun errore), ciò indica che non ci sono eventi con le impostazioni richieste.


Gestione degli errori e limiti durante l'utilizzo del calendario

Lavorare con dati remoti comporta sempre il rischio di interruzioni di connessione o restrizioni di accesso. Le funzioni del calendario restituiscono false o 0 in caso di errore. Per comprenderne il motivo, è necessario utilizzare GetLastError(). La documentazione evidenzia un gruppo separato di errori per il modulo del calendario.

Codici di errore:

  • ERR_CALENDAR_TIMEOUT (codice 5200) — il tempo di attesa per la risposta del server è scaduto. Guasto di rete o sovraccarico del server. Soluzione: Ripeti la richiesta dopo una pausa di 5-10 secondi.
  • ERR_CALENDAR_NO_DATA (codice 5201) — i dati del calendario non sono ancora stati caricati. Il calendario viene inizializzato in modo asincrono. Soluzione: Attendi 1...2 secondi e ripeti.
  • ERR_CALENDAR_INVALID_DATE (codice 5202) — intervallo di date non valido. Errore di codice (ad esempio, la data di inizio è successiva alla data di fine). Soluzione: Correggi la logica, ripetere la richiesta è inutile.
  • ERR_CALENDAR_INVALID_COUNTRY (codice 5203) — codice paese/valuta sconosciuto. Errore nei parametri della richiesta. Soluzione: Verifica il codice (ad esempio, "US" invece di "USA").
  • ERR_CALENDAR_TOO_MANY_REQUESTS (codice 5204) — limite di richieste superato. Errore critico. Soluzione: Aumenta l'intervallo tra le richieste.

Limitazione della frequenza delle richieste:

I server a cui si connette il terminale MetaTrader 5 proteggono l'infrastruttura dal sovraccarico. Se l'EA chiama CalendarValueHistory() ad ogni tick o in un ciclo senza ritardi, il server restituisce l'errore 5204 e blocca temporaneamente l'accesso al calendario per il vostro terminale. Buona prassi: caricare i dati una sola volta all'avvio in OnInit() per il periodo richiesto.

Per gli aggiornamenti in tempo reale, utilizzare CalendarValueLast() memorizzando la variabile change_id restituita - ciò consente di ricevere solo le modifiche, anziché l'intero array di dati. Aggiorna i dati su un timer in OnTimer() a intervalli non superiori a 5–10 minuti.

Vediamo alcuni esempi di soluzioni ai problemi che possono sorgere durante il caricamento di un calendario:

Quando si avvia il terminale (avvio a freddo) e l'EA, il calendario non è immediatamente pronto. I dati vengono caricati dal server in background. Se chiamiamo la funzione CalendarValueHistory() nella primissima riga di OnInit(), molto probabilmente otterremo l'errore 5201 - nessun dato. È necessario implementare un meccanismo di polling di disponibilità con un timeout esponenziale o fisso.

Esempio pratico - funzione di caricamento dei dati del calendario con gestione degli errori:

//+------------------------------------------------------------------+
//| Calendar loading function                                        |
//+------------------------------------------------------------------+
bool LoadCalendar(MqlCalendarValue& values[], const datetime from, const datetime to, const string country_code = NULL, const string currency = NULL, const int max_retries = 5)
 {
  int retry_count = 0;

  while(retry_count < max_retries)
   {
    ResetLastError();
    //--- download attempt
    if(CalendarValueHistory(values, from, to, country_code, currency))
      return true; // Success

    int error = GetLastError();

    //--- in case of "No data" (5201) or "Timeout" (5200) error — wait and repeat
    if(error == 5201 || error == 5200)
     {
      retry_count++;
      Sleep(1000); // 1 second pause before repeating
      continue;
     }

    //--- if the error is critical (for example, an invalid date), interrupt the download immediately
    Print("❌ Critical Calendar Error: ", error);
    return false;
   }

  Print("❌ Failed to load calendar after ", max_retries, " attempts.");
  return false;
 }
//+------------------------------------------------------------------+

Spiegazioni relative al codice fornito:

Tenere in considerazione la possibilità di errori "Nessun dato" (5201) e "Timeout" (5200). Si tratta di errori correggibili. Gestirli facendo una pausa di 1-5 secondi e richiedendo nuovamente i dati. Qualora si verifichino errori irreversibili, interrompere immediatamente il download. Gli errori irreversibili includono date non valide, valuta o codici paese errati, ecc. Il codice sorgente completo dello script è disponibile nel file GetTodayEvents-S.mq5 allegato a questo articolo.


Per evitare limiti e garantire la massima velocità di reazione, in OnTimer() dovremmo utilizzare il meccanismo change_id. All'avvio, carica la cronologia completa degli eventi e memorizza l'ultimo change_id. Nel timer, richiedi solo i nuovi dati utilizzando la funzione CalendarValueLast(). Il server restituirà solo i dati modificati (o "false" se non ci sono modifiche), senza sprecare risorse trasmettendo i vecchi dati.

Esempio pratico - funzione di aggiornamento dei dati del calendario con gestione degli errori:

//+------------------------------------------------------------------+
//| Timer: incremental update                                        |
//+------------------------------------------------------------------+
void OnTimer()
 {
  if(!is_initialized)
    return;

  MqlCalendarValue updates[];
  ResetLastError();

//--- API automatically updates last_change_id by reference
  if(!CalendarValueLast(last_change_id, updates,
                        (InpCountryCode == "") ? NULL : InpCountryCode,
                        (InpCurrency    == "") ? NULL : InpCurrency))
   {
    int err = GetLastError();
    // 0 = SUCCESS/NO_NEW_DATA, 5402 = ERR_CALENDAR_NO_CHANGES
    if(err != 0 && err != 5402)
      Print("🔴️ CalendarValueLast error: ", err);
    return;
   }

  int cnt = ArraySize(updates);
  if(cnt == 0)
    return;

  Print("🟢 Received ", cnt, " updates. New change_id: ", last_change_id);
  if(InpPrintChanges)
    ArrayPrint(updates);
  SyncCache(updates);
 }
//+------------------------------------------------------------------+
//| Cache synchronization                                            |
//+------------------------------------------------------------------+
void SyncCache(const MqlCalendarValue &updates[])
 {
  int upd_cnt  = ArraySize(updates);
  int cache_sz = ArraySize(calendar_cache);

  for(int u = 0; u < upd_cnt; u++)
   {
    bool found = false;
    for(int c = 0; c < cache_sz; c++)
     {
      if(calendar_cache[c].id == updates[u].id)
       {
        calendar_cache[c] = updates[u];
        found = true;
        break;
       }
     }
    if(!found)
     {
      ArrayResize(calendar_cache, cache_sz + 1);
      calendar_cache[cache_sz] = updates[u];
      cache_sz++;
      total_events++;
     }
   }
 }
//+------------------------------------------------------------------+

Spiegazioni relative al codice fornito:

L'aggiornamento incrementale degli eventi avviene tramite il gestore eventi del timer OnTimer(). Viene chiamata la funzione CalendarValueLast() dell'API del calendario - se compaiono nuovi eventi, questi aggiornano gli elementi corrispondenti dell’array della struttura MqlCalendarValue e invia i dati al registro del terminale. Se tale evento non viene trovato nell'array caricato, viene aggiunto all'array.

Il codice sorgente completo dello script è contenuto nel file CalendarEventMonitor-EA.mq5, allegato all'articolo.


Filtraggio degli eventi: Dal generale allo specifico

Perché filtrare:

Il calendario economico pubblica dai 60 ai 90 eventi al giorno. È come trovarsi davanti ad un flusso costante di centinaia di indicatori minori, festività e discorsi ufficiali che non hanno alcun impatto immediato sul mercato. Investire su ognuno di loro è un modo sicuro per incorrere in overtrading e perdere il proprio deposito. Il compito di un trader algoritmico che opera sulle notizie è quello di individuare 3-5 eventi che influenzino realmente il mercato.

Il filtraggio nel trading algoritmico di notizie equivale ad aumentare il rapporto segnale-rumore fino a un livello adatto al processo decisionale automatizzato. Nell'API del calendario MQL5, questo processo è implementato come un sistema di filtraggio multilivello attraverso il quale passano gli array di strutture MqlCalendarEvent e MqlCalendarValue.

Criteri di filtraggio:

Il mercato non reagisce alle notizie rilasciate in sé, bensì alla discrepanza tra i dati effettivi e le previsioni, nonché al livello di influenza macroeconomica. Gli eventi a basso impatto (MqlCalendarValue::impact_type < 3) vengono spesso ignorati dagli algoritmi di trading e dai market maker.

Senza filtraggio si ottiene:

  • False attivazioni della strategia basate su statistiche secondarie;
  • Trading durante periodi di spread elevati senza volatilità;
  • Sovraccarico della logica dell'EA con controlli non necessari.

L'obiettivo del filtraggio è ridurre il flusso di dati del 90%, lasciando solo gli eventi ad alto impatto (ENUM_CALENDAR_EVENT_IMPORTANCE::CALENDAR_IMPORTANCE_HIGH) per la valuta target selezionata dal trader in una determinata finestra temporale. 

Vediamo come costruire un filtro affidabile che funzioni efficacemente sia in tempo reale che in modalità di test.

Sistema di filtrazione multilivello:

I dati "grezzi" degli eventi scaricati dal terminale sono come minerale non lavorato: contengono migliaia di voci, che vanno da insignificanti report statistici a festività che non offrono alcun vantaggio alla strategia algoritmica.

Per trasformare questo flusso di dati in un segnale pulito, abbiamo bisogno di un sistema di filtraggio multilivello. Il filtraggio degli eventi agisce come un "setaccio" attraverso il quale passano i dati grezzi, lasciando in uscita solo gli eventi che soddisfano i criteri specificati: valuta, importanza, codice e finestra temporale.

Un filtro efficace dovrebbe avere una struttura gerarchica: partendo da una prima e approssimativa selezione geografica e terminando con una messa a punto precisa tramite finestra temporale.

Una caratteristica importante dell’API MQL5 delle notizie è che la struttura MqlCalendarValue non contiene i campi currency_id e country_id. Memorizza solo event_id, l'ora, i valori dell'indicatore e il tipo di influenza. In che modo ciò influisce sulla filtrazione?

Il filtraggio delle valute viene eseguito a livello di richiesta API. Quando chiamate CalendarValueHistory(..., NULL, "USD"), il terminale stesso scarta tutto tranne USD. L'array che si riceve è già filtrato per valuta. Pertanto, non è necessario controllare currency_id in tempo reale - è sufficiente filtrare per tempo, importanza e previsione di presenza/significato.

Livello 1: Filtro valuta

Il primo ostacolo è rappresentato dalla posizione geografica dell'evento. Durante le operazioni di trading su EURUSD, l'EA dovrebbe reagire solo agli eventi che interessano l'Eurozona (EUR) e gli Stati Uniti (USD). Il filtraggio consiste nel richiedere eventi con i codici valuta dello strumento negoziato. Per i cambi incrociati (ad esempio "GBPJPY"), dobbiamo richiedere eventi per entrambe le valute ("GBP" e "JPY") e "USD".

Livello 2: Importanza dell'evento

Tutte le notizie hanno un'importanza variabile in termini di impatto sull'economia, e in particolare sui prezzi. L'indice dei prezzi al consumo (Consumer Price Index CPI) può influenzare il mercato di 100 punti, mentre l'indice di fiducia dei consumatori ZEW può influenzarlo solo di 10.

L’API MQL5 utilizza l'enumerazione ENUM_CALENDAR_EVENT_IMPORTANCE per impostare il grado di importanza:

enum ENUM_CALENDAR_EVENT_IMPORTANCE
{
   CALENDAR_IMPORTANCE_NONE,      // importance level is not set
   CALENDAR_IMPORTANCE_LOW,       // low importance
   CALENDAR_IMPORTANCE_MODERATE,  // medium importance
   CALENDAR_IMPORTANCE_HIGH       // high importance
};

Gli Expert Advisor (EA) basati sulle notizie dovrebbero ignorare tutto ciò che è al di sotto di HIGH per evitare falsi positivi su notizie con bassa liquidità.

Livello 3: Codice evento

Anche tra gli eventi di grande importanza esistono delle eccezioni. Ad esempio, un discorso della BCE o del FMI può essere contrassegnato come importante, ma la sua elaborazione algoritmica è più complessa rispetto alla pubblicazione di dati specifici. Pertanto, abbiamo bisogno di ordinare per codice evento: Il campo MqlCalendarEvent::event_code contiene un ID univoco (ad esempio, "NONFARM", "CPI", "GDP"). Selezioniamo solo eventi con dati economici, non sondaggi e discorsi.

Solo dopo aver superato i primi tre livelli di verifica, l'evento viene copiato nell'array risultante e utilizzato nelle operazioni di trading.

Livelli di filtro

Fig. 4. Il filtraggio multilivello è la chiave del successo nel trading di notizie.

Dopo i primi tre livelli di filtraggio, l'EA verifica se l'evento rientra nella finestra temporale configurata. Ciò si verifica mentre l'EA di trading è in esecuzione.

Livello 4: Finestra temporale

La fase finale consiste nel verificare la pertinenza. Non abbiamo bisogno di notizie che usciranno tra un mese. La notizia diffusa ieri è già stata elaborata dal mercato. Pertanto, un evento è considerato attivo se TimeCurrent() rientra nell'intervallo: il tempo specificato prima del rilascio della notizia e il tempo specificato dopo il rilascio. In genere, si utilizzano le seguenti impostazioni: 15-30 minuti prima dell'uscita – per chiudere le posizioni e 60 minuti dopo – per analizzare la volatilità e la direzione del movimento dei prezzi.


Risorse binarie MQL5: Spostamento degli eventi ai test offline per una memorizzazione nella cache più efficiente.

Un problema legato ai test nel trading algoritmico basato sulle notizie è che il tester di strategia non ha accesso a Internet. Questa soluzione velocizza i test e protegge dai fattori non deterministici, ma crea un problema per i test delle strategie basate sulle notizie.

Se l'EA nel tester chiama la funzione CalendarValueHistory(), riceve un errore e un array vuoto. Per testare la strategia, dobbiamo incorporare dati storici sulle notizie nel file eseguibile .ex5. A tale scopo utilizziamo l'opzione delle risorse binarie MQL5. Perché proprio questa opzione? Questo è il metodo più rapido per accedere ai dati strutturati - la velocità di accesso è limitata solo dalle prestazioni del file system del computer.

Vediamo come trasformare l'array MqlCalendarValue[] in un file binario compatto e come incorporarlo nel codice in modo che il tester legga i dati dalla RAM alla velocità della luce. Il primo passo consiste nel creare uno script di esportazione che scarichi i dati correnti dal calendario e li salvi in un file binario.

Esempio pratico - uno script per esportare gli eventi in un file binario:

Il codice sorgente completo dello script è contenuto nel file ExportCalendarForTester.mq5 allegato all'articolo.


Fase 1: Assemblaggio e filtraggio dell'array

Non memorizzeremo tutti gli eventi mondiali nella risorsa. Nella fase di esportazione in file binario, applichiamo gli stessi filtri utilizzati nell'EA: valuta, importanza e tipo di evento. Gli input dello script specificano l'elenco delle valute, l'intervallo di tempo per il caricamento degli eventi, i codici degli eventi e l'importanza minima.

L'elenco dei codici evento (parametro InpEventCodes) è vuoto per impostazione predefinita - ciò significa che vengono caricati tutti i tipi di evento. Possiamo restringere questo filtro. Ad esempio, se si selezionano solo "non-farms" - l'elenco dei codici sarà "NONFARM".

Il flag InpUseCommonDir specifica dove salvare il file binario: true — salva nella cartella condivisa per tutti i terminali client "\Terminal\Common\Files".

//--- input parameters
input string                          InpCurrencies     = "USD";
input datetime                        InpDateFrom       = D'2025.01.01';
input datetime                        InpDateTo         = 0;
input string                          InpEventCodes     = "";
input ENUM_CALENDAR_EVENT_IMPORTANCE  InpMinImportance  = CALENDAR_IMPORTANCE_HIGH;
input string                          InpOutputFile     = "calendar_test_res.bin";
input bool                            InpUseCommonDir   = true;

La parte dello script che carica e filtra gli eventi in base ai valori specificati negli input è mostrata di seguito:

  Print("🔄 Calendar export:");
  Print("----------------------------------");
  Print("Filtering options:");
  Print(" 🟨 Interval = ", InpDateFrom, " — ", InpDateTo);
  Print(" 🟨 Currencies = ", InpCurrencies, "\n 🟨 Event Codes = ", InpEventCodes, "\n 🟨 Min Importance = ", EnumToString(InpMinImportance));
  Print("----------------------------------");

//--- initialize filter by currencies
  ArrayResize(currencies, 0);
  if(InpCurrencies == "")
    return;
  StringSplit(InpCurrencies, ',', currencies);
  currencies_size = ArraySize(currencies);
  for(int i = 0; i < currencies_size; i++)
    StringToUpper(currencies[i]);

//--- initialize the filter by event codes
  ArrayResize(event_codes, 0);
  if(InpEventCodes != "")
    StringSplit(InpEventCodes, ',', event_codes);
  event_codes_Size = ArraySize(event_codes);

//--- load calendar values with the CURRENCY FILTER (if specified)
  if(currencies_size > 0)
   {
    ArrayResize(values_size, currencies_size);
    ArrayFill(values_size, 0, currencies_size, 0);

    for(int i = 0; i < currencies_size; i++)
     {
      if(LoadCalendar(raw_values, InpDateFrom, InpDateTo, "", currencies[i]))
       {
        raw_values_size = ArraySize(raw_values);
        //--- load events with an IMPORTANCE AND EVENT CODE FILTER
        for(int k = 0; k < raw_values_size; k++)
         {
          //--- get event description
          if(CalendarEventById(raw_values[k].event_id, event))
           {
            //--- take indicators only
            if(event.type != CALENDAR_TYPE_INDICATOR)
              continue;                                   // nothing else to filter

            //--- check by IMPORTANCE
            if(event.importance < InpMinImportance)
              continue;                                   // nothing else to filter

            //--- check by EVENT CODE (if specified)
            if(event_codes_Size > 0)
             {
              bool code_allowed = false;
              for(int c = 0; c < event_codes_Size; c++)
               {
                StringToUpper(event.event_code);
                if(StringFind(event.event_code, event_codes[c]) >= 0)
                 {
                  code_allowed = true;
                  break;
                 }
               }
              if(code_allowed == false)
                continue;
             }

            //--- replenish the array of filtered events
            int event_index = ArraySize(values);
            ArrayResize(values, event_index + 1);
            values[event_index] = raw_values[k];
            values_size[i]++;
           }
         }
        Print("✅ Received values BY CURRENCY \"", currencies[i], "\": ", raw_values_size, " → Of these, filtered: ", values_size[i]);
       }
      else
       {
        int error = GetLastError();
        if(error == 0)
          Print("⚠ LoadCalendar Info: No Events for ", currencies[i]);
        else
          Print("❌ LoadCalendar Error: ", error, " for ", currencies[i]);
        return;                                     // nothing else to filter
       }
     }
   }

Spiegazioni relative al codice fornito:

  • L'array values_size[] memorizza il numero di eventi filtrati per ciascun codice valuta specificato negli input.
  • Il valore zero del tipo datetime MQL5 corrisponde alla data 1970.01.01 00:00:00.
  • Un ulteriore filtraggio avviene in base al tipo di evento. Soltanto gli eventi di tipoENUM_CALENDAR_EVENT_TYPE::CALENDAR_TYPE_INDICATOR sono ordinati - si tratta di eventi economici (non discorsi, ma numeri). Tutte le altre notizie vengono escluse. Ciò avviene tramite una convalida all'inizio del processo di filtraggio:
//--- take only indicators
if(event.type != CALENDAR_TYPE_INDICATOR)
  continue;                                   // Nothing else to filter


Eseguiamo lo script con diversi set di parametri di filtraggio e vediamo quanto velocemente funziona lo script di caricamento/filtraggio degli eventi. È chiaro che la velocità dipende dalla potenza del computer e dalla velocità di connessione ai server dei dati tramite Internet. Tuttavia, effettueremo uno stress test. I risultati sono presentati di seguito.

Tutti i possibili eventi USD di grande importanza — in tutto lo storico disponibile:

13:59:43.724    🔄 Calendar export:
13:59:43.724    ----------------------------------
13:59:43.724    Filtering options:
13:59:43.724      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
13:59:43.724      🟨 Currencies = USD
13:59:43.724      🟨 Event Codes = 
13:59:43.724      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
13:59:43.724    ----------------------------------
13:59:45.511    ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 9009
13:59:45.511    ----------------------------------
13:59:45.513    ✅ Saved: USD_calendar_test_res.bin   Size: 1153152 byte (9009 eventi)

Tempo di acquisizione dell'array dei valori filtrati (strutture MqlCalendarValue): 1.80 sec (0.20 ms / per filtraggio).


Tutti i possibili eventi per USD, EUR e JPY di grande importanza - in tutto lo storico disponibile:

14:03:08.724    🔄 Calendar export:
14:03:08.724    ----------------------------------
14:03:08.724    Filtering options:
14:03:08.724      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:03:08.724      🟨 Currencies = USD,EUR,JPY
14:03:08.724      🟨 Event Codes = 
14:03:08.724      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:03:08.724    ----------------------------------
14:03:10.488    ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 9009
14:03:10.947    ✅ Received values BY CURRENCY "EUR": 45139 → Of these, filtered: 1102
14:03:11.404    ✅ Received values BY CURRENCY "JPY": 18907 → Of these, filtered: 937
14:03:11.404    ----------------------------------
14:03:11.406    ✅ Saved: USD_calendar_test_res.bin   Size: 1153152 bytes  (9009 events)
14:03:11.407    ✅ Saved: EUR_calendar_test_res.bin   Size: 141056 bytes  (1102 events)
14:03:11.408    ✅ Saved: JPY_calendar_test_res.bin   Size: 119936 bytes  (937 events)

Tempo di acquisizione dell'array dei valori filtrati (strutture MqlCalendarValue): 2.68 secondi (0.24 ms / per filtraggio).


Eventi NFP ("non-farms") di grande importanza per USD in tutto lo storico disponibile:

14:07:22.203    🔄 Calendar export:
14:07:22.203    ----------------------------------
14:07:22.203    Filtering options:
14:07:22.203      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:07:22.203      🟨 Currencies = USD
14:07:22.203      🟨 Event Codes = NONFARM
14:07:22.203      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:07:22.203    ----------------------------------
14:07:22.290    ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 473
14:07:22.290    ----------------------------------
14:07:22.291    ✅ Saved: USD_calendar_test_res.bin   Size: 60544 bytes  (473 events)

Tempo di acquisizione dell'array dei valori filtrati (strutture MqlCalendarValue): 0.09 sec (0.18 ms / per filtraggio).

Osservazioni:

  1. Non è necessario specificare l'intero codice evento nel filtro. È sufficiente specificare una parte univoca della stringa contenente il codice. Ad esempio, per "non-farms", il codice completo è "NONFARM-PAYROLLS" — specificare "NONFARM" è sufficiente.
  2. Quando si esegue un sistema di trading in tempo reale nel terminale MetaTrader 5, è improbabile che sia necessario scaricare tutti gli eventi relativi all'intero periodo. In genere, vengono scaricati gli eventi correnti relativi alla giornata e alla settimana successiva. Pertanto, il tempo di caricamento nell'algoritmo EA per le notizie può essere trascurato.


Fase 2: Esportare l'array degli eventi in un file binario

La funzione SaveToBinary salva gli eventi filtrati in un file binario. Il numero di file corrisponde al numero di codici valuta specificati negli input - ogni valuta viene esportata nel proprio file binario. Il nome del file inizia con il prefisso del codice valuta. Ad esempio, "USD_calendar_test_res.bin". In questo modo otteniamo una corrispondenza diretta tra il codice valuta e l'elenco degli eventi ad esso associati.

//+------------------------------------------------------------------+
//| Save an array to a binary file                                   |
//+------------------------------------------------------------------+
void SaveToBinary(MqlCalendarValue &values[], const int &vls_size[], const string filename, const string &currencies[])
 {
  if(ArraySize(values) == 0)
   {
    Print("⚠️ Nothing to save");
    return;
   }

  Print("----------------------------------");
  int offset = 0;
  for(int i = 0; i < ArraySize(vls_size); i++)
   {
    int file_handle = FileOpen(currencies[i] + "_" + filename, FILE_WRITE | FILE_BIN | (InpUseCommonDir ? FILE_COMMON : 0));

    if(file_handle == INVALID_HANDLE)
     {
      Print("❌ FileSave failed: ", GetLastError());
      return;
     }

    FileWriteArray(file_handle, values, offset, vls_size[i]);
    FileFlush(file_handle);
    FileClose(file_handle);

    Print("✅ Saved: ", currencies[i] + "_" + filename, "   Size: ", vls_size[i] * sizeof(MqlCalendarValue), " bytes", "  (", vls_size[i], " events)");

    offset += vls_size[i];
   }
 }

Dopo aver eseguito correttamente lo script per l'esportazione degli eventi in file binari, nella scheda Expert di MetaTrader 5 compaiono messaggi come il seguente:

14:28:42.077    ----------------------------------
14:28:42.078    ✅ Saved: USD_calendar_test_res.bin   Size: 58240 bytes  (455 events)
14:28:42.079    ✅ Saved: EUR_calendar_test_res.bin   Size: 7680 bytes  (60 events)


Passo 3: Compilazione della risorsa nell'EA

Dopo aver avviato lo script ExportCalendarForTester.mq5 nella directory MQL5/Files/, vengono creati i file USD_calendar_test_res.bin e EUR_calendar_test_res.bin. Ora devono essere "integrati" nell'EA. All'inizio del file dell’EA (dopo le direttive #property), aggiungiamo una (se stai utilizzando un file per una sola valuta) o più righe del seguente tipo:

// Embed the binary file as a static resource at the compilation stage
#resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[]
#resource "\\Files\\EUR_calendar_test_res.bin" as MqlCalendarValue EUR_res_calendar_data[]

Nota:

  1. Il percorso alla risorsa #resource è specificato in relazione alla cartella MQL5/Files/. Il prefisso \\Files\\ è obbligatorio.
  2. Durante la compilazione dell'EA, nella scheda Errori di MetaEditor dovrebbero comparire messaggi simili ai seguenti:
  • 'USD_calendar_test_res.bin' as 'const MqlCalendarValue USD_res_calendar_data[455]' 
  • 'EUR_calendar_test_res.bin' as 'const MqlCalendarValue EUR_res_calendar_data[60]' 

All'avvio dell'EA, le strutture degli eventi salvati durante la fase di esportazione vengono memorizzate negli array USD_res_calendar_data[] e EUR_res_calendar_data[].


Integrazione nell'EA: Commutazione automatica della modalità

L'obiettivo è far sì che lo stesso codice dell’EA funzioni sia in tempo reale che nell'ambiente di test, selezionando automaticamente la fonte dei dati. La funzione MQLInfoInteger (MQL_TESTER) restituisce 'true' se l'EA è in esecuzione nello Strategy Tester o nell'Ottimizzatore.

//+------------------------------------------------------------------+
//| Initialization: select a data source                             |
//+------------------------------------------------------------------+
int OnInit()
 {
  Print("🔄 Initializing the news module:");

//--- initialize filter by currencies
  ArrayResize(currencies, 0);
  if(InpCurrencies == "")
    return INIT_FAILED;
  StringSplit(InpCurrencies, ',', currencies);
  currencies_size = ArraySize(currencies);
  for(int i = 0; i < currencies_size; i++)
    StringToUpper(currencies[i]);

//--- initialize the filter by event codes
  ArrayResize(event_codes, 0);
  if(InpEventCodes != "")
    StringSplit(InpEventCodes, ',', event_codes);
  event_codes_Size = ArraySize(event_codes);

//--- define the execution environment
  bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE);
  if(is_tester)
   {
    //--- TESTER MODE: Load from resource
    if(!LoadFromResource())
     {
      Print("❌ ERROR: Failed to load calendar from resource");
      return INIT_FAILED;
     }
    is_live_mode = false;
    Print("⚠️ Mode: TESTER (data from resource)");
   }
  else
   {
    //--- LIVE MODE: Load from API
    if(!LoadFromCalendarAPI())
     {
      int error = GetLastError();
      Print("❌ ERROR: Failed to load calendar from API - ", error);
      return INIT_FAILED;
     }
    is_live_mode = true;

    Print("⚠️ Mode: LIVE (data from API)");
   }

  return INIT_SUCCEEDED;
 }


Spiegazioni relative al codice fornito:

Il controllo principale viene effettuato nel gestore eventi di inizializzazione dell’EA OnInit():

   //--- define the execution environment
   bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE);
   if(is_tester)
    {
      //--- TESTER MODE: Load from resource
      if(!LoadFromResource())
       {
        ...
       }
    }
   else
    {
      //--- LIVE MODE: Load from API
      if(!LoadFromCalendarAPI())
       {
        ...
       }
    }

Spiegazioni relative al codice fornito:

Determiniamo in quale modalità sta operando il programma MQL5 in esecuzione (in questo caso il nostro Expert Advisor). Siamo interessati ai seguenti flag:

  • MQL_TESTER — flag del programma avviato in esecuzione nel tester;
  • MQL_OPTIMIZATION — flag del programma avviato durante l'ottimizzazione;
  • MQL_VISUAL_MODE — flag del programma avviato in modalità di test visivo.
Se almeno uno di questi flag è attivo, carichiamo l'elenco degli eventi dalla risorsa. In alternativa, carichiamo l'elenco degli eventi nel modo consueto dal server tramite l'API del calendario.


14:42:18.894    🔄 Initializing news module:
14:42:18.905    ✅ Events from Server Loaded: 455 events for: USD
14:42:18.914    ✅ Events from Server Loaded: 60 events for: EUR
14:42:18.914    ⚠️ Mode: LIVE (data from API)



Validazione della catena di trasformazione dei dati: Eventi → File Binario → Compila come Risorsa → Ottieni gli eventi dalla risorsa

Non resta che verificare il recupero degli eventi nel tester e assicurarsi che corrispondano perfettamente all'elenco ricevuto in tempo reale. Ciò confermerà la possibilità di testare e ottimizzare automaticamente gli algoritmi di trading basati sulle notizie.

Per fare ciò, aggiungiamo l'output degli eventi ricevuti dal server/scaricati dalla risorsa al terminale/log del tester di strategia. Il file di testo completo ImportTesterLog.txt con i risultati dell'esecuzione del tester è allegato di seguito. Qui di seguito è riportato un frammento del file di log - l'inizio e la fine della sequenza di eventi per ciascun codice valuta.

Risultato di una singola esecuzione nel tester di strategie, in modalità visiva:

16:48:22.527    EURUSD,M5: testing of Experts\ImportCalendarValidation-EA.ex5 from 2026.01.01 00:00 to 2026.03.07 00:00 started with inputs:
16:48:22.527      InpCurrencies=USD,EUR
16:48:22.527      InpDateFrom=1735689600
16:48:22.527      InpDateTo=1767225600
16:48:22.527      InpEventCodes=
16:48:22.527      InpMinImportance=3
16:48:22.546   🔄 Initializing news module:
16:48:22.546   ✅ Events from Resource Loaded: 455 events for: USD
16:48:22.546   ✅ Event #0
16:48:22.546   ID:                    230215
16:48:22.546   Event ID:          840140001
16:48:22.546   Time:               2025.01.02 16:30:00
16:48:22.546   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.546   Revision:          0
16:48:22.546   Actual:             211.0
16:48:22.546   Revised:           220.0
16:48:22.546   Forecast:          219.0
16:48:22.546   Previous:          219.0
16:48:22.546   ✅ Event #1
16:48:22.546   ID:                   230641
16:48:22.546   Event ID:          840500001
16:48:22.546   Time:               2025.01.02 17:45:00
16:48:22.546   Impact:            CALENDAR_IMPACT_NEGATIVE
16:48:22.546   Revision:          3
16:48:22.546   Actual:             49.4
16:48:22.546   Forecast:          50.5
16:48:22.546   Previous:          49.7
 ...
16:48:22.553   ✅ Event #453
16:48:22.553   ID:                   274419
16:48:22.553   Event ID:          840510001
16:48:22.553   Time:               2025.12.30 17:45:00
16:48:22.553   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:          0
16:48:22.553   Actual:             43.5
16:48:22.553   Forecast:          42.4
16:48:22.553   Previous:          36.3
16:48:22.553   ✅ Event #454
16:48:22.553   ID:                   274484
16:48:22.553   Event ID:          840140001
16:48:22.553   Time:               2025.12.31 16:30:00
16:48:22.553   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:          0
16:48:22.553   Actual:             199.0
16:48:22.553   Revised:           215.0
16:48:22.553   Forecast:          227.0
16:48:22.553   Previous:          214.0
...
16:48:22.553   ✅ Events from Resource Loaded: 60 events for: EUR
16:48:22.553   ✅ Event #0
16:48:22.553   ID:                   231322
16:48:22.553   Event ID:         999030013
16:48:22.553   Time:              2025.01.07 13:00:00
16:48:22.553   Impact:           CALENDAR_IMPACT_NA
16:48:22.553   Revision:         1
16:48:22.553   Actual:            2.4
16:48:22.553   Forecast:         2.4
16:48:22.553   Previous:         2.2
16:48:22.553   ✅ Event #1
16:48:22.553   ID:                  187384
16:48:22.553   Event ID:         999040007
16:48:22.553   Time:              2025.01.08 13:00:00
16:48:22.553   Impact:           CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:         0
16:48:22.553   Actual:            21.0
16:48:22.553   Revised:          17.8
16:48:22.553   Forecast:         15.7
16:48:22.553   Previous:         17.7
...
16:48:22.555   ✅ Event #58
16:48:22.555   ID:                  204746
16:48:22.555   Event ID:         999010006
16:48:22.555   Time:              2025.12.18 16:15:00
16:48:22.555   Impact:           CALENDAR_IMPACT_NA
16:48:22.555   Revision:         0
16:48:22.555   Actual:            2.0
16:48:22.555   Previous:         2.0
16:48:22.555   ✅ Event #59
16:48:22.555   ID:                  204762
16:48:22.555   Event ID:         999010007
16:48:22.555   Time:              2025.12.18 16:15:00
16:48:22.555   Impact:           CALENDAR_IMPACT_NA
16:48:22.555   Revision:         0
16:48:22.555   Actual:            2.15
16:48:22.555   Previous:         2.15
16:48:22.555   ⚠️ Mode: TESTER (data from resource)

È evidente che tutti gli array degli eventi sono stati caricati dalla risorsa in circa 10 ms, il che non sorprende — la risorsa è integrata nel codice dell'EA e viene caricata insieme ad esso all'avvio del test.

La stessa esecuzione (avvio) di un expert advisor in modalità Live nel terminale MetaTrader 5 produce un file di log simile con un elenco di eventi caricati. Il file LoadLiveLog.txt completo, contenente i risultati del caricamento in tempo reale, è allegato all'articolo. Qui di seguito è riportato un frammento del file di log - l'inizio e la fine della sequenza di eventi per ciascun codice valuta.

Risultati del download in tempo reale degli eventi dal server:

17:27:25.250    🔄 Initializing news module:
17:27:25.258    ✅ Received values BY CURRENCY "USD": 3589 → Of these, filtered: 455
17:27:25.258    ✅ Events from Server Loaded: 455 events for: USD
17:27:25.258    ✅ Event #0
17:27:25.258    ID:                   230215
17:27:25.258    Event ID:          840140001
17:27:25.258    Time:               2025.01.02 16:30:00
17:27:25.258    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.258    Revision:          0
17:27:25.258    Actual:             211.0
17:27:25.258    Revised:           220.0
17:27:25.258    Forecast:          219.0
17:27:25.258    Previous:          219.0
17:27:25.258    ✅ Event #1
17:27:25.258    ID:                   230641
17:27:25.258    Event ID:          840500001
17:27:25.258    Time:               2025.01.02 17:45:00
17:27:25.258    Impact:            CALENDAR_IMPACT_NEGATIVE
17:27:25.258    Revision:          3
17:27:25.258    Actual:             49.4
17:27:25.258    Forecast:         50.5
17:27:25.258    Previous:          49.7
...
17:27:25.288    ✅ Event #453
17:27:25.288    ID:                   274419
17:27:25.288    Event ID:          840510001
17:27:25.288    Time:               2025.12.30 17:45:00
17:27:25.288    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.288    Revision:          0
17:27:25.288    Actual:             43.5
17:27:25.288    Forecast:          42.4
17:27:25.288    Previous:          36.3
17:27:25.288    ✅ Event #454
17:27:25.288    ID:                    274484
17:27:25.288    Event ID:          840140001
17:27:25.288    Time:               2025.12.31 16:30:00
17:27:25.288    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.288    Revision:          0
17:27:25.288    Actual:             199.0
17:27:25.288    Revised:           215.0
17:27:25.288    Forecast:          227.0
17:27:25.288    Previous:          214.0

17:27:25.301    ✅ Received values BY CURRENCY "EUR": 3116 → Of these, filtered: 0
17:27:25.301    ✅ Events from Server Loaded: 60 events for: EUR
17:27:25.301    ✅ Event #0
17:27:25.301    ID:                   231322
17:27:25.301    Event ID:          999030013
17:27:25.301    Time:               2025.01.07 13:00:00
17:27:25.301    Impact:            CALENDAR_IMPACT_NA
17:27:25.301    Revision:          1
17:27:25.301    Actual:             2.4
17:27:25.301    Forecast:          2.4
17:27:25.301    Previous:          2.2
17:27:25.301    ✅ Event #1
17:27:25.301    ID:                   187384
17:27:25.301    Event ID:          999040007
17:27:25.301    Time:               2025.01.08 13:00:00
17:27:25.301    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.301    Revision:          0
17:27:25.301    Actual:             21.0
17:27:25.301    Revised:           17.8
17:27:25.301    Forecast:         15.7
17:27:25.301    Previous:          17.7
...
17:27:25.303    ✅ Event #58
17:27:25.303    ID:                   204746
17:27:25.303    Event ID:          999010006
17:27:25.303    Time:               2025.12.18 16:15:00
17:27:25.303    Impact:            CALENDAR_IMPACT_NA
17:27:25.303    Revision:          0
17:27:25.303    Actual:             2.0
17:27:25.303    Previous:          2.0
17:27:25.303    ✅ Event #59
17:27:25.303    ID:                   204762
17:27:25.303    Event ID:          999010007
17:27:25.303    Time:               2025.12.18 16:15:00
17:27:25.303    Impact:            CALENDAR_IMPACT_NA
17:27:25.303    Revision:          0
17:27:25.303    Actual:            2.15
17:27:25.303    Previous:         2.15
17:27:25.303    ⚠️ Mode: LIVE (data from API)

Un download completo con filtraggio e registrazione richiede circa 50 ms — un tempo comunque sufficientemente breve da poter ignorare il tempo di download/filtraggio degli eventi. Confrontando i due file di log, notiamo che l'elenco degli eventi è completamente identico sia per numero di eventi che per valore dei campi. Validazione della catena di trasformazione dei dati completata con successo.

Analisi degli errori più comuni e delle false aspettative.

Analizziamo i sei errori più comuni che gli sviluppatori commettono durante l'integrazione del calendario economico MQL5. Ognuno di questi casi è stato verificato nella pratica e potrebbe costare a qualcuno il deposito perduto.

1. " Il calendario prevede il movimento "

Falsa aspettativa:

Se vengono diffuse notizie con importanza HIGH e il risultato effettivo differisce significativamente dalle previsioni, è garantito che il prezzo si muoverà nella direzione della deviazione. Acquista semplicemente se il prezzo effettivo è superiore alle previsioni per la valuta di base.

Realtà:

Il calendario economico è una fonte di dati, non un generatore di segnali di trading. Ti dice cosa è successo, ma non come reagirà il mercato. Perché il prezzo potrebbe andare contro "l’ovvia" logica?

  • Il mercato aveva già scontato le aspettative giorni prima della pubblicazione. Nel momento stesso in cui la notizia viene diffusa, avviene la "vendita della notizia".
  • Dati sull'inflazione elevati in un periodo di inasprimento della politica monetaria da parte della banca centrale possono rafforzare la valuta, ma in un periodo di allentamento possono innescare un'ondata di vendite a causa dei timori di surriscaldamento dell'economia.
  • La notizia potrebbe essere positiva, ma se il valore precedente viene rivisto al ribasso, il segnale complessivo diventa ambiguo.
  • La pubblicazione simultanea di dati relativi a più valute crea effetti incrociati che non possono essere interpretati in modo lineare.

L'approccio corretto è quello di utilizzare il calendario come filtro di volatilità, non come segnale di ingresso:

//--- instead of
if(actual > forecast)
 OrderSend(...);

//--- use:
if(IsHighImpactNewsComingSoon(30)) 
 {
   //--- reduce the position size or temporarily suspend trading
   ReduceRiskExposure();
 }
Regola d'oro: Il calendario risponde alla domanda "Quando aspettarsi un aumento della volatilità?", non "In quale direzione operare?".


2. "Tutti gli eventi HIGH sono ugualmente importanti"

Falsa aspettativa:

Il campo importance == CALENDAR_IMPORTANCE_HIGH indica che l'evento è destinato a muovere il mercato di oltre 50 pip. Possiamo scambiare tutte queste notizie utilizzando lo stesso algoritmo.

Realtà:

I valori specifici nell'enumerazione ENUM_CALENDAR_EVENT_IMPORTANCE rappresentano una valutazione soggettiva da parte dei redattori del calendario, non una metrica quantitativa dell'impatto sul mercato. Ad esempio, prendiamo due eventi etichettati come HIGH, ma con diversa rilevanza per il mercato.

Il primo evento,Non-Farm Payrolls (USA), produce una risposta di volatilità di 80-150 punti, in quanto è un indicatore chiave dell'occupazione e influenza la politica della Fed. Il secondo evento, l'indice PMI manifatturiero (Eurozona), fornisce una variazione di 10-30 punti, poiché si tratta di un indicatore settoriale ristretto ed è secondario per la BCE.

L'approccio corretto consiste nell'integrare il filtro di importanza con un elenco di codici di eventi prioritari:

//--- a list of events that are really worth reacting to
bool IsGoodEvent(const string event_code)
 {
   static const string tier1_codes[] = 
   {
      "NONFARM", "CPI", "GDP", "RATE", "FOMC", "ECB_RATE", 
      "RETAIL_SALES", "UNEMPLOYMENT", "PMI_MANUFACTURING"
   };
   
   for(int i = 0; i < ArraySize(tier1_codes); i++)
      if(StringFind(event_code, tier1_codes[i]) != -1)
         return true;
   return false;
 }

//--- use in filter
if(event.importance == CALENDAR_IMPORTANCE_HIGH && IsGoodEvent(event.event_code))
 {
   //--- handle only truly significant news
 }

Raccomandazione:

Create la vostra classifica degli eventi basata sull'analisi della volatilità storica — più affidabile di qualsiasi etichetta predefinita.


3. "Utilizzare TimeLocal() invece di TimeTradeServer()"

Falsa aspettativa:

L'ora dell'evento nella struttura MqlCalendarValue::time è specificata nel mio fuso orario locale (o UTC), quindi posso confrontarla con TimeLocal() o TimeGMT().

Realtà:

Tutte le funzioni del calendario economico restituiscono l'ora nel fuso orario del server di trading (TimeTradeServer()). Si tratta di una scelta architetturale che elimina la necessità di conversioni manuali, ma richiede disciplina da parte dello sviluppatore.

Le conseguenze di questo errore sono gravi - se il vostro server si trova nel fuso orario EET (UTC+2) e utilizzate TimeLocal() (ad esempio MSK, UTC+3), controllerete gli eventi con un offset di 1 ora. L'EA potrebbe non venire a conoscenza della notizia o, al contrario, reagire ad essa a posteriori.

L'approccio corretto è quello di utilizzare sempre TimeTradeServer() per tutti i confronti temporali:

//--- WRONG — risk of desynchronization
datetime now = TimeLocal();
if(event.time - now < 1800)
 { ... }

//--- RIGHT — guaranteed synchronization
datetime now = TimeTradeServer();
if(event.time - now < 1800)
 { ... }

//--- in the tester, TimeTradeServer() returns the model time, so the logic works identically to live

Raccomandazione:

Aggiungete l'output di TimeToString(TimeTradeServer(), TIME_MINUTES) al log di debug e confrontatelo con l'ora dell'evento - dovrebbero corrispondere senza conversione.


4. "Dimenticare che i campi degli eventi possono essere vuoti"

Falsa aspettativa:

I campi actual_value, forecast_value e altri contengono sempre valori numerici corretti. Possiamo tranquillamente dividerli per 1.000.000 e confrontare i risultati.

Realtà:

Secondo la documentazione, i campi numerici della struttura MqlCalendarValue memorizzano valori moltiplicati per un milione o per la costante LONG_MIN se non viene specificato alcun valore. Cosa succede se ignoriamo il controllo?

//--- error
double actual = values[i].actual_value / 1000000.0; // if actual_value == LONG_MIN, result: -9223372036.854776

if(actual > forecast) // comparison with a "garbage" number causes a false alarm
  OpenBuy();

L'approccio corretto consiste nell'utilizzare i metodi integrati della struttura MqlCalendarValue per ottenere i valori in modo sicuro:

//--- the right approach is built-in methods
if(values[i].HasActualValue() && values[i].HasForecastValue())
 {
  double actual = values[i].GetActualValue();
  double forecast = values[i].GetForecastValue();

  if(!MathIsNaN(actual) && !MathIsNaN(forecast))
   {
    double deviation = actual - forecast;
    // ... analysis logic
   }
 }
//+------------------------------------------------------------------+

Nota:

Le funzioni GetActualValue(), GetForecastValue() e altre simili restituiscono NaN se non sono presenti dati. Prima di utilizzare il risultato nei calcoli, verificarlo sempre tramite le funzioni MathIsValidNumber() o MathIsNaN().


5. "Chiamare le funzioni API del calendario in OnTick()"

Falsa aspettativa:

Per avere sempre dati aggiornati, chiamerò CalendarValueHistory() a ogni tick. Ciò garantisce che l'EA non si perda nessuna notizia dell'ultima ora".

Realtà:

Le funzioni del calendario operano tramite un server remoto a cui MetaTrader 5 si connette e sono soggette a rigidi limiti di frequenza delle richieste. La chiamata in OnTick() (che può essere eseguita decine di volte al secondo) causerà problemi:

  • Errore 5204 (ERR_CALENDAR_TOO_MANY_REQUESTS) — blocco temporaneo dell'accesso al calendario.
  • Ritardi di esecuzione - una richiesta di rete nel ciclo di trading aumenta lo slippage.
  • Traffico eccessivo - download ripetuto degli stessi dati.
L'approccio corretto consiste nell'utilizzare la cache e l'aggiornamento incrementale:
//--- global variables
MqlCalendarValue calendar_cache[];
bool cache_initialized = false;
long last_change_id = 0;

//+------------------------------------------------------------------+
int OnInit()
 {
//--- initial history loading (once at startup)
  datetime from = TimeCurrent() - 7 * 86400;
  datetime to = TimeCurrent() + 30 * 86400;

  if(CalendarValueHistory(calendar_cache, from, to, "USD"))
   {
    cache_initialized = true;
   }

//--- set a timer for periodic updates (no more than 5-10 minutes)
  EventSetTimer(300);
  return INIT_SUCCEEDED;
 }
//+------------------------------------------------------------------+
void OnTimer()
 {
  if(!cache_initialized)
    return;

  MqlCalendarValue updates[];

//--- only request changes since the last update
  if(CalendarValueLast(last_change_id, updates, "USD") > 0)
   {
    if(ArraySize(updates) > 0)
     {
      //--- merge new data with the cache
      MergeUpdates(calendar_cache, updates);
      last_change_id = updates[ArraySize(updates) - 1].change_id;
     }
   }
 }
//+------------------------------------------------------------------+
void OnTick()
 {
//--- work only with local cache - no network delays
  if(cache_initialized)
    ProcessNewsSignals(calendar_cache);
 }

Raccomandazione:

OnTick() dovrebbe funzionare solo con dati locali. Richieste di rete - solo in OnInit(), OnTimer() o tramite evento utente.


6. "Dimenticare di ricompilare l'expert advisor per testarlo su nuovi eventi"

Falsa aspettativa:

Ho aggiornato il file di risorse calendar_test_res.bin nella cartella Files; ora il tester visualizzerà automaticamente i nuovi eventi. Non è necessario ricompilare l'EA.

Realtà:

La direttiva #resource incorpora i dati nel file eseguibile .ex5 in fase di compilazione. Le modifiche al file .bin esterno non vengono rilevate dinamicamente - l'EA continua a utilizzare la versione della risorsa compilata in fase di build.

Sintomi di errore:

  • Il registro di test non include gli eventi aggiunti alla risorsa dopo l'ultima compilazione.
  • La strategia "non rileva" le notizie importanti, sebbene siano presenti nel file.
  • I risultati del test differiscono dalle aspettative, sebbene il codice sia logicamente corretto.

L'approccio corretto consiste nel ricompilare sempre l'EA dopo aver aggiornato la risorsa:

//--- at the beginning of the EA file
#resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[]

//--- after USD_calendar_test_res.bin update:
// 1. Save changes to the resource file.
// 2. Press F7 in MetaEditor (or Compile in the menu).
// 3. Make sure there are no errors in the compilation log.
// 4. Run the test again.

Raccomandazione:

Aggiungi l'output della versione della risorsa (ad esempio hash o data dell'ultimo aggiornamento) al log di compilazione per monitorare visivamente la pertinenza dei dati in .ex5.

Osservazioni:

Gli errori discussi in questa sezione non derivano da una mancanza di conoscenza della sintassi MQL5, bensì da una comprensione semplificata della natura dei dati economici (indicatori). Chiunque impari a evitare questi sei errori non otterrà solo un codice funzionante, ma anche un sistema di trading stabile, capace di adattarsi ai cambiamenti del mercato e ai requisiti delle autorità di regolamentazione economica. È questo approccio che distingue un dilettante da un professionista nel trading algoritmico.


Conclusioni

Il calendario economico presente nel terminale MetaTrader 5 è uno strumento molto potente. Ma come qualsiasi strumento, richiede la comprensione del contesto, la disciplina nell'utilizzo e la considerazione dei limiti della piattaforma.

Abbiamo preso in considerazione una specifica struttura di implementazione e utilizzo per l'API delle notizie per l'EA in MetaTrader 5. L'articolo fornisce una serie di elementi pratici che, considerati nel loro insieme, trasformano il trading manuale di notizie in un modulo riproducibile:

  • comprensione dell'API del calendario (Evento vs Valore, strutture MqlCalendarEvent/MqlCalendarValue, ora del server);
  • metodi di caricamento e aggiornamento sicuri (CalendarValueHistory per il caricamento iniziale, CalendarValueLast + change_id per gli aggiornamenti incrementali);
  • gestione degli errori tipici e rispetto dei limiti delle richieste;
  • filtraggio multilivello per valuta, importanza, codice evento e finestre temporali per ridurre il rumore e lasciare 3-5 eventi significativi;
  • un meccanismo per esportare i dati filtrati in una risorsa binaria e commutare automaticamente la sorgente dati "in tempo reale" ↔ "tester di strategia", garantendo un comportamento identico in tempo reale e nel backtesting.

Criteri di prontezza del modulo: gli eventi per il periodo specificato vengono caricati correttamente; gli aggiornamenti incrementali funzionano tramite change_id senza superare i limiti; nell'ambiente di test, l'EA legge la risorsa e produce le stesse decisioni che produce in live con dati di input identici.

Prossimi passi consigliati: implementare l'esportatore, inserire il file .bin direttamente nella risorsa #resource, testare la logica di aggiornamento OnInit/OnTimer ed eseguire backtest controllati (ad esempio, nello scenario "non effettuare operazioni per 30 minuti / riprendi dopo 60 minuti").

Questo vi permetterà di passare dalle ipotesi a un sistema di trading di notizie testabile e scalabile. Lo sviluppo di Expert Advisor per le notizie non si limita alla programmazione; significa costruire un ponte tra la teoria macroeconomica e la pratica di mercato. 

Risorse consigliate per uno studio approfondito delle funzioni API del Calendario di MetaTrader 5 e del loro utilizzo nel trading sulle notizie:


Elenco dei file allegati all'articolo:

Nome del File Descrizione
CalendarEventMonitor-EA.mq5  Codice dello script di test per la verifica della funzione di aggiornamento dei dati del calendario
ExportCalendarForTester-S.mq5 Il codice di uno script di test per verificare l'esportazione di eventi con filtri specificati in un file binario
GetTodayEvents-S.mq5 Il codice di uno script di test per verificare il recupero degli eventi relativi al giorno corrente.
ImportCalendarValidation-EA.mq5 Il codice di un EA di test per verificare il recupero delle notizie nel tester di strategia da una risorsa
ImportTesterLog.txt  Risultati di una singola esecuzione dell'EA ImportCalendarValidation-EA.mq5 nel tester in modalità visuale
LoadLiveLog.txt  Risultati del caricamento live degli eventi nell'EA ImportCalendarValidation-EA.mq5

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

Ultimi commenti | Vai alla discussione (8)
Stanislav Korotky
Stanislav Korotky | 1 mag 2026 a 13:32

Scritto:

Если брокер учитывает переход на летнее/зимнее время — календарь автоматически подстраивается под этот переход

Correggetemi se qualcosa è cambiato nell'API MQL5, ma in precedenza il calendario si adattava al fuso orario CORRENTE tenendo conto dell'ora legale (DST), ovvero in estate le richieste alle funzioni restituivano timestamp, ad esempio, nel fuso orario UTC+3, mentre una richiesta relativa allo stesso intervallo di storia in inverno restituiva eventi con timestamp nel fuso orario UTC+2, se il server effettuava il passaggio all'ora legale e viceversa. Pertanto, per scaricare con precisione la cronologia del calendario per un periodo di sei mesi o più, è necessario analizzare la cronologia dei cambiamenti di fuso orario del broker. Maggiori dettagli nel codice sorgente.

Inoltre, l’approccio che prevede la cache del calendario sotto forma di risorsa sembra poco pratico e, in particolare, provoca gli errori menzionati nell’articolo stesso (del tipo: non dimenticate di ricompilare l’expert). Perché non impostare la cache del calendario come parametro di input, sotto forma di file proveniente dalla cartella «Common», accessibile a tutti gli agenti?

Maxim Kuznetsov
Maxim Kuznetsov | 3 mag 2026 a 17:44
Correggetemi se qualcosa è cambiato nell'API MQL5, ma in passato il calendario si adattava al fuso orario CORRENTE tenendo conto dell'ora legale (DST); in altre parole, in estate le richieste alle funzioni restituivano timestamp, ad esempio nel fuso orario UTC+3, mentre la richiesta dello stesso intervallo storico in inverno restituirà eventi con timestamp nel fuso orario UTC+2, se il server effettua il passaggio all’ora legale e viceversa. Pertanto, per scaricare con precisione la cronologia del calendario per un periodo di sei mesi o più, è necessario analizzare la cronologia dei cambi di fuso orario часового пояса del broker. Maggiori dettagli nel codice sorgente.

E perché le quotazioni (e in generale tutti i timestamp) non vengono registrate, ad esempio, in UTC?

perché i tick dei dealer hanno una rappresentazione numerica diversa dello stesso intervallo di tempo

Domanda filosofica :-) È così che è sempre stato, anche se non è corretto e crea problemi dal nulla.


P.S. Per questo è meglio attingere le «notizie storiche» da altre fonti.

E non bisogna mai «analizzare la cronologia delle conversioni dell’ora» da soli: tutto questo è già disponibile, è una funzione del sistema operativo o, al limite, delle librerie di sistema. Cercate su Google «tzdata»

quante biciclette si possono costruire, per di più storte

fxsaber
fxsaber | 3 mag 2026 a 19:30
Stanislav Korotky #:

in precedenza il calendario si adattava al fuso orario CORRENTE tenendo conto dell'ora legale (DST), ovvero in estate le richieste alle funzioni restituivano timestamp, ad esempio, nel fuso orario UTC+3, mentre la richiesta dello stesso intervallo di cronologia in inverno restituirà eventi con timestamp nel fuso orario UTC+2, se il server effettua il passaggio all’ora legale e viceversa.

Anch’io mi sono fatto la stessa idea.
Stanislav Korotky
Stanislav Korotky | 4 mag 2026 a 16:09
Maxim Kuznetsov #:


P.S. Per questo motivo è meglio attingere le "notizie storiche" da altre fonti.

E non bisogna mai "analizzare da soli la cronologia delle conversioni dell'ora": tutto questo è già disponibile, è una funzione del sistema operativo o, al limite, delle librerie di sistema. Cercate su Google "tzdata"

quante biciclette si possono costruire, per di più storte


Altre fonti non risolveranno il problema, poiché è insito nel modo in cui le quotazioni vengono memorizzate in MT5.

Per cominciare, mostrateci la vostra bicicletta "dritta", e poi dateci dei consigli.

ilex044
ilex044 | 11 mag 2026 a 10:09
MetaQuotes:

I problemi principali del trader che opera sulla base delle notizie sono la frammentazione degli strumenti a disposizione e la mancanza di un flusso di lavoro di trading sistematico e algoritmico. È piuttosto difficile dividere l’attenzione tra il browser Internet (per consultare i siti di notizie) e la piattaforma di trading mentre si effettuano le operazioni.

Il flusso di lavoro di un trader che opera sulla base delle notizie si presenta così: aprire rapidamente il calendario delle notizie nel browser web e verificare eventuali cambiamenti negli eventi → valutare rapidamente gli eventi imminenti e decidere su cosa e come operare → passare al terminale MetaTrader 5 – dove si possono inserire ordini in sospeso oppure rimanere al terminale in attesa della pubblicazione della notizia per prendere una decisione. In questo scenario, il trader spesso subisce una perdita di contesto, il che comporta ritardi nella reazione alle notizie, che a loro volta portano a perdite.

Vuoi che il trading basato sulle notizie funzioni come un problema di ingegneria — con regole chiare, risultati ripetibili e test automatizzati? Lo scopo di questo articolo è illustrare l’architettura operativa di un livello dedicato alle notizie per MetaTrader 5: un'unica fonte di dati, l'uso corretto dell'API del calendario, un meccanismo di filtraggio e memorizzazione nella cache, l'esportazione degli eventi storici in una risorsa per il tester e il passaggio automatico tra Live e Tester — in modo che lo stesso codice produca risultati deterministici sia in tempo reale che sui dati storici.

Sì, questo è un vero punto dolente per il trading basato sulle notizie.

Passare dal browser al calendario e al terminale distrae e rallenta notevolmente le reazioni. Disporre di un flusso di lavoro unificato o di un sistema che importi le notizie direttamente nell’ambiente di trading renderebbe sicuramente l’esecuzione più veloce e più coerente.

L’idea di trasformarlo in una configurazione strutturata e ripetibile in “stile ingegneristico”, con test e automazione, ha in realtà molto senso per evitare decisioni emotive o ritardate.

Arriva il Nuovo MetaTrader 5 e MQL5 Arriva il Nuovo MetaTrader 5 e MQL5
Questa è solo una panoramica di MetaTrader 5. Non posso descrivere tutte le nuove funzionalità del sistema per un periodo di tempo così breve: i test sono iniziati il 09.09.2009. Questa è una data simbolica e sono sicuro che sarà un numero fortunato. Sono passati alcuni giorni da quando ho ricevuto la versione beta del terminale MetaTrader 5 e MQL5. Non sono riuscito a provare tutte le sue funzionalità, ma sono già sorpreso.
Python + MetaTrader 5: Framework Rapido per la Ricerca su Dati, Feature e Prototipi Python + MetaTrader 5: Framework Rapido per la Ricerca su Dati, Feature e Prototipi
L'articolo dimostra come l'integrazione tra Python e MetaTrader 5 combini la flessibilità della ricerca e l'esecuzione dei trade in un unico flusso di lavoro. Python viene utilizzato per l'analisi dei dati, la selezione delle feature e l'addestramento dei modelli, mentre MetaTrader 5 viene utilizzato per i test e l'automazione del trading. Questo approccio semplifica il trasferimento delle soluzioni nella pratica, aumenta la riproducibilità e rende lo sviluppo dei sistemi di trading più rapido e strutturato.
Utilizza i canali MQL5.community e le chat di gruppo Utilizza i canali MQL5.community e le chat di gruppo
Il sito web MQL5.com riunisce trader di tutto il mondo. Gli utenti pubblicano articoli, condividono codici gratuiti, vendono prodotti nel Market, offrono servizi da freelance e copiano segnali di trading. Puoi comunicare con loro sul Forum, nelle chat dei trader e nei canali MetaTrader.
Trading algoritmico senza routine: Analisi rapida dei trade in MetaTrader 5 con SQLite Trading algoritmico senza routine: Analisi rapida dei trade in MetaTrader 5 con SQLite
L'articolo presenta un set minimo di funzionalità per la gestione di un registro di trading in MQL5 utilizzando SQLite: una struttura di tabelle per transazioni, segnali, eventi, indici, istruzioni preparate e gestione delle operazioni, nonché query SQL analitiche standard. Vengono illustrate l'integrazione con la dashboard delle statistiche in MetaTrader 5 e il lavoro con il database tramite MetaEditor. Questo approccio consente di automatizzare il registro, accelerare i calcoli ed eseguire analisi senza complicare il codice dell'EA.