English
preview
Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 17): Der TrendLoom EA

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 17): Der TrendLoom EA

MetaTrader 5Handelssysteme | 23 Juni 2025, 07:48
39 3
Christian Benjamin
Christian Benjamin

Inhalt



Einführung

Die Methoden der Marktanalyse und der Einstiegsbestätigung sind bei den Trendanalysten unterschiedlich. Viele Händler prüfen mehrere Zeitrahmen wie M1, M5 und M15 oder H1, H4 und W1, um ihre Eingaben zu validieren und die Zuverlässigkeit der Signale zu erhöhen. Anstatt den Zeitrahmen zu ändern, um den Gesamttrend abzuschätzen, drücken Sie einfach eine Taste und erhalten eine zeitnahe Aktualisierung oder werden automatisch aktualisiert. Haben Sie schon einmal einen Verkauf in einem niedrigeren Zeitrahmen gesehen, einen Handel abgeschlossen und dann einen Chart in einem höheren Zeitrahmen geöffnet, nur um einen Kauftrend zu entdecken?

TrendLoom EA wurde entwickelt, um diesen Fehler zu vermeiden. Es verfügt über ein Panel mit sieben Schaltflächen, die verschiedene Handelsstile darstellen. Jede Schaltfläche zeigt drei Zeitrahmen, die zusammen mit gleitenden Durchschnitten analysiert werden, um Signale wie KAUF, VERKAUF oder NEUTRAL zu erzeugen. Dieses robuste Tool bietet schnelle Bestätigungs-Updates und aktualisiert kontinuierlich relevante Signale, sobald sie erkannt werden.


Überblick über die Strategie

Der TrendLoom EA ist als grafische Oberfläche (Panel) aufgebaut. Das Panel enthält sieben Schaltflächen, die jeweils einer bestimmten Handelsstrategie entsprechen
  • Kurzfristiger Fokus (M1, M5, M15)
  • Skalierung/Intraday (M5, M15, H1)
  • Swing-Handel (M15, H1, H4)
  • Trendhandel (H1, H4, D1)
  • MTF Trend-Bestätigung (H1, H4, W1)
  • Kurzfristiges Scalping/Mittelfristiger Trend (M5, H1, D1)
  • Langfristiger Trend (H1, D1, W1)

Schauen wir uns an, wie der EA die Signale KAUFEN, VERKAUFEN oder NEUTRAL (BUY, SELL, NEUTRAL) erzeugt, wenn eine Schaltfläche gedrückt wird.

  • Sammeln von Daten: Für jeden der drei Zeitrahmen (z. B. M1, M5 und M15) ruft der EA den Schlusskurs der letzten vollständig abgeschlossenen Kerze ab.
  • Berechnung des SMA: Für jeden Zeitrahmen berechnet der EA einen einfachen gleitenden Durchschnitt (SMA) über 50 Perioden. Dieser SMA dient als Benchmark für den aktuellen Kurs.
Generierung einzelner Signale: Der EA vergleicht den Schlusskurs mit dem entsprechenden SMA

  • Liegt der Kurs über dem SMA, wird dies als Aufwärts-Zeichen gewertet und der Wert +1 zugewiesen.
  • Liegt der Kurs unter dem SMA, wird dies als Abwärts-Zeichen gewertet und der Wert -1 zugewiesen.
  • Wenn der Kurs dem SMA entspricht, ist das Signal neutral (0).

Kombinieren der Signale

  • Die drei einzelnen Signale (eines aus jedem Zeitrahmen) werden addiert.
  • Bestimmung des endgültigen Signals:
  • Wenn die Summe 2 oder mehr beträgt, deutet dies auf ein starkes Aufwärts-Momentum hin. Der EA liefert das Signal für einen „KAUF“.
  • Wenn die Summe -2 oder weniger beträgt, deutet dies auf ein starkes Abwärts-Momentum hin. Der EA liefert das Signal für einen „VERKAUF“.
  • Andernfalls sind die Signale gemischt oder neutral, sodass der EA „NEUTRAL“ zurückgibt.

Zum besseren Verständnis des Prozesses betrachten wir das folgende Ablaufdiagramm.

Ablaufdiagramm

Abb. 1. Ablaufdiagramm


MQL5-Implementierung

Ganz oben finden Sie die Kommentare in der Kopfzeile und die Eigenschaftsdefinitionen des EA. Diese Zeilen dienen als Metadaten für den EA, geben sein Copyright und seine Version an und verlinken ihn mit seiner Quelle. Die Direktive #property strict wird verwendet, um strengere Kompilierungsregeln zu erzwingen und so häufige Kodierungsfehler zu vermeiden.

//+------------------------------------------------------------------+
//|                                                 TrendLoom EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"
#property strict

Als Nächstes enthält der Code mehrere Header-Dateien, die Dialog-, Schaltflächen-, Label- und Panel-Steuerelemente bereitstellen. Außerdem können Sie mit den Steuerelementen für Chartobjekte Text im Chart anzeigen. Diese modulare Einbindung ermöglicht es dem EA, vorgefertigte Klassen für die Nutzeroberfläche zu verwenden.

Diese Include-Richtlinien verweisen auf Bibliotheken im Include-Ordner Ihres MetaEditors. Die Dateien im Unterordner Controls bieten integrierte Klassen für Dialoge und Schaltflächen. Sie bieten auch Klassen für Kennzeichnungen und Panels an. Dieses Design vereinfacht die Erstellung einer interaktiven Schnittstelle, ohne dass der Code umgeschrieben werden muss. Mit der Datei im Unterordner ChartObjects (ChartObjectsTxtControls.mqh) können Sie dynamischen Text im Chart anzeigen.

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

Anschließend werden Konstanten für die Textausrichtung und ein Farbwert definiert. Diese Praxis verbessert die Klarheit und Wartbarkeit des Codes.

#ifndef ALIGN_LEFT
  #define ALIGN_LEFT   0
#endif
#ifndef ALIGN_CENTER
  #define ALIGN_CENTER 1
#endif
#ifndef ALIGN_RIGHT
  #define ALIGN_RIGHT  2
#endif

#define clrSilver 0xC0C0C0

Der EA deklariert Eingabeparameter, die das Aussehen und die Position des Panels und seiner Schaltflächen anpassen. PanelX, PanelY und PanelWidth legen die Geometrie des Panels fest, während die Farbeingaben das visuelle Thema definieren. Die Abmessungen der Schaltflächen werden mit btnWidth, btnHeight und btnSpacing gesteuert, und mit EA können Sie sowohl das Layout als auch die Farben anpassen. Diese Konfiguration bietet Flexibilität, um die Nutzeroberfläche an Ihre Bedürfnisse anzupassen.

//---- Input parameters -----------------------------------------------
input int    PanelX               = 10;
input int    PanelY               = 10;
input int    PanelWidth           = 250;
input int    btnWidth             = 220;
input int    btnHeight            = 30;
input int    btnSpacing           = 5;

input color  PanelBackgroundColor = clrDimGray;
input color  PanelHeaderColor     = clrBlueViolet;
input color  ButtonBgColor        = clrBlack;
input color  ButtonTextColor      = clrBlueViolet;
input color  AnalysisTextColor    = clrLime;

Arrays speichern die Schaltflächennamen und -texte, was das Aktualisieren oder Hinzufügen neuer Schaltflächen schnell und einfach macht. Dieses Design zentralisiert alle Informationen zu den Schaltflächen an einer Stelle, sodass Änderungen nur geringfügige Anpassungen erfordern. Außerdem wird die Konsistenz der Nutzeroberfläche verbessert und die Fehleranfälligkeit verringert. Die Methode bietet Flexibilität für zukünftige Erweiterungen und hält den Code sauber und übersichtlich.

//---- Button Names and Texts (7 analysis options) --------------------
string buttonNames[7] =
  {
   "btnShortTerm",
   "btnScalping",
   "btnSwing",
   "btnTrend",
   "btnMTFTrend",
   "btnShortScalper",
   "btnLongTerm"
  };

string buttonTexts[7] =
  {
   "Short Term Focus\n(M1, M5, M15)",
   "Scalping/Intraday\n(M5, M15, H1)",
   "Swing Trading\n(M15, H1, H4)",
   "Trend Trading\n(H1, H4, D1)",
   "MTF Trend Confirm\n(H1, H4, W1)",
   "Short Scalper/Mid Trend\n(M5, H1, D1)",
   "Long Term Trend\n(H1, D1, W1)"
  };

Globale Makros definieren die Namen für den Panelkopf und die Analysebeschriftung. Diese Makros gewährleisten die Konsistenz des gesamten Codes und dienen als eine einzige Quelle für diese Bezeichnungen. Durch die Zentralisierung dieser Namen wird die Aktualisierung der Komponenten des Panels einfacher und das Risiko von Tippfehlern verringert. Dieser Ansatz vereinfacht die Wartung und gewährleistet einen konsistenten, klaren Code.

// Global object names for panel header and analysis label
#define PANEL_BG "PanelBG"
#define PANEL_HEADER "PanelHeader"
#define ANALYSIS_LABEL "AnalysisResult"

Der Code deklariert dann zwei Hilfsfunktionen: GetSMA berechnet den einfachen gleitenden Durchschnitt und AnalyzeTimeframes führt eine Marktanalyse über mehrere Zeitrahmen durch. Diese Funktionen bilden den Kern der Logik der Marktanalyse.

//--- Helper function declarations
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift);
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3);

Die nutzerdefinierte Klasse CTrendLoomPanel wird von CAppDialog abgeleitet. Sie gruppiert alle Elemente der Nutzeroberfläche, wie z. B. die Kopfzeile, das Hauptfenster, die Schaltflächen und die Ergebnisliste. Dieses Design schafft eine modulare Schnittstelle, die leichter zu verwalten und zu erweitern ist.

Erstellen des Panels

Die Methode CreateTrendPanel erstellt zunächst ein Dialogfenster. Anschließend wird ein Kopftext mit nutzerdefiniertem Text, Farbe, Schriftgröße und Schriftart erstellt. Die Ausrichtung wird mit der Funktion ObjectSetInteger festgelegt.

bool CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2)
{
   if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2))
   {
      Print("Failed to create TrendLoom dialog.");
      return false;
   }
   if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30))
   {
      Print("Failed to create header label.");
      return false;
   }
   m_lblHeader.Text("TrendLoom EA");
   m_lblHeader.Color(PanelHeaderColor);
   m_lblHeader.FontSize(14);
   m_lblHeader.Font("Segoe UI");
   Add(m_lblHeader);
   if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER))
      Print("Failed to set header alignment");

Die Methode fährt fort mit der Erstellung des Hauptpanels und der dynamischen Berechnung seiner Abmessungen. Anschließend werden die einzelnen Schaltflächen erstellt und nacheinander positioniert. Schließlich wird ein Ergebnisetikett unter den Schaltflächen hinzugefügt, um die Analyseergebnisse anzuzeigen.

Handhabung von Ereignissen

Die Methode OnEvent verarbeitet Nutzerinteraktionen. Wenn eine Schaltfläche angeklickt wird, ruft sie AnalyzeTimeframes mit den entsprechenden Zeitrahmenparametern auf. Das Analyseergebnis wird auf dem Bedienfeld aktualisiert und eine Warnmeldung wird angezeigt.

bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(sparam == "btnShortTerm")
   {
      string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15);
      string out = "Short Term Focus: " + res;
      UpdateResults(out);
      Alert(out);
      return true;
   }
   else if(sparam == "btnScalping")
   {
      string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1);
      string out = "Scalping/Intraday: " + res;
      UpdateResults(out);
      Alert(out);
      return true;
   }
   // Additional conditions for other buttons
   return false;
}

Aktualisierung der Nutzeroberfläche

Mit der Methode UpdateResults wird das Ergebnis mit neuen Analysedaten aktualisiert. Anschließend wird ChartRedraw aufgerufen, damit die aktualisierten Informationen sofort angezeigt werden.

void UpdateResults(const string &result)
{
   m_lblResults.Text("Analysis Result: " + result);
   ChartRedraw();
}

Zentrale Analysefunktionen

Berechnung des einfachen gleitenden Durchschnitts (SMA)

Die Funktion GetSMA berechnet den SMA, indem sie ein Indikator-Handle mit der Funktion iMA erstellt. Es kopiert die SMA-Werte aus dem Indikatorpuffer und gibt dann den Handle frei, um Ressourcen freizugeben.
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift)
{
   int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE);
   if(handle == INVALID_HANDLE)
   {
      Print("Failed to create iMA handle for timeframe ", timeframe);
      return 0.0;
   }
   double sma[];
   if(CopyBuffer(handle, 0, shift, 1, sma) <= 0)
   {
      Print("Failed to copy buffer for timeframe ", timeframe);
      IndicatorRelease(handle);
      return 0.0;
   }
   double result = sma[0];
   IndicatorRelease(handle);
   return result;
}

Analysieren mehrerer Zeitrahmen

Die Funktion AnalyzeTimeframes ruft den Schlusskurs und den SMA für drei Zeitrahmen ab und weist ein Aufwärtssignal zu, wenn der Kurs den SMA übersteigt, oder ein Aufwärtssignal, wenn er darunter fällt. Die einzelnen Signale werden addiert und ergeben eine endgültige Empfehlung: KAUFEN, wenn die Summe 2 oder höher ist, VERKAUFEN, wenn sie -2 oder niedriger ist und ansonsten NEUTRAL. Jeder Zeitrahmen wird unabhängig ausgewertet, um einen ausgewogenen Überblick über die Markttrends zu erhalten, während der Shift-Parameter sicherstellt, dass nur die letzte abgeschlossene Kerze für die Analyse verwendet wird. Durch die Kombination von Signalen aus mehreren Zeitrahmen werden die Auswirkungen des vorübergehenden Marktrauschens verringert, und durch die Anpassung der SMA-Periode wird die Empfindlichkeit der Handelssignale weiter verfeinert.

string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3)
{
   int period = 50;
   int shift  = 1; // last completed candle

   double price1 = iClose(_Symbol, tf1, shift);
   double sma1   = GetSMA(_Symbol, tf1, period, shift);
   int signal1   = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0);

   double price2 = iClose(_Symbol, tf2, shift);
   double sma2   = GetSMA(_Symbol, tf2, period, shift);
   int signal2   = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0);

   double price3 = iClose(_Symbol, tf3, shift);
   double sma3   = GetSMA(_Symbol, tf3, period, shift);
   int signal3   = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0);

   int sum = signal1 + signal2 + signal3;
   if(sum >= 2)
      return "BUY";
   else if(sum <= -2)
      return "SELL";
   else
      return "NEUTRAL";
}
Die Lebenszyklusfunktionen des EA übernehmen die Initialisierung, die Bereinigung und die Ereignisverarbeitung. Die Funktion OnInit erstellt das TrendLoom-Panel unter Verwendung der Eingabeparameter. Schlägt die Erstellung eines Panels fehl, gibt der EA einen Initialisierungsfehler zurück.
int OnInit()
{
   if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400))
   {
      Print("Failed to create TrendLoom Panel.");
      return INIT_FAILED;
   }
   return INIT_SUCCEEDED;
}

Die Funktion OnDeinit löscht das Panel, wenn der EA entfernt oder das Chart geschlossen wird.

void OnDeinit(const int reason)
{
   TrendPanel.Destroy(reason);
}

Schließlich leitet die Funktion OnChartEvent Chartereignisse an den Event-Handler des Panels weiter, sodass die Schnittstelle reaktionsfähig bleibt.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   TrendPanel.ChartEvent(id, lparam, dparam, sparam);
}

In Ihrem MetaEditor werden die erforderlichen Dateien im Include-Ordner gespeichert. Um auf die angegebenen Dateien zuzugreifen, verweisen Sie auf die Unterordner, die in den folgenden Charts dargestellt sind. Diese Organisation stellt sicher, dass der Compiler die Dialog-, Schaltflächen-, Label- und Panel-Steuerungsdateien im Ordner include/Controls und die Chartobjektsteuerungen im Ordner include/ChartObjects findet.

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

Schritt 1

Abb. 2. Schritt 1

Schritt 2

Abb. 3. Schritt 2


MQL5 Code

//+------------------------------------------------------------------+
//|                                                 TrendLoom EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"
#property strict

#include <Controls/Dialog.mqh>
#include <Controls/Button.mqh>
#include <Controls/Label.mqh>
#include <Controls/Panel.mqh>
#include <ChartObjects/ChartObjectsTxtControls.mqh>  // Adjusted include path (singular folder)

// Define alignment constants if not already defined
#ifndef ALIGN_LEFT
#define ALIGN_LEFT   0
#endif
#ifndef ALIGN_CENTER
#define ALIGN_CENTER 1
#endif
#ifndef ALIGN_RIGHT
#define ALIGN_RIGHT  2
#endif

#define clrSilver 0xC0C0C0

//---- Input parameters -----------------------------------------------
input int    PanelX               = 10;       // Top-left X coordinate of panel
input int    PanelY               = 10;       // Top-left Y coordinate of panel
input int    PanelWidth           = 250;      // Panel width (for longer text)
input int    btnWidth             = 220;      // Button width
input int    btnHeight            = 30;       // Button height
input int    btnSpacing           = 5;        // Spacing between buttons

input color  PanelBackgroundColor = clrDimGray;     // Panel background color
input color  PanelHeaderColor     = clrBlueViolet;  // Panel header text color

input color  ButtonBgColor        = clrBlack;       // Button background color
input color  ButtonTextColor      = clrBlueViolet;  // Button text color

input color  AnalysisTextColor    = clrLime;        // Analysis result text color

//---- Button Names and Texts (7 analysis options) --------------------
string buttonNames[7] =
  {
   "btnShortTerm",
   "btnScalping",
   "btnSwing",
   "btnTrend",
   "btnMTFTrend",
   "btnShortScalper",
   "btnLongTerm"
  };

string buttonTexts[7] =
  {
   "Short Term Focus\n(M1, M5, M15)",
   "Scalping/Intraday\n(M5, M15, H1)",
   "Swing Trading\n(M15, H1, H4)",
   "Trend Trading\n(H1, H4, D1)",
   "MTF Trend Confirm\n(H1, H4, W1)",
   "Short Scalper/Mid Trend\n(M5, H1, D1)",
   "Long Term Trend\n(H1, D1, W1)"
  };

// Global object names for panel header and analysis label
#define PANEL_BG "PanelBG"
#define PANEL_HEADER "PanelHeader"
#define ANALYSIS_LABEL "AnalysisResult"

//--- Helper function declarations
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift);
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3);

//------------------------------------------------------------------------------
// CTrendLoomPanel class - A modern, modular panel for TrendLoom EA
//------------------------------------------------------------------------------
class CTrendLoomPanel : public CAppDialog
  {
private:
   CLabel            m_lblHeader;
   CPanel            m_panelMain;
   CButton           m_btnShortTerm;
   CButton           m_btnScalping;
   CButton           m_btnSwing;
   CButton           m_btnTrend;
   CButton           m_btnMTFTrend;
   CButton           m_btnShortScalper;
   CButton           m_btnLongTerm;
   CLabel            m_lblResults;

public:
   // Create the TrendLoom Panel dialog
   bool              CreateTrendPanel(const long chart, const string name, const int x1, const int y1, const int x2, const int y2)
     {
      if(!CAppDialog::Create(chart, name, 0, x1, y1, x2, y2))
        {
         Print("Failed to create TrendLoom dialog.");
         return false;
        }
      // Create header label
      if(!m_lblHeader.Create(0, "TrendLoomHeader", 0, 10, 10, x2 - x1 - 20, 30))
        {
         Print("Failed to create header label.");
         return false;
        }
      m_lblHeader.Text("TrendLoom EA");
      m_lblHeader.Color(PanelHeaderColor);
      m_lblHeader.FontSize(14);
      m_lblHeader.Font("Segoe UI");
      Add(m_lblHeader);
      // Set header text alignment to center using ObjectSetInteger
      if(!ObjectSetInteger(0L, m_lblHeader.Name(), OBJPROP_ALIGN, (long)ALIGN_CENTER))
         Print("Failed to set header alignment");

      // Create main panel background
      int panelBottom = 50 + (btnHeight + btnSpacing) * 7 + btnSpacing;
      if(!m_panelMain.Create(0, "TrendLoomPanel", 0, 10, 50, x2 - x1 - 10, panelBottom))
        {
         Print("Failed to create main panel.");
         return false;
        }
      m_panelMain.Color(PanelBackgroundColor);
      m_panelMain.BorderType(BORDER_RAISED);
      m_panelMain.ColorBorder(clrSilver);
      Add(m_panelMain);

      // Starting coordinates for buttons
      int btnX = 20; // relative to dialog
      int btnY = 60;
      int buttonWidth = btnWidth;
      int buttonHeight = btnHeight;

      // Create each button with a modern look
      if(!m_btnShortTerm.Create(0, buttonNames[0], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnShortTerm.Text(buttonTexts[0]);
      m_btnShortTerm.Font("Segoe UI");
      m_btnShortTerm.FontSize(12);
      m_btnShortTerm.Color(ButtonBgColor);
      Add(m_btnShortTerm);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnScalping.Create(0, buttonNames[1], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnScalping.Text(buttonTexts[1]);
      m_btnScalping.Font("Segoe UI");
      m_btnScalping.FontSize(12);
      m_btnScalping.Color(ButtonBgColor);
      Add(m_btnScalping);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnSwing.Create(0, buttonNames[2], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnSwing.Text(buttonTexts[2]);
      m_btnSwing.Font("Segoe UI");
      m_btnSwing.FontSize(12);
      m_btnSwing.Color(ButtonBgColor);
      Add(m_btnSwing);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnTrend.Create(0, buttonNames[3], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnTrend.Text(buttonTexts[3]);
      m_btnTrend.Font("Segoe UI");
      m_btnTrend.FontSize(12);
      m_btnTrend.Color(ButtonBgColor);
      Add(m_btnTrend);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnMTFTrend.Create(0, buttonNames[4], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnMTFTrend.Text(buttonTexts[4]);
      m_btnMTFTrend.Font("Segoe UI");
      m_btnMTFTrend.FontSize(12);
      m_btnMTFTrend.Color(ButtonBgColor);
      Add(m_btnMTFTrend);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnShortScalper.Create(0, buttonNames[5], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnShortScalper.Text(buttonTexts[5]);
      m_btnShortScalper.Font("Segoe UI");
      m_btnShortScalper.FontSize(12);
      m_btnShortScalper.Color(ButtonBgColor);
      Add(m_btnShortScalper);
      btnY += buttonHeight + btnSpacing;

      if(!m_btnLongTerm.Create(0, buttonNames[6], 0, btnX, btnY, btnX + buttonWidth, btnY + buttonHeight))
         return false;
      m_btnLongTerm.Text(buttonTexts[6]);
      m_btnLongTerm.Font("Segoe UI");
      m_btnLongTerm.FontSize(12);
      m_btnLongTerm.Color(ButtonBgColor);
      Add(m_btnLongTerm);
      btnY += buttonHeight + btnSpacing;

      // Create results label below the buttons
      if(!m_lblResults.Create(0, "TrendResults", 0, btnX, btnY, btnX + buttonWidth, btnY + 30))
         return false;
      m_lblResults.Text("Analysis Result: [Waiting for Input]");
      m_lblResults.Font("Segoe UI");
      m_lblResults.FontSize(12);
      m_lblResults.Color(AnalysisTextColor);
      Add(m_lblResults);
      // Set results text alignment to left using ObjectSetInteger
      if(!ObjectSetInteger(0L, m_lblResults.Name(), OBJPROP_ALIGN, (long)ALIGN_LEFT))
         Print("Failed to set results alignment");

      Show();
      return true;
     }

   // Process events (button clicks)
   bool              OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
     {
      if(sparam == "btnShortTerm")
        {
         string res = AnalyzeTimeframes(PERIOD_M1, PERIOD_M5, PERIOD_M15);
         string out = "Short Term Focus: " + res;
         UpdateResults(out);
         Alert(out);
         return true;
        }
      else
         if(sparam == "btnScalping")
           {
            string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_M15, PERIOD_H1);
            string out = "Scalping/Intraday: " + res;
            UpdateResults(out);
            Alert(out);
            return true;
           }
         else
            if(sparam == "btnSwing")
              {
               string res = AnalyzeTimeframes(PERIOD_M15, PERIOD_H1, PERIOD_H4);
               string out = "Swing Trading: " + res;
               UpdateResults(out);
               Alert(out);
               return true;
              }
            else
               if(sparam == "btnTrend")
                 {
                  string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_D1);
                  string out = "Trend Trading: " + res;
                  UpdateResults(out);
                  Alert(out);
                  return true;
                 }
               else
                  if(sparam == "btnMTFTrend")
                    {
                     string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_H4, PERIOD_W1);
                     string out = "MTF Trend Confirm: " + res;
                     UpdateResults(out);
                     Alert(out);
                     return true;
                    }
                  else
                     if(sparam == "btnShortScalper")
                       {
                        string res = AnalyzeTimeframes(PERIOD_M5, PERIOD_H1, PERIOD_D1);
                        string out = "Short Scalper/Mid Trend: " + res;
                        UpdateResults(out);
                        Alert(out);
                        return true;
                       }
                     else
                        if(sparam == "btnLongTerm")
                          {
                           string res = AnalyzeTimeframes(PERIOD_H1, PERIOD_D1, PERIOD_W1);
                           string out = "Long Term Trend: " + res;
                           UpdateResults(out);
                           Alert(out);
                           return true;
                          }
      return false;
     }

   bool              ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
     {
      return OnEvent(id, lparam, dparam, sparam);
     }

   // Update the results label and refresh the chart
   void              UpdateResults(const string &result)
     {
      m_lblResults.Text("Analysis Result: " + result);
      ChartRedraw();
     }
  };

// Global instance of the TrendLoom Panel
CTrendLoomPanel TrendPanel;

//------------------------------------------------------------------------------
// Helper functions (core analysis logic)
//------------------------------------------------------------------------------
double GetSMA(string symbol, ENUM_TIMEFRAMES timeframe, int period, int shift)
  {
   int handle = iMA(symbol, timeframe, period, 0, MODE_SMA, PRICE_CLOSE);
   if(handle == INVALID_HANDLE)
     {
      Print("Failed to create iMA handle for timeframe ", timeframe);
      return 0.0;
     }
   double sma[];  // dynamic array to store SMA values
   if(CopyBuffer(handle, 0, shift, 1, sma) <= 0)
     {
      Print("Failed to copy buffer for timeframe ", timeframe);
      IndicatorRelease(handle);
      return 0.0;
     }
   double result = sma[0];
   IndicatorRelease(handle);
   return result;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string AnalyzeTimeframes(ENUM_TIMEFRAMES tf1, ENUM_TIMEFRAMES tf2, ENUM_TIMEFRAMES tf3)
  {
   int period = 50;
   int shift  = 1; // last completed candle

   double price1 = iClose(_Symbol, tf1, shift);
   double sma1   = GetSMA(_Symbol, tf1, period, shift);
   int signal1   = (price1 > sma1) ? 1 : (price1 < sma1 ? -1 : 0);

   double price2 = iClose(_Symbol, tf2, shift);
   double sma2   = GetSMA(_Symbol, tf2, period, shift);
   int signal2   = (price2 > sma2) ? 1 : (price2 < sma2 ? -1 : 0);

   double price3 = iClose(_Symbol, tf3, shift);
   double sma3   = GetSMA(_Symbol, tf3, period, shift);
   int signal3   = (price3 > sma3) ? 1 : (price3 < sma3 ? -1 : 0);

   int sum = signal1 + signal2 + signal3;
   if(sum >= 2)
      return "BUY";
   else
      if(sum <= -2)
         return "SELL";
      else
         return "NEUTRAL";
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(!TrendPanel.CreateTrendPanel(0, "TrendLoom Panel", PanelX, PanelY, PanelX + PanelWidth + 20, PanelY + 400))
     {
      Print("Failed to create TrendLoom Panel.");
      return INIT_FAILED;
     }
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   TrendPanel.Destroy(reason);
  }

//+------------------------------------------------------------------+
//| Chart Event Handler                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
  {
   TrendPanel.ChartEvent(id, lparam, dparam, sparam);
  }
//+------------------------------------------------------------------+


Ergebnisse

Es ist von entscheidender Bedeutung für jeden Händler, seine Systeme gründlich zu testen, bevor er sie im Live-Handel einsetzt. Das Testen beinhaltet Backtests mit historischen Daten, um zu sehen, wie das System ohne Risiko abgeschnitten hätte. Sie können auch Demo-Live-Konten verwenden, um die tatsächliche Leistung in Echtzeit zu beobachten. Dieser Prozess hilft Ihnen bei der Feinabstimmung und Entwicklung eines zuverlässigeren Tools, das Sie getrost auf einem Live-Konto einsetzen können. Ich persönlich ziehe es vor, viel Zeit mit dem Testen und Verfeinern des EA zu verbringen, um robustere Ergebnisse zu erzielen.

In diesem Abschnitt stelle ich die Testergebnisse des EA vor, der auf dem Chart läuft. Ich habe es an der Volatilität 75 (1s) getestet und es hat wunderbare und profitable Ergebnisse geliefert. Jede Taste funktioniert wie vorgesehen, und die Analyseergebnisse werden fast sofort aktualisiert, wenn Sie eine Taste drücken. Schauen wir uns den ersten Test unten an.

Abb. 4. Volatilität 75 (1s) Test

Das folgende Chart veranschaulicht, wie sich der Markt nach der Ausführung eines Handels auf der Grundlage des bereitgestellten Signals verhalten hat. Dieses Chart setzt den im obigen GIF gezeigten Handel fort. Ich habe den M1-Zeitrahmen verwendet, um einen breiteren Überblick über die Handelsgeschäfte zu erhalten.

Abb. 5. V 75 (1s) Prüfung


Schlussfolgerung

Nachdem ich den EA erstellt und getestet habe, kann ich getrost bestätigen, dass er sich positiv auf die Marktanalyse auswirkt. Die schnelle Signalverarbeitung und die allgemeine Trendauswertung haben bei den Volatilitätsindizes gute Ergebnisse erzielt. Dieses Instrument dient jedoch als ergänzendes Hilfsmittel und nicht als endgültiger Signalgeber. Ich möchte Sie ermutigen, das Programm gründlich zu testen und die Parameter Ihren Wünschen entsprechend anzupassen. Sie können sie auch weiter verändern, um das Aussehen der Schaltflächen anzupassen. Verwenden Sie es, um Ihre Gesamtstrategie zu bestätigen, ich habe gesehen, dass es auf diese Weise effektiv ist.

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 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/25  Parabolischer Stopp und Umkehr (PSAR)  Automatisierung der PSAR-Strategie 1.0 Erste Veröffentlichung  Toolkit Nummer 14
20/02/25  Quarters Drawer Script  Einzeichnen der Viertel- oder Quarter-Ebenen in die Tabelle  1.0  Erste Veröffentlichung  Toolkit Nummer 15 
27/02/25  Intrusion Detector Erkennen und warnen, wenn der Preis ein Quarter-Niveau erreicht 1.0   Erste Veröffentlichung Toolkit Nummer 16 
27/02/25  TrendLoom Tool  Analysepanel für mehrere Zeitrahmen 1.0 Erste Veröffentlichung Toolkit Nummer 17

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

Beigefügte Dateien |
TrendLoom_EA.mq5 (26.63 KB)
Letzte Kommentare | Zur Diskussion im Händlerforum (3)
linfo2
linfo2 | 21 März 2025 in 03:01
Wow, fantastisch, ich kann sehen, dass da eine Menge Mühe hineingesteckt wurde. Danke, dass Sie Ihren Ansatz und Ihren Code mit uns teilen.
Christian Benjamin
Christian Benjamin | 21 März 2025 in 11:21
linfo2 #:
Wow, phantastisch, ich kann sehen, dass da eine Menge Mühe hineingesteckt wurde. Danke, dass Sie Ihren Ansatz und Ihren Code mit uns teilen.
Gern geschehen. Vielen Dank, dass Sie sich gemeldet haben👏.
gardee005
gardee005 | 25 März 2025 in 16:49
Ihre Arbeit gefällt mir sehr, ich habe sie verfolgt. eine gute Auswahl an Ideen, die auch umgesetzt werden. danke!
Handel mit dem MQL5 Wirtschaftskalender (Teil 6): Automatisierung des Handelseinstiegs mit der Analyse von Nachrichtenereignissen und Countdown-Timern Handel mit dem MQL5 Wirtschaftskalender (Teil 6): Automatisierung des Handelseinstiegs mit der Analyse von Nachrichtenereignissen und Countdown-Timern
In diesem Artikel implementieren wir einen automatischen Handelseinstieg mit dem MQL5-Wirtschaftskalender, indem wir nutzerdefinierte Filter und Zeitverschiebungen anwenden, um qualifizierte Nachrichtenereignisse zu identifizieren. Wir vergleichen die prognostizierten und die vorherigen Werte, um zu entscheiden, ob ein KAUF oder VERKAUF eröffnet werden soll. Dynamische Countdown-Timer zeigen die verbleibende Zeit bis zur Veröffentlichung von Nachrichten an und werden nach einem Handel automatisch zurückgesetzt.
Automatisieren von Handelsstrategien in MQL5 (Teil 10): Entwicklung der Strategie Trend Flat Momentum Automatisieren von Handelsstrategien in MQL5 (Teil 10): Entwicklung der Strategie Trend Flat Momentum
In diesem Artikel entwickeln wir einen Expert Advisor in MQL5 für die Strategie Trend Flat Momentum. Wir kombinieren das Kreuzen zweier gleitender Durchschnitte, gefiltert mit dem Momentum von RSI und CCI, um Handelssignale zu generieren. Wir befassen uns auch mit Backtests und möglichen Verbesserungen für die reale Leistung.
Analyse mehrerer Symbole mit Python und MQL5 (Teil 3): Dreieck der Wechselkurse Analyse mehrerer Symbole mit Python und MQL5 (Teil 3): Dreieck der Wechselkurse
Händler sehen sich oft mit Drawdowns aufgrund falscher Signale konfrontiert, während das Warten auf eine Bestätigung zu verpassten Chancen führen kann. In diesem Artikel wird eine dreieckige Handelsstrategie vorgestellt, die den Silberpreis in Dollar (XAGUSD) und Euro (XAGEUR) zusammen mit dem EURUSD-Wechselkurs verwendet, um das Rauschen herauszufiltern. Durch die Nutzung marktübergreifender Beziehungen können Händler versteckte Stimmungen aufdecken und ihre Eingaben in Echtzeit verfeinern.
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 55): SAC mit priorisierter Erfahrungswiederholung MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 55): SAC mit priorisierter Erfahrungswiederholung
Replay-Puffer sind beim Reinforcement Learning besonders wichtig bei Off-Policy-Algorithmen wie DQN oder SAC. Damit wird das Sampling-Verfahren dieses Speicherpuffers in den Mittelpunkt gerückt. Während bei den Standardoptionen von SAC beispielsweise eine zufällige Auswahl aus diesem Puffer verwendet wird, wird bei den priorisierten Erfahrungswiederholungspuffern eine Feinabstimmung vorgenommen, indem eine Auswahl aus dem Puffer auf der Grundlage eines TD-Scores erfolgt. Wir gehen auf die Bedeutung des Reinforcement Learning ein und untersuchen wie immer nur diese Hypothese (nicht die Kreuzvalidierung) in einem von einem Assistenten zusammengestellten Expert Advisor.