English 日本語
preview
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 8): Metrics Board

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 8): Metrics Board

MetaTrader 5Handel | 30 Mai 2025, 11:30
91 0
Christian Benjamin
Christian Benjamin

Inhalt



Einführung

In der Anfangsphase unserer Serie veröffentlichten wir einen Artikel mit dem Titel „Analytics Master“, in dem wir Methoden zum Abrufen und Visualisieren der Marktkennzahlen des Vortags untersuchten. Diese grundlegenden Arbeiten bildeten die Grundlage für die Entwicklung anspruchsvollerer Instrumente. Wir freuen uns, Ihnen den Metrics Board EA vorstellen zu können, eine innovative und qualitativ hochwertige Lösung, die die Marktanalyse im MetaTrader 5 revolutioniert. Dieses Tool funktioniert als nahtlos integrierte Anwendung und bietet eine optimierte und einfache Nutzeroberfläche mit speziellen Schaltflächen für fortgeschrittene Analysen, einschließlich:

  • Hoch/Tief-Analyse: Erkennen Sie mühelos kritische Kursniveaus, um Markttrends zu bewerten und potenzielle Umschwünge zu identifizieren.
  • Volumenanalyse: Analysieren Sie die Handelsvolumina, um das Marktengagement und die Liquiditätsbedingungen zu beurteilen.
  • Trendanalyse: Bewertung der Richtungsstärke und Nachhaltigkeit anhand präziser Metriken.
  • Volatilitätsanalyse: Quantifizierung von Marktschwankungen zur Formulierung von Strategien, die auf unterschiedliche Handelsumgebungen zugeschnitten sind.
  • Analyse des gleitenden Durchschnitts: Überwachen der dynamische Preistrends, um ein besseres Verständnis des Marktverhaltens zu erlangen.
  • Analyse von Unterstützung/Widerstand: Identifizieren der entscheidende Kursniveaus, um Ein- und Ausstiege sowie Risikomanagementstrategien zu optimieren.

Jede Schaltfläche ermöglicht die Bereitstellung von Live-Daten mit einem einfachen Klick und verwandelt komplexe Marktdaten in sofort umsetzbare Erkenntnisse. Der EA Metrics Board wird von fortschrittlichen Algorithmen angetrieben, die schnelle und genaue Berechnungen gewährleisten, die den Bedürfnissen professioneller Trader entsprechen. Mit diesem Tool können Händler komplizierte Marktdaten in einfache und umsetzbare Erkenntnisse umwandeln. Dieser EA dient als wichtige Ressource für diejenigen, die ihre Handelsstrategien verfeinern wollen.


System-Übersicht

In diesem Abschnitt werde ich einen kurzen Überblick über die Systemlogik geben. Eine ausführliche Erläuterung der Schritte finden Sie im Abschnitt Codeaufschlüsselung und Implementierung. Gehen wir die folgenden Schritte durch:

  • Einrichtung der Klasse: Die Klasse erstellt einen Dialog mit Schaltflächen für verschiedene Analysen.
  • Ereignisbehandlung: Schaltflächenklicks lösen entsprechende Analysemethoden aus.
  • Analyse und Anzeige: Die Marktdaten werden verarbeitet und im Panel angezeigt.
  • Schließen: Eine Schaltfläche „Close“ ermöglicht es dem Nutzer, die Metrik-Tafel zu schließen.
Die oben genannten Schritte umreißen die Etappen, die unser EA bewältigen wird, um die erwarteten Ergebnisse zu erzielen. Jede Phase ist sorgfältig durchdacht, um eine präzise Ausführung zu gewährleisten, die von der Marktanalyse bis hin zur Gewinnung verwertbarer Erkenntnisse alles umfasst. Durch die Einhaltung dieser Schritte gewährleistet der EA einen nahtlosen und effizienten Prozess. Das nachstehende Chart veranschaulicht den gesamten Prozess.


Zusammenfassung der Logik des EAs

Abb. 1. Zusammenfassung der Logik des EAs


MQL5 Code

//+------------------------------------------------------------------+
//|                                                Metrics Board.mql5|
//|                                Copyright 2025, Christian Benjamin|
//|                                              https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\Panel.mqh>

// Metrics Board Class
class CMetricsBoard : public CAppDialog
  {
private:
   CButton           m_btnClose; // Close Button
   CButton           m_btnHighLowAnalysis;
   CButton           m_btnVolumeAnalysis;
   CButton           m_btnTrendAnalysis;
   CButton           m_btnVolatilityAnalysis;
   CButton           m_btnMovingAverage;
   CButton           m_btnSupportResistance;
   CPanel            m_panelResults;
   CLabel            m_lblResults;

public:
                     CMetricsBoard(void);
                    ~CMetricsBoard(void);
   virtual bool      Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2);
   virtual void      Minimize();
   virtual bool      Run(); // Declaration of Run method
   virtual bool      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   virtual bool      ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
   virtual void      Destroy(const int reason = REASON_PROGRAM); // Override Destroy method

private:
   bool              CreateButtons(void);
   bool              CreateResultsPanel(void);
   void              OnClickButtonClose(); // New close button handler
   void              PerformHighLowAnalysis(void);
   void              PerformVolumeAnalysis(void);
   void              PerformTrendAnalysis(void);
   void              PerformVolatilityAnalysis(void);
   void              PerformMovingAverageAnalysis(void);
   void              PerformSupportResistanceAnalysis(void);
   double            CalculateMovingAverage(int period);
  };

CMetricsBoard::CMetricsBoard(void) {}

CMetricsBoard::~CMetricsBoard(void) {}

// Override Destroy method
void CMetricsBoard::Destroy(const int reason)
  {
// Call base class Destroy method to release resources
   CAppDialog::Destroy(reason);
  }

//+------------------------------------------------------------------+
//| Create a control dialog                                          |
//+------------------------------------------------------------------+
bool CMetricsBoard::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
  {
   if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2))
     {
      Print("Failed to create CAppDialog instance.");
      return false; // Failed to create the dialog
     }

   if(!CreateResultsPanel())
     {
      Print("Failed to create results panel.");
      return false; // Failed to create the results panel
     }

   if(!CreateButtons())
     {
      Print("Failed to create buttons.");
      return false; // Failed to create buttons
     }

   Show(); // Show the dialog after creation
   return true; // Successfully created the dialog
  }

//+------------------------------------------------------------------+
//| Minimize the control window                                      |
//+------------------------------------------------------------------+
void CMetricsBoard::Minimize()
  {
   CAppDialog::Minimize();
  }

//+------------------------------------------------------------------+
//| Run the control.                                                 |
//+------------------------------------------------------------------+
bool CMetricsBoard::Run()
  {
// Assuming Run makes the dialog functional
   if(!Show())
     {
      Print("Failed to show the control.");
      return false; // Could not show the control
     }
// Additional initialization or starting logic can be added here
   return true; // Successfully run the control
  }

//+------------------------------------------------------------------+
//| Create the results panel                                         |
//+------------------------------------------------------------------+
bool CMetricsBoard::CreateResultsPanel(void)
  {
   if(!m_panelResults.Create(0, "ResultsPanel", 0, 10, 10, 330, 60))
      return false;

   m_panelResults.Color(clrLightGray);
   Add(m_panelResults);

   if(!m_lblResults.Create(0, "ResultsLabel", 0, 15, 15, 315, 30))
      return false;

   m_lblResults.Text("Results will be displayed here.");
   m_lblResults.Color(clrBlack);
   m_lblResults.FontSize(12);
   Add(m_lblResults);

   return true;
  }

//+------------------------------------------------------------------+
//| Create buttons for the panel                                     |
//+------------------------------------------------------------------+
bool CMetricsBoard::CreateButtons(void)
  {
   int x = 20;
   int y = 80;
   int buttonWidth = 300;
   int buttonHeight = 30;
   int spacing = 15;

// Create Close Button
   if(!m_btnClose.Create(0, "CloseButton", 0, x, y, x + buttonWidth, y + buttonHeight))
      return false;

   m_btnClose.Text("Close Panel");
   Add(m_btnClose);
   y += buttonHeight + spacing;

   struct ButtonData
     {
      CButton        *button;
      string         name;
      string         text;
     };

   ButtonData buttons[] =
     {
        {&m_btnHighLowAnalysis, "HighLowButton", "High/Low Analysis"},
        {&m_btnVolumeAnalysis, "VolumeButton", "Volume Analysis"},
        {&m_btnTrendAnalysis, "TrendButton", "Trend Analysis"},
        {&m_btnVolatilityAnalysis, "VolatilityButton", "Volatility Analysis"},
        {&m_btnMovingAverage, "MovingAverageButton", "Moving Average"},
        {&m_btnSupportResistance, "SupportResistanceButton", "Support/Resistance"}
     };

   for(int i = 0; i < ArraySize(buttons); i++)
     {
      if(!buttons[i].button.Create(0, buttons[i].name, 0, x, y, x + buttonWidth, y + buttonHeight))
         return false;

      buttons[i].button.Text(buttons[i].text);
      Add(buttons[i].button);
      y += buttonHeight + spacing;
     }

   return true;
  }

//+------------------------------------------------------------------+
//| Handle events for button clicks                                  |
//+------------------------------------------------------------------+
bool CMetricsBoard::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      Print("Event ID: ", id, ", Event parameter (sparam): ", sparam);

      if(sparam == "CloseButton") // Handle close button click
        {
         OnClickButtonClose(); // Call to new close button handler
         return true; // Event processed
        }
      else
         if(sparam == "HighLowButton")
           {
            Print("High/Low Analysis Button Clicked");
            m_lblResults.Text("Performing High/Low Analysis...");
            PerformHighLowAnalysis();
            return true; // Event processed
           }
         else
            if(sparam == "VolumeButton")
              {
               Print("Volume Analysis Button Clicked");
               m_lblResults.Text("Performing Volume Analysis...");
               PerformVolumeAnalysis();
               return true; // Event processed
              }
            else
               if(sparam == "TrendButton")
                 {
                  Print("Trend Analysis Button Clicked");
                  m_lblResults.Text("Performing Trend Analysis...");
                  PerformTrendAnalysis();
                  return true; // Event processed
                 }
               else
                  if(sparam == "VolatilityButton")
                    {
                     Print("Volatility Analysis Button Clicked");
                     m_lblResults.Text("Performing Volatility Analysis...");
                     PerformVolatilityAnalysis();
                     return true; // Event processed
                    }
                  else
                     if(sparam == "MovingAverageButton")
                       {
                        Print("Moving Average Analysis Button Clicked");
                        m_lblResults.Text("Calculating Moving Average...");
                        PerformMovingAverageAnalysis();
                        return true; // Event processed
                       }
                     else
                        if(sparam == "SupportResistanceButton")
                          {
                           Print("Support/Resistance Analysis Button Clicked");
                           m_lblResults.Text("Calculating Support/Resistance...");
                           PerformSupportResistanceAnalysis();
                           return true; // Event processed
                          }
     }

   return false; // If we reach here, the event was not processed
  }

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
bool CMetricsBoard::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   Print("ChartEvent ID: ", id, ", lparam: ", lparam, ", dparam: ", dparam, ", sparam: ", sparam);

   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      return OnEvent(id, lparam, dparam, sparam);
     }

   return false;
  }

//+------------------------------------------------------------------+
//| Analysis operations                                              |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformHighLowAnalysis(void)
  {
   double high = iHigh(Symbol(), PERIOD_H1, 0);
   double low = iLow(Symbol(), PERIOD_H1, 0);

   Print("Retrieved High: ", high, ", Low: ", low);

   if(high == 0 || low == 0)
     {
      m_lblResults.Text("Failed to retrieve high/low values.");
      return;
     }

   string result = StringFormat("High: %.5f, Low: %.5f", high, low);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformVolumeAnalysis(void)
  {
   double volume = iVolume(Symbol(), PERIOD_H1, 0);
   Print("Retrieved Volume: ", volume);

   if(volume < 0)
     {
      m_lblResults.Text("Failed to retrieve volume.");
      return;
     }

   string result = StringFormat("Volume (Last Hour): %.1f", volume);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformTrendAnalysis(void)
  {
   double ma = CalculateMovingAverage(14);
   Print("Calculated 14-period MA: ", ma);

   if(ma <= 0)
     {
      m_lblResults.Text("Not enough data for moving average calculation.");
      return;
     }

   string result = StringFormat("14-period MA: %.5f", ma);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformVolatilityAnalysis(void)
  {
   int atr_period = 14;
   int atr_handle = iATR(Symbol(), PERIOD_H1, atr_period);

   if(atr_handle == INVALID_HANDLE)
     {
      m_lblResults.Text("Failed to get ATR handle.");
      return;
     }

   double atr_value[];
   if(CopyBuffer(atr_handle, 0, 0, 1, atr_value) < 0)
     {
      m_lblResults.Text("Failed to copy ATR value.");
      IndicatorRelease(atr_handle);
      return;
     }

   string result = StringFormat("ATR (14): %.5f", atr_value[0]);
   m_lblResults.Text(result);
   IndicatorRelease(atr_handle);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformMovingAverageAnalysis(void)
  {
   double ma = CalculateMovingAverage(50);
   Print("Calculated 50-period MA: ", ma);

   if(ma <= 0)
     {
      m_lblResults.Text("Not enough data for moving average calculation.");
      return;
     }

   string result = StringFormat("50-period MA: %.5f", ma);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMetricsBoard::PerformSupportResistanceAnalysis(void)
  {
   double support = iLow(Symbol(), PERIOD_H1, 1);
   double resistance = iHigh(Symbol(), PERIOD_H1, 1);
   Print("Retrieved Support: ", support, ", Resistance: ", resistance);

   if(support == 0 || resistance == 0)
     {
      m_lblResults.Text("Failed to retrieve support/resistance levels.");
      return;
     }

   string result = StringFormat("Support: %.5f, Resistance: %.5f", support, resistance);
   m_lblResults.Text(result);
  }

//+------------------------------------------------------------------+
//| Calculate moving average                                         |
//+------------------------------------------------------------------+
double CMetricsBoard::CalculateMovingAverage(int period)
  {
   if(period <= 0)
      return 0;

   double sum = 0.0;
   int bars = Bars(Symbol(), PERIOD_H1);

   if(bars < period)
     {
      return 0;
     }

   for(int i = 0; i < period; i++)
     {
      sum += iClose(Symbol(), PERIOD_H1, i);
     }
   return sum / period;
  }

// Implementation of OnClickButtonClose
void CMetricsBoard::OnClickButtonClose()
  {
   Print("Close button clicked. Closing the Metrics Board...");
   Destroy();  // This method destroys the panel
  }

CMetricsBoard ExtDialog;

//+------------------------------------------------------------------+
//| Initialize the application                                       |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!ExtDialog.Create(0, "Metrics Board", 0, 10, 10, 350, 500))
     {
      Print("Failed to create Metrics Board.");
      return INIT_FAILED;
     }

   if(!ExtDialog.Run()) // Call Run to make the dialog functional
     {
      Print("Failed to run Metrics Board.");
      return INIT_FAILED; // Call to Run failed
     }

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Deinitialize the application                                     |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ExtDialog.Destroy(reason); // Properly call Destroy method
  }

//+------------------------------------------------------------------+
//| Handle chart events                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   ExtDialog.ChartEvent(id, lparam, dparam, sparam);
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+


Aufschlüsselung und Implementierung des Codes

  • Kopfzeilen und Metadaten
Der erste Teil des Codes sind die Kopfzeilen und der Abschnitt mit den Metadaten. Dieser Abschnitt enthält grundlegende Informationen über das Skript, einschließlich Angaben zum Urheberrecht, Links, Version und strenge Kompilierungsregeln.
//+------------------------------------------------------------------+
//|                                                Metrics Board.mql5|
//|                                Copyright 2025, Christian Benjamin|
//|                                              https://www.mql5.com|
//+------------------------------------------------------------------+
#property copyright "2025, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict
Der Kommentarblock beschreibt den Zweck des Skripts und nennt die Verdienste, was für die Identifizierung der Urheberschaft und die Sicherstellung der korrekten Zuordnung für zukünftige Nutzer unerlässlich ist. Die #property-Direktiven dienen dazu, verschiedene Eigenschaften des Skripts zu definieren, wie z. B. Copyright-Informationen, einen Link zum Autor oder zur Dokumentation, die Versionsnummer und die Einstellung des Strict-Modus, der dabei hilft, mögliche Probleme während der Kompilierung zu erkennen.
  • Einschließlich notwendiger Bibliotheken

Als Nächstes fügen wir die für unsere Anwendung erforderlichen Bibliotheken ein. Diese Bibliotheken bieten vordefinierte Funktionen, die die Codierung vereinfachen.

#include <Trade\Trade.mqh>
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Label.mqh>
#include <Controls\Panel.mqh>

Hier werden die Bibliotheken für die Handelsoperationen und die Bedienelemente der Nutzeroberfläche integriert. Beispielsweise ist Trade.mqh für die Ausführung von Handelsfunktionen unerlässlich, während Dialog.mqh, Button.mqh, Label.mqh und Panel.mqh zur Erstellung und Verwaltung der Nutzeroberflächenkomponenten des Metrics Board verwendet werden.

  • Definition der Klasse
Im Anschluss an die Einbindung der Bibliothek definieren wir die primäre Klasse für das Metrics Board.  Die Klasse CMetricsBoard wird von CAppDialog abgeleitet, sodass wir die Dialogfunktionalitäten nutzen können. Wir deklarieren mehrere private Mitgliedsvariablen, hauptsächlich Schaltflächen und Felder, die zur Interaktion mit der Anwendung verwendet werden. Jede Schaltfläche entspricht einer Analysefunktion, und die Ergebnisse werden in einem Panel mit der Bezeichnung m_panelResults angezeigt.

class CMetricsBoard : public CAppDialog
{
private:
   CButton           m_btnClose; 
   CButton           m_btnHighLowAnalysis;
   CButton           m_btnVolumeAnalysis;
   CButton           m_btnTrendAnalysis;
   CButton           m_btnVolatilityAnalysis;
   CButton           m_btnMovingAverage;
   CButton           m_btnSupportResistance;
   CPanel            m_panelResults;
   CLabel            m_lblResults;

Die Klasse enthält auch einen Konstruktor und einen Destruktor.

public:
                     CMetricsBoard(void);
                    ~CMetricsBoard(void);

CMetricsBoard::CMetricsBoard(void) {}

CMetricsBoard::~CMetricsBoard(void) {}

Der Konstruktor initialisiert die Klasse, und der Destruktor ist definiert (wenn auch in diesem Fall leer), um sicherzustellen, dass alle notwendigen Aufräumarbeiten stattfinden, wenn eine Instanz von CMetricsBoard zerstört wird. Dies ist eine wesentliche Voraussetzung für eine effiziente Verwaltung der Ressourcen.

  • Erstellen des Dialogs

Die Methode Create ist für den Aufbau des gesamten Kontrolldialogs zuständig. In dieser Methode versuchen wir zunächst, den Dialog über die Basisklasse (CAppDialog::Create) zu erstellen. Schlägt es fehl, wird ein Fehler protokolliert und false zurückgegeben. Als Nächstes erstellen wir eine Ergebnistafel und Schaltflächen und prüfen erneut auf mögliche Fehler. Wenn alle Schritte erfolgreich waren, wird der Dialog angezeigt und true zurückgegeben.

bool CMetricsBoard::Create(const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2)
{
   if(!CAppDialog::Create(chart, name, subwin, x1, y1, x2, y2))
   {
      Print("Failed to create CAppDialog instance.");
      return false; 
   }

   if(!CreateResultsPanel())
   {
      Print("Failed to create results panel.");
      return false; 
   }

   if(!CreateButtons())
   {
      Print("Failed to create buttons.");
      return false; 
   }

   Show(); 
   return true; 
}

Nun wird das Dialogfeld Ausführen (Run) angezeigt. Die Methode Run ist wichtig, damit der Dialog funktioniert.

bool CMetricsBoard::Run()
{
   if(!Show())
   {
      Print("Failed to show the control.");
      return false; 
   }
   return true; 
}

Hier wird der Dialog mit der Methode Show angezeigt. Wenn die Anzeige des Dialogs fehlschlägt, wird eine Fehlermeldung ausgegeben und false zurückgegeben.

  • Erstellen der Ergebnistafel

Mit der Methode CreateResultsPanel wird das Panel erstellt, in dem die Analyseergebnisse angezeigt werden sollen. Zunächst erstellen wir die Ergebnistafel und legen ihre Eigenschaften, wie Farbe und Abmessungen, fest. Anschließend fügen wir dieses Panel dem Dialog hinzu. Wir erstellen auch einen Bereich innerhalb des Panels, um die Ergebnisse anzuzeigen, und passen dessen Aussehen an, bevor wir es dem Panel hinzufügen. Diese Methode gibt bei erfolgreicher Erstellung true zurück.

bool CMetricsBoard::CreateResultsPanel(void)
{
   if(!m_panelResults.Create(0, "ResultsPanel", 0, 10, 10, 330, 60))
      return false;

   m_panelResults.Color(clrLightGray);
   Add(m_panelResults);

   if(!m_lblResults.Create(0, "ResultsLabel", 0, 15, 15, 315, 30))
      return false;

   m_lblResults.Text("Results will be displayed here.");
   m_lblResults.Color(clrBlack);
   m_lblResults.FontSize(12);
   Add(m_lblResults);

   return true;
}

  • Schaltflächen erstellen

Die Methode CreateButtons ist für die Initialisierung der interaktiven Schaltflächen im Dialog zuständig.

bool CMetricsBoard::CreateButtons(void)
{
   int x = 20;
   int y = 80;
   int buttonWidth = 300;
   int buttonHeight = 30;
   int spacing = 15;

   if(!m_btnClose.Create(0, "CloseButton", 0, x, y, x + buttonWidth, y + buttonHeight))
      return false;

   m_btnClose.Text("Close Panel");
   Add(m_btnClose);
   y += buttonHeight + spacing;

   struct ButtonData
   {
      CButton        *button;
      string         name;
      string         text;
   };

   ButtonData buttons[] =
   {
      {&m_btnHighLowAnalysis, "HighLowButton", "High/Low Analysis"},
      {&m_btnVolumeAnalysis, "VolumeButton", "Volume Analysis"},
      {&m_btnTrendAnalysis, "TrendButton", "Trend Analysis"},
      {&m_btnVolatilityAnalysis, "VolatilityButton", "Volatility Analysis"},
      {&m_btnMovingAverage, "MovingAverageButton", "Moving Average"},
      {&m_btnSupportResistance, "SupportResistanceButton", "Support/Resistance"}
   };

   for(int i = 0; i < ArraySize(buttons); i++)
   {
      if(!buttons[i].button.Create(0, buttons[i].name, 0, x, y, x + buttonWidth, y + buttonHeight))
         return false;

      buttons[i].button.Text(buttons[i].text);
      Add(buttons[i].button);
      y += buttonHeight + spacing;
   }

   return true;
}

In dieser Implementierung legen wir die Anfangskoordinaten, Abmessungen und Abstände für unsere Schaltflächen fest. Wir erstellen jede Schaltfläche, zuerst für das Schließen des Panels, und fügen sie dem Dialog hinzu. Anschließend verwenden wir ein Array von ButtonData-Strukturen, mit denen wir die Schaltflächendefinitionen in einer Schleife durchlaufen können. Jede Schaltfläche wird mit einem entsprechenden Text versehen und dem Dialogfeld hinzugefügt. Die Methode schließt mit der Rückgabe von true ab, wenn alle Schaltflächen erfolgreich erstellt wurden.

  • Handhabung von Ereignissen

1. Tastenklicks

Die Methode OnEvent verarbeitet Ereignisse, die durch Nutzerinteraktion erzeugt werden, wie z. B. das Klicken auf eine Schaltfläche.

bool CMetricsBoard::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      Print("Event ID: ", id, ", Event parameter (sparam): ", sparam);

      if(sparam == "CloseButton") 
      {
         OnClickButtonClose(); 
         return true; 
      }
      // ... Handling for other button clicks
   }

   return false; 
}

Wenn ein Ereignis eintritt, wird zunächst geprüft, ob es sich um ein Tastenklick-Ereignis handelt. Wir drucken die Ereignisdetails zu Debugging-Zwecken aus und reagieren auf bestimmte Schaltflächenklicks, indem wir die entsprechenden Bearbeitungsfunktionen aufrufen. Wenn es sich bei der angeklickten Schaltfläche um die Schaltfläche zum Schließen handelt, rufen wir die Methode OnClickButtonClose() auf.

2. Chart-Ereignisse

Die Methode ChartEvent dient einem ähnlichen Zweck, konzentriert sich aber speziell auf chartbezogene Ereignisse.

bool CMetricsBoard::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   Print("ChartEvent ID: ", id, ", lparam: ", lparam, ", dparam: ", dparam, ", sparam: ", sparam);

   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      return OnEvent(id, lparam, dparam, sparam);
   }

   return false;
}

Diese Methode erfasst alle Klicks auf Chartobjekte und übergibt das Ereignis zur weiteren Verarbeitung an die Methode OnEvent.

  • Analyse Operationen

Die folgenden Methoden implementieren die verschiedenen Marktanalysetypen, die unser Metrics Board durchführen kann. Die PerformHighLowAnalysis beispielsweise ruft die Hochs und Tiefs für einen bestimmten Zeitraum ab:

void CMetricsBoard::PerformHighLowAnalysis(void)
{
   double high = iHigh(Symbol(), PERIOD_H1, 0);
   double low = iLow(Symbol(), PERIOD_H1, 0);

   Print("Retrieved High: ", high, ", Low: ", low);

   if(high == 0 || low == 0)
   {
      m_lblResults.Text("Failed to retrieve high/low values.");
      return;
   }

   string result = StringFormat("High: %.5f, Low: %.5f", high, low);
   m_lblResults.Text(result);
}

Bei dieser Methode verwenden wir integrierte Funktionen, um die höchsten und niedrigsten Preise der letzten Stunde zu ermitteln. Bei Erfolg werden die Ergebnisse auf dem Panel angezeigt. Wenn nicht, wird eine Fehlermeldung angezeigt.

Eine ähnliche Logik wird auf andere Analysefunktionen angewandt, wie PerformVolumeAnalysis, PerformTrendAnalysis, PerformVolatilityAnalysis, PerformMovingAverageAnalysis und PerformSupportResistanceAnalysis. Jede Methode ruft die für ihren Analysetyp spezifischen Daten ab und aktualisiert die Nutzeroberfläche entsprechend.

  • Berechnung des gleitenden Durchschnitts

Eine der enthaltenen Hilfsmethoden ist CalculateMovingAverage, mit der der gleitende Durchschnitt über einen bestimmten Zeitraum berechnet wird. Bei dieser Methode werden die Schlusskurse über den angegebenen Zeitraum summiert und durch diese Zahl dividiert, um den Durchschnitt zu ermitteln. Es prüft, ob die Eingabe gültig ist und die Daten ausreichen, bevor die Berechnung durchgeführt wird.

double CMetricsBoard::CalculateMovingAverage(int period)
{
   if(period <= 0)
      return 0;

   double sum = 0.0;
   int bars = Bars(Symbol(), PERIOD_H1);

   if(bars < period)
   {
      return 0;
   }

   for(int i = 0; i < period; i++)
   {
      sum += iClose(Symbol(), PERIOD_H1, i);
   }
   return sum / period;
}
  • Globale Instanz und Initialisierung

Eine Instanz der Klasse CMetricsBoard wird global erstellt, gefolgt von den Initialisierungs- und Deinitialisierungsprozessen für die Anwendung.

CMetricsBoard ExtDialog;

int OnInit()
{
   if(!ExtDialog.Create(0, "Metrics Board", 0, 10, 10, 350, 500))
   {
      Print("Failed to create Metrics Board.");
      return INIT_FAILED;
   }

   if(!ExtDialog.Run())
   {
      Print("Failed to run Metrics Board.");
      return INIT_FAILED;
   }

   return INIT_SUCCEEDED;
}

In der Funktion OnInit wird das Metrics Board durch den Aufruf der Methode Create initialisiert. Wenn dies erfolgreich war, führen wir es aus. Fehler werden entsprechend protokolliert, wobei die Funktion den Erfolg oder Misserfolg anzeigt.

Der Deinitialisierungsprozess stellt sicher, dass die Ressourcen korrekt freigegeben werden, wenn der EA entfernt wird.

void OnDeinit(const int reason)
{
   ExtDialog.Destroy(reason); // Properly call Destroy method
}

  • Chart-Ereignisbehandlung

Schließlich definieren wir die Funktion OnChartEvent, um Ereignisse im Zusammenhang mit dem Chart zu verwalten. Dadurch werden die Nutzerinteraktionen direkt in die Funktionalität der Anwendung integriert.  Diese Methode erfasst Chartereignisse und übergibt sie an die ChartEvent-Methode unserer CMetricsBoard-Instanz.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   ExtDialog.ChartEvent(id, lparam, dparam, sparam);
}


Einbinden der Bibliotheken

Wenn Sie Ihren Code kompilieren, ohne die im vorigen Abschnitt erwähnten Bibliotheken einzubinden, können Fehler auftreten. Um dies zu beheben, öffnen Sie MetaEditor und navigieren Sie zum Navigator-Panel. Blättern Sie nach unten zum Abschnitt „Einbinden“, wo Sie auf die erforderlichen Bibliotheken zugreifen können. Öffnen Sie die erforderlichen Unterordner, wählen Sie die entsprechenden Dateien aus und kompilieren Sie sie einzeln. Stellen Sie sicher, dass die Bibliotheken in Ihrem Code korrekt referenziert werden, indem Sie die Direktive #include am Anfang Ihres Skripts verwenden. Dieser Schritt stellt sicher, dass alle Abhängigkeiten korrekt geladen werden, um mögliche Kompilierungsfehler zu vermeiden. Das folgende GIF zeigt, wie man auf Bibliotheken in MetaEditor zugreift und sie einbindet.

Einbinden von Bibliotheken

Abb. 2. Einbinden von Bibliotheken

In MQL5 ermöglicht eine eingebundene Bibliothek die Integration von externem Code, Funktionen oder Klassen in Ihr Programm, um dessen Funktionalität zu erweitern und die Wiederverwendung von Code aus verschiedenen Quellen zu ermöglichen. Wenn Sie eine Bibliothek einbinden, erhalten Sie Zugriff auf die darin definierten Funktionen, Klassen oder Variablen und können diese in Ihrem Skript, Expert Advisor (EA) oder Indikator verwenden. Die meisten Bibliotheken in MQL5 sind integriert und bieten fertige Lösungen für gängige Aufgaben wie Handelsfunktionen, technische Indikatoren und mehr.


Ergebnisse

Nachdem Sie den EA erfolgreich kompiliert haben, können Sie nun zu MetaTrader 5 gehen und den EA mit einem Chart verbinden. Schauen wir uns die Ergebnisse an, die wir bei den Tests erzielt haben.

ERGEBNISSE

Abb. 3. Ergebnisse

Anhand des obigen Diagramms ist ersichtlich, dass der EA Metrics Board eine optimale Funktionalität bietet und effektiv auf jeden Tastendruck reagiert. Diese Fähigkeit stellt sicher, dass der EA die erforderlichen Zahlen in Echtzeit bereitstellt, was die Interaktion mit dem Nutzer und die Leistung verbessert.

  • EA-Protokollierung

Wir können auch das Expertenprotokoll in MetaTrader 5 einsehen, um die Interaktion zwischen den gedrückten Tasten und den Ereignissen auf dem Chart zu beobachten. Da unser EA über eine integrierte Protokollierungsfunktion verfügt, werden diese Interaktionen erfasst. Werfen wir einen Blick auf die protokollierten Informationen und analysieren wir, was aufgezeichnet wurde. 

EXPERTEN-PROTOKOLLIERUNG

Abb. 4. Experten Logging


Schlussfolgerung

Der Metrics Board EA verfügt über ein dynamisches und nutzerfreundliches Panel-Interface, das direkt in MetaTrader 5 eingebettet ist und die Draw-Object-Funktion beinhaltet. Die nahtlose Integration vermittelt den Eindruck, mit nativen MetaTrader 5-Steuerungen zu arbeiten, und bietet eine Erfahrung, die mit der Verwendung einer integrierten Anwendung vergleichbar ist. Meiner Meinung nach stellt es einen bedeutenden Fortschritt bei den Handelswerkzeugen dar, da es eine Funktionalität und Nutzerfreundlichkeit bietet, die die Möglichkeiten einiger Analyseskripte, die ich zuvor entwickelt habe, übersteigt. Durch die Möglichkeit, sich mit einem einzigen Mausklick auf bestimmte Informationen zu konzentrieren, wird sichergestellt, dass nur die erforderlichen Daten angezeigt werden, was den Analyseprozess vereinfacht. Während diese früheren Skripte ihren Zweck effektiv erfüllten, hebt das Metrics Board EA die Marktanalyse auf ein höheres Niveau der Effizienz und Zugänglichkeit.

Zu den wichtigsten Merkmalen des Metrics Board EA gehören:

Merkmal Vorteil
Hoch/Tief-Analyse Identifiziert schnell wichtige Marktniveaus, um Händlern zu helfen.
Volumenverfolgung Bietet aktuelle Informationen über das Handelsvolumen für einen besseren Marktkontext.
Identifizierung von Trends Vereinfacht das Erkennen von aktuellen Markttrends.
Unterstützungs-/Widerstandsniveaus Zeigt genau die entscheidenden Preiszonen für den strategischen Handel an.

Dieses Tool ermöglicht es Händlern, die Märkte effektiv zu analysieren und bessere Entscheidungen zu treffen. Sein unkompliziertes Design vereinfacht komplexe Analysen, sodass sich die Nutzer auf die Verfeinerung ihrer Strategien konzentrieren können. Mit Blick auf die Zukunft besteht die Möglichkeit, den Funktionsumfang zu erweitern, indem neue Funktionen hinzugefügt und die Schnittstelle weiter verbessert werden.

Datum Name des Werkzeugs  Beschreibung Version  Aktualisierungen  Hinweis
01/10/24 Chart Projector Skript zur Überlagerung der Kursentwicklung des Vortages mit Geistereffekt. 1.0 Erste Veröffentlichung Erstes Werkzeug in Lynnchris Tool Chest
18/11/24 Analytischer Kommentar Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. 1.0 Erste Veröffentlichung Zweites Werkzeug in Lynnchris Tool Chest
27/11/24 Analytics Master Regelmäßige Aktualisierung der Marktmetriken alle zwei Stunden  1.01 Zweite Veröffentlichung Drittes Werkzeug in Lynnchris Tool Chest
02/12/24 Analytics Forecaster  Regelmäßige Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration 1.1 Dritte Auflage Werkzeug Nummer 4
09/12/24 Volatilitäts-Navigator Der EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR 1.0 Erste Veröffentlichung Werkzeug Nummer 5
19/12/24 Umkehr zur Mitte, Signal Reaper  Analysiert den Markt anhand der Strategie der Umkehr zur Mitte und liefert Signale  1.0  Erste Veröffentlichung  Werkzeug Nummer 6 
9/01/2025  Signal-Impulse  Analysator für mehrere Zeitrahmen 1.0  Erste Veröffentlichung  Werkzeug Nummer 7 
17/01/2025  Metrics Board  Bedienfeld mit Taste für die Analyse  1.0  Erste Veröffentlichung Werkzeug Nummer 8 

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

Beigefügte Dateien |
Metrics_Board.mq5 (15.92 KB)
MQL5 Handels-Toolkit (Teil 7): Erweitern der History Management EX5-Bibliothek um die Funktionen für den zuletzt stornierten, schwebenden Auftrag MQL5 Handels-Toolkit (Teil 7): Erweitern der History Management EX5-Bibliothek um die Funktionen für den zuletzt stornierten, schwebenden Auftrag
Erfahren Sie, wie Sie das letzte Modul in der Bibliothek des History Manager EX5 erstellen, wobei Sie sich auf die Funktionen konzentrieren, die für die Bearbeitung des zuletzt stornierten, schwebenden Auftrags verantwortlich sind. Damit haben Sie die Möglichkeit, wichtige Details zu stornierten offenen Aufträgen mit MQL5 effizient abzurufen und zu speichern.
Entwicklung eines Expert Advisors in MQL5 für Ausbrüche nach kalenderbasierten Nachrichtenereignissen Entwicklung eines Expert Advisors in MQL5 für Ausbrüche nach kalenderbasierten Nachrichtenereignissen
Die Volatilität erreicht ihren Höhepunkt in der Regel in der Nähe von Ereignissen mit hohem Nachrichtenwert, wodurch sich erhebliche Ausbruchschancen ergeben. In diesem Artikel werden wir den Umsetzungsprozess einer kalenderbasierten Ausbruch-Strategie skizzieren. Wir werden alles von der Erstellung einer Klasse zur Interpretation und Speicherung von Kalenderdaten über die Entwicklung realistischer Backtests mit diesen Daten bis hin zur Implementierung von Ausführungscode für den Live-Handel behandeln.
Meistern der Log-Einträge (Teil 3): Erkunden von Handles zum Speichern von Protokollen Meistern der Log-Einträge (Teil 3): Erkunden von Handles zum Speichern von Protokollen
In diesem Artikel werden wir das Konzept der Handler in der Logging-Bibliothek erkunden, verstehen, wie sie funktionieren, und drei erste Implementierungen erstellen: Konsole, Datenbank und Datei. Wir werden alles von der grundlegenden Struktur der Handler bis hin zu praktischen Tests behandeln, um den Boden für ihre volle Funktionalität in zukünftigen Artikeln zu bereiten.
Die Handelsstrategie Inverse Fair Value Gap Die Handelsstrategie Inverse Fair Value Gap
Eine Inverse Fair Value Gap (IFVG) liegt vor, wenn der Kurs in eine zuvor ermittelte „Fair Value Gap“ abprallt und statt der erwarteten unterstützenden oder Widerstandsreaktion diese nicht einhält. Dieses Scheitern kann eine potenzielle Veränderung der Marktrichtung signalisieren und einen konträren Handelsvorteil bieten. In diesem Artikel werde ich meinen selbst entwickelten Ansatz zur Quantifizierung und Nutzung der inversen Fair Value Gap als Strategie für MetaTrader 5 Expert Advisors vorstellen.