English 日本語
preview
Automatisieren von Handelsstrategien in MQL5 (Teil 1): Das Profitunity System (Trading Chaos von Bill Williams)

Automatisieren von Handelsstrategien in MQL5 (Teil 1): Das Profitunity System (Trading Chaos von Bill Williams)

MetaTrader 5Handel | 8 April 2025, 07:33
186 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In diesem Artikel befassen wir uns mit dem Profitunity System, einer von Bill Williams entwickelten Handelsstrategie, die darauf abzielt, vom „Chaos“ des Marktes zu profitieren, indem sie eine Reihe von Schlüsselindikatoren nutzt, und zeigen, wie sie in MetaQuotes Language 5 (MQL5) automatisiert werden kann. Wir beginnen mit einem Überblick über die Strategie und ihre wichtigsten Grundsätze. Anschließend gehen wir den Implementierungsprozess in MQL5 durch und konzentrieren uns dabei auf die Codierung der wichtigsten Indikatoren und die Automatisierung von Ein- und Ausstiegssignalen. Anschließend testen und optimieren wir das System, um die Leistung unter verschiedenen Marktbedingungen sicherzustellen. Abschließend erörtern wir das Potenzial und die Effektivität des Profitunity Systems im automatisierten Handel. Die Abschnitte, die wir in diesem Artikel behandeln, umfassen:

  1. Übersicht über das Profitunity System
  2. Strategieumsetzung in MQL5
  3. Testen und Optimieren von Strategien
  4. Schlussfolgerung

Am Ende dieses Artikels werden Sie wissen, wie Sie das Profitunity System mit MQL5 automatisieren können, und zwar von der Implementierung der Kennzahlen bis zur Optimierung der Performance. Dadurch erhalten Sie das Rüstzeug, um Ihre Handelsstrategie zu verbessern und das „Chaos“ am Markt für potenzielle Handelsergebnisse zu nutzen. Lassen Sie uns eintauchen.


Übersicht über das Profitunity System

Das von Bill Williams entwickelte Profitunity System verwendet eine Reihe spezialisierter Indikatoren, die es uns ermöglichen, die chaotischen Bewegungen auf dem Markt zu verstehen und darauf zu reagieren. Die Strategie kombiniert die Stärke von Trendfolge- und Momentum-Indikatoren zu einer dynamischen, hochgradig reaktionsfähigen Handelsmethodik. Das System identifiziert Trendumkehrungen und Marktbeschleunigungen und hilft uns dabei, Handels-Setups mit hoher Wahrscheinlichkeit zu finden. Die in der Strategie verwendeten Schlüsselindikatoren sind:

  • Fractals
  • Alligator
  • Awesome Oscillator (AO)
  • Accelerator Oscillator (AC)

Jeder dieser Indikatoren arbeitet zusammen und liefert wichtige Einblicke in die Marktbedingungen und bietet Einstiegs- und Ausstiegssignale. Schauen wir uns die einzelnen Indikatoreinstellungen, die für die Strategie gelten, genauer an.

Indikatoreinstellungen

Der Indikator Fractals: Er identifiziert Umkehrpunkte auf dem Markt. Die Fraktale entstehen, wenn fünf aufeinanderfolgende Balken vorhanden sind, wobei der mittlere Balken der höchste oder niedrigste ist. Sie signalisieren den potenziellen Beginn eines neuen Trends oder einer Preisumkehr, was bei der Markierung lokaler Höchst- oder Tiefststände hilfreich ist und einen frühzeitigen Hinweis auf einen möglichen Trendwechsel gibt. 2 oder 5 Perioden sind die Standardeinstellungen für die Fraktale. Das heißt, es wird nach Mustern gesucht, bei denen ein einzelner Balken von zwei Balken auf beiden Seiten umgeben ist, die niedriger (für fraktale Abwärtsbewegungen) oder höher (für fraktale Aufwärtsbewegungen) sind. So sieht es in der Grafik aus.

FRACTALS

Der Alligator: Dieser Indikator ist eine Kombination aus drei geglätteten gleitenden Durchschnitten - bekannt als Kiefer, Zähne und Lippen (Jaw, Teeth, Lips) - die zusammenarbeiten, um den Markttrend zu bestimmen. Die Interaktion zwischen diesen Linien hilft uns zu erkennen, ob sich der Markt in einem Trend befindet oder konsolidiert. Wenn die Linien beginnen, sich auseinander zu bewegen, signalisiert dies einen Trend; wenn sie konvergieren, deutet dies darauf hin, dass sich der Markt in einer Konsolidierungsphase befindet.

Einstellungen:

  • Kiefer (blaue Linie): Periodenlänge 13, verschoben um 8 Takte
  • Zähne (Rote Linie): Periodenlänge 8, verschoben um 5 Balken
  • Lippen (grüne Linie): Periodenlänge 5, verschoben um 3 Balken

Der Indikator hilft uns, die Trendrichtung und das Timing sowie Marktein- und -austritte zu erkennen. Hier sind die Einstellungen in der Tabelle.

ALLIGATOR

Der Indikator Awesome Oscillator (AO): Bei diesem Indikator handelt es sich um einen Momentum-Indikator, der die Differenz zwischen einem gleitenden Durchschnitt mit einer Periodenlänge von 34 und einem von 5 des Medianpreises berechnet. Es hilft uns, die Stärke und Richtung eines Trends abzuschätzen, indem die Differenz zwischen diesen beiden gleitenden Durchschnitten als Histogramm dargestellt wird. Die Einstellungen für diesen Indikator sind Standardwerte.

Die AO wird in der Regel verwendet, um eine steigende oder fallende Dynamik auf dem Markt zu erkennen und um Trendwechsel zu erkennen. Ein Histogramm oberhalb der Nulllinie zeigt eine Aufwärtsdynamik an, während ein Histogramm unterhalb der Nulllinie eine Abwärtsdynamik signalisiert.

Der Indikator Accelerator Oscillator (AC): Er ist vom AO-Indikator abgeleitet und misst die Beschleunigung der Marktdynamik. Sie gibt Aufschluss darüber, ob sich die Marktdynamik beschleunigt oder verlangsamt, was für die Erkennung von Trendänderungen von entscheidender Bedeutung ist, bevor sie sich voll entfalten. Der AC oszilliert um die Nulllinie und bewegt sich in grünen (positiven) oder roten (negativen) Bereichen. Seine Einstellungen sind auch die Standardeinstellungen.

Der AC-Indikator wird in Verbindung mit dem AO-Indikator verwendet, um eine Bestätigung der Marktstärke und der Momentumverschiebungen zu liefern und sicherzustellen, dass sich der Markt stark in eine Richtung bewegt, bevor ein Handel eingegangen wird. Werfen wir nun einen Blick auf die Ein- und Ausstiegsbedingungen, wie sie vom System verwendet werden. Die AO- und AC-Indikatoren würden der folgenden Abbildung entsprechen.

AO UND AC

Ein- und Ausstiegsbedingungen

Das System verwendet eine Reihe spezifischer Bedingungen für den Einstieg in und den Ausstieg aus dem Handel, die auf den sequentiellen Signalen der Indikatoren Fractal, Alligator, Accelerator Oscillator (AC) und Awesome Oscillator (AO) beruhen. Die Signale arbeiten zusammen, um sicherzustellen, dass nur dann gehandelt wird, wenn der Markt eine eindeutige Bestätigung der Richtung liefert, wodurch das Risiko von Fehlsignalen reduziert wird.

Die Eröffnungsbedingung für einen Kauf:

  1. Fraktales Signal: Ein fraktales Abwärtssignal tritt auf, wenn die Kursbewegung eine Reihe von niedrigeren Höchstständen bildet, was auf eine potenzielle Kursumkehr nach oben hindeutet.
  2. Alligator Line Breakdown: Die blaue Linie des Alligators (Kiefer) wurde von unten nach oben durchbrochen, was den Beginn eines Aufwärtstrends anzeigt.
  3. Bestätigung durch den Accelerator Oscillator (AC): Der AC befindet sich im grünen Bereich, was ein Aufwärtsmomentum anzeigt und die Stärke des Trends unterstützt.
  4. Bestätigung durch den Awesome Oscillator (AO): Das AO-Histogramm kreuzt von unten nach oben über der Nulllinie, was die Aufwärtsdynamik weiter bestätigt.

Bedingungen für einen Kauf:

Ein Einstieg zum Kauf wird ausgelöst, wenn das Histogramm des AO-Indikators die Nulllinie von unten nach oben durchbricht, was einen Anstieg des Aufwärtsmomentums bestätigt. Dies ist ein Anzeichen dafür, dass sich ein starker Aufwärtstrend entwickelt, und dies ist der Zeitpunkt, an dem wir eine Marktkaufposition eröffnen. Unten sehen Sie ein Beispiel für ein Kaufsignal auf dem Chart des MetaTrader 5.

MT5 KAUF-SIGNAL

Die Eröffnungsbedingung für einen Verkauf:

  1. Fraktales Signal: Ein fraktales Aufwärtssignal tritt auf, wenn der Kursverlauf eine Reihe höherer Tiefststände bildet, was auf eine mögliche Kursumkehr nach unten hindeutet.
  2. Ausbruch der Linie des Alligators: Die blaue Linie des Alligators (Kiefer) wurde von oben nach unten durchbrochen, was den Beginn eines Abwärtstrends signalisiert.
  3. Bestätigung durch den Accelerator Oscillator (AC): Der AC befindet sich im roten Bereich, was ein starkes Abwärtsmomentum bestätigt und auf eine hohe Wahrscheinlichkeit einer weiteren Abwärtsbewegung hindeutet.
  4. Bestätigung durch den Awesome Oscillator (AO): Das AO-Histogramm kreuzt von oben nach unten unter der Nulllinie und signalisiert damit einen Abwärtstrend.

Bedingungen für einen Verkauf:

Die Eröffnung eines Verkaufs wird ausgelöst, wenn das AO-Histogramm von oben unter die Nulllinie fällt, was ein Abwärtsmomentum bestätigt. Dies deutet darauf hin, dass sich der Markt wahrscheinlich weiter abwärts bewegen wird, und ist der Punkt, an dem wir eine Marktverkaufsposition eröffnen.

Ausstiegs- oder Umkehrbedingungen:

  1. Umkehr der Alligator Linie: Es kommt zu einer Umkehr der grünen Alligator-Linie (Lippen), was auf das Ende des aktuellen Trends hindeutet. Die Umkehrung der Lippen deutet darauf hin, dass sich der Kurs nun umkehren oder konsolidieren könnte.
  2. Umkehr des Accelerator Oscillator (AC): Der AC wechselt von der grünen in die rote Zone (oder umgekehrt) und signalisiert damit eine potenzielle Veränderung des Impulses. Dies ist ein frühes Anzeichen dafür, dass sich die Marktdynamik verschiebt und der aktuelle Trend möglicherweise zu Ende geht.
  3. Umkehr des Awesome Oscillator (AO): Das AO-Histogramm, das die Nulllinie in die entgegengesetzte Richtung kreuzt, bestätigt ebenfalls, dass eine Trendumkehr wahrscheinlich ist.

Bedingung für den Ausstieg:

In unserem Fall werden wir uns jedoch dafür entscheiden, die Positionen zu beenden, wenn die Histogramme des AO-Indikators in die entgegengesetzte Zone kreuzen, was auf eine Verschiebung der Marktdynamik hinweist.

Durch die Kombination der vorgenannten Indikatoren bietet das Profitunity System einen leistungsstarken Ansatz zur Identifizierung von Marktumkehrungen und starken Trendchancen. Im nächsten Abschnitt werden wir erörtern, wie diese Einstiegs- und Ausstiegsbedingungen in MQL5 implementiert werden können, um eine vollständige Automatisierung dieser Strategie zu ermöglichen.


Strategieumsetzung in MQL5

Nachdem wir alle Theorien über das Profitunity System von Bill William gelernt haben, wollen wir die Theorie automatisieren und einen Expert Advisor (EA) in MetaQuotes Language 5 (MQL5) für MetaTrader 5 erstellen.

Um einen Expert Advisor (EA) zu erstellen, klicken Sie in Ihrem MetaTrader 5-Terminal auf die Registerkarte Extras und aktivieren Sie MetaQuotes Language Editor oder drücken Sie einfach F4 auf Ihrer Tastatur. Alternativ können Sie auch auf das IDE-Symbol (Integrated Development Environment) in der Symbolleiste klicken. Dadurch wird die Umgebung des MetaQuotes-Spracheditors geöffnet, die das Schreiben von Handelsrobotern, technischen Indikatoren, Skripten und Funktionsbibliotheken ermöglicht.

META-EDITOR ÖFFNEN

Sobald der MetaEditor geöffnet ist, navigieren Sie in der Symbolleiste zur Registerkarte „Datei“ und wählen Sie „Neue Datei“, oder drücken Sie einfach die Tastenkombination STRG + N, um ein neues Dokument zu erstellen. Alternativ könnten wir auch auf das Symbol New auf der Registerkarte Werkzeuge klicken. Daraufhin erscheint ein Popup-Fenster des MQL-Assistenten.

EA NEU ERSTELLEN

In dem sich öffnenden Assistenten markieren wir die Option Expert Advisor (Template bzw. Vorlage) und klicken auf Weiter (Next).

MQL WIZARD

Wir geben in den allgemeinen Eigenschaften des Expert Advisors unter dem Abschnitt Name den Dateinamen Ihres Experten an. Nicht vergessen, den Backslash vor dem Namen des EA verwenden, um einen Ordner anzugeben oder zu erstellen, wenn er nicht existiert. Hier haben wir zum Beispiel standardmäßig „Experts\“. Das bedeutet, dass unser EA im Ordner Experts erstellt wird und wir ihn dort finden können. Die anderen Abschnitte sind ziemlich einfach, aber Sie können dem Link am Ende des Assistenten folgen, um zu erfahren, wie der Prozess genau abläuft.

NEUER EA-NAME

Nachdem Sie den gewünschten Expert Advisor-Dateinamen eingegeben haben, klicken Sie auf Weiter, dann auf Weiter und schließlich auf Fertig stellen. Nachdem wir all dies getan haben, können wir nun unsere Strategie programmieren.

Zunächst definieren wir einige Metadaten über den Expert Advisor (EA). Dazu gehören der Name des EA, die Copyright-Informationen und ein Link zur MetaQuotes-Website. Wir geben auch die Version des EA an, die auf „1.00“ eingestellt ist.

//+------------------------------------------------------------------+
//|              1. PROFITUNITY (TRADING CHAOS BY BILL WILLIAMS).mq5 |
//|      Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader. |
//|                                     https://forexalgo-trader.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader"
#property link      "https://forexalgo-trader.com"
#property description "1. PROFITUNITY (TRADING CHAOS BY BILL WILLIAMS)"
#property version   "1.00"

Dadurch werden beim Laden des Programms die System-Metadaten angezeigt. Anschließend können wir einige globale Variablen hinzufügen, die wir im Programm verwenden werden. Zunächst binden wir eine Handelsinstanz ein, indem wir #include am Anfang des Quellcodes verwenden. Dadurch erhalten wir Zugriff auf die Klasse „CTrade“, die wir zur Erstellung eines Handelsobjekts verwenden werden. Dies ist von entscheidender Bedeutung, da wir sie zur Eröffnung von Handelsgeschäften benötigen.

#include <Trade/Trade.mqh>
CTrade obj_Trade;

Der Präprozessor wird die Zeile #include <Trade/Trade.mqh> durch den Inhalt der Datei Trade.mqh ersetzen. Die spitzen Klammern zeigen an, dass die Datei Trade.mqh aus dem Standardverzeichnis verwendet werden soll (normalerweise ist es das Terminal-Installationsverzeichnis\MQL5\Include). Das aktuelle Verzeichnis wird bei der Suche nicht berücksichtigt. Die Zeile kann an beliebiger Stelle im Programm platziert werden, aber in der Regel werden alle Einbindungen am Anfang des Quellcodes platziert, um den Code besser zu strukturieren und die Referenz zu erleichtern. Die Deklaration des Objekts obj_Trade der Klasse CTrade ermöglicht uns dank der MQL5-Entwickler einen einfachen Zugriff auf die in dieser Klasse enthaltenen Methoden.

CTRADE CLASS

Danach müssen wir mehrere wichtige Indikator-Handles deklarieren, die wir im Handelssystem verwenden werden.

int handle_Fractals = INVALID_HANDLE; //--- Initialize fractals indicator handle with an invalid handle value
int handle_Alligator = INVALID_HANDLE; //--- Initialize alligator indicator handle with an invalid handle value
int handle_AO = INVALID_HANDLE; //--- Initialize Awesome Oscillator (AO) handle with an invalid handle value
int handle_AC = INVALID_HANDLE; //--- Initialize Accelerator Oscillator (AC) handle with an invalid handle value

Hier richten wir Anfangsvariablen ein, die die Handles für jeden technischen Indikator im Programm enthalten. Insbesondere initialisieren wir vier Ganzzahlvariablen: „handle_Fractals“, „handle_Alligator“, „handle_AO“ und „handle_AC“, mit dem Wert INVALID_HANDLE.

Jedes dieser Handles dient als Referenz für den Zugriff auf die jeweiligen Indikatoren im gesamten Code. Durch die Zuweisung des Anfangswertes „INVALID_HANDLE“ stellen wir sicher, dass jede Handle-Variable eindeutig einen ungültigen Zustand aufweist, bis später im Code eine ordnungsgemäße Initialisierung stattfindet. Diese Einstellung verhindert Fehler durch die Verwendung eines nicht initialisierten Handles und hilft zu erkennen, wenn ein Indikator während des Initialisierungsprozesses nicht geladen werden kann.

Zusammenfassend lässt sich sagen, was die Indikatoren im Einzelnen bewirken werden:

  • „handle_Fractals“ speichert das Handle für den Fractals-Indikator.
  • „handle_Alligator“ speichert das Handle für den Alligator-Indikator.
  • „handle_AO“ speichert das Handle für den Awesome Oscillator.
  • „handle_AC“ speichert das Handle für den Accelerator Oscillator.

Als Nächstes müssen wir Arrays und Konstanten definieren und initialisieren, die zum Speichern und Verarbeiten von Daten aus den in diesem Expert Advisor verwendeten Indikatoren erforderlich sind, die wir speziell über initialisierte Indikator-Handles abrufen. Wir werden dies der Reihe nach tun, damit alles übersichtlich und einfach zu referenzieren ist.

double fractals_up[]; //--- Array to store values for upward fractals
double fractals_down[]; //--- Array to store values for downward fractals

double alligator_jaws[]; //--- Array to store values for Alligator's Jaw line
double alligator_teeth[]; //--- Array to store values for Alligator's Teeth line
double alligator_lips[]; //--- Array to store values for Alligator's Lips line

double ao_values[]; //--- Array to store values of the Awesome Oscillator (AO)

double ac_color[]; //--- Array to store color status of the Accelerator Oscillator (AC)
#define AC_COLOR_UP 0 //--- Define constant for upward AC color state
#define AC_COLOR_DOWN 1 //--- Define constant for downward AC color state

Wir beginnen mit der Erstellung von zwei Arrays, „fractals_up“ und „fractals_down“, in denen Werte für nach oben bzw. nach unten gerichtete Fraktale gespeichert werden. Anhand dieser Felder können wir bestimmte fraktale Punkte verfolgen, die uns helfen, bedeutende Preisumkehrungen oder Muster zu erkennen.

Als Nächstes richten wir drei Arrays ein - „alligator_jaws“, „alligator_teeth“ und „alligator_lips“ -, um die Werte der verschiedenen Zeilen des Alligator-Indikators zu speichern. Indem wir diese Werte in separaten Arrays gespeichert, können wir den Status jeder Alligator-Linie effizient nachverfolgen und sie in Querverweisen für Handelssignale verwenden.

Dann definieren wir das Array „ao_values“, um die Werte des Awesome Oscillators (AO) zu speichern. Die AO wird uns helfen, die Marktdynamik und -trends zu erkennen, und die Speicherung dieser Werte wird es uns ermöglichen, Veränderungen im Laufe der Zeit zu analysieren und sie auf unsere Handelsbedingungen anzuwenden.

Schließlich definieren wir das Array „ac_color“, um den Farbstatus des Accelerator Oscillators (AC) zu erfassen. Dieses Array enthält Informationen über die Aufwärts- oder Abwärtsbewegung, die wir als Farbzustand speichern werden. Um dies zu erleichtern, definieren wir zwei Konstanten: „AC_COLOR_UP“ (auf 0 gesetzt) und „AC_COLOR_DOWN“ (auf 1 gesetzt). Diese Konstanten stellen die Farbzustände des AC dar, wobei grün (aufwärts) für ein dynamisches Wachstum und rot (abwärts) für eine Verlangsamung des Trends steht. Dieser Aufbau vereinfacht unsere Logik, wenn wir später den AC-Status auf Handelssignale überprüfen.

Sie haben vielleicht bemerkt, dass wir die Werte anderer Indikatoren als die der Fraktale direkt speichern können. Der Grund dafür ist, dass ihre Werte auf jedem Balken leicht verfügbar sind. Was jedoch die Fraktale betrifft, so bilden sie sich an bestimmten Swing-Punkten, die mindestens 3 Balken vom aktuellen Balken entfernt sind. Wir können also nicht einfach irgendeinen der fraktalen Balken abrufen, da sie sich nur bedingt bilden. Wir brauchen also eine Logik, um den vorherigen fraktalen Wert und seine Richtung zu verfolgen. Das ist die Logik, die wir anwenden.

double lastFractal_value = 0.0; //--- Variable to store the value of the last detected fractal
enum fractal_direction {FRACTAL_UP, FRACTAL_DOWN, FRACTAL_NEUTRAL}; //--- Enum for fractal direction states
fractal_direction lastFractal_direction = FRACTAL_NEUTRAL; //--- Variable to store the direction of the last fractal

Hier definieren wir Variablen und eine Enumeration, um die Daten des letzten Fraktals, das in unserer Handelsanalyse entdeckt wurde, zu speichern und zu verwalten. Zunächst deklarieren wir die Variable „lastFractal_value“ und initialisieren sie mit „0.0“. Diese Variable speichert den numerischen Wert des letzten Fraktals, das wir im Chart entdecken. Wenn wir diesen Wert im Auge behalten, können wir ihn mit dem aktuellen Kurs vergleichen und fraktale Formationen auf potenzielle Handelssignale hin analysieren.

Als nächstes definieren wir eine Enumeration namens „fractal_direction“ mit drei möglichen Zuständen: „FRACTAL_UP", „FRACTAL_DOWN“ und „FRACTAL_NEUTRAL“. Diese Zustände stellen die Richtung des letzten Fraktals dar:

  • „FRACTAL_UP“ zeigt ein aufwärts gerichtetes Fraktal an und signalisiert damit potenziell rückläufige Bedingungen.
  • „FRACTAL_DOWN“ zeigt ein abwärts gerichtetes Fraktal an und signalisiert damit potenziell steigende Kurse.
  • „FRACTAL_NEUTRAL“ steht für einen Zustand, in dem keine spezifische fraktale Richtung bestätigt wurde.

Schließlich deklarieren wir eine Variable, „lastFractal_direction“, vom Typ „fractal_direction“ und initialisieren sie mit „FRACTAL_NEUTRAL“. Diese Variable enthält die Richtung des zuletzt erkannten Fraktals, sodass wir innerhalb der Handelslogik Richtungseinschätzungen auf der Grundlage der jüngsten Fraktaldaten vornehmen können.

Nun können wir zur eigentlichen Logik der Code-Verarbeitung übergehen. Wir müssen unsere Indikatoren initialisieren und werden daher direkt in die Funktion OnInit eintauchen, die bei jeder Initialisierung des Programms aufgerufen und ausgeführt wird.
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   //---

   //---
   return(INIT_SUCCEEDED); //--- Return successful initialization status
}

Dies ist einfach der Standard-Initialisierungs-Ereignishandler, den wir verwenden werden, um die Steuerlogik unseres Programms zu initialisieren. Als Nächstes müssen wir die Indikatoren initialisieren, damit sie auf dem Chart gestartet werden und wir sie zum Abrufen von Daten und für Handelsentscheidungen verwenden können. Zunächst wird der Fraktalindikator wie unten beschrieben initialisiert.

   handle_Fractals = iFractals(_Symbol,_Period); //--- Initialize the fractals indicator handle
   if (handle_Fractals == INVALID_HANDLE){ //--- Check if the fractals indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE FRACTALS INDICATOR. REVERTING NOW!"); //--- Print error if fractals initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Hier initialisieren wir die Variable „handle_Fractals“ durch den Aufruf der Funktion iFractals. Diese Funktion erstellt ein Handle für den Fractals-Indikator, der auf das angegebene Symbol (durch _Symbol) und die aktuelle Chartperiode (_Period) angewendet wird. Indem wir „handle_Fractals“ auf den Rückgabewert von iFractals setzen, ermöglichen wir den Zugriff auf die Indikatordaten, die wir später zur Analyse fraktaler Formationen in unserer Strategie verwenden können.

Nach dem Versuch, den Fraktal-Indikator zu initialisieren, wird überprüft, ob dies gelungen ist, indem geprüft wird, ob „handle_Fractals“ gleich INVALID_HANDLE ist. Der Wert von „INVALID_HANDLE“ zeigt an, dass der Indikator nicht initialisiert werden konnte, was verschiedene Gründe haben kann, z. B. fehlende Systemressourcen oder falsche Parameter.

Wenn die Initialisierung fehlschlägt, verwenden wir die Funktion Print, um eine Fehlermeldung auszugeben: „ERROR: UNABLE TO INITIALIZE THE FRACTALS INDICATOR. REVERTING NOW!!“, an das Journal. Diese Meldung dient als eindeutiger Hinweis auf das Problem und erleichtert die Fehlersuche. Wir geben dann INIT_FAILED zurück, um die Funktion OnInit zu beenden und damit zu signalisieren, dass der Initialisierungsprozess nicht erfolgreich abgeschlossen werden konnte. Mit dieser Prüfung wird sichergestellt, dass der Expert Advisor nicht mit einer unvollständigen Einrichtung fortfährt, was zu Fehlern bei der Ausführung führen könnte. Dasselbe gilt für die Initialisierung des Alligator-Indikators.

   handle_Alligator = iAlligator(_Symbol,_Period,13,8,8,5,5,3,MODE_SMMA,PRICE_MEDIAN); //--- Initialize the alligator indicator with specific settings
   if (handle_Alligator == INVALID_HANDLE){ //--- Check if the alligator indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR. REVERTING NOW!"); //--- Print error if alligator initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Wir initialisieren die Variable „handle_Alligator“, indem wir die Funktion iAlligator aufrufen. Der Indikator Alligator benötigt mehrere Parameter, um seine drei Linien (Kiefer, Zähne und Lippen) zu definieren, von denen jede auf Markttrends reagiert. Wir legen diese Einstellungen wie folgt fest: „13“ für die Periodenlänge des Kiefers, „8“ für die Periodenlänge der Zähne und „5“ für die Periodenlänge der Lippen. Zusätzlich definieren wir für jede Linie die Shift-Werte „8“, „5“ und „3“, setzen die Berechnungsmethode auf MODE_SMMA (geglätteter gleitender Durchschnitt) und verwenden PRICE_MEDIAN als Preistyp.

Nachdem wir versucht haben, den Alligator-Indikator zu initialisieren, prüfen wir, ob "handle_Alligator" einen gültigen Handle hat. Wenn er gleich INVALID_HANDLE ist, bedeutet dies, dass der Initialisierungsprozess fehlgeschlagen ist. Dies könnte auf unzureichende Ressourcen oder falsche Parameter zurückzuführen sein, sodass der Alligator-Indikator nicht richtig funktioniert.

Wenn die Initialisierung fehlschlägt, rufen wir die Funktion Print auf, um eine Fehlermeldung anzuzeigen: „ERROR: UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR. REVERTING NOW!“ Diese Meldung macht uns auf das Problem aufmerksam, sodass wir es leichter diagnostizieren und beheben können. Nach dem Drucken der Meldung wird INIT_FAILED zurückgegeben, wodurch die Funktion OnInit beendet wird und angezeigt wird, dass die Initialisierung nicht erfolgreich abgeschlossen wurde. 

Wir verwenden einen ähnlichen Ansatz, um die Indikatoren AO und AC wie folgt zu initialisieren.

   handle_AO = iAO(_Symbol,_Period); //--- Initialize the Awesome Oscillator (AO) indicator handle
   if (handle_AO == INVALID_HANDLE){ //--- Check if AO indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AO INDICATOR. REVERTING NOW!"); //--- Print error if AO initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AC = iAC(_Symbol,_Period); //--- Initialize the Accelerator Oscillator (AC) indicator handle
   if (handle_AC == INVALID_HANDLE){ //--- Check if AC indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AC INDICATOR. REVERTING NOW!"); //--- Print error if AC initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Nachdem alle Indikatoren erfolgreich initialisiert wurden, können wir sie dem Chart automatisch hinzufügen, wenn das Programm geladen wird. Um dies zu erreichen, verwenden wir die folgende Logik.

   if (!ChartIndicatorAdd(0,0,handle_Fractals)){ //--- Add the fractals indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE FRACTALS INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if fractals addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Hier versuchen wir, den Fractals-Indikator mithilfe der Funktion ChartIndicatorAdd zum Haupt-Chartfenster hinzuzufügen. Wir übergeben „0“ als Chart-ID (die das aktuelle Chart angibt) und geben „0“ als Fenster-ID an, die auf das HauptChartfenster abzielt. Die Variable "handle_Fractals", die wir zuvor initialisiert haben, um das Handle des Fractals-Indikators zu speichern, wird übergeben, um diesen spezifischen Indikator hinzuzufügen.

Nach dem Aufruf der Funktion ChartIndicatorAdd prüfen wir, ob der Funktionsaufruf erfolgreich war. Wird „false“ zurückgegeben, dargestellt durch „!“, bedeutet dies, dass der Indikator Fraktale nicht zum Chart hinzugefügt werden konnte. Dies könnte aufgrund von Kartenbeschränkungen oder unzureichenden Ressourcen scheitern. In diesem Fall wird mit Print eine Fehlermeldung angezeigt, um uns zu warnen: „ERROR: UNABLE TO ADD THE FRACTALS INDICATOR TO CHART. REVERTING NOW!“ Anhand dieser Meldung können wir bei der Fehlersuche schnell die Ursache des Problems ermitteln.

Wenn die Hinzufügung fehlschlägt, geben wir INIT_FAILED zurück, um die OnInit-Funktion mit einem Fehlerstatus zu beenden. Dadurch wird sichergestellt, dass der Expert Advisor nicht ausgeführt wird, wenn der Fractals-Indikator im Chart fehlt, was dazu beiträgt, spätere Ausführungsfehler zu vermeiden, indem die visuelle Verfügbarkeit des Indikators bestätigt wird. Eine ähnliche Logik wird verwendet, um den Alligator-Indikator hinzuzufügen, da er sich ebenfalls im Hauptfenster befindet (siehe unten).

   if (!ChartIndicatorAdd(0,0,handle_Alligator)){ //--- Add the alligator indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE ALLIGATOR INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if alligator addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Um die anderen Indikatoren hinzuzufügen, wird ein ähnlicher Ansatz verwendet, nur dass sich die Unterfenster nun ändern, da wir für jeden Indikator jeweils ein neues Unterfenster wie folgt erstellen.

   if (!ChartIndicatorAdd(0,1,handle_AO)){ //--- Add the AO indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AO INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AO addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,2,handle_AC)){ //--- Add the AC indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AC INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AC addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }

Wir fügen die Indikatoren Awesome Oscillator (AO) und Accelerator Oscillator (AC) zu separaten Unterfenstern auf dem Chart hinzu, um sicherzustellen, dass sie jeweils ihre eigene Ansicht haben. Um dies zu erreichen, verwenden wir die Funktion ChartIndicatorAdd für jeden Indikator. Wir geben „0“ für die Chart-ID an (was das aktuelle Chart angibt) und verwenden unterschiedliche Fenster-IDs: „1“ für den AO-Indikator und „2“ für den AC-Indikator, sodass jeder in einem eigenen Teilfenster erscheint. Die Nummerierung ist hier von entscheidender Bedeutung, da sich jeder Indikator in einem eigenen Fenster befinden muss, sodass Sie die Indizierung der Unterfenster genau im Auge behalten müssen.

Wir überprüfen dann den Erfolg jeder einzelnen Zugabe. Wenn ChartIndicatorAdd entweder für den AO- oder den AC-Indikator den Wert „false“ zurückgibt, bedeutet dies, dass der Additionsprozess fehlgeschlagen ist. Im Falle eines Fehlers geben wir eine Fehlermeldung mit „Print“ aus, um zu verdeutlichen, welcher spezifische Indikator nicht geladen werden konnte. Wenn zum Beispiel der AO-Indikator nicht hinzugefügt werden kann, wird „ERROR: UNABLE TO ADD THE AO INDICATOR TO CHART. REVERTING NOW!“ Ebenso geben wir eine Fehlermeldung aus, wenn die Addition des AC-Indikators fehlschlägt.

Wenn einer der beiden Indikatorzusätze fehlschlägt, wird sofort INIT_FAILED zurückgegeben, wodurch die OnInit-Funktion beendet und die weitere Ausführung verhindert wird. Um sich zu vergewissern, dass alles in Ordnung ist, können wir die Indikator-Handles in das Journal drucken.

   Print("HANDLE ID FRACTALS = ",handle_Fractals); //--- Print the handle ID for fractals
   Print("HANDLE ID ALLIGATOR = ",handle_Alligator); //--- Print the handle ID for alligator
   Print("HANDLE ID AO = ",handle_AO); //--- Print the handle ID for AO
   Print("HANDLE ID AC = ",handle_AC); //--- Print the handle ID for AC

Wenn wir das Programm starten, erhalten wir die folgenden Initialisierungsdaten.

WERTE DER INDIKATOR-HANDLES

Aus dem Bild ist ersichtlich, dass die IDs der Handles mit 10 beginnen und sich bis 13 fortsetzen. Die IDs der Handle sind in MQL5 von entscheidender Bedeutung, da sie es uns ermöglichen, jeden Indikator während des gesamten Lebenszyklus des Expert Advisors zu referenzieren. Wenn eine Funktion wie CopyBuffer Werte aus einem Indikator abruft, ist sie auf diese Handles angewiesen, um auf die richtigen Daten zuzugreifen. Hier stellen die ganzen Zahlen spezifische Bezeichner für jeden initialisierten Indikator dar. Jede ID fungiert als eindeutiger „Zeiger“ innerhalb der MQL5-Umgebung, der jeden Handle mit dem zugehörigen Indikator verbindet. Dadurch weiß der EA, welche Indikatordaten er aus dem Speicher abrufen muss, was eine effiziente Ausführung und eine klare Organisation von indikatorbasierten Aufgaben unterstützt.

Nun müssen wir nur noch die Datenspeicher als Zeitreihen festlegen.

   ArraySetAsSeries(fractals_up,true); //--- Set the fractals_up array as a time series
   ArraySetAsSeries(fractals_down,true); //--- Set the fractals_down array as a time series
   
   ArraySetAsSeries(alligator_jaws,true); //--- Set the alligator_jaws array as a time series
   ArraySetAsSeries(alligator_teeth,true); //--- Set the alligator_teeth array as a time series
   ArraySetAsSeries(alligator_lips,true); //--- Set the alligator_lips array as a time series
   
   ArraySetAsSeries(ao_values,true); //--- Set the ao_values array as a time series
   
   ArraySetAsSeries(ac_color,true); //--- Set the ac_color array as a time series

Hier stellen wir jedes Array so ein, dass es als Zeitreihe arbeitet, d. h. die Daten in jedem Array werden vom neuesten zum ältesten Wert geordnet. Dazu wenden wir die Funktion ArraySetAsSeries auf jedes Array an und übergeben „true“ als zweites Argument. Diese Einstellung stellt sicher, dass der jüngste Datenpunkt immer bei Index 0 erscheint, was besonders bei Handelsanwendungen nützlich ist, wo der Zugriff auf den neuesten Wert für die Entscheidungsfindung in Echtzeit wichtig ist.

Wir beginnen damit, die Arrays „fractals_up“ und „fractals_down“ als Zeitreihen einzustellen, damit wir die letzten aufsteigenden und absteigenden Fraktalwerte effizient verfolgen können. In ähnlicher Weise wenden wir diese Organisation auf die Arrays „alligator_jaws“, „alligator_teeth“ und „alligator_lips“ an, die die drei Zeilen des Alligator-Indikators darstellen. Auf diese Weise können wir in Echtzeit auf die neuesten Werte jeder einzelnen Linie zugreifen, was die Erkennung von Änderungen der Markttrends erleichtert.

Wir konfigurieren auch das Array „ao_values“, das die Daten für den Awesome Oscillator speichert, auf die gleiche Weise. Indem wir ihn als Zeitreihe festlegen, stellen wir sicher, dass der jüngste Oszillatorwert für unsere Berechnungen immer zur Verfügung steht. Schließlich wenden wir diese Struktur auf das Array „ac_color“ an, das den Farbstatus des Accelerator Oscillators verfolgt, sodass der neueste Farbstatus sofort abgerufen werden kann. Der vollständige Initialisierungscode, der für eine reibungslose und saubere Initialisierung verantwortlich ist, sieht wie folgt aus.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   //---
   
   handle_Fractals = iFractals(_Symbol,_Period); //--- Initialize the fractals indicator handle
   if (handle_Fractals == INVALID_HANDLE){ //--- Check if the fractals indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE FRACTALS INDICATOR. REVERTING NOW!"); //--- Print error if fractals initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_Alligator = iAlligator(_Symbol,_Period,13,8,8,5,5,3,MODE_SMMA,PRICE_MEDIAN); //--- Initialize the alligator indicator with specific settings
   if (handle_Alligator == INVALID_HANDLE){ //--- Check if the alligator indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE ALLIGATOR INDICATOR. REVERTING NOW!"); //--- Print error if alligator initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AO = iAO(_Symbol,_Period); //--- Initialize the Awesome Oscillator (AO) indicator handle
   if (handle_AO == INVALID_HANDLE){ //--- Check if AO indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AO INDICATOR. REVERTING NOW!"); //--- Print error if AO initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   handle_AC = iAC(_Symbol,_Period); //--- Initialize the Accelerator Oscillator (AC) indicator handle
   if (handle_AC == INVALID_HANDLE){ //--- Check if AC indicator failed to initialize
      Print("ERROR: UNABLE TO INITIALIZE THE AC INDICATOR. REVERTING NOW!"); //--- Print error if AC initialization failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   
   if (!ChartIndicatorAdd(0,0,handle_Fractals)){ //--- Add the fractals indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE FRACTALS INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if fractals addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,0,handle_Alligator)){ //--- Add the alligator indicator to the main chart window and check for success
      Print("ERROR: UNABLE TO ADD THE ALLIGATOR INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if alligator addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,1,handle_AO)){ //--- Add the AO indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AO INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AO addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   if (!ChartIndicatorAdd(0,2,handle_AC)){ //--- Add the AC indicator to a separate subwindow and check for success
      Print("ERROR: UNABLE TO ADD THE AC INDICATOR TO CHART. REVERTING NOW!"); //--- Print error if AC addition failed
      return (INIT_FAILED); //--- Exit initialization with failed status
   }
   
   Print("HANDLE ID FRACTALS = ",handle_Fractals); //--- Print the handle ID for fractals
   Print("HANDLE ID ALLIGATOR = ",handle_Alligator); //--- Print the handle ID for alligator
   Print("HANDLE ID AO = ",handle_AO); //--- Print the handle ID for AO
   Print("HANDLE ID AC = ",handle_AC); //--- Print the handle ID for AC

   ArraySetAsSeries(fractals_up,true); //--- Set the fractals_up array as a time series
   ArraySetAsSeries(fractals_down,true); //--- Set the fractals_down array as a time series
   
   ArraySetAsSeries(alligator_jaws,true); //--- Set the alligator_jaws array as a time series
   ArraySetAsSeries(alligator_teeth,true); //--- Set the alligator_teeth array as a time series
   ArraySetAsSeries(alligator_lips,true); //--- Set the alligator_lips array as a time series
   
   ArraySetAsSeries(ao_values,true); //--- Set the ao_values array as a time series
   
   ArraySetAsSeries(ac_color,true); //--- Set the ac_color array as a time series
   
   //---
   return(INIT_SUCCEEDED); //--- Return successful initialization status
}

Als Nächstes können wir zur Ereignisbehandlung von OnTick übergehen, wo wir die Steuerungslogik unterbringen.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
//---
}
Dies ist einfach die standardmäßige Ereignisbehandlung eines Tick-Ereignisses, den wir als Grundlage für unsere Steuerungslogik verwenden werden. Als Nächstes müssen wir die Datenwerte aus den Indikator-Handles für die weitere Analyse abrufen.
   if (CopyBuffer(handle_Fractals,0,2,3,fractals_up) < 3){ //--- Copy upward fractals data; check if copying is successful
      Print("ERROR: UNABLE TO COPY THE FRACTALS UP DATA. REVERTING!"); //--- Print error message if failed
      return;
   }
   if (CopyBuffer(handle_Fractals,1,2,3,fractals_down) < 3){ //--- Copy downward fractals data; check if copying is successful
      Print("ERROR: UNABLE TO COPY THE FRACTALS DOWN DATA. REVERTING!"); //--- Print error message if failed
      return;
   }

Hier werden Daten aus den Puffern „fractals_up“ und „fractals_down“ des Indikators „handle_Fractals“ in die entsprechenden Arrays kopiert. Wir verwenden die Funktion CopyBuffer, um Daten aus dem Indikator-Handle abzurufen. Konkret versuchen wir, 3 Datenpunkte ab dem drittletzten Balken (Index 2) sowohl für die Aufwärts- als auch für die Abwärtsfraktale zu kopieren.

Zunächst wird geprüft, ob die Funktion einen Wert von weniger als 3 zurückgibt, was bedeuten würde, dass weniger als 3 Werte erfolgreich in das Array „fractals_up“ kopiert wurden. Wenn dies geschieht, wird eine Fehlermeldung „ERROR: UNABLE TO COPY THE FRACTALS UP DATA. REVERTING!“ ausgedruckt und wir beenden die Funktion, um eine weitere Verarbeitung mit unvollständigen Daten zu verhindern.

In ähnlicher Weise versuchen wir, die abwärts gerichteten Fraktaldaten mit der gleichen CopyBuffer-Funktion in das Array „fractals_down“ zu kopieren. Wenn das Kopieren fehlschlägt (weniger als 3 Werte werden zurückgegeben), wird eine entsprechende Fehlermeldung ausgegeben: „ERROR: UNABLE TO COPY THE FRACTALS DOWN DATA. REVERTING!“ und die Funktion beendet, um weitere Probleme zu vermeiden. Auf diese Weise wird sichergestellt, dass unser Programm nicht mit ungültigen oder unvollständigen Daten fortfährt, sodass die Integrität unserer Handelslogik gewahrt bleibt. Indem wir überprüfen, ob die richtige Anzahl von Werten kopiert wurde, können wir mögliche Fehler bei der Analyse von Fraktalen vermeiden, die für die Erkennung von Marktumkehrpunkten entscheidend sind.

Vielleicht haben Sie jedoch bemerkt, dass die Nummern der Indikatorpuffer variieren: 0 und 1. Dies sind wichtige Indizes, auf die Sie achten müssen, da sie die tatsächlichen Zuordnungspuffer der Indikatorwerte darstellen. Hier eine Illustration, damit wir verstehen, warum wir die spezifischen Indizes verwenden.

DIE INIZES DER PUFFER

Aus dem Bild geht hervor, dass das Fraktal oben das erste ist, also den Index 0 hat, und das Fraktal unten das zweite mit dem Index 1 ist. Mit der gleichen Logik werden die Alligatorlinien abgebildet.

   if (CopyBuffer(handle_Alligator,0,0,3,alligator_jaws) < 3){ //--- Copy Alligator's Jaw data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR JAWS DATA. REVERTING!");
      return;
   }
   if (CopyBuffer(handle_Alligator,1,0,3,alligator_teeth) < 3){ //--- Copy Alligator's Teeth data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR TEETH DATA. REVERTING!");
      return;
   }
   if (CopyBuffer(handle_Alligator,2,0,3,alligator_lips) < 3){ //--- Copy Alligator's Lips data
      Print("ERROR: UNABLE TO COPY THE ALLIGATOR LIPS DATA. REVERTING!");
      return;
   }

Da die Puffer in 3 Zeilen unterteilt sind, beginnen die Pufferindizes von 0 über 1 bis 2. Wenn es nur einen Puffer gibt, wie im Fall des AO-Indikators, dann hätten wir nur einen Pufferindex 0 für die Preise wie unten.

   if (CopyBuffer(handle_AO,0,0,3,ao_values) < 3){ //--- Copy AO data
      Print("ERROR: UNABLE TO COPY THE AO DATA. REVERTING!");
      return;
   }

Dasselbe gilt für den AC-Indikator, wenn wir an seinen Werten interessiert sind. Wir brauchen jedoch nur die Farbe des gebildeten Histogramms zu kennen. Diese können mit der gleichen Logik der Puffernummern erfasst werden, aber in diesem Fall werden die Farbpuffer meist auf den nächsten nicht verfügbaren Pufferindex im Datenfenster abgebildet. In unserem Fall ist es also 0+1=1 wie folgt.

   if (CopyBuffer(handle_AC,1,0,3,ac_color) < 3){ //--- Copy AC color data
      Print("ERROR: UNABLE TO COPY THE AC COLOR DATA. REVERTING!");
      return;
   }

Um die Farbpuffer zu erhalten, öffnen Sie einfach das Eigenschaftsfenster des Indikators und der Farbindex erscheint auf der Registerkarte Parameter.

DIE INIZES DER FARBPUFFER

Nachdem wir die Daten abgerufen und gespeichert haben, können wir sie nutzen, um Handelsentscheidungen zu treffen. Um Ressourcen zu sparen, werden die Prüfungen bei jedem Balken und nicht bei jedem Tick, der erzeugt wird, durchgeführt. Wir brauchen also eine Logik, um neue Balkenformationen zu erkennen.

if (isNewBar()){ //--- Check if a new bar has formed

//---

}

Hier verwenden wir eine nutzerdefinierte Funktion, deren Code unten zu sehen ist.

//+------------------------------------------------------------------+
//|   IS NEW BAR FUNCTION                                            |
//+------------------------------------------------------------------+
bool isNewBar(){ 
   static int prevBars = 0; //--- Store previous bar count
   int currBars = iBars(_Symbol,_Period); //--- Get current bar count for the symbol and period
   if (prevBars == currBars) return (false); //--- If bars haven't changed, return false
   prevBars = currBars; //--- Update previous bar count
   return (true); //--- Return true if new bar is detected
}

Hier definieren wir eine boolesche Funktion namens „isNewBar“, die prüft, ob ein neuer Balken auf dem Chart erschienen ist, was uns hilft, zu erkennen, wann sich eine neue Kerze oder ein neuer Balken gebildet hat, was für die Aktualisierung oder Neuberechnung der Handelsbedingungen unerlässlich ist. Zunächst deklarieren wir eine statische Integer-Variable „prevBars“ und initialisieren sie mit 0. Das Schlüsselwort „static“ stellt sicher, dass der Wert von „prevBars“ über mehrere Funktionsaufrufe hinweg erhalten bleibt und nicht bei jedem Funktionsaufruf zurückgesetzt wird. Dies ermöglicht es uns, die Anzahl der Takte des vorherigen Funktionsaufrufs zu speichern.

Als Nächstes definieren wir eine lokale Integer-Variable „currBars“ und verwenden die integrierte Funktion iBars, um die aktuelle Anzahl der Balken für das ausgewählte Symbol (_Symbol) und die Periode (_Period) abzurufen. Diese Funktion zählt die Gesamtzahl der verfügbaren Balken für den angegebenen Zeitrahmen und speichert sie in „currBars“.

Wir vergleichen dann „prevBars“ mit „currBars“. Wenn die beiden Werte gleich sind, bedeutet dies, dass sich seit dem letzten Aufruf der Funktion kein neuer Balken gebildet hat, also geben wir „false“ zurück, um anzuzeigen, dass kein neuer Balken erkannt wurde. Wenn sich die Anzahl der Balken geändert hat (d. h. ein neuer Balken gebildet wurde), schlägt die Bedingung fehl, und wir aktualisieren „prevBars“ mit der aktuellen Balkenanzahl „currBars“, um den neuen Wert zu berücksichtigen. Schließlich geben wir „true“ zurück, um zu signalisieren, dass ein neuer Balken erkannt wurde.

Innerhalb dieser Funktion können wir nun die Fraktaldaten bestimmen und speichern, indem wir den Wert und die Richtung des zuletzt erkannten Fraktals anhand der in den Arrays „fractals_up“ und „fractals_down“ gespeicherten Daten überprüfen und aktualisieren.

const int index_fractal = 0;
if (fractals_up[index_fractal] != EMPTY_VALUE){ //--- Detect upward fractal presence
   lastFractal_value = fractals_up[index_fractal]; //--- Store fractal value
   lastFractal_direction = FRACTAL_UP; //--- Set last fractal direction as up
}
if (fractals_down[index_fractal] != EMPTY_VALUE){ //--- Detect downward fractal presence
   lastFractal_value = fractals_down[index_fractal];
   lastFractal_direction = FRACTAL_DOWN;
}

Wir beginnen mit der Definition einer konstanten Ganzzahl „index_fractal“ und setzen diese auf 0. Diese Konstante steht für den Index der aktuellen fraktalen Daten, die wir überprüfen wollen. In diesem Fall prüfen wir das erste Fraktal in den Arrays.

Als Nächstes wird geprüft, ob der Wert bei „fractals_up[index_fractal]“ ungleich EMPTY_VALUE ist, was bedeutet, dass ein gültiges Aufwärtsfraktal vorhanden ist. Wenn diese Bedingung erfüllt ist, wird der Wert des aufsteigenden Fraktals in der Variablen „lastFractal_value“ gespeichert. Wir haben auch die „lastFractal_direction“ auf „FRACTAL_UP“ aktualisiert, um anzuzeigen, dass das letzte erkannte Fraktal ein Aufwärtsfraktal war.

Ebenso wird geprüft, ob der Wert bei „fractals_down[index_fractal]“ ungleich EMPTY_VALUE ist, was auf das Vorhandensein eines abwärtsgerichteten Fraktals hinweist. Wenn diese Bedingung erfüllt ist, wird der abwärts gerichtete Fraktalwert in der Variablen „lastFractal_value“ gespeichert und „lastFractal_direction“ auf „FRACTAL_DOWN“ gesetzt, um zu zeigen, dass das letzte erkannte Fraktal abwärts gerichtet war. Wir können dann die erfassten Daten protokollieren und ihre Gültigkeit überprüfen.

if (lastFractal_value != 0.0 && lastFractal_direction != FRACTAL_NEUTRAL){ //--- Ensure fractal is valid
   Print("FRACTAL VALUE = ",lastFractal_value);
   Print("FRACTAL DIRECTION = ",getLastFractalDirection());
}

Damit werden die Fractal-Daten aufgezeichnet. Wir haben eine nutzerdefinierte Funktion verwendet, um die fraktale Richtung zu ermitteln, und das Codeschnipsel sieht wie folgt aus.

//+------------------------------------------------------------------+
//|     FUNCTION TO GET FRACTAL DIRECTION                            |
//+------------------------------------------------------------------+

string getLastFractalDirection(){
   string direction_fractal = "NEUTRAL"; //--- Default direction set to NEUTRAL
   
   if (lastFractal_direction == FRACTAL_UP) return ("UP"); //--- Return UP if last fractal was up
   else if (lastFractal_direction == FRACTAL_DOWN) return ("DOWN"); //--- Return DOWN if last fractal was down
   
   return (direction_fractal); //--- Return NEUTRAL if no specific direction
}

Hier definieren wir die Funktion „getLastFractalDirection“, um die Richtung des zuletzt erkannten Fraktals zu ermitteln und zurückzugeben. Die Funktion prüft den Wert der Variablen „lastFractal_direction“, die die letzte fraktale Richtung (entweder aufwärts oder abwärts) festhält. Wir beginnen mit der Initialisierung der Variablen „direction_fractal“ vom typ string und setzen sie standardmäßig auf „NEUTRAL“. Das bedeutet, dass die Funktion „NEUTRAL“ als Ergebnis zurückgibt, wenn keine gültige Richtung gefunden wird oder die fraktale Richtung nicht aktualisiert wurde.

Als Nächstes wird der Wert der Variablen „lastFractal_direction“ überprüft. Ist sie gleich „FRACTAL_UP“ (was bedeutet, dass das letzte erkannte Fraktal ein Aufwärtsfraktal war), gibt die Funktion die Zeichenfolge „UP“ zurück. Wenn „lastFractal_direction“ gleich „FRACTAL_DOWN“ ist (was bedeutet, dass das letzte erkannte Fraktal ein abwärts gerichtetes Fraktal war), gibt die Funktion die Zeichenfolge „DOWN“ zurück. Ist keine dieser Bedingungen erfüllt (d. h. es wurde kein Aufwärts- oder Abwärtsfraktal erkannt oder die Richtung ist noch neutral), gibt die Funktion den Standardwert „NEUTRAL“ zurück, was bedeutet, dass es im Moment keine bestimmte Richtung gibt.

Wir können auch die Daten der anderen Indikatoren wie folgt protokollieren.

Print("ALLIGATOR JAWS = ",NormalizeDouble(alligator_jaws[1],_Digits));
Print("ALLIGATOR TEETH = ",NormalizeDouble(alligator_teeth[1],_Digits));
Print("ALLIGATOR LIPS = ",NormalizeDouble(alligator_lips[1],_Digits));

Print("AO VALUE = ",NormalizeDouble(ao_values[1],_Digits+1));

if (ac_color[1] == AC_COLOR_UP){
   Print("AC COLOR UP GREEN = ",AC_COLOR_UP);
}
else if (ac_color[1] == AC_COLOR_DOWN){
   Print("AC COLOR DOWN RED = ",AC_COLOR_DOWN);
}

Nach der Ausführung erhalten wir die folgende Ausgabe:

Bestätigung der Fraktale

BESTÄTIGUNG DER FRAKTALE

Andere Indikatoren Bestätigung:

BESTÄTIGUNG DER ANDEREN INDIKATOREN

Anhand der Visualisierung können wir sehen, dass die abgerufenen Daten mit den tatsächlichen Daten im Datenfenster übereinstimmen, was ein Erfolg ist. Wir können diese Daten dann weiterhin für Handelszwecke verwenden. Zunächst definieren wir einige notwendige Funktionen, die wir für die folgende Analyse verwenden werden.

//+------------------------------------------------------------------+
//|        FUNCTION TO GET CLOSE PRICES                              |
//+------------------------------------------------------------------+

double getClosePrice(int bar_index){
   return (iClose(_Symbol, _Period, bar_index)); //--- Retrieve the close price of the specified bar
}

//+------------------------------------------------------------------+
//|        FUNCTION TO GET ASK PRICES                                |
//+------------------------------------------------------------------+

double getAsk(){
   return (NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits)); //--- Get and normalize the Ask price
}

//+------------------------------------------------------------------+
//|        FUNCTION TO GET BID PRICES                                |
//+------------------------------------------------------------------+

double getBid(){
   return (NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits)); //--- Get and normalize the Bid price
}

Hier definieren wir 3 Funktionen, um den Schlusskurs, den Briefkurs bzw. den Geldkurs zu ermitteln. Als Nächstes müssen wir boolesche Variablen definieren, um auf der Grundlage der Kieferlinie des Alligators auf potenzielle Handelssignale zu prüfen (siehe unten).

bool isBreakdown_jaws_buy = alligator_jaws[1] < getClosePrice(1) //--- Check if breakdown for buy
                            && alligator_jaws[2] > getClosePrice(2);
bool isBreakdown_jaws_sell = alligator_jaws[1] > getClosePrice(1) //--- Check if breakdown for sell
                            && alligator_jaws[2] < getClosePrice(2);

Zunächst definieren wir „isBreakdown_jaws_buy“, um eine Breakdown-Bedingung für ein potenzielles Kaufsignal zu erkennen. Die Bedingung ist, dass der Wert des Arrays „alligator_jaws“ bei Index 1 (der den vorhergehenden Balken repräsentiert) kleiner ist als der Schlusskurs des vorhergehenden Balkens, der durch Aufruf der Funktion „getClosePrice(1)“ ermittelt wird. Außerdem sollte der Wert des Arrays „alligator_jaws“ bei Index 2 (der den vorangegangenen Balken darstellt) größer sein als der Schlusskurs des vorangegangenen Balkens, der durch Aufruf der Funktion „getClosePrice(2)“ ermittelt wird. Diese Kombination deutet darauf hin, dass die Kieferlinie des Alligators den Schlusskurs des vorangegangenen Balkens unterschritten hat, aber über dem Schlusskurs des vorherigen Balkens lag, was als potenzielles Setup für ein Kaufgeschäft interpretiert werden könnte.

Als Nächstes definieren wir „isBreakdown_jaws_sell“, um eine Breakdown-Bedingung für ein potenzielles Verkaufssignal zu erkennen. In diesem Fall sollte der „alligator_jaws“-Wert bei Index 1 größer sein als der Schlusskurs des vorangegangenen Balkens, und der „alligator_jaws“-Wert bei Index 2 sollte kleiner sein als der Schlusskurs des vorangegangenen Balkens. Dieses Szenario deutet darauf hin, dass die Kieferlinie des Alligators den Schlusskurs des vorangegangenen Balkens überquert hat, aber unter dem Schlusskurs des vorherigen Balkens lag, was auf ein potenzielles Setup für einen Verkaufshandel hindeutet. Von hier aus können wir die übrigen Bedingungen für offene Positionen festlegen.

if (lastFractal_direction == FRACTAL_DOWN //--- Conditions for Buy signal
   && isBreakdown_jaws_buy
   && ac_color[1] == AC_COLOR_UP
   && (ao_values[1] > 0 && ao_values[2] < 0)){
   Print("BUY SIGNAL GENERATED");
   obj_Trade.Buy(0.01,_Symbol,getAsk()); //--- Execute Buy order
}
else if (lastFractal_direction == FRACTAL_UP //--- Conditions for Sell signal
   && isBreakdown_jaws_sell
   && ac_color[1] == AC_COLOR_DOWN
   && (ao_values[1] < 0 && ao_values[2] > 0)){
   Print("SELL SIGNAL GENERATED");
   obj_Trade.Sell(0.01,_Symbol,getBid()); //--- Execute Sell order
}

Hier implementieren wir die Logik für die Ausführung von Kauf- und Verkaufssignalen auf der Grundlage der Kombination von Indikatoren, insbesondere der fraktalen Richtung, des Alligator-Kiefer-Durchbruchs, des Farbstatus des Accelerator Oscillator (AC) und der Werte des Awesome Oscillator (AO).

Zunächst prüfen wir, ob die Bedingungen für ein Kaufsignal erfüllt sind. Wir überprüfen, ob „lastFractal_direction“ auf „FRACTAL_DOWN“ gesetzt ist, was bedeutet, dass das letzte erkannte Fraktal ein abwärts gerichtetes Fraktal war. Dann prüfen wir, ob die Bedingung „isBreakdown_jaws_buy“ erfüllt ist, was signalisiert, dass die Kieferlinie des Alligators den Preis unterschritten hat und nun für einen potenziellen Kauf bereit ist.

Darüber hinaus stellen wir sicher, dass „ac_color[1]“ gleich „AC_COLOR_UP“ ist, was bedeutet, dass der Accelerator Oscillator sich in einem aufwärts gerichteten Farbzustand befindet, was auf eine steigende Marktstimmung hinweist. Schließlich überprüfen wir die Werte des Awesome Oscillators: „ao_values[1]“ sollte größer als Null sein (was auf ein positives Momentum hinweist), und „ao_values[2]“ sollte kleiner als Null sein (was auf ein vorheriges negatives Momentum hinweist). Diese Kombination deutet auf eine Umkehr der Dynamik hin, bei der der Markt von negativ auf positiv umschlägt. Wenn alle diese Bedingungen erfüllt sind, wird ein Kaufsignal generiert, und wir führen einen Kaufauftrag mit der angegebenen Losgröße (0,01) zum Briefkurs aus.

Andererseits prüfen wir, ob die Bedingungen für ein Verkaufssignal erfüllt sind. Wir überprüfen, ob „lastFractal_direction“ auf „FRACTAL_UP“ gesetzt ist, was bedeutet, dass das letzte erkannte Fraktal ein Aufwärtsfraktal war. Dann prüfen wir, ob die Bedingung „isBreakdown_jaws_sell“ erfüllt ist, was signalisiert, dass die Kieferlinie des Alligators den Preis überschritten hat und nun für einen potenziellen Verkaufsauftrag eingerichtet ist.

Darüber hinaus stellen wir sicher, dass „ac_color[1]“ gleich „AC_COLOR_DOWN“ ist, was bedeutet, dass der Accelerator Oscillator in einem abwärts gerichteten Farbzustand ist, was auf eine fallende Marktstimmung hinweist. Schließlich überprüfen wir die Werte des Awesome Oscillators: „ao_values[1]“ sollte kleiner als Null sein (was auf ein negatives Momentum hinweist), und „ao_values[2]“ sollte größer als Null sein (was auf ein vorheriges positives Momentum hinweist). Diese Kombination deutet darauf hin, dass der Markt von einem positiven zu einem negativen Momentum wechselt. Wenn alle diese Bedingungen erfüllt sind, wird ein Verkaufssignal generiert, und wir führen einen Verkaufsauftrag mit der angegebenen Losgröße (0,01) zum Geldkurs aus.

Dadurch werden die Positionen geöffnet. Sie können jedoch sehen, dass keine Ausstiegsaufträge erteilt wurden und die Positionen daher hängen bleiben. Wir brauchen also eine Logik, um die Positionen auf der Grundlage von Umkehrungen des AO-Indikators zu schließen.

if (ao_values[1] < 0 && ao_values[2] > 0){ //--- Condition to close all Buy positions
   if (PositionsTotal() > 0){
      Print("CLOSE ALL BUY POSITIONS");
      for (int i=0; i<PositionsTotal(); i++){
         ulong pos_ticket = PositionGetTicket(i); //--- Get position ticket
         if (pos_ticket > 0 && PositionSelectByTicket(pos_ticket)){ //--- Check if ticket is valid
            ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (pos_type == POSITION_TYPE_BUY){ //--- Close Buy positions
               obj_Trade.PositionClose(pos_ticket);
            }
         }
      }
   }
}
else if (ao_values[1] > 0 && ao_values[2] < 0){ //--- Condition to close all Sell positions
   if (PositionsTotal() > 0){
      Print("CLOSE ALL SELL POSITIONS");
      for (int i=0; i<PositionsTotal(); i++){
         ulong pos_ticket = PositionGetTicket(i); //--- Get position ticket
         if (pos_ticket > 0 && PositionSelectByTicket(pos_ticket)){ //--- Check if ticket is valid
            ENUM_POSITION_TYPE pos_type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (pos_type == POSITION_TYPE_SELL){ //--- Close Sell positions
               obj_Trade.PositionClose(pos_ticket);
            }
         }
      }
   }
}

Hier implementieren wir eine Logik zum Schließen aller aktiven Positionen (Kauf oder Verkauf) auf der Grundlage der Werte des Awesome Oscillator (AO). Zunächst prüfen wir, ob eine Bedingung zum Schließen aller Kaufpositionen vorliegt. Wenn „ao_values[1]“ kleiner als 0 und „ao_values[2]“ größer als 0 ist, deutet dies auf eine mögliche Verschiebung von einer negativen zu einer positiven Dynamik hin. Dies ist die Bedingung für die Schließung aller Kaufpositionen. Dazu wird zunächst mit der Funktion PositionsTotal geprüft, ob offene Positionen vorhanden sind.

Wenn es Positionen gibt, wird jede Position in einer Schleife durchlaufen und die Ticketnummer jeder Position mit der Funktion PositionGetTicket abgerufen. Für jede Position wird das Ticket mit der Funktion PositionSelectByTicket überprüft, um sicherzustellen, dass es sich um eine gültige Position handelt. Dann rufen wir den Positionstyp mit PositionGetInteger ab und „casten“ ihn in die Enumeration ENUM_POSITION_TYPE. Wenn die Positionsart POSITION_TYPE_BUY ist, d.h. es handelt sich um eine Kaufposition, schließen wir sie mit „obj_Trade.PositionClose(pos_ticket)“ und drucken zur Bestätigung „CLOSE ALL BUY POSITIONS“.

Als Nächstes prüfen wir, ob eine Bedingung zum Schließen aller Verkaufspositionen vorliegt. Wenn „ao_values[1]“ größer als 0 und „ao_values[2]“ kleiner als 0 ist, deutet dies auf eine mögliche Verschiebung von einem positiven Momentum zu einem negativen Momentum hin und signalisiert die Notwendigkeit, alle Verkaufspositionen zu schließen. In ähnlicher Weise prüfen wir zunächst, ob es offene Positionen gibt. Wenn es welche gibt, werden sie in einer Schleife durchlaufen, die Positionstickets abgerufen, die Tickets validiert und die Positionsart überprüft. Wenn die Positionsart POSITION_TYPE_SELL ist, d.h. es handelt sich um eine Verkaufsposition, schließen wir sie mit „obj_Trade.PositionClose(pos_ticket)“ und drucken zur Bestätigung „CLOSE ALL SELL POSITIONS“.

Wenn wir das Programm ausführen, erhalten wir die folgende Ausgabe.

KAUFPOSITION

Das war ein Erfolg. Wir können sehen, dass wir die Kaufposition bestätigt und eröffnet haben, als alle Einstiegsbedingungen erfüllt waren. Das war's mit der Umsetzung der Strategie. Nun müssen wir das Programm im Strategietester testen und gegebenenfalls optimieren, damit es sich an die aktuellen Marktbedingungen anpasst. Dies geschieht im nächsten Abschnitt.


Testen und Optimieren von Strategien

Nach Abschluss der Kernimplementierung besteht die nächste Phase nun darin, unseren Expert Advisor (EA) mit dem MetaTrader 5 Strategy Tester zu testen, um seine Leistung in verschiedenen Marktszenarien genau zu bewerten. In dieser Testphase wird überprüft, ob die Strategie unseren Erwartungen entspricht, und es werden alle erforderlichen Anpassungen zur Optimierung der Ergebnisse ermittelt. Hier haben wir bereits eine erste Optimierung vorgenommen, die sich speziell auf die für unsere Strategie wichtigen Parameter konzentriert.

Besonderes Augenmerk haben wir auf die Schwellenwerte für Fraktale und Alligatorlinien gelegt, um die Reaktionsfähigkeit des EA in verschiedenen Handelssitzungen und unter verschiedenen Bedingungen zu bewerten. Durch diese gründlichen Tests konnten wir sicherstellen, dass das Programm die erwarteten Kauf- und Verkaufssignale mit einer effizienten Handelsabwicklung einhält, was die Zuverlässigkeit und Leistung erhöht und gleichzeitig mögliche Fehler minimiert. Hier sind die Ergebnisse, die wir aus dem Testprozess gewonnen haben.

Backtest-Ergebnisse:

ERGEBNISSE

Backtest-Graph:

GRAPH


Schlussfolgerung

In diesem Artikel untersuchen wir den Prozess der Erstellung eines Expert Advisors (EA) in MQL5 mit der Profitunity-Handelsstrategie, der Fraktale, den Alligator-Indikator und Oszillatoren wie den Awesome- und Accelerator-Oszillator integriert, um strategische Kauf- und Verkaufssignale zu identifizieren. Ausgehend von den Kernindikatoren und schwellenwertbasierten Bedingungen automatisieren wir Handelssignale, die das Marktmomentum und Preisausbrüche nutzen. Jeder Schritt beinhaltet eine sorgfältige Code-Konstruktion, die Konfiguration von Indikator-Handles und die Implementierung einer Logik zur Auslösung von Kauf- und Verkaufstransaktionen gemäß den Kriterien der Strategie. Nach Abschluss der Implementierung haben wir den EA mit dem Strategy Tester von MetaTrader 5 auf Herz und Nieren geprüft, um seine Reaktionsfähigkeit und Zuverlässigkeit unter verschiedenen Marktbedingungen zu testen, wobei die Genauigkeit der Handelsausführung durch optimierte Parameter im Vordergrund stand.

Haftungsausschluss: Dieser Artikel ist ein Leitfaden für den Aufbau eines individuellen Programms, das auf indikatorgesteuerten Handelssignalen mit der Profitunity-Handelsstrategie basiert. Die vorgestellten Strategien und Methoden sind keine Garantie für bestimmte Handelsergebnisse und sollten mit Bedacht eingesetzt werden. Führen Sie stets gründliche Tests und Validierungen durch und passen Sie automatisierte Handelslösungen an die aktuellen Marktbedingungen und Ihre persönliche Risikotoleranz an.

Dieser Artikel bietet einen strukturierten Ansatz zur Automatisierung von Handelssignalen in MQL5 mit der Profitunity-Strategie. Wir hoffen, dass es Sie dazu ermutigt, die MQL5-Entwicklung weiter zu erforschen und die Erstellung von anspruchsvolleren und profitableren Handelssystemen zu inspirieren. Viel Spaß beim Kodieren und ein erfolgreicher Handel!

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

Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 3): Analytics Master — EA Entwicklung eines Toolkit zur Analyse von Preisaktionen (Teil 3): Analytics Master — EA
Der Übergang von einem einfachen Handelsskript zu einem voll funktionsfähigen Expert Advisor (EA) kann Ihre Handelserfahrung erheblich verbessern. Stellen Sie sich vor, Sie hätten ein System, das Ihre Charts automatisch überwacht, wichtige Berechnungen im Hintergrund durchführt und regelmäßig alle zwei Stunden Updates liefert. Dieser EA ist in der Lage, die wichtigsten Kennzahlen zu analysieren, die für fundierte Handelsentscheidungen wichtig sind, und stellt sicher, dass Sie Zugang zu den aktuellsten Informationen haben, um Ihre Strategien effektiv anzupassen.
MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 49): Verstärkungslernen mit Optimierung der proximalen Politik MQL5-Assistent-Techniken, die Sie kennen sollten (Teil 49): Verstärkungslernen mit Optimierung der proximalen Politik
Die „Proximal Policy Optimization“ ist ein weiterer Algorithmus des Reinforcement Learning, der die „Policy“, oft in Form eines Netzwerks, in sehr kleinen inkrementellen Schritten aktualisiert, um die Stabilität des Modells zu gewährleisten. Wir untersuchen, wie dies in einem von einem Assistenten zusammengestellten Expert Advisor von Nutzen sein könnte, wie wir es in früheren Artikeln getan haben.
Meistern der Log-Einträge (Teil 1): Grundlegende Konzepte und erste Schritte in MQL5 Meistern der Log-Einträge (Teil 1): Grundlegende Konzepte und erste Schritte in MQL5
Willkommen zum Beginn einer neuen Reise! Dieser Artikel eröffnet eine spezielle Serie, in der wir Schritt für Schritt eine Bibliothek für die Logmanipulation erstellen, die auf diejenigen zugeschnitten ist, die in der Sprache MQL5 entwickeln.
Connexus Observer (Teil 8): Hinzufügen eines Request Observer Connexus Observer (Teil 8): Hinzufügen eines Request Observer
In diesem letzten Teil unserer Connexus-Bibliotheksreihe haben wir uns mit der Implementierung des Observer-Patterns sowie mit wesentlichen Refactorings von Dateipfaden und Methodennamen beschäftigt. Diese Serie umfasst die gesamte Entwicklung von Connexus, das die HTTP-Kommunikation in komplexen Anwendungen vereinfachen soll.