MetaTrader 5 und der MQL5-Wirtschaftskalender: Wie sich News in ein reproduzierbares Handelssystem umwandeln lassen
Einführung
Die Hauptprobleme des modernen News-Traders sind das fragmentierte Instrumentarium und das Fehlen eines systematischen, algorithmischen Handelsablaufs. Es ist ziemlich schwierig, Ihre Aufmerksamkeit zwischen Ihrem Internetbrowser (Surfen auf Nachrichtenseiten) und Ihrem Handelsterminal aufzuteilen, während Sie Trades eröffnen oder verwalten.
Der Arbeitsablauf eines News-Traders sieht folgendermaßen aus: Öffnen Sie schnell den Nachrichtenkalender in Ihrem Webbrowser und prüfen Sie, ob sich bei den Ereignissen etwas geändert hat → Bewerten Sie schnell die anstehenden Ereignisse und entscheiden Sie, was und wie Sie handeln möchten → Wechseln Sie zum MetaTrader 5-Terminal – platzieren Sie entweder Pending Orders oder warten Sie am Terminal auf die Veröffentlichung der Nachrichten, um eine Entscheidung zu treffen. In diesem Szenario verliert der Händler oft den Kontext, was zu Verzögerungen bei der Reaktion auf Nachrichten führt, was wiederum Verluste zur Folge hat.
Möchten Sie, dass der Handel auf Basis von Nachrichten wie ein technischer Prozess funktioniert – mit klaren Regeln, reproduzierbaren Ergebnissen und automatisierten Tests? Der Zweck dieses Artikels ist es, die funktionierende Architektur eines News-Layers für MetaTrader 5 zu demonstrieren: eine einzige Datenquelle, die korrekte Nutzung der Kalender-API, ein Filter- und Caching-Mechanismus, der Export von historischen Ereignissen in eine Ressource für den Tester und das automatische Umschalten zwischen Live und Tester – sodass derselbe Code deterministische Ergebnisse sowohl in Echtzeit als auch in historischen Daten erzeugt.
Abb. 1. Das Hauptproblem eines manuellen Händlers ist die Fragmentierung der Werkzeuge
Das manuelle News-Trading ist überholt.
Erstens kann eine Nachrichtenstrategie, die von externen Faktoren abhängt, nicht getestet werden. Ein wesentlicher Teil des Erfolgs im Trading hängt davon ab, die Performance der Strategie anhand historischer Daten zu testen. Die Unmöglichkeit, eine Strategie zu testen, führt zu einer Subjektivität der getroffenen Entscheidungen. Die Strategie wird eine Hypothese bleiben, und Sie werden viel Zeit – Monate und sogar Jahre – damit verbringen, sie zu testen.
Zweitens ist der manuelle Handel sehr schwer zu skalieren. Versuchen Sie, ein Unternehmen zu skalieren, das unbeständig ist und unregelmäßige Gewinne erzielt. Eine Ausweitung des Systems kann die Probleme nur noch verschärfen. Wenn es keine klare Struktur, Systematisierung und Optimierung gibt, dann ist es sinnlos, über Skalierung nachzudenken.
Drittens sind Verzögerungen bei der Reaktion auf Nachrichten ein wesentlicher Schwachpunkt beim manuellen Handel. Stellen Sie sich vor, Sie sind ein FOREX-Trader und handeln mit den Daten von Non-Farm-Payrolls (NFP). Die NFP-Daten werden in der Regel einmal im Monat veröffentlicht. Sie haben sich ablenken lassen und den NFP verpasst, und haben dadurch die Gelegenheit verpasst, Geld zu verdienen. Diese Situation ist vielen Händlern vertraut.
Fazit: Automatisierung ist der einzige Weg zum reproduzierbaren News-Trading.

Abb. 2. Ein Roboter ist immer schneller
Integrierter Wirtschaftskalender in MetaTrader 5: Eine einzige Informationsquelle
Um das News-Trading algorithmisch abzubilden – und damit historische Tests zu ermöglichen – verwenden Sie das einzigartige Produkt unseres Unternehmens – einen in MetaTrader 5 integrierten Wirtschaftskalender mit Zugang zu Nachrichten über die MQL5 API. So wird Ihr News-Trading von einer Improvisation zu einem überprüfbaren algorithmischen Prozess. Sowohl aktuelle Ereignisse in Echtzeit als auch historische Ereignisse sind für Offline-Tests verfügbar.
Tabelle 1:
Was macht den in MetaTrader 5 integrierten Kalender so einzigartig?
| Parameter | |
|---|---|
| Zugriffsgeschwindigkeit | <100 ms – nach dem Laden von Nachrichten in das Terminal |
| Integration | Nativ – auf der Ebene des Terminal-Kerns + MQL-API |
| Test | Vollständige Unterstützung – nach dem Herunterladen von Nachrichten auf das Terminal (Zugriff im Tester über Dateien, Ressourcen oder SQLite) |
| Zuverlässigkeit | Hoch |
MetaTrader 5 verfügt über einen hervorragenden Strategietester – schnell, Multi-Asset und in der Lage, Computer in lokalen und globalen Netzwerken zum Testen und Optimieren zu nutzen. Testen Sie Ihr News-Trading-System mit historischen Daten. Dies könnte Ihren Handelsansatz zum Positiven verändern.
MetaTrader 5 Wirtschaftskalender-Funktionen: Ein Überblick über die MQL5-API
Der Übergang von der manuellen zur algorithmischen Analyse beginnt mit dem Verständnis der Datenarchitektur. In MQL5 ist der Wirtschaftskalender nicht nur eine Tabelle, sondern eine strukturierte Datenbank, die über eine eigene API zugänglich ist. Wir werden untersuchen, wie man Ereignisse korrekt abfragt, was der Unterschied zwischen Ereignis und Wert ist und warum die Zeitsynchronisation für eine erfolgreiche Strategie unerlässlich ist.
Der MQL5-Kalender basiert auf mehreren zentralen Funktionen, die jeweils eine eigene Aufgabe erfüllen. Es ist wichtig zu verstehen, dass es keine universelle Funktion gibt, die alle Wirtschaftskalenderdaten auf einmal liefert. Hier ist ein kombinierter Ansatz erforderlich.
- CalendarValueHistory – Hauptinstrument für das anfängliche Laden. Ermöglicht das Abrufen eines Arrays von Ereigniswerten für ein bestimmtes Zeitintervall. Dies ist die „schwere Artillerie“, die während der Initialisierung des EA verwendet wird, um den Cache mit historischen Daten oder Daten für die kommende Woche zu füllen.
- CalendarValueLast – Hauptfunktion für EAs, die in Echtzeit arbeiten. Gibt nur geänderte oder neue Werte seit der letzten Anfrage zurück (über den Mechanismus des Parameters change_id). Auf diese Weise können Datenverkehr und Serverressourcen eingespart werden, da nicht bei jedem Tick das gesamte Datenfeld angefordert wird.
- CalendarEventByCountry – liefert Beschreibungen aller Ereignisse in einem Land. Gibt eine Liste von Ereignisbeschreibungen für ein bestimmtes Land zurück, das durch einen Code gemäß ISO 3166-1 alpha-2 angegeben ist. Erforderlich für die Erstellung von Filtern (z. B. nur Ereignisse für „US“ (USA), „RU“ (Russland), „CA“ (Kanada) usw. anzeigen).
- CalendarEventByCurrency – liefert Beschreibungen aller Ereignisse nach Währung. Gibt eine Liste von Ereignisbeschreibungen für eine bestimmte, durch einen Code („USD“, „EUR“ usw.) angegebene Währung zurück.
- CalendarCountryById – erhält Ländereigenschaften nach „id“.
- CalendarEventById – erhält Ereigniseigenschaften nach „id“.
- CalendarValueById – einen bestimmten Wert nach „id“ abrufen.
Datenstrukturen: Was gibt die Kalender-MQL5-API zurück?
Alle Wirtschaftskalender-API-Funktionen geben entweder ein Array von Strukturen oder eine Variable mit einer einzelnen Struktur zurück. Wir wollen die Strukturen und ihre Felder vollständig auflisten.
Ereignisbeschreibungen – verwendet in den Funktionen CalendarEventById, CalendarEventByCountry und 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) };
Länderbeschreibungen – verwendet in den Funktionen CalendarCountryById und 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 };
Ereigniswerte – verwendet in den Funktionen CalendarValueById, CalendarValueHistoryByEvent, CalendarValueHistory, CalendarValueLastByEvent und 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 };
Anmerkung:
Beachten Sie, dass die Struktur MqlCalendarValue Methoden zum Prüfen und Abrufen von Werten aus den Feldern actual_value, forecast_value, prev_value und revised_prev_value bietet. Die aufgelisteten Felder haben möglicherweise keine Werte – so kann beispielsweise das Feld actual_value leer sein, weil die Nachricht noch nicht veröffentlicht wurde. Der beste Weg, um Werte zu erhalten, ist, die Prüfung durchzuführen und die Werte mit den Methoden der Struktur selbst zu erhalten.
Die Strukturen sind durch die folgenden Beziehungen miteinander verbunden:

Abb. 3. Beziehungen zwischen Kalenderstrukturen
Die Struktur MqlCalendarCountry ist mit MqlCalendarEvent über eine Länder-ID verknüpft. Die Beziehungsform ist „one-to-many“ (1..*).
Die Struktur MqlCalendarEvent ist mit MqlCalendarValue über eine Ereignis-ID verknüpft. Die Beziehungsform ist „one-to-many“ (1..*).
Veröffentlichungszeit der News und Serverzeit
Alle Funktionen zur Arbeit mit dem Wirtschaftskalender verwenden TimeTradeServer(), die Uhrzeit des Handelsservers. Dies bedeutet, dass die Zeit in der Struktur MqlCalendarValue und die Zeitangaben in der CalendarValueHistoryByEvent() und CalendarValueHistory() in der Zeitzone des Handelsservers und nicht in der Ortszeit des Nutzers angegeben werden.
Eine Umwandlung ist nicht erforderlich: Die Zeit des Ereignisses MqlCalendarValue::period kann direkt mit der Zeit verglichen werden, die durch den Aufruf der Funktion TimeCurrent() oder TimeTradeServer() erhalten werden kann. In der Testumgebung gibt TimeTradeServer() eine modellierte Zeit zurück, die mit der Zeit in den historischen Daten identisch ist. Die Logik für die Arbeit mit Zeitfenstern („30 Minuten vor den Nachrichten“) funktioniert in Echtzeit und in der Vergangenheit gleich. Wenn der Makler die Umstellung auf Sommer-/Winterzeit berücksichtigt, passt sich der Kalender automatisch an diese Umstellung an.
Praktisches Beispiel: Abrufen einer Liste von Ereignissen für heute (den aktuellen Tag):
//+------------------------------------------------------------------+ //| 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); } } } //+------------------------------------------------------------------+
Die Funktion zeigt eine Liste von Ereignissen für die Währung USD für den aktuellen Tag und den Inhalt der Hauptfelder der Strukturen an, die über die MQL-API des Kalenders abgerufen werden. Der vollständige Skriptcode ist in der Datei GetTodayEvents-S.mq5 enthalten, die dem Artikel beigefügt ist.
Die Ergebnisse der Funktion können in der Registerkarte Werkzeuge\Experts des MetaTrader 5-Terminals eingesehen werden. Wir sehen, dass zwei Ereignisse für USD empfangen wurden. Zum Zeitpunkt der Anfrage waren diese Ereignisse noch nicht eingetreten (die Nachricht war noch nicht veröffentlicht worden). Daher enthält das Feld MqlCalendarValue::actual_value keinen Wert – die Funktion HasActualValue() gibt „false“ zurück.
Bei diesen Ereignistypen wird dem Feld MqlCalendarValue::forecast_value, das von der Funktion HasForecastValue() überprüft wird, nichts zugewiesen (es enthält keinen Wert). Bei anderen Ereignissen können alle vier Felder (prev_value, actual_value, forecast_value und revised_prev_value) fehlen.
Empfangene Ereignisse für USD: 2
✅ Event #0
Ereignis-ID: 840220005
Ereignisname: Auktion von 3-Monats-Schatzanweisungen
Sektor: 1
Quelle: https://home.treasury.gov/
Name des Landes: USA
Länder-URL: united-states
Time: 2026.04.20 18:30:00
Impact: 0
Vorherige: 3.62
✅ Event #1
Ereignis-ID: 840220006
Ereignisname: Auktion von 6-Monats-Schatzanweisungen
Sektor: 1
Quelle: https://home.treasury.gov/
Name des Landes: USA
Länder-URL: united-states
Time: 2026.04.20 18:30:00
Impact: 0
Vorherige: 3.61
Erklärungen für den angegebenen Code:
Zunächst erhalten wir ein Array von Werten für alle Ereignisse in einem bestimmten Zeitbereich mit dem Währungsfilter „USD“. In der Schleife durchlaufen wir das Wertearray und rufen für jeden Wert anhand der Ereignis-IDMqlCalendarValue::event_id die Ereignisbeschreibung mit der Funktion CalendarEventById() ab. Anschließend rufen wir anhand der ID MqlCalendarEvent::country_id die Länderbeschreibung mit der Funktion CalendarCountryById() ab.
Wenn die CalendarValueHistory() „false“ zurückgibt, GetLastError() aber Null (kein Fehler), bedeutet dies, dass es keine Ereignisse mit den gewünschten Einstellungen gibt.
Fehlerbehandlung und Einschränkungen bei der Arbeit mit dem Kalender
Die Arbeit mit entfernten Daten birgt immer das Risiko von Verbindungsunterbrechungen oder Zugriffsbeschränkungen. Kalenderfunktionen geben im Fehlerfall false oder 0 zurück. Um den Grund zu verstehen muss GetLastError() verwendet werden. In der Dokumentation wird auf eine separate Gruppe von Fehlern für das Kalendermodul hingewiesen.
Fehlercodes:
- ERR_CALENDAR_TIMEOUT (Code 5200) – Der Timeout für die Serverantwort ist abgelaufen. Netzwerkausfall oder Serverüberlastung. Lösung: Wiederholen Sie die Anfrage nach einer Pause von 5...10 Sekunden.
- ERR_CALENDAR_NO_DATA (Code 5201) – Die Kalenderdaten wurden noch nicht geladen. Die Initialisierung des Kalenders erfolgt asynchron. Lösung: 1...2 Sekunden warten und wiederholen.
- ERR_CALENDAR_INVALID_DATE (Code 5202) – ungültiger Datumsbereich. Code-Fehler (z.B. das Startdatum ist größer als das Enddatum). Lösung: Korrigieren Sie die Logik, eine Wiederholung der Anfrage ist nutzlos.
- ERR_CALENDAR_INVALID_COUNTRY (Code 5203) – unbekannter Länder-/Währungscode. Fehler in den Anfrageparametern. Lösung: Überprüfen Sie den Code (z. B. „US“ anstelle von „USA“).
- ERR_CALENDAR_TOO_MANY_REQUESTS (Code 5204) – Anfragelimit überschritten. Kritischer Fehler. Lösung: Vergrößern Sie den Abstand zwischen den Anfragen.
Begrenzung der Anfragerate:
Die Server, mit denen das MetaTrader 5-Terminal verbunden ist, schützen die Infrastruktur vor Überlastung. Wenn der EA die Funktion CalendarValueHistory() bei jedem Tick oder in einer Schleife ohne Verzögerungen aufruft, gibt der Server den Fehler 5204 zurück und blockiert vorübergehend den Zugriff auf den Kalender für Ihr Terminal. Beste Praxis: Laden Sie die Daten einmal beim Start in OnInit() für den erforderlichen Zeitraum.
Für Echtzeitaktualisierungen verwenden Sie CalendarValueLast() und speichern Sie die zurückgegebene Variable change_id – so werden nur Änderungen statt des gesamten Datenarrays geladen. Aktualisieren Sie die Daten eines Timers in OnTimer() in Intervallen von nicht mehr als 5-10 Minuten.
Sehen wir uns nun einige Beispiele für Lösungen von Problemen an, die beim Laden eines Kalenders auftreten können:
Wenn Sie das Terminal (Kaltstart) und den EA starten, ist der Kalender nicht sofort bereit. Die Daten werden im Hintergrund vom Server geladen. Wenn wir CalendarValueHistory() in der allerersten Zeile von OnInit() aufrufen, wird höchstwahrscheinlich der Fehler 5201 – keine Daten – angezeigt. Es ist notwendig, einen Mechanismus zur Prüfung der Bereitschaft mit einem exponentiellen oder festen Timeout zu implementieren.
Praktisches Beispiel – Funktion zum Laden von Kalenderdaten mit Fehlerbehandlung:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Erklärungen für den angegebenen Code:
Berücksichtigen Sie die Möglichkeit der Fehler „Keine Daten“ (5201) und „Timeout“ (5200). Diese Fehler sind behebbar. Machen Sie eine Pause von 1...5 Sekunden und fordern Sie die Daten erneut an. Wenn nicht behebbare Fehler auftreten, brechen Sie den Download sofort ab. Zu den nicht behebbaren Fehlern gehören ungültige Daten, falsche Währungs- oder Ländercodes usw. Den vollständigen Skriptcode finden Sie in der Datei GetTodayEvents-S.mq5 im Anhang zu diesem Artikel.
Um Begrenzungen zu vermeiden und eine maximale Reaktionsgeschwindigkeit zu gewährleisten, sollte in OnTimer() der Mechanismus change_id verwendet werden. Beim Start laden wir den vollständigen Ereignisverlauf und speichern die letzte change_id. Im Timer fordern wir mit der Funktion CalendarValueLast() nur neue Daten an. Der Server gibt nur die geänderten Daten zurück (oder „false“, wenn keine Änderungen vorliegen), ohne Ressourcen für die Übertragung alter Daten zu verschwenden.
Praktisches Beispiel – die Funktion zur Aktualisierung von Kalenderdaten mit Fehlerbehandlung:
//+------------------------------------------------------------------+ //| 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++; } } } //+------------------------------------------------------------------+
Erklärungen für den angegebenen Code:
Die inkrementelle Aktualisierung von Ereignissen erfolgt über den Event-Handler des Timers OnTimer(). Die Kalender-API-Funktion CalendarValueLast() wird aufgerufen – sollten neue Ereignisse auftreten, werden die entsprechenden Elemente im zuvor geladenen Array MqlCalendarValue der Strukturen aktualisiert und die Informationen im Terminal-Protokoll ausgegeben. Ist ein solches Ereignis im geladenen Array nicht vorhanden, wird es dem Array hinzugefügt.
Der vollständige Skriptcode ist in CalendarEventMonitor-EA.mq5 enthalten, das dem Artikel beigefügt ist.
Ereignisse filtern: Vom Allgemeinen zum Speziellen
Warum filtern:
Im Wirtschaftskalender werden täglich 60-90 Ereignisse veröffentlicht. Es ist, als würde man ständig Hunderten von unbedeutenden Indikatoren, Feiertagen und offiziellen Reden zuhören, die keine unmittelbare Wirkung auf den Markt haben. Der Handel mit jedem einzelnen von ihnen ist ein todsicherer Weg, zu viel zu handeln und Ihre Einlage zu verlieren. Die Aufgabe eines algorithmischen News-Traders besteht darin, sich auf 3-5 Ereignisse zu konzentrieren, die den Markt wirklich bewegen.
Die Filterung im algorithmischen News-Trading ist gleichbedeutend mit der Erhöhung des Signal-Rausch-Verhältnisses auf ein Niveau, das für die automatische Entscheidungsfindung geeignet ist. In der MQL5-Kalender-API ist dieser Prozess wie ein mehrstufiges Sieb implementiert, das die Arrays der Strukturen MqlCalendarEvent und MqlCalendarValue durchlaufen.
Kriterien für die Filterung:
Der Markt reagiert nicht auf die Pressemitteilung selbst, sondern auf die Abweichung der tatsächlichen Daten von den Prognosen und den Grad des makroökonomischen Einflusses. Ereignisse mit geringer Wirkung (MqlCalendarValue::impact_type < 3) werden von Handelsalgorithmen und Market Makern häufig ignoriert.
Ohne Filterung entstehen Ihnen folgende Probleme:
- Falsche Auslösungen der Strategie aufgrund irrelevanter Statistiken;
- Handel in Phasen mit erhöhtem Spread ohne Volatilität;
- Überlastung der EAs-Logik durch unnötige Überprüfungen.
Das Ziel der Filterung ist es, den Datenfluss um 90 % zu reduzieren, sodass nur noch Ereignisse mit hoher Wirkung (ENUM_CALENDAR_EVENT_IMPORTANCE::CALENDAR_IMPORTANCE_HIGH) für die vom Händler ausgewählte Zielwährung in einem bestimmten Zeitfenster übrig bleiben.
Sehen wir uns an, wie man einen zuverlässigen Filter baut, der sowohl im Echtzeit- als auch im Testmodus gleichermaßen zuverlässig arbeitet.
Mehrstufiges Filtersystem:
Die vom Terminal heruntergeladenen „rohen“ Ereignisdaten sind wie unverarbeitetes Erz: Sie enthalten Tausende von Einträgen, die von unbedeutenden statistischen Berichten bis hin zu Feiertagen reichen, die keinen Nutzen für die algorithmische Strategie bieten.
Um diesen Datenstrom in ein sauberes Signal zu verwandeln, benötigen wir ein mehrstufiges Filtersystem. Die Ereignisfilterung fungiert als „Sieb“, durch das die Rohdaten hindurchgehen, sodass am Ausgang nur die Ereignisse übrig bleiben, die die angegebenen Kriterien erfüllen: Währung, Wichtigkeit, Code und Zeitfenster.
Ein wirksamer Filter sollte hierarchisch aufgebaut sein: Er beginnt mit einer groben Abgrenzung nach geografischen Gesichtspunkten und endet mit einer Feinabstimmung nach Zeitfenstern.
Ein wichtiges Merkmal der News-MQL5-API – der Struktur MqlCalendarValue fehlen die Felder currency_id und country_id. Sie speichert nur event_id, Zeit, Indikatorwerte und Wirkungstyp. Wie wirkt sich das auf die Filtration aus?
Die Währungsfilterung wird auf der Ebene der API-Anfrage durchgeführt. Wenn Sie CalendarValueHistory(..., NULL, „USD“) aufrufen, verwirft das Terminal selbst alles außer USD. Das Array, das Sie erhalten, ist bereits nach Währung gefiltert. Daher besteht keine Notwendigkeit, die currency_id in Echtzeit zu überprüfen – es genügt, nach Zeit, Wichtigkeit und prognostizierter Präsenz/Signifikanz zu filtern.
Stufe 1: Währungsfilter
Die erste Filterstufe ist die geografische Zuordnung des Ereignisses. Beim Handel mit EURUSD sollte der EA nur auf Ereignisse reagieren, die die Eurozone (EUR) und die USA (USD) betreffen. Die Filterung beruht auf der Abfrage von Ereignissen mit den Währungscodes des gehandelten Instruments. Bei Cross-Rates (z. B. „GBPJPY“), müssen wir Ereignisse für beide Währungen („GBP“ und „JPY“) und „USD“ anfordern.
Stufe 2: Wichtigkeit des Ereignisses
Alle Nachrichten sind von unterschiedlicher Wichtigkeit für die Wirtschaft, ja sogar für die Preise. Der Verbraucherpreisindex (VPI) kann den Markt um 100 Punkte bewegen, während der ZEW-Verbrauchervertrauensindex ihn nur um 10 Punkte bewegen kann.
MQL5-API verwendet die Enumeration ENUM_CALENDAR_EVENT_IMPORTANCE zur Einstellung des Wichtigkeitsgrades:
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 };
News-EAs sollten alles unter „HIGH“ ignorieren, um Fehlalarme bei News mit geringer Liquidität zu vermeiden.
Stufe 3: Ereignis-Code
Selbst bei Ereignissen von großer Wichtigkeit gibt es Ausnahmen. So kann beispielsweise eine Rede der EZB oder des IWF als wichtig eingestuft werden, ist aber algorithmisch schwieriger zu verarbeiten als die Veröffentlichung bestimmter Zahlen. Daher ist eine Sortierung nach Ereigniscode erforderlich: MqlCalendarEvent::event_code Feld enthält eine eindeutige ID (zum Beispiel „NONFARM“, „CPI“, „GDP“). Wir wählen nur Ereignisse mit Wirtschaftszahlen aus, nicht Umfragen und Reden.
Erst nachdem das Ereignis die ersten drei Überprüfungsstufen durchlaufen hat, wird es in das resultierende Array kopiert und im Handel verwendet.

Abb. 4. Mehrstufiges Filtern ist der Schlüssel zum Erfolg im News-Trading
Nach den ersten drei Filterstufen prüft der EA, ob das Ereignis in das konfigurierte Zeitfenster fällt. Dies geschieht, während der Handels-EA läuft.
Stufe 4: Zeitfenster
Der letzte Schritt ist die Überprüfung der Relevanz. Wir brauchen keine Nachrichten, die erst in einem Monat veröffentlicht werden. Eine Nachricht, die gestern veröffentlicht wurde, ist vom Markt bereits eingepreist. Daher wird ein Ereignis als aktiv betrachtet, wenn TimeCurrent() innerhalb des folgenden Intervalls liegt: der angegebenen Zeit vor der Pressemitteilung und der angegebenen Zeit nach der Pressemitteilung. In der Regel werden die folgenden Einstellungen verwendet: 15-30 Minuten vor dem Veröffentlichung – für das Schließen von Positionen und 60 Minuten danach – für die Analyse der Volatilität und der Richtung der Preisbewegung.
MQL5-Binärressourcen: Verschieben von Ereignissen in Offline-Tests für eine effiziente Zwischenspeicherung
Ein Problem beim Testen im nachrichtenbasierten algorithmischen Handel ist, dass der Strategietester keinen Internetzugang hat. Diese Lösung beschleunigt das Testen und schützt vor nicht-deterministischen Faktoren, schafft aber ein Problem für das Testen von auf Nachrichten basierenden Strategien.
Wenn der EA im Tester die Funktion CalendarValueHistory() aufruft, erhält er einen Fehler und ein leeres Array. Um die Strategie zu testen, müssen wir historische Nachrichtendaten in die ausführbare Datei .ex5 einbetten. Hierfür verwenden wir die Option mit MQL5-Binärressourcen. Warum gerade diese Option? Dies ist der schnellste Weg, um auf strukturierte Daten zuzugreifen – die Zugriffsgeschwindigkeit wird nur durch die Leistung des Dateisystems des Computers begrenzt.
Schauen wir uns an, wie man das Array MqlCalendarValue[] in eine kompakte Binärdatei umwandelt und in den Code einbettet, sodass der Tester die Daten blitzschnell aus dem RAM liest. Der erste Schritt besteht darin, ein Exporter-Skript zu erstellen, das die aktuellen Daten aus dem Kalender herunterlädt und in einer Binärdatei speichert.
Praktisches Beispiel – ein Skript zum Exportieren von Ereignissen in eine Binärdatei:
Der vollständige Skriptcode befindet sich in der Datei ExportCalendarForTester.mq5, die dem Artikel beigefügt ist.
Schritt 1: Zusammenstellung und Filterung des Arrays
Wir werden nicht alle Weltereignisse in der Ressource speichern. Beim Export in eine Binärdatei werden dieselben Filter wie im EA angewendet: Währung, Wichtigkeit und Ereignistyp. Die Skripteingaben geben die Liste der Währungen, das Zeitintervall für das Laden von Ereignissen, die Ereigniscodes und die Mindestbedeutung an.
Liste der Ereigniscodes (InpEventCodes) ist standardmäßig leer – das bedeutet, dass alle Ereignistypen geladen werden. Wir können diesen Filter einschränken. Zum Beispiel nur "Non-Farms“ – dann wird die Liste der Codes „NONFARM“ sein.
InpUseCommonDir gibt an, wo die Binärdatei gespeichert werden soll: true – Speichern im gemeinsamen Ordner für alle Client-Terminals „\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;
Der Teil des Skripts, der Ereignisse mit den in den Eingaben angegebenen Werten lädt und filtert, ist unten dargestellt:
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 } } }
Erklärungen für den angegebenen Code:
- Im Array values_size[] wird die Anzahl der gefilterten Ereignisse für jede in den Eingabeparametern des Codes angegebene Währung gespeichert.
- Dem Wert Null für den MQL5-Datentypdatetime entspricht das Datum 01.01.1970 00:00:00.
- Eine zusätzliche Filterung erfolgt nach Ereignistyp. Es werden nur Ereignisse vom Typ ENUM_CALENDAR_EVENT_TYPE::CALENDAR_TYPE_INDICATOR gefiltert – das sind wirtschaftliche Ereignisse (keine Reden, sondern Zahlen). Alle anderen Nachrichten werden aussortiert. Dies geschieht durch eine Validierung gleich zu Beginn der Filterung:
//--- take only indicators if(event.type != CALENDAR_TYPE_INDICATOR) continue; // Nothing else to filter
Führen wir das Skript mit verschiedenen Filterparametern aus, um zu sehen, wie schnell das Skript zum Laden und Filtern von Ereignissen funktioniert. Es ist klar, dass die Geschwindigkeit von der Leistung des Computers und der Geschwindigkeit der Verbindung zu den Datenservern über das Internet abhängt. Dennoch werden wir einen Stresstest durchführen. Die Ergebnisse werden im Folgenden vorgestellt.
Alle möglichen USD-Ereignisse – über den gesamten verfügbaren historischen Zeitraum hinweg – mit großer Wichtigkeit:
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 → Davon gefiltert: 9009
13:59:45.511 ----------------------------------
13:59:45.513 ✅ Saved: USD_calendar_test_res.bin Größe: 1153152 Bytes (9009 Ereignisse)
Dauer zum Abrufen des Arrays gefilterter Werte (Strukturen MqlCalendarValue): 1,80 Sekunden (0,20 ms / pro Filtration).
Alle möglichen USD, EUR und JPY von großer Wichtigkeit – über die gesamte verfügbare Historie:
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 → Davon gefiltert: 9009
14:03:10.947 ✅ Received values BY CURRENCY "EUR": 45139 → Davon gefiltert: 1102
14:03:11.404 ✅ Received values BY CURRENCY "JPY": 18907 → Davon gefiltert: 937
14:03:11.404 ----------------------------------
14:03:11.406 ✅ Saved: USD_calendar_test_res.bin Größe: 1153152 Bytes (9009 Ereignisse)
14:03:11.407 ✅ Saved: EUR_calendar_test_res.bin Größe: 141056 Bytes (1102 Ereignisse)
14:03:11.408 ✅ Saved: JPY_calendar_test_res.bin Größe: 119936 Bytes (937 Ereignisse)
Dauer zum Abrufen des Arrays gefilterter Werte (Strukturen MqlCalendarValue): 2,68 Sekunden (0,24 ms / pro Filtration).
NFP-Ereignisse („Non-Farms“) in USD von großer Wichtigkeit – in der gesamten verfügbaren Geschichte:
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 → Davon gefiltert: 473
14:07:22.290 ----------------------------------
14:07:22.291 ✅ Saved: USD_calendar_test_res.bin Größe: 60544 Bytes (473 Ereignisse)
Dauer zum Abrufen des Arrays gefilterter Werte (Strukturen MqlCalendarValue): 0,09 Sekunden (0,18 ms / pro Filtration).
Bemerkung:
- Es ist nicht erforderlich, den gesamten Ereigniscode im Filter anzugeben. Es reicht aus, einen eindeutigen Teil der Zeichenkette anzugeben, der den Code enthält. Für „Non-Farms“ lautet der vollständige Code beispielsweise „NONFARM-PAYROLLS“ – die Angabe von „NONFARM“ ist ausreichend.
- Beim Betrieb eines Echtzeit-Handelssystems im MetaTrader 5-Terminal ist es unwahrscheinlich, dass wir alle Ereignisse für den gesamten Zeitraum herunterladen müssen. In der Regel werden aktuelle Ereignisse für den Tag und die kommende Woche heruntergeladen. Daher kann die Ladezeit im News-EA-Algorithmus vernachlässigt werden.
Schritt 2: Exportieren wir das Ereignis-Array in eine Binärdatei
Die Funktion SaveToBinary speichert gefilterte Ereignisse in einer Binärdatei. Die Anzahl der Dateien entspricht der Anzahl der in den Eingaben angegebenen Währungscodes – jede Währung wird in eine eigene Binärdatei exportiert. Der Dateiname beginnt mit dem Präfix des Währungscodes. Zum Beispiel: „USD_calendar_test_res.bin“. Auf diese Weise erhalten wir eine Eins-zu-eins-Entsprechung zwischen dem Währungscode und der Liste der Ereignisse für diesen Code.
//+------------------------------------------------------------------+ //| Save an array to a binary file | //+------------------------------------------------------------------+ void SaveToBinary(MqlCalendarValue &values[], const int &vls_size[], const string filename, const string ¤cies[]) { 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]; } }
Nachdem das Skript zum Exportieren von Ereignissen in Binärdateien erfolgreich ausgeführt wurde, erscheinen Meldungen wie die folgende in der Registerkarte der Experten von MetaTrader 5:
14:28:42.077 ----------------------------------
14:28:42.078 ✅ Saved: USD_calendar_test_res.bin Größe: 58240 Bytes (455 Ereignisse)
14:28:42.079 ✅ Saved: EUR_calendar_test_res.bin Größe: 7680 Bytes (60 Ereignisse)
Schritt 3: Kompilieren der Ressource in den EA
Nach dem Start des Skripts ExportCalendarForTester.mq5 in MQL5/Files/ erscheinen die Dateien USD_calendar_test_res.bin und EUR_calendar_test_res.bin. Jetzt müssen sie in den EA „eingebettet“ werden. Fügen Sie am Anfang der EA-Datei (nach der Direktive #property) eine (wenn die Datei für eine Währung verwendet wird) oder mehrere Zeilen folgender Art ein:
// 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[]
Hinweis:
- Der Pfad zu #resource wird relativ zum Ordner MQL5/Files/ angegeben. Die Vorsilbe \\Files\ ist obligatorisch.
- Bei der Kompilierung des EA sollten Meldungen wie die folgenden auf der Registerkarte „Fehler“ von MetaEditor erscheinen:
- '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]'
Beim Starten des EA werden die Strukturen der Ereignisse, die während der Exportphase gespeichert wurden, in den Arrays USD_res_calendar_data[] und EUR_res_calendar_data[] gespeichert.
Integration in den EA: Automatische Betriebsartumschaltung
Ziel ist es, dass derselbe EA-Code sowohl in Echtzeit als auch im Tester funktioniert und die Datenquelle automatisch ausgewählt wird. Die Funktion MQLInfoInteger (MQL_TESTER) gibt „true“ zurück, wenn der EA im Strategy Tester oder Optimizer läuft.
//+------------------------------------------------------------------+ //| 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; }
Erklärungen für den angegebenen Code:
Die Hauptprüfung erfolgt in der Initialisierung des EAs 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()) { ... } }
Erklärungen für den angegebenen Code:
Wir bestimmen, in welchem Modus das laufende MQL5-Programm (hier ist es unser EA) arbeitet. Wir sind an den folgenden Flags interessiert:
- MQL_TESTER – Flag des gestarteten Programms, das im Tester läuft;
- MQL_OPTIMIZATION – Flag des gestarteten Programms während der Optimierung;
- MQL_VISUAL_MODE – Flag des gestarteten Programms im visuellen Testmodus.
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 (Daten aus API)
Validierung der Datenumwandlungskette: Ereignisse → Binärdatei → Kompilieren zur Ressource → Abrufen von Ereignissen aus der Ressource
Es bleibt nur noch, den Abruf der Ereignisse im Tester zu kontrollieren und sicherzustellen, dass sie vollständig mit der in Echtzeit empfangenen Liste übereinstimmen. Damit wird die Möglichkeit bestätigt, Algorithmen für das News-Trading automatisch zu testen und zu optimieren.
Fügen Sie dazu die Ausgabe von Ereignissen, die vom Server empfangen bzw. von der Ressource heruntergeladen wurden, in das Protokoll des Terminals/Strategietesters ein. Die vollständige Textdatei ImportTesterLog.txt mit den Ergebnissen des Testlaufs ist unten angefügt. Nachfolgend sehen Sie einen Ausschnitt aus der Protokolldatei – den Anfang und das Ende der Reihe von Ereignissen für jeden Währungscode.
Ergebnis eines einzelnen Laufs im Strategietester, im visuellen Modus:
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 (Daten aus der Ressource)
Es ist klar, dass alle Ereignis-Arrays in etwa 10 ms von der Ressource geladen werden, was nicht überraschend ist – die Ressource ist in den EA-Code integriert und wird zusammen mit ihm geladen, wenn der Test beginnt.
Der gleiche Durchlauf (Start) eines Expert Advisors im Live-Modus im MetaTrader 5-Terminal erzeugt eine ähnliche Protokolldatei mit einer Liste der geladenen Ereignisse. Die vollständige Datei LoadLiveLog.txt mit den Ergebnissen des Live-Ladens ist dem Artikel beigefügt. Nachfolgend sehen Sie einen Ausschnitt aus der Protokolldatei – den Anfang und das Ende der Reihe von Ereignissen für jeden Währungscode.
Ergebnisse des Live-Downloads von Ereignissen vom Server:
17:27:25.250 🔄 Initializing news module:
17:27:25.258 ✅ Received values BY CURRENCY "USD": 3589 → Davon gefiltert: 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 (Daten aus API)
Ein vollständiger Download mit Filterung und Protokollierung dauert etwa 50 ms – immer noch schnell genug, um die Download-/Filterungszeit von Ereignissen zu ignorieren. Der Vergleich der beiden Protokolldateien zeigt, dass die Liste der Ereignisse sowohl hinsichtlich der Anzahl der Ereignisse als auch der Werte der Felder völlig identisch ist. Validierung der Datenumwandlungskette erfolgreich abgeschlossen.
Analyse von typischen Fehlern und falschen Erwartungen
Sehen wir uns die sechs häufigsten Fehler an, die Entwickler bei der Integration des MQL5-Wirtschaftskalenders machen. Jeder dieser Fehler wurde in der Praxis bestätigt und kann für manche zum Verlust ihres Guthabens führen.
1. „Der Kalender sagt Bewegung voraus“
Falsche Erwartung:
Wenn Nachrichten mit GROSSER Wichtigkeit veröffentlicht werden und das tatsächliche Ergebnis erheblich von der Prognose abweicht, wird sich der Kurs garantiert in Richtung der Abweichung bewegen. Kaufen Sie einfach, wenn der tatsächliche Wert der Basiswährung über dem prognostizierten Wert liegt.
Die Realität:
Der Wirtschaftskalender ist eine Datenquelle, kein Generator für Handelssignale. Er sagt Ihnen, was passiert ist, aber nicht, wie der Markt reagieren wird. Warum könnte der Preis der „offensichtlichen“ Logik widersprechen?
- Der Markt hat die Erwartungen schon Tage vor der Veröffentlichung eingepreist. Genau in dem Moment, in dem die Nachricht veröffentlicht wird, findet der „Verkauf der Nachricht“ statt.
- Starke Inflationsdaten während einer Phase der Straffung der Zentralbankpolitik können die Währung stärken, aber während einer Phase der Lockerung können sie einen Ausverkauf aufgrund von Befürchtungen einer Überhitzung auslösen.
- Die Nachrichten mögen gut sein, aber wenn der vorherige Wert nach unten korrigiert wird, wird das Gesamtsignal mehrdeutig.
- Die gleichzeitige Veröffentlichung von Daten für mehrere Währungen führt zu Crossover-Effekten, die nicht linear interpretiert werden können.
Der richtige Ansatz ist, den Kalender als Volatilitätsfilter zu verwenden, nicht als Einstiegsauslöser:
//--- instead of if(actual > forecast) OrderSend(...); //--- use: if(IsHighImpactNewsComingSoon(30)) { //--- reduce the position size or temporarily suspend trading ReduceRiskExposure(); }
2. „Alle Ereignisse mit HOHER Wichtigkeit sind gleich wichtig“
Falsche Erwartung:
Das Feld importance == CALENDAR_IMPORTANCE_HIGH bedeutet, dass das Ereignis den Markt garantiert um mehr als 50 Pips bewegen wird. Wir können alle diese Nachrichten mit demselben Algorithmus handeln.
Die Realität:
Bestimmte Werte in der ENUM_CALENDAR_EVENT_IMPORTANCE sind eine subjektive Einschätzung der Kalenderredakteure und kein quantitativer Maßstab für die Marktwirkung. Nehmen wir zum Beispiel zwei Ereignisse, die als HOCH bezeichnet werden, aber eine unterschiedliche Marktbedeutung haben.
Das erste Ereignis, die Non-Farm Payrolls (USA), führt zu einer Volatilitätsreaktion von 80-150 Punkten, da es sich um einen wichtigen Beschäftigungsindikator handelt, der die Fed-Politik beeinflusst. Das zweite Ereignis, der PMI des verarbeitenden Gewerbes (Eurozone), führt typischerweise zu einer Bewegung von 10 – 30 Punkten, da es sich um einen eng gefassten Indikator handelt, der für die EZB zweitrangig ist.
Der richtige Ansatz besteht darin, die Wichtigkeitsfilterung durch eine Liste von Prioritätsereigniscodes zu ergänzen:
//--- 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 }
Empfehlung:
Erstellen Sie Ihr eigenes Ereignis-Ranking auf der Grundlage historischer Volatilitätsanalysen – zuverlässiger als jedes vorgegebene Label.
3. „Verwendet wird TimeLocal() anstelle von TimeTradeServer()“
Falsche Erwartung:
Ereigniszeit in der Struktur MqlCalendarValue::time ist in meiner lokalen Zeitzone (oder UTC) angegeben, sodass ich sie mit TimeLocal() oder TimeGMT() vergleichen kann.
Die Realität:
Alle Wirtschaftskalenderfunktionen geben die Zeit in der Zeitzone des Handelsservers zurück (TimeTradeServer()). Dies ist eine architektonische Entscheidung, die eine manuelle Konvertierung überflüssig macht, aber vom Entwickler Disziplin verlangt.
Dieser Fehler hat schwerwiegende Folgen: Wenn sich Ihr Server in der EET-Zeitzone (UTC+2) befindet und Sie TimeLocal() verwenden (z. B. MSK, UTC+3), werden Sie Ereignisse mit einem Versatz von 1 Stunde prüfen. Der EA kann die Nachricht verpassen oder umgekehrt erst im Nachhinein auf sie reagieren.
Der richtige Ansatz ist, immer den TimeTradeServer() für alle Zeitvergleiche zu verwenden:
//--- 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
Empfehlung:
Fügen Sie die Ausgabe von TimeToString(TimeTradeServer(), TIME_MINUTES) zum Debug-Protokoll hinzu und vergleichen Sie sie mit der Ereigniszeit – sie sollten ohne Umrechnung übereinstimmen.
4. „Vergessen, dass Ereignisfelder leer sein können“
Falsche Erwartung:
Die Felder actual_value, forecast_value und andere Felder enthalten immer korrekte numerische Werte. Man kann sie bedenkenlos durch 1 000 000 teilen und vergleichen.
Die Realität:
Der Dokumentation zufolge sind die numerischen Felder der Struktur MqlCalendarValue Werte multipliziert mit einer Million oder der Konstante LONG_MIN, wenn kein Wert angegeben ist. Was passiert, wenn wir die Prüfung ignorieren?
//--- 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();
Der richtige Ansatz ist die Verwendung der integrierten Methoden der Struktur MqlCalendarValue zu verwenden, um Werte sicher zu erhalten:
//--- 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 } } //+------------------------------------------------------------------+
Hinweis:
GetActualValue(), GetForecastValue() und andere Funktionen geben NaN zurück, wenn es keine Daten gibt. Prüfen Sie das Ergebnis immer mit MathIsValidNumber() oder MathIsNaN(), bevor Sie es in Berechnungen verwenden.
5. „Die Kalender-API-Funktionen bei jedem OnTick() aufrufen“
Falsche Erwartung:
„Um immer aktuelle Daten zu haben, sollte man CalendarValueHistory() bei jedem Tick aufrufen. Auf diese Weise wird sichergestellt, dass der EA keine aktuellen Nachrichten verpasst“.
Die Realität:
Die Kalenderfunktionen laufen über einen Remote-Server, mit dem MetaTrader 5 verbunden ist, und unterliegen strengen Begrenzungen der Abfragefrequenz. Zu häufige Aufrufe von OnTick() (kann Dutzende Male pro Sekunde passieren) führen zu Problemen:
- Error 5204 (ERR_CALENDAR_TOO_MANY_REQUESTS) – vorübergehende Blockierung des Zugriffs auf den Kalender.
- Ausführungsverzögerungen – eine Netzanfrage im Handelszyklus erhöht das Slippage.
- Übermäßiger Datenverkehr – wiederholtes Herunterladen der gleichen Daten.
//--- 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); }
Empfehlung:
OnTick() sollte nur mit lokalen Daten funktionieren. Netzwerkanfragen – nur in OnInit(), OnTimer() oder durch Nutzerereignis.
6. „Vergessen, den Experten neu zu kompilieren, um ihn auf neue Ereignisse zu testen“
Falsche Erwartung:
„Ich habe die Ressourcendatei calendar_test_res.bin im Ordner Files aktualisiert, sodass der Tester nun automatisch die neuen Ereignisse sieht. Es besteht keine Notwendigkeit, den EA neu zu kompilieren.“
Die Realität:
Die Direktive #resource bettet zur Kompilierungszeit Daten in die ausführbare .ex5-Datei ein. Änderungen an der externen .bin-Datei werden nicht dynamisch übernommen – der EA verwendet weiterhin die Version der Ressource, die zum Zeitpunkt der Erstellung kompiliert wurde.
Fehlersymptome:
- Das Prüfprotokoll enthält keine Ereignisse, die der Ressource nach der letzten Kompilierung hinzugefügt wurden.
- Die Strategie „sieht“ wichtige Nachrichten nicht, obwohl sie in der Datei enthalten sind.
- Die Testergebnisse sind anders als erwartet, obwohl der Code logisch korrekt ist.
Der richtige Ansatz ist, den EA nach der Aktualisierung der Ressource immer neu zu kompilieren:
//--- 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.
Empfehlung:
Fügen Sie die Ausgabe der Ressourcenversion (z. B. Hash oder Datum der letzten Aktualisierung) dem Kompilierungsprotokoll hinzu, um die Relevanz der Daten in .ex5 visuell zu überwachen.
Bemerkung:
Die in diesem Abschnitt diskutierten Fehler sind nicht auf mangelnde Kenntnisse der MQL5-Syntax zurückzuführen, sondern auf ein vereinfachtes Verständnis der Natur von Wirtschaftsdaten (Indikatoren). Wer lernt, diese sechs Fehler zu vermeiden, erhält nicht nur einen funktionierenden Code, sondern ein stabiles Handelssystem, das in der Lage ist, sich an Marktveränderungen und die Anforderungen der Wirtschaftsregulierer anzupassen. Es ist dieser Ansatz, der einen Amateur von einem Profi im algorithmischen Handel unterscheidet.
Schlussfolgerung
Der Wirtschaftskalender im MetaTrader 5-Terminal ist ein leistungsfähiges Instrument. Aber wie bei jedem anderen Werkzeug auch, muss man den Kontext verstehen, diszipliniert vorgehen und die Grenzen der Plattform berücksichtigen.
Wir haben uns eine konkrete Struktur für die Implementierung und Nutzung der News-API für den EA in MetaTrader 5 vorgestellt. Der Artikel enthält eine Reihe praktischer Elemente, die zusammengenommen das manuelle News-Trading in ein reproduzierbares Modul verwandeln:
- Verständnis der Kalender-API (Ereignis vs. Wert, MqlCalendarEvent/MqlCalendarValue-Strukturen, Serverzeit);
- sichere Lade- und Aktualisierungsmethoden (CalendarValueHistory für das erste Laden, CalendarValueLast + change_id für inkrementelle Aktualisierungen);
- Umgang mit typischen Fehlern und Einhaltung von Anfragegrenzen;
- mehrstufige Filterung nach Währung, Wichtigkeit, Ereigniscode und Zeitfenstern, um Rauschen zu reduzieren und 3-5 signifikante Ereignisse übrig zu lassen;
- einen Mechanismus für den Export gefilterter Daten in eine binäre Ressource und den automatischen Wechsel der Datenquelle „Echtzeit“ ↔ „Strategietester“, wodurch ein identisches Verhalten in Echtzeit und beim Backtesting gewährleistet wird.
Kriterien für die Einsatzbereitschaft des Moduls: Ereignisse für den angegebenen Zeitraum werden erfolgreich geladen; inkrementelle Aktualisierungen funktionieren über change_id ohne Überschreitung von Grenzwerten; im Tester liest EA die Ressource und produziert die gleichen Entscheidungen wie in Live mit identischen Eingabedaten.
Empfohlene nächste Schritte: Implementierung des Exporters, die .bin-Datei per #resource fest einzubinden, Test der OnInit/OnTimer-Aktualisierungslogik und Durchführung kontrollierter Backtests (z. B. Szenario „30 Minuten lang nicht handeln / nach 60 Minuten wieder aufnehmen“).
So können Sie von Hypothesen zu einem testbaren, skalierbaren News-Tradingssystem übergehen. Bei der Entwicklung von Nachrichten-EAs geht es nicht nur um Programmierung, sondern auch darum, eine Brücke zwischen makroökonomischer Theorie und Marktpraxis zu schlagen.
Empfohlene Ressourcen für ein eingehendes Studium der MetaTrader 5 Kalender-API-Funktionen und deren Verwendung im News-Trading:
- Dokumentation – Wirtschaftskalenderfunktionen;
- Artikel Handel mit dem MQL5-Wirtschaftskalender (Teil 1): Beherrschung der Funktionen des MQL5-Wirtschaftskalenders;
- Artikel Handel mit dem MQL5-Wirtschaftskalender (Teil 7): Vorbereitung auf den Strategietest mit der ressourcenbasierten Analyse von News-Ereignissen;
- Artikel Handel mit dem MQL5-Wirtschaftskalender (Teil 8): Optimierung des nachrichtenbasierten Backtestings mit intelligenter Ereignisfilterung und gezielten Protokollen;
- Artikel MQL5 Kochbuch – Wirtschaftskalender.
Liste der dem Artikel beigefügten Dateien:
| Dateiname | Beschreibung |
|---|---|
| CalendarEventMonitor-EA.mq5 | Testskript mit dem Code zum Testen der Funktion zur Aktualisierung der Kalenderdaten |
| ExportCalendarForTester-S.mq5 | Der Code eines Testskripts zur Überprüfung des Exports von Ereignissen mit bestimmten Filtern in eine Binärdatei |
| GetTodayEvents-S.mq5 | Der Code eines Testskripts zur Überprüfung des Abrufs von Ereignissen für den aktuellen Tag |
| ImportCalendarValidation-EA.mq5 | Der Code eines Test-EA zur Überprüfung des Nachrichtenabrufs im Strategietester aus einer Ressource |
| ImportTesterLog.txt | Ergebnisse eines einzelnen Laufs des EA ImportCalendarValidation-EA.mq5 im Tester im visuellen Modus |
| LoadLiveLog.txt | Ergebnisse des Live-Ladens von Ereignissen durch den EA ImportCalendarValidation-EA.mq5 |
Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/22196
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Arbitragehandel im Forex-Markt: Ein Matrix-Handelssystem mit Rückkehr zum fairen Wert mit Risikokontrolle
Kamelalgorithmus (CA)
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Einsatz spieltheoretischer Ansätze in Handelsalgorithmen
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.

Geschrieben von:
Korrigieren Sie mich, wenn sich in der MQL5-API etwas geändert hat, aber früher wurde der Kalender an die aktuelle Zeitzone unter Berücksichtigung der Sommerzeit angepasst, d.h. im Sommer geben Funktionsanfragen Zeitstempel z.B. in der UTC+3-Zone zurück, während eine Anfrage desselben Verlaufsabschnitts im Winter Ereignisse mit Stempeln in der UTC+2-Zone erhält, wenn der Server auf Sommerzeit umschaltet und umgekehrt. Um also einen Kalenderverlauf für sechs Monate oder länger hochzuladen, müssen Sie den Verlauf der Zeitzonenumstellung des Brokers analysieren. Weitere Einzelheiten in der Codobase.
Auch der Ansatz, den Kalender-Cache als Ressource zu verknüpfen, erscheint wenig praktikabel und provoziert vor allem die im Artikel selbst erwähnten Fehler (z. B. vergessen Sie nicht, den EA neu zu kompilieren). Warum nicht den Kalender-Cache im Input-Parameter als Datei aus dem Common-Ordner für alle Agenten verfügbar machen?
und warum werden die Kurse (im Allgemeinen alle Zeitstempel) nicht in UTC gehalten?
warum haben die Ticks der Händler unterschiedliche numerische Darstellungen ein und derselben Zeitreferenz?
eine philosophische Frage :-) es ist die Art und Weise, wie es gemacht wird, obwohl es falsch ist und Probleme vor Ort verursacht.
ZЫ. "Historische Neuigkeiten" sollte man also besser aus anderen Quellen entnehmen.
Und man muss nie "die Geschichte der Uhrenumrechnung analysieren" - es ist alles da, es ist eine Funktion des Betriebssystems oder der Systembibliotheken. Google tzdata
wie viele Fahrräder hergestellt werden können, und noch dazu krumme
Bisher wurde der Kalender unter Berücksichtigung der Sommerzeit an die aktuelle Zeitzone angepasst, d.h. im Sommer werden bei Funktionsanfragen z.B. Zeitstempel in der Zone UTC+3 zurückgegeben, und eine Anfrage für denselben Abschnitt der Historie im Winter liefert Ereignisse mit Stempeln in der Zone UTC+2, wenn der Server auf Sommerzeit und zurück umschaltet.
ZЫ. "Historische Nachrichten" sollte man also besser aus anderen Quellen entnehmen.
Und man sollte niemals selbst "die Geschichte der Uhrenübersetzung analysieren" - es ist alles da, es ist eine Funktion des Betriebssystems oder der Systembibliotheken. Google tzdata
wie viele Fahrräder hergestellt werden können, und dazu noch krumme
Andere Quellen werden das Problem nicht lösen, denn es liegt in der Art und Weise begraben, wie Zitate in MT5 gespeichert werden.
Zeigen Sie zuerst Ihr gerades Fahrrad, und geben Sie dann Ratschläge.
Die Hauptprobleme des modernen Nachrichtenhändlers sind das fragmentierte Instrumentarium und das Fehlen eines systematischen, algorithmischen Handelsablaufs. Es ist ziemlich schwierig, seine Aufmerksamkeit zwischen dem Internetbrowser (Surfen auf Nachrichtenseiten) und dem Handelsterminal aufzuteilen, während man Geschäfte tätigt.
Der Arbeitsablauf eines Nachrichtenhändlers sieht folgendermaßen aus: Schnelles Öffnen des Nachrichtenkalenders in Ihrem Webbrowser und Prüfen auf Änderungen bei den Ereignissen → Schnelles Bewerten der anstehenden Ereignisse und Entscheiden, was und wie gehandelt werden soll → Zum MetaTrader 5-Terminal gehen - entweder Pending Orders platzieren oder am Terminal sitzen und auf die Nachrichtenmeldung warten, um eine Entscheidung zu treffen. In diesem Szenario geht dem Händler oft der Kontext verloren, was zu Verzögerungen bei der Reaktion auf Nachrichten führt, was wiederum Verluste zur Folge hat.
Möchten Sie, dass der Nachrichtenhandel wie ein technisches Problem funktioniert - mit klaren Regeln, wiederholbaren Ergebnissen und automatischen Tests? Der Zweck dieses Artikels ist es, die funktionierende Architektur einer Nachrichtenschicht für MetaTrader 5 zu demonstrieren: eine einzige Datenquelle, die korrekte Verwendung der Kalender-API, ein Filter- und Zwischenspeichermechanismus, der Export historischer Ereignisse in eine Ressource für den Tester und das automatische Umschalten zwischen Live und Tester - so dass derselbe Code sowohl in Echtzeit als auch bei historischen Daten deterministische Ergebnisse liefert.
Ja, das ist ein echter Schmerzpunkt für den Nachrichtenhandel.
Das Umschalten zwischen Browser, Kalender und Terminal unterbricht den Fokus und verlangsamt die Reaktionen erheblich. Ein einheitlicher Workflow oder ein System, das die Nachrichten direkt in die Handelsumgebung zieht, würde die Ausführung definitiv schneller und konsistenter machen.
Die Idee, dies in ein strukturiertes, wiederholbares "ingenieurmäßiges" Setup mit Tests und Automatisierung umzuwandeln, macht tatsächlich viel Sinn, um emotionale oder verzögerte Entscheidungen zu vermeiden.