English Русский 中文 日本語
preview
Handel mit dem MQL5 Wirtschaftskalender (Teil 4): Implementierung von Echtzeit-Nachrichtenaktualisierungen im Dashboard

Handel mit dem MQL5 Wirtschaftskalender (Teil 4): Implementierung von Echtzeit-Nachrichtenaktualisierungen im Dashboard

MetaTrader 5Handel |
113 2
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In diesem Artikel bringen wir unsere Arbeit am Dashboard des MetaQuotes Language 5 (MQL5) Wirtschaftskalenders weiter voran, indem wir eine Funktion für Live-Updates hinzufügen, die es uns ermöglicht, eine ständig aktualisierte Anzeige wichtiger Wirtschaftsnachrichten zu erhalten. Im vorangegangenen Teil haben wir ein Dashboard-Panel entworfen und implementiert, mit dem wir Nachrichten nach Währung, Wichtigkeit und Zeit filtern können, sodass wir eine maßgeschneiderte Ansicht der relevanten Ereignisse erhalten. Jetzt gehen wir noch einen Schritt weiter, indem wir Aktualisierungen in Echtzeit ermöglichen und so sicherstellen, dass unser Kalender die aktuellsten Daten anzeigt, um zeitnahe Entscheidungen zu treffen. Zu den Themen, die wir behandeln werden, gehören:

  1. Implementierung von Echtzeit-Nachrichtenaktualisierungen in MQL5
  2. Schlussfolgerung

Diese Erweiterung wird unser Dashboard in ein dynamisches Echtzeit-Tool verwandeln, das ständig mit den neuesten wirtschaftlichen Ereignissen aktualisiert wird. Durch die Implementierung der Live-Aktualisierungsfunktionalität stellen wir sicher, dass unser Kalender stets genau und aktuell ist und zeitnahe Handelsentscheidungen im MetaTrader 5 oder dem Handelsterminal unterstützt.


Implementierung von Echtzeit-Nachrichtenaktualisierungen in MQL5

Um Live-Updates für unser Dashboard zu implementieren, müssen wir sicherstellen, dass Nachrichtenereignisse gespeichert und regelmäßig verglichen werden, um Änderungen zu erkennen. Dies erfordert die Pflege von Arrays, in denen aktuelle und frühere Ereignisdaten gespeichert werden, damit wir Aktualisierungen erkennen und sie auf dem Dashboard genau wiedergeben können. Auf diese Weise können wir sicherstellen, dass das Dashboard dynamisch angepasst wird, um die neuesten wirtschaftlichen Ereignisse in Echtzeit anzuzeigen. Im Folgenden definieren wir die Arrays, die wir zu diesem Zweck verwenden werden:

string current_eventNames_data[];
string previous_eventNames_data[];

Hier definieren wir zwei String-Arrays, „current_eventNames_data“ und „previous_eventNames_data“, die wir zur Verwaltung und zum Vergleich von Wirtschaftsereignisdaten für Live-Aktualisierungen des Dashboards verwenden werden. Das Array „current_eventNames_data“ speichert die letzten aus dem Wirtschaftskalender abgerufenen Ereignisse, während „previous_eventNames_data“ die Daten des letzten Aktualisierungszyklus enthält. Durch den Vergleich dieser beiden Arrays können wir alle Änderungen oder Neuzugänge zu den Ereignissen erkennen, sodass wir das Dashboard dynamisch aktualisieren können.

Mithilfe dieser Arrays müssen wir die aktuellen Werte für jedes im Initialisierungsabschnitt ausgewählte Ereignis abrufen und im Array des aktuellen Datenhalters speichern, um sie später in den vorherigen Datenhalter zu kopieren, den wir für den Vergleich beim nächsten Preis-Tick verwenden werden.

ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;

Hier wird das Array „current_eventNames_data“ dynamisch erweitert und um einen neuen Ereignisnamen ergänzt. Wir verwenden die Funktion ArrayResize, um die Größe des Arrays um eins zu erhöhen und so Platz für einen neuen Eintrag zu schaffen. Nach der Größenänderung wird der Name des Ereignisses dem letzten Index des Arrays mit dem Ausdruck „current_eventNames_data[ArraySize(current_eventNames_data)-1]“ zugewiesen. Dieser Prozess stellt sicher, dass jedes neue Ereignis, das aus dem Wirtschaftskalender abgerufen wird, in dem Array gespeichert wird, sodass wir eine aktuelle Liste von Ereignissen für die weitere Verarbeitung und den Vergleich erhalten können.

Bevor wir die Ereignisse dem Array hinzufügen, müssen wir jedoch sicherstellen, dass wir neu beginnen, d. h. wir brauchen ein leeres Array.

ArrayFree(current_eventNames_data);

Hier verwenden wir die Funktion ArrayFree, um alle Elemente aus dem Array „current_eventNames_data“ zu löschen und es somit auf einen leeren Zustand zurückzusetzen. Dies ist wichtig, um sicherzustellen, dass das Array keine veralteten Daten aus früheren Iterationen speichert, und um es darauf vorzubereiten, während des Verarbeitungszyklus einen neuen Satz von Ereignisnamen zu speichern. Nach dem Füllen des Arrays müssen wir es dann in den vorherigen Halter kopieren und später für den Vergleich verwenden.

Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

Hier protokollieren und verwalten wir den Übergang von Daten zwischen den Arrays „current_eventNames_data“ und „previous_eventNames_data“. Zunächst verwenden wir die Funktion Print, um die Größe des Arrays „current_eventNames_data“ anzuzeigen und so die Anzahl der zu diesem Zeitpunkt gespeicherten Ereignisnamen zu ermitteln. Anschließend rufen wir die Funktion ArrayPrint auf, um den Inhalt des Arrays zur weiteren Überprüfung auszugeben. Als Nächstes protokollieren wir die Größe des Arrays „previous_eventNames_data“ vor dem Kopieren, um eine Vergleichsgrundlage zu haben.

Mit der Funktion ArrayCopy wird der Inhalt von „current_eventNames_data“ in „previous_eventNames_data“ kopiert, wodurch die neuesten Ereignisnamen für zukünftige Vergleiche übertragen werden. Anschließend wird die Größe des Arrays „previous_eventNames_data“ nach dem Kopiervorgang ausgegeben, um die erfolgreiche Aktualisierung zu bestätigen. Schließlich rufen wir die Funktion ArrayPrint auf, um den aktualisierten Inhalt von „previous_eventNames_data“ auszugeben und sicherzustellen, dass die Datenübertragung korrekt und vollständig ist. Dies sind die Änderungen, die wir in OnInit vornehmen müssen, um die ersten Ereignisse zu speichern. Sie sind zur Verdeutlichung hervorgehoben.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //---

   ArrayFree(current_eventNames_data);
      
   //--- Loop through each calendar value up to the maximum defined total
   for (int i = 0; i < valuesTotal; i++){
   
      //---

      //--- Loop through calendar data columns
      for (int k=0; k<ArraySize(array_calendar); k++){
         //---

         //--- Prepare news data array with time, country, and other event details
         string news_data[ArraySize(array_calendar)];
         news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
         news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
         news_data[2] = country.currency; //--- Event country currency
      
         //--- Determine importance color based on event impact
         color importance_color = clrBlack;
         if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
         else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
         else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
      
         //--- Set importance symbol for the event
         news_data[3] = ShortToString(0x25CF);
      
         //--- Set event name in the data array
         news_data[4] = event.name;
            
         //--- Populate actual, forecast, and previous values in the news data array
         news_data[5] = DoubleToString(value.GetActualValue(),3);
         news_data[6] = DoubleToString(value.GetForecastValue(),3);
         news_data[7] = DoubleToString(value.GetPreviousValue(),3);         
         //---

      }
      
      ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
      current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
      
   }
   Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
   ArrayPrint(current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
   ArrayCopy(previous_eventNames_data,current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data); 
   
   //Print("Final News = ",news_filter_count);
   updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(),
              TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
              IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));
//---
   return(INIT_SUCCEEDED);
}

Hier haben wir nur die Änderungen vorgenommen, die uns helfen werden, die ersten Ereignisdaten zu erhalten. Wir haben sie der Übersichtlichkeit halber gelb hervorgehoben. Als Nächstes müssen wir nur die Dashboard-Werte aktualisieren, wenn beim Vergleich Änderungen festgestellt werden. Dazu erstellen wir eine nutzerdefinierte Funktion, die die gesamte Logik für die Ereignisaktualisierungen bzw. die Neuberechnung des Dashboards enthält.

//+------------------------------------------------------------------+
//| Function to update dashboard values                              |
//+------------------------------------------------------------------+
void update_dashboard_values(){

//---

}

Hier definieren wir die Funktion „update_dashboard_values“, mit der wir die dynamische Aktualisierung des Dashboards des Wirtschaftskalenders durchführen werden. Diese Funktion enthält die Kernlogik für den Vergleich gespeicherter Nachrichtendaten, die Erkennung von Änderungen und die Anwendung der erforderlichen Aktualisierungen auf die Dashboard-Oberfläche. Indem wir diese Funktionalität in dieser speziellen Funktion organisieren, stellen wir eine saubere und modulare Codestruktur sicher, die künftige Änderungen oder Erweiterungen einfacher zu verwalten macht. Anschließend rufen wir die Funktion in OnTick wie folgt auf.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
//---
   
   update_dashboard_values();
   
}

Hier rufen wir die nutzerdefinierte Funktion einfach bei jedem Tick auf, um die Aktualisierungen durchzuführen. Nach dem Kompilieren und Ausführen des Programms erhalten wir die folgenden Ergebnisse:

INITIALISIERUNG ARRAYS DATEN

Aus dem Bild ist ersichtlich, dass wir alle Nachrichtenereignisse im Array „current“ sammeln, das wir dann zur Speicherung in das frische Array „previous“ kopieren, was genau unseren Vorstellungen entspricht. Wir können nun diese kopierten Daten für die weitere Analyse verwenden. In der Funktion werden einfach die aktuellen Ereignisse wie folgt ermittelt:

//--- Declare variables for tracking news events and status
int totalNews = 0;
bool isNews = false;
MqlCalendarValue values[]; //--- Array to store calendar values

//--- Define start and end time for calendar event retrieval
datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H12);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H12);

//--- Set a specific country code filter (e.g., "US" for USD)
string country_code = "US";
string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE);

//--- Retrieve historical calendar values within the specified time range
int allValues = CalendarValueHistory(values,startTime,endTime,NULL,NULL);

//--- Print the total number of values retrieved and the array size
//Print("TOTAL VALUES = ",allValues," || Array size = ",ArraySize(values));

//--- Define time range for filtering news events based on daily period
datetime timeRange = PeriodSeconds(PERIOD_D1);
datetime timeBefore = TimeTradeServer() - timeRange;
datetime timeAfter = TimeTradeServer() + timeRange;

//--- Print the furthest time look-back and current server time
//Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> CURRENT = ",TimeTradeServer());

//--- Limit the total number of values to display
int valuesTotal = (allValues <= 11) ? allValues : 11;
   
string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"};
int news_filter_count = 0;

ArrayFree(current_eventNames_data);

// Define the levels of importance to filter (low, moderate, high)
ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH};

//--- Loop through each calendar value up to the maximum defined total
for (int i = 0; i < valuesTotal; i++){

   MqlCalendarEvent event; //--- Declare event structure
   CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID

   MqlCalendarCountry country; //--- Declare country structure
   CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID

   MqlCalendarValue value; //--- Declare calendar value structure
   CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values
   
   //--- Check if the event’s currency matches any in the filter array (if the filter is enabled)
   bool currencyMatch = false;
   if (enableCurrencyFilter) {
      for (int j = 0; j < ArraySize(curr_filter); j++) {
         if (country.currency == curr_filter[j]) {
            currencyMatch = true;
            break;
         }
      }
      
      //--- If no match found, skip to the next event
      if (!currencyMatch) {
         continue;
      }
   }
   
   //--- Check importance level if importance filter is enabled
   bool importanceMatch = false;
   if (enableImportanceFilter) {
      for (int k = 0; k < ArraySize(allowed_importance_levels); k++) {
         if (event.importance == allowed_importance_levels[k]) {
            importanceMatch = true;
            break;
         }
      }
      
      //--- If importance does not match the filter criteria, skip the event
      if (!importanceMatch) {
         continue;
      }
   }
   
   //--- Apply time filter and set timeMatch flag (if the filter is enabled)
   bool timeMatch = false;
   if (enableTimeFilter) {
      datetime eventTime = values[i].time;
      
      if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) {
         timeMatch = true;  //--- Event is already released
      }
      else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) {
         timeMatch = true;  //--- Event is yet to be released
      }
      
      //--- Skip if the event doesn't match the time filter
      if (!timeMatch) {
         continue;
      }
   }
   
   //--- If we reach here, the currency matches the filter
   news_filter_count++; //--- Increment the count of filtered events
   
   //--- Set alternating colors for each data row holder
   color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite;
      
   //--- Loop through calendar data columns
   for (int k=0; k<ArraySize(array_calendar); k++){
         
      //--- Print event details for debugging
      //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time);
   
      //--- Skip event if currency does not match the selected country code
      // if (StringFind(_Symbol,country.currency) < 0) continue;
   
      //--- Prepare news data array with time, country, and other event details
      string news_data[ArraySize(array_calendar)];
      news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
      news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
      news_data[2] = country.currency; //--- Event country currency
   
      //--- Determine importance color based on event impact
      color importance_color = clrBlack;
      if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
      else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
      else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
   
      //--- Set importance symbol for the event
      news_data[3] = ShortToString(0x25CF);
   
      //--- Set event name in the data array
      news_data[4] = event.name;
         
      //--- Populate actual, forecast, and previous values in the news data array
      news_data[5] = DoubleToString(value.GetActualValue(),3);
      news_data[6] = DoubleToString(value.GetForecastValue(),3);
      news_data[7] = DoubleToString(value.GetPreviousValue(),3);
   }
   
   ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
   current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
  
}   
//Print("Final News = ",news_filter_count);
updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(),
           TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
           IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));

Dies ist nur der vorherige Codeschnipsel, den wir während des Initialisierungsabschnitts verwendet haben, aber wir brauchen ihn bei jedem Tick, um die Aktualisierungen zu erhalten. Wir werden sie jedoch kurz durchgehen. Wir konzentrieren uns auf die dynamische Aktualisierung des Dashboards mit den neuesten Wirtschaftsnachrichten bei jedem Tick. Um dies zu erreichen, straffen wir die Logik, indem wir die Erstellung grafischer Objekte entfernen und uns stattdessen auf die effiziente Verwaltung von Ereignisdaten konzentrieren. Wir beginnen mit der Definition von Variablen, um die Gesamtzahl der Nachrichten und Filterkriterien wie Währung, Wichtigkeit und Zeiträume zu erfassen. Diese Filter stellen sicher, dass nur relevante Ereignisse für die weitere Verarbeitung berücksichtigt werden.

Wir durchlaufen die abgerufenen Kalenderwerte in einer Schleife und wenden die Filter an, um Ereignisse zu identifizieren, die den angegebenen Bedingungen entsprechen. Für jedes übereinstimmende Ereignis extrahieren wir wichtige Details wie den Namen des Ereignisses, die Uhrzeit, die Währung und die Wichtigkeitsstufe. Diese Details werden in dem Array „current_eventNames_data“ gespeichert, dessen Größe dynamisch angepasst wird, um neue Einträge aufzunehmen. Dieses Array ist für die Verfolgung der Ereignisse von entscheidender Bedeutung und ermöglicht es uns, Veränderungen zwischen den Ticks zu erkennen, indem wir sie mit früheren Daten vergleichen. Schließlich aktualisieren wir die Beschriftung des Dashboards, um die Summe der gefilterten Ereignisse und die aktuelle Serverzeit wiederzugeben, um sicherzustellen, dass das Dashboard immer die neuesten Ereignisdaten wiedergibt, ohne unnötige Objekte zu erstellen. Mit diesem Ansatz werden die Wirtschaftsnachrichten effizient erfasst und in Echtzeit aktualisiert.

Als Nächstes müssen wir anhand der neu erfassten Daten feststellen, ob es Änderungen in den Speicher-Arrays gibt. Zu diesem Zweck verwenden wir eine nutzerdefinierte Funktion.

//+------------------------------------------------------------------+
//|   Function to compare two string arrays and detect changes       |
//+------------------------------------------------------------------+
bool isChangeInStringArrays(string &arr1[], string &arr2[]) {
   bool isChange = false;
   
   int size1 = ArraySize(arr1);  // Get the size of the first array
   int size2 = ArraySize(arr2);  // Get the size of the second array
   
   // Check if sizes are different
   if (size1 != size2) {
      Print("Arrays have different sizes. Size of Array 1: ", size1, ", Size of Array 2: ", size2);
      isChange = true;
      return (isChange);
   }

   // Loop through the arrays and compare corresponding elements
   for (int i = 0; i < size1; i++) {
      // Compare the strings at the same index in both arrays
      if (StringCompare(arr1[i], arr2[i]) != 0) {  // If strings are different
         // Action when strings differ at the same index
         Print("Change detected at index ", i, ": '", arr1[i], "' vs '", arr2[i], "'");
         isChange = true;
         return (isChange);
      }
   }

   // If no differences are found, you can also log this as no changes detected
   //Print("No changes detected between arrays.");
   return (isChange);
}

Hier definieren wir die boolesche Funktion „isChangeInStringArrays“, die zwei String-Arrays, „arr1“ und „arr2“, vergleicht, um Änderungen zwischen ihnen zu erkennen. Zunächst werden die Größen der beiden Arrays mit der Funktion ArraySize bestimmt und in „size1“ und „size2“ gespeichert. Wenn sich die Größen der Arrays unterscheiden, geben wir die jeweiligen Größen aus, setzen das Flag „isChange“ auf true und geben true zurück, was eine Änderung anzeigt. Wenn die Größen gleich sind, vergleichen wir die Elemente der Arrays in einer for-Schleife. Für jeden Index verwenden wir die Funktion StringCompare, um zu prüfen, ob die Zeichenketten in beiden Arrays identisch sind. Wenn sich die Zeichenketten unterscheiden, werden die Details der Änderung gedruckt und „isChange“ auf true gesetzt, sodass true zurückgegeben wird, um die Aktualisierung zu signalisieren. Wenn nach der Schleife keine Unterschiede gefunden werden, gibt die Funktion den Wert false zurück, was bedeutet, dass es keine Änderungen gibt. Dieser Ansatz ist wichtig, um Aktualisierungen zu erkennen, z. B. neue oder aktualisierte Nachrichten, die auf dem Dashboard angezeigt werden müssen.

Mit der Funktion ausgestattet, können wir sie dann zur Aktualisierung der Ereignisse verwenden.

if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){
   Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES");
   
   ObjectsDeleteAll(0,DATA_HOLDERS);
   ObjectsDeleteAll(0,ARRAY_NEWS);
   
   ArrayFree(current_eventNames_data);

   //---

}

Hier wird geprüft, ob es eine Änderung zwischen den Arrays „previous_eventNames_data“ und „current_eventNames_data“ gegeben hat, indem die Funktion „isChangeInStringArrays“ aufgerufen wird. Wenn die Funktion den Wert true zurückgibt, was bedeutet, dass Änderungen erkannt wurden, wird die Meldung „CHANGES IN EVENT NAMES DETECTED UPDATE THE DASHBOARD VALUES“ (Änderungen des Ereignisnamens erkannt. Aktualisieren der Werte des Dashboards) ausgegeben. Anschließend löschen wir alle Objekte, die mit Datenhaltern und Nachrichten-Arrays im Diagramm zusammenhängen, mit der Funktion ObjectsDeleteAll, wobei wir die Bezeichner „DATA_HOLDERS“ und „ARRAY_NEWS“ als Objektpräfixe angeben. Wir tun dies, um veraltete Informationen zu bereinigen, bevor wir das Dashboard mit den neuesten Ereignisdaten aktualisieren. Schließlich wird der vom Array „current_eventNames_data“ belegte Speicher mit der Funktion ArrayFree freigegeben, um sicherzustellen, dass das Array in Vorbereitung auf die nächste Aktualisierung geleert wird. Anschließend aktualisieren wir die Ereignisdaten wie üblich, erstellen aber diesmal die Datenhalter und aktualisieren die Nachrichtenereignisse auf dem neuen Dashboard. Hier ist die Logik.

if (isChangeInStringArrays(previous_eventNames_data,current_eventNames_data)){
   Print("CHANGES IN EVENT NAMES DETECTED. UPDATE THE DASHBOARD VALUES");
   
   ObjectsDeleteAll(0,DATA_HOLDERS);
   ObjectsDeleteAll(0,ARRAY_NEWS);
   
   ArrayFree(current_eventNames_data);
   
   //--- Initialize starting y-coordinate for displaying news data
   int startY = 162;
   //--- Loop through each calendar value up to the maximum defined total
   for (int i = 0; i < valuesTotal; i++){
   
      MqlCalendarEvent event; //--- Declare event structure
      CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID
   
      MqlCalendarCountry country; //--- Declare country structure
      CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID

      MqlCalendarValue value; //--- Declare calendar value structure
      CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values
      
      //--- Check if the event’s currency matches any in the filter array (if the filter is enabled)
      bool currencyMatch = false;
      if (enableCurrencyFilter) {
         for (int j = 0; j < ArraySize(curr_filter); j++) {
            if (country.currency == curr_filter[j]) {
               currencyMatch = true;
               break;
            }
         }
         
         //--- If no match found, skip to the next event
         if (!currencyMatch) {
            continue;
         }
      }
      
      //--- Check importance level if importance filter is enabled
      bool importanceMatch = false;
      if (enableImportanceFilter) {
         for (int k = 0; k < ArraySize(allowed_importance_levels); k++) {
            if (event.importance == allowed_importance_levels[k]) {
               importanceMatch = true;
               break;
            }
         }
         
         //--- If importance does not match the filter criteria, skip the event
         if (!importanceMatch) {
            continue;
         }
      }
      
      //--- Apply time filter and set timeMatch flag (if the filter is enabled)
      bool timeMatch = false;
      if (enableTimeFilter) {
         datetime eventTime = values[i].time;
         
         if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) {
            timeMatch = true;  //--- Event is already released
         }
         else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) {
            timeMatch = true;  //--- Event is yet to be released
         }
         
         //--- Skip if the event doesn't match the time filter
         if (!timeMatch) {
            continue;
         }
      }
         
      //--- If we reach here, the currency matches the filter
      news_filter_count++; //--- Increment the count of filtered events
      
      //--- Set alternating colors for each data row holder
      color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite;
   
      //--- Create rectangle label for each data row holder
      createRecLabel(DATA_HOLDERS+string(news_filter_count),62,startY-1,716,26+1,holder_color,1,clrNONE);
   
      //--- Initialize starting x-coordinate for each data entry
      int startX = 65;
      
      //--- Loop through calendar data columns
      for (int k=0; k<ArraySize(array_calendar); k++){
            
         //--- Print event details for debugging
         //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time);
      
         //--- Skip event if currency does not match the selected country code
         // if (StringFind(_Symbol,country.currency) < 0) continue;
      
         //--- Prepare news data array with time, country, and other event details
         string news_data[ArraySize(array_calendar)];
         news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date
         news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time
         news_data[2] = country.currency; //--- Event country currency
      
         //--- Determine importance color based on event impact
         color importance_color = clrBlack;
         if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;}
         else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;}
         else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;}
      
         //--- Set importance symbol for the event
         news_data[3] = ShortToString(0x25CF);
      
         //--- Set event name in the data array
         news_data[4] = event.name;
            
         //--- Populate actual, forecast, and previous values in the news data array
         news_data[5] = DoubleToString(value.GetActualValue(),3);
         news_data[6] = DoubleToString(value.GetForecastValue(),3);
         news_data[7] = DoubleToString(value.GetPreviousValue(),3);         
         
         //--- Create label for each news data item
         if (k == 3){
            createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY-(22-12),news_data[k],importance_color,22,"Calibri");
         }
         else {
            createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY,news_data[k],clrBlack,12,"Calibri");
         }
      
         //--- Increment x-coordinate for the next column
         startX += buttons[k]+3;
      }
      
      ArrayResize(current_eventNames_data,ArraySize(current_eventNames_data)+1);
      current_eventNames_data[ArraySize(current_eventNames_data)-1] = event.name;
      
      //--- Increment y-coordinate for the next row of data
      startY += 25;
      //Print(startY); //--- Print current y-coordinate for debugging
   }
   
   Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
   ArrayPrint(current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data);
   ArrayFree(previous_eventNames_data);
   ArrayCopy(previous_eventNames_data,current_eventNames_data);
   Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
   ArrayPrint(previous_eventNames_data);
   
}

Hier aktualisieren wir das Dashboard auf der Grundlage der neu erfassten Daten, um sicherzustellen, dass die Aktualisierungen auch tatsächlich vorgenommen werden. Mit Hilfe der Kopierlogik protokollieren wir die Daten in den „vorherigen“ Datenträger, sodass wir die aktuellen Daten bei der nächsten Prüfung verwenden können. Wir haben die Logik hervorgehoben, die dafür sorgt, aber lassen Sie uns einen genaueren Blick darauf werfen.

Print("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
ArrayPrint(current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (Before) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);
ArrayFree(previous_eventNames_data);
ArrayCopy(previous_eventNames_data,current_eventNames_data);
Print("PREVIOUS EVENT NAMES DATA SIZE (After) = ",ArraySize(previous_eventNames_data));
ArrayPrint(previous_eventNames_data);

Hier beginnen wir damit, die aktuelle Größe des Arrays „current_eventNames_data“ mit der Funktion ArraySize zu drucken und seinen Inhalt mit der Funktion ArrayPrint anzuzeigen. Auf diese Weise können wir den aktuellen Satz von Ereignisnamen, die wir verfolgen, überprüfen. Anschließend wird die Größe des Arrays „previous_eventNames_data“ ausgedruckt, bevor es aktualisiert wird, und anschließend sein Inhalt.

Als Nächstes geben wir den von „previous_eventNames_data“ verwendeten Speicher mit der Funktion ArrayFree frei, um sicherzustellen, dass alle zuvor im Array gespeicherten Daten gelöscht werden, um Speicherprobleme zu vermeiden. Nach der Freigabe des Speichers wird der Inhalt des Arrays „current_eventNames_data“ mit der Funktion ArrayCopy in das Array „previous_eventNames_data“ kopiert, sodass es mit den neuesten Ereignisnamen aktualisiert wird.

Schließlich wird die aktualisierte Größe des Arrays „previous_eventNames_data“ und sein Inhalt ausgedruckt, um zu bestätigen, dass das Array nun die neuesten Ereignisnamen enthält. Dadurch wird sichergestellt, dass die früheren Ereignisnamen für zukünftige Vergleiche korrekt aktualisiert werden. Nach Ausführung des Programms erhalten wir folgendes Ergebnis.

Zeitaktualisierungen.

ZEITAKTUALISIERUNG GIF

Aktualisierung der Ereignisse.

VERANSTALTUNGEN UPDATE

Aktualisierung des Dashboards.

DASHBOARD-UPDATE

Auf dem Bild ist zu sehen, dass die neu registrierten Daten auf dem Dashboard genau aktualisiert werden. Um dies zu bestätigen, können wir wieder einige Zeit warten und versuchen, diese Daten zu verfolgen, und zwar mit demjenigen, der die aktualisierten Daten protokolliert. Hier ist das Ergebnis.

Aktualisierung der Ereignisdaten.

AKTUALISIERUNG DER DATEN ZU NEUEN EREIGNISSEN

Aktualisierung des Dashboards.

NEUES DASHBOARD-UPDATE

Aus dem Bild ist ersichtlich, dass Änderungen gegenüber den zuvor gespeicherten Daten erkannt und entsprechend den neu registrierten Daten aktualisiert und zur weiteren Verwendung gespeichert werden. Die gespeicherten Daten werden verwendet, um die Dashboard-Oberfläche in Echtzeit zu aktualisieren und die aktuellen Nachrichtenereignisse anzuzeigen, was den Erfolg unseres Ziels bestätigt.


Schlussfolgerung

Zusammenfassend lässt sich sagen, dass wir ein robustes System zur Überwachung und Erkennung von Änderungen in MQL5-Wirtschaftsnachrichten-Ereignissen implementiert haben, indem wir zuvor gespeicherte Ereignisdaten mit neu abgerufenen Aktualisierungen vergleichen. Dieser Vergleichsmechanismus stellt sicher, dass alle Unterschiede in den Ereignisnamen oder -details sofort erkannt werden und unser Dashboard aktualisiert wird, um Genauigkeit und Relevanz zu gewährleisten. Durch das Filtern von Daten nach Währung, Wichtigkeit und Zeit konnten wir den Prozess weiter verfeinern, um uns auf wichtige Ereignisse zu konzentrieren und die Schnittstelle dynamisch zu aktualisieren.

In den nächsten Teilen dieser Serie werden wir auf dieser Grundlage aufbauen, indem wir Wirtschaftsnachrichten in Handelsstrategien integrieren und so die praktische Anwendung der Daten ermöglichen. Darüber hinaus wollen wir die Funktionalität des Dashboards durch die Einführung von Mobilität und Reaktionsfähigkeit verbessern, um den Händlern ein nahtloses und interaktives Erlebnis zu bieten. Bleiben Sie am Ball.

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16386

Beigefügte Dateien |
Letzte Kommentare | Zur Diskussion im Händlerforum (2)
Stanislav Korotky
Stanislav Korotky | 3 Dez. 2024 in 20:57
Die Benutzer werden wahrscheinlich daran interessiert sein, zu erfahren, dass dieselben Themen im Algotrading-Buch ausführlich behandelt wurden (und die Website zeigt dies nicht irgendwie in automatischen Vorschlägen an), einschließlich der Verfolgung und Speicherung von Ereignisänderungen, der Filterung von Ereignissen nach mehreren Bedingungen (mit verschiedenen logischen Operatoren) für einen erweiterten Satz von Feldern, der Anzeige einer anpassbaren On-the-fly-Kalenderuntermenge in einem Panel auf dem Diagramm und der Einbettung für den Handel in EAs mit Unterstützung der Übertragung des kompletten Archivs des Kalenders in den Tester.
Allan Munene Mutiiria
Allan Munene Mutiiria | 5 Dez. 2024 in 00:08
Stanislav Korotky #:
Die Benutzer werden wahrscheinlich daran interessiert sein, zu erfahren, dass dieselben Themen im Algotrading-Buch ausführlich behandelt werden (und die Website zeigt dies nicht irgendwie in den automatischen Vorschlägen an), einschließlich der Verfolgung und Speicherung von Ereignisänderungen, der Filterung von Ereignissen nach mehreren Bedingungen (mit verschiedenen logischen Operatoren) für einen erweiterten Satz von Feldern, der Anzeige einer anpassbaren On-the-fly-Kalenderteilmenge in einem Panel auf dem Chart und der Einbettung für den Handel in EAs mit Unterstützung der Übertragung des vollständigen Archivs des Kalenders in den Tester.
Okay, danke. Vielen Dank!
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil VIII): Das Analytics Panel Erstellen eines Handelsadministrator-Panels in MQL5 (Teil VIII): Das Analytics Panel
Heute befassen wir uns mit dem Einbinden nützlicher Handelsmetriken in ein spezielles Fenster, das in den Admin Panel EA integriert ist. Diese Diskussion konzentriert sich auf die Implementierung von MQL5 zur Entwicklung des „Analytics Panel“ und hebt den Wert der Daten hervor, die es den Handelsadministratoren liefert. Die Auswirkungen sind weitgehend lehrreich, da aus dem Entwicklungsprozess wertvolle Lehren gezogen werden, von denen sowohl angehende als auch erfahrene Entwickler profitieren. Diese Funktion zeigt die grenzenlosen Möglichkeiten, die diese Entwicklungsreihe für die Ausstattung von Handelsmanagern mit fortschrittlichen Softwaretools bietet. Darüber hinaus werden wir die Implementierung der Klassen PieChart und ChartCanvas als Teil der kontinuierlichen Erweiterung der Funktionen des Trading Administrator-Panels untersuchen.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 50): Der Awesome Oszillator MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 50): Der Awesome Oszillator
Der Awesome Oscillator ist ein weiterer Bill-Williams-Indikator, der zur Messung des Momentums verwendet wird. Es kann mehrere Signale generieren, und deshalb überprüfen wir diese auf der Basis von Mustern, wie in früheren Artikeln, indem wir die MQL5-Assistenten-Klassen und -Assembly nutzen.
Nutzung des CatBoost Machine Learning Modells als Filter für Trendfolgestrategien Nutzung des CatBoost Machine Learning Modells als Filter für Trendfolgestrategien
CatBoost ist ein leistungsfähiges, baumbasiertes, maschinelles Lernmodell, das auf die Entscheidungsfindung auf der Grundlage stationärer Merkmale spezialisiert ist. Andere baumbasierte Modelle wie XGBoost und Random Forest haben ähnliche Eigenschaften in Bezug auf ihre Robustheit, ihre Fähigkeit, komplexe Muster zu verarbeiten, und ihre Interpretierbarkeit. Diese Modelle haben ein breites Anwendungsspektrum, das von der Merkmalsanalyse bis zum Risikomanagement reicht.
Meistern der Log-Einträge (Teil 1): Grundlegende Konzepte und erste Schritte in MQL5 Meistern der Log-Einträge (Teil 1): Grundlegende Konzepte und erste Schritte in MQL5
Willkommen zum Beginn einer neuen Reise! Dieser Artikel eröffnet eine spezielle Serie, in der wir Schritt für Schritt eine Bibliothek für die Logmanipulation erstellen, die auf diejenigen zugeschnitten ist, die in der Sprache MQL5 entwickeln.