English Русский 中文 Español 日本語
preview
Handel mit dem MQL5 Wirtschaftskalender (Teil 2): Erstellen eines News Dashboard Panels

Handel mit dem MQL5 Wirtschaftskalender (Teil 2): Erstellen eines News Dashboard Panels

MetaTrader 5Handel |
150 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In diesem Artikel bauen wir auf unserer vorherigen Erfahrungen mit dem Wirtschaftskalenders in Teil 1 in der Sprache MetaQuotes Language 5 (MQL5) auf, wo wir uns auf die Beherrschung der Funktionen konzentrierten, die zum Abrufen und Analysieren von Wirtschaftsnachrichten notwendig sind. Als Nächstes Schritt werden wir ein News-Dashboard einrichten, das den Händlern eine bequeme Schnittstelle für den Zugriff auf wichtige Wirtschaftsdaten in Echtzeit bietet. Dieses Dashboard wird dazu beitragen, Entscheidungsprozesse zu optimieren, indem es relevante Nachrichtenereignisse hervorhebt, die Marktbewegungen beeinflussen könnten. Zu den Themen, die wir behandeln werden, gehören:

  1. Gestalten des Dashboard-Panels
  2. Einrichten des Panels in MQL5
  3. Schlussfolgerung

Mit diesen Komponenten wollen wir die Handelserfahrung verbessern, indem wir ein effektives Werkzeug zur Überwachung wirtschaftlicher Ereignisse in Echtzeit für die Wirtschaftsnachrichten in MQL5 bereitstellen.


Gestalten des Dashboard-Panels

Die Gestaltung des Dashboard-Panels ist ein entscheidender Schritt bei der Erstellung eines effektiven Tools zur Überwachung von Wirtschaftsnachrichten mit dem MQL5-Wirtschaftskalender. Unser Ziel ist es, eine nutzerfreundliche und visuell ansprechende Oberfläche zu schaffen, die wichtige Informationen klar und prägnant darstellt. Ein gut strukturiertes Dashboard ermöglicht es uns, die Relevanz und die Auswirkungen wirtschaftlicher Ereignisse auf unsere Handelsstrategien schnell zu beurteilen.

Bei der Gestaltung des Dashboard-Panels müssen wir zunächst die wichtigsten Komponenten bestimmen, die angezeigt werden sollen. Diese Komponenten umfassen in der Regel den Namen des Ereignisses, die geplante Zeit, die betroffene Währung, die Wichtigkeitsstufe und eine kurze Beschreibung des Ereignisses. Um die Nutzerfreundlichkeit zu verbessern, werden wir diese Informationen in Tabellenform darstellen, wobei jede Zeile ein anderes wirtschaftliches Ereignis repräsentiert. Wir beabsichtigen, die Tabelle leicht lesbar zu machen, indem wir kontrastierende Farben für verschiedene Wichtigkeitsstufen verwenden, um eine schnelle Identifizierung von Ereignissen mit hoher Bedeutung zu ermöglichen.

Um das Panel ansprechender zu gestalten, werden wir visuelle Elemente wie Rahmen, Hintergründe und Schriftarten auswählen, um ein sauberes und professionelles Erscheinungsbild zu schaffen. Das Layout wird eine einfache Navigation ermöglichen und sicherstellen, dass wir die benötigten Informationen schnell finden können, ohne mit überflüssigen Details überhäuft zu werden. Indem wir das Design intuitiv und einfach halten, ermöglichen wir es den Händlern, sich auf fundierte Entscheidungen zu konzentrieren, die auf den im Dashboard angezeigten wirtschaftlichen Ereignissen basieren. Die Tafel wird wie oben beschrieben aufgebaut sein und die unten abgebildeten Komponenten enthalten:

Komponenten des Panels

Mit einer klaren Vorstellung von unseren Zielen können wir nun in den Automatisierungsprozess einsteigen. Im vorigen Artikel haben wir uns auf die Beherrschung der Funktionen des MQL5-Wirtschaftskalenders konzentriert, um Wirtschaftsnachrichten effektiv abzurufen und zu analysieren. Falls Sie dies noch nicht getan haben, sollten Sie sich diese Inhalte ansehen, um sicherzustellen, dass Sie gut vorbereitet sind, wenn wir mit der Erstellung unseres News-Dashboard-Panels fortfahren. Fangen wir an!


Einrichten des Panels in MQL5

In diesem Abschnitt werden wir uns auf die Einrichtung des Dashboard-Panels konzentrieren, indem wir die notwendigen Panel-Elemente mit MQL5 erstellen. Zunächst müssen wir Funktionen für die drei Elemente erstellen, die wir benötigen: die rechteckige Beschriftung, die Schaltfläche und die Textbeschriftung. Dieser Ansatz ist äußerst vorteilhaft, da er es uns ermöglicht, dieselben Funktionen bei der Erstellung ähnlicher Merkmale wiederzuverwenden, sodass wir den gesamten Prozess nicht für jedes neue Objekt wiederholen müssen. Auf diese Weise sparen wir Zeit und Platz, machen den Prozess schnell und unkompliziert und halten unsere Codeabschnitte übersichtlich.

Um die rechteckige Beschriftung zu erstellen, werden wir eine Funktion erstellen, die zehn Argumente oder Parameter benötigt. Diese Funktion definiert die Eigenschaften des Rechtecks, wie z. B. seine Position, Größe, Farbe und seinen Stil, sodass wir das visuelle Erscheinungsbild des Etiketts an die Designanforderungen unseres Dashboards anpassen können.

//+------------------------------------------------------------------+
//|     Function to create rectangle label                           |
//+------------------------------------------------------------------+

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {

...
}

Die Funktionssignatur veranschaulicht alles. Es handelt sich um eine boolesche Funktion mit dem Namen „createRecLabel“, was bedeutet, dass sie bei Erfolg bzw. Misserfolg zwei boolesche Flags, true bzw. false, zurückgibt. Zum besseren Verständnis der Parameter werden diese im Folgenden einzeln erläutert.

  • „objName:“ Dieser Parameter steht für den eindeutigen Namen des Rechteckobjekts. Er dient als Kennzeichen für das zu erstellende grafische Element.
  • „xD und yD:“ Diese Parameter bestimmen die X- und Y-Entfernungen von der Ecke, in der die Rechteckbeschriftung positioniert werden soll. Betrachten Sie sie als die Koordinaten, die die obere linke Ecke des Rechtecks relativ zum Chart definieren.
  • „xS und yS:“ Diese Parameter geben die Breite und Höhe des Rechtecks an. Der Wert „xS“ bestimmt, wie breit das Rechteck horizontal ist, während „yS“ die vertikale Höhe bestimmt.

Entfernung und Größe

  • „clrBg:“ Der Parameter „clrBg“ steht für die Hintergrundfarbe der Rechteckbeschriftung. Wählen Sie eine Farbe, die einen guten Kontrast zum Hintergrund des Charts bildet oder die andere Elemente ergänzt.
  • „widthBorder:“ Dieser Parameter bestimmt die Breite des Rahmens um das Rechteck. Wenn Sie einen Rand wünschen, geben Sie einen positiven Wert ein; andernfalls verwenden Sie Null für keinen Rand.
  • „clrBorder:“ Optionaler Parameter für die Farbe des Rahmens. Wenn Sie einen Rahmen wünschen, geben Sie eine Farbe an (bzw. „clrNONE“ für keine Rahmenfarbe).
  • „borderType:“ Gibt die Art des Rahmens für das Rechteck an. Zur Auswahl stehen flache, erhabene oder andere Formen. Für einen einfachen flachen Rahmen verwenden Sie BORDER_FLAT.
  • „borderStyle:“ Wenn Sie einen flachen Rahmen wählen, bestimmt dieser Parameter den Linienstil (z. B. durchgezogen, gestrichelt, ..). Verwenden Sie STYLE_SOLID für eine durchgehende Linie.

In der Funktionssignatur sollten Sie bemerkt haben, dass einige der Argumente bereits auf einen Wert initialisiert sind. Der Initialisierungswert stellt den Standardwert dar, der diesem Parameter zugewiesen wird, falls er während des Funktionsaufrufs ignoriert wird. Unsere Standard-Rahmenfarbe ist beispielsweise „none“, d. h., wenn der Farbwert während des Funktionsaufrufs nicht angegeben wird, wird für den Rand unseres Rechtecks keine Farbe verwendet. 

Innerhalb des Funktionskörpers, der von geschweiften Klammern ({}) eingerahmt wird, definieren wir unsere Prozeduren zur Erstellung von Objekten.

// Create a rectangle label object
if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
  Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
  return (false); // Return false if object creation fails
}

Wir beginnen mit einer if-Anweisung, um zu prüfen, ob das Objekt nicht erstellt wurde. Wir verwenden die Funktion ObjectCreate, die einen booleschen Wert zurückliefert und 6 Argumente benötigt. Diese Funktion erstellt ein Objekt mit dem angegebenen Namen, Typ und den Anfangskoordinaten im angegebenen Teilfenster des Charts. Zunächst geben wir das Chartfenster an, 0 bedeutet, dass das Objekt im Hauptfenster erstellt werden soll. Dann geben wir den Objektnamen an. Dies ist der Name, der einem bestimmten Objekt eindeutig zugewiesen wird. Das zu erstellende Objekt ist vom Typ OBJ_RECTANGLE_LABEL, d. h. es handelt sich um ein Objekt zur Erstellung und Gestaltung der nutzerdefinierten grafischen Oberfläche. Anschließend wird das Fenster angegeben, 0 für das aktuelle Chartfenster. Schließlich geben wir die Zeit- und Preiswerte als Null (0) an, da wir sie nicht mit dem Chart, sondern mit den Koordinaten des Chartfensters verbinden werden. Die Zuordnung wird mit Hilfe von Pixeln festgelegt.

Wenn die Erstellung des Objekts fehlschlägt und die Funktion ObjectCreate schließlich false zurückgibt, ist es offensichtlich sinnlos, weiterzumachen, wir kehren mit einem Fehler zurück. In diesem Fall informieren wir über den Fehler, indem wir ihn neben dem Fehlercode in das Journal drucken und false zurückgeben. Es könnte ein vorheriger Fehler vorliegen, und um den neuesten Fehler zu erhalten, müssen wir den vorherigen Fehler löschen. Dies geschieht durch den Aufruf der Funktion „ResetLastError“, einer intgrierten MQL5-Funktion, unmittelbar vor der Logik der Objekterstellung.

ResetLastError(); // Reset any previous error codes

Der Zweck der Funktion besteht darin, den Wert der vordefinierten Variablen _LastError, die den Fehlercode der letzten fehlerhaften Operation speichert, auf Null zu setzen. Durch den Aufruf dieser Funktion wird sichergestellt, dass alle vorherigen Fehlercodes gelöscht werden, bevor mit den nächsten Operationen fortgefahren wird. Dieser Schritt ist wichtig, weil er es uns ermöglicht, neue Fehler unabhängig von früheren Fehlerzuständen zu behandeln.

Wenn wir zu diesem Punkt gelangt sind, bedeutet dies, dass wir das Objekt erstellt haben, und wir können mit der Aktualisierung der Eigenschaften des Objekts fortfahren. Eine der integrierte Funktionen „ObjectSet...“ setzt den Wert der entsprechenden Objekteigenschaft. Die Objekteigenschaft muss vom Typ datetime, integer, color, boolean oder character sein.

// Set properties for the rectangle label
ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

Wir wollen uns auf die erste Eigenschaftslogik konzentrieren.

ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner

Hier verwenden wir die eingebaute Funktion ObjectSetInteger und übergeben die entsprechenden Parameter. Die Parameter sind wie unten beschrieben.

  • Chart id: Dies ist die ID des Charts. „0“ bezieht sich auf den aktuellen Chart (Chart-ID). Wir passen die Eigenschaften eines Objekts in diesem Chart an.
  • Name: Dies ist der Name des Objekts: „objName“ steht für den eindeutigen Namen, der dem Rechteckbeschriftungsobjekt zugewiesen wurde.
  • Property id: Dies ist die ID der Objekteigenschaft und ihr Wert kann einer der Werte der Enumeration ENUM_OBJECT_PROPERTY_INTEGER sein. OBJPROP_XDISTANCE gibt an, dass wir die Eigenschaft X-Distanz ändern.
  • Property value: Dies ist der Eigenschaftswert. Der Wert, der „xD“ zugewiesen wird, bestimmt, wie weit rechts (oder links, falls negativ) die obere linke Ecke unserer Rechteckbeschriftung horizontal vom linken Rand des Charts positioniert wird.

Auch die anderen Eigenschaften werden nach demselben Schema festgelegt. OBJPROP_YDISTANCE konfiguriert die Y-Abstandseigenschaft der Rechteckbeschriftung. Der Wert „yD“ legt fest, wie weit die linke obere Ecke der Rechteckbeschriftung vertikal vom oberen Rand des Charts entfernt sein soll. Mit anderen Worten, sie steuert die vertikale Platzierung der Beschriftung innerhalb des Chartbereichs. Damit wird der Y-Abstand von der Ecke festgelegt. Mit „OBJPROP_XSIZE“ und „OBJPROP_YSIZE“ wird die Breite bzw. Höhe des Rechtecks festgelegt. 

Um unser Objekt zu positionieren, verwenden wir die Eigenschaft OBJPROP_CORNER, um die Ecke zu bestimmen, die unser Objekt im Chartfenster haben soll.

ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner

Es kann nur 4 Eigenschaftsarten geben:

  • ECKE_LINKS_OBEN: Der Ankerpunkt der Koordinaten befindet sich in der oberen linken Ecke der Karte.
  • CORNER_LEFT_LOWER: Der Ankerpunkt der Koordinaten befindet sich in der unteren linken Ecke des Charts.
  • CORNER_RIGHT_LOWER: Der Ankerpunkt der Koordinaten befindet sich in der unteren rechten Ecke des Charts.
  • CORNER_RIGHT_UPPER: Der Ankerpunkt der Koordinaten befindet sich in der oberen rechten Ecke des Charts.

In einer fotografischen Darstellung haben wir das hier.

Ecken

Der Rest der Eigenschaften ist einfach zu handhaben. Zum besseren Verständnis haben wir sie mit Kommentaren versehen. Anschließend wird das Chart mit der Funktion ChartRedraw neu gezeichnet, damit die Änderungen automatisch wirksam werden, ohne dass auf eine Änderung der Kursnotierungen oder der Chartereignisse gewartet werden muss.

ChartRedraw(0); // Redraw the chart

Schließlich geben wir true zurück, was bedeutet, dass die Erstellung und Aktualisierung der Objekteigenschaften erfolgreich war.

return (true); // Return true if object creation and property settings are successful

Der vollständige Funktionscode, der für die Erstellung eines Rechteckobjekts im Chartfenster verantwortlich ist, lautet wie folgt.

bool createRecLabel(string objName, int xD, int yD, int xS, int yS,
                    color clrBg, int widthBorder, color clrBorder = clrNONE,
                    ENUM_BORDER_TYPE borderType = BORDER_FLAT, ENUM_LINE_STYLE borderStyle = STYLE_SOLID) {
    ResetLastError(); // Reset any previous error codes
    
    // Create a rectangle label object
    if (!ObjectCreate(0, objName, OBJ_RECTANGLE_LABEL, 0, 0, 0)) {
        Print(__FUNCTION__, ": failed to create rec label! Error code = ", _LastError);
        return (false); // Return false if object creation fails
    }
    
    // Set properties for the rectangle label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the rectangle
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Rectangle background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_TYPE, borderType); // Border type
    ObjectSetInteger(0, objName, OBJPROP_STYLE, borderStyle); // Border style (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_WIDTH, widthBorder); // Border width (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrBorder); // Border color (only if borderType is flat)
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Not a background object
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected
    
    ChartRedraw(0); // Redraw the chart
    
    return (true); // Return true if object creation and property settings are successful
}

Um ein Schaltflächenobjekt zu erstellen, wird derselbe Funktionsansatz verwendet. Der Code zum Erstellen einer nutzerdefinierten Schaltflächenfunktion lautet wie folgt.

//+------------------------------------------------------------------+
//|     Function to create button                                    |
//+------------------------------------------------------------------+

bool createButton(string objName, int xD, int yD, int xS, int yS,
                  string txt = "", color clrTxt = clrBlack, int fontSize = 12,
                  color clrBg = clrNONE, color clrBorder = clrNONE,
                  string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the button object
    if (!ObjectCreate(0, objName, OBJ_BUTTON, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the button! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the button
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_XSIZE, xS); // Width of the button
    ObjectSetInteger(0, objName, OBJPROP_YSIZE, yS); // Height of the button
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the button
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BGCOLOR, clrBg); // Background color
    ObjectSetInteger(0, objName, OBJPROP_BORDER_COLOR, clrBorder); // Border color
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Button state (not pressed)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the button
    ChartRedraw(0);

    return (true); // Button creation successful
}

Die Unterschiede im Code bestehen darin, dass ein Rechteck-Objekt keinen Text enthalten kann, eine Schaltfläche jedoch einen beschreibenden Text über die Funktionalität der Schaltfläche enthält, falls dies erforderlich ist. Daher berücksichtigen wir bei den Eingabeparametern Texteigenschaften, in unserem Fall den Textwert, die Farbe, die Schriftgröße und den Schriftnamen. Der Rahmentyp für unsere Schaltfläche ist statisch, sodass wir seine Eigenschaften loswerden und nur die Rahmenfarbe behalten. 

Der Objekttyp, den wir erstellen, ist OBJ_BUTTON, was bedeutet, dass wir ein grafisches Schaltflächenobjekt erstellen. Die Ankerpunkte werden in Pixel angegeben. Die Rahmeneigenschaft, die wir beibehalten, ist die Rahmenfarbe und der Rest wird durch die Texteingabeeigenschaften ersetzt.

Schließlich brauchen wir noch die Funktion des letzten Elements, das die Textbeschriftung ist. Die Kennzeichnung des Textes macht ein Hintergrundobjekt überflüssig und ist daher wesentlich einfacher zu implementieren als die übrigen Funktionen. Wir brauchen nur den Text und konzentrieren uns daher auf die Texteigenschaften. Der Code lautet wie folgt.

//+------------------------------------------------------------------+
//|     Function to create text label                                |
//+------------------------------------------------------------------+

bool createLabel(string objName, int xD, int yD,
                 string txt, color clrTxt = clrBlack, int fontSize = 12,
                 string font = "Arial Rounded MT Bold") {
    // Reset any previous errors
    ResetLastError();

    // Attempt to create the label object
    if (!ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0)) {
        // Print an error message if creation fails
        Print(__FUNCTION__, ": failed to create the label! Error code = ", _LastError);
        return (false);
    }

    // Set properties for the label
    ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, xD); // X distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, yD); // Y distance from the corner
    ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER); // Positioning corner
    ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label
    ObjectSetInteger(0, objName, OBJPROP_COLOR, clrTxt); // Text color
    ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, fontSize); // Font size
    ObjectSetString(0, objName, OBJPROP_FONT, font); // Font name
    ObjectSetInteger(0, objName, OBJPROP_BACK, false); // Transparent background
    ObjectSetInteger(0, objName, OBJPROP_STATE, false); // Label state (not active)
    ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); // Not selectable
    ObjectSetInteger(0, objName, OBJPROP_SELECTED, false); // Not selected

    // Redraw the chart to display the label
    ChartRedraw(0);

    return (true); // Label creation successful
}

Die wichtigsten Unterschiede in dieser Codestruktur gegenüber der Funktion der Schaltfläche sind die Objektgröße und die Rahmeneigenschaften. In der Funktionssignatur werden sowohl die Objektgrößen als auch die Randeigenschaften entfernt. Wir definieren unseren Objekttyp als OBJ_LABEL, um zu verdeutlichen, dass wir Beschriftungen gemäß den definierten Beschriftungskoordinaten in das Chartfenster zeichnen. Schließlich werden wir die Parameter Größe und Rahmen entfernen, und das ist alles. So einfach ist das.

Da wir nun die Funktionen haben, die wir zum Erstellen einer grafischen Nutzeroberfläche (GUI) benötigen, können wir sie zum Erstellen des Panels verwenden. Wir brauchen Namen für die Objekte und um die Interaktion der Objektnamen einfach zu verwalten, ist es viel einfacher, Makros zu definieren. 

#define MAIN_REC "MAIN_REC"

Wir verwenden das Schlüsselwort #define, um ein Makro mit dem Namen „MAIN_REC“ und dem Wert „MAIN_REC“ zu definieren, um unseren Basisnamen für das Hauptrechteck einfach zu speichern, anstatt den Namen bei jeder Erstellung der Ebene erneut eingeben zu müssen, was uns viel Zeit spart und die Gefahr einer falschen Namensgebung verringert. Grundsätzlich werden Makros also zur Textersetzung während der Kompilierung verwendet.

Unser Code wird sich hauptsächlich auf den Initialisierungsabschnitt des Experten stützen, da wir das Panel in der Initialisierungsinstanz erstellen wollen. OnInit wird also den größten Teil der Codestruktur enthalten. 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

int OnInit(){

   ...
   
   return(INIT_SUCCEEDED);
}

Die Funktion OnInit ist eine Ereignis, die bei der Initialisierungsinstanz des Experten aufgerufen wird, um gegebenenfalls notwendige Initialisierungen vorzunehmen. 

Anschließend rufen wir die Funktion auf, um eine rechteckige Kennzeichnung zu erstellen, indem wir ihren Namen eingeben und ihre Parameter angeben.

//--- Create main rectangle label for the dashboard panel
createRecLabel(MAIN_REC,50,50,740,410,clrSeaGreen,1);

Hier lautet der Name des Rechtecks „MAIN_REC“, wie in der Makrodefinition angegeben. Unser Abstand entlang der x-Achse, der Zeit- und Datumsskala, von der linken oberen Ecke des Chartfensters beträgt 50 Pixel, und der Abstand entlang der y-Achse, der Preisskala, beträgt 50 Pixel. Die Breite beträgt 740 Pixel und die Höhe 410 Pixel. Wir wählen grün (sea green) als unsere Hintergrundfarbe, mit einer Rahmenbreite von 1. Der Rest der Parameter sind Standardwerte. Um die Pixel annähernd zu erfassen, können Sie das Chart auf 0 verkleinern, und die Anzahl der Balken zwischen zwei Fadenkreuzkoordinaten ist gleich der Anzahl der Pixel auf der horizontalen Skala. Ein Beispiel, das ist gemeint:

Fadenkreuz

Die anderen Parameter wurden weggelassen, sodass die Standardwerte automatisch übernommen werden. Das heißt, der Rahmentyp ist flach, und die Linienart ist eine durchgehende, durchgezogene Linie. Nach dem Kompilieren ergibt sich das folgende Bild.

Hauptpanel

Um die Unterrahmen zu erstellen, deklarieren wir wieder explizit die entsprechenden Makros für dieselben.

#define SUB_REC1 "SUB_REC1"
#define SUB_REC2 "SUB_REC2"

Dann rufen wir die gleiche Funktion auf, um die Unterrahmen zu erstellen. Wir wollen, dass unsere Rahmen innerhalb des Rahmens der Grundplatte liegen, und deshalb müssen wir eine etwas andere Farbe verwenden. Zu diesem Zweck haben wir die Farben Weiß und Grün verwendet und einen Rand von 3 und 5 Pixeln.

//--- Create sub-rectangle labels within the main panel for different sections
createRecLabel(SUB_REC1,50+3,50+30,740-3-3,410-30-3,clrWhite,1);
createRecLabel(SUB_REC2,50+3+5,50+30+50+27,740-3-3-5-5,410-30-3-50-27-10,clrGreen,1);

Hier richten wir zwei zusätzliche Unterabschnitte, „SUB_REC1“ und „SUB_REC2“, innerhalb des Hauptpanels ein, um den Inhalt visuell zu organisieren und zu trennen. Mit der Funktion „createRecLabel“ positionieren wir „SUB_REC1“, indem wir einen Versatz von 3 Pixeln vom linken und rechten Rand und 30 Pixeln vom oberen Rand des Hauptrechtecks „MAIN_REC“ hinzufügen - und so einen gerahmten Bereich innerhalb des Hauptfensters schaffen. Wir definieren seine Breite als „740-3-3“, damit es in die reduzierten Ränder passt, und seine Höhe als „410-30-3“, damit oben und unten Platz bleibt und es sich gut in das Hauptrechteck einfügt. Dieser Unterabschnitt ist auf eine weiße Farbe eingestellt, die einen neutralen Hintergrund bildet, der sich von der Farbe „sea green“ des Hauptfensters abhebt und die visuelle Klarheit erhöht.

Als Nächstes verwenden wir „createRecLabel“, um „SUB_REC2“ hinzuzufügen, einen zusätzlichen Abschnitt innerhalb von „SUB_REC1“, und positionieren ihn mit feineren Abständen für ein geordnetes, geschichtetes Layout. Um dies zu erreichen, setzen wir die Start-X-Koordinate auf „50+3+5“ und positionieren sie weiter innerhalb von „SUB_REC1“, um sie visuell als einen eigenen Bereich innerhalb dieses Unterabschnitts zu definieren. Wir setzen die Y-Koordinate auf „50+30+50+27“, um den vertikalen Versatz sowohl des Haupt- als auch des ersten Teilrechtecks zu berücksichtigen. Die Breite, „740-3-3-5-5“, passt „SUB_REC2“ genau in den verbleibenden horizontalen Raum, während die Höhe, „410-30-3-50-27-10“, einen ausgewogenen und getrennten Bereich ermöglicht. Wenn Sie „SUB_REC2“ auf grün setzen, wird ein starker Kontrast erzeugt, der darauf hinweist, dass es sich um einen Bereich handelt, in dem kritische Daten angezeigt werden. Diese sorgfältige Schichtung von Rechtecken ist wichtig, um ein strukturiertes und visuell navigierbares Panel für das Armaturenbrett zu schaffen. Nach der Kompilierung erhalten wir die folgenden Ergebnisse:

Rahmen des Panels

Bis zu diesem Punkt ist die Einrichtung unserer Rahmen, Ränder und Begrenzungen für unser Panel abgeschlossen. Anschließend fügen wir die anderen Dienstprogramme des Panels, ihre Eigenschaften und Auswirkungen hinzu. Geben wir dem Panel zunächst einen Titel.

#define HEADER_LABEL "HEADER_LABEL"

//---

//--- Create the header label with text "MQL5 Economic Calendar"
createLabel(HEADER_LABEL,50+3+5,50+5,"MQL5 Economic Calendar",clrWhite,15);

Hier definieren wir den Bezeichner „HEADER_LABEL“ mit dem Wert „HEADER_LABEL“, um die Konsistenz zu gewährleisten und die Bezugnahme auf diesen speziellen Bezeichner in unserem Code zu erleichtern. Diese Kennzeichnung dient als Kopfzeile für unser Dashboard-Panel und trägt den Titel „MQL5-Wirtschaftskalender“ an prominenter Stelle.

Anschließend wird mit der Funktion „createLabel“ das Kopfetikett an der angegebenen Position erstellt. Wir setzen seine X-Koordinate auf „50+3+5“ und positionieren es leicht rechts vom Rand des Hauptfensters, um sicherzustellen, dass er innerhalb des Rechtecks „SUB_REC1“ ausgerichtet ist und sich nicht mit den Rändern überschneidet. Die Y-Koordinate „50+5“ liegt einige Pixel unterhalb des oberen Randes des Hauptrechtecks, um die Lesbarkeit zu gewährleisten. Um die Sichtbarkeit zu gewährleisten, haben wir die Textfarbe auf Weiß und die Schriftgröße auf „15“ gesetzt, sodass eine fette und auffällige Kopfzeile entsteht, die den Zweck des Dashboards kennzeichnet. Diese Kopfzeile verankert das visuelle Design des Dashboards und vermittelt den Nutzern sofort den Zweck des Dashboards. Das ist das Ergebnis.

Der Titel

Das war ein Erfolg. Jetzt können wir mit dem Erstellen der Kopfzeilen fortfahren. Hierfür verwenden wir die einfachste Methode, nämlich die Definition der Überschriften und ihre Platzierung in einem Array, und dann eine Schleife, um sie dynamisch zu platzieren, da sie sich in nur einer Zeile befinden. Allerdings müssen wir auch die Größen der Schaltflächen anders definieren, da sie aufgrund der individuellen Kopfzeilenlängen unterschiedliche Breiten haben werden. Im Folgenden finden Sie die Logik, mit der wir dies erreichen wollen.

string array_calendar[] = {"Date","Time","Cur.","Imp.","Event","Actual","Forecast","Previous"};
int buttons[] = {80,50,50,40,281,60,70,70};

Wir definieren zwei Arrays, um die Beschriftungen und Abmessungen der Schaltflächen im Dashboard zu organisieren. Das erste Array, „array_calendar“, enthält Text für jede Spaltenüberschrift, die angezeigt werden soll, und gibt die Art der Informationen an: „Date“, „Time“, „Cur.“ (Currency), „Imp.“ (Impact/Importance), „Event“, „Actual“, „Forecast“, and „Previous“ (Datum, Uhrzeit, Währ. (Währung), Ausw. (Auswirkung/Bedeutung), Ereignis, Ist-Wert, Prognose und Vorheriger Wert). Jede Zeichenkette stellt eine Bezeichnung für eine Datenkategorie dar und hilft uns zu verstehen, was jeder Abschnitt des Dashboards anzeigen wird.

Das zweite Array, „buttons“, enthält ganze Zahlen, die die Breiten (in Pixeln) für jede Schaltfläche darstellen, die mit den jeweiligen Spalten in „array_calendar“ verbunden sind. Diese Breiten sind auf die einzelnen Datentypen zugeschnitten, um sicherzustellen, dass das Layout ausgerichtet und visuell organisiert bleibt. So sind z. B. 80 Pixel für die Spalte „Datum“ für längere Datumsformate geeignet, während für die Spalten „Zeit“ und „Kurve“, die weniger Platz benötigen, eine geringere Breite von 50 Pixeln eingestellt wird. Zusammen helfen diese Arrays, die Erstellung der Spaltenüberschriften und Schaltflächen des Dashboards zu rationalisieren und bilden eine strukturierte Grundlage für weitere Elemente der Nutzeroberfläche (UI). Von hier aus können wir dann eine Schleife verwenden, um die Kopfzeilen dynamisch zu erstellen.

#define ARRAY_CALENDAR "ARRAY_CALENDAR"

//---

//--- Initialize starting x-coordinate for button positioning
int startX = 59;
   
//--- Loop through the array_calendar elements to create buttons
for (int i=0; i<ArraySize(array_calendar); i++){
   //--- Create each button for calendar categories
   createButton(ARRAY_CALENDAR+IntegerToString(i),startX,132,buttons[i],25,array_calendar[i],clrWhite,13,clrGreen,clrNONE,"Calibri Bold");
   startX += buttons[i]+3; //--- Update x-coordinate for the next button
}

Hier initialisieren und positionieren wir Schaltflächen basierend auf den Elementen von „array_calendar“, um jede Kategorie in unserem Dashboard-Panel zu beschriften. Zunächst definieren wir den Bezeichner „ARRAY_CALENDAR“ für die Kalender-Schaltflächenreihe. Dann setzen wir „startX“ auf „59“ als anfängliche x-Koordinate, wodurch die erste Schaltfläche horizontal auf dem Panel positioniert wird.

Dann verwenden wir eine for-Schleife, um jedes Element in „array_calendar“ zu durchlaufen und eine Schaltfläche zu erstellen. Bei jeder Iteration rufen wir die Funktion „createButton“ auf und übergeben eine eindeutige ID für jede Schaltfläche, indem wir den Schleifenindex an „ARRAY_CALENDAR“ anhängen. Dadurch wird sichergestellt, dass jede Schaltflächen-ID eindeutig ist und sich auf Kategorien wie „Date“, „Time“, „Cur“ usw. bezieht. Wir geben die Position „startX" an und verwenden Werte aus „buttons", um die Breite der einzelnen Schaltflächen zu definieren und die Ausrichtung auf die jeweilige Datenkategorie zu gewährleisten. Jede Schaltfläche erhält auch Styling-Eigenschaften, darunter eine Schriftfarbe (weiß), eine Schriftgröße (13) und Hintergrundfarben (grün für die Schaltfläche und keine für den Rahmen), die in der Schriftart „Calibri Bold" festgelegt sind. Nach der Erstellung jeder Schaltfläche wird „startX" angepasst, indem die Breite der aktuellen Schaltfläche plus ein Rand von „3" Pixeln hinzugefügt wird, um die Schaltflächen für die nächste Iteration gleichmäßig zu verteilen. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

Kopfzeilen

Nachdem wir die Überschriften erstellt haben, müssen wir nun die anderen Unterabschnitte für die Anzeige der Zeit, der Anzahl der identifizierten Nachrichtenereignisse und der Auswirkungsgrade erstellen. Wir beginnen mit den Ereignissen aus dem vorherigen Teil der Serie.

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

So erhalten wir die historischen Ereigniswerte, wie sie vom MQL5-Wirtschaftskalender abgerufen werden, und können sie auf dem Dashboard anzeigen, anstatt sie nur zu drucken. Hier ist die Logik, die wir anwenden.

#define TIME_LABEL "TIME_LABEL"

//---

//--- Create label displaying server time and total number of news events found
createLabel(TIME_LABEL,70,85,"Server Time: "+TimeToString(TimeCurrent(),
           TIME_DATE|TIME_SECONDS)+"   |||   Total News: "+
           IntegerToString(allValues),clrBlack,14,"Times new roman bold");

Hier wird ein Kennzeichen erstellt, das die aktuelle Serverzeit zusammen mit der Gesamtzahl der abgerufenen Nachrichten anzeigt. Zunächst definieren wir „TIME_LABEL", um diese Bezeichnung in unserem Dashboard-Panel eindeutig zu referenzieren.

Als Nächstes rufen wir die Funktion „createLabel" auf, um das Etikett selbst zu erstellen. Wir geben die Position des Etiketts durch die Koordinaten „70" und „85" an, die vorgeben, wo das Etikett auf der Tafel erscheinen soll. Der Text für die Beschriftung wird dynamisch mit der Funktion TimeToString erstellt, die die aktuelle Serverzeit, die von der Funktion TimeCurrent abgerufen wird, im Format Datum und Sekunden formatiert. Wir verketten diese formatierte Zeit mit der Zeichenkette „||| Total News:“ und wandeln die Variable „allValues“, die die Anzahl der Nachrichtenereignisse enthält, mit der Funktion IntegerToString in eine Zeichenkette um. Auf diese Weise wird eine umfassende Darstellung erstellt, das sowohl die Serverzeit als auch die Gesamtzahl der gefundenen Nachrichtenereignisse anzeigt. Wir gestalten das Etikett mit schwarzer Farbe, einer Schriftgröße von 14 und verwenden die Schriftart „Times New Roman bold" für eine klare Sichtbarkeit. Mit der gleichen Logik erstellen wir auch das Etikett für die Auswirkungen.

#define IMPACT_LABEL "IMPACT_LABEL"

//---

//--- Create label for displaying "Impact" category header
createLabel(IMPACT_LABEL,70,105,"Impact: ",clrBlack,14,"Times new roman bold");

Nach dem Kompilieren erhalten wir die folgende Ausgabe.

Werte und Auswirkung

Das war ein Erfolg. Wir müssen nun dazu übergehen, die entsprechenden Schaltflächen für die Auswirkungen mit den entsprechenden Beschriftungen und Farben anzuzeigen, damit die Nutzer wissen, was die einzelnen Auswirkungsstufen bedeuten. 

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

//--- Loop through impact levels to create buttons for each level
for (int i=0; i<ArraySize(impact_labels); i++){
   color impact_color = clrBlack, label_color = clrBlack; //--- Default colors for label and button

   //--- Assign color based on impact level
   if (impact_labels[i] == "None"){label_color = clrWhite;}
   else if (impact_labels[i] == "Low"){impact_color = clrYellow;}
   else if (impact_labels[i] == "Medium"){impact_color = clrOrange;}
   else if (impact_labels[i] == "High"){impact_color = clrRed;}

   //--- Create button for each impact level
   createButton(IMPACT_LABEL+string(i),140+impact_size*i,105,impact_size,25,impact_labels[i],label_color,12,impact_color,clrBlack);
}

Hier definieren wir die Bezeichnungen für die verschiedenen mit wirtschaftlichen Ereignissen verbundenen Auswirkungsebenen und die Größe der Anzeigebereiche für diese Auswirkungsindikatoren. Zunächst deklarieren wir ein Array mit der Bezeichnung „impact_labels", das Zeichenketten enthält, die die verschiedenen Auswirkungsstufen darstellen: "None", "Low", "Medium", and "High" (keine, niedrig, mittel und hoch). Zusätzlich initialisieren wir eine Integer-Variable „impact_size" mit einem Wert von 100, die die Breite der Schaltflächen bestimmt, die für jede Auswirkungsebene erstellt werden.

Als Nächstes wird eine Schleife eingefügt, die über das Array „impact_labels“ iteriert und die Funktion ArraySize verwendet, um die Gesamtzahl der Auswirkungsebenen zu ermitteln. In dieser Schleife legen wir zunächst die Standardfarben für die Schaltfläche und die Beschriftung fest, indem wir die Farbe Schwarz verwenden. Wir verwenden dann bedingte Anweisungen, um bestimmte Farben auf der Grundlage der aktuellen Auswirkungsstufe zuzuweisen. Wenn die Auswirkungsebene „None“ (Keine) ist, ändern wir die „label_color" in weiß. Wenn die Stufe „Niedrig" ist, setzen wir „impact_color" auf gelb. Für „Medium" weisen wir „impact_color" orange zu, und für „High" bezeichnen wir „impact_color" als rot. Schließlich rufen wir die Funktion „createButton“ auf, um eine Schaltfläche für jede Aufprallstufe zu erzeugen, wobei wir sie anhand einer dynamischen x-Koordinate positionieren, die mit „140 + impact_size * i“ berechnet wird, und eine feste y-Koordinate von 105 beibehalten und die Abmessungen und Farben entsprechend angeben. Hier ist der aktuelle Meilenstein.

Tasten für die Auswirkung

Das war ein Erfolg. Wir können nun dazu übergehen, die eigentlichen Kalenderdaten zum Dashboard hinzuzufügen. Zuvor müssen wir jedoch den zweiten Teilrahmen partitionieren, um dem Panel ein professionelleres Aussehen zu verleihen, anstatt nur Daten darin unterzubringen. Das erreichen wir durch die folgende Logik.

//--- Limit the total number of values to display
int valuesTotal = (allValues <= 11) ? allValues : 11;

//--- 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++){

   //--- Set alternating colors for each data row holder
   color holder_color = (i % 2 == 0) ? C'213,227,207' : clrWhite;

   //--- Create rectangle label for each data row holder
   createRecLabel(DATA_HOLDERS+string(i),62,startY-1,716,26,holder_color,1,clrBlack);

   //--- Increment y-coordinate for the next row of data
   startY += 25;
   Print(startY); //--- Print current y-coordinate for debugging
}

Wir begrenzen die Gesamtzahl der Werte, die in unserem Dashboard angezeigt werden sollen, indem wir eine Integer-Variable namens „valuesTotal“ definieren. Wir verwenden einen bedingten (ternären) Operator, um zu prüfen, ob „allValues“ kleiner oder gleich „11“ ist. Wenn ja, setzen wir „valuesTotal“ auf „allValues“, andernfalls setzen wir es auf „11“. Auf diese Weise wird sichergestellt, dass wir nicht versuchen, mehr als „11“ Nachrichtenereignisse anzuzeigen, sodass unser Dashboard übersichtlich und handlich bleibt.

Als Nächstes initialisieren wir eine Integer-Variable „startY“ mit dem Wert „162“, die als y-Startkoordinate für die Positionierung der Nachrichtendaten auf dem Panel dient. Anschließend wird eine Schleife eingefügt, die von „0“ bis „valuesTotal“ durchläuft und so jeden anzuzeigenden Kalenderwert verarbeitet. Innerhalb dieser Schleife legen wir die Farbe für jeden Zeilenhalter nach einem abwechselnden Muster fest, das auf dem aktuellen Index „i“ basiert. Wenn „i“ gerade ist, setzen wir „holder_color“ auf eine hellgraue Farbe, die durch „C'213,227,207'“ dargestellt wird; wenn „i“ ungerade ist, setzen wir sie auf weiß. Nachdem wir die Farbe bestimmt haben, rufen wir die Funktion „createRecLabel“ auf, um eine rechteckige Beschriftung für jeden Datenzeilenhalter zu erzeugen, die auf der x-Achse bei „62“ und auf der y-Achse bei „startY - 1“ positioniert ist und eine Breite von „716“, eine Höhe von „26“ und einen schwarzen Rand hat. Schließlich erhöhen wir „startY“ um „25“, um die y-Koordinate für die nächste Datenzeile anzupassen und sicherzustellen, dass jeder Eintrag nacheinander angezeigt wird. Zu Debugging-Zwecken geben wir den aktuellen Wert von „startY“ aus, damit wir die vertikale Positionierung jeder Datenzeile verfolgen können, während sie erstellt wird. Hier ist der aktuelle Meilenstein.

DATA HOLDERS

Sie haben vielleicht bemerkt, dass wir bei der Erstellung des Unterrahmens die Makrovariable „DATA_HOLDERS“ verwendet haben. Sie ist wie folgt definiert.

#define DATA_HOLDERS "DATA_HOLDERS"
#define ARRAY_NEWS "ARRAY_NEWS"

Wir haben auch das Makro „ARRAY_NEWS“ definiert, um die Erstellung der entsprechenden Daten zu erleichtern, die in den Datenhaltern zu den Spaltenüberschriften abgebildet werden sollen. Um die Daten auszufüllen, ist es erforderlich, dass wir für jeden ausgewählten Halter alle Daten für einen bestimmten Ereigniswert durchgehen und dessen Daten erhalten, die wir anzeigen werden. Dies geschieht also innerhalb der ersten Schleife und hat die folgende Logik.

//--- 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++){

   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

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

   MqlCalendarValue value; //--- Declare calendar value structure
   CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values

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

Hier initialisieren wir eine Integer-Variable namens „startX“ mit einem Wert von 65, die als Start-X-Koordinate für die Positionierung jedes Dateneintrags im Zusammenhang mit Kalenderereignissen dienen wird. Anschließend wird eine Schleife eingefügt, die jede Spalte im „array_calendar“ mit dem Index „k“ durchläuft. Innerhalb dieser Schleife deklarieren wir eine Strukturvariable „event“ vom Typ MqlCalendarEvent, die dazu dient, die Details eines bestimmten Kalenderereignisses zu speichern. Wir rufen die Ereignisdetails ab, indem wir die Funktion CalendarEventById aufrufen, die Ereignis-ID aus dem Array „values“ übergeben und die Ergebnisse in „event“ speichern.

Als Nächstes deklarieren wir eine weitere Strukturvariable „country“ vom Typ MqlCalendarCountry, um Informationen über das mit dem Kalenderereignis verbundene Land zu speichern. Wir verwenden die Funktion CalendarCountryById, um „country“ mit Details auf der Grundlage der Länder-ID des Ereignisses zu füllen. Zu Debugging-Zwecken werden wichtige Ereignisdetails wie der Name des Ereignisses, seine Wichtigkeitsstufe (mit der Funktion EnumToString in eine Zeichenkette umgewandelt), der Name des Landes und die in „values[i].time“ gespeicherte Ereigniszeit ausgegeben.

Dann bereiten wir ein String-Array namens „news_data“ vor, dessen Größe der von „array_calendar“ entspricht, um die Informationen über das Ereignis zu speichern. Das erste Element von „news_data“ wird auf das Ereignisdatum gesetzt, das mit der Funktion TimeToString und dem Flag „TIME_DATE“ als String formatiert wird. Das zweite Element erfasst den Zeitpunkt des Ereignisses, formatiert mit dem Flag „TIME_MINUTES“. Das dritte Element speichert die Währung des Landes, in dem das Ereignis stattfindet.

Als Nächstes bestimmen wir die Farbe für die Wichtigkeit des Ereignisses auf der Grundlage seiner Auswirkungsstufe, indem wir eine Variable „importance_color“ auf schwarz setzen. Wir überprüfen den Wert von „event.importance“, und je nach Wert (niedrig, mittel oder hoch) weisen wir die entsprechende Farbe zu: gelb für niedrig, orange für mittel und rot für hoch.

Wir setzen auch das vierte Element von „news_data“ auf ein Symbol, das den Wichtigkeitsgrad des Ereignisses darstellt, indem wir „ShortToString“ (0x25CF) verwenden, um einen gefüllten Kreis zu erstellen. Dem fünften Element wird der Ereignisname zugewiesen, der aus „event.name“ abgerufen wird.

Um aktuelle, prognostizierte und frühere Werte für das Ereignis abzurufen, deklarieren wir eine weitere Strukturvariable namens „value“ vom Typ MqlCalendarValue und verwenden die Funktion CalendarValueById, um diese Struktur auf der Grundlage der in „values[i].id“ gespeicherten ID des Ereignisses aufzufüllen. Das sechste, siebte und achte Element von „news_data“ werden mit den aktuellen, prognostizierten bzw. früheren Werten gefüllt, die mit der Funktion DoubleToString auf drei Dezimalstellen formatiert werden.

Schließlich erstellen wir mit der Funktion „createLabel“ ein Etikett für jedes Nachrichtenelement. Wenn „k“ gleich „3“ ist, wird die Farbe für die Wichtigkeit verwendet; andernfalls wird standardmäßig die Farbe Schwarz verwendet. Die x-Koordinate für jede Beschriftung wird durch „startX“ bestimmt, die wir dann durch Hinzufügen der Schaltflächenbreite aus dem Array „buttons“ erhöhen, um sicherzustellen, dass jede Datenspalte für eine klare Anzeige korrekt positioniert ist. Nach dem Kompilieren erhalten wir die folgende Ausgabe.

Panel mit Werten

Das war ein Erfolg. Wir haben jetzt ein MQL5-Wirtschaftskalender-Dashboard erstellt, das die Nachrichtendaten im Chart anzeigt, um die Referenzierung zu erleichtern. Was den aktuellen Meilenstein betrifft, so erhalten wir einfach alle Daten. In den nächsten Teilen der Serie werden wir das Panel durch die Integration von Filtern, die Integration von Echtzeitdaten-Updates und die Nutzung der Nachrichtendaten für Handelszwecke verbessern.


Schlussfolgerung

Zusammenfassend lässt sich sagen, dass wir erfolgreich die Grundlage für unseren Wirtschaftskalender in MQL5 gelegt haben, indem wir ein interaktives Dashboard-Panel konstruiert haben, das wichtige wirtschaftliche Ereignisse in einem nutzerfreundlichen Format anzeigt. Durch die Implementierung von Funktionen wie dem Abruf von Kalenderdaten, der visuellen Kategorisierung von Ereignissen auf der Grundlage ihrer Bedeutung und der intuitiven Beschriftung können wir über wichtige Marktbewegungen informiert bleiben. Diese Ersteinrichtung verbessert nicht nur die Nutzerfreundlichkeit, sondern bietet auch eine solide Grundlage für weitere Verbesserungen, die unser Dashboard auf die nächste Stufe heben werden.

In den nächsten Teilen dieser Serie werden wir zusätzliche Funktionen integrieren, wie z. B. Nachrichtenfilter, die uns dabei helfen, uns auf die relevantesten Informationen für unsere Strategien in MQL5 zu konzentrieren. Wir werden auch Echtzeit-Updates einführen, um sicherzustellen, dass unser Panel die neuesten Wirtschaftsdaten widerspiegelt, sobald diese verfügbar sind. Außerdem werden wir uns darauf konzentrieren, das Panel responsiv zu gestalten, sodass es sich nahtlos an verschiedene Bildschirmgrößen und Nutzerinteraktionen anpassen kann. Unser Ziel ist es, diese Daten zu nutzen, um fundierte Handelsentscheidungen zu treffen und unseren Wirtschaftskalender in ein leistungsstarkes Instrument für Händler zu verwandeln, die von der Volatilität der Märkte profitieren möchten. Bleiben Sie am Ball.

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

Beigefügte Dateien |
Schrittweise Merkmalsauswahl in MQL5 Schrittweise Merkmalsauswahl in MQL5
In diesem Artikel stellen wir eine modifizierte Version der schrittweisen Merkmalsauswahl vor, die in MQL5 implementiert ist. Dieser Ansatz basiert auf den Techniken, die in „Modern Data Mining Algorithms in C++ and CUDA C“ von Timothy Masters beschrieben sind.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 46): Ichimoku MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 46): Ichimoku
Der Ichimuko Kinko Hyo ist ein bekannter japanischer Indikator, der als Trenderkennungssystem dient. Wir untersuchen dies, wie schon in früheren ähnlichen Artikeln, Muster für Muster und bewerten auch die Strategien und Testberichte mit Hilfe der MQL5-Assistentenbibliothek Klassen und Assembly.
Klassische Strategien neu interpretieren (Teil XI): Kreuzung gleitender Durchschnitte (II) Klassische Strategien neu interpretieren (Teil XI): Kreuzung gleitender Durchschnitte (II)
Die gleitenden Durchschnitte und der Stochastik-Oszillator können verwendet werden, um trendfolgende Handelssignale zu generieren. Diese Signale werden jedoch erst nach dem Eintreten der Preisaktion beobachtet. Diese den technischen Indikatoren innewohnende Verzögerung können wir mit Hilfe von KI wirksam überwinden. In diesem Artikel erfahren Sie, wie Sie einen vollständig autonomen KI-gesteuerten Expert Advisor erstellen, der Ihre bestehenden Handelsstrategien verbessern kann. Selbst die älteste mögliche Handelsstrategie kann verbessert werden.
Feature Engineering mit Python und MQL5 (Teil II): Winkel des Preises Feature Engineering mit Python und MQL5 (Teil II): Winkel des Preises
Im MQL5-Forum gibt es viele Beiträge, in denen um Hilfe bei der Berechnung der Steigung von Preisänderungen gebeten wird. In diesem Artikel wird eine Möglichkeit zur Berechnung des Winkels aufgezeigt, der sich aus den Kursveränderungen eines beliebigen Marktes ergibt, mit dem Sie handeln möchten. Außerdem werden wir die Frage beantworten, ob die Entwicklung dieser neuen Funktion den zusätzlichen Aufwand und die investierte Zeit wert ist. Wir werden untersuchen, ob die Steigung des Kurses die Genauigkeit unseres KI-Modells bei der Vorhersage des USDZAR-Paares auf dem M1 verbessern kann.