
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil VIII): Das Analytics Panel
Einführung
Dieser Artikel markiert die Entwicklung des dritten Unter-Panels innerhalb des Admin Panels EA, wobei der Schwerpunkt auf der Überwindung aktueller Beschränkungen und der Verbesserung der Funktionalität liegt. Während das bestehende Design bereits die Kommunikation und das Handelsmanagement unterstützt, werden mit der heutigen Erweiterung statistische Werkzeuge eingeführt, um die Analyse wichtiger Marktkennzahlen zu optimieren. Durch die Automatisierung von Recherchen und Berechnungen machen diese Tools die Abhängigkeit von manuellen Methoden überflüssig und vereinfachen den Prozess für Handelsverwalter. Inspiriert von der Einfachheit und Klarheit der durch PieCharts visualisierten Daten, werden wir uns auf zwei Schlüsselaspekte der Handelsperformance konzentrieren: das Gewinn-Verlust-Verhältnis und die Kategorisierung der Handelstypen. Diese Metriken bieten unmittelbare Einblicke in den Handelserfolg und die Allokation von Geschäften über verschiedene Anlageklassen wie Forex, Aktien oder Optionen.
Das Analytics Panel nutzt die Echtzeit-Datenvisualisierung, um die Ineffizienzen der manuellen Analyse zu beseitigen. Durch die Integration von Tortendiagrammen ermöglicht das Panel den Nutzern eine schnelle Bewertung ihrer Gewinn/Verlust-Verhältnisse und der Verteilung der Handelstypen ohne Verzögerungen bei der Entscheidungsfindung. Diese Funktion stellt einen bedeutenden Effizienzsprung dar und ermöglicht es den Administratoren, fundierte Entscheidungen präzise und schnell zu treffen.
Durch diese Entwicklung werden wir die Klassen PieChart und ChartCanvas von MQL5 nutzen, um diese Prozesse zu automatisieren und das Potenzial fortschrittlicher statistischer Werkzeuge zu demonstrieren. Mit dieser Erweiterung wird das Admin Panel EA zu einem noch robusteren System, das wertvolle Einblicke auf einen Blick bietet und gleichzeitig den pädagogischen und praktischen Nutzen dieser Entwicklungsreihe unterstreicht.
Für den Erfolg des Projekts habe ich diese Unterthemen als unsere Kerninhalte festgelegt:
- Überblick über das Analytics Panel
- Vorbereiten von Analytics Panel mit der Klasse CDialog
- Abrufen der Handelshistorie zur Darstellung
- Implementierung der Klassen PieChart und ChartCanvas zur Darstellung von Daten
- Testen der neuen Funktionen
- Schlussfolgerung
Überblick über das Analytics Panel
Das Analytics Panel wird eine dynamische und interaktive Schnittstelle sein, die visuelle Einblicke in die Handelsleistung und die Verteilung der Aktivitäten bietet. Für die heutige Diskussion bietet dieses Panel zwei primäre Tortendiagramme: das Diagramm „Win vs. Loss Pie Chart“, das den Anteil der Gewinn- und Verlustgeschäfte veranschaulicht, und das Handelsarten-Verteilungsdiagramm, das die Handelsgeschäfte in Devisen, Aktien und Futures unterteilt. Diese Diagramme sind nahtlos in das Panel integriert und bieten ein klares und intuitives Layout für eine einfache Interpretation. Durch die Nutzung von Echtzeitdaten aus dem Handelsverlauf liefert das Analytics Panel eine umfassende Momentaufnahme der Handelsergebnisse, die es den Nutzern ermöglicht, die Handelsleistung zu beurteilen.
Das Analytics Panel kann durch zusätzliche Visualisierungen und Metriken erweitert werden, um eine umfassendere Analyse der Handelsleistung und -aktivitäten zu ermöglichen. Hier sind einige Merkmale, die aufgenommen werden könnten:
- Ein Liniendiagramm der Leistung
- Ein Balkendiagramm des Handelsvolumens
- Eine Tabelle der Rentabilitätskennzahlen
- Ein Bereich mit den leistungsstärksten Assets
- Eine Heatmap der Handelszeiten
- Eine Line von Gewinn und Verlust
- Ein Diagramm zur Risikoexposition
- Anpassbare Warnhinweise und Schwellenwerte
- Eine Integration der Stimmungsanalyse
- Interaktive Filter usw.
Mit anderen Worten: Das Analytics Panel bietet einen umfassenden Überblick über die Handelsleistung und ermöglicht es den Nutzern, Muster zu erkennen, die Rentabilität zu bewerten und den Fortschritt im Zeitverlauf zu überwachen. Dies hilft den Händlern, über ihre Stärken und Schwächen informiert zu bleiben und gewährleistet, dass sie ihre Strategien datengestützt anpassen können. Nun gehen wir dazu über, unsere alte Version des Admin-Panels für ein Upgrade vorzubereiten. Ich habe mir auch die Zeit genommen, jede Zeile des vorherigen Codes zu verfeinern, um sicherzustellen, dass er leicht zu verstehen ist.
Vorbereiten des Analytics Panels mit der Klasse CDialog
Die Aktualisierung eines großen Programms kann sich oft überwältigend anfühlen, vor allem, wenn es sich um die Wiederholung bereits erledigter Aufgaben handelt. Aus diesem Grund ist eine klar definierte Vorlage für das Layout und die Struktur des Programms von entscheidender Bedeutung. Mit einer soliden Vorlage und durch wiederholte Verwendung wird sie zu einem festen Bestandteil Ihres Arbeitsablaufs, der es Ihnen ermöglicht, vollständige Entwicklungsaufgaben durchzuführen, ohne ständig darauf zurückgreifen zu müssen. Unser Programm ist in der Tat erheblich gewachsen, und um diese Komplexität zu bewältigen, konzentriere ich mich darauf, was ich erreichen will und wie es abläuft, indem ich diese Ziele mit den modularen Abschnitten des Programms in Einklang bringe.
Nehmen wir zum Beispiel unser Admin Home Panel, das nach dem Start des Programms als zentrale Schnittstelle dient. Von dort aus können wir auf andere Panels zugreifen. Um das Analytics Panel einzubinden, stelle ich mir eine Schaltfläche im Admin Home Panel vor, die das Analytics Panel erstellt und öffnet, sobald sie angeklickt wird. Im Analytics Panel stelle ich mir Schaltflächen und Funktionen vor, die dem jeweiligen Zweck entsprechen. Mit dieser Vision im Hinterkopf gewinnt der Entwicklungsprozess an Klarheit und Richtung und bietet einen begründeten Ansatzpunkt. Lassen Sie mich Ihnen den von uns angewandten Ansatz erläutern.
Um es kurz zu machen: Die Geschichte beginnt hier;
Zunächst betrachten wir die Einbeziehung der notwendigen Klassen, die wir verwenden werden:
#include <Controls\Dialog.mqh> #include <Controls\Button.mqh>
Deklaration des Dialogs und der Schaltfläche für das Analytics Panel:
// Global variables for the Analytics Panel CDialog analyticsPanel; // The main panel for analytics CButton adminHomeAnalyticsButton; // Button for accessing analytics from the Home panel CButton minimizeAnalyticsButton; // Minimize button for the Analytics panel CButton closeAnalyticsButton; // Close button for the Analytics panel CButton analyticsPanelAccessButton; // The first Button that will take us a next step
Erstellung des Analytics Panels und der Handles für die Schaltflächen:
Um Analytics Panel zu erstellen, klicken Sie auf den analyticsPanelAccessButton. Wir haben diese Funktionalität mit einer Button-Handler-Funktion implementiert. Ein ähnlicher Ansatz wurde auch auf andere Panels angewandt. Zuvor wurden diese Panels während der Initialisierungsphase erstellt und ausgeblendet, wodurch die Initialisierungsfunktion unnötig belastet wurde. Jetzt werden die Panels dynamisch und nach Bedarf durch Anklicken der entsprechenden Schaltflächen erstellt, wodurch Leistung und Ressourcennutzung optimiert werden. Nachstehend finden Sie einen Codeausschnitt, der diese Verbesserung veranschaulicht:
//+------------------------------------------------------------------+ //| Analytics Panel Event Handling | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {} CreateAnalyticsPanel(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } } }
Dieser Codeausschnitt behandelt Ereignisse im Zusammenhang mit dem Analysebereich innerhalb der Funktion OnChartEvent, insbesondere, wenn Klicks der Nutzer auf Chartobjekte erkannt werden (CHARTEVENT_OBJECT_CLICK). Wenn die Schaltfläche für den Zugriff auf das Analytics Panel angeklickt wird, wird das Panel angezeigt, das Admin Home Panel wird ausgeblendet, und das Analytics Panel wird zusammen mit seinen Steuerelementen mit der Funktion CreateAnalyticsPanel dynamisch erstellt. Wenn Sie auf die Schaltfläche Analyse minimieren klicken, wird der Analysebereich ausgeblendet und der Admin-Startbereich wieder angezeigt. Wenn Sie schließlich auf die Schaltfläche „Analyse schließen“ klicken, wird der Analysebereich vollständig zerstört, und der Admin-Startbereich wird wieder eingeblendet. Diese dynamische Handhabung stellt sicher, dass die entsprechenden Bereiche je nach Nutzeraktion ein- oder ausgeblendet werden, was sowohl die Funktionalität als auch die Nutzerfreundlichkeit verbessert.
Erstellen der Steuerelemente für das Analytics Panel:
Dieser Codeabschnitt definiert eine Funktion, CreateAnalyticsPanelControls, die ein Analytics Panel in einer MQL5-Anwendung initialisiert und ihm Steuerelemente hinzufügt. Es beginnt damit, die ID des aktuellen Charts mit ChartID() zu ermitteln und versucht, eine Schaltfläche zum Minimieren (minimizeAnalyticsButton) an bestimmten Koordinaten zu erstellen. Wenn die Erstellung fehlschlägt, wird eine Fehlermeldung protokolliert und false zurückgegeben. Bei Erfolg wird die Schaltfläche mit einem Unterstrich „_“ beschriftet und dem analyticsPanel-Container hinzugefügt. In ähnlicher Weise wird eine Schaltfläche zum Schließen (closeAnalyticsButton) mit einem „X“ an einem anderen Koordinatensatz erstellt, wobei derselbe Fehlerprüfungsprozess durchgeführt wird. Die Funktion endet mit einem Platzhalterkommentar, der vorschlägt, wo zusätzliche analytikbezogene Steuerelemente, wie Diagramme oder Eingabeelemente, hinzugefügt werden könnten. Wenn alle Steuerelemente erfolgreich erstellt wurden, gibt die Funktion true zurück.
bool CreateAnalyticsPanelControls() { long chart_id = ChartID(); // Create Minimize Button if (!minimizeAnalyticsButton.Create(chart_id, "MinimizeAnalyticsButton", 0, 210, -22, 240, 0)) { Print("Failed to create minimize button for Analytics Panel"); return false; } minimizeAnalyticsButton.Text("_"); analyticsPanel.Add(minimizeAnalyticsButton); // Create Close Button if (!closeAnalyticsButton.Create(chart_id, "CloseAnalyticsButton", 0, 240, -22, 270, 0)) { Print("Failed to create close button for Analytics Panel"); return false; } closeAnalyticsButton.Text("X"); analyticsPanel.Add(closeAnalyticsButton); // Add additional controls specific to analytics as needed // For example, charts, labels, or input elements for data representation return true; }
Außerdem haben wir das Erstellen vieler Panels von den Initialisierungsfunktionen auf die Auslösung durch Button-Handler verlagert. Seitdem ich diese Änderung vorgenommen habe, konnte ich eine deutliche Verbesserung der Leistung des Expert Advisors (EA) feststellen, insbesondere in Bezug auf die Geschwindigkeit beim Navigieren zwischen den verschiedenen Panels.
Hier ist die Kombination mit der wichtigsten Funktion der Ereignisbehandlung OnChartEvent:
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if (id == CHARTEVENT_OBJECT_CLICK) { if (sparam == "HomeButtonComm") { adminHomePanel.Show(); communicationsPanel.Hide(); } else if (sparam == "HomeButtonTrade") { adminHomePanel.Show(); tradeManagementPanel.Hide(); } else if (sparam == "AdminHomeAnalyticsButton") { adminHomePanel.Show(); analyticsPanel.Hide(); } else if (sparam == "MinimizeAnalyticsButton") { analyticsPanel.Hide(); adminHomePanel.Show(); } else if (sparam == "CloseAnalyticsButton") { analyticsPanel.Destroy(); adminHomePanel.Show(); } else if (sparam == "TradeMgmtAccessButton") { tradeManagementPanel.Show(); adminHomePanel.Hide(); if (!tradeManagementPanel.Create(ChartID(), "Trade Management Panel", 0, 500, 30, 1280, 170) || !CreateTradeManagementControls()) {} } else if (sparam == "CommunicationsPanelAccessButton") { communicationsPanel.Show(); adminHomePanel.Hide(); if (!communicationsPanel.Create(ChartID(), "Communications Panel", 0, 20, 150, 490, 650) || !CreateCommunicationsPanelControls()) {} } else if (sparam == "CloseHomeButton") { adminHomePanel.Destroy(); } else if (sparam == "MinimizeHomeButton") { adminHomePanel.Hide(); maximizeHomeButton.Show(); } else if (sparam == "MaximizeHomeButton") { adminHomePanel.Show(); maximizeHomeButton.Show(); } else if (sparam == "AnalyticsPanelAccessButton") { analyticsPanel.Show(); adminHomePanel.Hide(); if (!analyticsPanel.Create(ChartID(), "Analytics Panel", 0, 500, 450, 1280, 650) || !CreateAnalyticsPanelControls()) {}; CreateAnalyticsPanel(); } else if (sparam == "ShowAllButton") { analyticsPanel.Show(); communicationsPanel.Show(); tradeManagementPanel.Show(); adminHomePanel.Hide(); } else if (sparam == "MinimizeComsButton") { OnMinimizeComsButtonClick(); } else if (sparam == "CloseComsButton") { communicationsPanel.Destroy(); } else if (sparam == "LoginButton") { OnLoginButtonClick(); } else if (sparam == "CloseAuthButton") { OnCloseAuthButtonClick(); } else if (sparam == "TwoFALoginButton") { OnTwoFALoginButtonClick(); } else if (sparam == "Close2FAButton") { OnClose2FAButtonClick(); } } switch (id) { case CHARTEVENT_OBJECT_CLICK: if (sparam == "SendButton") OnSendButtonClick(); else if (sparam == "ClearButton") OnClearButtonClick(); else if (sparam == "ChangeFontButton") OnChangeFontButtonClick(); else if (sparam == "ToggleThemeButton") OnToggleThemeButtonClick(); else if (sparam == "MinimizeComsButton") OnMinimizeComsButtonClick(); else if (sparam == "CloseComsButton") OnCloseComsButtonClick(); else if (StringFind(sparam, "QuickMessageButton") != -1) { long index = StringToInteger(StringSubstr(sparam, 18)); OnQuickMessageButtonClick(index - 1); } break; case CHARTEVENT_OBJECT_ENDEDIT: if (sparam == "InputBox") OnInputChange(); break; } }
Schließlich habe ich auch die Anpassung des Admin Home Panels in Betracht gezogen, wie die Koordinaten und die Breite in diesem Codeabschnitt unten zeigen:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { if (!ShowAuthenticationPrompt()) { Print("Authorization failed. Exiting..."); return INIT_FAILED; } if (!adminHomePanel.Create(ChartID(), "Admin Home Panel", 0, 30, 80,330, 550)) { Print("Failed to create Admin Home Panel"); return INIT_FAILED; } if (!CreateAdminHomeControls()) { Print("Home panel control creation failed"); return INIT_FAILED; } adminHomePanel.Hide(); // Hide home panel by default on initialization return INIT_SUCCEEDED; }
Abrufen der Handelshistorie zur Darstellung
Nun müssen wir Daten aus der Terminal-Historie abrufen, die wir in unserem neuen Panel mit Piechart darstellen können. Die Funktion GetTradeData dient dazu, historische Handelsdaten zu analysieren und sie in bestimmte Kategorien einzuordnen, was eine Grundlage für eine detaillierte Analyse der Handelsleistung darstellt. Zunächst werden die Zähler für Gewinne, Verluste und drei Handelsarten initialisiert: Devisen, Aktien und Futures. Die Funktion stützt sich auf die Funktion HistorySelect, um Handelsdaten vom Beginn der Historie des Handelskontos bis zum aktuellen Zeitpunkt abzurufen. Wenn dieser Auswahlprozess fehlschlägt, protokolliert die Funktion einen Fehler und beendet sich, um die Robustheit gegenüber nicht verfügbaren historischen Daten zu gewährleisten. Anschließend werden alle verfügbaren Angebote durchlaufen, indem HistoryDealGetTicket um die eindeutige Kennung von jedem Handelsgeschäft abzurufen. Für jedes gültige Geschäft bewertet die Funktion die Rentabilität, indem sie den Gewinnwert analysiert und entweder den Gewinn- oder Verlustzähler erhöht, je nachdem, ob der Gewinn positiv oder negativ war.
Die Kategorisierung von Handelsgeschäften wird durch ihre Symbole bestimmt. Devisengeschäfte werden durch das Fehlen eines Punktes in ihren Symbolnamen identifiziert, während Aktien- und Futures-Geschäfte durch die Überprüfung des SYMBOL_PATH Eigenschaft des Symbols. Der Gruppenname des Symbols bestimmt, ob es unter die Kategorien „Aktien“ oder „Futures“ fällt. Dieser Schritt gewährleistet, dass die Handelsgeschäfte genau nach ihren Finanzinstrumenten gruppiert werden. Durch die Aggregation dieser Informationen liefert die Funktion eine umfassende Aufschlüsselung der Handelsleistung, die für weitere Analysen oder zur Visualisierung verwendet werden kann.
Im heutigen Szenario kann diese Funktion in ein Analytics Panel integriert werden, um ein Tortendiagramm zu erstellen, das die Verteilung der Handelskategorien und das Verhältnis von Gewinnen und Verlusten zeigt. Ein Händler könnte die Funktion zum Beispiel nutzen, um zu visualisieren, dass 60 % seiner Handelsgeschäfte in Devisen, 30 % in Aktien und 10 % in Futures getätigt werden, während seine Gesamterfolgsquote bei 70 % liegt. Solche Einblicke sind von unschätzbarem Wert für die Bewertung der Handelsleistung und die Ermittlung von Bereichen mit Verbesserungspotenzial. Darüber hinaus eignet sich die Funktion dank ihrer Echtzeit-Datenanalysefähigkeiten für die Erstellung reaktionsschneller Dashboards, die Händlern helfen, ihre Strategien auf der Grundlage historischer Trends anzupassen.
Über ihre derzeitige Implementierung hinaus hat die Funktion GetTradeData das Potenzial für breitere Anwendungen. Es könnte erweitert werden, um bestimmte Zeitspannen zu analysieren oder zusätzliche Metriken wie den durchschnittlichen Gewinn oder den Drawdown einzubeziehen. Diese Daten könnten dann in externe Tools integriert werden, z. B. in Modelle für maschinelles Lernen für vorausschauende Analysen oder interaktive Berichte für Investorenpräsentationen. Mit solchen Erweiterungen wird die Funktion zu einem vielseitigen Werkzeug sowohl für einzelne Händler als auch für größere Handelssysteme, die auf eine Maximierung von Effizienz und Rentabilität abzielen
Hier ist der Code, wie er implementiert wurde:
//+------------------------------------------------------------------+ //| Data for Pie Chart | //+------------------------------------------------------------------+ void GetTradeData(int &wins, int &losses, int &forexTrades, int &stockTrades, int &futuresTrades) { wins = 0; losses = 0; forexTrades = 0; stockTrades = 0; futuresTrades = 0; if (!HistorySelect(0, TimeCurrent())) { Print("Failed to select trade history."); return; } int totalDeals = HistoryDealsTotal(); for (int i = 0; i < totalDeals; i++) { ulong dealTicket = HistoryDealGetTicket(i); if (dealTicket > 0) { double profit = HistoryDealGetDouble(dealTicket, DEAL_PROFIT); if (profit > 0) wins++; else if (profit < 0) losses++; string symbol = HistoryDealGetString(dealTicket, DEAL_SYMBOL); if (SymbolInfoInteger(symbol, SYMBOL_SELECT)) { if (StringFind(symbol, ".") == -1) forexTrades++; else { string groupName; if (SymbolInfoString(symbol, SYMBOL_PATH, groupName)) { if (StringFind(groupName, "Stocks") != -1) stockTrades++; else if (StringFind(groupName, "Futures") != -1) futuresTrades++; } } } } } }
Implementierung der Klassen PieChart und ChartCanvas zur Darstellung von Daten
Wir beginnen mit der Einbeziehung der Klassen:
#include <Canvas\Charts\PieChart.mqh> #include <Canvas\Charts\ChartCanvas.mqh>
Nutzerdefinierte Klasse für die Tortendiagramme:
Zunächst haben wir die Klasse CCustomPieChart von der Basisklasse CPieChart abgeleitet. Ziel war es, die geschützte Methode DrawPie freizulegen, die normalerweise außerhalb der übergeordneten Klasse unzugänglich ist. Durch die Erstellung der öffentlichen Methode DrawPieSegment, die DrawPie umschließt, haben wir die Flexibilität gewonnen, einzelne Tortendiagrammesegmente dynamisch zu zeichnen. Dies war besonders nützlich bei der Implementierung der nutzerdefinierten Rendering-Logik in der Methode DrawPieChart der Klasse CAnalyticsChart. Dieser Schritt gewährleistete, dass wir die visuelle Darstellung der einzelnen Tortenstücke genau steuern konnten, sodass wir dynamischere und visuell maßgeschneiderte Tortendiagramme für unser Analytics Panel erstellen konnten.
//+------------------------------------------------------------------+ //| Custom Pie Chart Class | //+------------------------------------------------------------------+ class CCustomPieChart : public CPieChart { public: void DrawPieSegment(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { DrawPie(fi3, fi4, idx, p, clr); // Expose protected method } };
Analytics Chart Class:
Als Nächstes haben wir die Klasse CWnd erweitert, um CAnalyticsChart zu erstellen, ein spezieller Diagramm-Container. In diese Klasse haben wir CCustomPieChart als Mitglied integriert, sodass sie als Grundlage für das Zeichnen von Tortendiagrammen dienen kann. Wir haben Methoden wie CreatePieChart implementiert, um das Tortendiagramm-Widget innerhalb eines definierten Bereichs zu initialisieren, und SetPieChartData, um Datenwerte, Beschriftungen und Farben mit dem Diagramm zu verknüpfen. Außerdem wurde die Methode DrawPieChart sorgfältig kodiert, um die Winkel von jedem Segment auf der Grundlage des Datensatzes zu berechnen und DrawPieSegment zum Rendern aufzurufen. Indem wir diese Logik durcharbeiteten, stellten wir sicher, dass das Tortendiagramm dynamisch gezeichnet werden konnte und die zugrundeliegenden Daten auf eine visuell ansprechende Weise widerspiegelte.
//+------------------------------------------------------------------+ //| Analytics Chart Class | //+------------------------------------------------------------------+ class CAnalyticsChart : public CWnd { private: CCustomPieChart pieChart; // Declare pieChart as a member of this class public: bool CreatePieChart(string label, int x, int y, int width, int height) { if (!pieChart.CreateBitmapLabel(label, x, y, width, height)) { Print("Error creating Pie Chart: ", label); return false; } return true; } void SetPieChartData(const double &values[], const string &labels[], const uint &colors[]) { pieChart.SeriesSet(values, labels, colors); pieChart.ShowPercent(); } void DrawPieChart(const double &values[], const uint &colors[], int x0, int y0, int radius) { double total = 0; int seriesCount = ArraySize(values); if (seriesCount == 0) { Print("No data for pie chart."); return; } for (int i = 0; i < seriesCount; i++) total += values[i]; double currentAngle = 0.0; // Resize the points array CPoint points[]; ArrayResize(points, seriesCount + 1); for (int i = 0; i < seriesCount; i++) { double segmentValue = values[i] / total * 360.0; double nextAngle = currentAngle + segmentValue; // Define points for the pie slice points[i].x = x0 + (int)(radius * cos(currentAngle * M_PI / 180.0)); points[i].y = y0 - (int)(radius * sin(currentAngle * M_PI / 180.0)); pieChart.DrawPieSegment(currentAngle, nextAngle, i, points, colors[i]); currentAngle = nextAngle; } // Define the last point to close the pie points[seriesCount].x = x0 + (int)(radius * cos(0)); // Back to starting point points[seriesCount].y = y0 - (int)(radius * sin(0)); } };
Die Funktion CreateAnalyticsPanel:
Um alles miteinander zu verbinden, haben wir die Funktion CreateAnalyticsPanel geschrieben, die die eigentliche Implementierung des Analytics Panels übernimmt. Zunächst haben wir die Handelsdaten - wie Gewinne, Verluste und Anzahl der Handelstypen - mit unserer Funktion GetTradeData abgerufen. Wir haben dann zwei CAnalyticsChart-Objekte für unterschiedliche Visualisierungen instanziiert. Für das erste Diagramm haben wir die abgerufenen Gewinn-/Verlustdaten verwendet, um ein Tortendiagramm mit der Bezeichnung „Win vs. Loss Pie Chart“ zu erstellen. In ähnlicher Weise haben wir für das zweite Diagramm die Daten zur Handelsart verwendet, um ein Tortendiagramm „Trade Type Distribution“ zu erstellen. Durch den Aufruf von SetPieChartData und DrawPieChart für jedes Diagramm haben wir sie dynamisch gerendert und analyticsPanel hinzugefügt. Dieser Ansatz ermöglichte es uns, den Code in modulare und wiederverwendbare Komponenten aufzuteilen und so Klarheit und Wartbarkeit zu gewährleisten.
//+------------------------------------------------------------------+ //| Create Analytics Panel | //+------------------------------------------------------------------+ void CreateAnalyticsPanel() { int wins, losses, forexTrades, stockTrades, futuresTrades; GetTradeData(wins, losses, forexTrades, stockTrades, futuresTrades); // Declare pieChart1 and pieChart2 as local variables CAnalyticsChart pieChart1; CAnalyticsChart pieChart2; // Win vs Loss Pie Chart if (!pieChart1.CreatePieChart("Win vs. Loss Pie Chart", 20, 20, 300, 300)) { Print("Error creating Win/Loss Pie Chart"); return; } double winLossValues[] = {wins, losses}; string winLossLabels[] = {"Wins", "Losses"}; uint winLossColors[] = {clrGreen, clrRed}; pieChart1.SetPieChartData(winLossValues, winLossLabels, winLossColors); pieChart1.DrawPieChart(winLossValues, winLossColors, 150, 150, 140); // Add pieChart1 to the analyticsPanel analyticsPanel.Add(pieChart1); // Trade Type Pie Chart if (!pieChart2.CreatePieChart("Trade Type Distribution", 350, 20, 300, 300)) { Print("Error creating Trade Type Pie Chart"); return; } double tradeTypeValues[] = {forexTrades, stockTrades, futuresTrades}; string tradeTypeLabels[] = {"Forex", "Stocks", "Futures"}; uint tradeTypeColors[] = {clrBlue, clrOrange, clrYellow}; pieChart2.SetPieChartData(tradeTypeValues, tradeTypeLabels, tradeTypeColors); pieChart2.DrawPieChart(tradeTypeValues, tradeTypeColors, 500, 150, 140); // Add pieChart2 to the analyticsPanel analyticsPanel.Add(pieChart2); // Show the analyticsPanel analyticsPanel.Show(); }
Warum wir es auf diese Weise gemacht haben:
Durch diese Kodierung des Systems konnten wir sicherstellen, dass die Erstellung von Diagrammen sowohl dynamisch als auch flexibel ist. Durch die Ableitung von CCustomPieChart haben wir die Kontrolle über die Darstellung des Tortendiagramms, während CAnalyticsChart es uns ermöglichte, die Tortendiagrammfunktion in einer eigenständigen Klasse zu kapseln. Dadurch war es einfach, neue Diagramme hinzuzufügen oder ihr Verhalten anzupassen, ohne andere Teile des Programms zu beeinträchtigen. Wenn wir zum Beispiel im heutigen Projekt ein weiteres Diagramm für die Aktienkurvenanalyse hinzufügen wollten, könnten wir dieselbe Struktur wie CAnalyticsChart mit minimalem Aufwand wiederverwenden. Dieser modulare Ansatz rationalisiert nicht nur die Entwicklung, sondern macht das Analytics Panel auch in hohem Maße erweiterbar für künftige Erweiterungen.
Verhinderung des Fehlers „Array out of range“:
Um den Fehler „array out of range“ in der CPieChart::DrawPie-Methode aus PieChart.mqh zu vermeiden, haben wir eine Bereichsüberprüfung hinzugefügt, um sicherzustellen, dass der Index (idx + 1) innerhalb der Grenzen des CPoint-Arrays (p[]) liegt, bevor darauf zugegriffen wird. Dadurch wird sichergestellt, dass das Array vor der Verwendung richtig dimensioniert ist und ungültige Operationen verhindert werden. Wenn der Index außerhalb der Grenzen liegt, wird die Funktion vorzeitig beendet und eine Fehlermeldung zur Fehlersuche ausgegeben. Außerdem wird während der Darstellung des Tortendiagramms die Größe des Arrays CPoint entsprechend angepasst, um alle Kreissegmente unterzubringen und sicherzustellen, dass die Datenstruktur immer groß genug für die Berechnungen ist. Die hinzugefügte Bedingung (idx + 1 >= ArraySize(p)) prüft, ob der nächste Index gültig ist, und wenn nicht, wird eine Fehlermeldung gedruckt und vorzeitig zurückgekehrt, um eine weitere Verarbeitung zu verhindern. Diese Prüfung verhindert, dass die Funktion versucht, auf ein Array-Element zuzugreifen, das außerhalb des zulässigen Bereichs liegt, wodurch der Fehler vermieden wird.
if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; }
Bitte beachten Sie, dass wir die integriert Klasse CPieChart modifizieren mussten, um den oben erwähnten Fehler beim Testen des Expert Advisors (EA) zu vermeiden.
//+------------------------------------------------------------------+ //| Draw pie | //+------------------------------------------------------------------+ void CPieChart::DrawPie(double fi3, double fi4, int idx, CPoint &p[], const uint clr) { // Ensure array index is within bounds if (idx + 1 >= ArraySize(p)) { Print("Array out of range error: idx = ", idx, ", ArraySize = ", ArraySize(p)); return; } //--- draw arc Arc(m_x0, m_y0, m_r, m_r, fi3, fi4, p[idx].x, p[idx].y, p[idx + 1].x, p[idx + 1].y, clr); //--- variables int x3 = p[idx].x; int y3 = p[idx].y; int x4 = p[idx + 1].x; int y4 = p[idx + 1].y; //--- draw radii if (idx == 0) Line(m_x0, m_y0, x3, y3, clr); if (idx != m_data_total - 1) Line(m_x0, m_y0, x4, y4, clr); //--- fill double fi = (fi3 + fi4) / 2; int xf = m_x0 + (int)(0.99 * m_r * cos(fi)); int yf = m_y0 - (int)(0.99 * m_r * sin(fi)); Fill(xf, yf, clr); //--- for small pie if (fi4 - fi3 <= M_PI_4) Line(m_x0, m_y0, xf, yf, clr); }
Testen der neuen Funktionen
In diesem Abschnitt stellen wir die Ergebnisse unserer Verbesserungen vor und zeigen die aktualisierte Version unseres Programms und seine Funktionen. Nachstehend finden Sie eine Reihe von Bildern, die die Verbesserungen veranschaulichen. Zunächst wird das neu gestaltete Admin Home Panel zusammen mit der neu hinzugefügten Schaltfläche hervorgehoben. Als Nächstes wird das Analytics Panel angezeigt, in dem die Verteilung der Handelsdaten visualisiert wird. Es folgt eine Vollansicht des Admin-Panels mit allen Unter-Panels. Abschließend zeigen wir Ihnen eine animierte Bildschirmaufnahme, die den Einsatz der Anwendung auf der Terminalkarte für eine nahtlose Integration demonstriert.
Das neue Admin Home Panel
Das Analytics Panel
Admin Panel V1.23 Vollansicht
Boom 300 Index, H4 : Start von Admin Panel V1.24 EA
Schlussfolgerung
In der heutigen Diskussion haben wir uns mit der Entwicklung fortgeschrittener Funktionen in MQL5 befasst und uns dabei auf die Integration neuer Klassen und Techniken zur Verbesserung des Admin Panels und seiner Funktionalität konzentriert. Durch die Nutzung der Fähigkeiten von MQL5 haben wir erfolgreich dynamische Panels und datengesteuerte Visualisierungen wie Tortendiagramme implementiert, um die Handelsleistung effektiv darzustellen. Dieses Projekt zeigt das immense Potenzial von MQL5 für die Erstellung anspruchsvoller, nutzerfreundlicher Tools, die für Händler und Entwickler gleichermaßen geeignet sind.
Das neu implementierte Analytics Panel bietet Händlern verwertbare Einblicke in ihre Handelsperformance und bietet Entwicklern ein solides Gerüst, auf dem sie aufbauen können. Durch die Bewältigung von Herausforderungen wie unübersichtliche Bedienfelder, Objektüberlagerungen und die dynamische Erstellung von Steuerelementen haben wir die Grundlage für eine effizientere und intuitivere Nutzeroberfläche geschaffen. Diese Verbesserungen sind grundlegend und ein Sprungbrett für künftige Innovationen. Entwickler können diesen Rahmen erweitern, um zusätzliche Analysen, interaktive Funktionen oder sogar völlig neue Funktionalitäten einzubinden. Die beigefügten Quelldateien und Bilder zeigen das Ergebnis unserer Bemühungen und bieten Inspiration für andere, die grenzenlosen Möglichkeiten von MQL5 zu erkunden. Viel Spaß beim Handel, und möge dieser Leitfaden Ihre Kreativität bei der Umsetzung Ihrer Projekte anregen!
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16356





- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.