English 日本語
preview
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (V): Die Klasse AnalyticsPanel

Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (V): Die Klasse AnalyticsPanel

MetaTrader 5Beispiele |
47 1
Clemence Benjamin
Clemence Benjamin

Inhalt


Einführung

In früheren Abschnitten habe ich das Konzept eines Analyse-Panels vorgestellt, das zu diesem Zeitpunkt hauptsächlich aus statischen Oberflächenelementen bestand, wie z. B. einem Tortendiagramm, das das Gewinn/Verlust-Verhältnis anzeigt. Diesen Komponenten fehlte es jedoch an Echtzeit-Datenaktualisierungen, was ihre Nützlichkeit in dynamischen Handelsumgebungen einschränkte. In dieser Diskussion machen wir einen bedeutenden Schritt nach vorn, indem wir sowohl das Design als auch die Funktionalität der Schnittstelle verbessern, wobei wir uns auf die Abfrage und Anzeige von Echtzeit-Handelsdaten konzentrieren.

Unser Entwicklungsansatz nutzt die MQL5-Standardbibliothek, insbesondere die Klassen, die sich im Verzeichnis \Include\Controls\ befinden. Wir werden bestehende Klassen wie CLabel, CEdit und CDialog erweitern und anpassen, um reaktionsfähige, datengesteuerte UI-Komponenten zu erstellen. Diese bilden das Rückgrat unseres sich weiterentwickelnden Trading Administrator Panels, das als modulares Multi-Interface-Tool konzipiert ist und ein umfassendes Konto- und Strategiemanagement sowie eine Kommunikationsschnittstelle über Telegram für Fernsteuerung und Echtzeit-Benachrichtigungen bietet.

Während das Hauptziel die Entwicklung dieses fortgeschrittenen Panels bleibt, können die hier gezeigten Techniken - insbesondere diejenigen, die Echtzeit-Datenerfassung und dynamische UI-Updates beinhalten - auf verschiedene MQL5-Projekte jenseits administrativer Schnittstellen angewendet werden, einschließlich Expert Advisors, nutzerdefinierter Indikatoren und interaktiver Lernwerkzeuge.


Überblick über die AnalyticsPanel-Klasse

Als Teil eines modularen Entwicklungsansatzes, der für umfangreiche MQL5-Programme geeignet ist - und um die Wiederverwendbarkeit und Wartbarkeit des Codes zu fördern - erstellen wir eine spezielle Datei für den Header der Klasse von AnalyticsPanel. Diese Klasse wurde entwickelt, um sowohl das visuelle Layout des Analyse-Panels als auch den Echtzeitabruf und die Anzeige von Marktdaten zu kapseln.

Zusätzlich zu den Standard-Kontometriken zeigt das Panel verschiedene technische Indikatorwerte an, die in eine nutzerdefinierte Strategie einfließen, die ich Confluence Strategy genannt habe. Diese Strategie basiert auf dem Prinzip des Zusammenflusses, bei dem die Signale mehrerer Indikatoren verglichen werden, um ein einheitliches Handelssignal zu erzeugen. Wenn keine Übereinstimmung zwischen den Indikatoren gefunden wird, zeigt das Panel einfach die Meldung „No Consensus“ (Kein Konsens) an, wodurch falsche oder schwache Signale vermieden werden.

Die Klasse AnalyticsPanel enthält Methoden zum Initialisieren und Aktualisieren des Panel-Layouts, zum Aktualisieren von Label-Werten in Echtzeit und zum Verwalten von visuellem Signal-Feedback auf der Grundlage der Logik der Strategie. Unten habe ich ein visuelles Design-Layout des Panels eingefügt, und in der folgenden Diskussion werden wir die Implementierungsdetails durchgehen, die es zum Leben erweckt haben.

Design des AnalyticsPanel

Merkmale des AnalyticsPanel

Nachdem wir unsere Klasse entwickelt haben, werden wir sie in das Hauptprogramm des Expert Advisors, das New_Admin_Panel, integrieren, um sie weiterzuentwickeln. Diese Integration unterstreicht die modulare Architektur unseres Systems und verdeutlicht die Vorteile des Aufbaus wiederverwendbarer und unabhängiger Komponenten, die innerhalb eines größeren Anwendungsrahmens nahtlos zusammenwirken können. Das folgende Bild zeigt die endgültige Leistung unseres Produkts, bei dem Handelssignale nur dann generiert werden, wenn alle Indikatorwerte einen starken Konsens für eine Kauf- oder Verkaufsentscheidung bilden

AnalyticsPanel Live

AnalyticsPanel Live

Durch die Integration des AnalyticsPanels in das New_Admin_Panel ergeben sich mehrere praktische Vorteile

  • Zentralisierte Überwachung: Echtzeit-Analysen wie Gewinn-/Verlustquoten, Kapitalveränderungen und Handelszusammenfassungen können jetzt über die primäre Schnittstelle abgerufen werden, ohne dass separate Tools erforderlich sind.
  • Verbessertes Nutzererlebnis: Die Kombination von Analysen mit Kernfunktionen wie Strategieumsetzung und Telegram-Nachrichten bietet einen einheitlichen und intuitiven Arbeitsablauf für den Nutzer.
  • Skalierbarkeit und Wartung des Codes: Die Trennung von Schnittstellenkomponenten in Klassen wie AnalyticsPanel verbessert die Lesbarkeit des Codes, erleichtert das Testen und unterstützt zukünftige Upgrades mit minimalen Unterbrechungen.
  • Projektübergreifende Wiederverwendbarkeit: Durch den modularen Aufbau kann das AnalyticsPanel (und andere Panels) in anderen Expert Advisors oder Trading Utilities wiederverwendet oder angepasst werden.
  • Handelssignal: Die hier vorliegende Version liefert nützliche, zusammenfließende Signale.



Implementierung von MQL5

Bei der Gestaltung unseres Analytics Panels folgen wir objektorientierten Prinzipien, die die wesentlichen Komponenten in verschiedene Zugriffsebenen aufteilen, um die Übersichtlichkeit, Sicherheit und Wartbarkeit zu verbessern. Die Klasse ist so strukturiert, dass bestimmte Funktionen auch für andere Teile des Programms zur Verfügung stehen - dies sind die „öffentlichen“ Elemente, die als Schnittstelle für die Interaktion mit dem Panel dienen. Andere interne Details, die sich mit dem Innenleben und der Datenverwaltung befassen, werden vor externen Komponenten verborgen gehalten; dies sind die „privaten“ Elemente. Diese Methode der Kapselung ermöglicht es uns, einen klaren und organisierten Plan für unser Panel zu präsentieren, der es zukünftigen Entwicklern erleichtert, die Rolle und den Zweck jedes Abschnitts zu verstehen. 

Bevor die Klasse CAnalyticsPanel definiert wird, werden zwei wichtige Header-Dateien eingefügt:

Dialog.mqh – Diese Kopfzeile bietet Zugriff auf dialogbezogene Klassen, einschließlich CAppDialog, die als Basisklasse für die Erstellung des nutzerdefinierten Panels dient.

Label.mqh – Diese Datei enthält die Definition der Klasse CLabel, die zum Erstellen und Verwalten aller im Panel angezeigten Textbeschriftungen verwendet wird.

Diese Einschlüsse sind notwendig, um dem nutzerdefinierten Panel Zugriff auf die Standard-UI-Steuerungsstrukturen von MQL5 zu geben. Ohne sie wäre die Klasse des Panels nicht in der Lage, von CAppDialog zu erben oder Label-Steuerelemente zu erstellen.

Wir müssen auch Makros für Abstände und Layout (AP_GAP, AP_DEFAULT_LABEL_HEIGHT) definieren, um die visuelle Struktur sowohl reaktionsschnell als auch sauber zu halten.
#include <Controls\Dialog.mqh>
#include <Controls\Label.mqh>

// Use unique macro names for layout in this class:
#define AP_DEFAULT_LABEL_HEIGHT 20
#define AP_GAP                10

Die folgende Übersicht gliedert die Hauptkomponenten unseres Unterrichts in fünf Schlüsselbereiche:

1. Struktur und Zweck der Klasse

Die Klasse CAnalyticsPanel dient als hochgradig visuelles und informatives Dashboard, das für Echtzeit-Updates zu Handels- und Marktbedingungen direkt in einem MetaTrader 5-Chart entwickelt wurde. Abgeleitet von der Klasse CAppDialog in der MQL5-Standardbibliothek, nutzt es die objektorientierte Programmierung, um strukturierte Daten in übersichtlich angeordneten Abschnitten anzuzeigen. Das Panel enthält Beschriftungen für Kontodetails, offene Trades, Marktkurse, Indikatoren und eine zusammengefasste Signalübersicht, sodass Händler alles in einem kompakten Fenster überwachen können. 

//+------------------------------------------------------------------+
//| Analytics Panel Class                                            |
//+------------------------------------------------------------------+
class CAnalyticsPanel : public CAppDialog
{
protected:
   // Helper: Create a text label.
   // The label's text color is set as provided and its background is forced to black.
   bool CreateLabelEx(CLabel &label, int x, int y, int width, int height, string label_name, string text, color clr)
   {
      // Construct a unique control name by combining the dialog name and label_name.
      string unique_name = m_name + "_" + label_name;
      if(!label.Create(m_chart_id, unique_name, m_subwin, x, y, x+width, y+height))
      {
         Print("Failed to create label: ", unique_name, " Err=", GetLastError());
         return false;
      }
      if(!Add(label))
      {
         Print("Failed to add label: ", unique_name, " Err=", GetLastError());
         return false;
      }
      if(!label.Text(text))
      {
         Print("Failed to set text for label: ", unique_name);
         return false;
      }
      label.Color(clr);          // Set text color
      label.Color(clrBlack);   // Force background to black
      return true;
   }

   // Account and Trade Data Labels:
   CLabel m_lblBalance;
   CLabel m_lblEquity;
   CLabel m_lblMargin;
   CLabel m_lblOpenTrades;
   // PnL is split into two labels:
   CLabel m_lblPnLName;
   CLabel m_lblPnLValue;

   // Market Data Labels (split Bid/Ask):
   CLabel m_lblBidName;
   CLabel m_lblBidValue;
   CLabel m_lblAskName;
   CLabel m_lblAskValue;
   CLabel m_lblSpread;

   // Indicator Section Separator:
   CLabel m_lblIndicatorSeparator;
   // New header for indicator section:
   CLabel m_lblIndicatorHeader;

   // Indicator Labels (static name and dynamic value labels):
   CLabel m_lblRSIName;
   CLabel m_lblRSIValue;
   CLabel m_lblStochName;
   CLabel m_lblStochK;  // %K value
   CLabel m_lblStochD;  // %D value
   CLabel m_lblCCIName;
   CLabel m_lblCCIValue;
   CLabel m_lblWilliamsName;
   CLabel m_lblWilliamsValue;

   // New Summary Labels (for consensus across indicators):
   CLabel m_lblSignalHeader;    // Header label for summary column ("SIGNAL")
   CLabel m_lblExpectation;     // Text summary (e.g., "Buy" or "Sell")
   CLabel m_lblConfirmation;    // Confirmation symbol (e.g., up or down arrow)

   // Previous values for dynamic color changes (market data):
   double m_prevBid;
   double m_prevAsk;

public:
   CAnalyticsPanel();
   virtual ~CAnalyticsPanel();

   // Create the panel and initialize UI controls.
   virtual bool CreatePanel(const long chart, const string name, const int subwin,
                            int x1, int y1, int x2, int y2);

   // Update the panel with the latest account, trade, market and indicator data.
   void UpdatePanel();
   void Toggle();

private:
   void CreateControls();
   void UpdateAccountInfo();
   void UpdateTradeStats();
   void UpdateMarketData();
   void UpdateIndicators();
};

Nachstehend finden Sie eine ausführliche Darstellung und Erklärung der Variablen.

Mitglied-Variablen

UI Labels für Konto- und Handelsdaten:

Konto-Kennzeichnungen:

  • m_lblBalance, m_lblEquity und m_lblMargin zeigen den Kontostand, das Kapital bzw. die Marge an.
Handelsstatistik:
  • m_lblOpenTrades zeigt die Anzahl der aktuell offenen Handelsgeschäfte an.
Die Gewinn- und Verlustinformationen sind in zwei Kennzeichnungen aufgeteilt:
  1. m_lblPnLName: Ein statisches Kennzeichen, das lediglich den Text „PnL:“ anzeigt (dieser bleibt schwarz).
  2. m_lblPnLValue: Ein dynamisches Kennzeichen, das den numerischen PnL-Wert anzeigt und die Farbe ändert (grün für Gewinn, rot für Verlust).

Marktdaten-Kennzeichnungen:

Diese Etiketten zeigen Bid-/Ask-Werte und Informationen zum Spread an:

  • m_lblBidName und m_lblBidValue für den Geldkurs.
  • m_lblAskName und m_lblAskValue für den Briefkurs.
  • m_lblSpread zeigt den aktuellen Spread in Pips an.
  • Die Farben der Geld- und Briefkurs werden dynamisch aktualisiert, um Marktveränderungen widerzuspiegeln (z. B. blau, wenn der Wert steigt, und rot, wenn er fällt).

Abschnitt „Indikator“:

  • Ein Trennzeichen (m_lblIndicatorSeparator) unterscheidet den Indikatorbereich visuell vom Rest des Panels.
  • Der Kopf (m_lblIndicatorHeader) zeigt „INDICATORS“ an und identifiziert den Abschnitt eindeutig.

Der Abschnitt enthält mehrere Indikatoren:

  • RSI: Zwei Beschriftungen, m_lblRSIName und m_lblRSIValue, zeigen den Namen („RSI:“) und seinen aktuellen Wert an.
  • Stochastischer Oszillator: Dieser Indikator ist in zwei Teile unterteilt:
          1. m_lblStochName: Der statische Teil („Stoch:“).
          2. m_lblStochK und m_lblStochD: Anzeige der dynamischen Werte für %K und %D.
  • CCI: m_lblCCIName und m_lblCCIValue zeigen den Commodity Channel Index.
  • Williams %R: m_lblWilliamsName und m_lblWilliamsValue zeigen die Williams %R-Werte an.

Zusammenfassung (Konsens) Abschnitt:

  • Eine Kopfzeile (m_lblSignalHeader) zeigt das Wort „SIGNAL“ oberhalb der Summenspalte an.
  • Zwei Labels, m_lblExpectation und m_lblConfirmation, werden verwendet, um das Konsenssignal aller Indikatoren anzuzeigen:
    1. m_lblExpectation liefert eine Textzusammenfassung wie „Kaufen“, „Verkaufen“ oder „Kein Konsens“.
    2. m_lblConfirmation zeigt eine symbolische Bestätigung an (ein Pfeil nach oben „↑“ für Kaufen, ein Pfeil nach unten „↓“ für Verkaufen oder ein Bindestrich „-“, wenn kein Konsens erzielt wird).

Interner Status für Marktdaten:

Zwei Variablen, m_prevBid und m_prevAsk, speichern die vorherigen Geld- und Briefkurse, um festzustellen, ob diese Werte steigen oder sinken - daher die Farbkodierung für diese Kennzeichnungen.

2. Hilfsmethode für die Erstellen der Kennzeichnungen

Eine zentrale Utility-Funktion innerhalb der Klasse ist CreateLabelEx, eine wiederverwendbare Methode zum Erstellen und Anpassen von Textbeschriftungen im Panel. Diese Methode kapselt alle Schritte, die erforderlich sind, um ein Kennzeichen zu instanziieren, ihm einen eindeutigen Namen zuzuweisen, seine Größe und Position zu konfigurieren, den gewünschten Text und die gewünschten Farben anzuwenden und es der Kontrollliste des Panels hinzuzufügen.  Wenn ein Schritt in diesem Prozess fehlschlägt, werden entsprechende Fehlermeldungen zur Fehlersuche protokolliert.

bool CAnalyticsPanel::CreateLabelEx(CLabel &label, int x, int y, int width, int height,
                                    string label_name, string text, color clr)
{
   string unique_name = m_name + "_" + label_name;
   if(!label.Create(m_chart_id, unique_name, m_subwin, x, y, x+width, y+height))
   {
      Print("Failed to create label: ", unique_name, " Err=", GetLastError());
      return false;
   }
   if(!Add(label))
   {
      Print("Failed to add label: ", unique_name, " Err=", GetLastError());
      return false;
   }
   if(!label.Text(text))
   {
      Print("Failed to set text for label: ", unique_name);
      return false;
   }
   label.Color(clr);          // Set text color
   label.BackColor(clrBlack); // Force background to black
   return true;
}
    

3. Organisieren des Layouts der Nutzeroberfläche

Die Methode CreateControls organisiert alle Elemente der Nutzeroberfläche auf dem Panel. Hier sind verschiedene Abschnitte angeordnet: Kontoinformationen (Saldo, Kapital, Marge), Handelsstatistiken (offene Handelsgeschäfte sowie Gewinn und Verlust), Marktdaten (Geld- und Briefkurs sowie Spread) und der Indikatorbereich. Im Abschnitt über die Indikatoren erstellen wir Überschriften wie „INDICATORS“ und „SIGNAL“, um die Informationsgruppen eindeutig zu kennzeichnen. Der Code verwendet vordefinierte Konstanten für die Höhe und die Abstände der Etiketten, um sicherzustellen, dass alle Elemente gleichmäßig angeordnet und optisch geordnet sind.

//+------------------------------------------------------------------+
//| CreateControls: Instantiate and add UI controls                  |
//+------------------------------------------------------------------+
void CAnalyticsPanel::CreateControls()
{
   int curX = AP_GAP;
   int curY = AP_GAP;
   int labelWidth = 150;

   // Account Information Labels:
   CreateLabelEx(m_lblBalance, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Balance", "Balance: $0.00", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   CreateLabelEx(m_lblEquity, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Equity", "Equity: $0.00", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   CreateLabelEx(m_lblMargin, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Margin", "Margin: 0", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Trade Statistics Labels:
   CreateLabelEx(m_lblOpenTrades, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "OpenTrades", "Open Trades: 0", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   // PnL labels:
   CreateLabelEx(m_lblPnLName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "PnLName", "PnL:", clrBlack);
   CreateLabelEx(m_lblPnLValue, curX+50, curY, labelWidth-50, AP_DEFAULT_LABEL_HEIGHT, "PnLValue", "$0.00", clrLime);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Market Data Labels:
   CreateLabelEx(m_lblBidName, curX, curY, 40, AP_DEFAULT_LABEL_HEIGHT, "BidName", "Bid:", clrDodgerBlue);
   CreateLabelEx(m_lblBidValue, curX+40, curY, 100, AP_DEFAULT_LABEL_HEIGHT, "BidValue", "0.00000", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   CreateLabelEx(m_lblAskName, curX, curY, 40, AP_DEFAULT_LABEL_HEIGHT, "AskName", "Ask:", clrDodgerBlue);
   CreateLabelEx(m_lblAskValue, curX+40, curY, 100, AP_DEFAULT_LABEL_HEIGHT, "AskValue", "0.00000", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   CreateLabelEx(m_lblSpread, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Spread", "Spread: 0.0 pips", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Indicator Section Separator:
   CreateLabelEx(m_lblIndicatorSeparator, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "Separator", "------------------------------------------", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Indicator Section Header:
   CreateLabelEx(m_lblIndicatorHeader, curX, curY, labelWidth, AP_DEFAULT_LABEL_HEIGHT, "IndicatorHeader", "INDICATORS", clrDodgerBlue);
   // Summary Column Header for Signal:
   CreateLabelEx(m_lblSignalHeader, curX+250, curY , 100, AP_DEFAULT_LABEL_HEIGHT, "SignalHeader", "SIGNAL", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Indicator Labels:
   // RSI:
   CreateLabelEx(m_lblRSIName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "RSIName", "RSI:", clrDodgerBlue);
   CreateLabelEx(m_lblRSIValue, curX+50, curY, 90, AP_DEFAULT_LABEL_HEIGHT, "RSIValue", "N/A", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   // Stochastic:
   CreateLabelEx(m_lblStochName, curX, curY, 60, AP_DEFAULT_LABEL_HEIGHT, "StochName", "Stoch:", clrDodgerBlue);
   CreateLabelEx(m_lblStochK, curX+60, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "StochK", "K: N/A", clrDodgerBlue);
   CreateLabelEx(m_lblStochD, curX+150, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "StochD", "D: N/A", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   // CCI:
   CreateLabelEx(m_lblCCIName, curX, curY, 50, AP_DEFAULT_LABEL_HEIGHT, "CCIName", "CCI:", clrDodgerBlue);
   CreateLabelEx(m_lblCCIValue, curX+50, curY, 90, AP_DEFAULT_LABEL_HEIGHT, "CCIValue", "N/A", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;
   // Williams %R:
   CreateLabelEx(m_lblWilliamsName, curX, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "WilliamsName", "Williams:", clrDodgerBlue);
   CreateLabelEx(m_lblWilliamsValue, curX+70, curY, 70, AP_DEFAULT_LABEL_HEIGHT, "WilliamsValue", "N/A", clrDodgerBlue);
   curY += AP_DEFAULT_LABEL_HEIGHT + AP_GAP;

   // Summary Column: Expectation text and Confirmation symbol.
   CreateLabelEx(m_lblExpectation, curX+250, curY - (AP_DEFAULT_LABEL_HEIGHT+AP_GAP)*4, 100, AP_DEFAULT_LABEL_HEIGHT, "Expectation", "Expect: N/A", clrDodgerBlue);
   CreateLabelEx(m_lblConfirmation, curX+300, curY - (AP_DEFAULT_LABEL_HEIGHT+AP_GAP)*4, 50, AP_DEFAULT_LABEL_HEIGHT, "Confirmation", "N/A", clrDodgerBlue);

   ChartRedraw(m_chart_id);
}

4. Datenaktualisierungen in Echtzeit für Konto- und Marktinformationen

Mithilfe der in MQL5 integrierten Funktionen ruft das Panel Kontoinformationen - wie Saldo, Kapital und Rohmargenwert - sowie Marktdaten wie Geld- und Briefkurse und die Spanne ab. Die Methoden UpdateAccountInfo und UpdateTradeStats fragen das Konto direkt mit Funktionen wie AccountInfoDouble() ab. In der Zwischenzeit ruft UpdateMarketData mithilfe von SymbolInfoTick() Tick-Daten in Echtzeit ab, vergleicht die aktuellen Werte mit den vorherigen und aktualisiert die Farbkodierung für Geld- und Briefkurse auf der Grundlage der Änderungen. Dies ermöglicht es Händlern, den neuesten Konto- und Marktstatus zu sehen, sobald sie auftreten.

//+------------------------------------------------------------------+
//| UpdateAccountInfo: Refresh account-related data                  |
//+------------------------------------------------------------------+
void CAnalyticsPanel::UpdateAccountInfo()
{
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double equity  = AccountInfoDouble(ACCOUNT_EQUITY);
   double margin  = AccountInfoDouble(ACCOUNT_MARGIN);

   m_lblBalance.Text("Balance: $" + DoubleToString(balance, 2));
   m_lblEquity.Text("Equity: $" + DoubleToString(equity, 2));
   // Directly display the raw margin value.
   m_lblMargin.Text("Margin: " + DoubleToString(margin, 2));
}

//+------------------------------------------------------------------+
//| UpdateTradeStats: Refresh trade statistics                       |
//+------------------------------------------------------------------+
void CAnalyticsPanel::UpdateTradeStats()
{
   int total = PositionsTotal();
   double pnl = 0;
   for(int i = 0; i < total; i++)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket != 0)
         pnl += PositionGetDouble(POSITION_PROFIT);
   }
   // Update PnL labels:
   m_lblPnLName.Text("PnL:");  // static remains black
   m_lblPnLValue.Text("$" + DoubleToString(pnl, 2));
   if(pnl < 0)
      m_lblPnLValue.Color(clrRed);
   else
      m_lblPnLValue.Color(clrLime);

   m_lblOpenTrades.Text("Open Trades: " + IntegerToString(total));
}

//+------------------------------------------------------------------+
//| UpdateMarketData: Refresh market data display                    |
//+------------------------------------------------------------------+
void CAnalyticsPanel::UpdateMarketData()
{
   MqlTick last_tick;
   if(SymbolInfoTick(Symbol(), last_tick))
   {
      // Update Bid value and color based on change:
      color bidColor = clrBlue;
      if(m_prevBid != 0)
         bidColor = (last_tick.bid >= m_prevBid) ? clrBlue : clrRed;
      m_lblBidValue.Color(bidColor);
      m_lblBidValue.Text(DoubleToString(last_tick.bid, 5));

      // Update Ask value and color based on change:
      color askColor = clrBlue;
      if(m_prevAsk != 0)
         askColor = (last_tick.ask >= m_prevAsk) ? clrBlue : clrRed;
      m_lblAskValue.Color(askColor);
      m_lblAskValue.Text(DoubleToString(last_tick.ask, 5));

      m_prevBid = last_tick.bid;
      m_prevAsk = last_tick.ask;

      // Update Spread:
      double spread_pips = (last_tick.ask - last_tick.bid) * 1e4;
      m_lblSpread.Text("Spread: " + DoubleToString(spread_pips, 1) + " pips");
   }
}

5. Berechnung von technischen Indikatoren und Generierung eines Konsenssignals

Die Methode UpdateIndicators ruft Werte für mehrere technische Indikatoren - RSI, Stochastic, CCI und Williams %R - ab, indem sie Indikatorfunktionen aufruft und deren neueste Daten liest. Der Wert eines jeden Indikators wird mit vordefinierten Schwellenwerten verglichen, um festzustellen, ob er eine Kauf- oder Verkaufsbedingung anzeigt. So wird beispielsweise ein RSI unter 30 als Kaufsignal interpretiert, während ein Wert über 70 auf Verkäufe hindeutet. Wenn alle Indikatoren übereinstimmen, wird in der Zusammenfassung ein klares Kauf- oder Verkaufssignal mit einem Pfeilsymbol angezeigt. Dies gibt Händlern einen schnellen visuellen Hinweis auf die Marktbedingungen.

//+------------------------------------------------------------------+
//| UpdateIndicators: Calculate and display various indicators       |
//+------------------------------------------------------------------+
void CAnalyticsPanel::UpdateIndicators()
{
   // Local suggestion variables (1 = Buy, -1 = Sell, 0 = Neutral)
   int suggestionRSI = 0, suggestionStoch = 0, suggestionCCI = 0, suggestionWilliams = 0;

   // --- RSI ---
   int handleRSI = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
   double rsi[1];
   color rsiValueColor = clrGreen; // default
   if(CopyBuffer(handleRSI, 0, 0, 1, rsi) > 0)
   {
      if(rsi[0] < 30)
      {
         rsiValueColor = clrBlue; // buy condition
         suggestionRSI = 1;
      }
      else if(rsi[0] > 70)
      {
         rsiValueColor = clrRed;  // sell condition
         suggestionRSI = -1;
      }
      m_lblRSIValue.Color(rsiValueColor);
      m_lblRSIValue.Text(DoubleToString(rsi[0], 2));
   }
   IndicatorRelease(handleRSI);

   // --- Stochastic ---
   int handleStoch = iStochastic(Symbol(), PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
   double stochK[1], stochD[1];
   if(CopyBuffer(handleStoch, 0, 0, 1, stochK) > 0 && CopyBuffer(handleStoch, 1, 0, 1, stochD) > 0)
   {
      // Initialize color variables.
      color colorK = clrGreen;
      color colorD = clrGreen;
      if(stochK[0] > stochD[0])
      {
         colorK = clrBlue;
         colorD = clrRed;
         suggestionStoch = 1;
      }
      else if(stochK[0] < stochD[0])
      {
         colorK = clrRed;
         colorD = clrBlue;
         suggestionStoch = -1;
      }
      else
         suggestionStoch = 0;

      m_lblStochK.Color(colorK);
      m_lblStochD.Color(colorD);
      m_lblStochK.Text("K: " + DoubleToString(stochK[0], 4));
      m_lblStochD.Text("D: " + DoubleToString(stochD[0], 4));
   }
   IndicatorRelease(handleStoch);

   // --- CCI ---
   int handleCCI = iCCI(Symbol(), PERIOD_CURRENT, 14, PRICE_TYPICAL);
   double cci[1];
   color cciValueColor = clrGreen;
   if(CopyBuffer(handleCCI, 0, 0, 1, cci) > 0)
   {
      if(cci[0] < -100)
      {
         cciValueColor = clrBlue; // buy condition
         suggestionCCI = 1;
      }
      else if(cci[0] > 100)
      {
         cciValueColor = clrRed;  // sell condition
         suggestionCCI = -1;
      }
      m_lblCCIValue.Color(cciValueColor);
      m_lblCCIValue.Text(DoubleToString(cci[0], 2));
   }
   IndicatorRelease(handleCCI);

   // --- Williams %R ---
   int handleWPR = iWPR(Symbol(), PERIOD_CURRENT, 14);
   double williams[1];
   color williamsValueColor = clrGreen;
   if(CopyBuffer(handleWPR, 0, 0, 1, williams) > 0)
   {
      if(williams[0] > -80)
      {
         williamsValueColor = clrBlue; // buy condition
         suggestionWilliams = 1;
      }
      else if(williams[0] < -20)
      {
         williamsValueColor = clrRed;  // sell condition
         suggestionWilliams = -1;
      }
      m_lblWilliamsValue.Color(williamsValueColor);
      m_lblWilliamsValue.Text(DoubleToString(williams[0], 2));
   }
   IndicatorRelease(handleWPR);

   // --- Consensus Summary ---
   int consensus = 0;
   if(suggestionRSI != 0 && suggestionRSI == suggestionStoch &&
      suggestionRSI == suggestionCCI && suggestionRSI == suggestionWilliams)
      consensus = suggestionRSI;

   if(consensus == 1)
   {
      m_lblExpectation.Text("Buy");
      m_lblExpectation.Color(clrBlue);
      m_lblConfirmation.Text("↑"); // Up arrow for Buy
      m_lblConfirmation.Color(clrBlue);
   }
   else if(consensus == -1)
   {
      m_lblExpectation.Text("Sell");
      m_lblExpectation.Color(clrRed);
      m_lblConfirmation.Text("↓"); // Down arrow for Sell
      m_lblConfirmation.Color(clrRed);
   }
   else
   {
      m_lblExpectation.Text("No Consensus");
      m_lblExpectation.Color(clrOrangeRed);
      m_lblConfirmation.Text("-");
      m_lblConfirmation.Color(clrOrangeRed);
   }
}

Einbindung des CAnalyticsPanel in das „Main Admin Panel“

1. Am Anfang der EA-Datei ist die Header-Datei AnalyticsPanel.mqh enthalten, die den Zugriff auf die Klasse CAnalyticsPanel ermöglicht:

#include <AnalyticsPanel.mqh>

Dadurch wird sichergestellt, dass der Compiler die Klasse und ihre Mitglieder während der Kompilierung erkennt.

2. Einen globalen Zeiger deklarieren

Es wird ein globaler Zeiger vom Typ CAnalyticsPanel deklariert, der zur dynamischen Verwaltung der Instanz des Panels verwendet wird:

CAnalyticsPanel *g_analyticsPanel = NULL;

Mit Hilfe dieses Zeigers lässt sich feststellen, ob das Panel existiert, und er ermöglicht seine dynamische Erstellung und Zerstörung sowie das Umschalten der Sichtbarkeit.

3. Erstellen einer Schaltfläche zum Starten des Panels

Mit der Funktion CreateAdminPanel() wird eine Schaltfläche mit der Bezeichnung „Analytics Panel“ erstellt und dem Hauptverwaltungsbereich hinzugefügt. Diese Schaltfläche dient dem Nutzer als Auslöser für den Start des Panels.

bool CreateAdminPanel()
{
 
   // Analytics Panel Button
   if(!CreateButton(g_analyticsButton, ANALYTICS_BTN_NAME, INDENT_LEFT, y, INDENT_LEFT+btnWidth, y+BUTTON_HEIGHT, "Analytics Panel"))
      return false;
  
return true;

}

4. Behandeln von Tastenklick-Ereignissen

Die Funktion HandleAnalytics() ist für die Verwaltung des Lebenszyklus des Panels zuständig. Es wird geprüft, ob das Panel bereits erstellt wurde. Ist dies nicht der Fall, wird das CAnalyticsPanel instanziiert, seine Methode CreatePanel() mit Positionskoordinaten aufgerufen und seine Sichtbarkeit umgeschaltet. Andernfalls wird das Bedienfeld einfach ein- oder ausgeschaltet.

//------------------------------------------------------------------
// Handle Analytics Panel button click
void HandleAnalytics()
{
   if(g_analyticsPanel == NULL)
   {
      g_analyticsPanel = new CAnalyticsPanel();
      // Coordinates for Analytics panel (adjust as needed)
      if(!g_analyticsPanel.CreatePanel(g_chart_id, "AnalyticsPanel", g_subwin, 900, 20, 900+500, 20+460))
      {
         delete g_analyticsPanel;
         g_analyticsPanel = NULL;
         Print("Failed to create Analytics Panel");
         return;
      }
   }
   g_analyticsPanel.Toggle();
   ChartRedraw();
}

5. Weiterleitung von Ereignissen

In der Funktion AdminPanelOnEvent() werden Ereignisse wie Klicks oder Nutzerinteraktionen an das g_analyticsPanel übergeben, wenn es sichtbar ist. Dadurch wird sichergestellt, dass das Panel unabhängig auf Nutzereingaben reagieren kann, ohne mit dem Haupt-Panel oder anderen Unter-Panels in Konflikt zu geraten.

if(g_analyticsPanel != NULL && g_analyticsPanel.IsVisible())
      return g_analyticsPanel.OnEvent(id, lparam, dparam, sparam);

6. Dynamisches Aktualisieren des Panels

Innerhalb der Funktion OnTick() wird die Methode UpdatePanel() regelmäßig aufgerufen, wenn das Analyse-Panel existiert. Dadurch kann das Panel seine angezeigten Analysen oder UI-Inhalte während der Ausführung des EA dynamisch aktualisieren.

void OnTick()
  {

    if(g_analyticsPanel != NULL)  
    {
      g_analyticsPanel.UpdatePanel();
      
    }
          
  }

7. Aufräumen

In der Funktion OnDeinit() wird das Panel ordnungsgemäß zerstört und der Speicher durch Aufruf von Destroy() und Löschen des Zeigers freigegeben. Dies ist wichtig, um Speicherlecks zu vermeiden, wenn der EA entfernt oder neu kompiliert wird.


Tests

Ich hatte eine unglaubliche Testerfahrung. Es fühlte sich fast wie live an, als ich sah, wie die Werte auf der Tafel mit jedem Ticken aktualisiert wurden. Es gelang mir, einen Handel mit der Confluence-Strategie zu tätigen, aber leider hatte sich das Signal zu dem Zeitpunkt, als ich mit der Aufzeichnung begann, bereits auf „No Consensus“ umgestellt. Dennoch freue ich mich, die Ergebnisse mit Ihnen zu teilen - siehe das Bild unten!

Testen des Anlytics-Panels und des Handels-New_Admin_Panels

Demo zum Testen der Funktionsweise des Analyse-Panels

In der obigen Abbildung wurde der Wert der offenen Geschäfte bei jeder Positionsschließung aktualisiert. Wir begannen mit 21 Positionen und hatten am Ende 18.

AnalyticsPanel

Alle Panels sind über das Home-Panel zugänglich



Schlussfolgerung

Wir haben unser Programm durch die Integration des Analytics Panels erfolgreich erweitert. Diese Ergänzung zeigt, dass mit dem gleichen modularen Ansatz, der für die anderen Panels angewandt wurde, viele weitere Unter-Panels integriert werden können. Diese Diskussion bildet den Abschluss von Teil (IX) der Reihe. Dies bedeutet jedoch nicht, dass die Arbeit abgeschlossen ist - es gibt noch einige Bereiche, die verbessert werden müssen. Das Kernkonzept ist jedoch inzwischen gut etabliert und klar dargestellt.

Sowohl Anfänger als auch erfahrene Entwickler können von dieser Reihe auf verschiedenen Ebenen profitieren. Es gibt viele aufschlussreiche Hinweise zum Mitnehmen. Diese Ideen bilden eine solide Grundlage für noch weitergehende Entwicklungen in der Zukunft.

In den dargestellten Ergebnissen hatte ich Kanallinien auf dem Chart eingezeichnet, und zufälligerweise wurde vom Analyse-Panel ein Kaufsignal generiert. Dieses Signal ergab sich aus dem Zusammentreffen aller aufgeführten Indikatoren, die perfekt auf die Unterstützungszone des Kanals ausgerichtet waren. Ich habe den Handel auf der Grundlage dieser Strategie des Zusammenflusses zuversichtlich aufgenommen. Der Test wurde auf einem Demokonto durchgeführt - wie immer empfehle ich allen Händlern, gründlich auf einem Demokonto zu testen, bevor sie echtes Geld riskieren.

Die Stärke dieses Konzepts besteht darin, dass Händler über das Analyse-Panel sofortigen Zugang zu wichtigen Markt- und Kontoinformationen erhalten und gleichzeitig von der Analyseleistung des Confluence-basierten Signals profitieren können. Ein verbesserungswürdiger Bereich ist das Fehlen von Warnmeldungen für die Strategie; das Hinzufügen von Benachrichtigungen würde das System noch nutzerfreundlicher machen und sicherstellen, dass keine Chancen verpasst werden.

Sowohl die Header-Datei als auch das Hauptprogramm sind unten angehängt. Teilen Sie uns Ihre Ansichten und Gedanken im Kommentarbereich mit. Bis zur nächsten Veröffentlichung - viel Spaß beim Entwickeln und erfolgreichen Handeln!

Dateiname Spezifikationen
AnalyticsPanel.mqh Eine Header-Datei, die die Struktur und das Verhalten des Analyse-Panels definiert, das mehrere Indikatoren zusammenfasst, um Confluence-basierte Handelssignale zu generieren.
New_Admin_Panel.mqh Das Hauptprogramm von MQL5 EA, das die gesamte Nutzeroberfläche des Admin-Panels initialisiert und verwaltet, einschließlich Navigation, Authentifizierung und Integration verschiedener Unter-Panels wie Kommunikation, Analyse und Handelsmanagement.

Zurück zum Inhalt

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

Beigefügte Dateien |
AnalyticsPanel.mqh (32.77 KB)
New_Admin_Panel.mq5 (19.61 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (1)
amrhamed83
amrhamed83 | 16 Apr. 2025 in 11:17
Können Sie bitte alle Dateien zusammen im Anhang veröffentlichen?
Vom Neuling zum Experten: Support and Resistance Strength Indicator (SRSI) Vom Neuling zum Experten: Support and Resistance Strength Indicator (SRSI)
In diesem Artikel erfahren Sie, wie Sie die MQL5-Programmierung nutzen können, um Marktniveaus zu bestimmen und zwischen schwächeren und stärkeren Kursniveaus zu unterscheiden. Wir werden einen funktionierenden Support and Resistance Strength Indicator (SRSI) entwickeln.
Meistern der Log-Einträge (Teil 6): Speichern von Protokollen in der Datenbank Meistern der Log-Einträge (Teil 6): Speichern von Protokollen in der Datenbank
Dieser Artikel befasst sich mit der Verwendung von Datenbanken zur strukturierten und skalierbaren Speicherung von Protokollen. Es behandelt grundlegende Konzepte, wesentliche Operationen, Konfiguration und Implementierung eines Datenbank-Handlers in MQL5. Schließlich werden die Ergebnisse validiert und die Vorteile dieses Ansatzes für die Optimierung und effiziente Überwachung hervorgehoben.
Datenwissenschaft und ML (Teil 35): NumPy in MQL5 - Die Kunst, komplexe Algorithmen mit weniger Code zu erstellen Datenwissenschaft und ML (Teil 35): NumPy in MQL5 - Die Kunst, komplexe Algorithmen mit weniger Code zu erstellen
Die NumPy-Bibliothek treibt fast alle Algorithmen des maschinellen Lernens in der Programmiersprache Python an. In diesem Artikel werden wir ein ähnliches Modul implementieren, das eine Sammlung des gesamten komplexen Codes enthält, um uns bei der Erstellung anspruchsvoller Modelle und Algorithmen jeglicher Art zu unterstützen.
Larry Connors‘ Strategien RSI2 Mean-Reversion im Day-Trading Larry Connors‘ Strategien RSI2 Mean-Reversion im Day-Trading
Larry Connors ist ein renommierter Händler und Autor, der vor allem für seine Arbeit im Bereich des quantitativen Handels und für Strategien wie den 2-Perioden-RSI (RSI2) bekannt ist, der dabei hilft, kurzfristig überkaufte und überverkaufte Marktbedingungen zu erkennen. In diesem Artikel werden wir zunächst die Motivation für unsere Forschung erläutern, dann drei von Connors' berühmtesten Strategien in MQL5 nachbilden und sie auf den Intraday-Handel mit dem S&P 500 Index CFD anwenden.