
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 14): Parabolischer Stopp und Umkehr-Tool
Inhalt
Einführung
Technische Indikatoren sind Signale, die durch die Analyse von historischen Datenmustern wie Preis, Volumen und offenem Interesse erzeugt werden. Diese heuristischen Instrumente ermöglichen es Händlern, das Marktverhalten zu bewerten und zukünftige Bewegungen auf der Grundlage bewährter Trends und statistischer Modelle vorherzusagen.
In diesem Artikel konzentrieren wir uns auf die Entwicklung eines Expert Advisors (EA) mit MQL5, der dazu dient, potenzielle Marktumkehrungen zu erkennen. Der EA nutzt den Parabolic SAR zur Signalerkennung und generiert Handelssignale, indem er technische Indikatoren überwacht, ihre Gültigkeit in Echtzeit bewertet und optimale Ausstiegspunkte identifiziert, wenn vordefinierte Niveaus erreicht werden.
Unsere Diskussion beginnt mit einem Überblick über die zugrunde liegende Strategie und die Gründe für den Einsatz technischer Indikatoren beim Handel. Anschließend werden wir den Implementierungsprozess in MQL5 detailliert beschreiben, unsere Testergebnisse umfassend analysieren und mit Erkenntnissen und Empfehlungen für Händler schließen, die diese Techniken in ihre Systeme integrieren möchten.
Die Strategie verstehen
Parabolic SAR
Beim Parabolic SAR-Indikator bezieht sich der Begriff „parabolisch“ auf die Form der gezeichneten Kurve. Wenn der Trend fortschreitet, beschleunigen sich die Punkte des Indikators in einer gekrümmten, parabolischen Weise, was die zunehmende Dynamik widerspiegelt, da sich die Preise weiter von den jüngsten Extremen entfernen.
Auf der anderen Seite steht „SAR“ für „Stop and Reverse“. Diese Komponente des Indikators signalisiert mögliche Trendumkehrungen. Wenn die Punkte von einer Seite des Kurses auf die andere wechseln, deutet dies darauf hin, dass der aktuelle Trend möglicherweise zu Ende geht, was Händler dazu veranlasst, den Stopp ihrer aktuellen Position zu erwägen und sich auf eine mögliche Umkehr der Marktrichtung vorzubereiten.
Bevor wir uns näher mit unserem Konzept befassen, ist es wichtig, den Parabolic SAR zu Ihrem Chart hinzuzufügen, damit Sie ihn leicht finden können. Hierfür gibt es zwei Methoden, von denen ich eine erläutern werde. Klicken Sie in Ihrem Terminal des MetaTrader 5 auf das Menü Einfügen, navigieren Sie dann zu Indikatoren und wählen Sie Trend. Suchen Sie den Parabolic SAR und setzen Sie ihn ein. Nach dem Hinzufügen konfigurieren Sie die Parameter nach Ihren Wünschen und stellen sicher, dass sie mit den in Ihrem Expert Advisor (EA) verwendeten Parametern übereinstimmen.
Weitere Einzelheiten zum Hinzufügen des Indikators finden Sie in Abbildung 1 unten.
Abb. 1. Hinzufügen des Indikators
Logik der Signalerzeugung
Bei der Arbeit mit dem Parabolic SAR-Indikator muss die Interaktion zwischen der SAR-Parabel und der Kursbewegung genau beobachtet werden. Bei dieser Strategie werden die Signale auf der Grundlage der folgenden Logik erzeugt:
Kaufsignal
Ein Kaufsignal wird ausgelöst, wenn:
- Der aktuelle Balken steigt (sein Schlusskurs ist höher als sein Eröffnungswert) und sein PSAR-Wert liegt unter dem Schlusskurs.
- Die beiden vorangegangenen Balken bestätigen einen Abwärtstrend, da ihre PSAR-Punkte über ihren Schlusskursen liegen.
- Der Abstand zwischen den PSAR-Werten der vorangegangenen Balken liegt in einem akzeptablen Bereich, sodass Konsistenz gewährleistet ist.
Abb. 2. Bedingungen zum Kaufen
Verkaufssignal
Ein Verkaufssignal wird ausgelöst, wenn:
- Der aktuelle Balken fällt (sein Schlusskurs ist niedriger als sein Eröffnungswert) und sein PSAR-Wert liegt über dem Schlusskurs.
- Die beiden vorangegangenen Balken bestätigen einen Aufwärtstrend, da ihre PSAR-Punkte unter ihren Schlusskursen liegen.
- Ebenso muss der Abstand zwischen den PSAR-Werten der vorangegangenen Balken innerhalb eines vordefinierten Schwellenwerts liegen.
Abb. 3. Bedingungen zum Verkauf
Implementierung in MQL5
Dateikopf und Eigenschaften
Ganz oben im Code beginnen wir mit einer Kopfzeile, die wichtige Dateiinformationen wie den Dateinamen, Angaben zum Urheberrecht und einen Link zur Webseite des Autors enthält, in diesem Fall habe ich meine angegeben. Unmittelbar danach folgen mehrere #property-Direktiven, die wichtige Kompilierungseigenschaften wie die Versionsnummer und den Strict-Modus festlegen.
//+--------------------------------------------------------------------+ //| Parabolic SAR EA.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+--------------------------------------------------------------------+ #property copyright "2025, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict
Die Verwendung von #property strict ist von grundlegender Bedeutung, denn sie erzwingt eine strenge Typüberprüfung und Parametervalidierung innerhalb des EA. Diese Vorsichtsmaßnahme hilft, potenzielle Kodierungsfehler zu erkennen, bevor sie sich zu Laufzeitfehlern auswachsen. Unabhängig davon, ob Sie planen, den EA zu veröffentlichen oder ihn in einer Live-Handelsumgebung zu verwenden, dient diese Einstellung als Schutz, um einen reibungslosen Betrieb und die künftige Kompatibilität mit MetaTrader 5-Updates zu gewährleisten. Betrachten Sie dies als eine wichtige Maßnahme zur Qualitätskontrolle Ihres Codes.
Eingabeparameter
Als Nächstes definiert der Code eine Reihe von Eingabeparametern, die Sie direkt über die MetaTrader 5-Schnittstelle anpassen können. Zu diesen Eingaben gehören Parameter für den Parabolic SAR-Indikator, wie SARStep und SARMaximum, die den Beschleunigungsfaktor bzw. die maximale Beschleunigung steuern. Es gibt auch Einstellungen zur Verfeinerung der Signalerkennung, wie MinConsecutiveDots und MaxDotGapPercentage, die dazu beitragen, dass nur starke Trends Signale auslösen. Sie können auch Warnmeldungen, akustische Benachrichtigungen und Pfeilzeichnungen auf dem Chart aktivieren.
// Input parameters for the Parabolic SAR indicator input double SARStep = 0.02; // Acceleration factor for PSAR input double SARMaximum = 0.2; // Maximum acceleration for PSAR // Input parameters for refining the signal based on PSAR dots input int MinConsecutiveDots = 2; // Require at least 2 consecutive bars in one trend before reversal input double MaxDotGapPercentage = 1.0; // Maximum allowed gap between consecutive PSAR dots (% of current close) // Input parameters for alerts and arrow drawing input bool EnableAlerts = true; // Enable popup alerts input bool EnableSound = true; // Enable sound alerts input bool EnableArrows = true; // Draw arrows on chart input string BuyArrowSymbol = "233"; // Wingdings up arrow (as string) input string SellArrowSymbol = "234"; // Wingdings down arrow (as string) input int ArrowWidth = 2; // Arrow thickness input double ArrowOffsetMultiplier = 5; // Multiplier for arrow placement offset
Mit diesen Eingaben können Sie den EA an unterschiedliche Marktbedingungen und Ihre Handelsvorlieben anpassen. Ein wichtiger Aspekt dabei ist die Vielseitigkeit der Pfeilsymbole im MetaTrader 5. Diese Symbole, die der Schriftart Wingdings entstammen, sind leicht anpassbar. So können Sie beispielsweise ein Häkchen für Kaufsignale oder ein „X“ für Verkaufssignale wählen, je nach Ihrem Handelsstil. Durch die Anpassung von Parametern wie der Pfeilbreite wird die Sichtbarkeit von Signalen weiter verbessert, sodass Sie die Darstellung des Charts für Klarheit und sofortige Erkennbarkeit fein abstimmen können.
Globale Variablen und Enumerationen
Um den internen Zustand des EA zu verwalten, werden mehrere globale Variablen und eine Enumeration deklariert. So speichern wir zum Beispiel den Indikator-Handle für den Parabolic SAR in der Variable sarHandle, wodurch wir den Indikator in unserem gesamten Code referenzieren können. Mit lastBarTime wird auch der Zeitpunkt des zuletzt verarbeiteten Balkens festgehalten, damit der EA jeden Balken nur einmal verarbeitet. Die Enumeration SignalType definiert die möglichen Signalzustände: kein Signal, ein Kaufsignal oder ein Verkaufssignal.
// Global indicator handle for PSAR int sarHandle = INVALID_HANDLE; // Global variable to track last processed bar time datetime lastBarTime = 0; // Enumeration for signal types enum SignalType { NO_SIGNAL, BUY_SIGNAL, SELL_SIGNAL }; // Global variables for pending signal mechanism SignalType pendingSignal = NO_SIGNAL; int waitCount = 0; // Counts new closed bars since signal detection double pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection
Darüber hinaus werden Variablen wie pendingSignal, waitCount und pendingReversalLevel verwendet, um ausstehende Signale zu verwalten, die über einige Balken hinweg auf eine weitere Bestätigung warten, bevor eine endgültige Aktion durchgeführt wird. Eine wichtige Variable ist pendingReversalLevel, die den PSAR-Wert erfasst, sobald ein Signal erzeugt wird. Dieses Niveau dient als Referenzpunkt und hilft dem EA, die nachfolgenden Kursbewegungen zu überwachen, um festzustellen, ob eine Umkehrung echt oder nur ein Fehlalarm ist. Dieser Checkpoint-Mechanismus ist wichtig, um unnötige Handelsgeschäfte zu reduzieren und die Gesamtgenauigkeit des EA zu verfeinern.
Zeichnen von Pfeilen auf dem Chart
Für eine intuitivere visuelle Darstellung enthält der EA eine Funktion namens DrawSignalArrow. Diese Funktion ist für das Zeichnen eines Pfeils auf dem Chart verantwortlich, wenn ein Signal erkannt wird. Dabei wird ein eindeutiger Objektname auf der Grundlage der Balkenzeit generiert, nach einem vorhandenen Objekt mit diesem Namen gesucht und dieses gelöscht, um Duplikate zu vermeiden.
void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode) { string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS); // Remove existing object with the same name to prevent duplicates if(ObjectFind(0, arrowName) != -1) ObjectDelete(0, arrowName); if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price)) { ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth); } else { Print("Failed to create arrow object: ", arrowName); } }
Der EA verwendet das Objekt OBJ_ARROW, um Signale auf dem Chart visuell darzustellen. Um Unordnung durch doppelte Markierungen zu vermeiden, prüft der Code zunächst, ob bereits Pfeile vorhanden sind, und entfernt diese, bevor ein neuer Pfeil gezeichnet wird. Auf diese Weise bleibt ein sauberes und gut lesbares Chart erhalten, das für Handelsentscheidungen in Echtzeit entscheidend ist. Sie können auch verschiedene Aspekte wie das Pfeilsymbol, die Farbe und den Versatz anpassen, um Ihre persönlichen Vorlieben für visuelle Hinweise zu berücksichtigen.
Funktion zur Signalerkennung
Das Herzstück des EA liegt in der Funktion CheckForSignal. Hier untersucht der Code die letzten drei Balken der Preis- und PSAR-Daten. Damit ein Kaufsignal erkannt wird, prüft die Funktion, ob der aktuelle Balken steigt (d.h. sein Schlusskurs ist höher als sein Eröffnungskurs) und ob der PSAR-Punkt unter der Kerze liegt, während die beiden vorangegangenen Balken gefallen sind und ihre PSAR-Punkte über den Kerzen liegen. Die umgekehrte Logik gilt für ein Verkaufssignal.
SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[]) { // Mapping indices: // Index 0: Last closed bar (current candidate) // Index 1: Previous bar // Index 2: Bar before previous double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2]; double open0 = openArray[0], close0 = closeArray[0]; double open1 = openArray[1], close1 = closeArray[1]; double open2 = openArray[2], close2 = closeArray[2]; // Check for BUY signal: if((close0 > open0) && (sar0 < close0) && (sar1 > close1) && (sar2 > close2)) { int countBearish = 0; if(sar1 > close1) countBearish++; if(sar2 > close2) countBearish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold) return BUY_SIGNAL; } // Check for SELL signal: if((close0 < open0) && (sar0 > close0) && (sar1 < close1) && (sar2 < close2)) { int countBullish = 0; if(sar1 < close1) countBullish++; if(sar2 < close2) countBullish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold) return SELL_SIGNAL; } return NO_SIGNAL; }
Die Funktion verwendet auch einen Abstands-Schwellenwert, um sicherzustellen, dass der Abstand zwischen aufeinanderfolgenden PSAR-Punkten innerhalb akzeptabler Grenzen bleibt. Wenn die Bedingungen erfüllt sind, wird der entsprechende Signaltyp (Kauf oder Verkauf) zurückgegeben; andernfalls wird kein Signal zurückgegeben. Die Signalerkennungsfunktion identifiziert effektiv Umkehrungen anhand der PSAR-Positionierung und der Kerzen-Muster. Sein Design ermöglicht jedoch eine weitere Verbesserung durch die Einbeziehung zusätzlicher Filter wie gleitende Durchschnitte, RSI oder sogar Volatilitätsindex. Die Hinzufügung dieser Schichten kann dazu beitragen, Fehlsignale in Seitwärtsmärkten oder in Phasen, die durch wichtige Nachrichten beeinflusst werden, zu vermeiden. Im Wesentlichen ist der EA so aufgebaut, dass er anpassungsfähig ist und Ihnen die Freiheit gibt, seine Logik an Ihre individuelle Handelsstrategie und die Marktbedingungen anzupassen.
Erkennen von neue Balken
Bevor der EA Daten verarbeitet, muss er feststellen, ob ein neuer Balken geschlossen wurde. Die Funktion IsNewBar behandelt dies, indem sie die Zeit des letzten geschlossenen Balkens abruft und sie mit der gespeicherten lastBarTime vergleicht. Wenn sich die Zeiten unterscheiden, bedeutet dies, dass ein neuer Balken gebildet wurde, sodass die Funktion lastBarTime aktualisiert und true zurückgibt.
bool IsNewBar() { datetime times[]; if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0) { Print("Failed to retrieve bar time in IsNewBar()."); return false; } if(times[0] != lastBarTime) { lastBarTime = times[0]; return true; } return false; }
Diese Prüfung ist von entscheidender Bedeutung, da sie sicherstellt, dass der EA die Daten nur einmal pro neuem Balken verarbeitet und somit eine wiederholte oder fehlerhafte Signalverarbeitung verhindert. Die Funktion IsNewBar ist ein intelligenter Effizienz-Booster für den EA. Indem sichergestellt wird, dass Signale nur einmal pro neuem Balken verarbeitet werden, werden redundante Berechnungen und wiederholte Alarme vermieden. Diese einfache Überprüfung sorgt dafür, dass der EA effizient läuft und verringert das Risiko, dass Kursbewegungen innerhalb eines einzelnen Balkens falsch interpretiert werden. Insgesamt trägt es dazu bei, eine konsistente und vorhersehbare Leistung auf der MetaTrader-Plattform zu erhalten.
Initialisierung und Deinitialisierung
Wenn der EA geladen wird, wird zuerst die Funktion OnInit ausgeführt. Ihre Hauptaufgabe besteht darin, ein Handle für den eingebauten Parabolic SAR-Indikator unter Verwendung der vom Nutzer angegebenen Parameter zu erstellen. Wenn der Indikator erfolgreich initialisiert wurde, wird eine Bestätigungsmeldung gedruckt; andernfalls wird eine Fehlermeldung erzeugt und die Initialisierung schlägt fehl. Umgekehrt wird die Funktion OnDeinit aufgerufen, wenn der EA aus dem Chart entfernt wird oder wenn das Terminal geschlossen wird.
int OnInit() { // Create the built-in Parabolic SAR indicator handle sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum); if(sarHandle == INVALID_HANDLE) { Print("Error creating PSAR handle"); return INIT_FAILED; } Print("SAR EA initialized successfully."); return INIT_SUCCEEDED; }
Diese Funktion kümmert sich um die Freigabe des Indikatorgriffs und bereinigt alle grafischen Objekte (wie Pfeile), die während der EA-Operation erstellt wurden, um sicherzustellen, dass keine unnötige Unordnung zurückbleibt. Ein gut durchdachter EA achtet auf die Bereinigung während der Deinitialisierung. Das Entfernen von Pfeilen oder anderen visuellen Elementen, die während des Betriebs erstellt wurden, verhindert, dass das Chart mit überflüssigen Markierungen überladen wird. Dieser Bereinigungsprozess ist wie eine gute Haushaltsführung, denn er stellt sicher, dass Sie jedes Mal, wenn Sie den EA starten, mit einem frischen, übersichtlichen Chart und einer optimalen Systemleistung arbeiten.
Hauptlogik (OnTick-Funktion)
Die Funktion OnTick schließlich ist der Hauptmotor, der bei jedem Tick läuft. Zunächst wird mit der Funktion IsNewBar geprüft, ob gerade ein neuer Balken geschlossen wurde. Wird kein neuer Balken entdeckt, wird die Funktion vorzeitig beendet, um eine redundante Verarbeitung zu vermeiden. Sobald ein neuer Balken bestätigt wird, ruft der EA die neuesten PSAR-Werte zusammen mit den entsprechenden Eröffnungs- und Schlusskursen für die letzten Balken ab. An diesem Punkt wertet der EA aus, ob es ein anstehendes Signal gibt, das auf Bestätigung wartet. Wenn ein Signal ansteht, wird ein Zähler (waitCount) inkrementiert, um festzustellen, wie viele Balken vergangen sind.
void OnTick() { // Process only once per new closed bar if(!IsNewBar()) return; // Retrieve PSAR and price data double sarArray[4]; if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3) { /* error handling */ } double openArray[4], closeArray[4]; if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 || CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3) { /* error handling */ } // Pending Signal Logic... if(pendingSignal != NO_SIGNAL) { waitCount++; // Increment waiting counter if(pendingSignal == BUY_SIGNAL) { if(closeArray[0] <= pendingReversalLevel) { // Confirm reversal: Close alert for BUY signal } else if(waitCount >= 3) { // Warn about a possible fake BUY signal } } else if(pendingSignal == SELL_SIGNAL) { if(closeArray[0] >= pendingReversalLevel) { // Confirm reversal: Close alert for SELL signal } else if(waitCount >= 3) { // Warn about a possible fake SELL signal } } return; // Wait until pending signal is resolved } // Check for a new reversal signal if no pending signal exists SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray); if(newSignal != NO_SIGNAL) { pendingSignal = newSignal; waitCount = 0; // Reset counter pendingReversalLevel = sarArray[0]; // Store current PSAR value // Alert and optionally draw an arrow based on the new signal if(newSignal == BUY_SIGNAL) { /* process BUY signal */ } else if(newSignal == SELL_SIGNAL) { /* process SELL signal */ } } }
Der EA prüft dann, ob der aktuelle Kurs das gespeicherte Umkehrniveau erreicht hat: Ist dies der Fall, wird eine Warnung ausgegeben, um das Signal „hier zu schließen“; vergehen drei Balken ohne Bestätigung, warnt der EA vor einem möglichen falschen Signal. Wenn kein aktives Signal ansteht, ruft der EA die Funktion CheckForSignal auf, um zu sehen, ob ein neues Signal entstanden ist. Ist dies der Fall, wird das Signal gespeichert, der Wartezähler zurückgesetzt, die anstehende Umkehrstufe auf der Grundlage des aktuellen PSAR-Werts festgelegt und die entsprechenden Warnmeldungen und visuellen Markierungen ausgelöst. Ein innovatives Merkmal der Funktion OnTickist die Methode zum Herausfiltern potenzieller Fehlsignale.
Durch die Verwendung eines Zählers (waitCount), der überwacht, wie viele Balken nach der Erzeugung eines Signals vergehen, lässt der EA Zeit für die Bestätigung, bevor er aktiv wird. Diese Verzögerung ist vor allem auf volatilen Märkten nützlich, wo rasche Kursschwankungen sonst verfrühte Signale auslösen könnten. Durch die Anpassung der Anzahl der Bestätigungsbalken können Sie ein Gleichgewicht zwischen Reaktionsfähigkeit und Vorsicht herstellen, wodurch der EA flexibel genug ist, um sowohl kurzfristiges Scalping als auch langfristige Trendstrategien zu unterstützen.
Vollständiger MQL5 EA-Code
//+--------------------------------------------------------------------+ //| Parabolic SAR EA.mql5 | //| Copyright 2025, Christian Benjamin | //| https://www.mql5.com | //+--------------------------------------------------------------------+ #property copyright "2025, Christian Benjamin" #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.2" #property strict // Input parameters for the Parabolic SAR indicator input double SARStep = 0.1; // Acceleration factor for PSAR input double SARMaximum = 1; // Maximum acceleration for PSAR // Input parameters for refining the signal based on PSAR dots input int MinConsecutiveDots = 2; // Require at least 2 consecutive bars in one trend before reversal input double MaxDotGapPercentage = 1.0; // Maximum allowed gap between consecutive PSAR dots (% of current close) // Input parameters for alerts and arrow drawing input bool EnableAlerts = true; // Enable popup alerts input bool EnableSound = true; // Enable sound alerts input bool EnableArrows = true; // Draw arrows on chart input string BuyArrowSymbol = "233"; // Wingdings up arrow (as string) input string SellArrowSymbol = "234"; // Wingdings down arrow (as string) input int ArrowWidth = 2; // Arrow thickness input double ArrowOffsetMultiplier = 5; // Multiplier for arrow placement offset // Global indicator handle for PSAR int sarHandle = INVALID_HANDLE; // Global variable to track last processed bar time datetime lastBarTime = 0; // Enumeration for signal types enum SignalType { NO_SIGNAL, BUY_SIGNAL, SELL_SIGNAL }; // Global variables for pending signal mechanism SignalType pendingSignal = NO_SIGNAL; int waitCount = 0; // Counts new closed bars since signal detection double pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection //+------------------------------------------------------------------+ //| DrawSignalArrow - Draws an arrow object on the chart | //+------------------------------------------------------------------+ void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode) { string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS); // Remove existing object with the same name to prevent duplicates if(ObjectFind(0, arrowName) != -1) ObjectDelete(0, arrowName); if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price)) { ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth); } else { Print("Failed to create arrow object: ", arrowName); } } //+-------------------------------------------------------------------+ //| CheckForSignal - Evaluates PSAR and price data to determine signal| //+-------------------------------------------------------------------+ SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[]) { // Mapping indices: // Index 0: Last closed bar (current candidate) // Index 1: Previous bar // Index 2: Bar before previous double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2]; double open0 = openArray[0], close0 = closeArray[0]; double open1 = openArray[1], close1 = closeArray[1]; double open2 = openArray[2], close2 = closeArray[2]; // Check for BUY signal: if((close0 > open0) && (sar0 < close0) && (sar1 > close1) && (sar2 > close2)) { int countBearish = 0; if(sar1 > close1) countBearish++; if(sar2 > close2) countBearish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold) return BUY_SIGNAL; } // Check for SELL signal: if((close0 < open0) && (sar0 > close0) && (sar1 < close1) && (sar2 < close2)) { int countBullish = 0; if(sar1 < close1) countBullish++; if(sar2 < close2) countBullish++; double dotGap = MathAbs(sar1 - sar2); double gapThreshold = (MaxDotGapPercentage / 100.0) * close0; if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold) return SELL_SIGNAL; } return NO_SIGNAL; } //+------------------------------------------------------------------+ //| IsNewBar - Determines if a new closed bar is available | //+------------------------------------------------------------------+ bool IsNewBar() { datetime times[]; if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0) { Print("Failed to retrieve bar time in IsNewBar()."); return false; } if(times[0] != lastBarTime) { lastBarTime = times[0]; return true; } return false; } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Create the built-in Parabolic SAR indicator handle sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum); if(sarHandle == INVALID_HANDLE) { Print("Error creating PSAR handle"); return INIT_FAILED; } Print("SAR EA initialized successfully."); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(sarHandle != INVALID_HANDLE) IndicatorRelease(sarHandle); // Remove all arrow objects from the current chart window ObjectsDeleteAll(0, (int)OBJ_ARROW, 0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Process only once per new closed bar if(!IsNewBar()) return; // Retrieve the last 4 PSAR values (we require at least 3 values) double sarArray[4]; if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3) { Print("Failed to retrieve PSAR data."); return; } // Retrieve the last 4 bars' price data (Open and Close) double openArray[4], closeArray[4]; if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 || CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3) { Print("Failed to retrieve price data."); return; } // Process pending signal logic if a signal is waiting confirmation if(pendingSignal != NO_SIGNAL) { waitCount++; // Increment the waiting counter if(pendingSignal == BUY_SIGNAL) { if(closeArray[0] <= pendingReversalLevel) { Print("Reversal level reached for BUY signal. Close here."); if(EnableAlerts) Alert("Close here for BUY signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = 0; } else if(waitCount >= 3) { Print("Warning: Possible fake BUY signal - reversal not confirmed in 3 candles."); if(EnableAlerts) Alert("Warning: Possible fake BUY signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = 0; } } else if(pendingSignal == SELL_SIGNAL) { if(closeArray[0] >= pendingReversalLevel) { Print("Reversal level reached for SELL signal. Close here."); if(EnableAlerts) Alert("Close here for SELL signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = 0; } else if(waitCount >= 3) { Print("Warning: Possible fake SELL signal - reversal not confirmed in 3 candles."); if(EnableAlerts) Alert("Warning: Possible fake SELL signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = 0; } } return; } // Check for a new reversal signal SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray); if(newSignal != NO_SIGNAL) { pendingSignal = newSignal; waitCount = 0; // Reset waiting counter pendingReversalLevel = sarArray[0]; // Set reversal level from current PSAR value if(newSignal == BUY_SIGNAL) { Print("Buy signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation (up to 3 candles)."); if(EnableAlerts) Alert("Buy signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableArrows) { double lowVal[]; if(CopyLow(_Symbol, _Period, 1, 1, lowVal) > 0) { double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("BuyArrow", lastBarTime, lowVal[0] - offset, clrGreen, StringToInteger(BuyArrowSymbol)); } else Print("Failed to retrieve low price for arrow placement."); } } else if(newSignal == SELL_SIGNAL) { Print("Sell signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation (up to 3 candles)."); if(EnableAlerts) Alert("Sell signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits)); if(EnableArrows) { double highVal[]; if(CopyHigh(_Symbol, _Period, 1, 1, highVal) > 0) { double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("SellArrow", lastBarTime, highVal[0] + offset, clrRed, StringToInteger(SellArrowSymbol)); } else Print("Failed to retrieve high price for arrow placement."); } } } } //+------------------------------------------------------------------+
Tests und Ergebnisse
Bevor Sie zum Live-Handel übergehen, empfehle ich Backtests auf einem Demokonto. Hier erfahren Sie, wie Sie Ihren EA auf der Grundlage Ihrer Testergebnisse feinabstimmen können:- Sobald Sie Ihren EA in MetaEditor erfolgreich kompiliert haben, öffnen Sie MetaTrader.
- Navigieren Sie im MetaTrader zum Strategietester. Wählen Sie den EA aus, den Sie testen möchten, und wählen Sie dann den gewünschten Zeitrahmen, den Testzeitraum und andere relevante Parameter.
- Nachdem Sie Ihre Einstellungen konfiguriert haben, klicken Sie auf „Start“, um den Backtest zu starten.
Abb. 4. Tester initialisieren
Im Folgenden finden Sie Bilder und mehrere GIFs, die ich während meiner Backtest-Sitzungen aufgenommen habe. Das erste Bild ist ein Chart für den Volatilitätsindex 25, in dem hervorgehoben wird, wo sowohl Verkaufs- als auch Kaufsignale während des Tests bestätigt wurden. Es folgen mehrere GIFs zur zusätzlichen Visualisierung, die Ihnen helfen können, die Leistung des EA besser zu verstehen.
Abb. 5. Backtest des Index Volatility 25
Backtest des Index Volatility 25 GIF.
Abb. 6: Backtest des Index Volatility 25
Backtest des Step-Index.
Abb. 7: Backtest des Step-Index
Live-Handel Step-Index.
Abb. 8: Live-Handel
Schlussfolgerung
Wir haben den EA entwickelt und getestet und dabei positive Ergebnisse erzielt. Bei einigen Signalen kann jedoch eine zusätzliche Filterung erforderlich sein. Denken Sie daran, dass dieser EA Ihre eigenen Handelsstrategien nicht ersetzen, sondern ergänzen soll. Überprüfen Sie immer alle relevanten Bedingungen, bevor Sie auf der Grundlage seiner Signale handeln. Außerdem kann die Arbeit mit größeren Zeitrahmen entscheidend dazu beitragen, Fehlsignale zu minimieren.
Datum | Name des Toolkits | Beschreibung | Version | Aktualisierungen | Hinweis |
---|---|---|---|---|---|
01/10/24 | Chart Projector | Skript zur Überlagerung der Kursentwicklung des Vortages mit Geistereffekt. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 1 |
18/11/24 | Analytical Comment | Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 2 |
27/11/24 | Analytics Master | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden. | 1.01 | Zweite Veröffentlichung | Toolkit Nummer 3 |
02/12/24 | Analytics Forecaster | Reguläre Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration. | 1.1 | Dritte Auflage | Toolkit Nummer 4 |
09/12/24 | Volatility Navigator | Der EA analysiert die Marktbedingungen anhand der Indikatoren Bollinger Bands, RSI und ATR. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 5 |
19/12/24 | Mean Reversion Signal Reaper | Analysiert den Markt anhand der Strategie „Umkehr zur Mitte“ und liefert Signale. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 6 |
9/01/25 | Signal-Impuls | Analysator für mehrere Zeitrahmen. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 7 |
17/01/25 | Metrics Board | Bedienfeld mit Taste für die Analyse. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 8 |
21/01/25 | External Flow | Analytik durch externe Bibliotheken. | 1.0 | Erste Veröffentlichung | Toolkit Nummer 9 |
27/01/25 | VWAP | Volumengewichteter Durchschnittspreis | 1.3 | Erste Veröffentlichung | Toolkit Nummer 10 |
02/02/25 | Heikin Ashi | Trendglättung und Identifizierung von Umkehrsignalen | 1.0 | Erste Veröffentlichung | Toolkit Nummer 11 |
04/02/25 | FibVWAP | Signalerzeugung durch Python-Analyse | 1.0 | Erste Veröffentlichung | Toolkit Nummer 12 |
14/02/25 | RSI DIVERGENCE | Kursentwicklung versus RSI-Divergenzen | 1.0 | Erste Veröffentlichung | Toolkit Nummer 13 |
17/02/2025 | Parabolischer Stopp und Umkehr (PSAR) | Automatisierung der PSAR-Strategie | 1.0 | Erste Veröffentlichung | Toolkit Nummer 14 |
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/17234
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.





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