Entwicklung eines nutzerdefinierten Indikators für die Kontoperformance-Matrix
Einführung
Viele Händler haben oft mit übermäßigem Handel, mangelnder Disziplin und emotionalen Entscheidungen zu kämpfen, vor allem, wenn sie nach den strengen Regeln von Prop-Firmen handeln oder ihr eigenes Kapital verwalten. Die Versuchung, den Verlusten hinterherzulaufen, die Losgröße nach einer Pechsträhne zu erhöhen oder die Tageslimits zu ignorieren, führt häufig dazu, dass die Drawdown-Regeln verletzt und die Konten vorzeitig aufgelöst werden. Selbst erfahrene Händler können in die Falle tappen, wenn sie die täglichen Risikogrenzen nicht einhalten, was zu einer inkonsistenten Leistung führt und dazu, dass sie keine langfristige Rentabilität erreichen oder finanzierte Handelsherausforderungen bestehen.
Der Indikator der Performance-Matrix des Kontos bietet eine praktische Lösung, indem er als eingebauter Risikomanager und Disziplin-Coach fungiert. Da die Händler ihren eigenen täglichen Risikoprozentsatz innerhalb der Grenzen der Regeln für den maximalen Drawdown festlegen können, werden Kontokapital, täglicher Gewinn/Verlust und Drawdowns automatisch in Echtzeit verfolgt. Wird der tägliche Risikoschwellenwert erreicht, schließt der Indikator alle Positionen und sperrt den Handel bis zum Beginn der nächsten Sitzung, wodurch die Möglichkeit eines Wiedergutmachungs-Handels oder des emotionalen Overtradings ausgeschlossen wird. Diese Struktur hilft den Händlern, Beständigkeit aufzubauen, ihr Kapital zu schützen und ihre Chancen zu erhöhen, die Herausforderungen der Prop-Firma zu bestehen oder ihre persönlichen Konten stetig zu vergrößern.
Planung und Logik
1. Konservative Einstellung:
- Account Balance = $10,000
- Max Overall Drawdown (6%) = $600
- Max Daily Drawdown (8%) = $800
- Daily Risk (1%) = $100
Der Handel kann nur $100 pro Tag verlieren. Damit haben sie 6 Verlusttage, bevor sie den maximalen Drawdown erreichen, was innerhalb der Sicherheitsgrenzen der Prop-Firmen liegt.
2. Moderate Einstellung:
- Account Balance = $10,000
- Max Overall Drawdown (6%) = $600
- Max Dailydown (8%) = $800
- Daily Risk (2%) = $200
Der Händler riskiert 200 Dollar pro Tag. Sie haben jetzt etwa 3 Tage Zeit, bevor der maximale Drawdown erreicht wird. Dies ist aggressiver, aber mit weniger Spielraum.
3. Aggressive Einstellung (nicht empfehlenswert):
- Account Balance = $10,000
- Max Overall Drawdown (6%) = $600
- Max Dailydown (8%) = $800
- Daily Risk (5%) = $500
Ein schlechter Tag könnte 500 $ vernichten, sodass nur sehr wenig Spielraum unter dem maximalen Drawdown von 600 $ bleibt. Wenn das Risiko nicht kontrolliert wird, ist das Scheitern fast garantiert.
Merkmale des Indikators:
- Das Dashboard zeigt die Leistungskennzahlen des Kontos
- Visueller Risikostatus des Handels
- Gewinn/Verlust (P/L), der auf dem Chart für geöffnete Positionen angezeigt wird

Logik des Risikomanagements

Die ersten Schritte
//+------------------------------------------------------------------+ //| Acc_Matrix.mq5 | //| GIT under Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/johnhlomohang/ | //+------------------------------------------------------------------+ #property copyright "GIT under Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/johnhlomohang/" #property version "1.00" #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_LINE #property indicator_color1 clrDodgerBlue #property indicator_style1 STYLE_SOLID #property indicator_width1 1 #property indicator_type2 DRAW_LINE #property indicator_color2 clrCrimson #property indicator_style2 STYLE_SOLID #property indicator_width2 1 #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| Input variables | //+------------------------------------------------------------------+ input bool ShowDashboard = true; // Show performance dashboard input bool ShowProfit_Loss = true; // Show Profit and Loss on the chart input color DashboardBGColor = clrWhiteSmoke; // Dashboard background color input color TextColor = clrBlack; // Text color input int DashboardX = 20; // Dashboard X position input int DashboardY = 20; // Dashboard Y position input int DashboardWidth = 280; // Dashboard width input int FontSize = 10; // Font size // Performance tracking mode input bool TrackFromIndicatorStart = true; // Track from indicator start (true) or overall (false) // Risk management parameters input double DailyRiskPercent = 1.0; // Daily risk percentage input double MaxDailyDrawdownPercent = 10.0; // Max daily drawdown percentage input double MaxOverallDrawdownPercent = 8.0; // Max overall drawdown percentage input bool EnableRiskManagement = true; // Enable risk management input ulong MagicNumber = 123456; // Magic number for position identification
Wir beginnen mit dem Abschnitt über die Eingabevariablen, der es den Händlern ermöglicht, die Darstellung und das Verhalten des Indikators anzupassen. Sie können umschalten, ob ein Dashboard angezeigt werden soll, Gewinn oder Verlust direkt im Chart anzeigen und visuelle Eigenschaften wie Hintergrundfarbe, Textfarbe, Positionierung und Schriftgröße anpassen. Dank dieser Optionen können Händler die visuelle Schnittstelle flexibel an ihre persönlichen Vorlieben anpassen, während die wichtigsten Kontodaten in Echtzeit sichtbar bleiben.
Vor allem aber machen die Parameter des Risikomanagements den Indikator zu mehr als nur einem visuellen Instrument. Händler können ihren täglichen Risikoprozentsatz, den maximalen täglichen Drawdown-Prozentsatz und den maximalen Gesamtdrawdown-Prozentsatz festlegen, um sicherzustellen, dass das System Disziplin erzwingt und rücksichtsloses Handeln verhindert. Durch die Aktivierung des Risikomanagements kann der Indikator die Handelsgeschäfte überwachen (über die magische Zahl zur Identifizierung) und bei Überschreitung von Limits Warnungen senden. Diese Funktion hilft den Händlern, die Konsistenz zu wahren, übermäßiges Handeln zu vermeiden und sich an die Regeln der Prop-Firma oder die persönlichen Strategien für das Kontowachstum anzupassen.
//+------------------------------------------------------------------+ //| Indicator buffers | //+------------------------------------------------------------------+ double BidBuffer[]; double AskBuffer[]; //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ double currentProfit; double balance; double equity; double margin; double freeMargin; double marginLevel; int totalOrders; double totalProfit; double dailyProfit; datetime lastTradeTime; int winCount; int lossCount; double maxDrawdown; double maxDrawdownPercent; // Risk management variables double initialBalance; double dailyHighEquity; double dailyLowEquity; double dailyStartEquity; bool tradingEnabled = true; string riskStatus = "Trading Enabled"; color riskStatusColor = clrGreen; // Performance tracking variables int totalClosedTrades; int closedWinCount; int closedLossCount; double totalGains; double totalLosses; double largestWin; double largestLoss; double averageWin; double averageLoss; double profitFactor; // Track the last time history was updated datetime lastHistoryUpdate; bool firstUpdate = true;
In diesem Abschnitt des Codes werden die globalen Variablen definiert, die der Indikator verwendet, um die Performance, das Risikomanagement und den Handelsverlauf über mehrere Sitzungen hinweg zu verfolgen. Die erste Gruppe von Variablen befasst sich mit den Leistungskennzahlen des Kontos wie laufender Gewinn, Saldo, Kapital, Marge, freie Marge und Margenhöhe. Außerdem werden die Anzahl der offenen Aufträge, der Gesamtgewinn, der Tagesgewinn, der Zeitpunkt des letzten Handels sowie die Anzahl der Handelsgeschäfte mit Gewinn und Verlust erfasst. Darüber hinaus überwacht es den maximalen Drawdown sowohl in absoluten Werten als auch in Prozent, was für die Bewertung des Risikos entscheidend ist.
Die zweite Gruppe von Variablen ist dem Risikomanagement gewidmet. Hier speichert der Code den Anfangssaldo, wenn die Verfolgung beginnt, sowie den Tageshöchst- und -tiefststand und den Startwert. Diese Werte helfen dabei, die täglichen Leistungsschwankungen zu messen und durch die Erkennung von Überschreitungen der Tages- oder Gesamtlimits für Disziplin zu sorgen. Das Flag tradingEnabled fungiert als Hauptschalter, der bei Überschreitung von Risikoschwellen Warnungen sendet. Ein visuelles Element ist durch den Text und Farbe in riskStatus und die riskStatusColor enthalten, die dem Händler eine klare Rückmeldung auf dem Chart geben, z. B. die Anzeige „Trading Enabled“ in grün oder „Warning“ in rot.
Die letzte Gruppe enthält Performance-Tracking-Variablen für die Analyse von abgeschlossenen Handelsgeschäften. Dazu gehören die Gesamtzahl der abgeschlossenen Handelsgeschäfte, wie viele davon Gewinne oder Verluste waren, die kumulierten Gewinne und Verluste sowie der größte Gewinn und der größte Verlust. Außerdem werden Durchschnittswerte für Gewinne und Verluste sowie der Gewinnfaktor berechnet, der eine wichtige Leistungskennzahl für den Vergleich von Gewinnen und Verlusten darstellt. Um genaue Aktualisierungen zu gewährleisten, verfolgt das System, wann der Verlauf zuletzt aktualisiert wurde und ob es sich um die erste Aktualisierung seit der Initialisierung handelt. Insgesamt geben diese Variablen den Händlern einen umfassenden Überblick über ihre Handelsleistung, um die Konsistenz zu verbessern.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, "ACCOUNT PERFORMANCE MATRIX"); IndicatorSetInteger(INDICATOR_DIGITS, _Digits); // Initialize variables currentProfit = 0.0; balance = AccountInfoDouble(ACCOUNT_BALANCE); equity = AccountInfoDouble(ACCOUNT_EQUITY); // Set initial balance based on tracking mode if(TrackFromIndicatorStart) { initialBalance = balance; } else { // For overall tracking, use the actual account balance initialBalance = AccountInfoDouble(ACCOUNT_BALANCE); } dailyStartEquity = equity; dailyHighEquity = equity; dailyLowEquity = equity; lastHistoryUpdate = TimeCurrent(); // Load historical trade data based on tracking mode LoadHistory(); // Create dashboard objects if enabled if(ShowDashboard) { CreateDashboard(); } // Set timer to update every second EventSetTimer(1); return(INIT_SUCCEEDED); }
Die Funktion OnInit() initialisiert den nutzerdefinierten Indikator, indem sie seinen Anzeigenamen und seine Genauigkeit festlegt und alle Variablen zur Leistungsverfolgung für die Verwendung vorbereitet. Es setzt den aktuellen Gewinn zurück, ruft den Kontostand und das Kapital ab und bestimmt den Anfangssaldo, je nachdem, ob der Nutzer die Performance ab dem Zeitpunkt, an dem der Indikator angebracht wird, oder über die gesamte Kontohistorie verfolgen möchte. Es legt auch den Startwert für den Tag fest und zeichnet die Höchst- und Tiefstwerte des Kapitalstands auf, um die Performance innerhalb eine Tages zu messen. Historische Handelsdaten werden mit der Funktion LoadHistory() geladen, um den Kontext für Berechnungen zu liefern, und wenn die Dashboard-Option aktiviert ist, wird das visuelle Performance-Panel mit CreateDashboard() erstellt. Schließlich aktiviert die Funktion ein Timer-Ereignis mit Aktualisierungen im Sekundentakt, um sicherzustellen, dass alle Kontokennzahlen und Dashboard-Anzeigen mit der Echtzeit-Handelsaktivität synchronisiert bleiben.
//+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Delete all objects created by the indicator ObjectsDeleteAll(0, 0, -1); EventKillTimer(); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { // Update account information UpdateAccountInfo(); // Update historical data periodically to capture new closed trades if(TimeCurrent() - lastHistoryUpdate >= 5 || firstUpdate) // Update every 5 seconds or on first run { LoadHistory(); lastHistoryUpdate = TimeCurrent(); firstUpdate = false; } // Update dashboard if enabled if(ShowDashboard) { UpdateDashboard(); } // Check risk management rules if(EnableRiskManagement) { CheckRiskManagement(); } } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { // Update bid and ask buffers if(ShowProfit_Loss) { UpdatePriceBuffers(rates_total, BidBuffer, AskBuffer, time); } return(rates_total); } //+------------------------------------------------------------------+ //| Update account information function | //+------------------------------------------------------------------+ void UpdateAccountInfo() { balance = AccountInfoDouble(ACCOUNT_BALANCE); equity = AccountInfoDouble(ACCOUNT_EQUITY); margin = AccountInfoDouble(ACCOUNT_MARGIN); freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL); // Update daily high/low equity if(equity > dailyHighEquity) dailyHighEquity = equity; if(equity < dailyLowEquity) dailyLowEquity = equity; CalculateProfitMetrics(); CalculateTradeMetrics(); }
Die Funktion OnDeinit() sorgt für ein sauberes Herunterfahren des Indikators, indem sie alle von ihm erstellten Chart-Objekte löscht und das Timer-Ereignis beendet, um Hintergrundaktualisierungen zu stoppen. Dadurch wird verhindert, dass das Chart unübersichtlich wird, nachdem der Indikator entfernt wurde, und es wird sichergestellt, dass keine unnötigen Prozesse aktiv bleiben. Die Funktion OnTimer(), die jede Sekunde ausgeführt wird, ist für die Funktionalität des Indikators von zentraler Bedeutung: Sie aktualisiert kontinuierlich die Kontoinformationen, aktualisiert die historischen Handelsdaten alle fünf Sekunden (oder beim ersten Durchlauf) und verwaltet das Performance-Dashboard, falls aktiviert. Außerdem werden die Regeln für das Risikomanagement überprüft und durchgesetzt, sodass der Händler bei Erreichen von Risikoschwellen in Echtzeit gewarnt wird.
In der Zwischenzeit integriert die Funktion OnCalculate() den Indikator in die Chartaktualisierung und stellt sicher, dass bei aktivierter Gewinn-/Verlustanzeige die Bid- und Ask-Linien durch Preispuffer aktualisiert werden. Die Funktion UpdateAccountInfo() ruft Live-Kontodetails wie Saldo, Kapital, Marge und freie Marge ab und zeichnet gleichzeitig den täglichen Höchst- und Tiefstwert des Kapitals auf, um die Performance genau zu verfolgen. Anschließend ruft es unterstützende Funktionen wie CalculateProfitMetrics() und CalculateTradeMetrics() auf, um die Leistung weiter zu analysieren. Zusammen bilden diese Funktionen ein sich selbst aktualisierendes, risikobewusstes Dashboard, das Händlern einen vollständigen Überblick über ihren Kontostatus gibt und gleichzeitig aktiv für Disziplin sorgt.
//+------------------------------------------------------------------+ //| Update account information function | //+------------------------------------------------------------------+ void UpdateAccountInfo() { balance = AccountInfoDouble(ACCOUNT_BALANCE); equity = AccountInfoDouble(ACCOUNT_EQUITY); margin = AccountInfoDouble(ACCOUNT_MARGIN); freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); marginLevel = AccountInfoDouble(ACCOUNT_MARGIN_LEVEL); // Update daily high/low equity if(equity > dailyHighEquity) dailyHighEquity = equity; if(equity < dailyLowEquity) dailyLowEquity = equity; CalculateProfitMetrics(); CalculateTradeMetrics(); } //+------------------------------------------------------------------+ //| Update price buffers with Bid and Ask values | //+------------------------------------------------------------------+ void UpdatePriceBuffers(int rates_total, double &bidBuffer[], double &askBuffer[], const datetime &time[]) { double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Calculate current profit for open positions currentProfit = 0.0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetSymbol(i) == _Symbol) { currentProfit += PositionGetDouble(POSITION_PROFIT); } } // Fill buffers with current bid and ask values if(ShowProfit_Loss && rates_total > 0) { for(int i = 0; i < rates_total; i++) { bidBuffer[i] = bid; askBuffer[i] = ask; } // Calculate position for labels (2 bars to the right of current candle) int currentBar = rates_total - 1; datetime labelTime = (currentBar + 2 < rates_total) ? time[currentBar + 2] : time[currentBar] + PeriodSeconds() * 2; // Add profit/loss label with color coding string plLabelText; color plColor; if(currentProfit >= 0) { plLabelText = "Profit: " + DoubleToString(currentProfit, 2); plColor = clrBlue; } else { plLabelText = "Loss: " + DoubleToString(currentProfit, 2); plColor = clrRed; } CreateOrUpdateLabel("PLLabel", plLabelText, labelTime, (bid + ask) / 2, plColor, ANCHOR_RIGHT); } }
Die Funktion UpdateAccountInfo() ist für den Abruf von Live-Kontodaten und die Verfolgung wichtiger Leistungskennzahlen zuständig. Es bezieht den aktuellen Saldo, das Kapital, die Marge, die freie Marge und die Margenhöhe vom Handelskonto. Darüber hinaus überwacht es die Tagesschwankungen des Kapitalstands, indem es dessen Höchst- und Tiefstwerte aktualisiert, sobald ein neuer Extremwert erreicht wird. Sobald die rohen Kontodaten aktualisiert sind, ruft die Funktion CalculateProfitMetrics() und CalculateTradeMetrics() auf, die tiefergehende Analysen wie Gewinnberechnungen, die Verfolgung von Handelsgewinnen und -verlusten und die Leistungsbewertung durchführen. Dadurch wird sichergestellt, dass das Dashboard immer die aktuellsten Kontobedingungen widerspiegelt.
Die Funktion UpdatePriceBuffers() konzentriert sich auf die Visualisierung von Preisen und Gewinnen/Verlusten. Zunächst werden die aktuellen Geld- und Briefkurse, Bid und Ask, abgerufen, dann werden die offenen Positionen durchlaufen, um den aktuellen Gewinn für das aktive Symbol zu berechnen. Wenn die Gewinn/Verlust-Visualisierung aktiviert ist, werden die Puffer des Indikators mit den letzten Bid- und Ask-Werten des Charts gefüllt und ein Etikett erstellt, das leicht rechts vom aktuellen Balken positioniert ist. Dieses Etikett zeigt entweder einen Gewinn (blau) oder einen Verlust (rot) an, je nach dem aktuellen Handelsergebnis. Durch die Kombination der Verfolgung der Kontoperformance mit der Visualisierung von Kursen und Gewinnen in Echtzeit bietet die Funktion Händlern sowohl numerisches als auch grafisches Feedback, das das Situationsbewusstsein und die Entscheidungsfindung verbessert.
//+------------------------------------------------------------------+ //| Create or update text label | //+------------------------------------------------------------------+ void CreateOrUpdateLabel(string name, string text, datetime time, double price, color clr, ENUM_ANCHOR_POINT anchor) { if(ObjectFind(0, name) < 0) { ObjectCreate(0, name, OBJ_TEXT, 0, time, price); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_ANCHOR, anchor); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize); } else { ObjectMove(0, name, 0, time, price); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); } } //+------------------------------------------------------------------+ //| Calculate profit metrics | //+------------------------------------------------------------------+ void CalculateProfitMetrics() { totalProfit = equity - initialBalance; // Calculate max drawdown - FIXED: Prevent division by zero double drawdown = dailyHighEquity - equity; if(drawdown > maxDrawdown) { maxDrawdown = drawdown; // Avoid division by zero - use a small epsilon if dailyHighEquity is zero double denominator = (dailyHighEquity == 0) ? 0.000001 : dailyHighEquity; maxDrawdownPercent = (drawdown / denominator) * 100; } }
Die Funktion UpdateAccountInfo() ist für den Abruf von Live-Kontodaten und die Verfolgung wichtiger Leistungskennzahlen zuständig. Es bezieht den aktuellen Saldo, das Kapital, die Marge, die freie Marge und die Margenhöhe vom Handelskonto. Darüber hinaus überwacht es die Tagesschwankungen des Kapitalstands, indem es dessen Höchst- und Tiefstwerte aktualisiert, sobald ein neuer Extremwert erreicht wird. Sobald die rohen Kontodaten aktualisiert sind, ruft die Funktion CalculateProfitMetrics() und CalculateTradeMetrics() auf, die tiefer gehende Analysen wie Gewinnberechnungen, die Verfolgung von Handelsgewinnen und -verlusten und die Leistungsbewertung durchführen. Dadurch wird sichergestellt, dass das Dashboard immer die aktuellsten Kontobedingungen widerspiegelt.
Die Funktion UpdatePriceBuffers() konzentriert sich auf die Visualisierung von Preisen und Gewinnen/Verlusten. Zunächst werden die aktuellen Geld- und Briefkurse, Bid und Ask, abgerufen, dann werden die offenen Positionen durchlaufen, um den aktuellen Gewinn für das aktive Symbol zu berechnen. Wenn die Gewinn/Verlust-Visualisierung aktiviert ist, werden die Puffer des Indikators mit den letzten Bid- und Ask-Werten des Charts gefüllt und ein Etikett erstellt, das leicht rechts vom aktuellen Balken positioniert ist. Dieses Etikett zeigt entweder einen Gewinn (blau) oder einen Verlust (rot) an, je nach dem aktuellen Handelsergebnis. Durch die Kombination der Verfolgung der Kontoperformance mit der Visualisierung von Kursen und Gewinnen in Echtzeit bietet die Funktion Händlern sowohl numerisches als auch grafisches Feedback, das das Situationsbewusstsein und die Entscheidungsfindung verbessert.
//+------------------------------------------------------------------+ //| Calculate trade metrics | //+------------------------------------------------------------------+ void CalculateTradeMetrics() { totalOrders = PositionsTotal(); winCount = 0; lossCount = 0; // Count winning and losing positions for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { double profit = PositionGetDouble(POSITION_PROFIT); if(profit > 0) winCount++; else if(profit < 0) lossCount++; } } } //+------------------------------------------------------------------+ //| Load historical trade data | //+------------------------------------------------------------------+ void LoadHistory() { datetime startDate = 0; if(TrackFromIndicatorStart) { // Only load history from when the indicator was started startDate = TimeCurrent() - 86400; // Load from 24 hours ago to ensure we capture all recent trades } HistorySelect(startDate, TimeCurrent()); int totalHistory = HistoryDealsTotal(); // Reset counters int newClosedTrades = 0; int newClosedWinCount = 0; int newClosedLossCount = 0; double newTotalGains = 0; double newTotalLosses = 0; double newLargestWin = 0; double newLargestLoss = 0; for(int i = 0; i < totalHistory; i++) { ulong ticket = HistoryDealGetTicket(i); if(ticket > 0) { // Check if this is a closing deal (not a deposit/withdrawal or opening trade) long dealType = HistoryDealGetInteger(ticket, DEAL_TYPE); if(dealType == DEAL_TYPE_BUY || dealType == DEAL_TYPE_SELL) { double profit = HistoryDealGetDouble(ticket, DEAL_PROFIT); if(profit != 0) { newClosedTrades++; if(profit > 0) { newClosedWinCount++; newTotalGains += profit; if(profit > newLargestWin) newLargestWin = profit; } else { newClosedLossCount++; newTotalLosses += MathAbs(profit); if(profit < newLargestLoss) newLargestLoss = profit; } } } } } // Update the global variables totalClosedTrades = newClosedTrades; closedWinCount = newClosedWinCount; closedLossCount = newClosedLossCount; totalGains = newTotalGains; totalLosses = newTotalLosses; largestWin = newLargestWin; largestLoss = newLargestLoss; // Calculate averages and profit factor averageWin = (closedWinCount > 0) ? totalGains / closedWinCount : 0; averageLoss = (closedLossCount > 0) ? totalLosses / closedLossCount : 0; profitFactor = (totalLosses > 0) ? totalGains / totalLosses : (totalGains > 0) ? 1000 : 0; }
Die Funktion CalcculateTradeMetrics() liefert einen Live-Schnappschuss der offenen Handelspositionen, indem sie zählt, wie viele derzeit im Gewinn und wie viele im Verlust sind. Zunächst wird die Gesamtzahl der offenen Positionen abgefragt, dann werden die einzelnen Positionen in einer Schleife durchlaufen und ihr Gewinn- oder Verlustwert überprüft. Ist die Position gewinnbringend, wird der Gewinnzähler erhöht, ist sie verlustbringend, wird der Verlustzähler erhöht. Mit dieser Funktion erhalten Händler sofortiges Feedback über die Qualität ihrer offenen Handelsgeschäfte und können so in Echtzeit beurteilen, ob ihre Positionen mit ihrem Handelsplan übereinstimmen.
Die Funktion LoadHistory() vertieft die historische Performance, indem sie abgeschlossene Trades innerhalb eines bestimmten Zeitrahmens analysiert. Wenn das Tracking beim Start des Indikators eingestellt ist, wird die Historie der letzten 24 Stunden geladen, um sicherzustellen, dass die jüngsten Handelsgeschäfte berücksichtigt werden. Es durchsucht dann alle historischen Handelsgeschäfte und filtert nur Kauf- oder Verkaufsabschlüsse heraus, während Einzahlungen, Abhebungen oder Eingänge ignoriert werden. Für jeden abgeschlossenen Handel wird der Gewinn oder Verlust aufgezeichnet, die Zählungen für Gewinne und Verluste aktualisiert, die Gesamtgewinne und -verluste summiert und der größte Einzelgewinn oder -verlust verfolgt. Schließlich werden Durchschnittswerte und der Gewinnfaktor berechnet, eine wichtige Kennzahl zum Vergleich von Gewinnen und Verlusten. Diese umfassende Aufschlüsselung der Performance ermöglicht es Händlern, Muster in ihrem Handelsverhalten zu erkennen, die Rentabilität zu bewerten und im Laufe der Zeit ein diszipliniertes Risikomanagement zu betreiben.
//+------------------------------------------------------------------+ //| Check risk management rules | //+------------------------------------------------------------------+ void CheckRiskManagement() { // Check if it's a new day (reset daily equity) MqlDateTime today, lastCheck; TimeToStruct(TimeCurrent(), today); TimeToStruct(TimeCurrent(), lastCheck); static int lastDay = -1; if(today.day != lastDay) { dailyStartEquity = equity; dailyHighEquity = equity; dailyLowEquity = equity; lastDay = today.day; // Re-enable trading at the start of a new day if(!tradingEnabled) { tradingEnabled = true; riskStatus = "Trading Enabled"; riskStatusColor = clrGreen; } } // Calculate daily drawdown percentage - FIXED: Prevent division by zero double dailyDrawdownPercent = 0; if(dailyHighEquity > 0) { dailyDrawdownPercent = (dailyHighEquity - equity) / dailyHighEquity * 100; } // Calculate overall drawdown percentage - FIXED: Prevent division by zero double overallDrawdownPercent = 0; if(initialBalance > 0) { overallDrawdownPercent = (initialBalance - equity) / initialBalance * 100; } double dailyRiskEquity = dailyStartEquity * (1 - DailyRiskPercent / 100); // Check if we've hit risk limits if(tradingEnabled) { if(equity <= dailyRiskEquity) { riskStatus = "Daily Risk Limit Reached"; riskStatusColor = clrRed; tradingEnabled = false; Alert("Daily Risk Limit Reached, Consider Closing Open Positions!!!"); } else if(dailyDrawdownPercent >= MaxDailyDrawdownPercent) { riskStatus = "Max Daily Drawdown Reached"; riskStatusColor = clrRed; tradingEnabled = false; Alert("Max Daily Drawdown Reached!!!"); } else if(overallDrawdownPercent >= MaxOverallDrawdownPercent) { riskStatus = "Max Overall Drawdown Reached"; riskStatusColor = clrRed; tradingEnabled = false; Alert("Max Overall Drawdown Reached!!!"); } } } //+------------------------------------------------------------------+ //| Create dashboard function | //+------------------------------------------------------------------+ void CreateDashboard() { // Create background rectangle ObjectCreate(0, "DashboardBG", OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, "DashboardBG", OBJPROP_XDISTANCE, DashboardX); ObjectSetInteger(0, "DashboardBG", OBJPROP_YDISTANCE, DashboardY); ObjectSetInteger(0, "DashboardBG", OBJPROP_XSIZE, DashboardWidth); ObjectSetInteger(0, "DashboardBG", OBJPROP_YSIZE, 320); ObjectSetInteger(0, "DashboardBG", OBJPROP_BGCOLOR, DashboardBGColor); ObjectSetInteger(0, "DashboardBG", OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, "DashboardBG", OBJPROP_BORDER_COLOR, clrGray); ObjectSetInteger(0, "DashboardBG", OBJPROP_BACK, true); ObjectSetInteger(0, "DashboardBG", OBJPROP_SELECTABLE, false); ObjectSetInteger(0, "DashboardBG", OBJPROP_SELECTED, false); ObjectSetInteger(0, "DashboardBG", OBJPROP_HIDDEN, true); ObjectSetInteger(0, "DashboardBG", OBJPROP_ZORDER, 0); // Create title ObjectCreate(0, "DashboardTitle", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "DashboardTitle", OBJPROP_XDISTANCE, DashboardX + 10); ObjectSetInteger(0, "DashboardTitle", OBJPROP_YDISTANCE, DashboardY + 10); ObjectSetString(0, "DashboardTitle", OBJPROP_TEXT, "ACCOUNT PERFORMANCE MATRIX"); ObjectSetInteger(0, "DashboardTitle", OBJPROP_COLOR, TextColor); ObjectSetInteger(0, "DashboardTitle", OBJPROP_FONTSIZE, FontSize + 2); // Create tracking mode indicator string trackingMode = TrackFromIndicatorStart ? "From Indicator Start" : "Overall Account"; ObjectCreate(0, "TrackingModeLabel", OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_XDISTANCE, DashboardX + 10); ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_YDISTANCE, DashboardY + 30); ObjectSetString(0, "TrackingModeLabel", OBJPROP_TEXT, "Tracking: " + trackingMode); ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_COLOR, clrDarkBlue); ObjectSetInteger(0, "TrackingModeLabel", OBJPROP_FONTSIZE, FontSize); // Create information labels CreateDashboardLabel("RiskStatusLabel", "Trading Status: ", 50, DashboardX, DashboardY); CreateDashboardLabel("BalanceLabel", "Balance: ", 70, DashboardX, DashboardY); CreateDashboardLabel("EquityLabel", "Equity: ", 90, DashboardX, DashboardY); CreateDashboardLabel("DailyProfitLabel", "Daily P/L: ", 110, DashboardX, DashboardY); CreateDashboardLabel("TotalProfitLabel", "Total P/L: ", 130, DashboardX, DashboardY); CreateDashboardLabel("PositionsLabel", "Open Positions: ", 150, DashboardX, DashboardY); CreateDashboardLabel("WinRateLabel", "Win Rate: ", 170, DashboardX, DashboardY); CreateDashboardLabel("DailyRiskLabel", "Daily Risk: ", 190, DashboardX, DashboardY); CreateDashboardLabel("DailyDrawdownLabel", "Daily Drawdown: ", 210, DashboardX, DashboardY); CreateDashboardLabel("TotalDrawdownLabel", "Total Drawdown: ", 230, DashboardX, DashboardY); CreateDashboardLabel("ProfitFactorLabel", "Profit Factor: ", 250, DashboardX, DashboardY); CreateDashboardLabel("TradesLabel", "Total Trades: ", 270, DashboardX, DashboardY); CreateDashboardLabel("AvgWinLossLabel", "Avg Win/Loss: ", 290, DashboardX, DashboardY); }
Die Funktion CheckRiskManagement() ist der Durchsetzungsmechanismus, der sicherstellt, dass die Händler ihren Risikoplan einhalten und die Kontolimits nicht überschreiten. Anschließend werden die täglichen und gesamten Drawdown-Prozentsätze berechnet, wobei die Division durch Null sorgfältig gehandhabt wird, um Fehler zu vermeiden. Die Funktion vergleicht das Kapital mit dem vordefinierten täglichen Risikolimit, dem maximalen täglichen Drawdown und dem maximalen Gesamtdrawdown des Händlers. Wird einer dieser Schwellenwerte überschritten, färbt sich die Statusmeldung rot, und es werden Warnmeldungen ausgelöst, um den Händler zu warnen. Dieser Ansatz trägt nicht nur dazu bei, katastrophale Verluste zu verhindern, sondern sorgt auch für Disziplin, indem er die Versuchung beseitigt, nach Erreichen der Limits weiter zu handeln.
Die Funktion CreateDashboard() erstellt die Bildschirmoberfläche, die alle verfolgten Metriken in einem organisierten und visuell klaren Panel anzeigt. Es beginnt mit der Erstellung eines Hintergrundrechtecks, das mit nutzerdefinierten Farben, Größen und Rahmen gestaltet wird und als Container für alle Leistungsdaten dient. Anschließend werden ein Titel und eine Kennzeichnung für den Verfolgungsmodus hinzugefügt, um anzugeben, ob das Dashboard die Ergebnisse ab dem Start des Indikators oder den gesamten Kontoverlauf überwacht. Darunter befinden sich in strukturierten Zeilen eine Reihe von beschrifteten Feldern wie Saldo, Kapital, Tages- und Gesamtgewinn/-verlust, Gewinnrate, Drawdowns, Gewinnfaktor und durchschnittlicher Gewinn/Verlust. Dieses visuelle Dashboard ermöglicht es Händlern, sowohl den Zustand ihres Kontos als auch ihren Risikostatus sofort zu beurteilen, ohne sich mit mehreren Berichten auseinandersetzen zu müssen, was es zu einem leistungsstarken Instrument macht, um Klarheit und Disziplin beim Handel zu bewahren.
//+------------------------------------------------------------------+ //| Create dashboard label helper function | //+------------------------------------------------------------------+ void CreateDashboardLabel(string name, string text, int yOffset, int x, int y) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x + 10); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y + yOffset); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetInteger(0, name, OBJPROP_COLOR, TextColor); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, FontSize); } //+------------------------------------------------------------------+ //| Update dashboard function | //+------------------------------------------------------------------+ void UpdateDashboard() { // Update risk status with color coding ObjectSetString(0, "RiskStatusLabel", OBJPROP_TEXT, "Trading Status: " + riskStatus); ObjectSetInteger(0, "RiskStatusLabel", OBJPROP_COLOR, riskStatusColor); // Update values for all dashboard labels UpdateDashboardLabel("BalanceLabel", "Balance: " + DoubleToString(balance, 2)); UpdateDashboardLabel("EquityLabel", "Equity: " + DoubleToString(equity, 2)); // Color code profit values double dailyPL = equity - dailyStartEquity; string dailyPLText = "Daily P/L: "; if(dailyPL >= 0) dailyPLText += "+" + DoubleToString(dailyPL, 2); else dailyPLText += DoubleToString(dailyPL, 2); UpdateDashboardLabel("DailyProfitLabel", dailyPLText); string totalPLText = "Total P/L: "; if(totalProfit >= 0) totalPLText += "+" + DoubleToString(totalProfit, 2); else totalPLText += DoubleToString(totalProfit, 2); UpdateDashboardLabel("TotalProfitLabel", totalPLText); UpdateDashboardLabel("PositionsLabel", "Open Positions: " + IntegerToString(totalOrders)); // Calculate and display win rate from closed trades int totalTrades = closedWinCount + closedLossCount; string winRateText = "Win Rate: "; if(totalTrades > 0) { double winRate = (double)closedWinCount / totalTrades * 100; winRateText += DoubleToString(winRate, 1) + "% (" + IntegerToString(closedWinCount) + "/" + IntegerToString(totalTrades) + ")"; } else winRateText += "N/A"; UpdateDashboardLabel("WinRateLabel", winRateText); // Risk metrics double dailyRiskEquity = dailyStartEquity * (1 - DailyRiskPercent / 100); // Calculate drawdown percentages with zero division protection double dailyDrawdownPercent = 0; if(dailyHighEquity > 0) { dailyDrawdownPercent = (dailyHighEquity - equity) / dailyHighEquity * 100; } double overallDrawdownPercent = 0; if(initialBalance > 0) { overallDrawdownPercent = (initialBalance - equity) / initialBalance * 100; } UpdateDashboardLabel("DailyRiskLabel", "Daily Risk: " + DoubleToString(DailyRiskPercent, 1) + "% (" + DoubleToString(dailyRiskEquity, 2) + ")"); string dailyDrawdownText = "Daily Drawdown: " + DoubleToString(dailyDrawdownPercent, 1) + "%"; UpdateDashboardLabel("DailyDrawdownLabel", dailyDrawdownText); string totalDrawdownText = "Total Drawdown: " + DoubleToString(overallDrawdownPercent, 1) + "%"; UpdateDashboardLabel("TotalDrawdownLabel", totalDrawdownText); // Performance metrics UpdateDashboardLabel("ProfitFactorLabel", "Profit Factor: " + DoubleToString(profitFactor, 2)); UpdateDashboardLabel("TradesLabel", "Total Trades: " + IntegerToString(totalClosedTrades)); UpdateDashboardLabel("AvgWinLossLabel", "Avg Win/Loss: " + DoubleToString(averageWin, 2) + "/" + DoubleToString(MathAbs(averageLoss), 2)); } //+------------------------------------------------------------------+ //| Update dashboard label helper function | //+------------------------------------------------------------------+ void UpdateDashboardLabel(string name, string text) { ObjectSetString(0, name, OBJPROP_TEXT, text); }
Die Funktion CreateDashboardLabel() dient als Hilfsfunktion, um schnell beschriftete Felder auf dem Dashboard zu erzeugen. Jedes Kennzeichen wird mit einem bestimmten Namen, Text und Positionsversatz erstellt, und es wird ein einheitliches Styling wie Schriftgröße und -farbe angewendet. Dadurch wird sichergestellt, dass alle Metriken auf dem Dashboard deutlich sichtbar und einheitlich formatiert sind, was den Händlern einen organisierten Überblick über die Kontoperformance und den Risikostatus bietet.
Die Funktion UpdateDashboard() aktualisiert das Dashboard kontinuierlich mit aktuellen Konto- und Leistungsdaten. Es aktualisiert alle wichtigen Kennzahlen, einschließlich Saldo, Kapital, täglicher und gesamter Gewinn/Verlust, offene Positionen, Gewinnrate, Drawdowns, tägliches Risiko, Gewinnfaktor, Gesamthandel und durchschnittlicher Gewinn/Verlust. Die Funktion kodiert außerdem wichtige Informationen wie Gewinn/Verlust und Handelsstatus farblich, um sofortiges visuelles Feedback zu geben. Durch die ständige Darstellung der Kontobedingungen in Echtzeit hilft es den Händlern, fundierte Entscheidungen zu treffen, stärkt die Disziplin und verhindert übermäßiges Handeln, indem es deutlich anzeigt, wann die Risikolimits erreicht sind.
Indikator-Demo:

Schlussfolgerung
Zusammenfassend lässt sich sagen, dass wir einen nutzerdefinierten Account Performance Matrix-Indikator entwickelt haben, der sowohl die Echtzeit- als auch die historische Handelsentwicklung verfolgt. Der Indikator überwacht wichtige Kontokennzahlen wie Saldo, Kapital, Marge, offene Positionen, Tages- und Gesamtgewinn/-verlust, Gewinnrate, Drawdowns, Gewinnfaktor und durchschnittlicher Gewinn/Verlust. Es enthält ein dynamisches Dashboard mit visuellen Kennzeichnungen und farbkodierten Warnungen, um Händlern einen klaren und organisierten Überblick über ihre Kontoperformance zu geben. Risikomanagementregeln sind integriert, um tägliche Risikolimits und maximale Drawdowns durchzusetzen, und wenn die Limits erreicht werden, wird der Händler über die aktuelle Kontoperformance informiert.
Zusammenfassend lässt sich sagen, dass dieser Indikator den Händlern hilft, Disziplin zu bewahren, übermäßiges Handeln zu vermeiden und fundiertere Entscheidungen zu treffen, indem er einen transparenten Überblick über den Zustand des Kontos und die Risikoexposition bietet. Indem sie klar aufzeigt, wann Risikogrenzen erreicht oder überschritten werden, fördert sie ein konsistentes Handelsverhalten und unterstützt nachhaltiges Wachstum. Unabhängig davon, ob ein Händler daran arbeitet, eine Herausforderung für eine Prop-Firma zu bestehen oder ein persönliches Handelskonto zu verwalten, bietet dieses Tool eine strukturierte Anleitung zum Risikomanagement, zur Optimierung von Handelsentscheidungen und letztlich zur Steigerung der langfristigen Rentabilität.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/19508
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Aufbau eines professionellen Handelssystems mit Heikin Ashi (Teil 2): Entwicklung eines EA
Entwicklung von Handelsstrategien mit den Oszillatoren Parafrac und Parafrac V2: Einzeleintritt Performance Insights
Vom Neuling zum Experten: Animierte Nachrichtenüberschrift mit MQL5 (XI) – Korrelation im Nachrichtenhandel
Der MQL5 Standard Library Explorer (Teil 1): Einführung in CTrade, CiMA, und CiATR
- 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.