Der MQL5 Standard Library Explorer (Teil 3): Experte für den Kanal der Standardabweichung
Inhalt
- Einführung
- Verstehen der Standardabweichung und ihrer Anwendung im Handel.
- Überblick über die Strategie
- Umsetzung
- Tests
- Schlussfolgerung
- Anlagen
Einführung
Das Ziel des Forschers ist es, den Dingen auf den Grund zu gehen, zu experimentieren und dabei neue Ideen zu entdecken. In der vorangegangenen Diskussion habe ich versucht, diese Reise zu vereinfachen, indem ich die Grundlagen und eine Routine für die Integration von Klassen in Expert Advisors skizziert habe. Das Hauptziel bestand darin, die Klassenschnittstellen zu untersuchen, um ihren Zweck zu verstehen – und dabei zu erkennen, wie die Kommentare der Entwickler den Lernprozess wesentlich erleichtern können.
Abschließend habe ich die wichtigsten Schritte für die Arbeit mit Klassen der Standardbibliothek zusammengefasst. Ein entscheidender Vorteil ist die umfassende Dokumentation, die für MQL5 verfügbar ist. Ähnlich wie bei anderen Programmiersprachen bildet die Dokumentation von MQL5 eine vollständige Wissensbasis. Tatsächlich dient die gesamte MQL5-Website – einschließlich ihrer Artikel, Foren, Bücher und Codebase – insgesamt als reichhaltige Quelle für Referenzmaterial. Jeder Abschnitt soll Entwicklern und Händlern helfen, praktische Herausforderungen im algorithmischen Handel zu lösen.
Die heutige Aufgabe besteht darin, einen Expert Advisor zu erstellen, der mit volatilitätsbasierten Kanälen handelt. Dabei werden wir die Klasse CChartObjectStdDevChannel untersuchen, die uns nicht nur bei der Erstellung eines funktionalen EA helfen wird, sondern auch einen tieferen Einblick in die Standardbibliothek gewährt. Es gibt immer etwas Neues zu lernen, sogar von bestehendem Code – denn jedes Experiment öffnet die Tür zu neuen Ideen.
Stellen Sie sich die heutige Aufgabe wie ein Puzzle vor: Das endgültige Bild ist unser Expert Advisor, und unsere Aufgabe ist es, die Teile anhand der Konzepte und Notizen aus der vorherigen Diskussion zusammenzusetzen.
Bevor wir in die Programmierung eintauchen, werde ich kurz zeigen, wie man die MQL5-Dokumentation verwendet, um eine Bibliotheksdatei zu verstehen – ein wichtiger erster Schritt, bevor man sich mit ihrer Implementierung beschäftigt. Entwickler, die neue Module erstellen, sollten stets auf die Kommentare der Programmierer achten und eine klare Dokumentation beisteuern, um anderen die Navigation in der Entwicklungslandschaft zu erleichtern. Schauen Sie sich zum Beispiel den untenstehenden Codeausschnitt an, den hervorgehobenen Kommentar.
//+------------------------------------------------------------------+ //| ChartObjectsChannels.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ //| All channels. | //+------------------------------------------------------------------+ #include "ChartObjectsLines.mqh" //+------------------------------------------------------------------+ //| Class CChartObjectChannel. | //| Purpose: Class of the "Equidistant channel" object of chart. | //| Derives from class CChartObjectTrend. | //+------------------------------------------------------------------+ class CChartObjectChannel : public CChartObjectTrend { public: CChartObjectChannel(void); ~CChartObjectChannel(void); //--- method of creating the object bool Create(long chart_id,const string name,const int window, const datetime time1,const double price1, const datetime time2,const double price2, const datetime time3,const double price3); //--- method of identifying the object virtual int Type(void) const { return(OBJ_CHANNEL); } };
Am Ende dieser Diskussion werden Sie gelernt haben, wie man:
- Die CTrade-Klasse als Kernstück für die Auftrags- und Positionsverwaltung verwendet.
- Die ChartObjectsChannels-Klassenbibliothek als Grundlage für die Strategielogik und Signalgenerierung verwendet.
- Diese Klassen auf praktische Weise in einen voll funktionsfähigen Expert Advisor integriert.
- Einer vollständige Handelsstrategie entwickelt und strukturiert.
- Wirksamer Risikomanagementtechniken anwendet.
- Den Strategy Tester nutzt, um die Leistung Ihres Expert Advisors zu bewerten und zu optimieren.
Verstehen des Zwecks einer Klasse durch Studium der Dokumentation oder der MQL5-Referenz
In Teil 2 haben wir uns auf die Routine konzentriert, die ich für die Integration von Klassen in einen Expert Advisor vorgestellt habe. In diesem Abschnitt werden wir jedoch einen anderen Ansatz wählen – einen, der Ihnen hilft, Bibliotheksklassen mithilfe der MQL5-Dokumentation schnell zu verstehen.
Unten sehen Sie eine Illustration eines leistungsstarken integrierten Tools: die MQL5-Referenz, die direkt von MetaEditor aus zugänglich ist. Da wir die ChartObjectsChannel-Bibliothek verwenden werden, habe ich gezeigt, wie man effizient auf sie zugreifen und sie untersuchen kann.
Suchen Sie im Quellcode der Bibliothek die Klasse, die Sie untersuchen möchten – in diesem Fall CChartObjectsChannel. Klicken Sie mit der rechten Maustaste auf den Klassennamen und wählen Sie den Link zur Hilfe. Dies öffnet das MQL5-Referenzfenster, in dem Sie detaillierte Informationen über die Klasse lesen können.
Wie ich bereits erwähnt habe, bietet die Dokumentation einen knappen Überblick, der oft ausreicht, um den Zweck der Klasse zu verstehen. Sein volles Potenzial lässt sich jedoch am besten durch praktisches Ausprobieren erschließen.
Abbildung 1 zeigt, wie die MQL5-Referenz in MetaEditor verwendet wird, während Abbildung 2 einen alternativen Ansatz zeigt, bei dem die Online-MQL5-Dokumentation für denselben Zweck verwendet wird.

Abb. 1. MQL5-Referenz verwenden

Abb. 2. MQL5-Dokumentation verwenden
Überblick über die Strategie
Bevor sie Algorithmen entwickeln, beginnen die meisten Händler mit der visuellen Analyse von Marktpreisen anhand von Chart-Objekten. Dieser Ansatz fühlt sich intuitiv an, da Werkzeuge wie horizontale Linien für Unterstützung und Widerstand, Trendlinien und Kanäle einfach direkt auf dem Chart platziert werden können. Die eigentliche Herausforderung ergibt sich jedoch, wenn man versucht, diese visuellen Analysekonzepte in Code zu übersetzen – insbesondere für diejenigen, die mit der MQL5-Entwicklungsumgebung noch nicht vertraut sind.
In dieser Diskussion werden wir diese Lücke schließen, indem wir untersuchen, wie diese manuellen Analysetools mit Hilfe der MQL5-Standardbibliothek in kundenspezifische algorithmische Lösungen umgewandelt werden können. Die Schönheit des MQL5-Frameworks liegt in seiner objektorientierten Struktur und der umfassenden Dokumentation, die die Standardklassen begleitet. Dies ermöglicht es Entwicklern, chartbasierte Tools leicht zu verstehen und zu erweitern, ohne das Rad neu erfinden zu müssen.
Wie in den vorangegangenen Abschnitten gezeigt wurde, gibt es mehrere Möglichkeiten, die Funktionalität von Bibliotheksklassen zu erkunden und zu verstehen. Eine besonders effiziente Methode ist die Verwendung des im MetaEditor integrierten Referenzsystems, das eine detaillierte Dokumentation für jede Klasse, einschließlich ihrer Mitglieder und Methoden, bereitstellt. Dies ist besonders nützlich, wenn Sie komplexe Komponenten wie die in der Datei ChartObjectsChannels.mqh untersuchen.
Bei der Überprüfung dieser Datei stellen wir fest, dass sie mehrere kanalorientierte Klassen enthält, darunter:
- CChartObjectChannel
- CChartObjectRegression
- CChartObjectStdDevChannel
- CChartObjectPitchfork
Für unsere heutige Entwicklung werden wir uns auf die Klasse CChartObjectStdDevChannel konzentrieren. Diese Klasse stellt einen Standardabweichungskanal dar, ein beliebtes Analyseinstrument, das die Preisabweichung von einem linearen Trend misst. Es bietet sowohl eine visuelle Struktur für die manuelle Chartanalyse als auch eine programmierbare Schnittstelle für algorithmische Strategien.
Unser Ziel ist es, dieses Channel-Objekt in einen Expert Advisor (EA) zu integrieren, damit dieser auf der Grundlage der Preisentwicklung relativ zu den Channel-Grenzen Ein- und Ausstiegssignale generieren kann. Durch diesen Prozess werden wir einen funktionsfähigen EA erstellen und außerdem einen tieferen Einblick erhalten, wie die Standardbibliothek von MQL5 die Entwicklung von professionellen Handelswerkzeugen vereinfacht.
Im Wesentlichen kann der Standardabweichungskanal manuell zu einem Chart hinzugefügt werden, aber unser Ziel ist es, seine Erstellung, Aktualisierung und Interpretation zu automatisieren und so ein vertrautes manuelles Werkzeug in eine leistungsstarke Komponente der systematischen Handelslogik zu verwandeln.

Abb. 3. Hinzufügen des StdDev-Kanals zum Chart
Verstehen der Standardabweichung und ihrer Anwendung im Handel.
Im Handel und in der quantitativen Analyse ist die Varianz ein statistisches Schlüsselkonzept, das zur Messung der Marktvolatilität verwendet wird, d. h. wie weit die Kurse von ihrem Durchschnittswert abweichen. Das Verständnis dieses Konzepts hilft Händlern dabei, festzustellen, ob der Markt ruhig oder sehr aktiv ist, was wiederum Entscheidungen über Risiko, Positionsgröße und Signalvalidierung beeinflusst.
1. Das Konzept der Varianz
Die Varianz bzw. Standardabweichung (bezeichnet mit σ) misst die Streuung der Daten um ihren Mittelwert. Bei der Preisanalyse gibt sie an, wie stark die einzelnen Preise vom Durchschnittspreis in einem bestimmten Zeitraum abweichen.
Mathematisch ist sie definiert als:

wobei:
- N – die Anzahl der Kursdatenpunkte (z. B. Kerzen oder Balken),
- x_i – jeder Kurswert (normalerweise der Schlusskurs),
- X-Balken – Durchschnittspreis (Mittelwert) im gleichen Zeitraum.
- Ein großes σ impliziert eine höhere Volatilität – die Preise weichen weit vom Mittelwert ab.
- Ein kleines σ deutet auf stabile Preise hin, die sich eng um den Mittelwert gruppieren.
2. Anwendung der Standardabweichung im Handel
In der Praxis verwenden Händler die Standardabweichung, um die Volatilität zu visualisieren und Handelsmöglichkeiten zu erkennen. Eine der gebräuchlichsten Implementierungen sind Volatilitätskanäle, wie der Standardabweichungskanal (StdDev-Kanal).
(a) Standardabweichung Kanal
Dieser Kanal besteht aus einer zentralen Basislinie (häufig eine Trendlinie oder lineare Regression) und zwei äußeren Linien, die mit einer bestimmten Anzahl von Standardabweichungen darüber und darunter eingezeichnet sind.
Die Gleichungen lauten:
- Oberer Kanal = Grundlinie+k×σ
- Unterer Kanal = Grundlinie-k×σ
Wobei
k ist der Abweichungsmultiplikator (in der Regel 1, 2 oder 3).
Zum Beispiel,
k=2 deckt etwa 95% der Preisschwankungen unter normalen Marktbedingungen ab (unter der Annahme einer Normalverteilung). Diese Kanalgrenzen helfen Händlern bei der Visualisierung von Volatilitätsumschlägen, die zur Erkennung von Ausbrüchen, Pullbacks oder Erschöpfungszonen verwendet werden können.
Umsetzung
Die Bibliothek ChartObjectsChannels.mqh definiert mehrere kanalbasierte Klassen, die von CChartObjectTrend abgeleitet sind, darunter den Standardabweichungskanal, den Regressionskanal und den Äquidistanten Kanal. Jede dieser Klassen bietet eine Möglichkeit, Preiskanäle im Chart darzustellen und zu manipulieren. Wir werden uns auf das CChartObjectStdDevChannel konzentrieren, das das Konzept einer Regressionslinie mit der statistischen Aussagekraft der Standardabweichung zur Messung der Preisstreuung kombiniert.
Um CChartObjectStdDevChannel effektiv in einen Expert Advisor zu integrieren, werden wir eine praktische Entwicklungssequenz befolgen, die sowohl Programmierung als auch analytisches Verständnis kombiniert.
Zielsetzungen- Verwenden der Klasse CChartObjectStdDevChannel der Standardbibliothek, um einen Standardabweichungskanal programmatisch zu erstellen und zu steuern.
- Automatisieren der Signalerzeugung, wenn der Preis mit dem Kanal interagiert oder aus ihm ausbricht.
- Integrieren der Logik der Auftragsverwaltung mit Hilfe der Klasse CTrade.
- Kombinieren sowohl die Chart-Visualisierung als auch die Handelslogik zu einem vollständigen Expert Advisor.
Konzeptionelle Grundlage
Alle Kanalobjekte in MQL5 haben eine ähnliche Struktur und werden von CChartObjectTrend abgeleitet. Sie bietet grundlegende Funktionen für die Bearbeitung von Linien wie das Setzen von Ankern, Farben und Sichtbarkeit. Die Klasse CChartObjectChannel erweitert diese Grundlage um eine parallele Linienstruktur, die einen äquidistanten Preiskorridor bildet.
Der CChartObjectStdDevChannel baut darauf auf, indem er statistische Abweichungsbänder einführt, die um eine lineare Regressionslinie herum berechnet werden. Diese oberen und unteren Grenzen helfen dabei, Zonen potenzieller Übertreibungen oder Mittelwertumkehr zu identifizieren – ein Konzept, das häufig bei volatilitätsbasierten Strategien verwendet wird.
Der erste Schritt besteht darin, unseren Code zu untersuchen und die für die Integration erforderlichen Methoden zu ermitteln. Sobald wir sie gefunden haben, können wir ein klares Verfahren für die Implementierung des CChartObjectStdDevChannel in unserem Expert Advisor skizzieren. Um den Prozess leichter nachvollziehen zu können, habe ich die wichtigsten Integrationsschritte in einer Tabelle nach dem folgenden Codeschnipsel zusammengefasst.
Bitte beachten Sie, dass dies nur ein Teilauszug aus der Header-Datei ist, der hier aufgenommen wurde, um sich ausschließlich auf die Klasse CChartObjectStdDevChannel zu konzentrieren.
//+------------------------------------------------------------------+ //| Class CChartObjectStdDevChannel. | //| Purpose: Class of the "Standrad deviation channel" | //| object of chart. | //| Derives from class CChartObjectTrend. | //+------------------------------------------------------------------+ class CChartObjectStdDevChannel : public CChartObjectTrend { public: CChartObjectStdDevChannel(void); ~CChartObjectStdDevChannel(void); //--- methods of access to properties of the object double Deviations(void) const; bool Deviations(const double deviation) const; //--- method of creating the object bool Create(long chart_id,const string name,const int window, const datetime time1,const datetime time2,const double deviation); //--- method of identifying the object virtual int Type(void) const { return(OBJ_STDDEVCHANNEL); } //--- methods for working with files virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CChartObjectStdDevChannel::CChartObjectStdDevChannel(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CChartObjectStdDevChannel::~CChartObjectStdDevChannel(void) { } //+------------------------------------------------------------------+ //| Create object "Standard deviation channel" | //+------------------------------------------------------------------+ bool CChartObjectStdDevChannel::Create(long chart_id,const string name,const int window, const datetime time1,const datetime time2,const double deviation) { if(!ObjectCreate(chart_id,name,OBJ_STDDEVCHANNEL,window,time1,0.0,time2,0.0)) return(false); if(!Attach(chart_id,name,window,2)) return(false); if(!Deviations(deviation)) return(false); //--- successful return(true); } //+------------------------------------------------------------------+ //| Get value of the "Deviations" property | //+------------------------------------------------------------------+ double CChartObjectStdDevChannel::Deviations(void) const { //--- check if(m_chart_id==-1) return(EMPTY_VALUE); //--- result return(ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION)); } //+------------------------------------------------------------------+ //| Set value for the "Deviations" property | //+------------------------------------------------------------------+ bool CChartObjectStdDevChannel::Deviations(const double deviation) const { //--- check if(m_chart_id==-1) return(false); //--- result return(ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,deviation)); } //+------------------------------------------------------------------+ //| Writing parameters of object to file | //+------------------------------------------------------------------+ bool CChartObjectStdDevChannel::Save(const int file_handle) { //--- check if(file_handle==INVALID_HANDLE || m_chart_id==-1) return(false); //--- write if(!CChartObjectTrend::Save(file_handle)) return(false); //--- write value of the "Deviations" property if(FileWriteDouble(file_handle,ObjectGetDouble(m_chart_id,m_name,OBJPROP_DEVIATION))!=sizeof(double)) return(false); //--- successful return(true); } //+------------------------------------------------------------------+ //| Reading parameters of object from file | //+------------------------------------------------------------------+ bool CChartObjectStdDevChannel::Load(const int file_handle) { //--- check if(file_handle==INVALID_HANDLE || m_chart_id==-1) return(false); //--- read if(!CChartObjectTrend::Load(file_handle)) return(false); //--- read value of the "Deviations" property if(!ObjectSetDouble(m_chart_id,m_name,OBJPROP_DEVIATION,FileReadDouble(file_handle))) return(false); //--- successful return(true); }
Integrationsprogramm:
| Schritt | Aktion | Zweck |
|---|---|---|
| 1 | Einbinden von ChartObjectsChannels.mqh | Zugriff auf alle Standardkanalklassen, einschließlich CChartObjectStdDevChannel. |
| 2 | Deklarieren von CChartObjectStdDevChannel | Vorbereiten des Objekts des Kanals der Standardabweichung für die Erstellung und Bearbeitung vor. |
| 3 | Aufruf von Create() | Zeichnen des Kanals auf dem Chart mit den ausgewählten Preis- und Zeitkoordinaten. |
| 4 | Einstellen der Eigenschaften von Deviations() | Definieren der Anzahl der Standardabweichungen für die Skalierung der Kanalbreite. |
| 5 | Anpassen des Erscheinungsbilds | Zum Anpassen von Farben, Stile und Beschriftungen an, um die Übersichtlichkeit zu erhöhen und einen besseren Einblick in den Handel zu erhalten. |
| 6 | Hinzufügen der Signallogik | Nutzen der Preisinteraktion mit den oberen und unteren Bändern, um automatische Handelssignale auszulösen. |
| 7 | Regelmäßige Aktualisierung | Berechnen und Aktualisieren des Kanals bei jedem neuen Balken, um die Genauigkeit aufrecht zu halten. |
ExpertStdDevChannel
1. Datei-Header und Kompilierzeit-Eigenschaften
In diesem Abschnitt werden die Identität des EA und die Kompilierzeitbeschränkungen erklärt. Die Zeilen mit #property liefern die Metadaten der Datei an (Copyright, Link, Version), während #property strict den Compiler anweist, strengere Typ- und Semantikprüfungen durchzuführen – eine defensive Wahl, die Typinkongruenzen und andere Probleme zur Erstellungszeit aufdeckt und das Verhalten während der Entwicklung und des Testens vorhersehbarer macht.
//ExpertStdDevChannel.mq5 #property copyright "Copyright 2025, Clemence Benjamin" #property link "https://www.mql5.com/go?link=https://www.mql5.com/en/users/billionaire2024/seller" #property version "1.00" #property strict
2. Bibliothekseinfuhr und Begründung
Hier importieren wir zwei Standard-Bibliotheksmodule, von denen der EA abhängt: ChartObjectsChannels.mqh liefert die Kanalklassen (einschließlich CChartObjectStdDevChannel), sodass der EA die Zeichnungs- und Objektsemantik der Plattform wiederverwenden kann, und Trade.mqh liefert den CTrade-Wrapper, der die Auftragsplatzierung und die Handhabung der Ergebnisse vereinfacht. Durch den Import dieser Module wird eine Neuimplementierung von Low-Level-Funktionen vermieden und die Übersichtlichkeit und Wartbarkeit des Codes erhöht.
#include <ChartObjects\ChartObjectsChannels.mqh> #include <Trade\Trade.mqh> // For CTrade
3. Nutzerseitige Eingänge (Konfigurationsoberfläche)
Dieser Block macht die Parameter des EA für den Nutzer und den Strategietester sichtbar. Jede Eingabe erzeugt einen einstellbaren Regler-Abweichungsmultiplikator, die Größe des Regressionsfensters, die Losgröße, die magische Zahl, den SL-Puffer, die aktivierten Handelsrichtungen sowie die Visualisierungs- und Modusflags. Diese Werte bestimmen das Verhalten des EA und müssen unter Berücksichtigung der Datenanforderungen (z. B. muss PeriodBars groß genug für eine Regression sein) und der Broker-Einschränkungen (z. B. SLBuffer) gewählt werden.
//--- Inputs input double Deviation = 2.0; // StdDev multiplier input int PeriodBars = 50; // Bars for channel calculation input double LotSize = 0.1; // Trade size input int Magic = 12345; // EA identifier input double SLBuffer = 20.0; // Points buffer for SL (increased for min distance) input bool EnableSells = true; // Enable sell trades (set to false for buys only) input bool EnableBuys = true; // Enable buy trades input bool DrawGraphical= true; // Draw channel object for visualization (disable for faster backtest) input bool UseMeanReversion = true; // True: Mean reversion (bounce buys/sells); False: Breakout (break buys/sells)
4. Globale Objekte und interner Zustand
Diese Deklarationen legen den Laufzeitzustand und die Objektlebenszyklen fest, die im gesamten EA verwendet werden. CTrade trade ist die Instanz für die Handels-Engine, die wir zur Ausführung von Aufträgen aufrufen werden; CChartObjectStdDevChannel *channel ist ein optionaler Zeiger für die Chart-Visualisierung, der sicher zugewiesen und freigegeben werden muss (new / delete); g_upper, g_lower und g_median enthalten das manuelle numerische Modell des EA für den Kanal, und g_levels_valid zeigt an, ob die berechneten Levels vertrauenswürdig sind. Die Trennung des numerischen Modells von visuellen Objekten garantiert eine reproduzierbare Logik in Backtests.
//--- Global objects CTrade trade; CChartObjectStdDevChannel *channel; // Optional for drawing double g_upper, g_lower, g_median; // Manually computed levels bool g_levels_valid = false; // Flag for valid computation
5. Initialisierung: Einrichtung der Ressourcen und erste Berechnung (OnInit)
OnInit() führt die Ressourcenzuweisung und die erste Validierung durch. Es markiert CTrade mit der magischen EA-Nummer, ordnet optional (neu) zu und versucht, den grafischen StdDev-Kanal zu erstellen, und kehrt elegant zurück, wenn die Visualisierung fehlschlägt (löscht den Zeiger und fährt fort). Schließlich führt er UpdateChannel() aus, um die anfänglichen numerischen Niveaus zu berechnen; wenn nicht genügend Daten vorhanden sind, protokolliert der EA die Bedingung und handelt nicht, bis gültige Niveaus verfügbar sind. Dadurch wird sowohl die visuelle als auch die programmatische Bereitschaft hergestellt, bevor der EA in die Laufzeitschleife eintritt.
int OnInit() { trade.SetExpertMagicNumber(Magic); if (DrawGraphical) { channel = new CChartObjectStdDevChannel(); if (!channel.Create(0, "StdDevChannel", 0, iTime(_Symbol, PERIOD_CURRENT, PeriodBars), iTime(_Symbol, PERIOD_CURRENT, 0), Deviation)) { Print("Failed to create graphical StdDev channel (continuing without viz)"); delete channel; channel = NULL; } else { channel.Deviations(Deviation); Print("Graphical channel created for visualization"); } } // Initial calculation if (UpdateChannel()) g_levels_valid = true; else Print("Initial channel calculation failed - need more bars"); Print("Channel EA initialized successfully. Mode: ", (UseMeanReversion ? "Mean Reversion" : "Breakout")); return INIT_SUCCEEDED; }
6. Laufzeitschleife und Orchestrierung (OnTick) – eine Übersicht
OnTick() ist der Herzschlag des EAs, in dem Statusaktualisierungen, Validierungen und Handelsentscheidungen stattfinden. Die Routine löst zunächst eine deterministische Neuberechnung bei einem neuen abgeschlossenen Balken aus, greift nur bei Bedarf auf eine On-Tick-Neuberechnung zurück, liest Live-Kurse und Broker-Parameter ein, bestätigt die numerische Gültigkeit und führt dann die Signalerkennung und die Handelsplatzierung aus, wenn alle Kontrollen bestanden sind. Bei dieser Struktur werden Berechnungen von abgeschlossenen Balken aus Gründen des Determinismus bevorzugt und die Neuberechnung auf Tick-Basis nur als Wiederherstellungsmaßnahme vorbehalten.
void OnTick() { static int skip_count = 0; // Update on new bar if (IsNewBar()) { if (!UpdateChannel()) { Print("Channel update failed - skipping until valid"); g_levels_valid = false; return; } g_levels_valid = true; } if (!g_levels_valid) { // Fallback: Recalc on tick if needed (rare) CalculateStdDevChannel(); if (g_upper == 0.0 || g_lower == 0.0 || g_upper <= g_lower) { if (++skip_count % 100 == 0) // Log every 100 ticks to avoid spam Print("Invalid manual channel values (", skip_count, " ticks skipped)"); return; } // Reset counter on successful recalc skip_count = 0; g_levels_valid = true; } ... }
7. Lesen von Marktdaten, Validierung und Maklereinschränkungen
Bei jedem Tick zieht der EA aktuelle Marktdaten (Bid, Ask), Symbolmeta (Punkt, Ziffern) und überprüft, ob die berechneten Levels einen korrekten Kanal bilden (g_upper > g_lower). Er ruft das SYMBOL_TRADE_STOPS_LEVEL des Brokers ab und konvertiert es in einen Preisabstand minDist, um zu gewährleisten, dass die SL/TP-Platzierungen den Brokerregeln entsprechen. Diese Prüfungen verhindern, dass Aufträge abgelehnt werden und logisch ungültige Operationen durchgeführt werden.
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); // Validate levels if (g_upper <= g_lower) { Print("Invalid channel levels: Upper=", g_upper, " Lower=", g_lower, " - skipping tick"); return; } // Get minimum stop distance long minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL); double minDist = minStopLevel * point;
8. Einreiseverhinderung und Einzelplatzpolitik
Bevor der EA neue Aufträge absendet, stellt er sicher, dass er keine offenen Positionen für dieses Symbol mit dem angegebenen Magic besitzt. Diese Politik mit nur einer Position pro Symbol pro EA vereinfacht die Zustandsverwaltung und die Risikokontrolle. Wenn keine Positionen gefunden werden, wertet der EA die Kauf- und Verkaufslogik aus, die durch EnableBuys, EnableSells und den gewählten Handelsmodus (Mean-Reversion vs. Breakout) bedingt ist. Diese Schranke verhindert überlappende Positionen und unkontrollierte Hebelauswirkungen.
// No open positions (check for this symbol and magic) if (PositionsTotalByMagic() == 0) { // buy and sell logic follows... }
9. Kaufsignalerzeugung und Konstruktion von Auftragsparametern
Die Kauflogik verzweigt sich durch UseMeanReversion: Im Modus mean-reversion (Rückkehr zum Mittelwert) sucht der EA nach einem Abprallen vom unteren Band (vorheriges Tief ≤ unten und aktuelles Geld > unten); im Breakout-Modus sucht er nach Ask > oberes Band. Bei einem Kaufsignal werden entry, sl und tp (normalisiert auf Ziffern) gebildet, minDist erzwungen, indem SL bei Bedarf angepasst wird, überprüft, ob TP ausreichend weit entfernt ist, und dann trade.Buy(...) aufgerufen. Erfolgs- und Fehlerpfade werden mit ResultRetcode() und beschreibenden Meldungen zur Fehlerbehebung protokolliert. Durch diese Konstruktion wird sichergestellt, dass die Aufträge den Präzisions- und Vermittlungsvorgaben entsprechen.
if (EnableBuys) { bool buySignal = false; if (UseMeanReversion) { // Mean reversion buy: Bounce off lower (current > lower, prior low <= lower) double prevLow = iLow(_Symbol, PERIOD_CURRENT, 1); buySignal = (bid > g_lower && prevLow <= g_lower); } else { // Breakout buy: Break above upper buySignal = (ask > g_upper); } if (buySignal) { double entry = ask; double sl = NormalizeDouble(g_lower - (SLBuffer * point), digits); double tp = NormalizeDouble(g_upper, digits); // Adjust SL to meet min distance if (entry - sl < minDist) sl = NormalizeDouble(entry - minDist, digits); // Check TP min distance if (tp - entry < minDist) { Print("TP too close for buy (dist=", (tp - entry)/point, " < ", minDist/point, ") - skipping"); } else if (trade.Buy(LotSize, _Symbol, entry, sl, tp, "Channel Buy")) { Print("Buy order placed: Entry=", entry, " SL=", sl, " TP=", tp, " (TP > SL)"); } else { Print("Buy order failed: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription()); } } }
10. Verkaufssignalerzeugung und gespiegelte Sicherheitsvorkehrungen
Die Verkaufslogik spiegelt die Kauflogik mit umgekehrten Bedingungen wider: Mean Reversion prüft das vorherige Hoch ≥ Upper und dann die aktuelle Ask < Upper, um einen Rückprall zu bestätigen; Breakout prüft Bid < Lower. Der Einstieg erfolgt über Bid, der SL wird über dem oberen Band platziert, der TP am unteren Band. Der EA verifiziert TP < SL, erzwingt minDist für SL und TP, normalisiert die Werte und ruft trade.Sell(...) auf. Ergebnisse und Fehler werden mit expliziten Details protokolliert, um die sofortige Fehlersuche zu erleichtern.
if (EnableSells) { bool sellSignal = false; if (UseMeanReversion) { // Mean reversion sell: Bounce off upper (current < upper, prior high >= upper) double prevHigh = iHigh(_Symbol, PERIOD_CURRENT, 1); sellSignal = (ask < g_upper && prevHigh >= g_upper); } else { // Breakout sell: Break below lower sellSignal = (bid < g_lower); } if (sellSignal) { double entry = bid; double sl = NormalizeDouble(g_upper + (SLBuffer * point), digits); double tp = NormalizeDouble(g_lower, digits); // For sells: Ensure TP < SL (lower < upper + buffer, always true) if (tp >= sl) { Print("Invalid TP/SL for sell (TP=", tp, " >= SL=", sl, ") - logic error"); return; } // Adjust SL to meet min distance if (sl - entry < minDist) sl = NormalizeDouble(entry + minDist, digits); // Check TP min distance (entry - tp >= minDist) double profitDist = entry - tp; if (profitDist < minDist) { Print("TP too close for sell (profit dist=", profitDist/point, " < ", minDist/point, ") - skipping"); } else if (trade.Sell(LotSize, _Symbol, entry, sl, tp, "Channel Sell")) { Print("Sell order placed: Entry=", entry, " SL=", sl, " TP=", tp, " (TP < SL)"); } else { Print("Sell order failed: ", trade.ResultRetcode(), " - ", trade.ResultRetcodeDescription()); Print("Sell details: Entry=", entry, " SL=", sl, " TP=", tp, " MinDist=", minDist/point); } } }
11. Numerischer Kern – lineare Regression, Residuen und σ (CalculateStdDevChannel)
Diese Funktion ist das maßgebliche numerische Modell des EA. Es kopiert fertiggestellte Balken, ordnet die Indizes konsistent zu, sodass i=1..n abgeschlossene Balken sind, wobei x den ältesten (0) bis zum neuesten (n-1) Balken umfasst, berechnet die Regressionssummen, berechnet die Steigung a und den Achsenabschnitt b mit dem Verfahren der kleinsten Quadrate, wertet die Regression am neuesten abgeschlossenen Balken aus, um die mittlere Mittellinie zu erhalten, berechnet die quadrierten Residuen und leitet die Standardabweichung der Residuen unter Verwendung des für die Regression geeigneten n-2-Nenners ab. Der Offset entspricht der Abweichung * σ, und die Grenzen g_upper/g_lower sind der Median ± Offset. Robuste Wächter können mit unzureichenden Daten und degenerierten Nennern umgehen.
void CalculateStdDevChannel() { MqlRates rates[]; ArraySetAsSeries(rates, true); int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, PeriodBars + 1, rates); // +1 for safety if (copied < PeriodBars) { Print("Insufficient bars for calculation: ", copied, " < ", PeriodBars); g_upper = g_lower = g_median = 0.0; return; } // Use completed bars: shift 1 (last complete) to PeriodBars (oldest) int n = PeriodBars; double sum_x = 0.0, sum_y = 0.0, sum_xy = 0.0, sum_x2 = 0.0; for (int i = 1; i <= n; i++) // i=1: last complete bar (x=n-1), i=n: oldest (x=0) { double x = n - i; // x=0 (oldest) to x=n-1 (newest completed) double y = rates[i].close; sum_x += x; sum_y += y; sum_xy += x * y; sum_x2 += x * x; } // Linear regression slope (a) and intercept (b) double denom = (n * sum_x2 - sum_x * sum_x); if (denom == 0.0) { Print("Division by zero in regression - flat data?"); g_upper = g_lower = g_median = 0.0; return; } double a = (n * sum_xy - sum_x * sum_y) / denom; double b = (sum_y - a * sum_x) / n; // Median (regression) at newest completed bar (x = n-1) g_median = a * (n - 1) + b; // Residuals sum of squares double sum_e2 = 0.0; for (int i = 1; i <= n; i++) { double x = n - i; double y_reg = a * x + b; double e = rates[i].close - y_reg; sum_e2 += e * e; } // StdDev of residuals (population, df = n-2 for regression fit) double stddev = (n > 2) ? MathSqrt(sum_e2 / (n - 2)) : 0.0; double offset = Deviation * stddev; g_upper = g_median + offset; g_lower = g_median - offset; Print("Manual Channel Calc: Median=", g_median, " Upper=", g_upper, " Lower=", g_lower, " StdDev=", stddev, " Offset=", offset); }
12. Synchronisierung mit dem Chartobjekt (UpdateChannel)
UpdateChannel() setzt das numerische Modell des EA als einzige Quelle der Wahrheit durch, indem es immer zuerst die manuelle Berechnung aufruft und die Ergebnisse validiert. Wenn der grafische Modus aktiviert ist und der Kanalzeiger existiert, werden alle alten Chart-Objekte gelöscht und mit neuen Ankern und dem Deviation-Parameter neu erstellt, damit die auf der Plattform gerenderte Visualisierung mit den berechneten Levels des EA übereinstimmt. Die Neuerstellung des Objekts ist pragmatisch und reduziert die Komplexität der Zustandsverwaltung auf Kosten des visuellen Flimmerns.
bool UpdateChannel() { CalculateStdDevChannel(); // Always manual if (g_upper == 0.0 || g_lower == 0.0 || g_upper <= g_lower) return false; // Optional graphical update if (DrawGraphical && channel != NULL) { datetime time1 = iTime(_Symbol, PERIOD_CURRENT, PeriodBars); datetime time2 = iTime(_Symbol, PERIOD_CURRENT, 0); ObjectDelete(0, "StdDevChannel"); if (!channel.Create(0, "StdDevChannel", 0, time1, time2, Deviation)) { Print("Failed to update graphical channel"); } else { channel.Deviations(Deviation); Print("Graphical channel updated"); } } return true; }
13. Hilfsfunktionen und deterministische Auslöser
Die Hilfsfunktion PositionsTotalByMagic() iteriert die offenen Positionen, um die Positionen zu zählen, die diesem EA gehören (Symbol + Magic), und bildet so die kanonische Eigentümerprüfung, die doppelte Eröffnungen verhindert. IsNewBar() verwendet die Verfolgung der letzten Balkenzeit, um nur dann true zurückzugeben, wenn ein neuer abgeschlossener Balken erscheint – dieser deterministische Auslöser richtet die Neuberechnungen an den abgeschlossenen Marktinformationen aus und vermeidet es, auf flüchtige Werte während der Bildung des Balkens zu reagieren. Diese Dienstprogramme sind kompakt, aber für ein vorhersehbares EA-Verhalten unerlässlich.
int PositionsTotalByMagic() { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { if (PositionGetSymbol(i) == _Symbol && PositionGetInteger(POSITION_MAGIC) == Magic) count++; } return count; } bool IsNewBar() { static datetime lastBarTime = 0; datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0); if (currentBarTime != lastBarTime) { lastBarTime = currentBarTime; return true; } return false; }
14. Aufräumen und elegantes Herunterfahren (OnDeinit)
Bei der Deinitialisierung entfernt der EA das grafische Objekt, falls erstellt, und gibt den Pufferspeicher frei, indem er den Kanalpuffer löscht. Dadurch bleiben die Charts übersichtlich und es werden Speicherverluste durch wiederholte An- und Abkopplungszyklen vermieden. Die Protokollierung des Deinit-Ereignisses hilft, das ordnungsgemäße Herunterfahren im laufenden Betrieb oder bei Tests zu bestätigen. Es ist gute Praxis, nach dem Löschen auch channel = NULL zu setzen, um versehentliche Dereferenzierungen zu vermeiden.
void OnDeinit(const int reason) { if (DrawGraphical && channel != NULL) { ObjectDelete(0, "StdDevChannel"); delete channel; } Print("Channel EA deinitialized"); }
Alle diese Komponenten zusammen bilden ExpertStdDevChannel. Der vollständige Quellcode ist unterhalb des Artikels verfügbar. Der nächste Schritt ist das Testen des EAs im Strategy Tester und in kontrollierten Live-/Demo-Umgebungen, bevor Sie echtes Kapital einsetzen.
Tests
Testen ist wichtig, um zu überprüfen, ob unsere Idee richtig umgesetzt wurde. Für diesen Test habe ich den kompilierten EA im Navigator von MetaTrader 5 gefunden und den Strategy Tester im visuellen Modus gestartet. Der EA wurde erfolgreich ausgeführt: Die Aufträge wurden wie erwartet ausgeführt und der Kanal der Standardabweichung wurde korrekt auf dem Chart dargestellt.
Abb. 4. Testen des ExpertStdDevChannel in der Strategy Tester-Visualisierung
Schlussfolgerung
Wir haben erfolgreich Teile der MQL5-Standardbibliothek in einen funktionierenden Expert Advisor, ExpertStdDevChannel, eingebaut. Diese Übung vertiefte unser praktisches Verständnis der Standardabweichung und ihrer Anwendung im Handel und zeigte, wie Bibliothekskomponenten kombiniert werden können, um ein funktionales volatilitätsbasiertes Handelsmodul zu erstellen. Die Breite der Standardbibliothek gibt uns viele weitere Möglichkeiten, diese Arbeit durch die Kombination zusätzlicher Bausteine zu erweitern und zu verfeinern.
Dieses Beispiel ist ein pädagogischer Prototyp, keine Garantie für Rentabilität. Sein Hauptzweck ist es, zu zeigen, wie man Bibliotheksstücke zu einem kohärenten EA verbindet; es gibt reichlich Raum, um die Idee zu einem produktionsreifen System weiterzuentwickeln. Sie sind eingeladen, mit der beigefügten Quelle zu experimentieren, die Parameter einzustellen und Ihre Ergebnisse in den Kommentaren mitzuteilen.
Zu den vorgeschlagenen nächsten Schritten gehören die Überarbeitung der Einstiegs- und Ausstiegsregeln, das Hinzufügen robuster Signalfilter (Multi-Timeframe-Bestätigung, Volumen- oder Volatilitätsfilter), die Verbesserung der Positionsgrößen- und Risikokontrollen sowie die Durchführung systematischer Optimierungen im Strategy Tester. Diese Verbesserungen werden dazu beitragen, diese Grundlage in eine effizientere und widerstandsfähigere Handelslösung zu verwandeln. Bis zur nächsten Veröffentlichung – bleiben Sie dran.
Anlagen
| Dateiname | Version | Beschreibung |
|---|---|---|
| ExpertStdDevChannel.mq5 | 1.00 | Expert Advisor, der einen Standardabweichungskanal unter Verwendung einer linearen Regressionsmittellinie und der Reststandardabweichung (σ) über ein konfigurierbares Fenster berechnet. Wesentliche Merkmale: Mean-Reversion- und Breakout-Modi; manuelle numerische Berechnung von Median/oberen/unteren Bändern (maßgeblich für Signale); optionale grafische Darstellung über CChartObjectStdDevChannel; Handelsausführung über CTrade mit SL/TP-Platzierung, SLBuffer- und Broker-Min-Distance-Prüfungen und Single-Position-Gating über Magic Number. Zu den Eingaben gehören Deviation, PeriodBars, LotSize, Magic, SLBuffer, EnableBuys/EnableSells, DrawGraphical und UseMeanReversion. Entwickelt für reproduzierbare Backtests (deaktivieren Sie den grafischen Modus, um die Geschwindigkeit zu erhöhen) und enthält Schutzmechanismen für Datenausreichend, Normalisierung und Auftragsvalidierung. |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/20041
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.
Die Übertragung der Trading-Signale in einem universalen Expert Advisor.
Risikobasierter Trade Placement EA mit On-Chart UI (Teil 2): Hinzufügen von Interaktivität und Logik
Eine alternative Log-datei mit der Verwendung der HTML und CSS
Automatisieren von Handelsstrategien in MQL5 (Teil 39): Statistische Rückkehr zum Mittelwert mit Konfidenzintervallen und Dashboard
- 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.
In Ihrem Code, wenn UseMeanReversion = false, sollte der tp-Wert höher sein als g_upper, nicht wahr?