English Русский Deutsch 日本語 한국어 Italiano Türkçe
preview
MetaTrader 5 et le Calendrier Économique MQL5 : comment transformer les actualités en un système de trading reproductible

MetaTrader 5 et le Calendrier Économique MQL5 : comment transformer les actualités en un système de trading reproductible

MetaTrader 5Exemples |
117 8
MetaQuotes
MetaQuotes

Introduction

Les principaux problèmes du trader d'actualités moderne sont la fragmentation des outils et l'absence d’un processus de trading structuré et algorithmique. Il est assez difficile de répartir son attention entre son navigateur internet (pour consulter des sites d'actualités) et son terminal de trading lorsqu'on passe des ordres.

Le flux de travail d'un trader sur actualités ressemble à ceci : Ouvrir rapidement le calendrier des actualités dans son navigateur Web et vérifier les changements d'événements → Évaluer rapidement les événements à venir et décider quoi et comment trader → Accéder au terminal MetaTrader 5 – placer des ordres en attente ou rester devant le terminal et attendre la publication des actualités pour prendre une décision. Dans ce scénario, le trader perd souvent le fil de l’analyse, ce qui entraîne des retards dans sa réaction aux actualités, ce qui à son tour engendre des pertes.

Et si le trading d’actualités fonctionnait comme un problème d’ingénierie — avec des règles claires, des résultats reproductibles et des tests automatisés ? L'objectif de cet article est de démontrer l'architecture opérationnelle d'un module d’actualités pour MetaTrader 5 : une source de données unique, une utilisation appropriée de l'API Calendar, un mécanisme de filtrage et de mise en cache, l'export des événements historiques vers une ressource pour le testeur et la bascule automatique entre les modes Live et Tester — afin que le même code produise des résultats déterministes à la fois en temps réel et avec des données historiques.

Principaux problèmes du trader

Fig. 1 : le principal problème d'un trader manuel est la fragmentation des outils.


Le trading manuel sur actualités est obsolète

Premièrement, une stratégie de trading sur actualités qui dépend de facteurs externes ne peut pas être testée. Une grande part du succès en trading repose sur l’évaluation historique de la stratégie. L'impossibilité de tester une stratégie engendre une subjectivité dans les décisions prises. La stratégie restera au stade de l’hypothèse, et vous passerez beaucoup de temps – des mois, voire des années – à la tester.

Deuxièmement, il est très difficile de développer le trading manuel à grande échelle. Essayez de développer une entreprise instable et générant des bénéfices irréguliers. L'étendre ne fera qu'aggraver les problèmes. Sans structure claire, sans systématisation ni optimisation, toute tentative de l’industrialiser est vouée à l’échec.

Troisièmement, les délais de réaction aux actualités constituent un problème majeur du trading manuel. Imaginez que vous êtes un trader FOREX et que vous tradez la publication des Non-Farm Payrolls (NFP). Les données NFP sont généralement publiées une fois par mois. Vous avez été distrait et avez manqué la publication du NFP, perdant ainsi une opportunité de gain. Il s'agit d'une situation familière pour de nombreux traders.

Conclusion : l'automatisation est la seule voie vers un trading d'actualités reproductible.

Comparaison des réactions

Fig. 2 : un robot est toujours plus rapide


Calendrier Économique intégré à MetaTrader 5 : une source d’informations unique

Pour faire du trading sur actualités un processus algorithmique — et donc rendre les tests historiques possibles — utilisez le produit unique de notre société : un Calendrier Économique intégré à MetaTrader 5 avec accès aux actualités via l'API MQL5. C’est ce qui transformera votre trading d’actualités, en le faisant passer de l’improvisation à un processus algorithmique vérifiable. Les événements actuels en temps réel et les événements historiques sont disponibles pour les tests hors ligne.

Tableau 1 :

ce qui rend le calendrier intégré à MetaTrader 5 unique :

Paramètre
Vitesse d'accès
<100 ms — une fois les données du calendrier chargées dans le terminal
Intégration Natif — au niveau du noyau du terminal + API MQL
Test Entièrement pris en charge - après téléchargement des actualités dans le terminal (accès dans le testeur via les fichiers, les ressources ou SQLite)
Fiabilité Haute

MetaTrader 5 dispose d'un excellent testeur de stratégie : rapide, multi-actifs et capable d'utiliser des ordinateurs sur des réseaux locaux et mondiaux pour les tests et l'optimisation. Essayez d'exécuter votre système de trading d'actualités sur des données historiques. Cela pourrait améliorer votre approche de trading.


Fonctions du Calendrier Économique de MetaTrader 5 : Présentation de l'API MQL5

La transition de l'analyse manuelle à l'analyse algorithmique commence par la compréhension de l'architecture des données. En MQL5, le Calendrier Économique n'est pas simplement un tableau, mais une base de données structurée accessible via une API native. Nous verrons comment interroger correctement les événements, la différence entre événement et valeur, et pourquoi la synchronisation temporelle est essentielle à la réussite d'une stratégie.

Le cœur du calendrier MQL5 se compose de plusieurs fonctions clés, chacune ayant un rôle spécifique. Il est important de comprendre qu'il n'existe pas de fonction universelle permettant de fournir simultanément toutes les données du Calendrier Économique. Il faut donc combiner plusieurs fonctions.

  • CalendarValueHistory — l’outil principal pour le chargement initial. Cette fonction permet d'obtenir un tableau de valeurs d'événements pour un intervalle de temps spécifié. Il s'agit de « l'artillerie lourde » utilisée lors de l'initialisation de l'EA pour remplir le cache avec des données historiques ou des données pour la semaine à venir.
  • CalendarValueLast — la fonction principale pour les EA fonctionnant en temps réel. Elle renvoie uniquement les valeurs modifiées ou nouvelles depuis la dernière requête (via le mécanisme change_id). Cela permet d'économiser du trafic et des ressources serveur en évitant de demander l'intégralité du tableau de données à chaque tick.
  • CalendarEventByCountry — retourne la description de tous les événements associés à un pays donné. Cette fonction renvoie une liste de descriptions d'événements pour un pays spécifique spécifié par code selon la norme ISO 3166-1 alpha-2. Elle est nécessaire pour créer des filtres (par exemple, afficher uniquement les événements pour « US » (États-Unis), « RU » (Russie), « CA » (Canada), etc.).
  • CalendarEventByCurrency — retourne la description de tous les événements par devise. Cette fonction renvoie une liste de descriptions d'événements pour une devise spécifique spécifiée par code (« USD », « EUR », etc.).
  • CalendarCountryById — retourne les propriétés du pays par « id ».
  • CalendarEventById — retourne les propriétés de l'événement par « id ».
  • CalendarValueById — retourne une valeur spécifique par « id ».

Structures de données : que renvoie l'API MQL5 Calendar ?

Toutes les fonctions de l'API du Calendrier Économique renvoient soit un tableau de structures, soit une variable contenant une seule structure. Énumérons ici l'ensemble des structures et de leurs champs.

Descriptions des événements - utilisées dans les fonctions CalendarEventById, CalendarEventByCountry et 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)
  };


Descriptions des pays — utilisées dans les fonctions CalendarCountryById et 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
  };


Valeurs des événements - utilisées dans les fonctions CalendarValueById, CalendarValueHistoryByEvent, CalendarValueHistory, CalendarValueLastByEvent et 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
  };

Note :

Notez que la structure MqlCalendarValue fournit des méthodes pour vérifier et obtenir les valeurs des champs actual_value, forecast_value, prev_value et revised_prev_value. Les champs listés peuvent ne pas avoir de valeurs ; par exemple, le champ actual_value peut être vide car l’indicateur n’a pas encore été publié. La meilleure façon d'obtenir les valeurs est d'effectuer la vérification et d'obtenir les valeurs en utilisant les méthodes de la structure elle-même.

Les structures sont liées entre elles par les relations suivantes :

Relations du calendrier

Fig. 3 : relations entre les structures du calendrier


La structure MqlCalendarCountry est liée à MqlCalendarEvent via un identifiant de pays. La forme de la relation est « un à plusieurs » (1..*).

La structure MqlCalendarEvent est liée à MqlCalendarValue via un ID d'événement. La forme de la relation est « un à plusieurs » (1..*).


Heure de publication de l'actualité et heure du serveur

Toutes les fonctions permettant de travailler avec le Calendrier Économique utilisent l'heure du serveur de trading TimeTradeServer(). Cela signifie que l'heure dans la structure MqlCalendarValue et les entrées temporelles dans les fonctions CalendarValueHistoryByEvent()et CalendarValueHistory() sont définies dans le fuseau horaire du serveur de trading, plutôt que dans l'heure locale de l'utilisateur.

Aucune conversion n'est nécessaire : les valeurs temporelles, telle que l'heure de l'événement dans MqlCalendarValue::period, peuvent être comparées directement à l'heure renvoyée par TimeCurrent() ou TimeTradeServer(). Dans le testeur, la fonction TimeTradeServer() renvoie une heure simulée identique à celle des données historiques. La logique de fonctionnement avec les fenêtres temporelles (« 30 minutes avant les actualités ») fonctionne de la même manière en temps réel et dans l'historique. Si le courtier tient compte du passage à l'heure d'été/d'hiver, le calendrier s'ajuste automatiquement à ce changement.


Exemple pratique — obtenir la liste des événements du jour (aujourd'hui) :

//+------------------------------------------------------------------+
//| 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);
     }
   }
 }
//+------------------------------------------------------------------+

Cette fonction affiche une liste des événements en devise USD pour la journée en cours ainsi que le contenu des principaux champs des structures récupérées via l'API MQL5 Calendar. Le code complet du script est joint à l’article, dans le fichier GetTodayEvents-S.mq5.

Les résultats de l'exécution de cette fonction peuvent être consultés dans l'onglet Boîte à Outils\Experts du terminal MetaTrader 5. Nous constatons que deux événements ont été reçus pour l’USD. Au moment de la demande, ces événements ne s'étaient pas encore produits (la statistique n'avait pas encore été diffusée). Par conséquent, le champ MqlCalendarValue::actual_value ne contient pas de valeur — la fonction HasActualValue() renvoie 'false'.

Pour ces types d'événements, le champ MqlCalendarValue::forecast_value vérifié par HasForecastValue() est absent (ne contient aucune valeur). Pour d'autres événements, les quatre champs (prev_value, actual_value, forecast_value et revised_prev_value) peuvent être manquants.

  Received events for 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

Explications du code fourni :

Tout d'abord, nous obtenons un tableau de valeurs pour tous les événements dans une plage horaire donnée avec le filtre de devise « USD ». Dans une boucle, nous parcourons le tableau de valeurs et demandons la description de l'événement par l'ID d'événement MqlCalendarValue::event_id en utilisant la fonction CalendarEventById(). Ensuite, nous demandons une description du pays par son identifiant MqlCalendarEvent::country_id en utilisant la fonction CalendarCountryById().

Si la fonction CalendarValueHistory() renvoie « false », mais que GetLastError() renvoie zéro (aucune erreur), cela indique qu'il n'y a pas d'événements avec les paramètres demandés.


Gestion des erreurs et limites lors de l'utilisation du calendrier

Travailler avec des données distantes comporte toujours un risque d'interruptions de connexion ou de restrictions d'accès. Les fonctions de calendrier renvoient la valeur « false » ou 0 en cas d'échec. Pour comprendre la raison, il est nécessaire d'utiliser GetLastError(). La documentation met en évidence un groupe d'erreurs distinct pour le module calendrier.

Codes d'erreur :

  • ERR_CALENDAR_TIMEOUT (code 5200) — le délai d'attente de la réponse du serveur a expiré. Panne de réseau ou surcharge du serveur. Solution : Répétez la demande après une pause de 5 à 10 secondes.
  • ERR_CALENDAR_NO_DATA (code 5201) — les données du calendrier n'ont pas encore été chargées. Le calendrier est initialisé de manière asynchrone. Solution : Attendez 1 à 2 secondes et répétez la demande.
  • ERR_CALENDAR_INVALID_DATE (code 5202) — plage de dates invalide. Erreur de code (par exemple, la date de début est postérieure à la date de fin). Solution : Corrigez la logique, répéter la demande est inutile.
  • ERR_CALENDAR_INVALID_COUNTRY (code 5203) — code pays/devise inconnu. Erreur dans les paramètres de la requête. Solution : Vérifiez le code (par exemple, « US » au lieu de « USA »).
  • ERR_CALENDAR_TOO_MANY_REQUESTS (code 5204) — limite de requêtes dépassée. Erreur critique. Solution : Augmentez l'intervalle entre les requêtes.

Limitation du taux de requêtes :

Les serveurs auxquels se connecte le terminal MetaTrader 5 protègent l'infrastructure contre la surcharge. Si l'EA appelle CalendarValueHistory() à chaque tick ou dans une boucle sans délai, le serveur renvoie l'erreur 5204 et bloque temporairement l'accès au calendrier pour votre terminal. Meilleure pratique : charger les données une seule fois au démarrage dans OnInit() pour la période requise.

Pour les mises à jour en temps réel, utilisez CalendarValueLast() tout en stockant la variable change_id renvoyée — cela permet de recevoir uniquement les modifications, plutôt que l'ensemble du tableau de données. Mettez à jour les données via une minuterie dans OnTimer() à des intervalles de 5 à 10 minutes maximum.

Examinons quelques exemples de solutions aux problèmes pouvant survenir lors du chargement d'un calendrier :

Lorsque vous démarrez le terminal (démarrage à froid) et l'EA, le calendrier n'est pas immédiatement prêt. Les données sont chargées depuis le serveur en arrière-plan. Si nous appelons la fonction CalendarValueHistory() dans la toute première ligne de OnInit(), vous obtiendrez très probablement l'erreur 5201 — aucune donnée. Il est nécessaire de mettre en œuvre un mécanisme de vérification de disponibilité avec un délai d'expiration exponentiel ou fixe.

Exemple pratique — fonction de chargement de données de calendrier avec gestion des erreurs :

//+------------------------------------------------------------------+
//| 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;
 }
//+------------------------------------------------------------------+

Explications du code fourni :

Tenez compte de la possibilité d'erreurs « Aucune donnée » (5201) et « Délai d'attente dépassé » (5200). Ce sont des erreurs corrigibles. Gérez-les en faisant une pause de 1 à 5 secondes et en demandant à nouveau les données. En cas d'erreurs irrécupérables, arrêtez immédiatement le téléchargement. Les erreurs irrécupérables comprennent les dates invalides, les codes de devise ou de pays incorrects, etc. Vous trouverez le code source complet du script dans le fichier GetTodayEvents-S.mq5 joint à cet article.


Pour éviter les limites et garantir une vitesse de réaction maximale, dans OnTimer(), nous devrions utiliser le mécanisme change_id. Au démarrage, chargez l'historique complet des événements et mémorisez le dernier change_id. Dans le minuteur, ne demandez que de nouvelles données à l'aide de la fonction CalendarValueLast(). Le serveur ne renverra que les données modifiées (ou « false » s'il n'y a pas de modifications), sans gaspiller de ressources à transmettre d'anciennes données.

Exemple pratique — fonction de mise à jour des données du calendrier avec gestion des erreurs :

//+------------------------------------------------------------------+
//| 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++;
     }
   }
 }
//+------------------------------------------------------------------+

Explications du code donné :

La mise à jour incrémentale des événements s'effectue via le gestionnaire d'événements du minuteur OnTimer(). La fonction CalendarValueLast() de l'API Calendar est appelée : si de nouveaux événements apparaissent, les éléments correspondants dans le tableau de structures MqlCalendarValue précédemment chargé sont mis à jour et les données sont écrites dans le journal du terminal. Si un événement n'est pas trouvé dans le tableau chargé, il y est ajouté.

Le code complet du script se trouve dans le fichier CalendarEventMonitor-EA.mq5, joint à l'article.


Filtrage des événements : du général au spécifique

Pourquoi filtrer :

Le Calendrier Économique publie quotidiennement entre 60 et 90 événements. C'est comme écouter un flot continu de centaines d'indicateurs mineurs, de fermeture des marchés et de discours officiels qui n'ont aucun impact immédiat sur le marché. Trader sur chacun de ces évènements est un moyen infaillible de multiplier inutilement les opérations et de perdre son dépôt. La tâche d'un trader algorithmique spécialisé dans l'actualité est de ne retenir que 3 à 5 événements qui influencent réellement le marché.

Le filtrage dans le trading algorithmique d'actualités équivaut à augmenter le rapport signal/bruit à un niveau adapté à la prise de décision automatisée. Dans l'API MQL5 Calendar, ce processus est implémenté comme un système de filtre à plusieurs niveaux à travers lequel passent les tableaux de structures MqlCalendarEvent et MqlCalendarValue.

Critères de filtrage :

Le marché ne réagit pas à l'annonce elle-même, mais à l'écart entre les données réelles et les prévisions, ainsi qu'au niveau d'influence macroéconomique. Les événements à faible impact (MqlCalendarValue::impact_type < 3) sont souvent ignorés par les algorithmes de trading et les teneurs de marché.

Sans filtrage, vous obtenez :

  • des déclenchements erronés de la stratégie sur des actualités secondaires ;
  • des opérations exécutées pendant des périodes de spread large sans volatilité réelle ;
  • une surcharge de la logique de l'EA avec des vérifications inutiles.

L'objectif du filtrage est de réduire le flux de données de 90%, ne laissant que les événements à fort impact (ENUM_CALENDAR_EVENT_IMPORTANCE::CALENDAR_IMPORTANCE_HIGH) pour la devise cible sélectionnée par le trader dans une fenêtre temporelle donnée. 

Voyons comment construire un filtre fiable qui fonctionnera de manière tout aussi fiable en temps réel qu'en mode test.

Système de filtration à plusieurs niveaux :

Les données d'événements « brutes » téléchargées depuis le terminal sont comme du minerai non traité : elles contiennent des milliers d'entrées, allant de rapports statistiques insignifiants à des jours fériés qui n'apportent aucun avantage à la stratégie algorithmique.

Pour transformer ce flux de données en un signal propre, nous avons besoin d'un système de filtrage à plusieurs niveaux. Le filtrage des événements agit comme un « tamis » à travers lequel passent les données brutes, ne laissant en sortie que les événements qui répondent aux critères spécifiés : devise, importance, code et fenêtre temporelle.

Un filtre efficace doit avoir une structure hiérarchique : partant d’une coupure initiale approximative par zone géographique et se terminant par un réglage fin par fenêtre temporelle.

Une caractéristique importante de l’API MQL5 Calendar : la structure MqlCalendarValue ne contient pas les champs currency_id et country_id. Elle ne stocke que l’identifiant de l'événement, l'heure, les valeurs de l'indicateur et le type d'influence. Quel est l'impact sur la filtration ?

Le filtrage des devises est effectué au niveau de la requête API. Lorsque vous appelez CalendarValueHistory(..., NULL, "USD"), le terminal lui-même ignore tout sauf USD. Le tableau que vous recevez est déjà filtré par devise. Il n'est donc pas nécessaire de vérifier currency_id en temps réel ; il suffit de filtrer par date, importance et la présence d’une prévision et, le cas échéant, sa pertinence.

Niveau 1 : Filtre de devises

Le premier critère est la zone géographique concernée par l’événement. Lors du trading de l'EUR/USD, l'EA ne doit réagir qu'aux événements qui affectent la zone euro (EUR) et les États-Unis (USD). Le filtrage consiste à demander des événements avec les codes de devise de l'instrument négocié. Pour les paires croisées (par exemple "GBPJPY"), nous devons demander des événements pour les deux devises ("GBP" et "JPY") et "USD".

Niveau 2 : Importance de l'événement

Chaque évènement macro-économique a une importance variable en termes d'impact sur l'économie — et notamment sur les prix. L'indice des prix à la consommation (IPC) peut faire varier le marché de 100 points, tandis que l'indice de confiance des consommateurs ZEW ne peut le faire varier que de 10 points.

L'API MQL5 utilise l'énumération ENUM_CALENDAR_EVENT_IMPORTANCE pour définir le degré d'importance :

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
};

Les EA d'actualités doivent ignorer tout ce qui est inférieur à HIGH afin d'éviter les faux positifs sur les actualités à faible liquidité.

Niveau 3 : Code d'événement

Même parmi les événements de grande importance, il existe des exceptions. Par exemple, un discours de la BCE ou du FMI peut être jugé important, mais son traitement algorithmique est plus complexe que celui de la publication de chiffres précis. Il nous faut donc trier par code d'événement : Le champ event_code de MqlCalendarEvent contient un identifiant unique (par exemple, « NONFARM », « CPI », « GDP »). Nous sélectionnons uniquement les événements comportant des données économiques, et non les sondages et les discours.

Ce n'est qu'après avoir passé les trois premiers niveaux de vérification que l'événement est copié dans le tableau résultant et utilisé pour les transactions.

Niveaux de filtrage

Fig. 4 : le filtrage à plusieurs niveaux est la clé du succès dans le trading d'actualités.

Après les trois premiers niveaux de filtrage, l'EA vérifie si l'événement se situe dans la fenêtre temporelle configurée. Cela se produit pendant l'exécution du robot de trading.

Niveau 4 : Période

La dernière étape consiste à vérifier la pertinence. Nous n'avons pas besoin d'actualités qui paraîtront dans un mois. Celle parue hier a déjà été intégrée par le marché. Par conséquent, un événement est considéré comme actif si TimeCurrent() tombe dans l'intervalle : le temps spécifié avant la publication de l'actualité et le temps spécifié après la publication. En général, les paramètres suivants sont utilisés : 15 à 30 minutes avant la sortie – pour réduire ou fermer les positions, et 60 minutes après – pour analyser la volatilité et la direction des mouvements de prix.


Ressources binaires MQL5 : déplacer les événements vers des tests hors ligne pour une mise en cache efficace

Un problème lié aux tests dans le cadre du trading algorithmique basé sur l'actualité est que le Testeur de Stratégie n'a pas accès à Internet. Cette solution accélère les tests et réduit l’influence des facteurs non déterministes, mais elle pose un problème pour les tests de stratégies basées sur l'actualité.

Si l'EA dans le testeur appelle la fonction CalendarValueHistory(), il obtient une erreur et un tableau vide. Pour tester cette stratégie, nous devons intégrer des données d'actualités historiques dans le fichier exécutable .ex5. Pour cela, nous utilisons l'option avec les ressources binaires MQL5. Pourquoi cette option en particulier ? C'est la méthode la plus rapide pour accéder aux données structurées ; la vitesse d'accès n'est limitée que par les performances du système de fichiers de l'ordinateur.

Voyons comment transformer le tableau MqlCalendarValue[] en un fichier binaire compact et comment l'intégrer au code afin que le testeur lise les données de la RAM très rapidement. La première étape consiste à créer un script d'export qui téléchargera les données actuelles du calendrier et les enregistrera dans un fichier binaire.

Exemple pratique — un script pour exporter des événements vers un fichier binaire :

Le code complet du script se trouve dans le fichier ExportCalendarForTester.mq5 joint à l'article.


Étape 1 : assemblage et filtrage du tableau

Nous ne stockerons pas tous les événements mondiaux dans la ressource. Lors de l'export vers un fichier binaire, nous appliquons les mêmes filtres que dans l'EA : devise, importance et type d'événement. Les paramètres du script spécifient la liste des devises, l'intervalle de temps pour le chargement des événements, les codes d'événements et l'importance minimale.

La liste des codes d'événements (paramètre InpEventCodes) est vide par défaut ; cela signifie que tous les types d'événements sont chargés. Nous pouvons affiner ce filtre. Par exemple, uniquement les « non-farm payrolls » - la liste des codes sera alors « NONFARM ».

L'indicateur InpUseCommonDir spécifie où enregistrer le fichier binaire : true — enregistrer dans le dossier partagé commun à tous les terminaux clients « \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 partie du script qui charge et filtre les événements en fonction des valeurs spécifiées dans les entrées est présentée ci-dessous :

  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
       }
     }
   }

Explications du code fourni :

  • Le tableau values_size[] stocke le nombre d'événements filtrés pour chaque code de devise spécifié dans les entrées.
  • La valeur zéro du type datetime MQL5 correspond à la date du 1970.01.01 00:00:00.
  • Un filtrage supplémentaire est effectué par type d'événement. Seuls les évènements de type ENUM_CALENDAR_EVENT_TYPE::CALENDAR_TYPE_INDICATOR sont retenus — ce sont des événements économiques (pas des discours, mais des chiffres). Toutes les autres actualités sont supprimées. Cela se fait par validation dès le début du filtrage :
//--- take only indicators
if(event.type != CALENDAR_TYPE_INDICATOR)
  continue;                                   // Nothing else to filter


Exécutons le script avec différents ensembles de paramètres de filtrage et voyons à quelle vitesse fonctionne le script de chargement/filtrage des événements. Il est clair que la vitesse dépend de la puissance de l'ordinateur et de la vitesse de connexion aux serveurs de données via Internet. Néanmoins, nous allons effectuer un test de charge. Les résultats sont présentés ci-dessous.

Tous les événements possibles en dollars américains d'une importance haute — sur l’ensemble de l’historique disponible :

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 bytes  (9009 events)

Temps d'obtention du tableau de valeurs filtrées (structures MqlCalendarValue) : 1,80 sec (0,20 ms / par filtration).


Tous les évènements possibles sur les devises USD, EUR et JPY d'importance haute — sur l’ensemble de l’historique disponible :

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)

Temps d'obtention du tableau de valeurs filtrées (structures MqlCalendarValue) : 2,68 sec (0,24 ms / par filtration).


Événements NFP (« non agricoles ») par USD d'importance haute — sur l’ensemble de l’historique disponible :

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)

Temps d'obtention du tableau de valeurs filtrées (structures MqlCalendarValue) : 0,09 sec (0,18 ms / par filtration).

Remarques :

  1. Il n'est pas nécessaire de spécifier l'intégralité du code d'événement dans le filtre. Il suffit de spécifier une partie unique de la chaîne contenant le code. Par exemple, pour les « emplois non-agricoles », le code complet est « NONFARM-PAYROLLS » — spécifier « NONFARM » suffit.
  2. Lors de l'exécution d'un système de trading en temps réel dans le terminal MetaTrader 5, il est peu probable que nous ayons besoin de télécharger tous les événements pour toute la période. En règle générale, les actualités sont téléchargées pour la journée et la semaine à venir. Par conséquent, le temps de chargement dans l'algorithme de l’EA d'actualités peut être négligé.


Étape 2 : exporter le tableau d'événements vers un fichier binaire

La fonction SaveToBinary enregistre les événements filtrés dans un fichier binaire. Le nombre de fichiers est égal au nombre de codes de devise spécifiés dans les entrées ; chaque devise est exportée dans son propre fichier binaire. Le nom du fichier commence par le préfixe du code de devise. Par exemple, « USD_calendar_test_res.bin ». De cette manière, nous obtenons une correspondance directe entre le code de la devise et la liste des événements associés.

//+------------------------------------------------------------------+
//| 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];
   }
 }

Après l'exécution réussie du script d'export des événements vers des fichiers binaires, des messages comme le suivant apparaissent dans l'onglet Experts de MetaTrader 5 :

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)


Étape 3 : compiler la ressource dans l'EA

Après avoir lancé le script ExportCalendarForTester.mq5 dans MQL5/Files/, les fichiers USD_calendar_test_res.bin et EUR_calendar_test_res.bin apparaissent. Il faut maintenant les « intégrer » à l'EA. Au début du fichier de l’EA (après les directives #property), ajoutez une (si vous utilisez un fichier pour une seule devise) ou plusieurs lignes du type suivant :

// 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[]

Note :

  1. Le chemin d'accès à #resource est spécifié par rapport au dossier MQL5/Files/. Le préfixe \\Files\\ est obligatoire.
  2. Lors de la compilation de l'EA, des messages comme les suivants devraient apparaître dans l'onglet Erreurs de MetaEditor :
  • '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]' 

Lors du démarrage de l'EA, les structures des événements enregistrés pendant la phase d'export sont stockées dans les tableaux USD_res_calendar_data[] et EUR_res_calendar_data[].


Intégration dans l'EA : changement de mode automatique

L'objectif est de faire fonctionner le même code de l’EA à la fois en temps réel et dans l'environnement de test, en sélectionnant automatiquement la source de données. La fonction MQLInfoInteger(MQL_TESTER) renvoie 'true' si l'EA est en cours d'exécution dans le Testeur de Stratégie ou dans l'Optimiseur.

//+------------------------------------------------------------------+
//| 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;
 }


Explications du code fourni :

La vérification principale est effectuée dans le gestionnaire d'événements d'initialisation 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())
       {
        ...
       }
    }

Explications du code fourni :

Nous déterminons dans quel mode fonctionne le programme MQL5 en cours d'exécution (ici, notre EA). Nous nous intéressons aux drapeaux suivants :

  • MQL_TESTER — indicateur du programme lancé s'exécutant dans le testeur ;
  • MQL_OPTIMIZATION — indicateur du programme lancé pendant l'optimisation ;
  • MQL_VISUAL_MODE — indicateur du programme lancé en mode de test visuel.
Si au moins un de ces indicateurs est actif, alors nous chargeons la liste des événements à partir de la ressource. Sinon, nous chargeons la liste des événements de manière classique depuis le serveur via l'API Calendar.


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)



Validation de la chaîne de transformation des données : Événements → Fichier binaire → Compilation sous forme de ressource → Récupération des événements de la ressource

Il ne reste plus qu'à vérifier la récupération des événements dans l'environnement de test et à s'assurer qu'ils correspondent parfaitement à la liste reçue en temps réel. Cela confirmera la possibilité de tester et d'optimiser automatiquement les algorithmes de trading d'actualités.

Pour ce faire, ajoutez la sortie des événements reçus du serveur/téléchargés depuis la ressource au journal du terminal/testeur de stratégie. Le fichier texte complet ImportTesterLog.txt contenant les résultats de l'exécution du test est joint ci-dessous. Ci-dessous figure un extrait du fichier journal : le début et la fin du tableau d’événements pour chaque code de devise.

Résultat d'une exécution unique dans le Testeur de Stratégie, en mode visuel :

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)

Il est clair que tous les tableaux d'événements ont été chargés à partir de la ressource en environ 10 ms, ce qui n'est pas surprenant : la ressource est intégrée au code de l'EA et se charge en même temps que lui au démarrage des tests.

Le lancement du même Expert Advisor en mode Live dans le terminal MetaTrader 5 produit un fichier journal similaire avec une liste d'événements chargés. Le fichier LoadLiveLog.txt complet contenant les résultats du chargement en direct est joint à l'article. Ci-dessous figure un extrait du fichier journal : le début et la fin du tableau d’événements pour chaque code de devise.

Résultats du téléchargement en direct des événements depuis le serveur :

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 chargement complet avec filtrage et écriture dans le journal prend environ 50 ms, ce qui est encore suffisamment rapide pour ignorer le temps de téléchargement/filtrage des événements. En comparant les deux fichiers journaux, on constate que la liste des événements est parfaitement identique, tant en termes de nombre d'événements que de valeur des champs. La validation de la chaîne de transformation des données s'est terminée avec succès.

Analyse des erreurs typiques et des fausses attentes

Examinons les six erreurs les plus courantes commises par les développeurs lors de l'intégration du Calendrier Économique MQL5. Chacune de ces erreurs a été observée en conditions réelles et pourrait coûter très cher au trader, voire conduire à la perte du capital.

1. « Le calendrier prédit la direction du marché »

Fausse attente :

Si une actualité d'une importance capitale est publiée et que le résultat réel diffère sensiblement des prévisions, le prix évoluera forcément dans le sens de l'écart. Achetez simplement si la valeur publiée est supérieure aux prévisions pour la devise de base.

Réalité :

Le Calendrier Économique est une source de données, et non un générateur de signaux de trading. Il vous indique ce qui s'est passé, mais pas comment le marché va réagir. Pourquoi le prix pourrait-il aller à l'encontre d'une logique « évidente » ?

  • Le marché avait déjà intégré les anticipations plusieurs jours avant la publication de l’actualité. Au moment même où l'actualité est diffusée, la « vente de l'actualité » a lieu.
  • Des données inflationnistes solides pendant une période de resserrement de la politique monétaire des banques centrales peuvent renforcer la monnaie, mais pendant une période d'assouplissement, elles peuvent déclencher une vague de ventes par crainte de surchauffe.
  • La statistique publiée peut être bonne, mais si la valeur précédente est révisée à la baisse, le signal global devient ambigu.
  • La publication simultanée de données pour plusieurs devises crée des effets croisés qui ne peuvent pas être interprétés de manière linéaire.

La bonne approche consiste à utiliser le calendrier comme filtre de volatilité, et non comme déclencheur d'entrée :

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

//--- use:
if(IsHighImpactNewsComingSoon(30)) 
 {
   //--- reduce the position size or temporarily suspend trading
   ReduceRiskExposure();
 }
Règle d'or : Le calendrier répond à la question « Quand faut-il s'attendre à une volatilité accrue ? », et non à la question « Dans quelle direction trader ? »


2. « Tous les événements HIGH sont d'égale importance »

Fausse attente :

Le champ importance == CALENDAR_IMPORTANCE_HIGH signifie que l'événement est garanti de faire bouger le marché de plus de 50 pips. Nous pouvons exploiter toutes ces actualités en utilisant le même algorithme.

Réalité :

Les valeurs spécifiques de l'énumération ENUM_CALENDAR_EVENT_IMPORTANCE sont une évaluation subjective des éditeurs du calendrier, et non une mesure quantitative de l'impact sur le marché. Prenons par exemple deux événements dont l’importance est qualifiée de HAUTE, mais ayant une importance différente sur le marché.

Le premier événement, les créations d'emplois non agricoles (États-Unis), produit une réaction de volatilité de 80 à 150 points, car il s'agit d'un indicateur clé de l'emploi et il influence la politique de la Fed. Le deuxième événement, l'indice PMI manufacturier (zone euro), donne une réponse de 10 à 30 points, puisqu'il s'agit d'un indicateur sectoriel restreint et qu'il est secondaire pour la BCE.

La bonne approche consiste à compléter le filtrage par importance par une liste de codes d'événements prioritaires :

//--- 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
 }

Recommandation :

Créez votre propre classement des événements basé sur l'analyse de la volatilité historique — plus fiable que n'importe quelle étiquette prédéfinie.


3. « Utilisation de TimeLocal() au lieu de TimeTradeServer() »

Fausse attente :

L'heure de l'événement dans la structure MqlCalendarValue::time est spécifiée dans mon fuseau horaire local (ou UTC), je peux donc la comparer avec TimeLocal() ou TimeGMT().

Réalité :

Toutes les fonctions du Calendrier Économique renvoient l'heure dans le fuseau horaire du serveur de trading (TimeTradeServer()). Il s'agit d'un choix architectural qui élimine le besoin de conversion manuelle, mais qui exige de la rigueur de la part du développeur.

Les conséquences de cette erreur sont graves : si votre serveur se trouve dans le fuseau horaire EET (UTC+2) et que vous utilisez TimeLocal() (par exemple MSK, UTC+3), vous vérifierez des événements avec un décalage d'une heure. L'EA peut manquer la publication de l'actualité ou, à l'inverse, y réagir après coup.

La bonne approche consiste à toujours utiliser TimeTradeServer() pour toutes les comparaisons de temps :

//--- 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

Recommandation :

Ajoutez la sortie de TimeToString(TimeTradeServer(), TIME_MINUTES) au journal de débogage et comparez-la avec l'heure de l'événement - elles devraient correspondre sans conversion.


4. « J'ai oublié que les champs d'événement peuvent être vides »

Fausse attente :

Les champs actual_value, forecast_value et autres contiennent toujours des valeurs numériques correctes. Nous pouvons les diviser sans risque par 1 000 000 et comparer.

Réalité :

Selon la documentation, les champs numériques de la structure MqlCalendarValue stockent des valeurs multipliées par un million ou par la constante LONG_MIN si aucune valeur n'est spécifiée. Que se passe-t-il si nous ignorons la vérification :

//--- 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();

La bonne approche consiste à utiliser les méthodes intégrées de la structure MqlCalendarValue pour obtenir des valeurs en toute sécurité :

//--- 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
   }
 }
//+------------------------------------------------------------------+

Note :

Les fonctions GetActualValue(), GetForecastValue() et autres renvoient NaN s'il n'y a pas de données. Vérifiez toujours le résultat via MathIsValidNumber() ou MathIsNaN() avant de l'utiliser dans des calculs.


5. « Appeler les fonctions de l'API Calendar dans OnTick() »

Fausse attente :

Pour avoir toujours des données à jour, j'appellerai CalendarValueHistory() à chaque tick. Cela permet à l'EA de ne manquer aucune actualité importante.

Réalité :

Les fonctions du calendrier fonctionnent via un serveur distant auquel MetaTrader 5 se connecte, et sont soumises à des limites strictes en termes de débit de requêtes. L'appel à OnTick() (qui peut se déclencher des dizaines de fois par seconde) entraînera des problèmes :

  • Erreur 5204 (ERR_CALENDAR_TOO_MANY_REQUESTS) — blocage temporaire de l'accès au calendrier.
  • Retards d'exécution - une requête réseau dans le cycle de trading augmente le glissement.
  • Trafic excessif – téléchargement répété des mêmes données.
La solution correcte consiste à utiliser la mise en cache et l'actualisation incrémentale :
//--- 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);
 }

Recommandation :

La fonction OnTick() ne devrait fonctionner qu'avec des données locales. Requêtes réseau - uniquement dans OnInit(), OnTimer() ou par événement utilisateur.


6. « J'ai oublié de recompiler l'expert pour tester sur de nouveaux événements »

Fausse attente :

J'ai mis à jour le fichier de ressources calendar_test_res.bin dans le dossier Files ; le testeur verra désormais automatiquement les nouveaux événements. Il n'est pas nécessaire de recompiler l'EA.

Réalité :

La directive #resource intègre des données dans le fichier exécutable .ex5 au moment de la compilation. Les modifications apportées au fichier .bin externe ne sont pas prises en compte dynamiquement ; l’EA continue d’utiliser la version de la ressource compilée au moment de la compilation.

Symptômes d'erreur :

  • Le journal du testeur n'inclut pas les événements ajoutés à la ressource après la dernière compilation.
  • La stratégie « ne voit pas » les actualités importantes, même si elles figurent dans le dossier.
  • Les résultats des tests diffèrent des attentes, bien que le code soit logiquement correct.

La bonne approche consiste à toujours recompiler l'EA après la mise à jour de la ressource :

//--- 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.

Recommandation :

Ajoutez la sortie de version de la ressource (par exemple, le hachage ou la date de dernière mise à jour) au journal de compilation pour surveiller visuellement la pertinence des données dans .ex5.

Remarques :

Les erreurs évoquées dans cette section ne proviennent pas d'un manque de connaissance de la syntaxe MQL5, mais d'une compréhension simplifiée de la nature des données économiques (indicateurs). Quiconque apprend à éviter ces six erreurs obtiendra non seulement un code fonctionnel, mais aussi un système de trading stable, capable de s'adapter aux fluctuations du marché et aux exigences des régulateurs économiques. C’est cette approche qui distingue un amateur d’un professionnel du trading algorithmique.


Conclusion

Le Calendrier Économique du terminal MetaTrader 5 est un outil puissant. Mais comme tout outil, il nécessite de comprendre le contexte, la discipline dans son utilisation et de prendre en compte les limitations de la plateforme.

Nous avons envisagé une structure d'implémentation et d'utilisation spécifique pour l'API d'actualités de l'EA dans MetaTrader 5. L'article propose un ensemble d'éléments pratiques qui, pris ensemble, transforment le trading manuel d'actualités en un module reproductible :

  • comprendre l'API Calendar (Événement vs Valeur, structures MqlCalendarEvent/MqlCalendarValue, heure du serveur) ;
  • méthodes de chargement et de mise à jour sécurisées (CalendarValueHistory pour le chargement initial, CalendarValueLast + change_id pour les mises à jour incrémentales) ;
  • gestion des erreurs typiques et respect des limites des requêtes ;
  • filtrage à plusieurs niveau par devise, importance, code d'événement et fenêtres temporelles pour réduire le bruit et ne retenir que 3 à 5 événements significatifs ;
  • un mécanisme d'export des données filtrées vers une ressource binaire et de bascule automatique de la source de données « temps réel » ↔ « Testeur de Stratégie », garantissant un comportement identique en temps réel et lors des backtests.

Critères de préparation du module : les événements de la période spécifiée sont chargés avec succès ; les mises à jour incrémentales fonctionnent via change_id sans dépasser les limites ; dans le Testeur, l’EA lit la ressource et produit les mêmes décisions qu’en conditions réelles avec des données d’entrée identiques.

Étapes suivantes recommandées : implémenter le script d’export, intégrer en dur le fichier .bin dans #resource, tester la logique de mise à jour OnInit/OnTimer et exécuter des backtests contrôlés (par exemple, scénario « ne pas trader pendant 30 minutes / reprendre après 60 minutes »).

Cela vous permettra de passer des hypothèses à un système de trading d'actualités testable et évolutif. Développer des EA de trading sur actualités ne se limite pas à programmer. Il s'agit de construire un pont entre la théorie macroéconomique et la pratique du marché. 

Ressources recommandées pour une étude approfondie des fonctions de l'API Calendar de MetaTrader 5 et de leur utilisation dans le trading d'actualités :


Liste des fichiers joints à l'article :

Nom de fichier Description
CalendarEventMonitor-EA.mq5  Code de test de l’Expert Advisor pour la fonction de mise à jour des données du calendrier
ExportCalendarForTester-S.mq5 Code du script de test permettant de vérifier l'export d'événements avec des filtres spécifiés vers un fichier binaire
GetTodayEvents-S.mq5 Code du script de test permettant de vérifier la récupération des événements du jour.
ImportCalendarValidation-EA.mq5 Code de l’EA de test pour vérifier la récupération des actualités dans le Testeur de Stratégie à partir d'une ressource
ImportTesterLog.txt  Résultats d'une seule exécution de l'EA ImportCalendarValidation-EA.mq5 dans le Testeur en mode visuel
LoadLiveLog.txt  Résultats du chargement en direct des événements dans l'EA ImportCalendarValidation-EA.mq5

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/22196

Derniers commentaires | Aller à la discussion (8)
Stanislav Korotky
Stanislav Korotky | 1 mai 2026 à 13:32

Écrit :

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

Corrigez-moi si quelque chose a changé dans l'API MQL5, mais auparavant, le calendrier s'adaptait au fuseau horaire ACTUEL en tenant compte de l'heure d'été : ainsi, en été, les appels de fonctions renvoyaient des horodatages, par exemple, dans le fuseau UTC+3, tandis qu’une requête portant sur la même période historique en hiver renverrait des événements horodatés dans le fuseau UTC+2, si le serveur effectue le passage à l’heure d’été et inversement. Ainsi, pour exporter avec précision l’historique du calendrier sur une période de six mois ou plus, il est nécessaire d’analyser l’historique des changements de fuseau horaire du courtier. Plus de détails dans la base de code.

De plus, l’approche consistant à mettre en cache le calendrier sous forme de lien vers une ressource semble peu pratique et, en particulier, provoque des erreurs mentionnées dans l’article lui-même (du type : « n’oubliez pas de recompiler l’expert »). Pourquoi ne pas définir le cache du calendrier dans le paramètre d’entrée sous la forme d’un fichier issu du dossier « Common », accessible à tous les agents ?

Maxim Kuznetsov
Maxim Kuznetsov | 3 mai 2026 à 17:44
Corrigez-moi si quelque chose a changé dans l'API MQL5, mais auparavant, le calendrier s'adaptait au fuseau horaire ACTUEL en tenant compte de l'heure d'été : ainsi, en été, les appels de fonctions renvoyaient des horodatages, par exemple, dans le fuseau UTC+3, tandis qu’une requête portant sur le même segment d’historique en hiver renverrait des événements avec des horodatages dans le fuseau UTC+2, si le serveur effectue le passage à l’heure d’été et inversement. Ainsi, pour exporter avec précision l’historique du calendrier sur une période de six mois ou plus, il est nécessaire d’analyser l’historique des conversions часового пояса du courtier. Plus de détails dans la base de code.

Et pourquoi les cotations (et plus généralement tous les horodatages) ne sont-elles pas enregistrées, par exemple, en UTC ?

Pourquoi les ticks des courtiers ont-ils des représentations numériques différentes pour un même repère temporel ?

C'est une question philosophique :-) C'est ainsi que cela s'est fait, même si ce n'est pas correct et que cela engendre des problèmes sans raison.


P.S. C’est pourquoi il vaut mieux puiser les « informations historiques » dans d’autres sources.

Et il ne faut jamais « analyser soi-même l’historique des conversions d’heure » : tout cela existe déjà, c’est une fonctionnalité du système d’exploitation ou, au pire, des bibliothèques système. Cherchez « tzdata » sur Google

Combien de vélos peut-on fabriquer, surtout des vélos tordus ?

fxsaber
fxsaber | 3 mai 2026 à 19:30
Stanislav Korotky #:

Auparavant, le calendrier s'adaptait au fuseau horaire ACTUEL en tenant compte de l'heure d'été ; ainsi, en été, les appels de fonctions renvoyaient des horodatages, par exemple dans le fuseau horaire UTC+3, tandis qu’une requête portant sur la même période historique en hiver renverra des événements horodatés dans le fuseau horaire UTC+2, si le serveur effectue le passage à l’heure d’été et inversement.

C'est exactement ce que j'avais compris.
Stanislav Korotky
Stanislav Korotky | 4 mai 2026 à 16:09
Maxim Kuznetsov #:


P.S. : c'est pourquoi il vaut mieux puiser les « informations historiques » dans d'autres sources.

Et il ne faut jamais « analyser soi-même l'historique des conversions d'horloge » : tout cela existe déjà, c'est une fonction du système d'exploitation ou, tout au plus, des bibliothèques système. Cherchez « tzdata » sur Google.

Combien de vélos peut-on fabriquer, surtout des vélos tordus ?


Les autres sources ne résoudront pas le problème, car celui-ci est ancré dans la manière dont les cotations sont stockées dans MT5.

Commencez par nous montrer votre vélo tout droit, puis donnez-nous des conseils.

ilex044
ilex044 | 11 mai 2026 à 10:09
MetaQuotes:

Les principaux problèmes auxquels est confronté le trader d'actualité moderne sont la fragmentation de ses outils et l'absence d'un processus de trading systématique et algorithmique. Il est en effet assez difficile de partager son attention entre son navigateur Internet (pour consulter les sites d'actualités) et son terminal de trading lorsqu'on effectue des transactions.

Le flux de travail d’un trader réactif aux actualités se présente ainsi : ouvrir rapidement le calendrier des actualités dans son navigateur web et vérifier s’il y a des changements dans les événements → évaluer rapidement les événements à venir et décider quoi et comment trader → se rendre sur le terminal MetaTrader 5 – soit passer des ordres en attente, soit rester devant le terminal et attendre la publication de l’actualité pour prendre une décision. Dans ce scénario, le trader perd souvent le fil de la situation, ce qui entraîne des retards dans sa réaction aux actualités, et donc des pertes.

Souhaitez-vous que le trading sur l’actualité fonctionne comme un problème d’ingénierie — avec des règles claires, des résultats reproductibles et des tests automatisés ? L’objectif de cet article est de présenter l’architecture fonctionnelle d’une couche d’actualités pour MetaTrader 5 : une source de données unique, une utilisation appropriée de l’API du calendrier, un mécanisme de filtrage et de mise en cache, l’exportation des événements historiques vers une ressource pour le testeur, et le basculement automatique entre le mode Live et le mode Tester — afin que le même code produise des résultats déterministes aussi bien en temps réel qu’avec des données historiques.

Oui, c’est un véritable casse-tête pour le trading sur l’actualité.

Passer du navigateur au calendrier puis au terminal brise la concentration et ralentit considérablement les réactions. Disposer d’un flux de travail ou d’un système unifié qui intègre directement les actualités dans l’environnement de trading rendrait sans aucun doute l’exécution plus rapide et plus cohérente.

L’idée d’en faire une configuration structurée et reproductible, de type « ingénierie », avec des tests et de l’automatisation, est en réalité tout à fait pertinente pour éviter les décisions émotionnelles ou tardives.

Du CPU au GPU en MQL5 : un framework OpenCL pratique pour accélérer la recherche, l’optimisation et la détection de motifs Du CPU au GPU en MQL5 : un framework OpenCL pratique pour accélérer la recherche, l’optimisation et la détection de motifs
Découvrez comment construire une approche pratique de migration des calculs du processeur (CPU) vers le processeur graphique (GPU) en MQL5 en utilisant OpenCL. Nous nous concentrerons sur l'initialisation du contexte, l'organisation des buffers, le traitement par lots de grande taille, le lancement du noyau et la minimisation des échanges de données. Les erreurs courantes et les moyens de les éliminer seront également examinés. Un exemple utilisant des figures de chandeliers japonais illustre l'intérêt pratique de cette approche.
Trading algorithmique sans tâches routinières : analyse rapide des opérations dans MetaTrader 5 avec SQLite Trading algorithmique sans tâches routinières : analyse rapide des opérations dans MetaTrader 5 avec SQLite
Cet article présente un socle minimal opérationnel pour la tenue d'un journal de trading en MQL5 en utilisant SQLite : un schéma des tables pour les transactions, les signaux et les événements, des index, des requêtes préparées et des transactions, ainsi que des requêtes SQL d’analyse standard. L'intégration avec le tableau de bord statistique de MetaTrader 5 et l'utilisation de la base de données via MetaEditor sont démontrées. Cette approche permet d'automatiser le journal, d'accélérer les calculs et d'effectuer des analyses sans complexifier le code de l’EA.
L'Histogramme des prix (Profile du Marché) et son implémentation  en MQL5 L'Histogramme des prix (Profile du Marché) et son implémentation en MQL5
Le Profile du Marché a été élaboré par le brillant penseur Peter Steidlmayer. Il a suggéré l’utilisation de la représentation alternative de l'information sur les mouvements de marché « horizontaux » et « verticaux » qui conduit à un ensemble de modèles complètement différent. Il a assumé qu'il existe une impulsion sous-jacente du marché ou un modèle fondamental appelé cycle d'équilibre et de déséquilibre. Dans cet article, j’examinerai l'Histogramme des Prix - un modèle simplifié de profil de marché, et décrirai son implémentation dans MQL5.
Python + MetaTrader 5 : Сadre de recherche rapide pour les données, les variables et les prototypes Python + MetaTrader 5 : Сadre de recherche rapide pour les données, les variables et les prototypes
Cet article démontre comment l'intégration de Python et de MetaTrader 5 combine la flexibilité de la recherche et l'exécution des transactions dans un même flux de travail. Python est utilisé pour l'analyse des données, la sélection des variables et l'entraînement des modèles, et MetaTrader 5 est utilisé pour les tests et l’automatisation du trading. Cette approche simplifie la mise en pratique des solutions, accroît la reproductibilité et rend le développement des systèmes de trading plus rapide et plus structuré.