Trading-Disziplin im Code verankern (Teil 3): Durchsetzung symbolbezogener Handelsgrenzen mit einer Whitelist in MQL5
Inhalt
- Einführung
- Das zugrunde liegende Konzept
- Überblick über die Systemarchitektur
- MQL5-Implementierung
- Tests und Ergebnisse
- Schlussfolgerung
Einführung
Selbst disziplinierte Trader können Geld verlieren – nicht, weil ihre Strategie fehlerhaft ist, sondern weil sie das falsche Symbol handeln. In MetaTrader 5 kann dies in typischen Situationen vorkommen, beispielsweise wenn ein Expert Advisor an ein unbekanntes Chart angehängt wird, eine manuelle Pending Order für ein noch nicht getestetes Symbol platziert oder dieselbe Strategie ohne Einschränkung des Anwendungsbereichs auf mehrere Instrumente angewendet wird. Das technische Problem ist daher klar: Es muss verhindert werden, dass Aufträge ausgeführt oder Geschäfte mit Instrumenten getätigt werden, die nicht ausdrücklich genehmigt sind – sowohl beim manuellen Handel als auch beim Handel mit EAs.
Dieser Artikel stellt eine in MQL5 implementierte praktische Lösung vor, die mithilfe von OnTradeTransaction die Einhaltung der Regeln auf Symbolebene auf der Ebene der Handelsereignisse sicherstellt. Das System basiert auf einer Whitelist zugelassener Instrumente und blockiert aktiv sowohl das Hinzufügen von Pending Orders als auch Marktgeschäfte mit Symbolen, die nicht zur zulässigen Gruppe gehören. Jeder blockierte Versuch wird aus Gründen der Transparenz protokolliert, während ein Dashboard die Konfiguration und einen Echtzeit-Überblick über die zulässigen Symbole bietet.
In der Praxis verwandelt dieser Ansatz die Symboldisziplin von einer freiwilligen Richtlinie in eine strukturelle Regel, die von der Handelsumgebung selbst erzwungen wird. Anstatt sich darauf zu verlassen, dass sich der Händler merkt, welche Instrumente gehandelt werden sollen, stellt das System sicher, dass nur die vordefinierten Symbole in die Strategieausführung einbezogen werden können.
In den folgenden Abschnitten werden das Konzept der Handelsbeschränkung auf Symbolebene, die Architektur der Lösung und deren Umsetzung in MQL5 beschrieben. Anschließend stellen wir Testergebnisse vor, die zeigen, wie der Mechanismus Handelsversuche mit nicht zugelassenen Symbolen zuverlässig blockiert, während der normale Betrieb für die in der Whitelist konfigurierten Symbole weiterhin möglich ist.
Das zugrunde liegende Konzept
In den beiden vorangegangenen Teilen dieser Reihe mit dem Titel Trading-Disziplin in den Code integrieren haben wir untersucht, wie Disziplin über die bloße Absicht hinausgehen und direkt in Handelssysteme eingebettet werden kann. Diese Diskussionen machten eine entscheidende Tatsache deutlich: Die Regeln zu kennen, ist nicht dasselbe wie sie durchzusetzen. Ein Händler kann die Grundsätze des Risikomanagements zwar vollständig verstehen und dennoch unter Druck gegen sie verstoßen. Bei der Automatisierung geht es also nicht darum, den Trader zu ersetzen – sondern darum, ihn vor Unbeständigkeit zu schützen.
Warum Disziplin bei der Symbolauswahl wichtig ist
Einer der Bereiche, in denen es am häufigsten zu Verstößen gegen die Disziplin kommt, ist die Auswahl der Symbole. Viele Trader beginnen mit einer festgelegten Auswahl an Währungspaaren oder Instrumenten, mit denen sie sich gut auskennen. Im Laufe der Zeit untersuchen sie, wie sich diese Symbole in verschiedenen Handelssitzungen verhalten, wie sie auf Nachrichten reagieren, wie volatil sie sind und wie klar sich ihre Handelssignale ausbilden. Diese Vertrautheit sorgt für statistische Sicherheit und eine strukturierte Entscheidungsfindung. Moderne Handelsplattformen bieten jedoch Zugang zu Dutzenden – manchmal sogar Hunderten – von Finanzinstrumenten. Mit einem einzigen Scrollen kann ein Händler vom EUR/USD zum NASDAQ, von Gold zu exotischen Währungspaaren wechseln.
Diese Zugänglichkeit birgt eine Versuchung. Trader diversifizieren oft impulsiv. Selbst algorithmische Händler binden manchmal einen Expert Advisor an mehrere Charts an, ohne sorgfältig zu prüfen, welche Instrumente zulässig sind. Was als Experiment beginnt, kann sich unbemerkt zu einer Inkonsistenz entwickeln.
Im Laufe der Zeit führt dies zu:
- Strategieabweichung – die Anwendung einer Strategie, die für eine bestimmte Marktstruktur konzipiert wurde, auf Instrumente mit anderen Volatilitäts- und Liquiditätsmerkmalen.
- Datenverfälschung bei Backtesting-Vergleichen – die Vermischung von Ergebnissen aus Instrumenten, die nie Teil des ursprünglichen Testumfangs waren, was die Performanz-Bewertung unzuverlässig macht.
- Psychologische Inkonsistenz – ein Wechsel des Fokus zwischen Symbolen mindert die Klarheit und verstärkt emotionale Entscheidungsfindung.
- Risikoausweitung über die beabsichtigten Grenzen hinaus – das Risiko steigt unbeabsichtigt an, wenn mehrere ungeplante Instrumente gleichzeitig gehandelt werden.
Man muss sich bewusst machen, dass oft nicht die Strategie selbst das Problem ist. Der Trader verfügt möglicherweise über einen bewährten Ansatz, der unter bestimmten Bedingungen effektiv funktioniert. Die eigentliche Schwäche liegt darin, dass die Vorschriften nicht durchgesetzt werden. Es gibt Regeln, aber nichts hindert daran, sie zu brechen.
Symbol-Whitelist
Das in diesem Rahmenwerk implementierte System folgt einem Whitelist-Modell, d. h., es arbeitet nach einem genehmigungsbasierten Ausführungsmodell. Es gibt keine eigenständige Blacklist-Komponente, die eine Liste verbotener Instrumente verwaltet. Stattdessen definiert die Architektur ein kontrolliertes Handelsuniversum, indem sie explizit festlegt, welche Symbole zur Ausführung zugelassen sind. Jedes Instrument, das nicht in dieser vordefinierten Gruppe enthalten ist, gilt automatisch als nicht zulässig.
Eine Symbol-Whitelist ist somit eine formal festgelegte Sammlung von Finanzinstrumenten, die für den Handel innerhalb des Systems zugelassen sind. Sie dient als Validierungsschicht, die direkt in die Ausführungslogik integriert ist. Bevor eine Orderanfrage bearbeitet wird, prüft das System, ob das aktuelle Symbol in der genehmigten Liste enthalten ist. Diese Validierung erfolgt programmgesteuert und einheitlich, ohne Ausnahme.
Die Entscheidungsstruktur ist binär und deterministisch:
- Wenn das Symbol in der Whitelist enthalten ist, wird die Ausführung fortgesetzt.
- Wenn das Symbol nicht in der Whitelist enthalten ist, wird die Ausführung automatisch verweigert.
Es gibt keine bedingten Überschreibungen, keine situationsbezogene Interpretation und keine manuellen Eingriffe zur Laufzeit. Die Berechtigungsprüfung erfolgt automatisch und ist absolut.
Whitelist vs. Blacklist
Es ist wichtig, dieses Modell von einem auf einer Blacklist basierenden Ansatz zu unterscheiden.
- Ein Whitelist-Modell legt ausdrücklich fest, was erlaubt ist, und schließt standardmäßig alles andere aus.
- Ein Blacklist-Modell legt ausdrücklich fest, was verboten ist, während der Rest des Handelsuniversums zugänglich bleibt.
Dieses System basiert ausschließlich auf dem Whitelist-Modell. Symbole werden nicht abgelehnt, weil sie auf einer Verbotsliste stehen, sondern weil sie nicht zum zugelassenen Satz gehören. Die Einschränkung ergibt sich implizit durch Ausschluss und nicht durch ein ausdrückliches Verbot. Aus struktureller Sicht ist diese Unterscheidung von Bedeutung. Eine Blacklist erlaubt weiterhin eine breite Marktteilnahme und filtert lediglich ausgewählte Symbole heraus. Eine Whitelist schafft dagegen einen geschlossenen operativen Rahmen. Die Handelsaktivitäten können nicht über den bewusst festgelegten Rahmen hinausgehen. Wenn ein Broker neue Instrumente hinzufügt oder die Plattform zusätzliche Symbole bereitstellt, bleiben diese unzugänglich, sofern sie nicht bewusst in die Whitelist-Konfiguration aufgenommen werden.
Warum die Durchsetzung auf Code-Ebene wichtig ist
In Umgebungen, in denen ein gewisser Ermessensspielraum besteht, kann die Symbolauswahl nach und nach über den ursprünglichen Entwurfsrahmen hinausgehen. Selbst in automatisierten Umgebungen können Expert Advisors an mehrere Charts angehängt werden, ohne dass streng kontrolliert wird, welche Instrumente zulässig sind. Im Laufe der Zeit führt dies zu Schwankungen, die bei der Validierung der Strategie nicht berücksichtigt wurden.
Durch die Einbindung einer Modellvalidierung anhand einer Whitelist in die Ausführungs-Pipeline wird die Eignung eines Instruments zu einem kontrollierten Parameter und nicht mehr zu einer einstellbaren Variablen. Das System prüft nicht, ob eine Handelssituation bei einem nicht zugelassenen Symbol „gültig“ aussieht. Es wird lediglich der Autorisierungsstatus überprüft, bevor fortgefahren wird. Dadurch wird sichergestellt, dass die Strategielogik ausschließlich innerhalb ihres erforschten und getesteten Anwendungsbereichs funktioniert.
Vorteile des Whitelist-Modells
Wenn die Durchsetzung der Whitelist als Teil der Handelsinfrastruktur implementiert wird, bietet sie messbare betriebliche Vorteile:
| Vorteil | Auswirkungen auf den Betrieb |
|---|---|
| Definiertes Handelsuniversum | Die Ausführung beschränkt sich weiterhin auf Instrumente, die ursprünglich untersucht und validiert wurden. |
| Schutz vor einer Ausweitung des Anwendungsbereichs | Verhindert die unbeabsichtigte Einbindung zusätzlicher oder neu aufgelisteter Symbole. |
| Integrität des Backtestings | Stellt sicher, dass die Performance-Ergebnisse nicht durch unbeabsichtigt einbezogene Instrumente verzerrt werden. |
| Risikokontrolle | Hält die Gesamtmarktbeteiligung innerhalb vordefinierter Grenzen. |
| Verantwortlichkeit für die Konfiguration | Macht den genehmigten Instrumentensatz transparent und überprüfbar. |
| Sicherheit beim Einsatz | Verhindert die Ausführung, wenn ein EA an ein nicht autorisiertes Chart angehängt wird. |
| Strukturelle Steuerung | Führt eine regelbasierte Steuerung ein, die mit den Risikofiltern institutioneller Anleger vergleichbar ist. |
| Auditierbarkeit | Ermöglicht die Protokollierung abgelehnter Symbole zu Überwachungs- und Auswertungszwecken. |
Praktische Folgen
Ohne eine Durchsetzung auf Symbolebene bleibt die Zulässigkeit von Instrumenten variabel. Diese Flexibilität mag auf den ersten Blick harmlos erscheinen, führt jedoch zu Inkonsistenzen bei den Ausführungsdaten, der Risikoposition und der Performanz-Analyse. Eine Whitelist beseitigt diese Unklarheit, indem sie die Berechtigung in einen festen Konfigurationsparameter umwandelt. Das System stützt sich weder auf Selbstbeherrschung noch auf Urteilsvermögen oder Gedächtnis. Es stützt sich auf Validierungslogik. Nur Instrumente, die die Autorisierungsprüfung bestehen, dürfen mit der Ausführungs-Engine interagieren.
Überblick über die Systemarchitektur
Der Symbol Whitelist Enforcer ist als modulares dreistufiges System aufgebaut, das auf Klarheit, klare Verantwortlichkeitstrennung und langfristige Wartbarkeit ausgelegt ist. Jede Komponente erfüllt eine einzige, genau definierte Aufgabe, während die Koordination zwischen ihnen über einen gemeinsamen, dateibasierten Speichermechanismus erfolgt. Dieses Design gewährleistet, dass Konfiguration, Validierung, Durchsetzung und Berichterstellung synchronisiert bleiben, ohne dass eine enge Kopplung zwischen den Modulen entsteht.
Die Architektur besteht aus:
- Kern-Include-Datei – SymbolWhitelist.mqh
- Dashboard-Indikator – SymbolWhitelistDashboard.mq5
- Expert Advisor zur Durchsetzung – SymbolWhitelistEnforcer.mq5
Alle Komponenten kommunizieren über persistente Speicherdateien (SymbolWhitelist.txt und SymbolWhitelistLog.csv), die als gemeinsame Zustandsschicht des Systems dienen.

Das Dateisystem fungiert als neutrale Synchronisationsschicht. Keine Komponente kommuniziert direkt mit einer anderen; stattdessen liest und schreibt jede Komponente über die Kernbibliothek in den gemeinsamen Speicher. Dadurch werden gegenseitige Abhängigkeiten vermieden und das System bleibt übersichtlich und vorhersehbar.
1. Kern-Include-Datei – SymbolWhitelist.mqh
Die Include-Datei bildet die zentrale Logik-Engine des Systems. Es handelt sich nicht um ein ausführbares Programm, sondern um eine wiederverwendbare Bibliothek, die sowohl vom Dashboard als auch von der Enforcement-EA importiert wird. Durch die Bündelung der gesamten Validierungs- und Dateiverarbeitungslogik an einer einzigen Stelle gewährleistet das System, dass jedes Modul identische Regeln anwendet und mit konsistenten Daten arbeitet.
Seine Aufgaben sind in drei Funktionsbereiche gegliedert.
Verwaltung der Whitelist
Die Bibliothek verwaltet die Persistenz der genehmigten Symbole. SaveWhitelist() schreibt die konfigurierte Symbol-Liste in die Datei SymbolWhitelist.txt, während LoadWhitelist() sie bei Bedarf abruft. Um die Zuverlässigkeit zu gewährleisten, wandelt ParseWhitelist() die gespeicherte, durch Kommas getrennte Zeichenfolge in ein ordnungsgemäß bereinigtes Array um, wodurch eine flexible Formatierung der Benutzereingaben möglich ist, ohne dass die Validierungslogik beeinträchtigt wird.
Symbolüberprüfung
IsSymbolAllowed() ist die entscheidende Kontrollfunktion. Sie lädt die aktuelle Whitelist, wertet sie aus und führt einen Vergleich mit dem zu prüfenden Symbol durch, bei dem die Groß-/Kleinschreibung nicht berücksichtigt wird. Diese Funktion wird vom Enforcer aufgerufen, bevor Korrekturmaßnahmen ergriffen werden.
Protokollierung und Auditierbarkeit
Aus Gründen der Transparenz protokolliert LogBlockedAttempt() jeden abgelehnten Handelsversuch in der Datei SymbolWhitelistLog.csv, einschließlich Zeitstempel, Symbol und Herkunft des Trades (manuell oder EA). ReadLog() ruft die neuesten Einträge für die Anzeige im Dashboard ab. Dieser Mechanismus gewährleistet Nachvollziehbarkeit und operative Verantwortlichkeit.
Da alle Dateioperationen innerhalb dieser Bibliothek zentralisiert und auf Fehler überprüft werden, fungiert sie als zentrale Informationsquelle für das gesamte System.
2. Dashboard-Indikator – SymbolWhitelistDashboard.mq5
Das Dashboard ermöglicht die Konfigurationssteuerung und bietet Echtzeit-Transparenz. Es beeinträchtigt den Handelsbetrieb nicht, sondern setzt den Systemzustand in ein leicht verständliches visuelles Format um. Bei der Initialisierung verwendet das Dashboard den Parameter InpWhitelist und schreibt die zugelassenen Symbole mithilfe der Kernbibliothek in die gemeinsam genutzte Datei. Diese Maßnahme legt den operativen Einsatzbereich des Systems fest.
Optisch wird auf dem Dashboard ein übersichtliches Bedienfeld angezeigt, das Folgendes darstellt:
- Die Liste der zugelassenen Symbole
- Der Autorisierungsstatus des aktuellen Charts
- Kürzlich blockierte Versuche
- Status der Regelumsetzung
Ein Ein-Sekunden-Timer aktualisiert die Anzeige, indem er die Whitelist- und Protokolldaten neu lädt. Dadurch wird sichergestellt, dass die von der EA durchgeführten Durchsetzungsmaßnahmen sofort auf dem Bildschirm angezeigt werden. Das Dashboard dient der Übersichtlichkeit. Dadurch wird die Konfiguration der Regeln sichtbar und die Durchsetzung nachvollziehbar, ohne dass die Durchsetzungslogik in die Benutzeroberfläche selbst eingebettet werden muss.
3. Expert Advisor zur Durchsetzung – SymbolWhitelistEnforcer.mq5
Die Enforcement-EA ist die aktive Steuerungsebene, die für die Durchsetzung von Einschränkungen zuständig ist. Sie arbeitet unabhängig vom Dashboard und konzentriert sich ausschließlich auf die Überwachung und das Ergreifen von Korrekturmaßnahmen. Bei der Initialisierung bestätigt der EA die Aktivierung und überwacht anschließend die vom MetaTrader 5-Terminal generierten OnTradeTransaction-Ereignisse. Dabei werden insbesondere neue Pending Orders (TRADE_TRANSACTION_ORDER_ADD) und ausgeführte Marktgeschäfte (TRADE_TRANSACTION_DEAL_ADD) ausgewertet.
Für jedes relevante Ereignis extrahiert die EA das Symbol und ruft die Funktion IsSymbolAllowed() aus der Kernbibliothek auf. Wenn das Symbol zugelassen ist, werden keine Maßnahmen ergriffen.
Ist das Symbol nicht autorisiert, führt der EA unverzüglich folgende Schritte durch:
- Protokolliert den Versuch über LogBlockedAttempt()
- Storniert Pending Orders oder schließt offene Positionen
- Schreibt eine Bestätigungsmeldung in das Expertenprotokoll
Der EA arbeitet ereignisgesteuert und zustandslos, er kommt ohne Timer oder Hintergrundschleifen aus, er reagiert sofort auf Handelsereignisse und gewährleistet so eine sofortige Durchsetzung.
Verhalten des integrierten Systems
Der Arbeitsablauf folgt einer strukturierten Abfolge. Die Whitelist wird über das Dashboard definiert. Die Kernbibliothek speichert und vereinheitlicht die Validierungslogik. Der Enforcer überwacht die Handelsaktivitäten und setzt bei Bedarf Beschränkungen durch. Jeder blockierte Versuch wird protokolliert und anschließend im Dashboard angezeigt. Diese Trennung stellt sicher, dass Konfiguration, Validierung, Durchsetzung und Berichterstattung unabhängig voneinander bleiben und dennoch aufeinander abgestimmt sind.
MQL5-Implementierung
Nachdem wir die architektonischen Grundlagen geschaffen haben, gehen wir nun vom Konzept zum ausführbaren MQL5-Code über. Die Implementierung entspricht dem in der Systemübersicht beschriebenen modularen Aufbau und besteht aus drei voneinander abhängigen, aber eigenständigen Komponenten: der Kern-Engine, dem Dashboard-Indikator und dem Expert Advisor zur Durchsetzung. Jede Komponente spielt eine entscheidende Rolle dabei, die Handelsdisziplin auf Symbolebene von der Theorie in einen robusten, automatisierten Mechanismus umzusetzen. Durch diese Art der Implementierung gewährleistet das System Konsistenz, Wartbarkeit und eine nahtlose Benutzererfahrung.
Dieser Abschnitt geht über eine bloße Beschreibung des Codes hinaus – er beleuchtet die Überlegungen hinter jeder Entwurfsentscheidung und veranschaulicht, wie sich Handelsdisziplin technisch im Code verankern lässt, was die Integrität der Strategie gewährleistet, Risikokontrollen durchsetzt und den Einfluss von Emotionen auf Handelsentscheidungen verringert.
Teil 1 – Das Kern-Modul (SymbolWhitelist.mqh)
Das Kern-Modul bildet das konzeptionelle Rückgrat des Systems. Indem die gesamte kritische Logik in einer gemeinsamen Include-Datei untergebracht wird, wird sichergestellt, dass sowohl das Dashboard als auch die Durchsetzungs-EA auf der Grundlage derselben Regeln und Daten arbeiten, wodurch Doppelarbeit und mögliche Inkonsistenzen vermieden werden. Dieser Ansatz veranschaulicht das Prinzip der Single Responsibility in der Softwareentwicklung: Eine Komponente übernimmt die Logik und die Datenverarbeitung, während sich andere auf die Darstellung oder die Durchsetzung konzentrieren.
Ein eigener Namensraum, SWL, isoliert alle Funktionen und verhindert so Namenskonflikte mit anderen Handelsprogrammen. Zwei Konstanten, WHITELIST_FILE und LOG_FILE, definieren die Text- und CSV-Dateien, die zur dauerhaften Speicherung von Konfigurations- und Ereignisprotokollen verwendet werden. Diese Entwurfsentscheidung stellt sicher, dass das System für Menschen lesbar, überprüfbar und bei Bedarf bearbeitbar bleibt, während es gleichzeitig vollständig mit den Laufzeitvorgängen kompatibel ist.
//+------------------------------------------------------------------+ //| SymbolWhitelist.mqh| //| Copyright 2026, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ namespace SWL { const string WHITELIST_FILE = "SymbolWhitelist.txt"; const string LOG_FILE = "SymbolWhitelistLog.csv";
Speichern der Whitelist – SaveWhitelist()
Die Funktion SaveWhitelist() speichert die Liste der zulässigen Symbole in einer Datei. Die Funktion öffnet die Datei im Schreibmodus, schreibt die durch Kommas getrennte Zeichenfolge von Symbolen und gibt einen booleschen Status zurück. Durch die externe Speicherung der Konfiguration wird das System vom statischen Code entkoppelt, wodurch dynamische Aktualisierungen ermöglicht werden. Sie können die zulässigen Instrumente ändern, indem Sie die Datei direkt bearbeiten oder das Dashboard mit den aktualisierten Eingabedaten erneut einbinden, sodass eine Neukompilierung des Codes entfällt.
//+------------------------------------------------------------------+ //| Saves the whitelist string to file | //+------------------------------------------------------------------+ bool SaveWhitelist(string whitelist) { int handle = FileOpen(WHITELIST_FILE,FILE_TXT|FILE_WRITE); if(handle==INVALID_HANDLE) return false; FileWrite(handle,whitelist); FileClose(handle); return true; } //+------------------------------------------------------------------+
Durch die Trennung von Konfiguration und Ausführung stellt SaveWhitelist() sicher, dass Aktualisierungen sofort zwischen den Komponenten synchronisiert werden, wodurch eine zentrale verlässliche Datenquelle gewährleistet bleibt. Dieser Ansatz unterstützt zudem automatisierte Arbeitsabläufe in Umgebungen mit mehreren Benutzern oder mehreren Strategien.
Laden der Whitelist – LoadWhitelist()
LoadWhitelist() ist die zugehörige Funktion zum Einlesen der gespeicherten Konfiguration. Zunächst wird geprüft, ob die Datei vorhanden ist; ist dies nicht der Fall, wird eine leere Zeichenkette zurückgegeben, wodurch eine sichere Standardwertvorgabe für die Initialisierung gewährleistet ist. Wenn die Datei vorhanden ist, liest das Programm den Inhalt ein und gibt ihn zur Weiterverarbeitung zurück. Dieser Mechanismus stellt sicher, dass das Dashboard und EA stets mit der aktuellen Konfiguration arbeiten und den ersten Startvorgang sowie versehentliche Löschungen reibungslos bewältigen.
//+------------------------------------------------------------------+ //| Loads the whitelist from file, returns as string | //+------------------------------------------------------------------+ string LoadWhitelist() { if(!FileIsExist(WHITELIST_FILE)) return ""; int handle = FileOpen(WHITELIST_FILE,FILE_TXT|FILE_READ); if(handle==INVALID_HANDLE) return ""; string data = FileReadString(handle); FileClose(handle); return data; } //+------------------------------------------------------------------+
Die Funktion sorgt sowohl bei manuellen als auch bei automatisierten Handelskonfigurationen für Robustheit. Indem es Laufzeitfehler aufgrund fehlender Dateien verhindert, stellt es sicher, dass das System ab dem Zeitpunkt seiner Bereitstellung betriebsbereit ist.
Auswerten der Whitelist – ParseWhitelist()
Während die Whitelist als einfache, durch Kommas getrennte Zeichenkette gespeichert ist, wandelt ParseWhitelist() diese in ein übersichtliches Array aus einzelnen Symbolen um. Es verwendet StringSplit(), um jeden Eintrag zu extrahieren, und entfernt Leerzeichen mit StringTrimLeft() und StringTrimRight(). Leere Einträge werden ignoriert, wodurch unabhängig von der Formatierung der Benutzereingaben ein zuverlässiges und konsistentes Array gewährleistet wird.
//+------------------------------------------------------------------+ //| Parses a comma‑separated whitelist into an array of symbols | //+------------------------------------------------------------------+ int ParseWhitelist(string list,string &result[]) { ArrayResize(result,0); if(list=="") return 0; string parts[]; int count = StringSplit(list,',',parts); for(int i=0; i<count; i++) { string trimmed = parts[i]; StringTrimLeft(trimmed); StringTrimRight(trimmed); if(trimmed!="") { int sz = ArraySize(result); ArrayResize(result,sz+1); result[sz] = trimmed; } } return ArraySize(result); } //+------------------------------------------------------------------+
Beispielsweise könnten Sie EURUSD, GBPUSD, XAUUSD mit uneinheitlichen Leerzeichen eingeben. ParseWhitelist() standardisiert dies auf ["EURUSD","GBPUSD","XAUUSD"] und verhindert so mögliche Unstimmigkeiten oder Fehler bei der Durchsetzung. Diese Liebe zum Detail sorgt dafür, dass das System benutzerfreundlich bleibt und gleichzeitig menschliche Fehler reduziert werden.
Prüfen, ob ein Symbol zulässig ist – IsSymbolAllowed()
Die Funktion IsSymbolAllowed() kapselt die Zulässigkeitsprüfung. Sie lädt und analysiert die Whitelist, durchläuft anschließend das Array und führt dabei einen Vergleich mit dem angegebenen Symbol durch, bei dem die Groß-/Kleinschreibung nicht berücksichtigt wird. Wird eine Übereinstimmung gefunden, gibt die Funktion true zurück; andernfalls false.
//+------------------------------------------------------------------+ //| Checks if a given symbol is in the whitelist | //+------------------------------------------------------------------+ bool IsSymbolAllowed(string symbol) { string list = LoadWhitelist(); string allowed[]; ParseWhitelist(list,allowed); for(int i=0; i<ArraySize(allowed); i++) if(StringCompare(allowed[i],symbol,false)==0) return true; return false; } //+------------------------------------------------------------------+
Die Zentralisierung dieser Überprüfung gewährleistet Einheitlichkeit: Das Dashboard für die visuelle Rückmeldung und der Enforcer für die aktive Blockierung arbeiten nach identischen Regeln. Vergleiche, bei denen Groß- und Kleinschreibung nicht berücksichtigt wird, entsprechen den Konventionen von MetaTrader und verhindern versehentliche Fehlabgleiche. Diese Funktion ist das Herzstück der Disziplin auf Symbolebene und setzt abstrakte Regeln in eine durchsetzbare Logik um.
Protokollierung gesperrter Versuche – LogBlockedAttempt()
Immer wenn ein Handel blockiert wird, protokolliert LogBlockedAttempt() jeden abgelehnten Handelsversuch in der Datei SymbolWhitelistLog.csv, einschließlich Zeitstempel, Symbol und Quelle (manuell oder EA). Dieser transparente Prüfpfad ermöglicht es Händlern, Durchsetzungsmaßnahmen zu überprüfen, impulsive Verhaltensmuster zu erkennen und die Wirksamkeit des Systems zu überprüfen.
//+------------------------------------------------------------------+ //| Appends a blocked attempt to the log file | //+------------------------------------------------------------------+ void LogBlockedAttempt(datetime time,string symbol,string source) { int handle = FileOpen(LOG_FILE,FILE_TXT|FILE_READ|FILE_WRITE|FILE_CSV,','); if(handle==INVALID_HANDLE) return; FileSeek(handle,0,SEEK_END); FileWrite(handle,TimeToString(time),symbol,source); FileClose(handle); } //+------------------------------------------------------------------+
Eine genaue Protokollierung unterstützt zudem die analytische Überprüfung: Im Laufe der Zeit lässt sich quantifizieren, wie oft unzulässige Handelsgeschäfte versucht werden, und entsprechend können Strategien angepasst oder zusätzliche Sicherheitsvorkehrungen automatisiert werden.
Auslesen des Protokolls – ReadLog()
Das Dashboard nutzt die Funktion ReadLog(), um die zuletzt blockierten Versuche anzuzeigen. Es liest die CSV-Datei ein und gibt die Einträge in umgekehrter chronologischer Reihenfolge zurück, wobei die Anzeige auf eine konfigurierbare Höchstanzahl (Standard: 10) begrenzt wird. Dadurch wird eine übersichtliche, aktuelle visuelle Dokumentation gewährleistet, die die Disziplin stärkt und gleichzeitig eine Informationsüberflutung verhindert.
//+------------------------------------------------------------------+ //| Reads the last N log entries (most recent first) | //+------------------------------------------------------------------+ int ReadLog(string ×[],string &symbols[],string &sources[],int max=10) { ArrayResize(times,0); ArrayResize(symbols,0); ArrayResize(sources,0); if(!FileIsExist(LOG_FILE)) return 0; int handle = FileOpen(LOG_FILE,FILE_TXT|FILE_READ|FILE_CSV,','); if(handle==INVALID_HANDLE) return 0; string tmpTime[], tmpSym[], tmpSrc[]; while(!FileIsEnding(handle)) { string t = FileReadString(handle); string s = FileReadString(handle); string src = FileReadString(handle); if(t!="" && s!="") { int sz = ArraySize(tmpTime); ArrayResize(tmpTime,sz+1); ArrayResize(tmpSym,sz+1); ArrayResize(tmpSrc,sz+1); tmpTime[sz] = t; tmpSym[sz] = s; tmpSrc[sz] = src; } } FileClose(handle); int total = ArraySize(tmpTime); int start = (total>max) ? total-max : 0; for(int i=total-1; i>=start; i--) { int sz = ArraySize(times); ArrayResize(times,sz+1); ArrayResize(symbols,sz+1); ArrayResize(sources,sz+1); times[sz] = tmpTime[i]; symbols[sz] = tmpSym[i]; sources[sz] = tmpSrc[i]; } return ArraySize(times); } } //+------------------------------------------------------------------+
Teil 2 – Dashboard-Indikator (SymbolWhitelistDashboard.mq5)
Das Dashboard setzt die abstrakten Regeln in ein visuelles Echtzeit-Cockpit um und bietet so einen vollständigen Überblick über das System, ohne dass dabei Handelsgeschäfte ausgeführt werden. Die Trennung vom Enforcer gewährleistet einen übersichtlichen, modularen Aufbau. Händler können das Dashboard an jedes beliebige Chart anhängen, was flexible Konfigurationen ermöglicht, die sich in verschiedene Strategien oder Handelskonten integrieren lassen.
//+------------------------------------------------------------------+ //| SymbolWhitelistDashboard.mq5| //| Copyright 2026, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.00" #property indicator_chart_window #property indicator_buffers 0 #property indicator_plots 0 #include <SymbolWhitelist.mqh> //--- input parameters input string InpWhitelist = "EURUSD,GBPUSD,XAUUSD"; // Allowed symbols (comma separated) input int InpX = 20; // Panel X offset input int InpY = 20; // Panel Y offset input int InpWidth = 500; // Panel width input int InpHeight = 300; // Panel height //--- colors input color InpBgColor = C'30,30,30'; // Background input color InpBorderColor = C'80,80,80'; // Border input color InpChipBg = C'70,70,70'; // Chip background input color InpChipBorder = C'120,120,120'; // Chip border input color InpTextColor = clrWhite; // Text input color InpAllowedColor = clrLimeGreen; // Allowed indicator input color InpBlockedColor = clrTomato; // Blocked indicator input color InpActiveColor = clrLimeGreen; // Enforcement active //--- global prefixes string PREFIX = "SWL_";
Initialisierung – OnInit()
Nach dem Anhängen schreibt OnInit() die Eingabe-Whitelist über SWL::SaveWhitelist() in die gemeinsam genutzte Datei und stellt so die Übereinstimmung mit dem Enforcer sicher. Anschließend wird das Bedienfeld gezeichnet und ein Timer von einer Sekunde gestartet. Dieser Timer sorgt für Live-Aktualisierungen, sodass das Display dynamisch aktualisiert werden kann, ohne den normalen Chartbetrieb zu beeinträchtigen.
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Save initial whitelist to file SWL::SaveWhitelist(InpWhitelist); CreatePanel(); EventSetTimer(1); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); DeleteObjectsByPrefix(PREFIX); } //+------------------------------------------------------------------+
Timer-Aktualisierungen – OnTimer() und UpdateDashboard()
Jede Sekunde löst der Timer die Funktion UpdateDashboard() aus. Die Funktion lädt die Whitelist und das Protokoll neu und passt die visuellen Elemente an den aktuellen Systemzustand an. Diese Live-Rückkopplungsschleife sorgt für eine kontinuierliche Stärkung der Handelsdisziplin und zeigt an, welche Trades zulässig sind und welche blockiert werden.
//+------------------------------------------------------------------+ //| Custom indicator iteration function (required) | //+------------------------------------------------------------------+ 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[]) { return(rates_total); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { UpdateDashboard(); } //+------------------------------------------------------------------+
Zeichnen des Panels – CreatePanel()
CreatePanel() erstellt eine professionelle, übersichtliche und visuell intuitive Benutzeroberfläche. Es löscht alle bisherigen Objekte, um Unübersichtlichkeit zu vermeiden, zeichnet den Hintergrund, die Abschnittsüberschriften sowie Platzhalter für dynamische Elemente wie Symbolchips, Chart-Status und Protokolleinträge. Einheitliche Namenskonventionen ermöglichen eine übersichtliche Verwaltung von Objekten. Das visuelle Layout nutzt farbcodierte Statusanzeigen, wodurch die Lesbarkeit gewährleistet bleibt und Verwirrung während des Live-Handels vermieden wird.
//+------------------------------------------------------------------+ //| Creates the entire panel | //+------------------------------------------------------------------+ void CreatePanel() { DeleteObjectsByPrefix(PREFIX); //--- Background ObjectCreate(0,PREFIX+"BG",OBJ_RECTANGLE_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_XDISTANCE,InpX); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_YDISTANCE,InpY); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_XSIZE,InpWidth); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_YSIZE,InpHeight); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_BGCOLOR,InpBgColor); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_BORDER_TYPE,BORDER_FLAT); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_COLOR,InpBorderColor); ObjectSetInteger(0,PREFIX+"BG",OBJPROP_BACK,false); //--- Header ObjectCreate(0,PREFIX+"HEADER",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_YDISTANCE,InpY+8); ObjectSetString(0,PREFIX+"HEADER",OBJPROP_TEXT,"SYMBOL WHITELIST ENFORCER"); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_FONTSIZE,12); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"HEADER",OBJPROP_SELECTABLE,false); //--- Separator line ObjectCreate(0,PREFIX+"SEP1",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"SEP1",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"SEP1",OBJPROP_YDISTANCE,InpY+30); ObjectSetString(0,PREFIX+"SEP1",OBJPROP_TEXT,"────────────────────"); ObjectSetInteger(0,PREFIX+"SEP1",OBJPROP_COLOR,InpBorderColor); ObjectSetInteger(0,PREFIX+"SEP1",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"SEP1",OBJPROP_SELECTABLE,false); //--- Allowed symbols section header ObjectCreate(0,PREFIX+"ALLOWED_TITLE",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_YDISTANCE,InpY+40); ObjectSetString(0,PREFIX+"ALLOWED_TITLE",OBJPROP_TEXT,"ALLOWED SYMBOLS"); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_FONTSIZE,10); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"ALLOWED_TITLE",OBJPROP_SELECTABLE,false); //--- Current chart section header ObjectCreate(0,PREFIX+"CURRENT_TITLE",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_YDISTANCE,InpY+95); ObjectSetString(0,PREFIX+"CURRENT_TITLE",OBJPROP_TEXT,"CURRENT CHART"); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_FONTSIZE,10); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"CURRENT_TITLE",OBJPROP_SELECTABLE,false); //--- Log section header ObjectCreate(0,PREFIX+"LOG_TITLE",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_YDISTANCE,InpY+150); ObjectSetString(0,PREFIX+"LOG_TITLE",OBJPROP_TEXT,"TODAY'S BLOCKED ATTEMPTS"); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_FONTSIZE,10); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"LOG_TITLE",OBJPROP_SELECTABLE,false); //--- Footer (enforcement status) ObjectCreate(0,PREFIX+"FOOTER",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_YDISTANCE,InpY+InpHeight-25); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_COLOR,InpActiveColor); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_FONTSIZE,11); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"FOOTER",OBJPROP_SELECTABLE,false); //--- Dynamic elements (chips, status, log lines) for(int i=0; i<10; i++) { string name = PREFIX+"CHIP_"+IntegerToString(i); ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0); ObjectSetInteger(0,name,OBJPROP_BGCOLOR,InpChipBg); ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT); ObjectSetInteger(0,name,OBJPROP_COLOR,InpChipBorder); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_HIDDEN,true); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); name = PREFIX+"CHIPTXT_"+IntegerToString(i); ObjectCreate(0,name,OBJ_LABEL,0,0,0); ObjectSetInteger(0,name,OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,10); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_HIDDEN,true); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); name = PREFIX+"LOG_"+IntegerToString(i); ObjectCreate(0,name,OBJ_LABEL,0,0,0); ObjectSetInteger(0,name,OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,9); ObjectSetString(0,name,OBJPROP_FONT,"Consolas"); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_HIDDEN,true); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false); } //--- Status lines ObjectCreate(0,PREFIX+"STATUS_SYM",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_COLOR,InpTextColor); ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_FONTSIZE,10); ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_SELECTABLE,false); ObjectCreate(0,PREFIX+"STATUS_IND",OBJ_LABEL,0,0,0); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_FONTSIZE,10); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_BACK,false); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_SELECTABLE,false); UpdateDashboard(); } //+------------------------------------------------------------------+
Anzeige zulässiger Symbole – Chip-Zeichnung
Symbole werden als Chips angezeigt, also als optisch deutlich erkennbare, abgerundete Rechtecke mit dem Symbolnamen. Das Layout passt sich dynamisch an die Breite des Fensters an und ermöglicht so einen Überblick über die gesamte Whitelist auf einen Blick. Im Gegensatz zu einfachen Textlisten verringert diese grafische Darstellung die kognitive Belastung und hilft dem Händler, schnell zu erkennen, welche Instrumente zulässig sind.
//+------------------------------------------------------------------+ //| Updates all dynamic panel content | //+------------------------------------------------------------------+ void UpdateDashboard() { string whitelist = SWL::LoadWhitelist(); string allowed[]; int num = SWL::ParseWhitelist(whitelist,allowed); //--- Hide all chips first for(int i=0; i<10; i++) { ObjectSetInteger(0,PREFIX+"CHIP_"+IntegerToString(i),OBJPROP_HIDDEN,true); ObjectSetInteger(0,PREFIX+"CHIPTXT_"+IntegerToString(i),OBJPROP_HIDDEN,true); } //--- Draw chips int x = InpX + 10; int y = InpY + 55; int chipHeight = 22; int margin = 8; for(int i=0; i<num && i<10; i++) { string sym = allowed[i]; int textWidth = StringLen(sym) * 7; int chipWidth = textWidth + 16; if(x + chipWidth > InpX + InpWidth - 10) { x = InpX + 10; y += chipHeight + 5; } string chipName = PREFIX+"CHIP_"+IntegerToString(i); ObjectSetInteger(0,chipName,OBJPROP_XDISTANCE,x); ObjectSetInteger(0,chipName,OBJPROP_YDISTANCE,y); ObjectSetInteger(0,chipName,OBJPROP_XSIZE,chipWidth); ObjectSetInteger(0,chipName,OBJPROP_YSIZE,chipHeight); ObjectSetInteger(0,chipName,OBJPROP_HIDDEN,false); string txtName = PREFIX+"CHIPTXT_"+IntegerToString(i); ObjectSetInteger(0,txtName,OBJPROP_XDISTANCE,x+8); ObjectSetInteger(0,txtName,OBJPROP_YDISTANCE,y+3); ObjectSetString(0,txtName,OBJPROP_TEXT,sym); ObjectSetInteger(0,txtName,OBJPROP_HIDDEN,false); x += chipWidth + margin; }
Aktueller Chart-Status – Dynamisches Feedback
Das Dashboard überprüft das Symbol des Charts, an den es angehängt ist, und zeigt entweder die grüne Anzeige ZULÄSSIG oder die rote Anzeige GESPERRT an. Die Positionierung wird dynamisch angepasst, um Überschneidungen zu vermeiden, und lange Symbolnamen werden elegant gekürzt. Händler können sofort erkennen, ob der aktuelle Chart auf der Whitelist steht, wodurch Fehler aufgrund von Unachtsamkeit oder impulsiven Entscheidungen vermieden werden.
//--- Current chart status with dynamic positioning string currSym = Symbol(); bool allowedNow = SWL::IsSymbolAllowed(currSym); string statusText = allowedNow ? "ALLOWED" : "BLOCKED"; color statusColor = allowedNow ? InpAllowedColor : InpBlockedColor; int statusWidth = StringLen(statusText) * 8; int statusX = InpX + InpWidth - statusWidth - 40; if(statusX < InpX + 10) statusX = InpX + 10; int maxSymbolWidth = statusX - (InpX + 10) - 10; int maxChars = maxSymbolWidth / 7; string prefix = "Symbol: "; int prefixLen = StringLen(prefix); int symLen = StringLen(currSym); string displaySym; if(prefixLen + symLen <= maxChars) displaySym = prefix + currSym; else { int availableForSym = maxChars - prefixLen - 3; if(availableForSym < 1) availableForSym = 1; string truncated = StringSubstr(currSym,0,availableForSym) + "..."; displaySym = prefix + truncated; } ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,PREFIX+"STATUS_SYM",OBJPROP_YDISTANCE,InpY+110); ObjectSetString(0,PREFIX+"STATUS_SYM",OBJPROP_TEXT,displaySym); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_XDISTANCE,statusX); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_YDISTANCE,InpY+110); ObjectSetString(0,PREFIX+"STATUS_IND",OBJPROP_TEXT,statusText); ObjectSetInteger(0,PREFIX+"STATUS_IND",OBJPROP_COLOR,statusColor);
Anzeigen von Protokollen – Ausgerichtete Einträge
Das Dashboard zeigt die zuletzt blockierten Versuche in ausgerichteten Spalten mit fester Zeichenbreite an. In jeder Zeile werden die Uhrzeit (HH:MM), der aufgefüllte Symbolname und ein Symbol angezeigt, das angibt, ob es sich um eine manuelle oder eine EA-Quelle handelt. Diese übersichtliche Gestaltung ermöglicht ein schnelles Verständnis und stärkt die Transparenz und Rechenschaftspflicht des Systems.
//--- Log entries with fixed‑width columns (monospaced font) string times[], symbols[], sources[]; int logCount = SWL::ReadLog(times,symbols,sources,5); int logY = InpY + 165; for(int i=0; i<5; i++) { string name = PREFIX+"LOG_"+IntegerToString(i); if(i < logCount) { string timePart = StringSubstr(times[i],11,5); string symPart = symbols[i]; string icon = (sources[i] == "manual" ? "M" : "EA"); int symLen = StringLen(symPart); if(symLen < 30) { for(int j=symLen; j<30; j++) symPart += " "; } else if(symLen > 30) symPart = StringSubstr(symPart,0,30); string text = StringFormat("%s %s %s",timePart,symPart,icon); ObjectSetString(0,name,OBJPROP_TEXT,text); ObjectSetInteger(0,name,OBJPROP_XDISTANCE,InpX+10); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,logY + i*16); ObjectSetInteger(0,name,OBJPROP_HIDDEN,false); } else ObjectSetInteger(0,name,OBJPROP_HIDDEN,true); } ObjectSetString(0,PREFIX+"FOOTER",OBJPROP_TEXT,"ENFORCEMENT: ● ACTIVE"); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Deletes all objects with a given prefix | //+------------------------------------------------------------------+ void DeleteObjectsByPrefix(string prefix) { for(int i=ObjectsTotal(0)-1; i>=0; i--) { string name = ObjectName(0,i); if(StringFind(name,prefix) == 0) ObjectDelete(0,name); } } //+------------------------------------------------------------------+
Teil 3 – Der Durchsetzungs-EA (SymbolWhitelistEnforcer.mq5)
Die Durchsetzungs-EA ist die aktive Kontrollinstanz der Disziplin auf Symbolebene. Im Gegensatz zum Dashboard greift es automatisch ein und blockiert jeden Handel mit einem Symbol, das nicht auf der Whitelist steht. Da es eigenständig läuft, stellt es sicher, dass das System auch dann weiterfunktioniert, wenn das Dashboard entfernt oder die Charts geschlossen werden.
//+------------------------------------------------------------------+ //| SymbolWhitelistEnforcer.mq5| //| Copyright 2026, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.00" #property strict #property description "Blocks any trade on symbols not in the whitelist." #include <SymbolWhitelist.mqh>
Initialisierung – OnInit()
Beim Start protokolliert der EA eine Bestätigungsmeldung und überprüft, ob der automatische Handel aktiviert ist. Zwar kann das System einen Timer einstellen, doch basiert die Hauptlogik auf einer ereignisgesteuerten Überwachung, wodurch eine sofortige Reaktion auf Handelstransaktionen gewährleistet wird, ohne übermäßig viele CPU-Ressourcen zu beanspruchen.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("SymbolWhitelistEnforcer started. AutoTrading must be enabled."); EventSetTimer(1); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); Print("SymbolWhitelistEnforcer stopped."); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Timer function (not strictly needed) | //+------------------------------------------------------------------+ void OnTimer() { //--- Nothing to do here } //+------------------------------------------------------------------+
Transaktionen überwachen – OnTradeTransaction()
//+------------------------------------------------------------------+ //| Trade transaction handler - block disallowed symbols | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { string symbol = ""; ulong ticket = 0; bool isManual = false; if(trans.type == TRADE_TRANSACTION_ORDER_ADD) { ticket = trans.order; if(ticket == 0) return; if(!OrderSelect(ticket)) { Print("Failed to select order ", ticket); return; } symbol = OrderGetString(ORDER_SYMBOL); isManual = (OrderGetInteger(ORDER_MAGIC) == 0); } else if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { ticket = trans.deal; if(ticket == 0) return; if(HistoryDealSelect(ticket)) { symbol = HistoryDealGetString(ticket, DEAL_SYMBOL); long magic = HistoryDealGetInteger(ticket, DEAL_MAGIC); isManual = (magic == 0); } } else return; if(symbol == "") return; if(!SWL::IsSymbolAllowed(symbol)) { string source = isManual ? "manual" : "EA"; Print("Blocking ", source, " trade on disallowed symbol: ", symbol); SWL::LogBlockedAttempt(TimeCurrent(), symbol, source); if(trans.type == TRADE_TRANSACTION_ORDER_ADD) { MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_REMOVE; req.order = ticket; req.comment = "Symbol not whitelisted"; if(!OrderSend(req, res)) Print("Failed to cancel order ", ticket, ": ", res.comment); } else if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { ulong posTicket = HistoryDealGetInteger(ticket, DEAL_POSITION_ID); if(posTicket == 0) return; if(!PositionSelectByTicket(posTicket)) { Print("Position ", posTicket, " not found."); return; } MqlTradeRequest req = {}; MqlTradeResult res = {}; req.action = TRADE_ACTION_DEAL; req.position = posTicket; req.symbol = symbol; req.volume = PositionGetDouble(POSITION_VOLUME); req.deviation = 5; req.comment = "Symbol not whitelisted"; if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { req.price = SymbolInfoDouble(symbol, SYMBOL_BID); req.type = ORDER_TYPE_SELL; } else { req.price = SymbolInfoDouble(symbol, SYMBOL_ASK); req.type = ORDER_TYPE_BUY; } if(!OrderSend(req, res)) Print("Failed to close position ", posTicket, ": ", res.comment); } } } //+------------------------------------------------------------------+
Der EA überwacht die Ereignisse TRADE_TRANSACTION_ORDER_ADD und TRADE_TRANSACTION_DEAL_ADD. Bei jedem Ereignis extrahiert es das Symbol, überprüft es mithilfe von SWL::IsSymbolAllowed() und reagiert entsprechend. Dieser ereignisgesteuerte Ansatz gewährleistet eine sofortige Durchsetzung und bietet ein solides Sicherheitsnetz gegen impulsive Handelsentscheidungen.
Ermittlung der Herkunft des Trades – MagicNumber
Anhand der MagicNumber unterscheidet der EA manuelle von automatisierten Trades. Diese Informationen werden zu Analysezwecken protokolliert, um Händlern Einblicke zu verschaffen, welche Trades gegen die Whitelist verstoßen hätten und ob automatisierte Strategien die Kontoregeln einhalten.
Blockierung unzulässiger Handelsgeschäfte – Sofortmaßnahmen
Ist ein Symbol nicht zulässig, protokolliert der EA das Ereignis und storniert umgehend Pending Orders oder schließt Marktpositionen mithilfe einer Marktorder in die entgegengesetzte Richtung. Es wird eine geringfügige Abweichung vorgenommen, um den Ausführungserfolg in schnelllebigen Märkten zu verbessern. Dadurch wird sichergestellt, dass keine unzulässigen Positionen offen bleiben, wodurch die Disziplin strukturell und nicht mehr ermessensabhängig wird.
Praktischer Arbeitsablauf
Nach dem Anhängen arbeiten das Dashboard und der EA nahtlos zusammen: Händler konfigurieren zulässige Symbole, überwachen den Live-Status und verlassen sich darauf, dass der Enforcer sie vor jeglichen Abweichungen schützt. Dadurch wird die Disziplin auf Symbolebene vollständig automatisiert, wodurch eine Verhaltensanforderung in eine Eigenschaft auf Systemebene umgewandelt wird.
Tests und Ergebnisse
Nachdem die MQL5-Implementierung abgeschlossen ist, besteht der nächste entscheidende Schritt darin, zu bewerten, wie effektiv das System unter realen Handelsbedingungen die Disziplin auf Symbolebene durchsetzt. In diesem Abschnitt werden die Methodik, die Testszenarien und die beobachteten Ergebnisse vorgestellt, wobei sowohl die Zuverlässigkeit des Durchsetzungsmechanismus als auch dessen Auswirkungen auf die Wahrung der strategischen Integrität hervorgehoben werden.
Im ersten Test ging es darum, zu überprüfen, ob das System in der Lage ist, genau zu bestimmen, ob das Symbol des Charts, an das es angehängt ist, zulässig oder unzulässig ist. Dies ist eine grundlegende Überprüfung, da alle nachfolgenden Durchsetzungsmaßnahmen auf dieser Feststellung beruhen. Das Dashboard und der Enforcer wurden mit mehreren Charts verknüpft, die sowohl genehmigte als auch nicht genehmigte Symbole enthielten, und ihre Reaktionen wurden beobachtet.
Die folgenden Diagramme veranschaulichen die Leistungsfähigkeit des Systems und zeigen Fälle auf, in denen zulässige Symbole korrekt erkannt und als ZULÄSSIG gekennzeichnet wurden, während unzulässige Symbole sofort als GESPERRT markiert wurden. Die Ergebnisse zeigen, dass das System zuverlässig zwischen zugelassenen und nicht zugelassenen Instrumenten unterscheidet und damit eine solide Grundlage für die umfassende Durchsetzung der Handelsvorschriften bildet.
Zulässig

Gesperrt

Validierung von Handelserlaubnis und Sperrung
Der entscheidende Test für das System bestand darin, seine Fähigkeit zur Ausführung von zwei Hauptfunktionen zu überprüfen: (1) nur den Handel mit Symbolen zuzulassen, die auf der Whitelist stehen, und (2) den Handel mit Symbolen zu sperren, die nicht auf der Whitelist stehen.
Die folgende Darstellung visualisiert alle Handelsversuche auf dem betreffenden Chart. Transaktionen, die mit zugelassenen, auf der Whitelist stehenden Symbolen ausgeführt werden, laufen normal ab, während Versuche mit Symbolen, die nicht auf der Whitelist stehen, vom Enforcer abgefangen und blockiert werden. Jeder Handelsversuch – ob zugelassen oder blockiert – wird dargestellt, wodurch ein vollständiger Überblick über den Betrieb des Systems entsteht.

Diese Visualisierung zeigt, dass das Tool wie vorgesehen funktioniert: Symbole auf der Whitelist werden ohne Beeinträchtigung verarbeitet, während die Ausführung aller anderen Symbole wirksam verhindert wird. Indem das System jeden Handelsversuch im Chart anzeigt, sorgt es für vollständige Transparenz, stärkt die Disziplin auf Symbolebene und stellt sicher, dass die Handelsaktivitäten streng innerhalb der vordefinierten strategischen Grenzen bleiben.
Schlussfolgerung
Wir haben einen gezielten Durchsetzungsmechanismus implementiert, der die Einhaltung der Symbolregeln innerhalb der MetaTrader 5-Umgebung von einer Absicht in ein Systemverhalten umsetzt. Die Lösung stellt sicher, dass Handelsaktivitäten ausschließlich auf einer vordefinierten Whitelist von Instrumenten stattfinden, wodurch Strategien vor einer versehentlichen Ausführung auf unbekannten Symbolen geschützt werden.
Die Implementierung besteht aus drei zusammenwirkenden MQL5-Komponenten. Ein gemeinsam genutztes Include-Modul verwaltet die Konfiguration der Whitelist, die Analyse, die Validierungslogik und die Ereignisprotokollierung. Eine Anzeige auf dem Dashboard liefert visuelles Feedback, indem sie die genehmigten Symbole und die zuletzt blockierten Versuche anzeigt. Schließlich überwacht ein Enforcement Expert Advisor die Handelsvorgänge über OnTradeTransaction und storniert umgehend Pending Orders oder schließt Positionen, die auf nicht zugelassenen Symbolen ausgeführt wurden.
Tests bestätigen, dass der Mechanismus die festgelegten Einschränkungen konsequent durchsetzt. Aufträge für Symbole, die auf der Whitelist stehen, werden wie gewohnt ausgeführt, während Versuche, mit nicht zugelassenen Instrumenten zu handeln, abgefangen, entfernt und im Systemprotokoll erfasst werden.
Durch die direkte Einbindung der Validierung in die Handelspipeline wandelt das System die Einhaltung der Symbolregeln von einer Verhaltensgewohnheit in eine programmatische Vorgabe um. Strategien werden daher nur für den vorgesehenen Satz an Symbolen verwendet, während die Erweiterung dieses Spektrums eine explizite und kontrollierte Konfigurationsentscheidung bleibt.
Beigefügte Dateien:
| Dateiname | Beschreibung |
|---|---|
| SymbolWhitelist.mqh | Kern-Modul / gemeinsam genutzte Include-Datei. Enthält die gesamte zentrale Logik für die Verwaltung der Whitelist (SaveWhitelist, LoadWhitelist, ParseWhitelist), die Symbolvalidierung (IsSymbolAllowed) sowie Funktionen zur Protokollierung und Auditierbarkeit (LogBlockedAttempt, ReadLog). Dient als zentrale Informationsquelle für das System. |
| SymbolWhitelistDashboard.mq5 | Dashboard-Indikator. Bietet Konfigurationskontrolle und Echtzeit-Transparenz. Übernimmt die eingegebenen Whitelist, speichert sie in einer Datei und zeigt ein strukturiertes Fenster an, in dem die zugelassenen Symbole, der aktuelle Autorisierungsstatus des Charts, die zuletzt blockierten Versuche sowie der Durchsetzungsstatus angezeigt werden. Aktualisierungen im Ein-Sekunden-Takt. |
| SymbolWhitelistEnforcer.mq5 | Expert Advisor für die Durchsetzung. Dient als aktive Steuerungsebene, die Handelstransaktionen überwacht (OnTradeTransaction). Überwacht neue Pending Orders und ausgeführte Geschäfte, gleicht die Symbole mit der Whitelist ab und storniert oder schließt automatisch alle Geschäfte mit nicht autorisierten Symbolen. Protokolliert alle blockierten Versuche. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/21493
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.
Implementierung des Truncated-Newton-Conjugate-Gradient-Algorithmus in MQL5
MQL5-Handelswerkzeuge (Teil 22): Grafische Darstellung des Histogramms und der Wahrscheinlichkeitsfunktion (PMF) von der Binomialverteilung
MQL5-Handelswerkzeuge (Teil 23): Kameragesteuerte 3D-Diagramme mit DirectX-Unterstützung für Einblicke in die Verteilungen
Verwendung des MQL5-Wirtschaftskalenders zur Nachrichtenfilterung (Teil 2): Verwaltung von Stopps offener Positionen während Nachrichtenereignissen
- 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.