English 日本語
preview
Handel mit dem MQL5 Wirtschaftskalender (Teil 5): Verbessern des Dashboards mit reaktionsschnellen Steuerelementen und Filterschaltflächen

Handel mit dem MQL5 Wirtschaftskalender (Teil 5): Verbessern des Dashboards mit reaktionsschnellen Steuerelementen und Filterschaltflächen

MetaTrader 5Handel | 14 April 2025, 08:00
43 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In diesem Artikel bauen wir auf der vorherigen Arbeit in Teil 4 der Serie MetaQuotes Language 5 (MQL5) auf, in der wir dem Dashboard des MQL5-Wirtschaftskalenders Echtzeit-Updates hinzugefügt haben. Hier konzentrieren wir uns darauf, das Dashboard interaktiver zu gestalten, indem wir Schaltflächen hinzufügen, die es uns ermöglichen, die Filter für Währungspaare, Wichtigkeitsstufen und Zeitspannen direkt vom Panel aus zu steuern, ohne dass wir die Einstellungen im Code ändern müssen. Wir werden auch eine Schaltfläche „Cancel“ (Abbrechen) einfügen, die die ausgewählten Filter löscht und die Komponenten des Dashboards entfernt, sodass wir die volle Kontrolle über die Anzeige haben. Schließlich werden wir die Nutzerfreundlichkeit verbessern, indem wir die Schaltflächen so gestalten, dass sie auf Klicks reagieren, reibungslos funktionieren und sofortiges Feedback geben. Zu den Themen, die wir in diesem Artikel behandeln, gehören:

  1. Erstellen von Filterschaltflächen und Steuerelementen
  2. Automatisieren und Hinzufügen von Reaktionsfähigkeit zu den Schaltflächen
  3. Testen des verbesserten Dashboards
  4. Schlussfolgerung

Diese Ergänzungen werden die Nutzerfreundlichkeit unseres Dashboards erheblich verbessern und es für die Nutzer flexibler und dynamischer machen, damit sie in Echtzeit damit interagieren können. Mit diesen interaktiven Elementen können wir die angezeigten Nachrichtendaten leicht filtern und verwalten, ohne den zugrunde liegenden Code jedes Mal ändern zu müssen. Beginnen wir damit, die Filterschaltflächen zu erstellen und sie in unser bestehendes Dashboard-Layout zu integrieren.


Erstellen von Filterschaltflächen und Steuerelementen

In diesem Abschnitt werden wir uns auf die Erstellung der Filterschaltflächen konzentrieren, mit denen wir die verschiedenen Aspekte unseres Dashboards, wie z. B. den Filter für Währungspaare, den Filter für die Wichtigkeitsstufe und den Filter für den Zeitbereich, direkt vom Panel aus steuern können. Durch das Hinzufügen dieser Schaltflächen wird die Interaktion mit dem Dashboard erleichtert, ohne dass jedes Mal, wenn wir eine Filtereinstellung ändern wollen, der Code aufgerufen oder geändert werden muss. Ziel ist es, eine intuitive Nutzeroberfläche zu entwerfen, die Flexibilität bietet und gleichzeitig einfach und übersichtlich gestaltet ist.

Zunächst werden wir die Positionen und Eigenschaften der einzelnen Filterschaltflächen festlegen. Wir werden diese Schaltflächen im Dashboard-Panel platzieren, sodass wir zwischen verschiedenen Einstellungen für Währungspaare, Wichtigkeitsstufen und Zeitfilter umschalten können. Beispielsweise werden wir die Schaltflächen für den Währungsfilter in der oberen rechten Ecke des Dashboards platzieren, die Schaltflächen für die Auswahl der Währungs-, Wichtigkeits- und Zeitfilter im Kopfbereich und die Schaltfläche zum Abbrechen direkt nach ihrer Definition. Jede Schaltfläche entspricht einer bestimmten Filtereinstellung, und wir können auf diese Schaltflächen klicken, um unsere bevorzugten Filter anzuwenden. Das folgende Bild zeigt das ursprüngliche Layout für die Filterschaltflächen im Dashboard:

LAYOUT BLAUPAUSE

Wie in der Abbildung zu sehen ist, sind die Filter-Schaltflächen innerhalb des Dashboards angeordnet, um den Zugriff und die Verwaltung zu erleichtern. Jede Schaltfläche ist für eine bestimmte Funktion vorgesehen, z. B. zum Aktivieren der verfügbaren Währungspaare, zum Einstellen der Wichtigkeit der Ereignisse oder zum Filtern nach Zeit. Die Schaltflächen werden auch optisch voneinander abgegrenzt, damit wir die verschiedenen Kontrollgruppen leicht unterscheiden können.

Um dies zu implementieren, müssen wir Konstanten für die zusätzlichen Objekte und Steuerelemente definieren, die wir in das Dashboard aufnehmen werden.

#define FILTER_LABEL "FILTER_LABEL"  //--- Define the label for the filter section on the dashboard

#define FILTER_CURR_BTN "FILTER_CURR_BTN"  //--- Define the button for filtering by currency pair
#define FILTER_IMP_BTN "FILTER_IMP_BTN"  //--- Define the button for filtering by event importance
#define FILTER_TIME_BTN "FILTER_TIME_BTN"  //--- Define the button for filtering by time range

#define CANCEL_BTN "CANCEL_BTN"  //--- Define the cancel button to reset or close the filters

#define CURRENCY_BTNS "CURRENCY_BTNS"  //--- Define the collection of currency buttons for user selection

Hier definieren wir eine Reihe von String-Konstanten, die die Namen der verschiedenen Dashboard-Elemente darstellen, die wir hinzufügen werden, vor allem Schaltflächen und Beschriftungen, unter Verwendung des Schlüsselworts #define. Wir werden diese Konstanten verwenden, um Komponenten der Nutzeroberfläche wie Filterschaltflächen und eine Abbruchschaltfläche zu erstellen und zu verwalten. Zunächst definieren wir „FILTER_LABEL“, das die Bezeichnung für den Filterbereich auf dem Dashboard darstellt.

Als Nächstes definieren wir drei Schaltflächen: “FILTER_CURR_BTN“ für die Filterung nach Währungspaaren, FILTER_IMP_BTN“ für die Filterung nach der Bedeutung des Ereignisses und FILTER_TIME_BTN“ für die Filterung nach dem Zeitbereich des Ereignisses. Wir definieren auch ein „CANCEL_BTN“, um die aktiven Filter zurückzusetzen oder zu schließen und die Dashboard-Komponenten zu löschen, und schließlich stellt „CURRENCY_BTNS“ eine Sammlung von Währungsschaltflächen dar, mit denen wir bestimmte Währungspaare auswählen können. Diese Definitionen helfen uns, ein dynamisches und interaktives Dashboard zu erstellen, bei dem wir die angezeigten Daten direkt über die Schnittstelle steuern können. Um die Dynamik zu erhöhen, entfernen wir die Reihe der definierten Währungen im globalen Bereich wie folgt:

string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"};
string curr_filter_selected[];

Hier verbessern wir die Flexibilität und Dynamik des Währungsfilters, indem wir die vordefinierte Liste der Währungen aus den Funktionen entfernen und in einen globalen Bereich stellen. Wir definieren nun ein neues globales Array „curr_filter“, das die Liste der möglichen Währungen enthält, wie „AUD“, „CAD“, „CHF“, „EUR“, „GBP“, „JPY“, „NZD“ und „USD“. Zusätzlich erstellen wir ein leeres Array „curr_filter_selected“, in dem die vom Nutzer ausgewählten Währungen dynamisch zur Laufzeit gespeichert werden. Zum Schluss erstellen wir eine Variable, die die Notwendigkeit von Aktualisierungen verfolgt, da wir dieses Mal keine Aktualisierungen benötigen, sobald wir das Dashboard über die Schaltfläche „Abbrechen“ loswerden. Ganz einfach.

bool isDashboardUpdate = true;

Wir definieren einfach eine boolesche Variable „isDashboardUpdate“ und initialisieren sie mit true. Wir werden die Variable verwenden, um festzustellen, ob das Dashboard aktualisiert werden muss. Durch das Setzen auf true können wir anzeigen, dass eine Änderung oder Aktion (z. B. eine Filterauswahl oder ein Schaltflächenklick) stattgefunden hat, die eine Aktualisierung des Dashboards mit neuen Daten oder Einstellungen erfordert. Ebenso bedeutet die Einstellung „false“, dass wir den Aktualisierungsprozess nicht durchführen müssen, was dazu beiträgt, den Status des Dashboards effizient zu verwalten, sicherzustellen, dass es nur bei Bedarf aktualisiert wird, und unnötige Neuaufrufe zu vermeiden.

Vom globalen Bereich aus können wir zum Initialisierungsabschnitt gehen und unsere zusätzlichen Filterkomponenten dem Dashboard zuordnen. Wir beginnen mit den obersten Schaltflächen, die das Filtern erlauben.

createLabel(FILTER_LABEL,370,55,"Filters:",clrYellow,16,"Impact"); //--- Create a label for the "Filters" section in the dashboard

//--- Define the text, color, and state for the Currency filter button
string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; //--- Set text based on filter state
color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; //--- Set text color based on filter state
bool filter_curr_state = enableCurrencyFilter ? true : false; //--- Set button state (enabled/disabled)
createButton(FILTER_CURR_BTN,430,55,110,26,filter_curr_text,filter_curr_txt_color,12,clrBlack); //--- Create Currency filter button
ObjectSetInteger(0,FILTER_CURR_BTN,OBJPROP_STATE,filter_curr_state); //--- Set the state of the Currency button

Hier fügen wir eine Beschriftung und eine Schaltfläche für den Währungsfilter auf dem Dashboard hinzu. Zunächst platzieren wir mit der Funktion „createLabel“ eine Beschriftung mit dem Titel „Filters:“ auf dem Chart an den Koordinaten (370 und 55), mit einer gelben Farbe und einer Schriftgröße von 16. Diese Bezeichnung dient als Überschrift für den Filterbereich und zeigt dem Nutzer deutlich, wo sich die Filteroptionen befinden.

Als Nächstes definieren und richten wir die Schaltfläche für den Filter „Currency“ (Währung) ein. Wir überprüfen den Status der Variable „enableCurrencyFilter“ und legen auf der Grundlage ihres Wertes den Text der Schaltfläche dynamisch mit Hilfe der Variable „filter_curr_text“ fest. Wenn der Währungsfilter aktiviert ist („enableCurrencyFilter“ ist wahr), zeigt die Schaltfläche ein Häkchen („0x2714“) mit dem Text „Currency“ an, was bedeutet, dass der Filter aktiv ist; ist er deaktiviert, wird stattdessen ein Kreuz („0x274C“) angezeigt, was bedeutet, dass der Filter inaktiv ist. Wir erreichen dies durch die Verwendung eines ternären Operators, der ähnlich wie der if-Operator funktioniert, nur dass er kleiner, einfacher und unkomplizierter ist.

Um den Zustand des Filters auch visuell widerzuspiegeln, legen wir die Textfarbe der Schaltfläche mit der Variablen „filter_curr_txt_color“ fest. Ist der Filter aktiv, erscheint der Text in Grün, ist er inaktiv, erscheint er in Rot. Außerdem verwenden wir die boolesche Variable „filter_curr_state“, um den tatsächlichen Zustand der Schaltfläche zu steuern, der bestimmt, ob die Schaltfläche aktiviert oder deaktiviert ist.

Dann erstellen wir die Schaltfläche selbst mit der Funktion „createButton“ und platzieren sie bei (430, 55) im Chart mit der entsprechenden Beschriftung („filter_curr_text“), Textfarbe („filter_curr_txt_color“) und einem schwarzen Hintergrund. Schließlich verwenden wir die Funktion ObjectSetInteger, um den Zustand der Schaltfläche (aktiviert oder deaktiviert) durch Verweis auf die Variable „filter_curr_state“ festzulegen. Dadurch wird sichergestellt, dass das Aussehen und die Funktionalität der Schaltfläche mit den aktuellen Filtereinstellungen übereinstimmen. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

WÄHRUNGSFILTER UND ETIKETT

Das war ein Erfolg. Wir können nun mit der gleichen Logik die Filterschaltflächen hinzufügen.

//--- Define the text, color, and state for the Importance filter button
string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; //--- Set text based on filter state
color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; //--- Set text color based on filter state
bool filter_imp_state = enableImportanceFilter ? true : false; //--- Set button state (enabled/disabled)
createButton(FILTER_IMP_BTN,430+110,55,120,26,filter_imp_text,filter_imp_txt_color,12,clrBlack); //--- Create Importance filter button
ObjectSetInteger(0,FILTER_IMP_BTN,OBJPROP_STATE,filter_imp_state); //--- Set the state of the Importance button

//--- Define the text, color, and state for the Time filter button
string filter_time_text = enableTimeFilter ? ShortToString(0x2714)+"Time" : ShortToString(0x274C)+"Time"; //--- Set text based on filter state
color filter_time_txt_color = enableTimeFilter ? clrLime : clrRed; //--- Set text color based on filter state
bool filter_time_state = enableTimeFilter ? true : false; //--- Set button state (enabled/disabled)
createButton(FILTER_TIME_BTN,430+110+120,55,70,26,filter_time_text,filter_time_txt_color,12,clrBlack); //--- Create Time filter button
ObjectSetInteger(0,FILTER_TIME_BTN,OBJPROP_STATE,filter_time_state); //--- Set the state of the Time button

//--- Create a Cancel button to reset all filters
createButton(CANCEL_BTN,430+110+120+79,51,50,30,"X",clrWhite,17,clrRed,clrNONE); //--- Create the Cancel button with an "X"

//--- Redraw the chart to update the visual elements
ChartRedraw(0); //--- Redraw the chart to reflect all changes made above

Hier richten wir die Schaltflächen für die Filter „Importance“ (Wichtigkeit), „Time“ (Zeit) und „Cancel“ (Abbrechen) auf dem Dashboard ein. Für den Filter „Importance“ definieren wir zunächst den Text der Schaltfläche mit der Variablen „filter_imp_text“. Basierend auf dem Wert von „enableImportanceFilter“ wird, wenn der Filter aktiv ist, ein Häkchen („0x2714“) neben dem Text „Importance“ angezeigt, was bedeutet, dass der Filter aktiviert ist; wenn nicht, wird ein Kreuz („0x274C“) mit demselben Text angezeigt, was bedeutet, dass der Filter deaktiviert ist. Außerdem wird die Textfarbe der Schaltfläche mit „filter_imp_txt_color“ festgelegt, die bei Aktivierung grün und bei Deaktivierung rot ist. Der boolesche Wert „filter_imp_state“ steuert, ob die Schaltfläche aktiviert oder deaktiviert ist.

Als Nächstes verwenden wir die Funktion „createButton“, um die Filterschaltfläche „Wichtigkeit“ zu erstellen und sie an der Position (430+110, 55) mit dem entsprechenden Text, der Farbe und dem Status zu platzieren. Anschließend wird mit ObjectSetInteger der Status der Schaltfläche „OBJPROP_STATE“ auf der Grundlage von „filter_imp_state“ festgelegt, um sicherzustellen, dass die Schaltfläche den richtigen Status wiedergibt.

Ähnlich verfahren wir mit der Filterschaltfläche „Time“. Wir definieren den Text in „filter_time_text“ und passen die Farbe mit „filter_time_txt_color“ auf der Grundlage des Werts von „enableTimeFilter“ an. Die Schaltfläche wird an der Position (430+110+120, 55) erstellt, und der Status wird mit „filter_time_state“ entsprechend festgelegt.

Schließlich erstellen wir die Schaltfläche „Cancel“ mit der Funktion „createButton“, die alle Filter zurücksetzt und das Dashboard löscht, wenn sie angeklickt wird. Diese Schaltfläche befindet sich an der Position (430+110+120+79, 51) und ist mit einem weißen „X“ auf rotem Hintergrund versehen, um ihren Zweck anzuzeigen. Schließlich rufen wir die Funktion ChartRedraw auf, um das Chart zu aktualisieren und die neu erstellten Schaltflächen und Änderungen visuell zu aktualisieren. Nach der Ausführung erhalten wir das folgende Ergebnis.

ALLE SCHALTFLÄCHEN DER FILTER

Das war ein Erfolg. Wir haben nun alle Filterschaltflächen zum Dashboard hinzugefügt. Bei der Erstellung der Texte haben wir jedoch eine Verkettung fremder Zeichen verwendet, die Unicode-Zeichen genannt wird. Schauen wir sie uns einmal genauer an.

ShortToString(0x2714);
ShortToString(0x274C);

Hier verwenden wir die Funktionen „ShortToString(0x2714)“ und „ShortToString(0x274C)“, um Unicode-Zeichen in MQL5 darzustellen, und die Werte „0x2714“ und „0x274C“ beziehen sich auf bestimmte Symbole im Unicode-Zeichensatz.

  • „0x2714“ ist das Unicode-Zeichen für das Symbol „CHECK MARK“. Es wird verwendet, um anzuzeigen, dass etwas möglich, abgeschlossen oder korrekt ist. Im Zusammenhang mit den Filter-Schaltflächen zeigen wir damit an, dass ein Filter (z. B. der Filter „Currency“ oder „Importance“) aktiv oder aktiviert ist.
  • „0x274C“ ist das Unicode-Zeichen für das Symbol „CROSS MARK“. Es wird verwendet, um etwas Unmögliches, Unerledigtes oder Falsches darzustellen. Hier wird er verwendet, um anzuzeigen, dass ein Filter inaktiv oder deaktiviert ist.

Sie können auch Ihre eigenen Zeichen verwenden, vorausgesetzt, Sie stellen Zeichen bereit, die mit der MQL5-Umgebung kompatibel sind. Eine Reihe von Zeichen ist wie unten dargestellt:

CHECK MARK UNICODE BEISPIELE

Im Code wandelt die Funktion ShortToString diese Unicode-Zeichen in die entsprechenden Zeichendarstellungen um. Diese Zeichen werden dann an den Text der Filterschaltflächen angehängt, um visuell anzuzeigen, ob ein Filter aktiv ist oder nicht. Als Nächstes können wir die Schaltflächen für den Währungsfilter dynamisch erstellen.

int curr_size = 51;               //--- Button width
int button_height = 22;           //--- Button height
int spacing_x = 0;               //--- Horizontal spacing
int spacing_y = 3;               //--- Vertical spacing
int max_columns = 4;              //--- Number of buttons per row

for (int i = 0; i < ArraySize(curr_filter); i++){
   int row = i / max_columns;                              //--- Determine the row
   int col = i % max_columns;                             //--- Determine the column

   int x_pos = 575 + col * (curr_size + spacing_x);        //--- Calculate X position
   int y_pos = 83 + row * (button_height + spacing_y);    //--- Calculate Y position
   
   //--- Create button with dynamic positioning
   createButton(CURRENCY_BTNS+IntegerToString(i),x_pos,y_pos,curr_size,button_height,curr_filter[i],clrBlack);
}

if (enableCurrencyFilter == true){
   ArrayFree(curr_filter_selected);
   ArrayCopy(curr_filter_selected,curr_filter);
   Print("CURRENCY FILTER ENABLED");
   ArrayPrint(curr_filter_selected);
   
   for (int i = 0; i < ArraySize(curr_filter_selected); i++) {
      // Set the button to "clicked" (selected) state by default
      ObjectSetInteger(0, CURRENCY_BTNS + IntegerToString(i), OBJPROP_STATE, true);  // true means clicked
   }
}

Hier erstellen wir dynamisch Schaltflächen für Währungsfilter und verwalten deren Layout und Status, je nachdem, ob der Filter aktiviert ist oder nicht. Wir beginnen mit der Definition von Parametern für das Schaltflächenlayout. Wir setzen die Integer-Variable „curr_size“ auf 51, was die Breite jeder Schaltfläche bestimmt, und „button_height“ auf 22, was die Höhe der Schaltfläche bestimmt. „spacing_x“ und „spacing_y“ werden auf 0 bzw. 3 gesetzt, um den Abstand zwischen den Schaltflächen in horizontaler und vertikaler Richtung zu steuern. Wir definieren auch „max_columns“ als 4, wodurch die Anzahl der Schaltflächen pro Zeile auf vier begrenzt wird.

Als Nächstes verwenden wir eine for-Schleife, um das Array „curr_filter“ zu durchlaufen, das die Währungspaar-Codes wie „AUD“, „CAD“ usw. enthält. Für jede Iteration wird die Zeile und Spalte berechnet, in der die Schaltfläche platziert werden soll. Wir berechnen die Zeilen als „i / max_columns“, um die Zeilennummer zu bestimmen, und die Spalten als „i % max_columns“, um die Spalte innerhalb der Zeile zu bestimmen. Anhand dieser Werte berechnen wir die X- („x_pos“) und Y-Position („y_pos“) der Schaltflächen auf dem Bildschirm. Dann rufen wir die Funktion „createButton“ auf, um jede Schaltfläche dynamisch zu erstellen, wobei die Beschriftung auf die entsprechende Währung aus dem Array „curr_filter“ und die Farbe auf schwarz gesetzt wird.

Nachdem wir die Schaltflächen erstellt haben, prüfen wir, ob der Filter aktiviert ist, indem wir den Wert von „enableCurrencyFilter“ auswerten. Wenn der Filter aktiviert ist, löschen wir das Array der ausgewählten Währungen mit der Funktion ArrayFree und kopieren den Inhalt von „curr_filter“ in „curr_filter_selected“ mit der Funktion ArrayCopy. Dadurch werden alle Währungen in das ausgewählte Feld kopiert. Wir drucken dann „CURRENCY FILTER ENABLED“ und zeigen das ausgewählte Filter-Array mit der Funktion ArrayPrint an. Schließlich werden die ausgewählten Währungen im Array „curr_filter_selected“ in einer Schleife durchlaufen und der Status jeder entsprechenden Schaltfläche mit der Funktion ObjectSetInteger auf „selected“ gesetzt, indem die entsprechenden Parameter angegeben werden. Wir verwenden die Funktion IntegerToString, um den Index der Auswahl zu verketten und an das Makro „CURRENCY_BTNS“ anzuhängen, und setzen den Status auf true, wodurch die Schaltfläche visuell als angeklickt markiert wird.

Nach der Kompilierung erhalten wir die folgenden Ergebnisse.

ENDERGEBNIS DER SCHALTFLÄCHEN

Anhand des Bildes können wir sehen, dass wir die Filterschaltflächen erfolgreich zum Dashboard hinzugefügt haben. Als Nächstes müssen wir nun die Funktion, die für die Zerstörung des Dashboards verantwortlich ist, so aktualisieren, dass sie auch die neu hinzugefügten Komponenten berücksichtigt.

//+------------------------------------------------------------------+
//|      Function to destroy the Dashboard panel                     |
//+------------------------------------------------------------------+

void destroy_Dashboard(){
   
   //--- Delete the main rectangle that defines the dashboard background
   ObjectDelete(0,"MAIN_REC");
   
   //--- Delete the sub-rectangles that separate sections in the dashboard
   ObjectDelete(0,"SUB_REC1");
   ObjectDelete(0,"SUB_REC2");
   
   //--- Delete the header label that displays the title of the dashboard
   ObjectDelete(0,"HEADER_LABEL");
   
   //--- Delete the time and impact labels from the dashboard
   ObjectDelete(0,"TIME_LABEL");
   ObjectDelete(0,"IMPACT_LABEL");

   //--- Delete all calendar-related objects
   ObjectsDeleteAll(0,"ARRAY_CALENDAR");
   
   //--- Delete all news-related objects
   ObjectsDeleteAll(0,"ARRAY_NEWS");

   //--- Delete all data holder objects (for storing data within the dashboard)
   ObjectsDeleteAll(0,"DATA_HOLDERS");
   
   //--- Delete the impact label objects (impact-related elements in the dashboard)
   ObjectsDeleteAll(0,"IMPACT_LABEL");

   //--- Delete the filter label that identifies the filter section
   ObjectDelete(0,"FILTER_LABEL");
   
   //--- Delete the filter buttons for Currency, Importance, and Time
   ObjectDelete(0,"FILTER_CURR_BTN");
   ObjectDelete(0,"FILTER_IMP_BTN");
   ObjectDelete(0,"FILTER_TIME_BTN");
   
   //--- Delete the cancel button that resets or closes the filters
   ObjectDelete(0,"CANCEL_BTN");
   
   //--- Delete all currency filter buttons dynamically created
   ObjectsDeleteAll(0,"CURRENCY_BTNS");
   
   //--- Redraw the chart to reflect the removal of all dashboard components
   ChartRedraw(0);
   
}

Wir müssen auch die Logik der Ereignisbehandlung von OnTick aktualisieren, um die Aktualisierungen nur auszuführen, solange das Aktualisierungs-Flag wahr ist. Das erreichen wir durch die folgende Logik.

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

   if (isDashboardUpdate){
      update_dashboard_values(curr_filter_selected);
   }   
}

Hier wird geprüft, ob die Bedingung „isDashboardUpdate“ wahr ist, was bedeutet, dass das Dashboard mit den neuesten Daten aktualisiert werden sollte. Wenn diese Bedingung erfüllt ist, rufen wir die Funktion „update_dashboard_values“ auf, um die auf dem Dashboard angezeigten Werte anhand der im Array „curr_filter_selected“ gespeicherten ausgewählten Währungsfilter zu aktualisieren.

Das Array „curr_filter_selected“ enthält die Währungen, die für die Filterung ausgewählt wurden. Indem wir es an die Funktion „update_dashboard_values“ übergeben, stellen wir sicher, dass das Dashboard die aktuellsten Filterauswahlen widerspiegelt. Wenn das Flag falsch ist, werden keine Aktualisierungen berücksichtigt. Das ist alles, was wir bei der Erstellung der Filterschaltflächen beachten müssen. Jetzt müssen wir nur noch den erstellten Schaltflächen Reaktionsfähigkeit verleihen, was wir im nächsten Abschnitt tun werden.


Automatisieren und Hinzufügen von Reaktionsfähigkeit zu den Schaltflächen

Um das Dashboard reaktionsfähiger zu machen, müssen wir einen Ereignis- (Zuhörer) einfügen, der die Klicks verfolgt und darauf basierend Maßnahmen ergreift. Dazu verwenden wir die integrierte Ereignisbehandlung von OnChartEvent in MQL5.

//+------------------------------------------------------------------+
//|    OnChartEvent handler function                                 |
//+------------------------------------------------------------------+
void  OnChartEvent(
   const int       id,       // event ID  
   const long&     lparam,   // long type event parameter 
   const double&   dparam,   // double type event parameter 
   const string&   sparam    // string type event parameter 
){

//---

}

Dies ist die Funktion, die für die Erkennung von Chartaktivitäten wie Änderungen, Klicks, Objekterstellungen und vieles mehr verantwortlich ist. Wir sind jedoch nur an den Chartklicks interessiert, da wir nur auf die Schaltflächenklicks hören wollen. Wir werden mit den einfachsten bis zu den komplexesten beginnen. Die Abbruchtaste ist die einfachste.

if (id == CHARTEVENT_OBJECT_CLICK){ //--- Check if the event is a click on an object
   
   if (sparam == CANCEL_BTN){ //--- If the Cancel button is clicked
      isDashboardUpdate = false; //--- Set dashboard update flag to false
      destroy_Dashboard(); //--- Call the function to destroy the dashboard
   }
}

Hier wird das Szenario behandelt, wenn das erkannte Ereignis ein Klick auf ein Objekt mit der Ereignis-ID CHARTEVENT_OBJECT_CLICK ist. Wenn das Ereignis ein Klick ist, prüfen wir, ob das angeklickte Objekt „CANCEL_BTN“ ist, indem wir auswerten, ob der String-Parameter „sparam“ „CANCEL_BTN“ ist. Wenn diese Bedingung erfüllt ist, bedeutet dies, dass die Schaltfläche Abbrechen auf dem Dashboard angeklickt wurde. Als Reaktion darauf setzen wir das globale Flag „isDashboardUpdate“ auf „false“, wodurch weitere Aktualisierungen des Dashboards effektiv verhindert werden. Als Nächstes rufen wir die Funktion „destroy_Dashboard“ auf, um alle mit dem Dashboard verbundenen grafischen Elemente aus dem Chart zu entfernen und es damit zu löschen. Dadurch wird sichergestellt, dass die Schnittstelle zurückgesetzt und gelöscht wird, wenn die Schaltfläche Abbrechen angeklickt wird. Hier ist die Illustration.

GIF ABBRECHEN

Das war ein Erfolg. Wir können nun die gleiche Logik anwenden, um die anderen Schaltflächen zu automatisieren. Wir werden die Schaltfläche für den Währungsfilter jetzt automatisieren. Wir verwenden die folgende Logik in einem Codeschnipsel, um dies zu erreichen.

if (sparam == FILTER_CURR_BTN){ //--- If the Currency filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state (clicked/unclicked)
   enableCurrencyFilter = btn_state; //--- Update the Currency filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableCurrencyFilter); //--- Log the state
   string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; //--- Set button text based on state
   color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; //--- Set button text color based on state
   ObjectSetString(0,FILTER_CURR_BTN,OBJPROP_TEXT,filter_curr_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_CURR_BTN,OBJPROP_COLOR,filter_curr_txt_color); //--- Update the button text color
   Print("Success. Changes updated! State: "+(string)enableCurrencyFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart to reflect changes
}

Hier geht es um das Verhalten, wenn die Schaltfläche „FILTER_CURR_BTN“ (Währungsfilter) angeklickt wird. Wenn diese Bedingung erfüllt ist, wird der aktuelle Zustand der Schaltfläche (angeklickt oder nicht angeklickt) mit der Funktion ObjectGetInteger und der Eigenschaft OBJPROP_STATE abgefragt und in der Variablen „btn_state“ gespeichert. Anschließend wird das Flag „enableCurrencyFilter“ mit dem Wert „btn_state“ aktualisiert, um anzuzeigen, ob der Währungsfilter aktiv ist.

Als Nächstes protokollieren wir den Zustand der Schaltfläche und dem aktualisierten Flag, um mit der Druckfunktion ein Feedback zu geben. Basierend auf dem Status des Währungsfilters setzen wir den Text der Schaltfläche dynamisch durch ein Häkchen oder ein Kreuz mit der Funktion ShortToString und aktualisieren seine Farbe auf grün für aktiv oder rot für inaktiv. Diese Aktualisierungen werden mit ObjectSetString für den Text und ObjectSetInteger für die Farbeigenschaft auf die Schaltfläche angewendet.

Schließlich protokollieren wir eine Erfolgsmeldung, um zu bestätigen, dass die Änderungen übernommen wurden, und rufen die Funktion ChartRedraw auf, um das Chart zu aktualisieren und sicherzustellen, dass die visuellen Änderungen an der Schaltfläche sofort angezeigt werden. Diese Interaktion ermöglicht es uns, den Währungsfilter dynamisch umzuschalten und die Änderungen auf dem Dashboard wiederzugeben. Das gleiche Verfahren gilt für die anderen Filterschaltflächen.

if (sparam == FILTER_IMP_BTN){ //--- If the Importance filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state
   enableImportanceFilter = btn_state; //--- Update the Importance filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableImportanceFilter); //--- Log the state
   string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; //--- Set button text
   color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; //--- Set button text color
   ObjectSetString(0,FILTER_IMP_BTN,OBJPROP_TEXT,filter_imp_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_IMP_BTN,OBJPROP_COLOR,filter_imp_txt_color); //--- Update the button text color
   Print("Success. Changes updated! State: "+(string)enableImportanceFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart
}
if (sparam == FILTER_TIME_BTN){ //--- If the Time filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state
   enableTimeFilter = btn_state; //--- Update the Time filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableTimeFilter); //--- Log the state
   string filter_time_text = enableTimeFilter ? ShortToString(0x2714)+"Time" : ShortToString(0x274C)+"Time"; //--- Set button text
   color filter_time_txt_color = enableTimeFilter ? clrLime : clrRed; //--- Set button text color
   ObjectSetString(0,FILTER_TIME_BTN,OBJPROP_TEXT,filter_time_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_TIME_BTN,OBJPROP_COLOR,filter_time_txt_color); //--- Update the button text color
   Print("Success. Changes updated! State: "+(string)enableTimeFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart
}

Hier wird das Verhalten für die Behandlung von Klicks auf die Schaltflächen „FILTER_IMP_BTN“ (Wichtigkeitsfilter) und „FILTER_TIME_BTN“ (Zeitfilter) definiert, um ein dynamisches Umschalten dieser Filter zu ermöglichen. Für „FILTER_IMP_BTN“ wird beim Anklicken zunächst der aktuelle Zustand mit ObjectGetInteger und der Eigenschaft OBJPROP_STATE abgefragt und in der Variablen „btn_state“ gespeichert. Anschließend wird das Flag „enableImportanceFilter“ aktualisiert, um anzuzeigen, ob der Filter „Importance“ aktiv ist. Mit der Funktion Print protokollieren wir den Zustand der Schaltfläche und den aktualisierten Wert des Flags. Je nach Status setzen wir den Text der Schaltfläche über die Funktion ShortToString auf ein Häkchen oder ein Kreuz und aktualisieren seine Farbe auf grün für aktiv oder rot für inaktiv. Diese Änderungen werden mit den Funktionen ObjectSetString für den Text und ObjectSetInteger für die Farbeigenschaft vorgenommen. Schließlich wird eine Erfolgsmeldung protokolliert und die Funktion ChartRedraw aufgerufen, um sicherzustellen, dass die Aktualisierungen visuell übernommen werden.

Für den „FILTER_TIME_BTN“ gehen wir in gleicher Weise vor. Wir rufen den Zustand der Schaltfläche mit der Funktion ObjectGetInteger ab und aktualisieren das Flag „enableTimeFilter“ entsprechend. Wir protokollieren den Status und kennzeichnen Aktualisierungen für Rückmeldungen. Der Schaltflächentext und die Farbe werden dynamisch aktualisiert, um den Status (aktiv/inaktiv) widerzuspiegeln, wobei die Funktionen ShortToString, ObjectSetString bzw. ObjectSetInteger verwendet werden. Nachdem wir die Aktualisierungen mit einem Protokoll bestätigt haben, zeichnen wir das Chart mit der Funktion ChartRedraw neu. Dieser Prozess gewährleistet eine Echtzeit-Reaktionszeit für die Filterschaltflächen und ermöglicht ein nahtloses Umschalten ihrer Funktionalität. Hier ist ein visuelles Ergebnis.

SCHALTFLÄCHEN-FILTER GIF

Das war ein Erfolg. Wir können nun auch die Währungsschaltflächen automatisieren.

if (StringFind(sparam,CURRENCY_BTNS) >= 0){ //--- If a Currency button is clicked
   string selected_curr = ObjectGetString(0,sparam,OBJPROP_TEXT); //--- Get the text of the clicked button
   Print("BTN NAME = ",sparam,", CURRENCY = ",selected_curr); //--- Log the button name and currency
   
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state
   
   if (btn_state == false){ //--- If the button is unselected
      Print("BUTTON IS IN UN-SELECTED MODE.");
      //--- Loop to find and remove the currency from the array
      for (int i = 0; i < ArraySize(curr_filter_selected); i++) {
         if (curr_filter_selected[i] == selected_curr) {
            //--- Shift elements to remove the selected currency
            for (int j = i; j < ArraySize(curr_filter_selected) - 1; j++) {
               curr_filter_selected[j] = curr_filter_selected[j + 1];
            }
            ArrayResize(curr_filter_selected, ArraySize(curr_filter_selected) - 1); //--- Resize the array
            Print("Removed from selected filters: ", selected_curr); //--- Log removal
            break;
         }
      }
   }
   else if (btn_state == true){ //--- If the button is selected
      Print("BUTTON IS IN SELECTED MODE. TAKE ACTION");
      //--- Check for duplicates
      bool already_selected = false;
      for (int j = 0; j < ArraySize(curr_filter_selected); j++) {
         if (curr_filter_selected[j] == selected_curr) {
            already_selected = true;
            break;
         }
      }

      //--- If not already selected, add to the array
      if (!already_selected) {
         ArrayResize(curr_filter_selected, ArraySize(curr_filter_selected) + 1); //--- Resize array
         curr_filter_selected[ArraySize(curr_filter_selected) - 1] = selected_curr; //--- Add the new currency
         Print("Added to selected filters: ", selected_curr); //--- Log addition
      }
      else {
         Print("Currency already selected: ", selected_curr); //--- Log already selected
      }
      
   }
   Print("SELECTED ARRAY SIZE = ",ArraySize(curr_filter_selected)); //--- Log the size of the selected array
   ArrayPrint(curr_filter_selected); //--- Print the selected array
   
   update_dashboard_values(curr_filter_selected); //--- Update the dashboard with the selected filters
   Print("SUCCESS. DASHBOARD UPDATED"); //--- Log success
   
   ChartRedraw(0); //--- Redraw the chart to reflect changes
}

Hier verarbeiten wir Klicks auf die Schaltflächen der Währungen, um die ausgewählten Währungen dynamisch zu verwalten und das Dashboard entsprechend zu aktualisieren. Wenn eine Schaltfläche angeklickt wird, wird zunächst mithilfe der Funktion StringFind festgestellt, ob sie zur Gruppe „CURRENCY_BTNS“ gehört. Wenn ja, wird die Textbeschriftung der Schaltfläche mit der Funktion ObjectGetString und der Eigenschaft „OBJPROP_TEXT“ abgerufen, um die Währung zu identifizieren, die sie darstellt. Als Nächstes überprüfen wir den Zustand der Schaltfläche mithilfe von ObjectGetInteger mit der Eigenschaft „OBJPROP_STATE“, um festzustellen, ob die Schaltfläche ausgewählt (true) oder nicht ausgewählt (false) ist.

Wenn die Schaltfläche nicht ausgewählt ist, wird die entsprechende Währung aus dem Array „curr_filter_selected“ entfernt. Um dies zu erreichen, durchlaufen wir das Array in einer Schleife, um die passende Währung zu finden, verschieben alle nachfolgenden Elemente nach links, um sie zu überschreiben, und ändern dann die Größe des Arrays mit der Funktion ArrayResize, um die letzte Position zu entfernen. Jede Entfernung wird protokolliert, um die Aktion zu bestätigen. Befindet sich die Schaltfläche hingegen in einem ausgewählten Zustand, wird nach Duplikaten gesucht, um zu verhindern, dass dieselbe Währung mehrfach hinzugefügt wird. Befindet sich die Währung noch nicht im Array, wird die Größe des Arrays mit der Funktion „ArrayResize“ geändert, die neue Währung an die letzte Position angehängt und die Ergänzung protokolliert. Wenn die Währung bereits ausgewählt ist, wird eine Meldung protokolliert, dass keine weiteren Maßnahmen erforderlich sind.

Nach der Aktualisierung des Arrays „curr_filter_selected“ protokollieren wir seine Größe und seinen Inhalt mit der Funktion ArrayPrint, um die Sichtbarkeit zu gewährleisten. Anschließend rufen wir die Funktion „update_dashboard_values“ auf, um das Dashboard mit den neu ausgewählten Filtern zu aktualisieren. Um sicherzustellen, dass alle Änderungen visuell wiedergegeben werden, rufen wir abschließend die Funktion ChartRedraw auf und aktualisieren die Chartoberfläche in Echtzeit.

Da wir jetzt unterschiedliche Währungsfilter nach Nutzerinteraktion haben, müssen wir die Funktion, die für die Aktualisierungen verantwortlich ist, mit den neuesten vom Nutzer ausgewählten Währungen aktualisieren.

//+------------------------------------------------------------------+
//| Function to update dashboard values                              |
//+------------------------------------------------------------------+
void update_dashboard_values(string &curr_filter_array[]){

//---

      //--- 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_array); j++) {
            if (country.currency == curr_filter_array[j]) {
               currencyMatch = true;
               break;
            }
         }
         
         //--- If no match found, skip to the next event
         if (!currencyMatch) {
            continue;
         }
      }

//---

}

Hier aktualisieren wir die Funktion „update_dashboard_values“, indem wir eine entscheidende Verbesserung einführen, indem wir den Parameter „curr_filter_array“ verwenden, der als Referenz mit dem Symbol „&“ übergeben wird. Auf diese Weise können wir die ausgewählten Währungsfilter direkt bearbeiten und sicherstellen, dass das Dashboard mit den Nutzereinstellungen synchronisiert bleibt.

Hier ist erklärt, was wir mit „Übergabe per Referenz (&)“ meinen. Der Parameter „curr_filter_array“ wird per Referenz an die Funktion übergeben. Das bedeutet, dass die Funktion auf das tatsächliche Array im Speicher zugreift und nicht auf eine Kopie. Änderungen am Array innerhalb der Funktion (falls vorhanden) wirken sich direkt auf das ursprüngliche Array außerhalb der Funktion aus. Dieser Ansatz verbessert die Effizienz, insbesondere bei größeren Arrays, und gewährleistet die Konsistenz mit den aktuellen Filterauswahlen des Nutzers. Später wird das ursprüngliche Array nicht mehr verwendet, sondern durch das aktuelle Array ersetzt, das als Referenz mit den Nutzereinstellungen übergeben wird. Zur Verdeutlichung haben wir die Änderungen gelb hervorgehoben. Bei der Kompilierung ergibt sich folgendes Ergebnis.

WÄHRUNGSTASTEN GIF

Die Visualisierung zeigt, dass das Dashboard jedes Mal aktualisiert wird, wenn wir auf eine der Währungsschaltflächen klicken, was ein Erfolg ist. Derzeit besteht jedoch eine Abhängigkeit der Währungsfilter-Schaltfläche von den Währungen, da nach dem Anklicken des einzelnen Währungsfilters das Dashboard nicht aktualisiert wird. Um dieses Problem zu lösen, müssen wir nur die Aktualisierungsfunktion für jede Filterschaltfläche aufrufen, wie unten dargestellt.

if (sparam == FILTER_CURR_BTN){ //--- If the Currency filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state (clicked/unclicked)
   enableCurrencyFilter = btn_state; //--- Update the Currency filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableCurrencyFilter); //--- Log the state
   string filter_curr_text = enableCurrencyFilter ? ShortToString(0x2714)+"Currency" : ShortToString(0x274C)+"Currency"; //--- Set button text based on state
   color filter_curr_txt_color = enableCurrencyFilter ? clrLime : clrRed; //--- Set button text color based on state
   ObjectSetString(0,FILTER_CURR_BTN,OBJPROP_TEXT,filter_curr_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_CURR_BTN,OBJPROP_COLOR,filter_curr_txt_color); //--- Update the button text color
   update_dashboard_values(curr_filter_selected);
   Print("Success. Changes updated! State: "+(string)enableCurrencyFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart to reflect changes
}
if (sparam == FILTER_IMP_BTN){ //--- If the Importance filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state
   enableImportanceFilter = btn_state; //--- Update the Importance filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableImportanceFilter); //--- Log the state
   string filter_imp_text = enableImportanceFilter ? ShortToString(0x2714)+"Importance" : ShortToString(0x274C)+"Importance"; //--- Set button text
   color filter_imp_txt_color = enableImportanceFilter ? clrLime : clrRed; //--- Set button text color
   ObjectSetString(0,FILTER_IMP_BTN,OBJPROP_TEXT,filter_imp_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_IMP_BTN,OBJPROP_COLOR,filter_imp_txt_color); //--- Update the button text color
   update_dashboard_values(curr_filter_selected);
   Print("Success. Changes updated! State: "+(string)enableImportanceFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart
}
if (sparam == FILTER_TIME_BTN){ //--- If the Time filter button is clicked
   bool btn_state = ObjectGetInteger(0,sparam,OBJPROP_STATE); //--- Get the button state
   enableTimeFilter = btn_state; //--- Update the Time filter flag
   Print(sparam+" STATE = "+(string)btn_state+", FLAG = "+(string)enableTimeFilter); //--- Log the state
   string filter_time_text = enableTimeFilter ? ShortToString(0x2714)+"Time" : ShortToString(0x274C)+"Time"; //--- Set button text
   color filter_time_txt_color = enableTimeFilter ? clrLime : clrRed; //--- Set button text color
   ObjectSetString(0,FILTER_TIME_BTN,OBJPROP_TEXT,filter_time_text); //--- Update the button text
   ObjectSetInteger(0,FILTER_TIME_BTN,OBJPROP_COLOR,filter_time_txt_color); //--- Update the button text color
   update_dashboard_values(curr_filter_selected);
   Print("Success. Changes updated! State: "+(string)enableTimeFilter); //--- Log success
   ChartRedraw(0); //--- Redraw the chart
}

Hier stellen wir nur sicher, dass wir die Aktualisierungsfunktion aufrufen, um die Unabhängigkeit der Dashboard-Ereignisse zu verbessern. Wir haben die Änderungen der Übersichtlichkeit halber gelb hervorgehoben. Mit diesen Änderungen sind die Tasten also unabhängig voneinander. Hier ist eine schnelle Visualisierung.

UNABHÄNGIGKEIT DER SCHALTFLÄCHEN GIF

Bis zu diesem Punkt haben wir es geschafft, die Währungsfilter zu integrieren. Nach demselben Verfahren können wir auch die Wichtigkeitsfilter integrieren. Dies wird etwas komplexer, da wir mit den vorhandenen Schaltflächen arbeiten werden, um den Filtereffekt hinzuzufügen, und wir benötigen 2 Arrays für die Wichtigkeitsstufen, ein Hauptarray und ein Side-String-Array, das wir für die Vergleiche verwenden werden. Zuerst werden wir alle wichtigen Arrays in den globalen Bereich bringen, damit wir überall im Code auf sie zugreifen können.

//--- Define labels for impact levels and size of impact display areas
string impact_labels[] = {"None","Low","Medium","High"};
string impact_filter_selected[];

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

Hier definieren wir das String-Array „impact_labels“, das die verschiedenen Wirkungsstufen enthält, die der Nutzer auswählen kann. Die Bezeichnungen sind „None“ (Keine), „Low“ (Niedrig), „Medium“ (Mittel) und „High“ (Hoch). Wir haben dieses Feld verwendet, um dem Nutzer diese Optionen zum Filtern von Kalenderereignissen auf der Grundlage ihrer wahrgenommenen Auswirkungen zu präsentieren.

Dann führen wir das Array „impact_filter_selected“ ein, in dem die tatsächlichen Kennzeichnungen gespeichert werden, die der Nutzer aus dem Array „impact_labels“ auswählt. Immer wenn der Nutzer mit der Schnittstelle interagiert und eine Auswirkungsstufe auswählt, fügen wir die entsprechende Bezeichnung zu diesem Array hinzu. Es handelt sich dabei um ein String-Format, sodass wir die jeweils ausgewählten Ebenen leicht interpretieren können, anders als bei der Aufzählungsliste. So können wir die Filterpräferenzen des Nutzers dynamisch verfolgen.

Als Nächstes definieren wir das Array „allowed_importance_levels“, das die Enumerationswerte vom Typ ENUM_CALENDAR_EVENT_IMPORTANCE enthält. Diese Werte sind mit den Stufen der Wichtigkeit oder Auswirkung verbunden: “CALENDAR_IMPORTANCE_NONE“, „CALENDAR_IMPORTANCE_LOW“, „CALENDAR_IMPORTANCE_MODERATE“ und „CALENDAR_IMPORTANCE_HIGH“. Wir hatten sie bereits definiert, wir haben sie nur in den globalen Bereich verschoben. Diese Werte werden verwendet, um Kalenderereignisse nach ihrer Wichtigkeit zu filtern.

Wir definieren auch das Array „imp_filter_selected“, in dem wir die Wichtigkeitsstufen speichern, die den vom Nutzer ausgewählten Wirkungskennzeichnungen entsprechen. Wenn der Nutzer Labels aus „impact_labels“ auswählt, gleichen wir jedes Label mit der entsprechenden Wichtigkeitsstufe aus „allowed_importance_levels“ ab und speichern das Ergebnis in „imp_filter_selected“. Dieses Array wird dann zum Filtern von Kalenderereignissen verwendet, um sicherzustellen, dass nur Ereignisse mit den ausgewählten Wichtigkeitsstufen angezeigt werden.

Nach der Initialisierungsfunktion werden wir die Schaltflächen aktualisieren, um sie übersichtlicher zu gestalten, da wir sie jetzt nicht mehr nur für die Anzeige von Ereignissen, sondern auch für den Filterungsprozess verwenden. Wir wollen also ihren aktiven oder inaktiven Zustand anzeigen, wenn sie angeklickt werden.

if (enableImportanceFilter == true) { 
   ArrayFree(imp_filter_selected); //--- Clear the existing selections in the importance filter array
   ArrayCopy(imp_filter_selected, allowed_importance_levels); //--- Copy all allowed importance levels as default selections
   ArrayFree(impact_filter_selected);
   ArrayCopy(impact_filter_selected, impact_labels);
   Print("IMPORTANCE FILTER ENABLED"); //--- Log that importance filter is enabled
   ArrayPrint(imp_filter_selected); //--- Print the current selection of importance levels
   ArrayPrint(impact_filter_selected);
   
   // Loop through the importance levels and set their buttons to "selected" state
   for (int i = 0; i < ArraySize(imp_filter_selected); i++) {
      string btn_name = IMPACT_LABEL+IntegerToString(i); //--- Dynamically name the button for each importance level
      ObjectSetInteger(0, btn_name, OBJPROP_STATE, true); //--- Set the button state to "clicked" (selected)
      ObjectSetInteger(0, btn_name, OBJPROP_BORDER_COLOR, clrNONE); //--- Set the button state to "clicked" (selected)
   }
}

Hier wird zunächst geprüft, ob die Variable „enableImportanceFilter“ auf true gesetzt ist. Wenn dies der Fall ist, fahren wir mit der Konfiguration des Wichtigkeitsfiltersystems fort. Wir beginnen mit dem Löschen der vorhandenen Auswahl im Array „imp_filter_selected“ mit der Funktion ArrayFree. Anschließend werden alle Werte aus dem Array „allowed_importance_levels“ in „imp_filter_selected“ kopiert, sodass im Wesentlichen alle Wichtigkeitsstufen als Standardauswahl festgelegt werden. Das bedeutet, dass standardmäßig zunächst alle Wichtigkeitsstufen für die Filterung ausgewählt werden.

Anschließend wird das Array „impact_filter_selected“ mit der Funktion ArrayFree gelöscht, wodurch sichergestellt wird, dass alle vorherigen Auswahlen im Array „impact labels“ entfernt werden. Anschließend werden alle Werte aus dem Array „impact_labels“ in „impact_filter_selected“ kopiert. Dadurch wird sichergestellt, dass die Beschriftungen, die die Wichtigkeitsstufen („None“, „Low“, „Medium“ und „High“) darstellen, für den Filter verfügbar sind. Nach dem Einrichten der Arrays wird die Protokollmeldung „IMPORTANCE FILTER ENABLED“ (Wichtigkeitsfilter aktiviert) ausgegeben, um zu bestätigen, dass der Wichtigkeitsfilter jetzt aktiv ist. Wir geben auch den Inhalt der Arrays „imp_filter_selected“ und „impact_filter_selected“ aus, um die aktuellen Auswahlen anzuzeigen.

Schließlich durchlaufen wir das Array „imp_filter_selected“, das die derzeit ausgewählten Wichtigkeitsstufen enthält, und setzen die Schaltflächenzustände für jede entsprechende Wichtigkeitsstufe dynamisch. Für jede Wichtigkeitsstufe erstellen wir dynamisch einen Schaltflächennamen mit „IMPACT_LABEL“ und den Index der aktuellen Wichtigkeitsstufe mit der Funktion IntegerToString. Anschließend setzen wir den Zustand der Schaltfläche mit der Funktion ObjectSetInteger auf „true“ (ausgewählt). Außerdem wird die Farbe des Rahmens entfernt, indem die Eigenschaft OBJPROP_BORDER_COLOR auf none gesetzt wird, um optisch hervorzuheben, dass die Schaltfläche ausgewählt ist. Das ist alles, was wir für die Initialisierung brauchen. Wir gehen nun zur Funktion des Ereignis-Listeners über, wo wir die Klicks auf die Schaltfläche Importance verfolgen und entsprechend handeln. Hier verwenden wir eine ähnliche Logik wie bei den Währungsfilter-Schaltflächen.

if (StringFind(sparam, IMPACT_LABEL) >= 0) { //--- If an Importance button is clicked
   string selected_imp = ObjectGetString(0, sparam, OBJPROP_TEXT); //--- Get the importance level of the clicked button
   ENUM_CALENDAR_EVENT_IMPORTANCE selected_importance_lvl = get_importance_level(impact_labels,allowed_importance_levels,selected_imp);
   Print("BTN NAME = ", sparam, ", IMPORTANCE LEVEL = ", selected_imp,"(",selected_importance_lvl,")"); //--- Log the button name and importance level

   bool btn_state = ObjectGetInteger(0, sparam, OBJPROP_STATE); //--- Get the button state
   
   color color_border = btn_state ? clrNONE : clrBlack;
   
   if (btn_state == false) { //--- If the button is unselected
      Print("BUTTON IS IN UN-SELECTED MODE.");
      //--- Loop to find and remove the importance level from the array
      for (int i = 0; i < ArraySize(imp_filter_selected); i++) {
         if (impact_filter_selected[i] == selected_imp) {
            //--- Shift elements to remove the unselected importance level
            for (int j = i; j < ArraySize(imp_filter_selected) - 1; j++) {
               imp_filter_selected[j] = imp_filter_selected[j + 1];
               impact_filter_selected[j] = impact_filter_selected[j + 1];
            }
            ArrayResize(imp_filter_selected, ArraySize(imp_filter_selected) - 1); //--- Resize the array
            ArrayResize(impact_filter_selected, ArraySize(impact_filter_selected) - 1); //--- Resize the array
            Print("Removed from selected importance filters: ", selected_imp,"(",selected_importance_lvl,")"); //--- Log removal
            break;
         }
      }
   } 
   else if (btn_state == true) { //--- If the button is selected
      Print("BUTTON IS IN SELECTED MODE. TAKE ACTION");
      //--- Check for duplicates
      bool already_selected = false;
      for (int j = 0; j < ArraySize(imp_filter_selected); j++) {
         if (impact_filter_selected[j] == selected_imp) {
            already_selected = true;
            break;
         }
      }

      //--- If not already selected, add to the array
      if (!already_selected) {
         ArrayResize(imp_filter_selected, ArraySize(imp_filter_selected) + 1); //--- Resize the array
         imp_filter_selected[ArraySize(imp_filter_selected) - 1] = selected_importance_lvl; //--- Add the new importance level
         
         ArrayResize(impact_filter_selected, ArraySize(impact_filter_selected) + 1); //--- Resize the array
         impact_filter_selected[ArraySize(impact_filter_selected) - 1] = selected_imp; //--- Add the new importance level
         Print("Added to selected importance filters: ", selected_imp,"(",selected_importance_lvl,")"); //--- Log addition
      } 
      else {
         Print("Importance level already selected: ", selected_imp,"(",selected_importance_lvl,")"); //--- Log already selected
      }
   }
   Print("SELECTED ARRAY SIZE = ", ArraySize(imp_filter_selected)," >< ",ArraySize(impact_filter_selected)); //--- Log the size of the selected array
   ArrayPrint(imp_filter_selected); //--- Print the selected array
   ArrayPrint(impact_filter_selected);
   
   update_dashboard_values(curr_filter_selected,imp_filter_selected); //--- Update the dashboard with the selected filters
   
   ObjectSetInteger(0,sparam,OBJPROP_BORDER_COLOR,color_border);
   Print("SUCCESS. DASHBOARD UPDATED"); //--- Log success

   ChartRedraw(0); //--- Redraw the chart to reflect changes
}

Hier wird zunächst mit Hilfe der Funktion StringFind festgestellt, ob eine Schaltfläche für einen wichtigen Filter angeklickt wurde. Diese Funktion prüft, ob der Name der angeklickten Schaltfläche (dargestellt durch „sparam“) die Zeichenfolge „IMPACT_LABEL“ enthält. Wenn dies der Fall ist, wird die der Schaltfläche zugeordnete Wichtigkeitsstufe abgerufen, indem die Funktion ObjectGetString aufgerufen und die Eigenschaft text übergeben wird, die den Text (z. B. „Low“, „Medium“ usw.) der angeklickten Schaltfläche enthält. Anschließend wandeln wir diesen Text in den entsprechenden Wert der Enumeration um (z. B. CALENDAR_IMPORTANCE_LOW), indem wir die ausgewählte Bezeichnung an die Funktion „get_importance_level(impact_labels, allowed_importance_levels, selected_imp)“ übergeben. Diese Funktion nimmt das Array der Bezeichnungen, die zulässigen Enumerationswerte und die ausgewählte Textbezeichnung, um die entsprechende Wichtigkeitsstufe als Enumeration zurückzugeben. Wir werden die nutzerdefinierte Funktion später behandeln.

Als Nächstes überprüfen wir den Zustand der Schaltfläche mit der Funktion ObjectGetInteger und übergeben die Eigenschaft state, die bestimmt, ob sich die Schaltfläche in einem ausgewählten Zustand (true) oder in einem nicht ausgewählten Zustand (false) befindet. Auf der Grundlage dieses Zustands wird die gewählte Wichtigkeitsstufe entweder zu den Filterfeldern hinzugefügt oder aus ihnen entfernt. Wenn die Schaltfläche nicht ausgewählt ist, durchlaufen wir das Array „imp_filter_selected“ und entfernen die Wichtigkeitsstufe, indem wir die Größe des Arrays mit der Funktion ArrayResize ändern. Das Gleiche gilt für das Array „impact_filter_selected“, um sicherzustellen, dass beide Arrays synchronisiert bleiben. Wenn die Schaltfläche ausgewählt ist, wird zunächst in einer Schleife geprüft, ob die Wichtigkeitsstufe bereits in den Filter-Arrays enthalten ist. Ist dies nicht der Fall, wird der Wert in beide Arrays eingefügt, indem die Größe geändert und der neue Wert angehängt wird.

Sobald die Arrays aktualisiert sind, verwenden wir die Funktion ArrayPrint, um den aktuellen Inhalt der Filter-Arrays zur Fehlersuche zu protokollieren. Dann aktualisieren wir das Dashboard mit den neuen Filterauswahlen, indem wir „update_dashboard_values(curr_filter_selected, imp_filter_selected)“ aufrufen, was die Änderungen in den Filterarrays auf dem Dashboard widerspiegelt. Wir haben die Funktion aktualisiert, um die beiden Array-Parameter jetzt gemäß den Nutzerpräferenzen zu übernehmen. Auch das werden wir uns später ansehen. Schließlich wird das Erscheinungsbild der angeklickten Schaltfläche aktualisiert, indem ihre Rahmenfarbe auf die berechnete Farbe gesetzt wird, wobei die Farbe davon abhängt, ob die Schaltfläche ausgewählt ist oder nicht. Anschließend wird das Chart mit der Funktion ChartRedraw neu gezeichnet, um die Änderungen visuell darzustellen.

Werfen wir nun einen Blick auf die nutzerdefinierte Funktion, die die entsprechende Enumeration der Wichtigkeitsstufen abruft.

//+------------------------------------------------------------------+
//| Function to get the importance level based on the selected label |
//+------------------------------------------------------------------+
ENUM_CALENDAR_EVENT_IMPORTANCE get_importance_level(string &impact_label[], ENUM_CALENDAR_EVENT_IMPORTANCE &importance_levels[], string selected_label) {
    // Loop through the impact_labels array to find the matching label
    for (int i = 0; i < ArraySize(impact_label); i++) {
        if (impact_label[i] == selected_label) {
            // Return the corresponding importance level
            return importance_levels[i];
        }
    }
    
    // If no match found, return CALENDAR_IMPORTANCE_NONE as the default
    return CALENDAR_IMPORTANCE_NONE;
}

Hier definieren wir eine Funktion „get_importance_level“, die zur Bestimmung der Wichtigkeitsstufe auf der Grundlage des ausgewählten Labels verwendet wird. Die Funktion benötigt drei Parameter:

  • „impact_label“: Hierbei handelt es sich um ein Array von Strings, das die verschiedenen Bezeichnungen für die Wichtigkeitsstufen enthält („None“, „Low“, „Medium“ und „High“).
  • „importance_levels": Dieses Array enthält die entsprechenden Wichtigkeitsstufen als Enum-Werte (wie CALENDAR_IMPORTANCE_NONE, CALENDAR_IMPORTANCE_LOW, etc.).
  • "selected_label": Dies ist die Bezeichnung (eine Zeichenkette), die an die Funktion übergeben wird und die die vom Nutzer gewählte Wichtigkeitsstufe darstellt (z. B. „Mittel“).

Innerhalb der Funktion wird das Array „impact_label“ in einer for-Schleife durchlaufen. Bei jeder Iteration wird geprüft, ob das aktuelle Element im Array mit dem „selected_label“ übereinstimmt. Wenn eine Übereinstimmung gefunden wird, wird die entsprechende Wichtigkeitsstufe aus dem Array „importance_levels“ mit demselben Index zurückgegeben. Wenn nach der Überprüfung aller Kennzeichnungen keine Übereinstimmung gefunden wird, gibt die Funktion standardmäßig CALENDAR_IMPORTANCE_NONE zurück. Wir benötigen diese Funktion, um eine Zeichenkette, die die gewählte Wichtigkeitsstufe (z. B. „Medium“) darstellt, in die entsprechende Wichtigkeitsstufe (z. B. „KALENDAR_IMPORTANZ_MODERAT“) umzuwandeln.

Die anderen Änderungen, die wir vorgenommen haben, waren die Übergabe der neuen gefilterten Arraydaten in die Aktualisierungsfunktion als Referenz, sodass die Filter dynamisch gemäß den aktualisierten Nutzereinstellungen wirksam werden. Die Funktionsdeklaration sieht nun so aus wie im folgenden Codeschnipsel dargestellt.

//+------------------------------------------------------------------+
//| Function to update dashboard values                              |
//+------------------------------------------------------------------+
void update_dashboard_values(string &curr_filter_array[], ENUM_CALENDAR_EVENT_IMPORTANCE &imp_filter_array[]){

//---      

}

Nach der Aktualisierung der Funktion müssen wir auch die bestehenden ähnlichen Funktionen aktualisieren, damit sie das Array der Wichtigkeitsfilter enthalten. Der Aufruf der „OnInit“-Ereignishandlerfunktion sieht beispielsweise wie folgt aus.

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

   if (isDashboardUpdate){
      update_dashboard_values(curr_filter_selected,imp_filter_selected);
   }
   
}

Das ist alles, was wir brauchen, um sowohl den Währungs- als auch den Wichtigkeitsfilter einzubauen. Werfen wir einen Blick auf den aktuellen Meilenstein, um uns zu vergewissern, dass die Wichtigkeitsfilter auch so funktionieren, wie wir es erwarten.

WICHTIGKEITSFILTER GIF

Anhand der Visualisierung können wir sehen, dass wir unser Ziel, die Reaktionsfähigkeit des Wichtigkeitsfilters hinzuzufügen, erreicht haben. Schließlich können wir auch die Gesamtzahl der angezeigten Ereignisse aktualisieren. Wir können die Anzahl der gefilterten Ereignisse, die Gesamtzahl der möglichen Ereignisse, die wir im Chart anzeigen können, und die Gesamtzahl der berücksichtigten Ereignisse angeben. Hier ist die Logik, mit der wir das erreichen können. Im globalen Bereich können wir einige Track-Variablen definieren.

int totalEvents_Considered = 0;
int totalEvents_Filtered = 0;
int totalEvents_Displayable = 0;

Hier definieren wir drei ganzzahlige Variablen: „totalEvents_Considered“, „totalEvents_Filtered“ und „totalEvents_Displayable“. Diese Variablen dienen als Zähler, um den Status von Ereignissen während der Verarbeitung zu verfolgen:

  • „totalEvents_Considered“: Mit dieser Variablen wird die Gesamtzahl der Ereignisse festgehalten, die während des Verarbeitungsschritts zunächst berücksichtigt werden. Er stellt den Ausgangspunkt dar, an dem alle Ereignisse berücksichtigt werden, bevor irgendeine Filterung vorgenommen wird.
  • „totalEvents_Filtered“: Diese Variable zählt die Gesamtzahl der Ereignisse, die aufgrund der angewandten Bedingungen, wie Währungs-, Wichtigkeits- oder Zeitfilter, ausgeschlossen oder herausgefiltert werden. Sie gibt an, wie viele Ereignisse aus dem Datensatz entfernt wurden.
  • „totalEvents_Displayable“: Diese Variable erfasst die Gesamtzahl der Ereignisse, die nach der Filterung verbleiben und für die Anzeige auf dem Dashboard in Frage kommen. Sie stellt die endgültige Menge der Ereignisse dar, die alle Filterkriterien erfüllen und angezeigt werden können.

Mithilfe dieser Zähler können wir die Ereignisverarbeitungspipeline überwachen und analysieren, um sicherzustellen, dass die Filterlogik wie erwartet funktioniert, und um Einblicke in den gesamten Datenfluss zu erhalten. Bevor die Daten gefiltert werden, setzen wir sie auf 0.

totalEvents_Displayable = 0;
totalEvents_Filtered = 0;
totalEvents_Considered = 0;

Vor der ersten Schleife ersetzen wir die früheren Werte durch die neuesten Werte, um alle Ereignisse zu berücksichtigen. Hier ist ein Beispiel.

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

//---

}

Wie Sie sehen können, werden alle Ereignisse berücksichtigt, anstatt die Beschränkungsbedingungen frühzeitig anzuwenden. Dies wird uns helfen, die Überlaufdaten anzuzeigen. Innerhalb der Schleife haben wir also die folgende Aktualisierungslogik.

   //--- Loop through each calendar value up to the maximum defined total
   for (int i = 0; i < allValues; i++){
   
      MqlCalendarEvent event; //--- Declare event structure
      CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID
   
      //--- Other declarations
      
      totalEvents_Considered++;
      
      //--- 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;
         }
      }
      
      //--- Other filters

      //--- If we reach here, the filters passed
      totalEvents_Filtered++;
      
      //--- Restrict the number of displayable events to a maximum of 11
      if (totalEvents_Displayable >= 11) {
        continue; // Skip further processing if display limit is reached
      }
      
      //--- Increment total displayable events
      totalEvents_Displayable++;
      
      //--- Set alternating colors for data holders
      color holder_color = (totalEvents_Displayable % 2 == 0) ? C'213,227,207' : clrWhite;
      
      //--- Create rectangle label for the data holder
      createRecLabel(DATA_HOLDERS + string(totalEvents_Displayable), 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++){
         
         //--- 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
      
         //--- Other fills and creations
      }
      
      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("CURRENT EVENT NAMES DATA SIZE = ",ArraySize(current_eventNames_data));
   //--- Other logs
      
   updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(),
              TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
              IntegerToString(totalEvents_Displayable)+"/"+IntegerToString(totalEvents_Filtered)+"/"+IntegerToString(totalEvents_Considered));
//---

Hier aktualisieren wir einfach die Halter der Ereignisnummern entsprechend. Ein wichtiger Punkt ist der hellblau hervorgehobene Codeschnipsel. Die Logik ist dieselbe wie bei den Filtern: Wenn die anzeigbare Gesamtmenge erreicht ist, wird die Verarbeitung übersprungen. Schließlich aktualisieren wir die Kennzeichnung so, dass es alle 3 Ereigniszählungen enthält, was uns hilft, die Anzahl der Datenüberläufe auf lange Sicht zu ermitteln. Anschließend wenden wir dieselbe Logik auf die Aktualisierungsfunktion an, um sicherzustellen, dass sie ebenfalls in Echtzeit synchronisiert wird. Wenn wir das System laufen lassen, erhalten wir das folgende Ergebnis.

ANZEIGE DES ERGEBNISSES

Aus dem Bild können wir ersehen, dass wir jetzt 3 Nachrichten zählen. Die erste Zahl, in diesem Fall 11, zeigt die Anzahl der insgesamt anzeigbaren Nachrichten an, die zweite, 24, zeigt die Anzahl der insgesamt gefilterten Ereignisse an, nur dass wir nicht alle auf dem Dashboard anzeigen können, und die dritte, 539, zeigt die Gesamtzahl der für die Verarbeitung in Frage kommenden Nachrichten an. Um den Zeitfilter zu aktivieren, können wir die gewünschten Zeitspannen in den Eingabeformaten haben, sodass wir sie bei der Initialisierung des Programms einstellen können. Hier ist die Logik, um dies zu erreichen.

sinput group "General Calendar Settings"
input ENUM_TIMEFRAMES start_time = PERIOD_H12;
input ENUM_TIMEFRAMES end_time = PERIOD_H12;
input ENUM_TIMEFRAMES range_time = PERIOD_H8;

Hier definieren wir eine Gruppe mit dem Namen „General Calendar Settings“ (Allgemeine Kalendereinstellungen), um konfigurierbare Optionen für die Verwaltung kalenderbezogener Funktionen bereitzustellen. Wir verwenden drei Eingänge vom Typ ENUM_TIMEFRAMES, um die Zeitparameter zu steuern, innerhalb derer die Kalenderereignisse gefiltert oder analysiert werden. Zunächst definieren wir die „start_time“, die den Beginn des Zeitraums für Kalenderereignisse angibt und standardmäßig 12 Stunden beträgt, „PERIOD_H12“.

Als Nächstes führen wir „end_time“ ein, das das Ende dieses Zeitraums markiert und ebenfalls standardmäßig auf „PERIOD_H12“ eingestellt ist. Schließlich verwenden wir „range_time“, um die Dauer oder Spanne zu definieren, die für die Kalenderfilterung oder Berechnungen von Interesse ist, mit einem Standardwert von 8 Stunden, „PERIOD_H8“. Auf diese Weise stellen wir sicher, dass das Programm flexibel auf der Grundlage von nutzerdefinierten Zeitrahmen arbeitet, sodass wir die Kalenderdaten an bestimmte Intervalle von Interesse anpassen können. Diese Einstellungen ermöglichen eine dynamische Filterung und bieten dem Nutzer die Kontrolle über den zeitlichen Umfang der angezeigten oder analysierten Ereignisse.

Um die Änderungen vorzunehmen, fügen wir sie wie folgt zu den Steuereingängen der jeweiligen Halterfunktionen und Logiken hinzu.

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

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

Das ist alles. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

ERGEBNIS DER EINGÄNGE

Aus dem Bild geht hervor, dass wir jetzt auf die Eingabeparameter zugreifen und die Zeiteinstellungen aus der aktivierten Dropdown-Liste auswählen können. Bis zu diesem Punkt ist unser Dashboard voll funktionsfähig und ansprechbar. Wir müssen es nur unter verschiedenen Bedingungen und in verschiedenen Umgebungen testen, um sicherzustellen, dass es fehlerfrei funktioniert, und falls es Fehler gibt, diese abstellen. Dies wird im nächsten Abschnitt geschehen.


Testen des verbesserten Dashboards

In diesem Abschnitt führen wir Tests mit dem von uns entwickelten erweiterten Dashboard durch. Ziel ist es, sicherzustellen, dass alle Filter, die Ereignisverfolgung und die Datenanzeigemechanismen wie vorgesehen funktionieren. Wir haben eine Reihe von Filtern implementiert, darunter Währungs-, Wichtigkeits- und Zeitfilter, die es uns ermöglichen, Kalenderereignisse effektiver anzuzeigen und zu analysieren.

Der Testprozess umfasst die Simulation von Nutzerinteraktionen mit dem Dashboard, die Aktivierung und Deaktivierung von Filtern und die Sicherstellung, dass die Kalenderereignisse dynamisch auf der Grundlage der ausgewählten Kriterien aktualisiert werden. Wir überprüfen auch die korrekte Anzeige von Ereignisdaten wie Land, Währung, Wichtigkeitsstufe und Ereigniszeitpunkt innerhalb des definierten Zeitraums.

Durch die Ausführung verschiedener Testszenarien bestätigen wir die Funktionalität jeder Funktion, z. B. das Filtern von Ereignissen nach Wichtigkeit oder Währung, die Begrenzung der Anzahl der angezeigten Ereignisse und die Sicherstellung, dass die Datenbeschriftungen wie erwartet aktualisiert werden. Das folgende Video demonstriert diese Tests in der Praxis.



Schlussfolgerung

Abschließend haben wir das verbesserte Dashboard des MQL5-Wirtschaftskalenders erfolgreich entwickelt und getestet und sichergestellt, dass die Filter, Datenanzeigen und Ereignisverfolgungssysteme nahtlos funktionieren. Dieses Dashboard bietet eine intuitive Schnittstelle zur Verfolgung von Wirtschaftsereignissen, indem es Filter auf der Grundlage von Währung, Bedeutung und Zeit anwendet, was uns hilft, informiert zu bleiben und marktdatengestützte Entscheidungen zu treffen.

Im nächsten Teil dieser Serie werden wir auf dieser Grundlage aufbauen, um die Signalerzeugung und Handelseinträge zu integrieren. Durch die Nutzung der Daten aus dem erweiterten Dashboard werden wir ein System entwickeln, das automatisch Handelssignale auf der Grundlage von wirtschaftlichen Ereignissen und Marktbedingungen generieren kann und damit effizientere und fundiertere Handelsstrategien ermöglicht. Bleiben Sie am Ball.

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

Beigefügte Dateien |
Risikomodell für ein Portfolio unter Verwendung des Kelly-Kriteriums und der Monte-Carlo-Simulation Risikomodell für ein Portfolio unter Verwendung des Kelly-Kriteriums und der Monte-Carlo-Simulation
Seit Jahrzehnten verwenden Händler die Formel des Kelly-Kriteriums, um den optimalen Anteil des Kapitals für eine Investition oder eine Wette zu bestimmen, um das langfristige Wachstum zu maximieren und gleichzeitig das Risiko des Ruins zu minimieren. Das blinde Befolgen des Kelly-Kriteriums auf der Grundlage der Ergebnisse eines einzigen Backtests ist jedoch für einzelne Händler oft gefährlich, da beim Live-Handel der Handelsvorsprung im Laufe der Zeit abnimmt und die vergangene Leistung keine Vorhersage für das zukünftige Ergebnis ist. In diesem Artikel werde ich einen realistischen Ansatz für die Anwendung des Kelly-Kriteriums für die Risikoallokation eines oder mehrerer EAs in MetaTrader 5 vorstellen und dabei die Ergebnisse der Monte-Carlo-Simulation von Python einbeziehen.
Integration von MQL5 mit Datenverarbeitungspaketen (Teil 4): Umgang mit großen Daten Integration von MQL5 mit Datenverarbeitungspaketen (Teil 4): Umgang mit großen Daten
Dieser Teil befasst sich mit fortgeschrittenen Techniken zur Integration von MQL5 mit leistungsstarken Datenverarbeitungswerkzeugen und konzentriert sich auf den effizienten Umgang mit Big Data zur Verbesserung der Handelsanalyse und Entscheidungsfindung.
Klassische Strategien neu interpretieren (Teil 12): EURUSD Ausbruchsstrategie Klassische Strategien neu interpretieren (Teil 12): EURUSD Ausbruchsstrategie
Begleiten Sie uns heute, wenn wir uns der Herausforderung stellen, eine profitable Ausbruchs-Handelsstrategie in MQL5 zu entwickeln. Wir haben das Währungspaar EURUSD ausgewählt und versucht, Kursausbrüche auf dem stündlichen Zeitrahmen zu handeln. Unser System hatte Schwierigkeiten, zwischen falschen Ausbrüchen und dem Beginn eines echten Trends zu unterscheiden. Wir haben unser System mit Filtern überlagert, die unsere Verluste minimieren und gleichzeitig unsere Gewinne erhöhen sollen. Am Ende haben wir unser System erfolgreich profitabel und weniger anfällig für falsche Ausbrüche gemacht.
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. In diesem Artikel werden wir das Verfahren zur Verwendung eines trainierten CatBoost-Modells als Filter für eine klassische Trendfolgestrategie mit gleitendem Durchschnitt erläutern. Dieser Artikel soll einen Einblick in den Strategieentwicklungsprozess geben und gleichzeitig auf die Herausforderungen eingehen, denen man sich auf diesem Weg stellen kann. Ich werde meinen Arbeitsablauf vorstellen, bei dem ich Daten von MetaTrader 5 abrufe, ein maschinelles Lernmodell in Python trainiere und zurück in MetaTrader 5 Expert Advisors integriere. Am Ende dieses Artikels werden wir die Strategie durch statistische Tests validieren und zukünftige Bestrebungen erörtern, die über den derzeitigen Ansatz hinausgehen.