
Erstellen eines Handelsadministrator-Panels in MQL5 (Teil IX): Code Organisation (V): Die Klasse AnalyticsPanel
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.
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
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.
- m_lblOpenTrades zeigt die Anzahl der aktuell offenen Handelsgeschäfte an.
- m_lblPnLName: Ein statisches Kennzeichen, das lediglich den Text „PnL:“ anzeigt (dieser bleibt schwarz).
- 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:
- m_lblStochName: Der statische Teil („Stoch:“).
- 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:
- m_lblExpectation liefert eine Textzusammenfassung wie „Kaufen“, „Verkaufen“ oder „Kein Konsens“.
- 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!
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.
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. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17397






- 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.