English Русский Español 日本語 Português
preview
Lernen Sie Schritt für Schritt, wie Sie die Fair Value Gap (FVG)/Ungleichgewichte handeln können: Ein Ansatz des Smart Money-Konzepts

Lernen Sie Schritt für Schritt, wie Sie die Fair Value Gap (FVG)/Ungleichgewichte handeln können: Ein Ansatz des Smart Money-Konzepts

MetaTrader 5Handel | 3 Juni 2024, 12:23
325 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Einführung

In diesem Artikel werden wir die grundlegenden Schritte zur Erstellung und Entwicklung eines Expert Advisors (EA) erörtern, der auf der Strategie des Ungleichgewichts bzw. dem Fair Value Gap (FVG), einem Smart-Money-Konzept, basiert. Der Weg zur Erstellung eines Expert Advisors, der auf der Fair-Value-Gap-Strategie basiert, stellt im Wesentlichen eine Konvergenz von Kunst und Wissenschaft dar, da ein Händler in der Regel nicht nur in der Lage sein muss, die Kerzen zu analysieren, sondern auch zu zeichnen, um die Konzeptebenen zu visualisieren. Begleiten Sie uns, wenn wir die Geheimnisse des intelligenten Geldes lüften und uns auf die Suche nach seiner transformativen Kraft im Bereich des algorithmischen Handels begeben. Wir werden den Expert Advisor mit einer Fair Value Gap anhand der folgenden Themen erstellen:

  1. Definition des Ungleichgewichts
  2. Beschreibung der Handelsstrategie
  3. Handelsstrategie-Entwurf
  4. Handelssystem in MQL5
  5. Ergebnisse der Strategietester
  6. Schlussfolgerung


Auf dieser Reise werden wir ausgiebig MetaQuotes Language 5 (MQL5) als unsere Basis-IDE-Codierungsumgebung verwenden und die Dateien auf MetaTrader 5 (MT5) Handelsterminal ausführen. Daher ist es von größter Bedeutung, die oben genannten Versionen zu haben. Fangen wir also an.


Definition von Fair Value Gap (FVG) bzw. Ungleichgewicht

Die Fair-Value-Lücke beschreibt die Differenz zwischen Ungleichgewichten, die durch Kauf- und Verkaufsdruck entstehen. Typischerweise treten sie dann auf, wenn eine hohe Volatilität herrscht, die entweder die Bären oder die Bullen vollständig aus dem Markt treibt, sodass ein ungleicher Marktdruck entsteht. Dies ist typischerweise durch massive unidirektionale Bewegungen auf dem Markt gekennzeichnet. In der Regel werden Sie lange Kerzen auf dem Chart sehen. Mit diesem Wissen können wir verschiedene Ansätze anwenden, um die Fair-Value-Lücke auszunutzen und möglicherweise eine Handelsstrategie zu entwickeln.

Beschreibung der Handelsstrategie des Fair Value Gap (FVG)

Die Fair-Value-Gap-Handelsstrategie integriert das Konzept der Fair-Value-Bewertung mit Kerzen-Ungleichgewichten, um potenzielle Handelsmöglichkeiten zu identifizieren.

Hier finden Sie eine detaillierte Beschreibung der Fair-Value-Gap-Handelsstrategie, die Kerzen-Ungleichgewichte berücksichtigt:

  • Die Händler führen eine umfassende Fundamentalanalyse durch, um Fair-Value-Lücken zu ermitteln. Dies wird durch die Analyse der Marktpreisentwicklung mit Hilfe von Kerzen-Mustern erreicht, um Ungleichgewichte zwischen Kauf- und Verkaufsdruck zu erkennen. Kerzen-Muster wie Bullish Engulfing, Bearish Engulfing und Doji geben Aufschluss über die Marktstimmung und potenzielle Verschiebungen der Dynamik. Händler suchen nach Fällen, in denen der Marktpreis erheblich vom geschätzten fairen Wert abweicht, und beobachten dabei auch bemerkenswerte Kerzen-Ungleichgewichte. Eine große Lücke zwischen dem Schlusskurs der vorangegangenen Börsensitzung und dem Eröffnungskurs der aktuellen Börsensitzung in Verbindung mit starken Auf- oder Abwärts-Kerzenmustern kann auf eine potenzielle Fair-Value-Lücke hinweisen. Der schwierigste Aspekt des Fair-Value-Gap-Ansatzes ist, wie bei anderen Chartmustern, das Erkennen dieser speziellen Konfiguration in einem Preischart. Die FVG verwendet ein Drei-Kerzen-Muster mit besonderen Vorgaben. In diesem Fall ist die Fair-Value-Lücke die Fläche oder der Abstand zwischen den Dochten der ersten und der dritten Kerze.

Im Folgenden wird beschrieben, wie Sie ein FVG auf dem Chart erkennen können:

  • Die lange Kerze finden: Wenn Sie versuchen, eine Fair-Value-Lücke herauszufinden, sollten Sie zunächst in Ihrem Kurschart nach einer langen Kerze suchen. Das Verhältnis von Körper zu Docht sollte bei dieser Kerze deutlich sein — idealerweise 70 %.
  • Untersuchung benachbarter Kerzen: Nachdem Sie die besonders langen Kerzen gefunden haben, untersuchen Sie die Kerzen, die sich direkt vor und hinter ihm befinden. Die wichtige Kerze sollte sich nicht vollständig mit diesen nahe gelegenen Kerzen überschneiden. Vielmehr kann es zu leichten Überschneidungen an der Ober- und Unterseite des signifikanten Leuchters kommen. Die Fair-Value-Lücke entsteht dann durch die Differenz zwischen den Dochten benachbarter Kerzen.
  • Ermittlung der Fair-Value-Differenz: Die Fair-Value-Lücke muss in einem letzten Schritt definiert und in Ihrem Preischart dargestellt werden. Die Preisspanne zwischen dem Hoch und dem Tief der vorangegangenen Kerze in einem Abwärtstrend wird als Fair-Value-Lücke bezeichnet. Hier zeigt sich das Ungleichgewicht des Marktes und könnte eine Handelsmöglichkeit darstellen. Ebenso gilt ein Aufwärtstrend, allerdings unter umgekehrten Bedingungen.



  • Ein- und Ausstiegssignale: Wird eine Fair-Value-Lücke in Verbindung mit signifikanten Kerzen-Ungleichgewichten identifiziert, führen Händler den Handel entsprechend aus. Wenn der Marktpreis beispielsweise unter dem geschätzten fairen Wert liegt und sich ein zinsbullisches Engulfing-Muster abzeichnet, können Händler in Erwartung einer Kurskorrektur eine Kauf-Position eingehen. Umgekehrt können Händler eine Verkaufs-Position eingehen, wenn der Marktpreis über dem fairen Wert liegt und ein rückläufiges Engulfing-Muster erscheint.
  • Risikomanagement: Die Händler wenden Risikomanagementtechniken an, wie z. B. die Festlegung von Stop-Loss-Orders und Positionsgrößen, um potenzielle Verluste zu begrenzen, falls sich der Handel nicht wie erwartet entwickelt.
  • Überwachung und Anpassung: Die Händler überwachen den Handel fortlaufend und passen ihre Positionen auf der Grundlage der sich entwickelnden Marktbedingungen und der Neubewertung der Schätzungen des beizulegenden Zeitwerts an.

Wie Sie bereits bemerkt haben, gibt es zwei verschiedene Arten von Fair-Value-Lücken, die jeweils einzigartige Auswirkungen für Händler haben. Eine ausführliche Beschreibung finden Sie im Folgenden:

  • Bearish Fair Value Gap, oder unterbewertete Fair Value Gap

Diese Art von FVG zeigt an, dass der Preis eines Währungspaares oder eines anderen finanziellen Vermögenswertes derzeit unter seinem beizulegenden Zeitwert liegt. Vereinfacht ausgedrückt, können Händler mit einem Gegenentwicklung des Marktes rechnen, um diese Ineffizienz zu beheben. Wenn Sie eine große rückläufige Kerze auf Ihrem Chart sehen, deutet dies wahrscheinlich auf ein unterbewertetes FVG hin.

  • Bullish Fair Value Gap oder überbewertetes Fair Value Gap

Auf der anderen Seite zeigt ein überbewertetes FVG, dass ein finanzieller Vermögenswert oder ein Währungspaar jetzt über seinem eigentlichen Wert gehandelt wird. Der Markt ist hier überhitzt, und eine Korrektur steht unmittelbar bevor. Vor einem Anstieg sollten Händler mit einem Kursrückgang rechnen, da der Markt sich selbst korrigiert.


Fair-Value-Gap (FVG)-Handelsstrategie-Entwurf

Nachdem wir die Fair Value Gap-Strategie definiert und beschrieben haben, wollen wir nun Schritt für Schritt die Bedingungen festlegen, die für den Handel mit der FVG-Strategie zu beachten sind. Es sei daran erinnert, dass zwei Arten von FVG auf dem Markt entstehen könnten.

  • Bullish FVG: Gemäß der Strategie müssen wir eine bullische Kerze finden, die eine größere Kursbewegung aufweist, und dann die benachbarten Kerzen — links und rechts — bewerten. Wenn dies der Fall ist, ermitteln wir die Differenz zwischen der dritten Kerze und der ersten Kerze in einer Zeitreihe, und wenn die Differenz nicht innerhalb der vordefinierten Punkte liegt, haben wir ein bullisches FVG, das wir entsprechend handeln werden. Das FVG wird zu unserem Interessenpunkt, und wir dokumentieren es im Algorithmus. Wir zeichnen gleichzeitig das FVG, das auf dem Chart grün/limonenfarben eingefärbt ist, mit einer vordefinierten Länge zu Visualisierungszwecken, um zu signalisieren, dass wir ein bullisches FVG-Setup gefunden haben und dass wir bereit sind, das Setup zu handeln. Wenn der Kurs nun zurückkommt und den unteren FVG-Bereich berührt, senden wir einen sofortigen Marktkaufauftrag. Der Take-Profit wird auf den oberen Teil des FVG gesetzt, während der Stop-Loss unterhalb des Eröffnungskurses der Order gesetzt wird, mit einem Risiko-Ertrags-Verhältnis von 1:3. Wenn der Preis jedoch nach der vordefinierten Dauer nicht zur FVG-Einstellung zurückkehrt, lassen wir ihn einfach außer Acht.


Das gleiche Verfahren gilt für alle anderen bullischen FVG-Setups.

  • Bearish FVG: Auch hier müssen wir eine Abwärts-Kerze finden, die eine größere Kursbewegung aufweist, und dann die benachbarten Kerzen — links und rechts — bewerten. Wenn dies der Fall ist, ermitteln wir die Differenz zwischen der dritten Kerze und der ersten Kerze in einer Zeitreihe, und wenn die Differenz nicht innerhalb der vordefinierten Punkte liegt, haben wir ein Abwärts-FVG, das wir entsprechend handeln werden. Das FVG wird zu unserem Interessenpunkt, und wir dokumentieren es im Algorithmus. Gleichzeitig zeichnen wir das FVG, rot/tomato gefärbt, mit einer vordefinierten Länge zu Visualisierungszwecken in den Chart ein, um zu signalisieren, dass wir ein Abwärts-FVG-Setup gefunden haben und dass wir bereit sind, das Setup zu handeln. Wenn der Kurs nun zurückkommt und den oberen FVG-Bereich berührt, senden wir einen sofortigen Marktverkaufsauftrag. Der Take-Profit wird auf den unteren Teil des FVG gesetzt, während der Stop-Loss über dem Eröffnungskurs der Order liegt, mit einem Risiko-Ertrags-Verhältnis von 1:10. Wenn der Preis jedoch nach der vordefinierten Dauer nicht zur FVG-Einstellung zurückkehrt, lassen wir ihn einfach außer Acht.


Das gleiche Verfahren gilt für alle anderen Abwärts-FVG-Setups.


Fair Value Gap (FVG) Handelssystem in MQL5

Nachdem wir die ganze Theorie über die FVG-Handelsstrategie gelernt haben, wollen wir nun die Theorie automatisieren und einen Expert Advisor (EA) in MQL5 für MetaTrader 5 erstellen. 

Um einen EA zu erstellen, klicken Sie auf Ihrem MetaTrader 5-Terminal auf die Registerkarte Tools und wählen Sie MetaQuotes Language Editor oder drücken Sie einfach F4 auf Ihrer Tastatur. Dadurch wird die MetaQuotes-Spracheditor-Umgebung geöffnet, die das Schreiben von Handelsrobotern, technischen Indikatoren, Skripten und Funktionsbibliotheken ermöglicht.


Klicken Sie nun auf Neu, markieren Sie Expert Advisor (Vorlage) und klicken Sie auf Weiter.


NEUE DATEI ÖFFNEN

Geben Sie dann den gewünschten Namen der Expert Advisor-Datei ein, klicken Sie auf Weiter, klicken Sie auf Weiter und dann auf Fertig stellen. Nachdem wir all das getan haben, sind wir nun bereit, unsere FVG-Strategie zu codieren und zu programmieren.

Zunächst binden wir eine Handelsinstanz ein, indem wir #include am Anfang des Quellcodes verwenden. Dadurch erhalten wir Zugriff auf die Klasse CTrade, mit der wir ein Handelsobjekt erstellen werden.

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

Auch hier verwenden wir #define, um eine Variable zu definieren, die wir als Präfix für alle erstellten FVG-Rechtecke und deren Farben verwenden.

#define FVG_Prefix "FVG REC "
#define CLR_UP clrLime
#define CLR_DOWN clrRed

Im Folgenden wird die Bedeutung der oben genannten Parameter veranschaulicht.


Wir werden einige andere Variablen vordefinieren müssen, um die Kodierung des EA weiter zu erleichtern. Dies sind die Mindestpunkte für einen große Balkenlänge, damit er als brauchbar angesehen wird, und die Länge des gezeichneten Rechtecks ist in diesem Fall die Ausdehnung der Balken vom zentralen Ungleichgewichtsbalken. Wir werden diese als globale Variablen definieren.

int minPts = 100;
int FVG_Rec_Ext_Bars = 10;

Nachfolgend finden Sie eine Abbildung. Wir definieren minPts für die minimalen Punkte und FVG_Rec_Bars für den Bereich in Balken, in dem die Rechtecklänge dargestellt werden soll.


Schließlich definieren wir vier Arrays mit Variablen des Datentyps String, Integer, Datetime und Boolean, in denen die Daten gespeichert werden, die wir für die Erstellung des EA benötigen. Dies sind wiederum Globals.

string totalFVGs[];
int barINDICES[];
datetime barTIMEs[];
bool signalFVGs[];

Im Abschnitt OnInit suchen wir die FVG-Setups nur für die sichtbaren Balken des Charts. Dies wird unserem EA einen eher indikator-dominanten Touch verleihen. Wenn der Nutzer also das Chart startet, kann er immer noch die vorherigen FVG-Setups sehen und darauf warten, dass weitere auf den vorangehenden Kerzen erstellt werden. 

Zunächst werden alle sichtbaren Balken im Chart angezeigt und ihre Anzahl mitgeteilt.

   int visibleBars = (int)ChartGetInteger(0,CHART_VISIBLE_BARS);
   Print("Total visible bars on chart = ",visibleBars);

Wenn keine Rechteckobjekte im Chart vorhanden sind, werden die Speicherfelder freigegeben und auf Null gesetzt, um für neue Daten vorbereitet zu sein. Dies ist ein sehr wichtiger Schritt, da der Nutzer entweder alle Objekte im Chart gelöscht haben könnte, bevor er den EA erneut initialisiert.

   if (ObjectsTotal(0,0,OBJ_RECTANGLE)==0){
      Print("No FVGs Found, Resizing storage arrays to 0 now!!!");
      ArrayResize(totalFVGs,0);
      ArrayResize(barINDICES,0);
      ArrayResize(signalFVGs,0);
   }

Um Überschneidungen von Objekten zu vermeiden, werden alle vorherigen FVG-Konfigurationen gelöscht und neue auf der Grundlage der aktuell angewandten Eigenschaften der Kartenumgebung erstellt. Dies wird durch die Verwendung des Präfixes unserer FVG-Setups erreicht, das sicherstellt, dass wir nur FVG-Rechteckobjekte löschen, die von unserem EA erstellt wurden, sodass er mit anderen EAs kompatibel ist.

   ObjectsDeleteAll(0,FVG_Prefix);

Wir werden dann eine Schleife über alle sichtbaren Balken auf dem Chart machen, die Balkeneigenschaften abrufen und dann prüfen, ob es sich um ein gültiges FVG-Setup handelt.

Hier ist eine schrittweise Beschreibung:

Um nach einem Aufwärts-FVG-Setup zu suchen, ermitteln wir den Tiefststand des ersten Balkens bei Index i - technisch gesehen ist dies unser Balken Nummer 0, wenn wir davon ausgehen, dass wir bereits ein Setup von nur 3 Balken haben, den Höchststand des dritten Balkens bei Index i+2 und ermitteln die Differenz zwischen den beiden in Form von Punkten.

      double low0 = iLow(_Symbol,_Period,i);
      double high2 = iHigh(_Symbol,_Period,i+2);
      double gap_L0_H2 = NormalizeDouble((low0 - high2)/_Point,_Digits);

Die gleiche Logik gilt für die Suche nach Abwärts-Setups. Um nach einem Abwärts-FVG-Setup zu suchen, nehmen wir das Hoch des ersten Balkens bei Index i, technisch gesehen ist dies unser Balken Nummer 0, wenn wir davon ausgehen, dass wir bereits ein Setup von nur 3 Balken haben, nehmen wir das Tief des dritten Balkens bei Index i+2 und erhalten ihre Gap-Differenz in Punktform.

      double high0 = iHigh(_Symbol,_Period,i);
      double low2 = iLow(_Symbol,_Period,i+2);
      double gap_H0_L2 = NormalizeDouble((low2 - high0)/_Point,_Digits);

Nachdem wir die Punktedifferenz ermittelt haben, können wir die zurückgegebenen Werte verwenden, um zu prüfen, ob es eine der FVG-Einstellungen gibt. Um dies zu erreichen, verwenden wir zwei boolesche Variablen: 

  1. FVG_UP - Prüft, ob der Tiefstwert des Balkenindexes i größer ist als der Höchstwert des Balkenindexes i+2 und ob gleichzeitig die berechneten Lückenpunkte größer sind als die minimal zulässigen Rechteckpunkte.

  2. FVG_DOWN - Prüft, ob der Höchstwert des Balkenindexes i kleiner ist als der Tiefstwert des Balkenindexes i+2 und ob gleichzeitig die berechneten Lückenpunkte größer sind als die minimal zulässigen Rechteckpunkte.

Offensichtlich stellt die Prüfung auf Mindestpunkte sicher, dass wir nur gültige und aussagekräftige FVG-Setups haben, die durch mögliche spontane Kursbewegungen verursacht werden, und nicht unseren Chart zerstören.

      bool FVG_UP = low0 > high2 && gap_L0_H2 > minPts;
      bool FVG_DOWN = low2 > high0 && gap_H0_L2 > minPts;

Sobald wir eine bestätigte FVG-Einrichtung haben, fahren wir damit fort, die entsprechende FVG-Einrichtung zusammen mit ihrer Datendokumentation in den Speicher-Arrays zu erstellen.

Wir definieren die Variable time1 vom Datentyp datetime, in der wir die Zeit für den zentralen Balken, also den mittleren oder zweiten Balken, bei Index i+1 speichern, an dem das Rechteck beginnt.

Auch hier definieren wir die Variable price1 vom Datentyp double, wobei wir den ternären Operator verwenden, um das Hoch des dritten Balkens im Falle eines Aufwärts-FVG-Setups und das Hoch des ersten Balkens im Falle eines Abwärts-FVG-Setups zurückzugeben.

Technisch gesehen sind dies die Koordinaten des ersten Punktes unseres zu zeichnenden Rechteckobjekts.

         datetime time1 = iTime(_Symbol,_Period,i+1);
         double price1 = FVG_UP ? high2 : high0;

Nach der Festlegung der ersten Koordinaten werden die zweiten Koordinaten bestimmt. 

Wir definieren die Variable time2 vom Datentyp datetime, in der wir die Zeit für den Endbalken speichern, d. h. den Balken, an dem das gezeichnete Rechteck endet. Dazu wird zu time1, der Startzeit, einfach die Anzahl der Balken addiert, um die das Rechteck erweitert werden soll.

Auch hier definieren wir die Variable price2 vom Datentyp double, wobei wir den ternären Operator verwenden, um das Tief des ersten Balkens im Falle eines Aufwärts-FVG-Setups und das Tief des dritten Balkens im Falle eines Abwärts-FVG-Setups zurückzugeben.

         datetime time2 = time1 + PeriodSeconds(_Period)*FVG_Rec_Ext_Bars;
         double price2 = FVG_UP ? low0 : low2;

Nachfolgend finden Sie eine Viasualisierung der Koordinaten, die für eine reibungslose Erstellung der Rechtecke erforderlich sind.


Nachdem wir die Koordinaten der FVG-Einrichtung erhalten haben, müssen wir diesem FVG-Rechteck-Objekt einen Namen geben.

Wir verwenden das vordefinierte Präfix als Präfix unserer FVG und fügen den Zeitpunkt der Erstellung hinzu. Dadurch wird erstens sichergestellt, dass wir ein FVG-Objekt zu diesem Balkenzeitpunkt nicht noch einmal erstellen können, da zu diesem bestimmten Kerzenzeitpunkt bereits ein Objekt mit einem ähnlichen Titel existiert, und zweitens ist die Einzigartigkeit gegeben, da es mit Sicherheit keinen anderen ähnlichen Taktzeitpunkt geben kann.

         string fvgNAME = FVG_Prefix+"("+TimeToString(time1)+")";

Wir müssen unseren FVG-Setups auch unterschiedliche Farben zuweisen, damit wir zwischen Auf- und Abwärts-Setups unterscheiden können. Aufwärts-Setups erhalten die vordefinierte bullische Farbe, d.h. CLR_UP, und Abwärts-Setups die vordefinierte bärische Farbe, d.h. CLR_DOWN.

         color fvgClr = FVG_UP ? CLR_UP : CLR_DOWN;

Bis zu diesem Punkt haben wir alles, was wir brauchen, um das jeweilige FVG-Setup in den Chart zu zeichnen. 

Um dies einfach zu tun, erstellen wir eine ungültige Funktion im globalen Bereich. Wir definieren die Funktion als CreateRec und übergeben den Objektnamen, die Koordinaten für Punkt eins bzw. Punkt zwei und die Farbe als Variablen, die für die Erstellung der FVG-Setups benötigt werden.

void CreateRec(string objName,datetime time1,double price1,
               datetime time2, double price2,color clr){
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_RECTANGLE,0,time1,price1,time2,price2);
      
      ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
      ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_FILL,true);
      ObjectSetInteger(0,objName,OBJPROP_BACK,false);
      
      ChartRedraw(0);
   }
}

Verwenden Sie anschließend die erstellte Funktion, um das entsprechende FVG-Rechteck auf dem Chart zu erstellen, und übergeben Sie dabei die vorgefertigten Parameter.

         CreateRec(fvgNAME,time1,price1,time2,price2,fvgClr);

Nach der Erstellung des FVG-Setups müssen wir die Daten in den Speicher-Arrays speichern. Da wir jedoch dynamische Arrays erstellt haben, müssen wir zunächst deren Größe ändern, um einen zusätzlichen Datenwert aufzunehmen, indem wir die Funktion ArrayResize verwenden.

         ArrayResize(totalFVGs,ArraySize(totalFVGs)+1);
         ArrayResize(barINDICES,ArraySize(barINDICES)+1);

Nachdem wir die Größe der Datenspeicher-Arrays geändert haben, fügen wir die neuen Daten zu den jeweiligen Arrays hinzu.

         totalFVGs[ArraySize(totalFVGs)-1] = fvgNAME;
         barINDICES[ArraySize(barINDICES)-1] = i+1;

Bis zu diesem Punkt ist es uns gelungen, FVG-Setups für alle sichtbaren Balken des Charts zu erstellen. Nachstehend finden Sie das Ergebnis des Meilensteins.


Der Nutzer könnte verlangen, dass die Aufstellungen, die bestätigt werden könnten, nach der Bestätigung gekürzt werden, um zu sagen, dass es bereits eine erfolgreiche FVG-Aufstellung gab. Wir müssen also die zusätzliche Länge der Setups abschneiden, sobald der Preis sie bestätigt. Wir erreichen dies, indem wir eine Schleife über alle insgesamt erstellten und bestätigten FVG-Setups ziehen, die jeweiligen Details abrufen, die Daten mit der Kontrolllogik abgleichen und schließlich die Setups entsprechend aktualisieren.

Im Folgenden wird Schritt für Schritt erläutert, wie dies erreicht wird:

Schleife über alle erstellten FVG-Setups mit der Funktion for loop.

   for (int i=ArraySize(totalFVGs)-1; i>=0; i--){// ... }

Abrufen der Einrichtungsdaten.

      string objName = totalFVGs[i];
      string fvgNAME = ObjectGetString(0,objName,OBJPROP_NAME);
      int barIndex = barINDICES[i];
      datetime timeSTART = (datetime)ObjectGetInteger(0,fvgNAME,OBJPROP_TIME,0);
      datetime timeEND = (datetime)ObjectGetInteger(0,fvgNAME,OBJPROP_TIME,1);
      double fvgLOW = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,0);
      double fvgHIGH = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,1);
      color fvgColor = (color)ObjectGetInteger(0,fvgNAME,OBJPROP_COLOR);

Schleife über alle Verlängerungsleisten des Rechtecks, d. h. über die Länge des ausgewählten Rechtecks.

      for (int k=barIndex-1; k>=(barIndex-FVG_Rec_Ext_Bars); k--){//... }

Abrufen der Balkendaten.

         datetime barTime = iTime(_Symbol,_Period,k);
         double barLow = iLow(_Symbol,_Period,k);
         double barHigh = iHigh(_Symbol,_Period,k);

Wenn das Rechteck über den ersten sichtbaren Balken einer Zeitreihe hinausgeht, schneiden wir es einfach auf die Zeit des ersten Balkens, d. h. auf den Balken mit dem Index 0 oder, einfacher gesagt, auf den aktuellen Balken. Wir informieren über die Erkennung des Überlaufs, aktualisieren die FVG-Einstellung auf die Zeit des aktuellen Balkens und unterbrechen die Betriebsschleife.

         if (k==0){
            Print("OverFlow Detected @ fvg ",fvgNAME);
            UpdateRec(fvgNAME,timeSTART,fvgLOW,barTime,fvgHIGH);
            break;
         }

Um die Einstellungen einfach zu aktualisieren, erstellen wir eine ungültige Funktion mit dem Namen UpdateRec, die den Objektnamen und die Koordinaten der beiden wichtigen Punkte des zu aktualisierenden Rechteckobjekts enthält.

void UpdateRec(string objName,datetime time1,double price1,
               datetime time2, double price2){
   if (ObjectFind(0,objName) >= 0){
      ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
      ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
      
      ChartRedraw(0);
   }
}

Handelt es sich bei dem FVG-Setup um ein Abwärts-FVG, das an der Farbe zu erkennen ist, und liegt der Höchstkurs des ausgewählten Balkens über den oberen Koordinaten des FVG-Objekts, signalisiert es, dass das FVG erfolgreich war, und schneidet es dementsprechend ab, d. h. es aktualisiert die Koordinaten des zweiten Punktes auf die Kerze, bei der der Bruch des FVG auftritt. Das Gleiche gilt für eine Aufwärts-FVG-Einstellung.

         if ((fvgColor == CLR_DOWN && barHigh > fvgHIGH) ||
            (fvgColor == CLR_UP && barLow < fvgLOW)
         ){
            Print("Cut Off @ bar no: ",k," of Time: ",barTime);
            UpdateRec(fvgNAME,timeSTART,fvgLOW,barTime,fvgHIGH);
            break;
         }


Sobald alles eingestellt ist, setzen wir die Speicherfelder auf Null, um für den OnTick-Abschnitt bereit zu sein.

   ArrayResize(totalFVGs,0);
   ArrayResize(barINDICES,0);

Der vollständige OnInit-Code, der für die Erstellung von FVG-Setups auf den sichtbaren Balken im Chart und deren entsprechende Aktualisierung verantwortlich ist, sieht wie folgt aus:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   int visibleBars = (int)ChartGetInteger(0,CHART_VISIBLE_BARS);
   Print("Total visible bars on chart = ",visibleBars);
   
   if (ObjectsTotal(0,0,OBJ_RECTANGLE)==0){
      Print("No FVGs Found, Resizing storage arrays to 0 now!!!");
      ArrayResize(totalFVGs,0);
      ArrayResize(barINDICES,0);
      ArrayResize(signalFVGs,0);
   }
   
   ObjectsDeleteAll(0,FVG_Prefix);
   
   for (int i=0; i<=visibleBars; i++){
      //Print("Bar Index = ",i);
      double low0 = iLow(_Symbol,_Period,i);
      double high2 = iHigh(_Symbol,_Period,i+2);
      double gap_L0_H2 = NormalizeDouble((low0 - high2)/_Point,_Digits);
      
      double high0 = iHigh(_Symbol,_Period,i);
      double low2 = iLow(_Symbol,_Period,i+2);
      double gap_H0_L2 = NormalizeDouble((low2 - high0)/_Point,_Digits);
      
      bool FVG_UP = low0 > high2 && gap_L0_H2 > minPts;
      bool FVG_DOWN = low2 > high0 && gap_H0_L2 > minPts;
      
      if (FVG_UP || FVG_DOWN){
         Print("Bar Index with FVG = ",i+1);
         datetime time1 = iTime(_Symbol,_Period,i+1);
         double price1 = FVG_UP ? high2 : high0;
         datetime time2 = time1 + PeriodSeconds(_Period)*FVG_Rec_Ext_Bars;
         double price2 = FVG_UP ? low0 : low2;
         string fvgNAME = FVG_Prefix+"("+TimeToString(time1)+")";
         color fvgClr = FVG_UP ? CLR_UP : CLR_DOWN;
         CreateRec(fvgNAME,time1,price1,time2,price2,fvgClr);
         Print("Old ArraySize = ",ArraySize(totalFVGs));
         ArrayResize(totalFVGs,ArraySize(totalFVGs)+1);
         ArrayResize(barINDICES,ArraySize(barINDICES)+1);
         Print("New ArraySize = ",ArraySize(totalFVGs));
         totalFVGs[ArraySize(totalFVGs)-1] = fvgNAME;
         barINDICES[ArraySize(barINDICES)-1] = i+1;
         ArrayPrint(totalFVGs);
         ArrayPrint(barINDICES);
      }
   }
   
   for (int i=ArraySize(totalFVGs)-1; i>=0; i--){
      string objName = totalFVGs[i];
      string fvgNAME = ObjectGetString(0,objName,OBJPROP_NAME);
      int barIndex = barINDICES[i];
      datetime timeSTART = (datetime)ObjectGetInteger(0,fvgNAME,OBJPROP_TIME,0);
      datetime timeEND = (datetime)ObjectGetInteger(0,fvgNAME,OBJPROP_TIME,1);
      double fvgLOW = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,0);
      double fvgHIGH = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,1);
      color fvgColor = (color)ObjectGetInteger(0,fvgNAME,OBJPROP_COLOR);
      
      Print("FVG NAME = ",fvgNAME," >No: ",barIndex," TS: ",timeSTART," TE: ",
            timeEND," LOW: ",fvgLOW," HIGH: ",fvgHIGH," CLR = ",fvgColor);
      for (int k=barIndex-1; k>=(barIndex-FVG_Rec_Ext_Bars); k--){
         datetime barTime = iTime(_Symbol,_Period,k);
         double barLow = iLow(_Symbol,_Period,k);
         double barHigh = iHigh(_Symbol,_Period,k);
         //Print("Bar No: ",k," >Time: ",barTime," >H: ",barHigh," >L: ",barLow);
         
         if (k==0){
            Print("OverFlow Detected @ fvg ",fvgNAME);
            UpdateRec(fvgNAME,timeSTART,fvgLOW,barTime,fvgHIGH);
            break;
         }
         
         if ((fvgColor == CLR_DOWN && barHigh > fvgHIGH) ||
            (fvgColor == CLR_UP && barLow < fvgLOW)
         ){
            Print("Cut Off @ bar no: ",k," of Time: ",barTime);
            UpdateRec(fvgNAME,timeSTART,fvgLOW,barTime,fvgHIGH);
            break;
         }
      }
      
   }
   
   ArrayResize(totalFVGs,0);
   ArrayResize(barINDICES,0);

   return(INIT_SUCCEEDED);
}

Im Abschnitt OnTick werden ähnliche Funktionen und Logiken verwendet. Wir durchlaufen eine Schleife über alle vordefinierten vorherigen Verlängerungsstangen oder vielmehr die Länge der FVG-Einstellung von der aktuellen Stange, suchen nach potenziellen Einstellungen und erstellen, wenn eine gefunden und bestätigt wird. 

Hier sind die leichten Unterschiede in der verwendeten Erstellungsschleife.

In der OnInit-Schleife zur Erstellung des FVG-Setups berücksichtigen wir alle sichtbaren Balken im Chart. Hier hingegen wird nur die letzte vordefinierte Verlängerungslänge berücksichtigt.

   for (int i=0; i<=FVG_Rec_Ext_Bars; i++){//... }

Beim Abrufen der Informationen für die Balken beginnen wir mit dem Balken vor dem aktuellen Balkenindex, da sich der Balken noch im Entstehungsprozess befindet. Wir fügen also 1 zum ausgewählten Index hinzu.

      double low0 = iLow(_Symbol,_Period,i+1);
      double high2 = iHigh(_Symbol,_Period,i+2+1);

In der Schleife in OnInit, um FVG zuzuschneiden, werden die bestätigten und getesteten FVG-Setups abgeschnitten. Im OnTick werden die Setups nicht abgeschnitten, weil wir sie sehen wollen. Wir senden stattdessen jeweils sofortige Marktaufträge. Sobald der Preis die Länge des Balkens überschreitet, können wir mit diesem Setup nicht mehr handeln, und wir löschen die gespeicherten Daten in den Arrays. Hier sind die Unterschiede im Code:

Wir fügen eine neue boolesche Variable fvgExist hinzu und initialisieren sie auf false, damit sie die Flags über die Verfügbarkeit eines Setups innerhalb der gescannten Balken enthalten kann.

      bool fvgExist = false;

Wir wiederholen die Schleife über die vordefinierten Balken, beginnend mit dem Balken vor dem aktuellen Balken, d.h. 0 + 1 = 1, und erhalten die Höchst- und Tiefstpreise des ausgewählten Balkens, und wenn einer der Preise mit den Koordinaten des zweiten Punktes des Setups übereinstimmt, ist er noch innerhalb der Spanne, kann also noch gehandelt werden, und daher setzen wir die Variable fvgExist auf true.

      for (int k=1; k<=FVG_Rec_Ext_Bars; k++){
         double barLow = iLow(_Symbol,_Period,k);
         double barHigh = iHigh(_Symbol,_Period,k);
         
         if (barHigh == fvgLow || barLow == fvgLow){
            //Print("Found: ",fvgNAME," @ bar ",k);
            fvgExist = true;
            break;
         }
      }

Da wir in den Markt eindringen wollen und dazu die Einstiegskurse benötigen, legen wir die aktuellen Symbolkurse frühzeitig fest.

      double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
      double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

Anschließend verwenden wir if-Anweisungen, um zu prüfen, ob es sich bei dem ausgewählten FVG-Setup um ein Abwärts-Setup handelt und ob der aktuelle Geldkurs über den oberen Koordinaten des Setups liegt und dies gleichzeitig das erste Handelssignal für das Setup ist. Wenn alle Bedingungen erfüllt sind, eröffnen wir einen Verkaufsauftrag mit einem Handelsvolumen von 0,01. Der Eröffnungskurs ist der aktuelle Geldkurs, das Take-Profit-Niveau liegt an den unteren Koordinaten des FVG-Setups und der Stop-Loss bei einem Chance-Risiko-Verhältnis von 1:10 oberhalb des Einstiegskurses. Sobald die Position initiiert wurde, setzen wir die Signaldaten bei diesem bestimmten Index auf true, sodass wir beim nächsten Tick keine andere Position auf der Grundlage dieses bestimmten Setups eröffnen.

      if (fvgColor == CLR_DOWN && Bid > fvgHigh && !signalFVGs[j]){
         Print("SELL SIGNAL For (",fvgNAME,") Now @ ",Bid);
         double SL_sell = Ask + NormalizeDouble((((fvgHigh-fvgLow)/_Point)*10)*_Point,_Digits);
         double trade_lots = Check1_ValidateVolume_Lots(0.01);
         
         if (Check2_Margin(ORDER_TYPE_SELL,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_SELL,SL_sell,fvgLow)){
            obj_Trade.Sell(trade_lots,_Symbol,Bid,SL_sell,fvgLow);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }


Gleichermaßen gilt eine Aufwärts-Bestätigung, aber es herrschen entgegengesetzte Bedingungen.

      else if (fvgColor == CLR_UP && Ask < fvgLow && !signalFVGs[j]){
         Print("BUY SIGNAL For (",fvgNAME,") Now @ ",Ask);
         double SL_buy = Bid - NormalizeDouble((((fvgHigh-fvgLow)/_Point)*10)*_Point,_Digits);
         double trade_lots = Check1_ValidateVolume_Lots(0.01);

         if (Check2_Margin(ORDER_TYPE_BUY,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_BUY,SL_buy,fvgHigh)){
            obj_Trade.Buy(trade_lots,_Symbol,Ask,SL_buy,fvgHigh);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }


Sobald die FVG nicht mehr existiert, können wir nicht mehr mit ihr handeln, und das ist unsere geringste Sorge. Wir geben also die Speicherbereiche frei, indem wir die entsprechenden Daten loswerden. Dies wird mit der Funktion ArrayRemove erreicht, wobei das Array, die Startposition, in diesem Fall 0 für die ersten Daten, und die Gesamtzahl der Elemente, in diesem Fall 1, übergeben werden, da wir nur die Daten für dieses eine und aktuell ausgewählte FVG-Setup entfernen wollen.

      if (fvgExist == false){
         bool removeName = ArrayRemove(totalFVGs,0,1);
         bool removeTime = ArrayRemove(barTIMEs,0,1);
         bool removeSignal = ArrayRemove(signalFVGs,0,1);
         if (removeName && removeTime && removeSignal){
            Print("Success removing the FVG DATA from the arrays. New Data as Below:");
            Print("FVGs: ",ArraySize(totalFVGs)," TIMEs: ",ArraySize(barTIMEs),
                     " SIGNALs: ",ArraySize(signalFVGs));
            ArrayPrint(totalFVGs);
            ArrayPrint(barTIMEs);
            ArrayPrint(signalFVGs);
         }
      }


Es folgt der OnTick-Code, der benötigt wird, um die FVG-Setups zu erstellen, die bestätigten Setups zu handeln und die Daten der nicht zulässigen Setups aus den Speicherfeldern zu entfernen:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   for (int i=0; i<=FVG_Rec_Ext_Bars; i++){
      double low0 = iLow(_Symbol,_Period,i+1);
      double high2 = iHigh(_Symbol,_Period,i+2+1);
      double gap_L0_H2 = NormalizeDouble((low0 - high2)/_Point,_Digits);
      
      double high0 = iHigh(_Symbol,_Period,i+1);
      double low2 = iLow(_Symbol,_Period,i+2+1);
      double gap_H0_L2 = NormalizeDouble((low2 - high0)/_Point,_Digits);
      
      bool FVG_UP = low0 > high2 && gap_L0_H2 > minPts;
      bool FVG_DOWN = low2 > high0 && gap_H0_L2 > minPts;
      
      if (FVG_UP || FVG_DOWN){
         datetime time1 = iTime(_Symbol,_Period,i+1+1);
         double price1 = FVG_UP ? high2 : high0;
         datetime time2 = time1 + PeriodSeconds(_Period)*FVG_Rec_Ext_Bars;
         double price2 = FVG_UP ? low0 : low2;
         string fvgNAME = FVG_Prefix+"("+TimeToString(time1)+")";
         color fvgClr = FVG_UP ? CLR_UP : CLR_DOWN;
         
         if (ObjectFind(0,fvgNAME) < 0){
            CreateRec(fvgNAME,time1,price1,time2,price2,fvgClr);
            Print("Old ArraySize = ",ArraySize(totalFVGs));
            ArrayResize(totalFVGs,ArraySize(totalFVGs)+1);
            ArrayResize(barTIMEs,ArraySize(barTIMEs)+1);
            ArrayResize(signalFVGs,ArraySize(signalFVGs)+1);
            Print("New ArraySize = ",ArraySize(totalFVGs));
            totalFVGs[ArraySize(totalFVGs)-1] = fvgNAME;
            barTIMEs[ArraySize(barTIMEs)-1] = time1;
            signalFVGs[ArraySize(signalFVGs)-1] = false;
            ArrayPrint(totalFVGs);
            ArrayPrint(barTIMEs);
            ArrayPrint(signalFVGs);
         }
      }
   }
   
   for (int j=ArraySize(totalFVGs)-1; j>=0; j--){
      bool fvgExist = false;
      string objName = totalFVGs[j];
      string fvgNAME = ObjectGetString(0,objName,OBJPROP_NAME);
      double fvgLow = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,0);
      double fvgHigh = ObjectGetDouble(0,fvgNAME,OBJPROP_PRICE,1);
      color fvgColor = (color)ObjectGetInteger(0,fvgNAME,OBJPROP_COLOR);
      
      for (int k=1; k<=FVG_Rec_Ext_Bars; k++){
         double barLow = iLow(_Symbol,_Period,k);
         double barHigh = iHigh(_Symbol,_Period,k);
         
         if (barHigh == fvgLow || barLow == fvgLow){
            //Print("Found: ",fvgNAME," @ bar ",k);
            fvgExist = true;
            break;
         }
      }
      
      //Print("Existence of ",fvgNAME," = ",fvgExist);
      
      double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
      double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
      
      if (fvgColor == CLR_DOWN && Bid > fvgHigh && !signalFVGs[j]){
         Print("SELL SIGNAL For (",fvgNAME,") Now @ ",Bid);
         double SL_sell = Ask + NormalizeDouble((((fvgHigh-fvgLow)/_Point)*10)*_Point,_Digits);
         double trade_lots = Check1_ValidateVolume_Lots(0.01);
         
         if (Check2_Margin(ORDER_TYPE_SELL,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_SELL,SL_sell,fvgLow)){
            obj_Trade.Sell(trade_lots,_Symbol,Bid,SL_sell,fvgLow);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }
      else if (fvgColor == CLR_UP && Ask < fvgLow && !signalFVGs[j]){
         Print("BUY SIGNAL For (",fvgNAME,") Now @ ",Ask);
         double SL_buy = Bid - NormalizeDouble((((fvgHigh-fvgLow)/_Point)*10)*_Point,_Digits);
         double trade_lots = Check1_ValidateVolume_Lots(0.01);

         if (Check2_Margin(ORDER_TYPE_BUY,trade_lots) &&
             Check3_VolumeLimit(trade_lots) &&
             Check4_TradeLevels(POSITION_TYPE_BUY,SL_buy,fvgHigh)){
            obj_Trade.Buy(trade_lots,_Symbol,Ask,SL_buy,fvgHigh);
            signalFVGs[j] = true;
         }
         ArrayPrint(totalFVGs,_Digits," [< >] ");
         ArrayPrint(signalFVGs,_Digits," [< >] ");
      }
      
      if (fvgExist == false){
         bool removeName = ArrayRemove(totalFVGs,0,1);
         bool removeTime = ArrayRemove(barTIMEs,0,1);
         bool removeSignal = ArrayRemove(signalFVGs,0,1);
         if (removeName && removeTime && removeSignal){
            Print("Success removing the FVG DATA from the arrays. New Data as Below:");
            Print("FVGs: ",ArraySize(totalFVGs)," TIMEs: ",ArraySize(barTIMEs),
                     " SIGNALs: ",ArraySize(signalFVGs));
            ArrayPrint(totalFVGs);
            ArrayPrint(barTIMEs);
            ArrayPrint(signalFVGs);
         }
      }      
   }
   
}

Prost auf uns! Nun haben wir ein Smart-Money-Konzept-Handelssystem erstellt, das auf der Strategie von FVG bzw. Ungleichgewicht basiert, um Handelssignale zu generieren.


Ergebnisse des Strategietesters Fair Value Gap (FVG)

Nach einem Test mit dem Strategietester sind die Ergebnisse wie folgt.

  • Salden-/Kapitalkurve:


  • Backtest-Ergebnisse:



Schlussfolgerung

Zusammenfassend lässt sich sagen, dass die Untersuchung der Kodierung der Fair-Value-Gap- oder Ungleichgewichtsstrategie anhand der verschiedenen beschriebenen Themen wertvolle Einblicke in quantitative Handelsmethoden bietet. In diesem Artikel haben wir uns mit den komplizierten Details der Umsetzung solcher Strategien befasst und sind dabei auf Schlüsselkomponenten wie Datenanalyse, statistische Modellierung und algorithmische Handelstechniken eingegangen.

Erstens ist das Verständnis des Konzepts der Marktwertlücke oder des Ungleichgewichts von wesentlicher Bedeutung, da es die Grundlage der Strategie bildet. Es geht darum, Diskrepanzen zwischen dem Marktpreis eines Vermögenswerts und seinem inneren Wert festzustellen und statistische Methoden einzusetzen, um diese Unterschiede genau zu messen.

Darüber hinaus unterstreicht der Artikel die Bedeutung robuster Datenanalysetechniken für die Gewinnung aussagekräftiger Erkenntnisse aus Finanzdaten. Techniken wie die Zeitreihenanalyse, die Kerzen-Analyse und die Stimmungsanalyse spielen eine entscheidende Rolle bei der Ermittlung von Mustern und Trends, die als Grundlage für Handelsentscheidungen dienen können.

Darüber hinaus unterstreicht der Codierungsaspekt der Strategie die Bedeutung der Beherrschung der MQL5-Programmiersprache sowie der Vertrautheit mit den MQL5-Bibliotheken und -Funktionen. Effiziente Kodierungsverfahren ermöglichen die Automatisierung von Handelsprozessen, was eine schnellere Ausführung und die Skalierbarkeit der Strategie erleichtert.

Haftungsausschluss: Die in diesem Artikel dargestellten Informationen dienen nur zu Lehrzwecken. Er soll lediglich Einblicke in die Erstellung eines Fair-Value-Gap-EAs auf der Grundlage des Smart-Money-Konzepts geben und somit als Basis für die Erstellung eines besseren Expert Advisors mit mehr Optimierung und Datenextraktion dienen. Die dargestellten Informationen garantieren keine Handelsergebnisse. 

Insgesamt unterstreicht der Artikel die Interdisziplinarität von quantitativem Handel, Statistik und Balkenanalyse zur Entwicklung effektiver Strategien für die Navigation auf dynamischen Finanzmärkten. Durch die Synthese von theoretischen Konzepten mit praktischen Kodierungsimplementierungen gibt der Artikel den Lesern die notwendigen Werkzeuge an die Hand, um quantitative Handelsbestrebungen erfolgreich zu verfolgen, insbesondere den Smart Money Concept (SMC)-Ansatz.


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

Beigefügte Dateien |
FVG_SMC_EA.mq5 (21.23 KB)
Nutzerdefinierte Indikatoren (Teil 1): Eine schrittweise Einführung in die Entwicklung von einfachen nutzerdefinierten Indikatoren in MQL5 Nutzerdefinierte Indikatoren (Teil 1): Eine schrittweise Einführung in die Entwicklung von einfachen nutzerdefinierten Indikatoren in MQL5
Erfahren Sie, wie Sie mit MQL5 nutzerdefinierte Indikatoren erstellen können. Dieser Einführungsartikel führt Sie durch die Grundlagen des Aufbaus einfacher nutzerdefinierter Indikatoren und demonstriert einen praktischen Ansatz zur Codierung verschiedener nutzerdefinierter Indikatoren für alle MQL5-Programmierer, die neu in diesem interessanten Thema sind.
Aufbau eines Modells von Kerzen, Trend und Nebenbedingungen (Teil 1): Für EAs und technische Indikatoren Aufbau eines Modells von Kerzen, Trend und Nebenbedingungen (Teil 1): Für EAs und technische Indikatoren
Dieser Artikel richtet sich an Anfänger und Profi-MQL5-Entwickler. Es stellt einen Code zur Verfügung, um signalgenerierende Indikatoren zu definieren und auf Trends in höheren Zeitrahmen zu beschränken. Auf diese Weise können Händler ihre Strategien verbessern, indem sie eine breitere Marktperspektive einbeziehen, was zu potenziell robusteren und zuverlässigeren Handelssignalen führt.
Bewältigung der Herausforderungen bei der ONNX-Integration Bewältigung der Herausforderungen bei der ONNX-Integration
ONNX ist ein großartiges Werkzeug für die Integration von komplexem KI-Code zwischen verschiedenen Plattformen. Es ist ein großartiges Werkzeug, das einige Herausforderungen mit sich bringt, die man angehen muss, um das Beste daraus zu machen.
Entwicklung eines MQTT-Clients für MetaTrader 5: ein TDD-Ansatz — Finale Entwicklung eines MQTT-Clients für MetaTrader 5: ein TDD-Ansatz — Finale
Dieser Artikel ist der letzte Teil einer Serie, die unsere Entwicklungsschritte für einen nativen MQL5-Client für das MQTT 5.0-Protokoll beschreibt. Obwohl die Bibliothek noch nicht produktionsreif ist, werden wir in diesem Teil unseren Client verwenden, um ein nutzerdefiniertes Symbol mit Ticks (oder Kursen) zu aktualisieren, die von einem anderen Broker stammen. Am Ende dieses Artikels finden Sie weitere Informationen über den aktuellen Status der Bibliothek, was ihr noch fehlt, um vollständig mit dem MQTT 5.0-Protokoll kompatibel zu sein, eine mögliche Roadmap und wie Sie die Entwicklung verfolgen und zu ihr beitragen können.