
Nachrichtenhandel leicht gemacht (Teil 6): Ausführen des Handels (III)
Einführung
In diesem Artikel werden wir Verbesserungen an der Speicherdatenbank vornehmen. Es werden neue Ansichten hinzugefügt, um Daten zu präsentieren, wie z. B. die Anzeige von Daten für das letzte Nachrichtenereignis oder das nächste Nachrichtenereignis für jedes einzelne Ereignis im MQL5-Wirtschaftskalender - dies wird die Erfahrung des Nutzers bei der Verwendung des Programms verbessern, da es ihn auf zukünftige oder vergangene Ereignisse aufmerksam macht. Darüber hinaus wird das Experten-Eingabemenü um die Nachrichtenfilterung und die Stop-Order-Eingabemethoden erweitert.
Außerdem wird der Expertencode aktualisiert, um den früheren Code zu verwenden, der zur Verringerung der Expertenlaufzeit im Strategietester aus dem Artikel „Nachrichtenhandel leicht gemacht (Teil 4): Leistungsverbesserung“ geschrieben wurde, sowie den Code aus dem Artikel „Nachrichtenhandel leicht gemacht (Teil 5): Ausführen des Handels (II)“ wo wir Slippage und offene Stop-Orders verwalten.
Nachrichteneinstellungen Eingaben
- SELECT NEWS OPTION: Diese Option dient dazu, verschiedene Nachrichtenprofile zu ermöglichen. Die verschiedenen Profile sind:
- NEWS SETTINGS: In diesem Nachrichtenprofil kann der Nutzer/Händler die Nachrichten nach seinen Wünschen filtern, basierend auf:
- CALENDAR IMPORTANCE (Bedeutung)
- EVENT FREQUENCY (Häufigkeit)
- EVENT SECTOR (Sektor)
- EVENT TYPE (Typ)
- EVENT CURRENCY (Währung)
- CUSTOM NEWS EVENTS: In diesem Nachrichtenprofil kann der Nutzer/Händler Nachrichtenereignisse nach seinen Wünschen filtern, abhängig von den als Eingabe eingegebenen Ereignis-IDs, mit bis zu 14 Ereignis-IDs pro Eingabe.
Handelseinstellungen Eingaben
- SELECT TRADE ENTRY OPTION: Der Zweck dieser Option besteht darin, verschiedene Einstiegsmethoden für den Handel zu ermöglichen. Diese Methoden sind:
- MARKET POSITION: Bei dieser Methode erfolgt der Handel nur durch Marktausführung (Kauf oder Verkauf). Die Hauptanforderung ist, dass jedes Nachrichtenereignis, das für die Auswahl des Handelseinstiegs ausgewählt wird, eine Auswirkung auf das Ereignis haben muss, um die Richtung des Handels (Kauf oder Verkauf) im Voraus zu kennen.
- STOP ORDERS: Bei dieser Methode werden Handelsgeschäfte nur mit einem Buy-Stop- und Sell-Stop-Auftrag ausgeführt, bevor ein ausgewähltes Nachrichtenereignis eintritt. Die Hauptanforderung besteht darin, dass der Nutzer/Händler eine Preisabweichung festlegen sollte, damit der Experte einen Preispuffer hat, um die Buy-Stop- und Sell-Stop-Order zu platzieren. Sobald der Buy-Stop oder Sell-Stop ausgelöst wird, wird der entgegengesetzte Auftrag gelöscht. Wenn zum Beispiel die Buy-Stop- und Sell-Stop-Order vor dem NFP (Nachrichtenereignis) platziert wird und die Buy-Stop-Order ausgelöst wird, was bedeutet, dass eine Kaufposition ausgeführt wird, sobald ein bestimmter Preis erreicht wird, wird der Experte die verbleibende Sell-Stop-Order aktiv löschen. Bei dieser Methode ist es nicht erforderlich, dass ein Ereignis Auswirkungen auf die Platzierung von Handelsgeschäften im Vorfeld hat.
- SINGLE STOP ORDER: Bei dieser Methode werden Handelsgeschäfte nur mit einem Buy-Stop- oder Sell-Stop-Auftrag ausgeführt. Die beiden wichtigsten Anforderungen sind:
- Jedes Nachrichtenereignis, das für den Handel in dieser Auswahl für den Handelseinstieg ausgewählt wird, muss eine Auswirkung auf das Ereignis haben, um die Richtung des Auftrags (Kauf-Stopp oder Verkaufs-Stopp) im Voraus zu kennen.
- Der Nutzer/Händler sollte eine Preisabweichung festlegen, damit der Experte einen Preispuffer hat, um entweder den Kauf-Stopp oder den Verkauf-Stopp-Auftrag zu platzieren.
Die Klasse der Nachrichten
In dieser Header-Datei mit dem Namen News.mqh werden wir eine Enumeration namens NewsSelection außerhalb der Klasse CNews deklarieren. Der Zweck dieser Enumeration ist es, den Nutzern/Händlern die Möglichkeit zu geben, verschiedene Nachrichtenprofile innerhalb der Experteneingabe auszuwählen. Außerdem werden wir eine Variable namens myNewsSelection haben, die die bevorzugte Auswahl des Nutzers/Händlers speichern wird. Außerdem wird eine Struktur namens CustomEvent deklariert. Diese Struktur speichert den booleschen Wert, der darüber entscheidet, ob nach den Ereignis-IDs im String-Array EventIds innerhalb der Struktur gefiltert werden soll. Darüber hinaus werden in der Struktur Variablen wie CEvent1 deklariert, diese Variable fungiert als 1 von 5 Möglichkeiten, mit denen der Benutzer/Händler benutzerdefinierte Ereignis-IDs filtern kann.
Enumerationen:
- NewsSelection: Definiert zwei Profile:
- News_Select_Custom_Events: Für nutzerdefinierte Nachrichtenereignisse.
- News_Select_Settings: Für Nachrichteneinstellungen.
- myNewsSelection ist eine Variable dieses Enum-Typs, die die aktuelle Auswahl des Nachrichtenprofils speichert.
Strukturen:
- NutzerdefiniertesEreignis: Eine Struktur zum Speichern von nutzerdefinierten Ereignis-IDs und ein Flag (useEvents), das angibt, ob diese Ereignisse in die Abfrage einbezogen werden sollen.
- Es gibt fünf Variablen: CEvent1, CEvent2, CEvent3, CEvent4 und CEvent5 des Typs CustomEvent, die jeweils eine eigene Gruppe von Ereignissen darstellen.
//--- Enumeration for News Profiles enum NewsSelection { News_Select_Custom_Events,//CUSTOM NEWS EVENTS News_Select_Settings//NEWS SETTINGS } myNewsSelection; //--- Structure to store event ids and whether to use these ids struct CustomEvent { bool useEvents; string EventIds[]; } CEvent1,CEvent2,CEvent3,CEvent4,CEvent5;
Enumeration CalendarComponents:
- KalenderKomponenten: Zählt verschiedene Komponenten des Wirtschaftskalenders auf, wie z. B. Tabellen und Ansichten, die zur Strukturierung von Daten im Zusammenhang mit Sommerzeitplänen, Ereignisinformationen und Währungsdaten verwendet werden.
Innerhalb der CalendarComponents-Enumeration haben wir zwei neue Werte hinzugefügt:
- RecentEventInfo_View
- UpcomingEventInfo_View
//-- To keep track of what is in our database enum CalendarComponents { // ... RecentEventInfo_View,//View for Recent Dates For Events UpcomingEventInfo_View,//View for Upcoming Dates For Events // ... };
Die Funktion GetCalendar(CalendarData &Data[]):
- Diese Funktion ruft alle relevanten Kalenderdaten aus der Kalenderdatenbank im Speicher ab und speichert sie im Array „Data“.
- Sie öffnet eine Datenbank (NEWS_DATABASE_FILE) und führt eine SQL-Abfrage auf der Grundlage der aktuellen Nachrichtenauswahl (myNewsSelection) aus.
- Je nachdem, ob News_Select_Custom_Events oder News_Select_Settings ausgewählt ist, wird eine andere SQL-Abfrage zum Abrufen von Ereignisinformationen generiert.
- Nutzerdefinierte Ereignisse: Verbindet die MQL5Calendar-Tabelle und die TimeSchedule-Tabelle, um nutzerdefinierte Nachrichtenereignisse mit einem Filter auf der Grundlage von nutzerdefinierten Ereignis-IDs abzurufen.
- Nachrichteneinstellungen: Ruft Ereignisdaten gefiltert nach nutzerdefinierten Einstellungen wie Wichtigkeit, Häufigkeit, Sektor, Typ und Währung ab.
- Die Funktion verarbeitet die Ergebnisse der SQL-Abfrage und speichert die abgerufenen Daten im Array „Data“.
- Wenn die Datenbankabfrage fehlschlägt, werden ein Fehler und die fehlgeschlagene SQL-Abfrage ausgegeben.
//--- Will Retrieve all relevant Calendar data for DB in Memory from DB in Storage void GetCalendar(CalendarData &Data[]) { // ... string SqlRequest; //--- switch statement for different News Profiles switch(myNewsSelection) { case News_Select_Custom_Events://CUSTOM NEWS EVENTS //--- Get filtered calendar DB data SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID Where %s OR %s OR %s OR %s OR %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Events(CEvent1),Request_Events(CEvent2),Request_Events(CEvent3), Request_Events(CEvent4),Request_Events(CEvent5)); break; case News_Select_Settings://NEWS SETTINGS //--- Get filtered calendar DB data SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency," "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency," "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ " "Inner Join %s TS on TS.ID=MQ.ID " "Where %s and %s and %s and %s and %s;", CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name, Request_Importance(myImportance),Request_Frequency(myFrequency), Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency)); break; default://Unknown break; } // ...
Die Funktion Request_Events(CustomEvent &CEvent):
- Diese Funktion generiert eine SQL WHERE-Klausel zur Abfrage der Datenbank auf der Grundlage der in der CustomEvent-Struktur gespeicherten nutzerdefinierten Ereignis-IDs.
- Sie prüft, ob useEvents wahr ist. Wenn ja, wird jede Ereignis-ID aus dem Array CEvent.EventIds[] zur SQL-Abfrage hinzugefügt.
//--- Retrieve Sql request string for custom event ids string Request_Events(CustomEvent &CEvent) { //--- Default request string string EventReq="MQ.EventId='0'"; //--- Check if this Custom event should be included in the SQL request if(CEvent.useEvents) { //--- Get request for first event id EventReq=StringFormat("(MQ.EventId='%s'", (CEvent.EventIds.Size()>0)? CEvent.EventIds[0]:"0"); //--- Iterate through remaining event ids and add to the SQL request for(uint i=1;i<CEvent.EventIds.Size();i++) { EventReq+=StringFormat(" OR MQ.EventId='%s'",CEvent.EventIds[i]); } EventReq+=")"; } //--- Return SQL request for custom event ids return EventReq; }
Öffentliche Klassenmitglieder:
Für diese Funktionen werden Aktualisierungen vorgenommen: EconomicDetailsMemory,EconomicNextEvent und isEvent.
- EconomicDetailsMemory: Holt die Werte aus der In-Memory-Kalenderdatenbank.
- EconomicNextEvent: Aktualisiert die Strukturvariable mit den Daten des nächsten Ereignisses.
- isEvent: Prüft, ob ein Nachrichtenereignis ansteht und ändert die übergebenen Parameter entsprechend.
//Public declarations accessable via a class's Object public: // ... void EconomicDetailsMemory(Calendar &NewsTime[],datetime date,bool ImpactRequired);//Gets values from the MQL5 DB Calendar in Memory void EconomicNextEvent();//Will update UpcomingNews structure variable with the next event data // ... //--- Checks if a news event is occurring and modifies the parameters passed by reference bool isEvent(uint SecondsPreEvent,string &Name,string &Importance,string &Code);
Die Funktion EconomicDetailsMemory dient dazu, Ereignisdaten des Wirtschaftskalenders aus einer In-Memory-Datenbank (DBMemory) für ein bestimmtes Datum abzurufen, optional unter Berücksichtigung der Ereignisauswirkungen, und speichert die Daten in einem Array NewsTime[].
- Die Funktion holt für ein bestimmtes Datum wirtschaftliche Ereignisdetails aus einer Datenbank und speichert sie im Array NewsTime[].
- Wenn ImpactRequired wahr ist, werden die vorherigen und prognostizierten Werte des Ereignisses abgerufen und die Auswirkungen auf der Grundlage historischer Daten zugewiesen.
- Wenn ImpactRequired falsch ist, werden einfach die Daten des aktuellen Tages und des nächsten Ereignisses abgerufen.
- Die Ergebnisse werden mithilfe einer vorbereiteten SQL-Abfrage abgerufen und im Array NewsTime[] gespeichert, dessen Größe dynamisch auf der Grundlage der Anzahl der abgerufenen Ereignisse angepasst wird.
//+------------------------------------------------------------------+ //|Gets values from the MQL5 DB Calendar in Memory | //+------------------------------------------------------------------+ void CNews::EconomicDetailsMemory(Calendar &NewsTime[],datetime date,bool ImpactRequired) { //--- SQL query to retrieve news data for a certain date string request_text; //--- Check if Event impact is required for retrieving news events if(ImpactRequired) { request_text=StringFormat("WITH DAILY_EVENTS AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as" " 'Type',M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE" " as 'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE'," "M.EVENTFREQUENCY as 'Freq' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))=DATE(REPLACE('%s','.','-'))" " AND (Forecast<>'None' AND Prevalue<>'None')),DAILY_IMPACT AS(SELECT DE.E_ID,DE.COUNTRY,DE.Name," "DE.Type,DE.Importance,DE.Time,DE.Currency,DE.Code,DE.Sector,DE.Forecast,DE.Prevalue,DE.Freq," "MC.EVENTIMPACT as 'IMPACT', RANK() OVER(PARTITION BY DE.E_ID,DE.Time ORDER BY MC.%s DESC)DateOrder" " FROM %s MC INNER JOIN DAILY_EVENTS DE on DE.E_ID=MC.EVENTID WHERE DATE(REPLACE(MC.%s,'.','-'))<" "DATE(REPLACE(DE.Time,'.','-')) AND DATE(REPLACE(MC.%s,'.','-'))>=DATE(REPLACE(DE.Time,'.','-')," "'-24 months') AND (MC.EVENTFORECAST<>'None' AND MC.EVENTPREVALUE<>'None' AND (CASE WHEN Forecast>" "Prevalue THEN 'more' WHEN Forecast<Prevalue THEN 'less' ELSE 'equal' END)=(CASE WHEN MC.EVENTFORECAST" ">MC.EVENTPREVALUE THEN 'more' WHEN MC.EVENTFORECAST<MC.EVENTPREVALUE THEN 'less' ELSE 'equal' END)) " "ORDER BY MC.%s),DAILY_EVENTS_RECORDS AS(SELECT * FROM DAILY_IMPACT WHERE DateOrder=1 ORDER BY Time" " ASC),NEXT_EVENT AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as 'Type'," "M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE as 'Code'," "M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE',M.EVENTFREQUENCY" " as 'Freq' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))>DATE(REPLACE('%s','.','-')) AND (Forecast<>" "'None' AND Prevalue<>'None' AND DATE(REPLACE(Time,'.','-'))<=DATE(REPLACE('%s','.','-'),'+60 days')))," "NEXT_IMPACT AS(SELECT NE.E_ID,NE.COUNTRY,NE.Name,NE.Type,NE.Importance,NE.Time,NE.Currency,NE.Code" ",NE.Sector,NE.Forecast,NE.Prevalue,NE.Freq,MC.EVENTIMPACT as 'IMPACT',RANK() OVER(PARTITION BY " "NE.E_ID,NE.Time ORDER BY MC.%s DESC)DateOrder FROM %s MC INNER JOIN NEXT_EVENT NE on NE.E_ID=MC.EVENTID " "WHERE DATE(REPLACE(MC.%s,'.','-'))<DATE(REPLACE(NE.Time,'.','-')) AND DATE(REPLACE(MC.%s,'.','-'))>=" "DATE(REPLACE(NE.Time,'.','-'),'-24 months') AND (MC.EVENTFORECAST<>'None' AND MC.EVENTPREVALUE<>'None'" " AND (CASE WHEN Forecast>Prevalue THEN 'more' WHEN Forecast<Prevalue THEN 'less' ELSE 'equal' END)=" "(CASE WHEN MC.EVENTFORECAST>MC.EVENTPREVALUE THEN 'more' WHEN MC.EVENTFORECAST<MC.EVENTPREVALUE THEN " "'less' ELSE 'equal' END)) ORDER BY MC.%s),NEXT_EVENT_RECORD AS(SELECT * FROM NEXT_IMPACT WHERE " "DateOrder=1 ORDER BY Time ASC LIMIT 1),ALL_EVENTS AS(SELECT * FROM NEXT_EVENT_RECORD UNION ALL " "SELECT * FROM DAILY_EVENTS_RECORDS)SELECT E_ID,Country,Name,Type,Importance,Time,Currency,Code," "Sector,Forecast,Prevalue,Impact,Freq FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;", EnumToString(MySchedule),DBMemory.name,TimeToString(date),EnumToString(MySchedule),DBMemory.name, EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule) ,DBMemory.name,TimeToString(date),TimeToString(date),EnumToString(MySchedule),DBMemory.name, EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule)); } else { /* Within this request we select all the news events that will occur or have occurred in the current day and the next news event after the current day */ request_text=StringFormat("WITH DAILY_EVENTS AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as" " 'Type',M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE" " as 'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE'" ",M.EVENTFREQUENCY as 'Freq',M.EVENTIMPACT as 'Impact' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))" "=DATE(REPLACE('%s','.','-'))),DAILY_EVENTS_RECORDS AS(SELECT * FROM DAILY_EVENTS ORDER BY Time ASC)" ",NEXT_EVENT AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as 'Type'," "M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE as " "'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE'," "M.EVENTFREQUENCY as 'Freq',M.EVENTIMPACT as 'Impact' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))" ">DATE(REPLACE('%s','.','-')) AND (DATE(REPLACE(Time,'.','-'))<=DATE(REPLACE('%s','.','-')," "'+60 days'))),NEXT_EVENT_RECORD AS(SELECT * FROM NEXT_EVENT ORDER BY Time ASC LIMIT 1)," "ALL_EVENTS AS(SELECT * FROM NEXT_EVENT_RECORD UNION ALL SELECT * FROM " "DAILY_EVENTS_RECORDS)SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;", EnumToString(MySchedule),DBMemory.name,TimeToString(date),EnumToString(MySchedule),DBMemory.name, TimeToString(date),TimeToString(date)); } // ...
Die Funktion Signature
- Argumente:
- Calendar &NewsTime[]: Ein Array von Kalender-Strukturen (die jeweils Ereignisdetails enthalten), die mit den abgerufenen Daten gefüllt werden.
- datetime date: Das spezifische Datum, für das wirtschaftliche Ereignisse abgerufen werden.
- bool ImpactRequired: Ein Flag, das angibt, ob die Auswirkungen des Ereignisses bei der Abfrage berücksichtigt werden sollen.
SQL-Query-Konstruktion auf der Grundlage von Impact-Anforderungen
Die SQL-Abfrage unterscheidet sich je nachdem, ob ImpactRequired auf true oder false gesetzt ist. Wenn wahr, erfordern die Nachrichtenereignisse eine Ereignisauswirkung für die Handelsrichtung für das Ereignis, wenn falsch, ist die Ereignisauswirkung nicht erforderlich, da die Ereignisrichtung nicht notwendig ist, um einen Handel zu eröffnen.
A. Wenn ImpactRequired wahr ist
Diese Abfrage ist komplexer und umfasst mehrere Teile:
- Die Abfrage ruft wirtschaftliche Ereignisse für das angegebene Datum ab und berücksichtigt auch das nächste Ereignis, das nach dem aktuellen Tag ansteht.
- Sie sucht nach früheren Ereignissen innerhalb der letzten 24 Monate, für die sowohl „forecast“ als auch „prevalue“ verfügbar sind, und vergleicht sie mit dem aktuellen Ereignis.
- Ist forecast größer als der prevalue (oder umgekehrt) oder sogar gleich, wird er mit dem historischen Ereignis mit demselben Trend (forecast > prevalue oder forecast < prevalue oder forecast = prevalue) abgeglichen.
- Sie ordnet die Ereignisauswirkungen des vergangenen Ereignisses dem aktuellen Ereignis zu.
Hier ist ein Überblick über den Aufbau der Abfrage:
"WITH DAILY_EVENTS AS(...) , DAILY_IMPACT AS(...) , NEXT_EVENT AS(...), NEXT_IMPACT AS(...),
ALL_EVENTS AS(...) SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;"
- DAILY_EVENTS: Wählt alle wirtschaftlichen Ereignisse für das angegebene Datum aus dem Kalender aus. Es werden Ereignisse mit einem gültigen „Forecast“ und „Prevalue“ ausgewählt.
- DAILY_IMPACT: Damit werden historische Ereignisse (innerhalb der letzten 24 Monate) gefunden, bei denen der Trend von „Forecast“ und „Prevalue“ (größer/kleiner oder gleich) dem aktuellen Ereignis ähnlich ist. Es ordnet die Ereignisse nach Datum, um das jüngste passende Ereignis zu finden, und ordnet dessen Auswirkungen dem aktuellen Ereignis zu.
- NEXT_EVENT: Wählt das nächste anstehende Ereignis nach dem aktuellen Tag aus.
- NEXT_IMPACT: Ähnlich wie bei DAILY_IMPACT wird das jüngste Ereignis der Vergangenheit abgerufen, das dem Trend forecast/prevalue entspricht, und seine Auswirkungen werden dem nächsten Ereignis zugeordnet.
- ALL_EVENTS: Kombiniert DAILY_EVENTS_RECORDS (für den aktuellen Tag) und NEXT_EVENT_RECORD (für das nächste Ereignis) und ordnet sie nach Zeit.
B. Wenn ImpactRequired falsch ist
Wenn die Auswirkungen nicht erforderlich sind, ist die Abfrage einfacher:
- Es werden alle Ereignisse für den aktuellen Tag und das nächste Ereignis nach dem aktuellen Tag (innerhalb von 60 Tagen) abgerufen.
Die Gliederung der SQL-Abfrage:
"WITH DAILY_EVENTS AS(...) , NEXT_EVENT AS(...), ALL_EVENTS AS(...) SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;"
- DAILY_EVENTS: Ruft die wirtschaftlichen Ereignisse für den aktuellen Tag ab.
- NEXT_EVENT: Ruft das nächste anstehende Ereignis nach dem aktuellen Tag innerhalb der nächsten 60 Tage ab.
- ALL_EVENTS: Kombiniert sowohl die täglichen Ereignisse als auch das nächste Ereignis und ordnet sie nach Zeit.
Ausführung von SQL-Abfragen
int request = DatabasePrepare(DBMemoryConnection, request_text);
- DatabasePrepare: Bereitet die SQL-Abfrage für die Ausführung vor. Das Ergebnis wird in request gespeichert, das ein Handle zur Abfrage ist. Dieses Handle wird zum Abrufen der Daten verwendet.
- Fehlerbehandlung: Wenn die Anfrage fehlschlägt (request == INVALID_HANDLE), werden die Fehlermeldung und die SQL-Abfrage zu Debugging-Zwecken ausgegeben.
Lesen der Ergebnisse
Calendar ReadDB_Data; ArrayRemove(NewsTime, 0, WHOLE_ARRAY); for (int i = 0; DatabaseReadBind(request, ReadDB_Data); i++) { ArrayResize(NewsTime, i + 1, i + 2); NewsTime[i] = ReadDB_Data; }
- ArrayRemove: Löscht das Array NewsTime[], um es für neue Daten vorzubereiten.
- DatabaseReadBind: Holt die Ergebnisse aus der vorbereiteten Abfrage und bindet jede Ergebniszeile an die ReadDB_Data-Variable, die eine Kalenderstruktur ist.
- ArrayResize: Ändert die Größe des Arrays NewsTime[], um die neuen Daten aufzunehmen. Für jede Zeile, die von DatabaseReadBind zurückgegeben wird, wächst das Array um 1 Element.
- NewsTime[i] = ReadDB_Data: Kopiert die abgerufenen Daten in das Array NewsTime[].
Fertigstellung der Abfrage
DatabaseFinalize(request);
- DatabaseFinalize: Räumt die von DatabasePrepare zugewiesenen Ressourcen auf und gibt das Abfragehandle frei.
Die Funktion EconomicNextEvent hat die Aufgabe, das nächste anstehende Wirtschaftsereignis zu ermitteln und die Variable UpcomingNews mit dessen Einzelheiten zu aktualisieren.
- Die Funktion durchsucht alle Ereignisse im CalendarArray und findet anhand der Serverzeit (TimeTradeServer()) das nächste anstehende Ereignis.
- Sie aktualisiert die Struktur UpcomingNews mit den Details dieses nächsten Ereignisses.
- Die Logik stellt sicher, dass nur zukünftige Ereignisse (in Bezug auf die Serverzeit) berücksichtigt werden, und dass das nächstliegende Ereignis ausgewählt wird.
//+------------------------------------------------------------------+ //|Will update UpcomingNews structure variable with the next news | //|event data | //+------------------------------------------------------------------+ void CNews::EconomicNextEvent() { //--- Declare unassigned Calendar structure variable Next Calendar Next; //--- assign empty values to Calendar structure variable UpcomingNews UpcomingNews = Next; //--- assign default date datetime NextEvent=0; //--- Iterate through CalendarArray to retrieve news events for(uint i=0;i<CalendarArray.Size();i++) { //--- Check for next earliest news event from CalendarArray if((NextEvent==0)||(TimeTradeServer()<datetime(CalendarArray[i].EventDate) &&NextEvent>datetime(CalendarArray[i].EventDate))||(NextEvent<TimeTradeServer())) { //--- assign values from the CalendarArray NextEvent = datetime(CalendarArray[i].EventDate); Next = CalendarArray[i]; } } //--- assign the next news event data into UpcomingNews variable UpcomingNews = Next; }
Nicht zugeordnete Kalenderstruktur deklarieren
Calendar Next;
- Die Variable Next wird als Kalenderstruktur deklariert (eine nutzerdefinierte Struktur, die Ereignisdetails wie Datum, Name, Land usw. enthält).
- Sie ist zunächst nicht zugewiesen und wird später die Daten des nächsten wirtschaftlichen Ereignisses enthalten.
Leere Werte an UpcomingNews zuweisen
UpcomingNews = Next;
- UpcomingNews ist eine globale Variable oder eine Variable auf Klassenebene (eine weitere Calendar-Struktur), die die Details des nächsten bevorstehenden Ereignisses speichert.
- Beim Start wird sie auf die Standardwerte (leere Werte) der Variablen Next zurückgesetzt.
Standarddatum zuweisen
datetime NextEvent = 0;
- Die Variable NextEvent ist auf 0 initialisiert, was bedeutet, dass noch kein Ereignis zugewiesen wurde.
- NextEvent speichert den Zeitstempel (im Datetime-Format) des nächsten wirtschaftlichen Ereignisses in der Schleife.
Iterieren durch CalendarArray
for (uint i = 0; i < CalendarArray.Size(); i++)
- CalendarArray ist ein Array, das die Details der wirtschaftlichen Ereignisse enthält.
- Die for-Schleife durchläuft jedes Element dieses Arrays (das jeweils ein Ereignis darstellt) und prüft, ob das Ereignis als das nächste anstehende Ereignis gilt.
Bedingungen für das nächste Ereignis prüfen
if ((NextEvent == 0) || (TimeTradeServer() < datetime(CalendarArray[i].EventDate) && NextEvent > datetime(CalendarArray[i].EventDate)) || (NextEvent < TimeTradeServer()))
Diese if-Anweisung überprüft mehrere Bedingungen, um festzustellen, ob das aktuelle Ereignis im Array (CalendarArray[i]) das nächste Nachrichtenereignis ist:
- Erste Bedingung: (NächstesEreignis == 0)
- Wenn NextEvent immer noch 0 ist (es wurde noch kein Ereignis zugewiesen), wird das aktuelle Ereignis als nächstes Ereignis ausgewählt.
- Zweite Bedingung: (TimeTradeServer() < datetime(CalendarArray[i].EventDate) && NextEvent > datetime(CalendarArray[i].EventDate))
- Dies prüft, ob das aktuelle Ereignis im Array (CalendarArray[i]) nach der aktuellen Serverzeit (TimeTradeServer()) stattfindet und vor dem aktuell in NextEvent gespeicherten Ereignis liegt. Wenn true, wird das aktuelle Ereignis zum nächsten Ereignis.
- Dritte Bedingung: (NextEvent < TimeTradeServer())
- Wenn das aktuell in NextEvent gespeicherte Ereignis bereits eingetreten ist (in der Vergangenheit liegt), fährt die Funktion mit der Suche nach einem gültigen zukünftigen Ereignis fort.
Werte aus dem CalendarArray zuweisen
NextEvent = datetime(CalendarArray[i].EventDate);
Next = CalendarArray[i];
- Wenn eine der Bedingungen erfüllt ist, wird das aktuelle Ereignis in CalendarArray[i] als Nächstes Ereignis bestimmt:
- NextEvent wird auf das Ereignisdatum des aktuellen Ereignisses aktualisiert.
- Next wird aktualisiert, um alle Details (Datum, Name, Typ usw.) des aktuellen Ereignisses zu enthalten.
Das nächste Ereignis UpcomingNews zuweisen
UpcomingNews = Next;
- Nachdem die Schleife die Iteration durch CalendarArray beendet hat, wird die Variable UpcomingNews mit den Details des nächsten anstehenden Ereignisses (gespeichert in Next) aktualisiert.
- Die Funktion sorgt dafür, dass das erste gefundene zukünftige Ereignis, bezogen auf die aktuelle Serverzeit, in UpcomingNews gespeichert wird.
In der Funktion isEvent wird geprüft, ob ein Nachrichtenereignis in Kürze eintritt oder gerade innerhalb eines bestimmten Zeitraums eintritt. Der Zweck dieser Funktion ist es, anhand eines Zeitversatzes zu prüfen, ob ein Nachrichtenereignis aus dem CalendarArray gerade stattfindet oder kurz bevorsteht. Wenn ein solches Ereignis gefunden wird, werden Details über das Ereignis wie Name, Bedeutung und Code angezeigt.
- Diese Funktion durchläuft das CalendarArray (das die Daten der Wirtschaftsereignisse enthält) und prüft, ob ein Ereignis innerhalb eines durch SecondsPreEvent definierten Zeitraums eintritt oder in Kürze eintreten wird.
- Wenn ein solches Ereignis gefunden wird, werden Name, Bedeutung und Code mit den Details des Ereignisses aktualisiert und true zurückgegeben.
- Wird innerhalb des definierten Zeitraums kein Ereignis gefunden, wird false zurückgegeben und Name, Wichtigkeit und Code bleiben unverändert (oder werden auf default/NULL gesetzt).
//+------------------------------------------------------------------+ //|Checks if News is event is about to occur or is occurring | //+------------------------------------------------------------------+ bool CNews::isEvent(uint SecondsPreEvent,string &Name,string &Importance,string &Code) { //--- assign default value Name=NULL; //--- Iterate through CalendarArray for(uint i=0;i<CalendarArray.Size();i++) { //--- Check if news event is within a timespan if(CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate),SecondsPreEvent), CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate),59))) { //--- assign appropriate CalendarArray values Name=CalendarArray[i].EventName; Importance=CalendarArray[i].EventImportance; Code=CalendarArray[i].EventCode; //--- news event is currently within the timespan return true; } } //--- no news event is within the current timespan. return false; }
Parameter:
- uint SecondsPreEvent: Die Anzahl der Sekunden vor dem Ereignis, in denen das Ereignis als „bevorstehend“ gilt.
- string &Name: Ein Verweis auf eine Zeichenkette, die den Namen des Ereignisses speichert, wenn es innerhalb des festgelegten Zeitraums liegt.
- string &Importance: Ein Verweis auf eine Zeichenkette, in der die Wichtigkeitsstufe des Ereignisses gespeichert wird, falls sie gefunden wird.
- string &Code: Ein Verweis auf eine Zeichenkette, in der der Ereigniscode gespeichert wird.
Standardwert dem Namen zuweisen
Name = NULL;
- Die Variable Name wird mit NULL initialisiert. Wenn innerhalb des angegebenen Zeitraums kein Ereignis gefunden wird, bleibt Name NULL.
- Dadurch wird sichergestellt, dass Name nur aktualisiert wird, wenn ein Ereignis innerhalb der Zeitspanne gefunden wird.
Iterieren durch CalendarArray
for (uint i = 0; i < CalendarArray.Size(); i++)
- Die Schleife durchläuft jedes Element im CalendarArray, wobei jedes Element ein Nachrichtenereignis darstellt.
- In der Schleife wird jedes Ereignis daraufhin überprüft, ob es in den angegebenen Zeitbereich um die aktuelle Zeit fällt.
Prüfen, ob das Ereignis innerhalb des Zeitbereichs liegt
if (CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate), SecondsPreEvent), CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate), 59)))
- CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate), SecondsPreEvent):
- Dieser Funktionsaufruf prüft, ob das Datum des Ereignisses (CalendarArray[i].EventDate) minus dem Wert SecondsPreEvent in der Vergangenheit liegt.
- Sie definiert im Wesentlichen die untere Grenze des Zeitfensters (wie viele Sekunden vor dem Ereignis).
- CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate), 59):
- Diese Funktion prüft, ob das Datum des Ereignisses plus 59 Sekunden in der Zukunft liegt, wodurch die obere Grenze des Zeitfensters definiert wird (wie lange das Ereignis als aktiv betrachtet wird).
- Die Funktion CTime.TimeIsInRange prüft, ob die aktuelle Zeit innerhalb dieses Zeitbereichs liegt. Liegt die aktuelle Uhrzeit innerhalb dieses Bereichs, bedeutet dies, dass das Ereignis kurz bevorsteht oder bereits eingetreten ist.
Werte aus CalendarArray zuweisen
Name = CalendarArray[i].EventName; Importance = CalendarArray[i].EventImportance; Code = CalendarArray[i].EventCode;
- Wenn das Ereignis innerhalb des angegebenen Zeitraums liegt, werden die relevanten Details (Ereignisname, Bedeutung und Code) aus dem CalendarArray extrahiert und den Referenzparametern zugewiesen:
- Name: Der Name des Nachrichtenereignisses.
- Importance: Der Wichtigkeitsgrad des Ereignisses.
- Code: Der Ereigniscode.
Gibt true zurück, wenn ein Ereignis gefunden wird
return true;
- Wird ein Nachrichtenereignis innerhalb der Zeitspanne gefunden, gibt die Funktion true zurück, was bedeutet, dass ein relevantes Ereignis gerade stattfindet oder kurz bevorsteht.
Return false wenn kein Ereignis gefunden wird
return false;
- Wenn die Schleife die Iteration durch alle Ereignisse in CalendarArray beendet und kein Ereignis innerhalb des angegebenen Zeitraums gefunden wird, gibt die Funktion false zurück, was bedeutet, dass kein relevantes Ereignis stattfindet.
Constructor CNews::CNews(void):
- Initialisiert die Klasse durch Einrichten von SQL DROP-, CREATE- und INSERT-Anweisungen für verschiedene Komponenten des Wirtschaftskalenders.
- Tables: Definiert Tabellen wie AutoDST, Record, TimeSchedule und MQL5Calendar.
- Views: Definiert Ansichten für verschiedene Sommerzeitpläne (Calendar_AU, Calendar_UK, etc.), Ereignisinformationen, Währungen und aktuelle/künftige Ereignisdaten.
- Triggers: Definiert Auslöser wie OnlyOne_AutoDST und OnlyOne_Record, um sicherzustellen, dass nur ein Datensatz in bestimmten Tabellen existiert.
Jede Komponente (Tables, Views oder Trigger) wird mit ihren jeweiligen SQL-Befehlen initialisiert, einschließlich des Erstellens, Einfügens und Löschens von Datensätzen.
SQL-Ansicht erstellen:
- Für jede DST-Zeitplan- und Kalenderkomponente werden spezifische SQL-Ansichten definiert, um Daten nach verschiedenen Kriterien zu strukturieren (z. B. nach Wichtigkeit des Ereignisses, Währung oder Datum des Ereignisses). Zum Beispiel:
- Ansicht für bevorstehende Ereignisse: Zeigt anstehende Ereignisstermine zusammen mit dem Wochentag und den Ereignissdetails an.
- Ansicht für aktuelle Ereignisse: Ähnlich wie bei den anstehenden Terminen, jedoch werden die letzten Termine abgerufen.
SQL-Trigger:
- Trigger werden verwendet, um sicherzustellen, dass in den Tabellen AutoDST und Record zu jedem Zeitpunkt nur ein Datensatz vorhanden ist, indem vorhandene Datensätze vor einem Einfügevorgang gelöscht werden.
//+------------------------------------------------------------------+ //|Constructor | //+------------------------------------------------------------------+ CNews::CNews(void):DropRequest("PRAGMA foreign_keys = OFF; " "PRAGMA secure_delete = ON; " "Drop %s IF EXISTS '%s'; " "Vacuum; " "PRAGMA foreign_keys = ON;")//Sql drop statement { // ... string views[] = {"AU","NONE","UK","US"}; //-- Sql statement for creating the table views for each DST schedule string view_sql = "CREATE VIEW IF NOT EXISTS Calendar_%s " "AS " "SELECT C.Eventid as 'ID',C.Eventname as 'Name',C.Country as 'Country', " "(CASE WHEN Date(REPLACE(T.DST_%s,'.','-'))<R.Date THEN CONCAT(T.DST_%s,' | Yesterday') " "WHEN Date(REPLACE(T.DST_%s,'.','-'))=R.Date THEN CONCAT(T.DST_%s,' | Today') " "WHEN Date(REPLACE(T.DST_%s,'.','-'))>R.Date THEN CONCAT(T.DST_%s,' | Tomorrow') END) as " "'Date',C.EventCurrency as 'Currency',Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','')" " as 'Importance' from MQL5Calendar C,Record R Inner join TimeSchedule T on C.ID=T.ID Where" " DATE(REPLACE(T.DST_%s,'.','-'))>=DATE(R.Date,'-1 day') AND DATE(REPLACE(T.DST_%s,'.','-'))" "<=DATE(R.Date,'+1 day') Order by T.DST_%s Asc;"; // ... //--- initializing properties for the EventInfo view CalendarContents[5].Content = EventInfo_View; CalendarContents[5].name = "Event Info"; CalendarContents[5].sql = "CREATE VIEW IF NOT EXISTS 'Event Info' " "AS SELECT DISTINCT MC.EVENTID as 'ID',MC.COUNTRY as 'Country',MC.EVENTNAME as 'Name'," "REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector'," "REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MC.EVENTCURRENCY as 'Currency'," "REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency',MC.EVENTCODE as 'Code' " "FROM MQL5Calendar MC ORDER BY \"Country\" Asc," "CASE \"Importance\" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,\"Sector\" Desc;"; CalendarContents[5].tbl_name = "Event Info"; CalendarContents[5].type = "view"; // ... //--- initializing properties for the UpcomingEventInfo view CalendarContents[7].Content = UpcomingEventInfo_View; CalendarContents[7].name = "Upcoming Event Dates"; CalendarContents[7].sql = "CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID'," "M.COUNTRY as 'Country',M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M)," "INFO_DATE AS(SELECT E_ID,Country,Name,Currency,(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M," "Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))>R.Date AND " "E_ID=M.EVENTID ORDER BY Time ASC LIMIT 1) as 'Next Event Date' FROM UNIQUE_EVENTS) SELECT E_ID " "as 'ID',Country,Name,Currency,(CASE WHEN \"Next Event Date\" IS NULL THEN 'Unknown' ELSE " "\"Next Event Date\" END) as 'Upcoming Date',(CASE WHEN \"Next Event Date\"<>'Unknown' THEN " "(case cast (strftime('%w', DATE(REPLACE(\"Next Event Date\",'.','-'))) as integer) WHEN 0 THEN" " 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday'" " WHEN 5 THEN 'Friday' ELSE 'Saturday' END) ELSE 'Unknown' END) as 'Day' FROM INFO_DATE Order BY " "\"Upcoming Date\" ASC;"; CalendarContents[7].tbl_name = "Upcoming Event Dates"; CalendarContents[7].type = "view"; //--- initializing properties for the RecentEventInfo view CalendarContents[8].Content = RecentEventInfo_View; CalendarContents[8].name = "Recent Event Dates"; CalendarContents[8].sql = "CREATE VIEW IF NOT EXISTS 'Recent Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID" " as 'E_ID',M.COUNTRY as 'Country',M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency'" "FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency," "(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON" " T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))<=R.Date AND E_ID=M.EVENTID ORDER BY Time DESC" " LIMIT 1) as 'Last Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name,Currency" ",\"Last Event Date\" as 'Recent Date',(case cast (strftime('%w', DATE(REPLACE(\"Last Event Date\"" ",'.','-'))) as integer) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN" " 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END) as 'Day' FROM INFO_DATE" " Order BY \"Recent Date\" DESC;"; CalendarContents[8].tbl_name = "Recent Event Dates"; CalendarContents[8].type = "view"; // ...
Die folgende Abfrage ist für die Erstellung von vier ähnlichen, aber unterschiedlichen Ansichten verantwortlich: Kalender_AU, Kalender_NONE, Kalender_UK und Kalender_US. Jede dieser Ansichten greift auf Daten aus drei Tabellen zurück: MQL5Calendar, Record, und TimeSchedule. Diese Abfragen erstellen Ansichten, die Ereignisdetails (ID, Name, Land, Datum, Währung und Bedeutung) für verschiedene Zeitzonen (Australien, Keine/Standard, Großbritannien und USA) anzeigen. Das Datum jedes Ereignisses wird danach gekennzeichnet, ob es gestern, heute oder morgen im Verhältnis zum aktuellen Datum eingetreten ist, und die Ergebnisse werden so gefiltert, dass Ereignisse angezeigt werden, die innerhalb eines Tages nach dem aktuellen Datum stattfinden. Die Ansichten sind nach dem Ereignisdatum in der entsprechenden Zeitzone sortiert.
Wir werden die Ansicht Calendar_AU zur Erläuterung verwenden.
Vollständig sichtbare Abfrage:
CREATE VIEW IF NOT EXISTS Calendar_AU AS SELECT C.Eventid as 'ID',C.Eventname as 'Name',C.Country as 'Country', (CASE WHEN Date(REPLACE(T.DST_AU,'.','-'))<R.Date THEN CONCAT(T.DST_AU,' | Yesterday') WHEN Date(REPLACE(T.DST_AU,'.','-'))=R.Date THEN CONCAT(T.DST_AU,' | Today') WHEN Date(REPLACE(T.DST_AU,'.','-'))>R.Date THEN CONCAT(T.DST_AU,' | Tomorrow') END) as 'Date', C.EventCurrency as 'Currency',Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','') as 'Importance' from MQL5Calendar C, Record R Inner join TimeSchedule T on C.ID=T.ID Where DATE(REPLACE(T.DST_AU,'.','-'))>=DATE(R.Date,'-1 day') AND DATE(REPLACE(T.DST_AU,'.','-'))<=DATE(R.Date,'+1 day') Order by T.DST_AU Asc;
CREATE VIEW IF NOT EXISTS Calendar_AU, Hiermit wird eine Ansicht mit dem Namen Calendar_AU erstellt, wenn sie noch nicht existiert. Eine Ansicht ist im Wesentlichen eine virtuelle Tabelle, die auf der Grundlage einer Abfrage erstellt wird und es Ihnen ermöglicht, Daten abzurufen, ohne sie erneut zu speichern.
Die Klausel SELECT:
SELECT C.Eventid as 'ID', C.Eventname as 'Name', C.Country as 'Country', (CASE WHEN Date(REPLACE(T.DST_AU,'.','-')) < R.Date THEN CONCAT(T.DST_AU, ' | Yesterday') WHEN Date(REPLACE(T.DST_AU,'.','-')) = R.Date THEN CONCAT(T.DST_AU, ' | Today') WHEN Date(REPLACE(T.DST_AU,'.','-')) > R.Date THEN CONCAT(T.DST_AU, ' | Tomorrow') END) as 'Date', C.EventCurrency as 'Currency', Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','') as 'Importance'
Dieser Teil der Abfrage wählt bestimmte Felder aus den Tabellen MQL5Calendar, Record und TimeSchedule aus und formatiert die Daten entsprechend:
- C.Eventid ist die Ereignis-ID.
- C.Ereignisname ist der Name des Ereignisses.
- C.Country ist das zugehörige Land des Ereignisses.
- Mit einer CASE-Anweisung wird das Datum DST_AU (australische Zeitzone, gespeichert in TimeSchedule) mit R.Date (aktuelles Datum aus der Tabelle Record) verglichen, um das Ereignis entweder als „Gestern“, „Heute“ oder „Morgen“ zu kennzeichnen.
- C.EventCurrency ist die Währung, die sich auf das Ereignis bezieht.
- Replace(C.EventImportance,“CALENDAR_IMPORTANCE_“,““) entfernt das Präfix „CALENDAR_IMPORTANCE_“ aus dem Feld EventImportance und extrahiert nur die entsprechende Wichtigkeitsstufe (z. B. „HIGH“ oder „LOW“).
Die Klausel FROM:
FROM MQL5Calendar C, Record R Inner join TimeSchedule T on C.ID=T.ID
- Die Abfrage bezieht die Daten aus drei Tabellen: MQL5Calendar (C), Record (R), und TimeSchedule (T).
- Die Tabellen MQL5Calendar und Record sind Teil der FROM-Klausel, und die Tabelle TimeSchedule wird mittels INNER JOIN mit der Bedingung C.ID=T.ID verbunden, was bedeutet, dass die ID aus der Tabelle MQL5Calendar mit der ID in der Tabelle TimeSchedule übereinstimmen muss.
Die Klausel WHERE:
WHERE DATE(REPLACE(T.DST_AU,'.','-')) >= DATE(R.Date,'-1 day') AND DATE(REPLACE(T.DST_AU,'.','-')) <= DATE(R.Date,'+1 day')
- Dadurch werden die Ergebnisse so gefiltert, dass nur Ereignisse berücksichtigt werden, bei denen die Sommerzeit (das Ereignisdatum in der australischen Zeitzone) innerhalb eines Tages vor oder nach dem aktuellen Datum (R.Date) liegt.
Die Klausel ORDER BY:
ORDER BY T.DST_AU Asc;
- Damit werden die Ereignisse in aufsteigender Reihenfolge nach DST_AU, dem Datum in australischer Zeit, sortiert.
Schlüsselkonzepte:
- Formatierung von Datum und Uhrzeit: Die Funktion REPLACE() wird verwendet, um Punkte . durch Bindestriche zu ersetzen - in den DST_-Spalten, die als Zeichenketten gespeichert sind, die Datumsangaben darstellen (z. B. wird 2024.09.23 in 2024-09-23 umgewandelt).
- Bedingte Logik: Die CASE-Anweisung prüft, ob das Ereignisdatum (DST_AU, DST_NONE, DST_UK oder DST_US) vor, gleich oder nach dem aktuellen Datum (R.Date) liegt, und fügt dementsprechend eine Beschriftung hinzu (“Yesterday“, „Today“ oder „Tomorrow“).
- Filtern: Die WHERE-Klausel stellt sicher, dass nur Ereignisse, die in den Bereich von einem Tag vor oder nach dem aktuellen Datum fallen, in die Ansicht aufgenommen werden.
- Extraktion der Wichtigkeit: Die Funktion REPLACE() entfernt das Präfix aus der Spalte EventImportance, um nur die relevante Wichtigkeitsstufe anzuzeigen (z. B. „HIGH“, „MEDIUM“ oder „LOW“).
Calendar_AU Ansicht der Ausgabedaten:
ID Name Country Date Currency Importance 392080012 Autumnal Equinox Day Japan 2024.09.22 02:00 | Yesterday JPY NONE 554010007 Exports New Zealand 2024.09.23 00:45 | Today NZD LOW 554010008 Imports New Zealand 2024.09.23 00:45 | Today NZD LOW // ... 710010010 Heritage Day South Africa 2024.09.24 02:00 | Tomorrow ZAR NONE 36030005 RBA Rate Statement Australia 2024.09.24 07:30 | Tomorrow AUD MODERATE // ...
Die folgende Abfrage erstellt eine Ansicht namens „Event Info“, die Ereignisinformationen aus der Tabelle MQL5Calendar auswählt und organisiert. Diese Ansicht extrahiert bestimmte Ereignisinformationen aus der MQL5Calendar-Tabelle und formatiert die Daten zum leichteren Lesen und Analysieren. Es bereinigt die Feldnamen, indem es unnötige Präfixe entfernt (KALENDER_TYP_, KALENDER_SPEKTOR_, usw.).
CREATE VIEW IF NOT EXISTS 'Event Info' AS SELECT DISTINCT MC.EVENTID as 'ID',MC.COUNTRY as 'Country',MC.EVENTNAME as 'Name', REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector', REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MC.EVENTCURRENCY as 'Currency', REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency',MC.EVENTCODE as 'Code' FROM MQL5Calendar MC ORDER BY "Country" Asc,CASE "Importance" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,"Sector" Desc;
CREATE VIEW IF NOT EXISTS 'Event Info'
Dieser Teil erstellt eine Ansicht mit der Bezeichnung 'Event Info', falls sie noch nicht vorhanden ist. Ein „View“ in SQL ist eine virtuelle Tabelle, die auf dem Ergebnis einer SELECT-Abfrage basiert und es Ihnen ermöglicht, eine komplexe Abfrage zu kapseln und auf sie wie auf eine Tabelle zu verweisen.
Die Klausel SELECT DISTINCT:
SELECT DISTINCT MC.EVENTID as 'ID', MC.COUNTRY as 'Country', MC.EVENTNAME as 'Name', REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type', REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector', REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance', MC.EVENTCURRENCY as 'Currency', REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency', MC.EVENTCODE as 'Code'
Dieser Abschnitt ruft eindeutige Zeilen (unter Entfernung von Duplikaten) aus der Tabelle MQL5Calendar (MC ist ein Alias für diese Tabelle) ab und wählt bestimmte Spalten aus, um die Ansicht zu bilden.
Ausgewählte Felder:
- MC.EVENTID as 'ID': Ruft die eindeutige ID eines jeden Ereignisses ab und benennt sie in „ID“ um.
- MC.COUNTRY as 'Country': Ruft das mit dem Ereignis verbundene Land ab.
- MC.EVENTNAME as 'Name': Ruft den Ereignisnamen ab.
Datenumwandlung mit REPLACE():
Mehrere Felder verwenden die Funktion REPLACE(), um Präfixe wie CALENDAR_TYPE_, CALENDAR_SECTOR_, CALENDAR_IMPORTANCE_ und CALENDAR_FREQUENCY_ zu entfernen, sodass nur der sinnvolle Teil des Feldes übrig bleibt:
- REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type': Entfernt das Präfix CALENDAR_TYPE_ aus dem Feld EVENTTYPE, um einen saubereren Wert zu erhalten (z. B. erhalten Sie anstelle von CALENDAR_TYPE_CONSUMER den Wert CONSUMER).
- REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector': Entfernt das Präfix CALENDAR_SECTOR_ aus dem Feld EVENTSECTOR, um den Sektornamen zu erhalten.
- REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance': Entfernt das Präfix CALENDAR_IMPORTANCE_ aus dem Feld EVENTIMPORTANCE, um die Wichtigkeitsstufe anzuzeigen (z. B. HIGH, MODERATE, LOW).
- MC.EVENTCURRENCY as 'Currency': Ruft die am Ereignis beteiligte Währung ab.
- REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency': Entfernt das Präfix CALENDAR_FREQUENCY_ aus dem Feld EVENTFREQUENCY und liefert die Häufigkeit des Ereignisses (z. B. MONATLICH oder QUARTERLICH).
- MC.EVENTCODE as 'Code': Ruft den Ereigniscode ohne jegliche Transformation ab.
Die Klausel FROM:
FROM MQL5Calendar MC
Die Abfrage bezieht Daten aus der Tabelle MQL5Calendar, die als MC bezeichnet wird.
Die Klausel ORDER BY:
ORDER BY "Country" Asc, CASE "Importance" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END, "Sector" Desc
In diesem Abschnitt werden die Daten nach mehreren Feldern geordnet, um die Ausgabe der Ansicht zu organisieren.
Ordering by Country (Ascending):
- Das erste Sortierkriterium ist „Country“ in aufsteigender Reihenfolge (Asc), d. h. die Ereignisse werden gruppiert und alphabetisch nach dem Feld „Country“ sortiert.
Ordering by Importance (Custom Ordering):
- Die CASE-Anweisung sortiert die Wichtigkeitsebenen auf der Grundlage einer nutzerdefinierten Priorität:
- Die Wichtigkeit 'HIGH' erhält den Wert 1 (höchste Priorität).
- Der Wichtigkeit 'MODERATE' wird ein Wert von 2 zugewiesen.
- 'LOW' wird ein Wert von 3 zugewiesen.
- Jeder andere Wert (z. B. NONE) wird mit dem Wert 4 bewertet, der die niedrigste Priorität darstellt.
Das bedeutet, dass Ereignisse mit der Wichtigkeit HIGH zuerst erscheinen, gefolgt von den Wichtigkeitsstufen MODERATE, LOW und dann NONE.
Ordering by Sector (Descending):
- Schließlich werden die Ereignisse nach dem Feld Sektor in absteigender Reihenfolge geordnet (Desc). So könnten Sektoren wie MONEY, CONSUMER usw. in umgekehrter alphabetischer Reihenfolge angeordnet werden.
Beispiel für die Ausgabedaten der Ansicht 'Event Info':
ID Country Name Type Sector Importance Currency Frequency Code 36030008 Australia RBA Interest Rate Decision INDICATOR MONEY HIGH AUD NONE AU 36030006 Australia RBA Governor Lowe Speech EVENT MONEY HIGH AUD NONE AU 36010003 Australia Employment Change INDICATOR JOBS HIGH AUD MONTH AU // ... 36010036 Australia Current Account INDICATOR TRADE MODERATE AUD QUARTER AU 36010011 Australia Trade Balance INDICATOR TRADE MODERATE AUD MONTH AU 36010029 Australia PPI q/q INDICATOR PRICES MODERATE AUD QUARTER AU // ... 36010009 Australia Exports m/m INDICATOR TRADE LOW AUD MONTH AU 36010010 Australia Imports m/m INDICATOR TRADE LOW AUD MONTH AU 36010037 Australia Net Exports Contribution INDICATOR TRADE LOW AUD QUARTER AU // ... 76020002 Brazil BCB Interest Rate Decision INDICATOR MONEY HIGH BRL NONE BR // ...
Die folgende Abfrage erstellt eine Ansicht mit dem Namen 'Recent Event Dates', die eine Zusammenfassung der jüngsten Ereignisse aus der Tabelle MQL5Calendar zusammen mit dem Wochentag, an dem das Ereignis eingetreten ist, liefert. Diese Ansicht bietet eine Liste der letzten Ereignisse aus der Tabelle MQL5Calendar, zusammen mit dem Wochentag, an dem das Ereignis eingetreten ist. Sie konzentriert sich auf das jüngste Ereignis für jedes einzelne Ereignis im Kalender.
CREATE VIEW IF NOT EXISTS 'Recent Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID',M.COUNTRY as 'Country', M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency'FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency, (SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-')) <=R.Date AND E_ID=M.EVENTID ORDER BY Time DESC LIMIT 1) as 'Last Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name, Currency,"Last Event Date" as 'Recent Date',(case cast (strftime('%w', DATE(REPLACE("Last Event Date",'.','-'))) as integer) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END) as 'Day' FROM INFO_DATE Order BY "Recent Date" DESC;
CREATE VIEW IF NOT EXISTS 'Recent Event Dates'
Dieser Teil erstellt eine Ansicht mit der Bezeichnung 'Recent Event Dates', falls diese noch nicht vorhanden ist.
Die Klausel WITH: gemeinsame Tabellenausdrücke
In diesem Teil werden zwei gemeinsame Tabellenausdrücke (Common Table Expressions, CTEs) definiert, die die Abfragelogik vereinfachen, indem sie in Zwischenschritte zerlegt werden.
CTE 1: UNIQUE_EVENTS
WITH UNIQUE_EVENTS AS ( SELECT DISTINCT M.EVENTID as 'E_ID', M.COUNTRY as 'Country', M.EVENTNAME as 'Name', M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M )
- Dieses CTE (UNIQUE_EVENTS) extrahiert eindeutige Ereignisse aus der Tabelle MQL5Calendar.
- Es wählt die ID des Ereignisses (EVENTID), das Land, den Namen und die Währung aus und stellt sicher, dass jedes Ereignis nur einmal aufgeführt wird (DISTINCT entfernt doppelte Einträge).
In UNIQUE_EVENTS ausgewählte Spalten:
- M.EVENTID as 'E_ID': Die eindeutige Ereignis-ID.
- M.COUNTRY as 'Country': Das mit dem Ereignis verbundene Land.
- M.EVENTNAME as 'Name': Der Name des Ereignisses.
- M.EVENTCURRENCY as 'Currency': Die mit dem Ereignis verbundene Währung.
CTE 2: INFO_DATUM
INFO_DATE AS ( SELECT E_ID, Country, Name, Currency, ( SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M, Record R INNER JOIN TimeSchedule T ON T.ID = M.ID WHERE DATE(REPLACE(Time, '.', '-')) <= R.Date AND E_ID = M.EVENTID ORDER BY Time DESC LIMIT 1 ) as 'Last Event Date' FROM UNIQUE_EVENTS )
Dieses CTE (INFO_DATE) fügt ein Datumsfeld (Datum des letzten Ereignisses) zu den eindeutigen Ereignissen aus dem vorherigen CTE hinzu. Sie tut dies durch:
- Für jedes eindeutige Ereignis (E_ID, Land, Name, Währung) wird das jüngste Ereignisdatum aus den Tabellen TimeSchedule und MQL5Calendar ausgewählt.
Felder in INFO_DATE:Unterabfrage Erläuterung:
- Die Unterabfrage ruft das Feld DST_NONE aus der Tabelle TimeSchedule (verbunden mit den Tabellen MQL5Calendar und Record) ab, das einen Zeitstempel oder eine Ereigniszeit darstellt.
- Die Bedingung DATE(REPLACE(Time, „.“, „-“)) <= R.Date stellt sicher, dass das Datum für das Ereignis (Time, nachdem die Punkte . durch Bindestriche ersetzt wurden - um ein gültiges Datumsformat zu bilden) kleiner oder gleich dem aktuellen Datum in der Tabelle Record (R.Date) ist.
- Die Ereignisse werden in absteigender Reihenfolge nach Zeit sortiert (ORDER BY Time DESC), und LIMIT 1 stellt sicher, dass nur die jüngste Ereigniszeit abgerufen wird.
- E_ID: Die Ereignis-ID aus dem CTE UNIQUE_EVENTS.
- Country: Das Land aus dem UNIQUE_EVENTS CTE.
- Name: Der Ereignisname aus dem CTE UNIQUE_EVENTS.
- Currency: Die Währung aus dem UNIQUE_EVENTS CTE.
- Last Event Date: Das jüngste Ereignisdatum für jedes Ereignis, das aus den Tabellen MQL5Calendar und TimeSchedule abgerufen wird.
Main Query: Endgültige Auswahl und Umwandlung
SELECT E_ID as 'ID', Country, Name, Currency, "Last Event Date" as 'Recent Date', ( CASE CAST (strftime('%w', DATE(REPLACE("Last Event Date", '.', '-'))) AS INTEGER) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END ) as 'Day' FROM INFO_DATE ORDER BY "Recent Date" DESC;
Der Hauptteil der Abfrage wählt das Endergebnis aus dem CTE INFO_DATE aus und enthält die folgenden Felder:
- E_ID as 'ID': Die Ereignis-ID, umbenannt in „ID“.
- Country: Das mit dem Ereignis verbundene Land.
- Name: Der Name des Ereignisses.
- Currency: Die mit dem Ereignis verbundene Währung.
- "Last Event Date" as 'Recent Date': Das jüngste Ereignisdatum wird umbenannt in 'Recent Date'.
Wochentagsberechnung:
- Die Abfrage verwendet strftime(„%w“, DATE(REPLACE(“Last Event Date“, „.“, „-“))), das das „Last Event Date“ in ein gültiges Datumsformat umwandelt und den Wochentag abruft.
- %w gibt eine ganze Zahl für den Wochentag zurück, wobei 0 = Sonntag, 1 = Montag, ..., 6 = Samstag.
- Die CASE-Anweisung ordnet die Ganzzahl dem entsprechenden Tagesnamen zu (z.B. 0 -> Sonntag, 1 -> Montag, usw.).
Sortieren der Ergebnisse:
ORDER BY "Recent Date" DESC
Die Ergebnisse sind nach dem letzten Datum, 'Recent Date', in absteigender Reihenfolge sortiert, d. h. die neuesten Ereignisse stehen ganz oben in der Liste.
Beispiel für Ausgabedaten in der Ansicht 'Recent Event Dates':
ID Country Name Currency Recent Date Day 554520001 New Zealand CFTC NZD Non-Commercial Net Positions NZD 2024.09.27 21:30 Friday 999520001 European Union CFTC EUR Non-Commercial Net Positions EUR 2024.09.27 21:30 Friday 392520001 Japan CFTC JPY Non-Commercial Net Positions JPY 2024.09.27 21:30 Friday // ...
Die folgende Abfrage erstellt eine Ansicht mit dem Namen 'Upcoming Event Dates', um kommende Ereignissen aus der Tabelle MQL5Calendar aufzulisten. Sie enthält das nächste Datum und den Wochentag des Ereignisses. Die Abfrage hat zwei Hauptbestandteile: Zunächst werden eindeutige Ereignisse identifiziert, dann wird das nächste geplante Ereignisdatum für jedes dieser Ereignisse ermittelt.
CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID',M.COUNTRY as 'Country',M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency,(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))>R.Date AND E_ID=M.EVENTID ORDER BY Time ASC LIMIT 1) as 'Next Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name,Currency,(CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' ELSE "Next Event Date" END) as 'Upcoming Date',(CASE WHEN "Next Event Date"<>'Unknown' THEN (case cast (strftime('%w', DATE(REPLACE("Next Event Date",'.','-'))) as integer) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END) ELSE 'Unknown' END) as 'Day' FROM INFO_DATE Order BY "Upcoming Date" ASC;
CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates'
Dadurch wird eine Ansicht mit dem Namen 'Upcoming Event Dates' erstellt, aber nur, wenn sie noch nicht existiert.
Die Klausel WITH: gemeinsame Tabellenausdrücke
Die Abfrage verwendet gemeinsame Tabellenausdrücke, Common Table Expressions, CTEs, mit denen komplexe Abfragen in einfachere, wiederverwendbare Teile zerlegt werden können. Hier gibt es zwei CTEs: UNIQUE_EVENTS und INFO_DATE.
CTE 1: UNIQUE_EVENTS
WITH UNIQUE_EVENTS AS ( SELECT DISTINCT M.EVENTID as 'E_ID', M.COUNTRY as 'Country', M.EVENTNAME as 'Name', M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M )
- Dieser Teil wählt eindeutige Ereignisse aus der Tabelle MQL5Calendar aus.
- Sie ruft die ID des Ereignisses (EVENTID), das Land, den Namen und die Währung ab und stellt sicher, dass jedes Ereignis nur einmal mit DISTINCT aufgelistet wird.
Das Ergebnis dieses CTE ist eine Reihe von unterschiedlichen Ereignissen mit den dazugehörigen Details.
Spalten in UNIQUE_EVENTS:
- E_ID: Die eindeutige ID des Ereignisses.
- Country: Das Land, dem das Ereignis zugeordnet ist.
- Name: Der Name des Ereignisses.
- Currency: Die mit dem Ereignis verbundene Währung.
CTE 2: INFO_DATUM
INFO_DATE AS ( SELECT E_ID, Country, Name, Currency, ( SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M, Record R INNER JOIN TimeSchedule T ON T.ID=M.ID WHERE DATE(REPLACE(Time, '.', '-')) > R.Date AND E_ID = M.EVENTID ORDER BY Time ASC LIMIT 1 ) as 'Next Event Date' FROM UNIQUE_EVENTS )
Dieses CTE (INFO_DATE) holt das nächste Ereignisdatum für jedes einzelne Ereignis.
- Für jedes Ereignis (E_ID, Land, Name, Währung) wird in der Tabelle TimeSchedule (Feld DST_NONE) nach dem Datum des bevorstehenden Ereignisses gesucht.
Unterabfrage Erläuterung:
- Die Unterabfrage ruft das Feld DST_NONE aus der Tabelle TimeSchedule ab, das die Uhrzeit oder das Datum des Ereignisses darstellt.
- Die Bedingung DATE(REPLACE(Time, „.“, „-“)) > R.Date stellt sicher, dass nur zukünftige Ereignisse (Daten größer als das aktuelle Datum, R.Date) ausgewählt werden.
- Die Ereignisse werden in aufsteigender Reihenfolge nach Zeit sortiert (ORDER BY Time ASC), sodass das früheste anstehende Ereignisdatum ausgewählt wird (LIMIT 1 gewährleistet, dass nur ein Datum zurückgegeben wird).
Spalten in INFO_DATE:
- E_ID: Die Ereignis-ID aus UNIQUE_EVENTS.
- Country: Das Land, in dem das Ereignis stattfindet.
- Name: Der Name des Ereignisses.
- Currency: Die Währung des Ereignisses.
- Nächstes Ereignissdatum: Das nächste anstehende Ereignisdatum, das durch die Unterabfrage ermittelt wird.
Main Query: Endgültige Auswahl und Umwandlung
SELECT E_ID as 'ID', Country, Name, Currency, (CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' ELSE "Next Event Date" END) as 'Upcoming Date', (CASE WHEN "Next Event Date" <> 'Unknown' THEN (CASE CAST (strftime('%w', DATE(REPLACE("Next Event Date", '.', '-'))) AS INTEGER) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END) ELSE 'Unknown' END) as 'Day' FROM INFO_DATE ORDER BY "Upcoming Date" ASC;
Die Hauptabfrage ruft die endgültige Ausgabe des CTEs INFO_DATE ab, wandelt die Ergebnisse um und fügt zusätzliche Logik hinzu, um Fälle zu behandeln, in denen Ereignisdaten (NULL-Werte) fehlen könnten.
Ausgewählte Spalten:
- E_ID as 'ID': Die Ereignis-ID, umbenannt in „ID“.
- Country: Das mit dem Ereignis verbundene Land.
- Name: Der Name des Ereignisses.
- Currency: Die mit dem Ereignis verbundene Währung.
- Upcoming Date: Dies basiert auf 'Next Event Date'. Wenn 'Next Event Date'. NULL ist, wird 'Unknown' angezeigt andernfalls wird das Datum angezeigt.
CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' ELSE "Next Event Date" END
Diese CASE-Anweisung prüft, ob es ein gültiges Datum für ein bevorstehendes Ereignis gibt. Wenn das Datum NULL ist, wird 'Unknown' ausgegeben; andernfalls wird 'Next Event Date'. angezeigt.
Wochentagsberechnung:
- Wenn das Datum des nächsten Ereignisses nicht 'Unknown' ist, wandelt die Abfrage das bevorstehende Datum in einen Wochentag um, indem sie die folgende CASE-Anweisung verwendet:
CASE CAST (strftime('%w', DATE(REPLACE("Next Event Date", '.', '-'))) AS INTEGER) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END
Die Funktion strftime('%w', ...) extrahiert den Wochentag aus dem 'Next Event Date':
- %w gibt eine ganze Zahl zurück, die den Wochentag angibt (0 = Sonntag, 1 = Montag usw.).
- Die CASE-Anweisung ordnet diese Ganzzahl einem Tagesnamen zu (z. B. 0 -> Sonntag).
- Wenn das Datum des nächsten Ereignisses 'Unknown' ist, wird in der Spalte Tag ebenfalls 'Unknown' angezeigt.
Ordnen der Ergebnisse:
ORDER BY "Upcoming Date" ASC;
Die Ergebnisse sind nach 'Upcoming Date' in aufsteigender Reihenfolge sortiert, d. h. die frühesten kommenden Ereignisse erscheinen zuerst.
Beispiel für Ausgabedaten in der Ansicht 'Upcoming Date':
ID Country Name Currency Upcoming Date Day 410020004 South Korea Industrial Production y/y KRW 2024.09.30 01:00 Monday 410020005 South Korea Retail Sales m/m KRW 2024.09.30 01:00 Monday 410020006 South Korea Index of Services m/m KRW 2024.09.30 01:00 Monday // ... 36500001 Australia S&P Global Manufacturing PMI AUD 2024.10.01 01:00 Tuesday 392030007 Japan Unemployment Rate JPY 2024.10.01 01:30 Tuesday 392050002 Japan Jobs to Applicants Ratio JPY 2024.10.01 01:30 Tuesday // ...
Experten-Code
Dies ist die Hauptprogrammdatei, in der wir die Strategie des Nachrichtenhandels implementieren. Der folgende Code ermöglicht die Eingabe von Einstellungen für den Handel mit nutzerdefinierten Nachrichtenereignissen.
input Choice iCustom_Event_1=No;//USE EVENT IDs BELOW? input string iCustom_Event_1_IDs="";//EVENT IDs[Separate with a comma][MAX 14] input Choice iCustom_Event_2=No;//USE EVENT IDs BELOW? input string iCustom_Event_2_IDs="";//EVENT IDs[Separate with a comma][MAX 14] input Choice iCustom_Event_3=No;//USE EVENT IDs BELOW? input string iCustom_Event_3_IDs="";//EVENT IDs[Separate with a comma][MAX 14] input Choice iCustom_Event_4=No;//USE EVENT IDs BELOW? input string iCustom_Event_4_IDs="";//EVENT IDs[Separate with a comma][MAX 14] input Choice iCustom_Event_5=No;//USE EVENT IDs BELOW? input string iCustom_Event_5_IDs="";//EVENT IDs[Separate with a comma][MAX 14]
Erläuterung der einzelnen Eingaben:
Choice iCustom_Event_1=No;
- Type: Wählbar
- Name der Variablen: iCustom_Event_1
- Standardwert: No
- Beschreibung: Mit dieser Eingabe kann der Nutzer die Verwendung von nutzerdefinierten Ereignis-IDs für Ereignis 1 aktivieren oder deaktivieren. Der Choice-Typ ist hier ein Enum-Typ mit zwei Werten, Yes oder No. Wenn er auf Yes gesetzt ist, verwendet das Programm die Ereignis-IDs, die in der entsprechenden String-Eingabe (iCustom_Event_1_IDs) angegeben sind.
string iCustom_Event_1_IDs="";
- Typ: Zeichenkette
- Name der Variablen: iCustom_Event_1_IDs
- Standardwert: Eine leere Zeichenkette ''
- Beschreibung: Mit dieser Eingabe kann der Nutzer eine Liste von Ereignis-IDs für das nutzerdefinierte Ereignis 1 eingeben. Es wird erwartet, dass diese IDs durch Kommas getrennt werden (z. B. "36010006,840030005,840030016"), und es werden maximal 14 IDs angegeben.
Initialisierung von nutzerdefinierten Nachrichtenereignissen
CEvent1.useEvents = Answer(iCustom_Event_1); StringSplit(iCustom_Event_1_IDs, ',', CEvent1.EventIds); CEvent2.useEvents = Answer(iCustom_Event_2); StringSplit(iCustom_Event_2_IDs, ',', CEvent2.EventIds); CEvent3.useEvents = Answer(iCustom_Event_3); StringSplit(iCustom_Event_3_IDs, ',', CEvent3.EventIds); CEvent4.useEvents = Answer(iCustom_Event_4); StringSplit(iCustom_Event_4_IDs, ',', CEvent4.EventIds); CEvent5.useEvents = Answer(iCustom_Event_5); StringSplit(iCustom_Event_5_IDs, ',', CEvent5.EventIds);
Dieser Codeblock initialisiert mehrere nutzerdefinierte Nachrichtenereignisobjekte (CEvent1, CEvent2 usw.) und verarbeitet ihre zugehörigen IDs.
- CEvent1.useEvents = Answer(iCustom_Event_1);:
- CEvent1 ist eine Struktur, die Informationen über ein bestimmtes nutzerdefiniertes Nachrichten-Ereignis-Set enthält. Das Flag useEvents wird mit der Funktion Answer() gesetzt, die auf der Grundlage der Eingabevariablen iCustom_Event_1 einen booleschen Wert (true oder false) zurückgibt.
- Wenn iCustom_Event_1 wahr ist, verwendet der Experte dieses nutzerdefinierte Ereignis für die Handelslogik; andernfalls wird es ignoriert.
- StringSplit(iCustom_Event_1_IDs, ',', CEvent1.EventIds);:
- StringSplit() ist eine Funktion, die eine Zeichenkette von Ereignis-IDs (iCustom_Event_1_IDs) durch ein Komma (,) aufteilt, und die resultierende Liste von Ereignis-IDs wird in CEvent1.EventIds gespeichert.
- iCustom_Event_1_IDs ist eine Zeichenkette, die eine oder mehrere Ereignis-IDs enthält, und die Split-Funktion wandelt diese Zeichenkette in ein Array von Ereignis-IDs zur weiteren Verwendung in der Handelslogik um.
Ähnlicher Code für CEvent2 bis CEvent5.
Die Funktion OnInit()
Dies ist die Initialisierungsfunktion, die aufgerufen wird, wenn der EA gestartet oder zu einem Diagramm hinzugefügt wird.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Assign if in LightMode or not isLightMode=(iDisplayMode==Display_LightMode)?true:false; //--- call function for common initialization procedure InitCommon(); //--- store Init result int InitResult; if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester { //--- initialization procedure outside strategy tester InitResult=InitNonTester(); } else { //--- initialization procedure inside strategy tester InitResult=InitTester(); } //--- Create DB in memory NewsObject.CreateEconomicDatabaseMemory(); //--- Initialize Candle properties pointer object CP = new CCandleProperties(); //--- Retrieve news events for the current Daily period into array CalendarArray NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0), (iOrderType!=StopOrdersType)?true:false); //--- Initialize Common graphics class pointer object CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread), Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj)); CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects //--- Set Time CDay.SetmyTime(CalendarArray); /* create timer, if in the strategy tester set the timer to 30s else 100ms */ EventSetMillisecondTimer((!MQLInfoInteger(MQL_TESTER))?100:30000); //-- Initialize Trade Management class pointer object Trade = new CTradeManagement(iDeviation); //--- return Init result return InitResult; }
Wichtige Schritte:
Anzeigemodus:
- Der EA prüft, ob er im hellen oder dunklen Modus läuft (isLightMode).
Gemeinsame Initialisierung:
- Ruft die Funktion InitCommon() auf, um allgemeine Initialisierungsaufgaben durchzuführen.
Strategie-Tester-Check:
- Er prüft, ob der EA im Strategietestermodus läuft, indem er MQLInfoInteger(MQL_TESTER) verwendet, und ruft dann je nach Ergebnis entweder InitNonTester() oder InitTester() auf.
Datenbank für Nachrichtenereignisse:
- Die Funktion NewsObject.CreateEconomicDatabaseMemory() initialisiert die In-Memory-Datenbank für wirtschaftliche Ereignisse. Hier speichert der EA nachrichtenbezogene Daten.
Initialisieren der Eigenschaften der Kerzen:
- Der Zeiger auf die Klasse CP für CCandleProperties wird erstellt. Diese Klasse ist für die Verwaltung von Kerzeneigenschaften wie Open, Close, High, Low usw. zuständig.
Abrufen von Nachrichtenereignissen:
- Die Funktion NewsObject.EconomicDetailsMemory() ruft die relevanten Nachrichtenereignisse anhand der ausgewählten Kriterien ab. Sie filtert Nachrichten für den aktuellen Handelstag.
Initialisieren von grafischen Objekten:
- Die Klasse CGraphics wird initialisiert, die für die Erstellung von grafischen Elementen auf dem Diagramm zuständig ist, z. B. für die Visualisierung von Ereignisdaten. Die Methode GraphicsRefresh() sorgt dafür, dass die grafischen Objekte entsprechend der konfigurierten Zeit (iSecondsPreEvent) aufgefrischt werden.
Zeit und Timer einstellen:
- Die Methode CDay.SetmyTime() verarbeitet das Nachrichten-Ereignis-Array und übernimmt das Zeitmanagement für den Handel.
- Es wird ein Timer mit unterschiedlichen Intervallen gesetzt, je nachdem, ob der EA im Tester oder im Live-Modus läuft (EventSetMillisecondTimer()), um die Leistung beim Testen des Experten im Strategietester zu gewährleisten.
Initialisieren des Handelsgeschäfts:
- Der Zeiger der Handelsklasse wird mit iDeviation initialisiert, um bei Bedarf Stop-Order zu eröffnen.
Rückgabe des Initialisierungsergebnisses:
- Die Funktion gibt das Ergebnis des Initialisierungsprozesses zurück.
Die Funktion OnTimer
Die Funktion OnTimer() wird periodisch ausgelöst und jedes Mal ausgeführt, wenn ein Timer-Ereignis aufgerufen wird.
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { if(((!MQLInfoInteger(MQL_TESTER))?int(TimeTradeServer())%30==0:true)) { //--- Store start-up time. static datetime Startup_date = TimeTradeServer(); if(CTM.DateisToday(Startup_date)&&CP.NewCandle(0,PERIOD_D1) &&MQLInfoInteger(MQL_TESTER)) { //--- Retrieve news events for the current Daily period into array CalendarArray NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0), (iOrderType!=StopOrdersType)?true:false); //--- Initialize Common graphics class pointer object CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread), Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj)); CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects //--- Set Time CDay.SetmyTime(CalendarArray); } //--- Run procedures ExecutionOnTimer(Startup_date); if(CTS.isSessionStart()&&!CTS.isSessionEnd()) { //--- function to open trades TradeTime(); } //--- close trades within 45 min before end of session if(CTS.isSessionStart()&&CTS.isSessionEnd()&&!CTS.isSessionEnd(0,0)) { Trade.CloseTrades("NewsTrading"); } } }
Wesentliche Merkmale:
- Zeitbasierte Bedingungen: Die if-Anweisung prüft, ob der Code im Strategietester oder in Echtzeit ausgeführt wird. Wenn es in Echtzeit läuft (außerhalb des Strategietesters), wird geprüft, ob die Serverzeit durch 30 teilbar ist (für ein 30-Sekunden-Intervall).
- Aktualisierung der Kerze und der News:
- Wenn das heutige Datum mit dem Startup_date übereinstimmt. Wenn heute ein neuer Tag ist und sich eine neue Tageskerze gebildet hat (CP.NewCandle(0, PERIOD_D1)), holt der Experte die Wirtschaftsnachrichten für den aktuellen Tag mit NewsObject.EconomicDetailsMemory.
- Außerdem wird das Chart mit neuen Informationen aktualisiert.
- Sitzungskontrolle: Wenn die Handelssitzung begonnen hat (CTS.isSessionStart()), werden Handelsgeschäfte während der Sitzung zugelassen. Der Experte schließt Handelsgeschäfte auch, wenn die Sitzung kurz vor dem Ende steht.
Die Funktion ExecutionOnTimer
//+------------------------------------------------------------------+ //|Execute program procedures in time intervals | //+------------------------------------------------------------------+ void ExecutionOnTimer(datetime Startup_date) { //--- Check if not start-up date if(!CTM.DateisToday(Startup_date)) { //--- Run every New Daily Candle if(CP.NewCandle(1,PERIOD_D1)) { //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Update/Create DB in Memory NewsObject.CreateEconomicDatabaseMemory(); } //--- retrieve news events for the current day NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0), (iOrderType!=StopOrdersType)?true:false); //--- Set time from news events CDay.SetmyTime(CalendarArray); CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create/Re-create chart objects } //--- Check if not in strategy tester if(!MQLInfoInteger(MQL_TESTER)) { //--- Run every New Hourly Candle if(CP.NewCandle(2,PERIOD_H1)) { //--- Check if DB in Storage needs an update if(NewsObject.UpdateRecords()) { //--- initialization procedure outside strategy tester InitNonTester(); } } } } else { //--- Run every New Daily Candle if(CP.NewCandle(3,PERIOD_D1)) { //--- Update Event objects on chart CGraphics.NewsEvent(); } } //--- Update realtime Graphic every 1 min if(CP.NewCandle(4,PERIOD_M1)) { //--- get the news events for the next min ahead of time. datetime Time_ahead = TimeTradeServer()+CTM.MinutesS(); CDay.GetmyTime(CTV.Hourly(CTM.ReturnHour(Time_ahead)), CTV.Minutely(CTV.Minutely(CTM.ReturnMinute(Time_ahead))), myTimeData,myEvents); CGraphics.Block_2_Realtime(iSecondsPreEvent); } }
Wesentliche Merkmale:
- Tägliches Kerzen-Update: Es wird nach neuen Tageskerzen gesucht. Wenn sich eine neue Tageskerze gebildet hat, wird die Nachrichtendatenbank aktualisiert (NewsObject.CreateEconomicDatabaseMemory()), und die Nachrichtenereignisse für den Tag werden abgerufen.
- Stündliches Kerzen-Update: Wenn sich eine neue Stundenkerze bildet, prüft der EA, ob die Wirtschaftsnachrichten-Datenbank aktualisiert werden muss, und wenn ja, wird der EA außerhalb des Strategie-Tester-Modus neu initialisiert (InitNonTester()).
- Aktualisierungen in Echtzeit: Jede Minute aktualisiert der EA die Echtzeitgrafiken auf dem Chart und ruft die Nachrichtenereignisse für die nächste Minute ab und bereitet die Trades entsprechend vor.
Die Funktion TradeTime
Diese Funktion verwaltet die Ausführung von Handelsgeschäften im Zusammenhang mit Nachrichtenereignissen.
//+------------------------------------------------------------------+ //|function to check trading time | //+------------------------------------------------------------------+ void TradeTime() { //--- Iterate through the event times for(uint i=0;i<myTimeData.Size();i++) { //--- Check if it is time to trade each news event if(CTM.TimePreEvent(CTM.TimeMinusOffset(datetime(myEvents[i].EventDate),iSecondsPreEvent) ,datetime(myEvents[i].EventDate)) &&(CTM.isDayOfTheWeek(TradingDay)||iNewSelection==News_Select_Custom_Events)) { //--- switch for order type selection switch(iOrderType) { case StopOrdersType:// triggers for STOP ORDERS StopOrders(myEvents[i]); break; default:// triggers for both MARKET POSITION & SINGLE STOP ORDER SingleOrder(myEvents[i]); break; } } } }
Wesentliche Merkmale:
- Überprüfung der Ereigniszeit: Für jedes Ereignis im Array myTimeData prüft der EA, ob die aktuelle Zeit innerhalb des vordefinierten Zeitfensters „vor dem Ereignis“ (iSecondsPreEvent) vor dem eigentlichen Ereignis liegt.
- Wochentagsfilter: Handelsgeschäfte werden nur eröffnet, wenn der aktuelle Tag mit dem konfigurierten Handelstag (TradingDay) übereinstimmt oder wenn nutzerdefinierte Ereignisse ausgewählt wurden (iNewSelection == News_Select_Custom_Events).
- Auswahl der Auftragsart: Basierend auf der iOrderType-Eingabe (Marktposition oder Stop-Order(s)) eröffnet die Funktion entweder Markt-Order oder Stop-Order um das Nachrichtenereignis herum.
Die Funktion SingleOrder
Mit dieser Funktion werden je nach Auswirkung des Nachrichtenereignisses Einzelmarkt- oder Stop-Orders eröffnet.
//+------------------------------------------------------------------+ //|function to open single order types | //+------------------------------------------------------------------+ void SingleOrder(Calendar &NewsEvent) { //--- Check each Impact value type switch(NewsObject.IMPACT(NewsEvent.EventImpact)) { //--- When Impact news is negative case CALENDAR_IMPACT_NEGATIVE: //--- Check if profit currency is news event currency if(NewsEvent.EventCurrency==CSymbol.CurrencyProfit()) { switch(iOrderType) { case MarketPositionType:// triggers for MARKET POSITION //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-"+NewsEvent.EventCode); break; case StopOrderType:// triggers for SINGLE STOP ORDER //--- Open buy-stop with Event id as Magic number Trade.OpenBuyStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-SStop-"+NewsEvent.EventCode); break; default: break; } } else { switch(iOrderType) { case MarketPositionType:// triggers for MARKET POSITION //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-"+NewsEvent.EventCode); break; case StopOrderType:// triggers for SINGLE STOP ORDER //--- Open buy-stop with Event id as Magic number Trade.OpenSellStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-SStop-"+NewsEvent.EventCode); break; default: break; } } break; //--- When Impact news is positive case CALENDAR_IMPACT_POSITIVE: //--- Check if profit currency is news event currency if(NewsEvent.EventCurrency==CSymbol.CurrencyProfit()) { switch(iOrderType) { case MarketPositionType:// triggers for MARKET POSITION //--- Open sell trade with Event id as Magic number Trade.Sell(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-"+NewsEvent.EventCode); break; case StopOrderType:// triggers for SINGLE STOP ORDER //--- Open sell-stop with Event id as Magic number Trade.OpenSellStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-SStop-"+NewsEvent.EventCode); break; default: break; } } else { switch(iOrderType) { case MarketPositionType:// triggers for MARKET POSITION //--- Open buy trade with Event id as Magic number Trade.Buy(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-"+NewsEvent.EventCode); break; case StopOrderType:// triggers for SINGLE STOP ORDER //--- Open sell-stop with Event id as Magic number Trade.OpenBuyStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-SStop-"+NewsEvent.EventCode); break; default: break; } } break; //--- Unknown default: break; } }
Wesentliche Merkmale:
- Folgenabschätzung: Der EA bewertet die Auswirkungen des Nachrichtenereignisses (NewsObject.IMPACT(NewsEvent.EventImpact)), die entweder negativ oder positiv sein können.
- Negative Auswirkungen: Wenn die Auswirkung der Nachricht negativ ist und die Ereigniswährung mit der Gewinnwährung des Kontos übereinstimmt, wird ein Kaufgeschäft eröffnet, wenn der iOrderType Marktposition oder eine Kauf-Stopp-Order für Stop-Orders ist. Wenn die Ereigniswährung nicht mit der Gewinnwährung übereinstimmt, wird ein Verkaufsgeschäft oder ein Verkaufsstoppauftrag eröffnet.
- Positive Auswirkungen: Ist die Auswirkung der Nachricht positiv und stimmt die Ereigniswährung mit der Gewinnwährung überein, wird ein Verkaufsgeschäft oder eine Verkaufs-Stopp-Order eröffnet. Wenn die Ereigniswährung nicht übereinstimmt, wird ein Kaufgeschäft oder ein Kauf-Stopp-Auftrag eröffnet.
Die Funktion StopOrders
Mit dieser Funktion werden gleichzeitig Kauf- und Verkaufsstopp-Aufträge rund um das Nachrichtenereignis eröffnet. Unabhängig von den Auswirkungen des Ereignisses werden beide Arten von Stop-Orders platziert, um Kursbewegungen in beide Richtungen aufzufangen.
//+------------------------------------------------------------------+ //|function to open orders | //+------------------------------------------------------------------+ void StopOrders(Calendar &NewsEvent) { //--- Opens both buy-stop & sell-stop regardless of event impact Trade.OpenStops(iStoploss,iTakeprofit,ulong(NewsEvent.EventId), "NewsTrading-Stops-"+NewsEvent.EventCode); }
Wesentliche Merkmale:
- Kauf-Stopp- und Verkaufs-Stopp-Aufträge: Öffnet beide Arten von Stop-Orders, die jeweils mit einem bestimmten Ereignis verknüpft sind, wobei die EventId des Ereignisses als magische Zahl für den Handel verwendet wird.
Die Funktion OnTrade
Diese Funktion wird immer dann ausgelöst, wenn ein neues Handelsereignis eintritt. Diese Funktion wird für die Verwaltung von Handelsgeschäften verwendet.
void OnTrade() { //--- Check if time is within the trading session if(CTS.isSessionStart() && !CTS.isSessionEnd(0,0)) { //--- Run procedures ExecutionOnTrade(); } }
- CTS.isSessionStart() and !CTS.isSessionEnd(0,0):
- CTS (Objekt der Klasse Sessions) wird verwendet, um zu prüfen, ob die aktuelle Zeit in eine aktive Handelssitzung fällt.
- isSessionStart() prüft, ob die Sitzung begonnen hat.
- !CTS.isSessionEnd(0,0) prüft, ob die Sitzung noch nicht beendet ist. Das Argument 0,0 steht für den Versatz oder den Pufferzeitraum vor dem Ende der Sitzung.
- Dadurch wird sichergestellt, dass Handelsgeschäfte nur dann angepasst werden, wenn der aktuelle Zeitpunkt innerhalb einer aktiven Handelssitzung liegt.
- ExecutionOnTrade();:
- Wenn die Sitzung aktiv ist, wird die Funktion ExecutionOnTrade() aufgerufen, um die Ausführung der erforderlichen Verfahren im Zusammenhang mit dem neuen Geschäft zu steuern.
Die Funktion ExecutionOnTrade
Diese Funktion enthält die Logik, die jedes Mal abläuft, wenn ein neuer Handelsgeschäft ausgeführt wird.
void ExecutionOnTrade() { //--- if stop orders, enable fundamental mode if(iOrderType == StopOrdersType) { Trade.FundamentalMode("NewsTrading"); } //--- when stop order(s), enable slippage reduction if(iOrderType != MarketPositionType) { Trade.SlippageReduction(iStoploss, iTakeprofit, "NewsTrading"); } }
- if (iOrderType == StopOrdersType):
- Hier wird geprüft, ob es sich bei dem aktuellen Handel um eine Stop-Order (StopOrdersType) handelt. Wenn die Bedingung erfüllt ist, ruft der Code die Funktion Trade.FundamentalMode() auf.
- Trade.FundamentalMode("NewsTrading");:
- Mit dieser Funktion wird der Fundamentalmodus aktiviert. Diese Funktion ist für die Löschung schwebender Aufträge in der entgegengesetzten Richtung zuständig.
- "NewsTrading": Dies ist die Kennzeichnung im Kommentar einer Position des EAs.
- if(iOrderType != MarketPositionType):
- Diese Bedingung prüft, ob die Eingangsvariable nicht die Enumeration MarketPositionType ist. Bei „true“ aktiviert der Code die Verringerung des Slippage.
- Trade.SlippageReduction(iStoploss, iTakeprofit, „NewsTrading“):
- Diese Funktion reduziert die Slippage bei nicht marktgerechten Aufträgen.
- Slippage tritt auf, wenn der ausgeführte Preis vom erwarteten Preis abweicht, insbesondere bei volatilen Märkten oder Nachrichtenereignissen.
- Durch den Aufruf von SlippageReduction() versucht der EA, diesen Schlupf zu minimieren.
- Parameter:
- iStoploss: Der Stop-Loss-Wert, d. h. der Preis, bei dem der Handel automatisch geschlossen werden soll, um mögliche Verluste zu begrenzen.
- iTakeprofit: Der Take-Profit-Wert, d. h. der Preis, zu dem der Handel automatisch geschlossen werden sollte, um Gewinne zu sichern.
- "NewsTrading": Dies ist die Kennzeichnung im Kommentar einer Position des EAs.
Schlussfolgerung
In diesem Artikel ermöglicht es der Experte den Nutzern, nutzerdefinierte Nachrichtenereignisse zu definieren, auf die der Expert Advisor reagieren soll. Diese Ereignisse werden durch Nutzereingaben initialisiert, die dann vom Experten analysiert und entsprechend behandelt werden. Die gespeicherte Kalenderdatenbank wurde verbessert, um zusätzliche Informationen über bevorstehende und kürzlich stattgefundene Ereignisse in Form von Ansichten bereitzustellen, wobei die Abfragen der einzelnen Ansichten im Detail erläutert wurden. Die Funktionen OnTimer und OnTrade wurden hinzugefügt, um die Codeausführung auf der Grundlage bestimmter zeitlicher Bedingungen zu steuern. Vielen Dank für Ihre Zeit, ich freue mich darauf, im nächsten Artikel mehr Wert zu bieten :)
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16170






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