English 日本語
preview
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 7): Der EA Signal Pulse

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 7): Der EA Signal Pulse

MetaTrader 5Beispiele | 2 Juni 2025, 10:37
60 0
Christian Benjamin
Christian Benjamin

Inhalt



Einführung

In diesem Artikel werden wir untersuchen, wie man einen Expert Advisor (EA) in MQL5 namens Signal Pulse EA entwickelt. Der EA verwendet eine Kombination aus Bollinger Bands und Stochastik-Oszillator-Indikatoren in drei verschiedenen Zeitrahmen, um Kauf- und Verkaufssignale zu erkennen. Dieser EA soll Händlern helfen, fundierte Entscheidungen zu treffen, indem er Signale aus mehreren Zeitrahmen bestätigt, bevor sie einen Handel eingehen. Wir haben mehrere Zeitrahmen, Bollinger Bands (BB) und den Stochastic Oscillator für die Signalgenerierung integriert. Unser Ziel ist es, falsche Signale, die für Händler frustrierend sein können, zu minimieren. Durch die Kombination dieser Elemente wollen wir die Genauigkeit unserer Handelssignale verbessern. Im Folgenden habe ich die Bedeutung der einzelnen Komponenten unseres Signalerzeugungstools tabellarisch dargestellt.

  • Mehrere Zeitrahmen
Vorteil Beschreibung
Risikomanagement Durch die Verwendung mehrerer Zeitrahmen kann der EA den Markt aus verschiedenen Blickwinkeln analysieren, was die Auswirkungen von Fehlsignalen verringert und das Risikomanagement verbessert.
Vertrauen in Signale Durch die Bestätigung von Signalen über mehrere Zeitrahmen hinweg gewinnt der EA Vertrauen in die Handelsrichtung und verringert die Wahrscheinlichkeit, einen Handel mit einem schwachen oder falschen Signal einzugehen.
Diversifizierung Die Analyse mehrerer Zeitrahmen bietet eine breitere Sicht auf den Markt, die es dem EA ermöglicht, sich an veränderte Marktbedingungen anzupassen und fundiertere Handelsentscheidungen zu treffen.
  • Stochastic
Vorteil Beschreibung
Überkauf/Überverkauf Bedingungen
Die Stochastik hilft dabei, überkaufte und überverkaufte Bedingungen zu erkennen, die auf potenzielle Umkehrpunkte auf dem Markt hinweisen.
Bestätigungswerkzeug
Die Stochastik dient als Bestätigungsinstrument für die Bollinger Bänder und stellt sicher, dass der EA nicht allein aufgrund von BB-Signalen in den Handel einsteigt.
Falsche Signale herausfiltern
Durch die Verwendung der Stochastik kann der EA falsche Signale herausfiltern, die von den Bollinger-Bändern erzeugt werden, insbesondere in Zeiten hoher Volatilität.

  • Bollinger-Bänder
Vorteil Beschreibung
Volatilitätsindikator
Bollinger Bänder zeigen den Grad der Volatilität im Markt an und helfen dem EA, die Stimmung des Marktes und potenzielle Handelsmöglichkeiten zu verstehen.
Unterstützungs-/Widerstandsniveaus
Bollinger Bänder fungieren als dynamische Unterstützungs- und Widerstandsniveaus, die dem EA potenzielle Einstiegs- und Ausstiegspunkte bieten.
Trendbestätigung 
Die Breite der Bollinger-Bänder kann das Vorhandensein eines Trends bestätigen oder verneinen und hilft dem EA, fundierte Handelsentscheidungen zu treffen.

Die Interaktion zwischen mehreren Zeitrahmen, der Stochastik und den Bollinger Bändern (BB) steigert die Effektivität des EA bei der Generierung zuverlässiger Handelssignale und dem Risikomanagement erheblich. Durch die Analyse von Signalen über verschiedene Zeitrahmen hinweg stellt der EA sicher, dass Handelsmöglichkeiten durch ein starkes Zusammentreffen von Indikatoren sowohl der Stochastik als auch der BB bestätigt werden. Dieser mehrdimensionale Ansatz verringert die Wahrscheinlichkeit von Fehlsignalen, da der EA potenzielle Handelsgeschäfte nur dann identifiziert, wenn es robuste Beweise gibt, die die Entscheidung unterstützen. Durch die Kombination dieser Elemente wird die Zuverlässigkeit der generierten Signale erhöht und das Risikomanagement insgesamt verbessert, sodass die Händler fundiertere Entscheidungen auf der Grundlage eines höheren Maßes an Vertrauen und Präzision treffen können. 


Die Strategie verstehen

Das Signal Pulse Skript generiert Handelssignale basierend auf der Ausrichtung der Bollinger Bänder und des Stochastik Oszillators über drei Zeitrahmen (M15, M30 und H1). Die Bedingungen für jedes Signal sind wie folgt:

Kaufsignal

  1. Bedingung der Bollinger Bänder: Der Kurs berührt das untere Band der Bollinger Bänder auf allen drei Zeitskalen.
  2. Bedingung des Oszillators Stochastic: Der Stochastic Oscillator zeigt auf allen drei Zeitebenen einen überverkauften Zustand an, der in der Regel unter 20 liegt.
  3. Bestätigungsanforderung: Beide Bedingungen müssen gleichzeitig im M15-, M30- und H1-Zeitrahmen erfüllt sein, um ein Kaufsignal zu generieren.

KAUFBEDINGUNGEN

Abb. 1. Bedingungen zum Kaufen

Verkaufssignal

  1. Bedingung der Bollinger Bänder: Der Kurs berührt das obere Band der Bollinger Bänder auf allen drei Zeitskalen.
  2. Bedingung des Oszillators Stochastic: Der Stochastic Oscillator zeigt auf allen drei Zeitebenen einen überkauften Zustand an, der in der Regel über 80 liegt.
  3. Bestätigungsanforderung: Beide Bedingungen müssen gleichzeitig im M15-, M30- und H1-Zeitrahmen erfüllt sein, um ein Verkaufssignal zu generieren.

VERKAUFSBEDINGUNG

Abb. 2. Bedingungen zum Verkauf

Veranschaulichen wir uns diesen Prozess anhand des folgenden Diagramms.  

SIGNALERZEUGUNGSDIAGRAMM

Abb. 3. Prozess der Signalerzeugung


MQL5 Code

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping

// Signal tracking structure
struct SignalInfo
  {
   datetime          time;
   double            price;
   bool              isBuySignal;
  };

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle)
  {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
     }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand))
     {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value)
  {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
     }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer))   // %D line
     {
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal()
  {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3))
     {
      Print("Error retrieving Bollinger Bands data.");
      return;
     }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3))
     {
      Print("Error retrieving Stochastic data.");
      return;
     }

// Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

// Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1))
     {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
     }

   if(sellSignal && !ArrowExists(close1))
     {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
     }
  }

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price)
  {
   for(int i = 0; i < ArraySize(signalPrices); i++)
     {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance)
        {
         return true; // Arrow exists in the same price region
        }
     }
   return false; // No arrow exists in the same region
  }

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
   CheckAndGenerateSignal();
  }

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--)
     {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1)
        {
         ObjectDelete(chart_id, name);
        }
     }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
  }
//+------------------------------------------------------------------+



Code-Aufschlüsselung

In dieser Aufschlüsselung des Signal Pulse EA werden die verschiedenen Komponenten des Expert Advisors, seine Funktionsmechanismen und die zugrundeliegende Logik seiner Funktionalitäten Schritt für Schritt erläutert.
  • Kopfzeilen, Eigenschaften und Eingabeparameter

Ganz am Anfang unseres EAs stehen die Kopfzeilen, die wichtige Metadaten enthalten. Diese besteht aus dem Namen des EA, Angaben zum Urheberrecht und einem Link, über den Sie mehr über unsere Arbeit erfahren können. Aber was Ihnen als Händler wirklich hilft, sind die Eingabeparameter. Diese anpassbaren Einstellungen ermöglichen es Ihnen, das Verhalten des EAs an Ihren Handelsstil anzupassen.

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping
Hier legen wir verschiedene Zeitrahmen fest (M15, M30 und H1), die es Ihnen ermöglichen, Kursbewegungen über mehrere Zeiträume hinweg zu analysieren. Wir definieren auch Parameter für die Bollinger-Bänder, wie z. B. ihre Periode und Abweichung, sowie Einstellungen für den Stochastik-Oszillator, einschließlich seiner %K- und %D-Perioden. Wir bieten sogar visuelle Einstellungen für die Pfeile, die Kauf- und Verkaufssignale auf Ihrem Chart markieren, sowie Parameter, die die visuelle Unübersichtlichkeit minimieren, indem sie überlappende Pfeile verhindern.
  •  Signalverfolgung und Strukturen

Als Nächstes definieren wir die SignalInfo-Struktur, die eine wichtige Rolle bei der Organisation unserer Handelssignale spielt. Diese Struktur sammelt Informationen darüber, wann ein Signal aufgetreten ist, wie hoch der Preis zu diesem Zeitpunkt war und ob es sich um ein Kauf- oder Verkaufssignal handelte. Außerdem richten wir Arrays ein, um diese Informationen dynamisch zu speichern. 

// Signal tracking structure
struct SignalInfo {
   datetime time;
   double price;
   bool isBuySignal;
};

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];
Mit den Arrays signalTimes, signalPrices und signalBuySignals führen wir eine klare Aufzeichnung der Handelssignale, die der EA im Laufe der Zeit generiert, sodass es viel einfacher ist, mit mehreren Signalen umzugehen, ohne durcheinander zu kommen.
  •  Funktionen zum Abrufen von Indikatoren

Lassen Sie uns nun auf die Funktionen eingehen, die wir zum Abrufen von Indikatorwerten verwenden, insbesondere die Bollinger-Bänder und den Stochastik Oszillator. 

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
   }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand)) {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
}

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
   }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer)) { // %D line
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
}
Die erste Funktion, GetBollingerBands(), ermittelt das obere, mittlere und untere Niveau der Bollinger-Bänder für einen bestimmten Zeitrahmen. Er erstellt einen Handle für den Indikator und prüft, ob er erfolgreich erstellt wurde. Wenn alles in Ordnung ist, werden die Bandwerte in Arrays kopiert, die wir später für unsere Handelslogik verwenden können. In ähnlicher Weise ruft die Funktion GetStochastic() die Werte %K und %D des stochastischen Oszillators ab. Es verwendet dieselben Verfahren zur Fehlerprüfung und Datenkopie, um sicherzustellen, dass wir stets korrekte Daten für unsere Entscheidungsfindung erhalten.

  • Signalüberprüfung und -generierung

Nachdem wir uns um die Indikatoren gekümmert haben, gehen wir nun zur Funktion CheckAndGenerateSignal() über, die die Kernlogik unseres EA enthält. Diese Funktion ruft unsere zuvor definierten Indikatorfunktionen auf, um Daten der Indikatoren Bollinger Bänder und Stochastic über alle angegebenen Zeitrahmen zu sammeln. Außerdem werden die letzten Schlusskurse für diese Zeiträume ermittelt.

Die Funktion sucht auf der Grundlage der aktuellen Marktbedingungen nach Kauf- und Verkaufssignalen. Ein Kaufsignal wird ausgelöst, wenn die Schlusskurse unter dem unteren Bollinger Band liegen und die Stochastik-Werte auf überverkaufte Bedingungen hinweisen (weniger als 5). Umgekehrt entstehen Verkaufssignale, wenn die Kurse das obere Bollinger Band überschreiten und der Stochastic über 95 anzeigt, was auf überkaufte Bedingungen hindeutet.

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal() {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) {
      Print("Error retrieving Bollinger Bands data.");
      return;
   }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3)) {
      Print("Error retrieving Stochastic data.");
      return;
   }

   // Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

   // Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1)) {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
   }

   if(sellSignal && !ArrowExists(close1)) {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
   }
}

Außerdem stellt die Funktion vor der Platzierung eines Pfeils zur Anzeige eines Signals im Chart sicher, dass sich kein bestehender Pfeil überschneidet, indem sie die Funktion ArrowExists() aufruft. Wenn alles in Ordnung ist, wird der entsprechende Pfeil erstellt und die Informationen über das Signal in den zuvor definierten Arrays gespeichert.

  • Existenzprüfung des Pfeils

In unserem Streben nach einem aufgeräumten Chart spielt die Funktion ArrowExists() eine wichtige Rolle, indem sie prüft, ob sich ein vorhandener Pfeil in der Nähe des Preises des aktuellen Signals befindet. Dadurch wird verhindert, dass sich mehrere Pfeile überschneiden, was zu Verwechslungen führen könnte. Durch den Vergleich des neuen Signalpreises mit den im Array signalPrices gespeicherten Preisen wird festgestellt, ob ein vorhandener Pfeil nahe genug ist, um die Erstellung eines neuen zu überspringen.

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price) {
   for(int i = 0; i < ArraySize(signalPrices); i++) {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) {
         return true; // Arrow exists in the same price region
      }
   }
   return false; // No arrow exists in the same region
}

  • Die Funktionen OnTick und OnDeinit

Schließlich gibt es noch die Funktionen OnTick() und OnDeinit(). Die Funktion OnTick() wird jedes Mal aufgerufen, wenn es einen neuen Markttick gibt, um sicherzustellen, dass unser EA reaktionsfähig und aktuell bleibt. Sie ruft die Funktion CheckAndGenerateSignal() auf, um potenzielle Handelssignale auf der Grundlage der neuesten Daten neu zu bewerten.

Im Gegensatz dazu wird die Funktion OnDeinit() aufgerufen, wenn der EA entfernt oder das Terminal geschlossen wird. Seine Aufgabe ist es, alle vom EA erstellten grafischen Objekte zu bereinigen - insbesondere die Pfeile, die Kauf- und Verkaufssignale markieren - und so für ein übersichtliches Chart zu sorgen.

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick() {
   CheckAndGenerateSignal();
}

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   // Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1) {
         ObjectDelete(chart_id, name);
      }
   }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
}

Darüber hinaus haben wir im Signal Pulse EA die Schwellenwerte für den stochastischen Oszillator angepasst, um sicherzustellen, dass nur die zuverlässigsten Signale erzeugt werden. Diese Anpassungen konzentrieren sich darauf, zu bestätigen, dass sich der Markt in einem extremen Zustand befindet - entweder überverkauft bei Kaufsignalen oder überkauft bei Verkaufssignalen - bevor gehandelt wird.

  • Überverkaufter Zustand: Kaufsignal
bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                 (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition

Für ein Kaufsignal muss der Kurs in allen drei Zeitrahmen (M15, M30, H1) am oder unter dem unteren Bollinger Band liegen, was auf einen starken Abwärtsdruck hindeutet. Außerdem muss der %K-Wert des Stochastik-Oszillators in allen drei Zeitrahmen unter 5 liegen. Dieser Wert deutet auf einen extrem überverkauften Zustand hin, in dem der Markt höchstwahrscheinlich nach oben drehen wird. Der strengere Schwellenwert von < 5 stellt sicher, dass der EA nur Signale berücksichtigt, bei denen die Wahrscheinlichkeit einer Umkehrung signifikant hoch ist.

  • Überkaufter Zustand: Verkaufssignal

bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                  (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

Für ein Verkaufssignal muss der Kurs in allen drei Zeitrahmen am oder über dem oberen Bollinger Band liegen, was auf ein starkes Aufwärtsmomentum hinweist, das sich bald umkehren könnte. Der %K-Wert des Stochastik-Oszillators muss in allen Zeitrahmen über 95 liegen, was auf einen extrem überkauften Zustand hindeutet, in dem der Markt wahrscheinlich nach unten drehen wird. Diese strenge Bedingung stellt sicher, dass der EA falsche Verkaufssignale bei moderaten Kursbewegungen oder Konsolidierungen vermeidet.


Tests und Ergebnisse

  • Backtesting mit historischen Daten
Backtesting ist eine wichtige Komponente bei der Entwicklung von Expert Advisor (EA), die es Händlern ermöglicht, die Leistung ihres EA anhand historischer Kursdaten zu analysieren. Dieser Prozess hilft dabei, die Rentabilität, Genauigkeit und Robustheit des EAs zu ermitteln, sodass Händler ihre Strategie verfeinern und ihre Leistung optimieren können.
1. Laden der historischen Daten

Um mit dem Backtesting zu beginnen, müssen Sie unbedingt hochwertige historische Daten auf Tick-Ebene für das gewählte Instrument und den gewählten Zeitrahmen laden. Diese Daten dienen als Grundlage für die Bewertung der Leistung der EA. Es ist von entscheidender Bedeutung, dass die Daten genau und zuverlässig sind, da Unstimmigkeiten zu falschen Schlussfolgerungen über die Leistung der EA führen können.

2. Prüfparameter festlegen

Sobald die Daten geladen sind, ist es an der Zeit, den Strategietester im MetaTrader mit den erforderlichen Parametern zu konfigurieren. Dazu gehören:
  • Symbol: Wählen Sie das Währungspaar oder den Vermögenswert, mit dem Sie handeln möchten.
  • Period: Verwenden Sie die gleichen Zeitrahmen wie die Einstellungen des EA (z. B. M15, M30, H1).
  • Spread: Legen Sie einen realistischen oder fixen Spread fest, um die Handelskosten zu simulieren und sicherzustellen, dass die Ergebnisse repräsentativ für reale Handelsbedingungen sind.
  • Optimierung: Testen Sie die Eingabeparameter (z. B. Bollinger-Band-Periode, Stochastik-Schwellenwerte) auf optimale Leistung.
3. Ergebnisse auswerten
Nachdem die Testparameter festgelegt wurden, ist es an der Zeit, die Ausgabemetriken zu analysieren:
  • Rentabilität: Bewerten Sie den Nettogewinn und den Gewinnfaktor des EA, um seine Gesamtrentabilität zu ermitteln.
  • Risiko: Beurteilen Sie den maximalen Drawdown, um die Risikotoleranz des EA zu ermitteln.
  • Gewinnrate und Handelshäufigkeit: Analysieren Sie die Anzahl der erfolgreichen Trades und die Handelshäufigkeit, um die Leistung des EA unter verschiedenen Marktbedingungen zu verstehen.

Schauen wir uns die unten aufgeführten Testergebnisse an.

TESTERGEBNIS 1

Abb. 4. Testergebnis 1

TESTERGEBNIS 2

Abb. 5. Testergebnis 2

Die obigen Charts veranschaulichen den Leistungstest des EA. Im GIF können wir die Aufzeichnung jedes erkannten Signals beobachten. Sie können weitere Tests durchführen, indem Sie Eingabeparameter, Zeitrahmen und stochastische Niveaus ändern, bis Sie Ergebnisse erzielen, die Ihren Anforderungen entsprechen.


Schlussfolgerung

In diesem Artikel haben wir den „Pulse Trader“ Expert Advisor entwickelt, der die Indikatoren Bollinger Bands und Stochastic Oscillator kombiniert, um Handelssignale für die Zeitrahmen M15, M30 und H1 zu generieren. Das System erkennt überkaufte/überverkaufte Bedingungen nur, wenn mehrere Zeitrahmen übereinstimmen, was die Erfolgswahrscheinlichkeit erhöht. Gründliches Backtesting unter verschiedenen Marktbedingungen ist unerlässlich. Zukünftige Verbesserungen könnten das Hinzufügen von Trendrichtungsfiltern, ein erweitertes Risikomanagement und die Verfeinerung der Signallogik für verschiedene Markttypen umfassen. Wir ermutigen Händler, „Signal Pulse“ zusammen mit ihren eigenen Strategien und Techniken zu verwenden, um einen umfassenden Ansatz für den Handel zu erhalten.

Datum Name des Werkzeugs  Beschreibung Version  Aktualisierungen  Hinweis
01/10/24 Chart Projector Skript zur Überlagerung der Kursentwicklung des Vortages mit Geistereffekt. 1.0 Erste Veröffentlichung Erstes Werkzeug in Lynnchris Tool Chest
18/11/24 Analytical Comment Er liefert Informationen zum Vortag in Tabellenform und nimmt die zukünftige Marktentwicklung vorweg. 1.0 Erste Veröffentlichung Zweites Werkzeug in Lynnchris Tool Chest
27/11/24 Analytics Master Regelmäßige Aktualisierung der Marktmetriken alle zwei Stunden  1.01 Zweite Veröffentlichung Drittes Werkzeug in Lynnchris Tool Chest
02/12/24 Analytics Forecaster  Regelmäßige Aktualisierung der Marktmetriken alle zwei Stunden mit Telegram-Integration 1.1 Dritte Auflage Werkzeug 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 Werkzeug Nummer 5
19/12/24 Mean Reversion Signal Reaper Analysiert den Markt anhand der Mean-Reversion-Strategie und liefert Signale  1.0  Erste Veröffentlichung  Werkzeug Nummer 6 
9/01/2025  Signal Pulse  Analysator für mehrere Zeitrahmen 1.0  Erste Veröffentlichung  Werkzeug Nummer 7 

Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16861

Beigefügte Dateien |
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 9): External Flow Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 9): External Flow
In diesem Artikel wird eine neue Dimension der Analyse unter Verwendung externer Bibliotheken untersucht, die speziell für fortgeschrittene Analysen entwickelt wurden. Diese Bibliotheken, wie z. B. Pandas, bieten leistungsstarke Werkzeuge für die Verarbeitung und Interpretation komplexer Daten, die es Händlern ermöglichen, tiefere Einblicke in die Marktdynamik zu gewinnen. Durch die Integration solcher Technologien können wir die Lücke zwischen Rohdaten und umsetzbaren Strategien schließen. Begleiten Sie uns, wenn wir den Grundstein für diesen innovativen Ansatz legen und das Potenzial der Kombination von Technologie und Handelskompetenz erschließen.
Hidden Markov Modelle für trendfolgende Volatilitätsprognosen Hidden Markov Modelle für trendfolgende Volatilitätsprognosen
Hidden Markov Modelle (HMM) sind leistungsstarke statistische Instrumente, die durch die Analyse beobachtbarer Kursbewegungen die zugrunde liegenden Marktzustände identifizieren. Im Handel verbessern HMM die Volatilitätsprognose und liefern Informationen für Trendfolgestrategien, indem sie Marktverschiebungen modellieren und antizipieren. In diesem Artikel stellen wir das vollständige Verfahren zur Entwicklung einer Trendfolgestrategie vor, die HMM zur Prognose der Volatilität als Filter einsetzt.
Meistern der Log-Einträge (Teil 4): Speichern der Protokolle in Dateien Meistern der Log-Einträge (Teil 4): Speichern der Protokolle in Dateien
In diesem Artikel zeige ich Ihnen die grundlegenden Dateioperationen und wie Sie einen flexiblen Handler zur Anpassung konfigurieren. Wir werden die Klasse CLogifyHandlerFile aktualisieren, um Protokolle direkt in die Datei zu schreiben. Wir werden einen Leistungstest durchführen, indem wir eine Strategie für EURUSD eine Woche lang simulieren und bei jedem Tick Protokolle erstellen, mit einer Gesamtzeit von 5 Minuten und 11 Sekunden. Das Ergebnis wird in einem zukünftigen Artikel verglichen, in dem wir ein Caching-System zur Verbesserung der Leistung implementieren werden.
Meistern der Log-Einträge (Teil 3): Erkunden von Handles zum Speichern von Protokollen Meistern der Log-Einträge (Teil 3): Erkunden von Handles zum Speichern von Protokollen
In diesem Artikel werden wir das Konzept der Handler in der Logging-Bibliothek erkunden, verstehen, wie sie funktionieren, und drei erste Implementierungen erstellen: Konsole, Datenbank und Datei. Wir werden alles von der grundlegenden Struktur der Handler bis hin zu praktischen Tests behandeln, um den Boden für ihre volle Funktionalität in zukünftigen Artikeln zu bereiten.