Verbessern Sie Ihren Handel mit Smart Money Konzepten (SMC): OB, BOS und FVG
Einführung
Manchmal stehen Händler vor der Herausforderung, dass ihre Strategien inkonsistent sind und sie oft zwischen Indikatoren, Setups und Methoden hin- und herspringen, ohne einen soliden Rahmen zu haben, der sie leitet. Dieser Mangel an Struktur kann zu Verwirrung, verpassten Chancen und zunehmender Frustration führen, wenn sich die Marktbedingungen ändern und die traditionellen Instrumente nicht mehr mithalten können. In diesem Thema untersuchen wir die Vorteile eines einzigen EA, der mehrere Smart Money Concept (SMC)-Strategien in einer einzigen leistungsstarken Lösung vereint.
Smart Money Concepts (SMC) bieten einen strukturierten Weg zum Verständnis des Marktverhaltens durch Order Blocks (OB), Break of Structure (BOS) und Fair Value Gaps (FVG). Durch die Kombination dieser Funktionen in einem einzigen EA können Händler ihre Arbeitsabläufe vereinfachen, die Entscheidungsfindung automatisieren und sich auf die aussagekräftigsten Preisaktionssignale konzentrieren. Egal, ob Sie den Automodus für eine nahtlose Ausführung nutzen oder einzelne Konzepte auswählen, dieser Ansatz reduziert das Rätselraten und macht den Handel effizienter, konsistenter und anpassungsfähiger an sich ändernde Marktbedingungen.
Logik des Experten
Order Block:
Ein Order Block (OB) stellt die letzte Auf- oder Abwärtskerze vor einer bedeutenden Marktbewegung dar und zeigt oft an, wo institutionelle Händler ihre Aufträge platziert haben. Wenn der Kurs diese Zonen wieder erreicht, fungieren sie in der Regel als starke Unterstützungs- oder Widerstandsbereiche, die mit hoher Wahrscheinlichkeit Handelsmöglichkeiten bieten. In diesem EA wird die Erkennung von Order Blocks noch verbessert, indem der Fibonacci-Indikator zur Validierung integriert wird, um sicherzustellen, dass die Handelsgeschäfte mit wichtigen Retracement- oder Extension-Levels übereinstimmen. Wie im vorangegangenen Artikel erläutert, werden durch die Kombination von OB und Fibonacci-Bestätigung schwächere Setups herausgefiltert, sodass Händler einen zuverlässigeren Rahmen für den Einstieg in den Handel und die Verwaltung von Handelsgeschäften erhalten.

Fair Value Gap:
Eine Fair Value Gap (FVG) tritt auf, wenn ein Ungleichgewicht in der Kursbewegung besteht, das typischerweise durch eine starke impulsive Bewegung entsteht, bei der eine oder mehrere Kerzen eine Lücke zwischen den Dochten der vorangehenden und der nachfolgenden Kerzen hinterlassen. Diese Lücke spiegelt die Ineffizienz des Marktes wider, auf dem nicht alle Aufträge ausgeführt wurden, und der Preis kehrt oft zurück, um diese Lücke zu „füllen“, bevor er seine beabsichtigte Richtung fortsetzt. Durch das Aufspüren von FVGs und das Handeln um diese herum, können Händler potenzielle Rückschritte in diese Zonen antizipieren und so präzise Einstiegsmöglichkeiten mit klar definiertem Risiko und Ertrag bieten.

Break Of Structure:
Ein Break Of Structure (BOS) tritt auf, wenn der Kurs über einen vorherigen hohen oder tiefen Umkehrpunkt unter einen vorherigen tiefen Umkehrpunkt durchbricht und damit eine potenzielle Richtungsänderung des Marktes signalisiert. Im letzten Artikel haben wir uns darauf konzentriert, zu verkaufen, wenn ein hoher Umkehrpunkt durchbrochen wurde, um das Abwärtsmomentum zu nutzen. Bei diesem Ansatz wird die BOS-Logik jedoch so verfeinert, dass sie mit dem vorherrschenden Markttrend übereinstimmt, d. h., wenn ein hoher Umkehrpunkt durchbrochen wird, suchen wir nach einer Kaufgelegenheit, um die Aufwärtsbewegung zu bestätigen, während ein Durchbruch eines tiefen Umkehrpunktes eine Verkaufsgelegenheit signalisiert. Diese Verschiebung sorgt dafür, dass der Handel der vorherrschenden Marktströmung folgt, anstatt ihr entgegenzuwirken.

Systemarchitektur:

Die ersten Schritte
//+------------------------------------------------------------------+ //| SMC_ALL_IN_1.mq5 | //| GIT under Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com/en/users/johnhlomohang/ | //+------------------------------------------------------------------+ #property copyright "GIT under Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/johnhlomohang/" #property version "1.01" #property description "Unified SMC: FVG + Order Blocks + BOS. Detect + Draw + Trade." #include <Trade/Trade.mqh> #include <Trade/PositionInfo.mqh> CTrade trade; CPositionInfo pos; enum ENUM_STRATEGY { STRAT_OB, // Use Order Blocks Only STRAT_FVG, // Use FVGs Only STRAT_BOS, // Use Break of Structure Only STRAT_AUTO // Auto (All SMC Concepts) }; enum SWING_TYPE{ SWING_OB, SWING_BOS, };
Der Code enthält die MetaTrader-Handelsbibliotheken, insbesondere CTrade und CPositionInfo, die dem EA das Platzieren und Verwalten von Handelsgeschäften sowie den Zugriff auf Informationen über offene Positionen ermöglichen. Durch die Einrichtung dieser Klassen zu Beginn stellt der EA sicher, dass er über die wichtigsten Werkzeuge verfügt, die für die Auftragsausführung und Positionsverfolgung erforderlich sind.
Im nächsten Teil werden die strategische Flexibilität und die Klassifizierung für eine Umkehrung durch Enumerationen definiert. ENUM_STRATEGY gibt Händlern die Möglichkeit zu wählen, welcher Methode der EA folgen soll: strikt Order Blocks, strikt FVGs, strikt BOS, oder ein vollautomatischer Modus (STRAT_AUTO), der alle drei Konzepte dynamisch nutzt. In ähnlicher Weise unterscheidet die Enumeration SWING_TYPE zwischen Umkehrpunkten, die für Order Blocks verwendet werden, und solchen, die für die Analyse von Break of Structure verwendet werden. Diese Struktur macht den Code modular und anpassungsfähig, sodass Händler mit verschiedenen SMC-Ansätzen experimentieren oder den EA automatisch auf Basis der Marktbedingungen entscheiden lassen können.
//----------------------------- Inputs ------------------------------// input ENUM_STRATEGY TradeStrategy = STRAT_AUTO; input double In_Lot = 0.02; input double StopLoss = 3500; // points input double TakeProfit = 7500; // points input long MagicNumber = 76543; input int SwingPeriod = 5; // bars each side to confirm swing input int SwingProbeBar = 5; // bar index we test for swings (>=SwingPeriod) input double Fib_Trade_lvls = 61.8; // OB retrace must reach this % input bool DrawBOSLines = true; input int FVG_MinPoints = 3; // minimal gap in points input int FVG_ScanBars = 20; // how many bars to scan for FVGs input bool FVG_TradeAtEQ = true; // trade at 50% of the gap (EQ) input bool OneTradePerBar = true; //---------------------------- Colors -------------------------------// #define BullOB clrLime #define BearOB clrRed #define BullFVG clrPaleGreen #define BearFVG clrMistyRose #define BOSBull clrDodgerBlue #define BOSBear clrTomato
In diesem Abschnitt des Codes werden die Eingaben definiert, die der Händler an seinen Handelsstil und seine Risikomanagementpräferenzen anpassen kann. Mit der Eingabe der TradeStrategy kann der Nutzer auswählen, ob der EA nur mit Order Blocks, nur mit Fair Value Gaps, nur mit Break of Structure oder automatisch mit einer Kombination aus allen drei Strategien handeln soll. Die Einstellungen für das Risiko- und Geldmanagement werden über In_Lot, StopLoss, TakeProfit und MagicNumber gesteuert, die eine korrekte Losgröße, schützende Stopps, Gewinnziele und eine eindeutige Handelsidentifizierung gewährleisten. Darüber hinaus geben Erkennungsparameter der Umkehrpunkte wie SwingPeriod und SwingProbeBar an, wie viele Balken bei der Identifizierung von hohen oder tiefen Umkehrpunkten berücksichtigt werden, während Fib_Trade_lvls sicherstellt, dass die Handelsgeschäfte des Order Blocks mit der Fibonacci-Retracement-Bestätigung übereinstimmen. Die Option DrawBOSLines bietet Flexibilität bei der Chartdarstellung und ermöglicht es Händlern, Break of Structure-Levels direkt auf dem Chart zu sehen.
Es folgen die Einstellungen von Fair Value Gap (FVG), die eine genauere Kontrolle darüber ermöglichen, wie Lücken erkannt und gehandelt werden. FVG_MinPoints stellt sicher, dass nur signifikante Ungleichgewichte berücksichtigt werden, während FVG_ScanBars festlegt, wie weit zurück in der Historie der EA nach gültigen Gaps suchen soll. Die Option FVG_TradeAtEQ ermöglicht den Handel auf dem Gleichgewichtsniveau (50 % des Gaps), das in der SMC-Theorie häufig als ausgewogener Einstiegspunkt angesehen wird. Schließlich machen Farbdefinitionen wie BullOB, BearOB, BullFVG, BearFVG, BOSBull und BOSBear die Chartobjekte visuell intuitiv, sodass Händler auf einen Blick zwischen Auf- und Abwärts-Setups unterscheiden können.
//---------------------------- Globals ------------------------------// double Bid, Ask; datetime g_lastBarTime = 0; // OB state class COrderBlock : public CObject { public: int direction; // +1 bullish, -1 bearish datetime time; // OB candle time double high; // OB candle high double low; // OB candle low string Key() const { return TimeToString(time, TIME_DATE|TIME_MINUTES); } void draw(datetime tmS, datetime tmE, color clr){ string objOB = " OB REC" + TimeToString(time); ObjectCreate( 0, objOB, OBJ_RECTANGLE, 0, time, low, tmS, high); ObjectSetInteger( 0, objOB, OBJPROP_FILL, true); ObjectSetInteger( 0, objOB, OBJPROP_COLOR, clr); string objtrade = " OB trade" + TimeToString(time); ObjectCreate( 0, objtrade, OBJ_RECTANGLE, 0, tmS, high, tmE, low); // trnary operator ObjectSetInteger( 0, objtrade, OBJPROP_FILL, true); ObjectSetInteger( 0, objtrade, OBJPROP_COLOR, clr); } }; COrderBlock* OB = NULL; // OB fib state // Track if an OB has already been traded datetime lastTradedOBTime = 0; bool tradedOB = false; double fib_low, fib_high; datetime fib_t1, fib_t2; bool isBullishOB = false; bool isBearishOB = false; datetime T1; datetime T2; color OBClr; #define FIB_OB_BULL "FIB_OB_BULL" #define FIB_OB_BEAR "FIB_OB_BEAR" #define FIBO_OBJ "Fibo Retracement" // BOS state datetime lastBOSTradeTime = 0; bool Bull_BOS_traded, Bear_BOS_traded; int lastBOSTradeDirection = 0; // 1 for buy, -1 for sell double swng_High = -1.0, swng_Low = -1.0; datetime bos_tH = 0, bos_tL = 0;
In diesem globalen Abschnitt des Codes werden die Hauptvariablen und -strukturen festgelegt, die den Marktstatus, die Handelsmöglichkeiten und die Chartobjekte verfolgen. Es beginnt mit einfachen globalen Werten wie Bid, Ask und g_lastBarTime, die für die Preisverfolgung in Echtzeit wichtig sind und sicherstellen, dass der Expert Advisor die Logik nur einmal pro neuem Balken ausführt. Von dort aus wird eine spezielle Klasse, COrder Block, erstellt, um die Eigenschaften eines Order Blocks zu kapseln, einschließlich seiner Richtung (Auf- oder Abwärts), der Zeit und der Preisniveaus (Hoch/Tief). Die Klasse enthält auch eine Funktion draw(), die automatisch Rechtecke auf dem Chart erstellt und einfärbt, sodass Händler aktive Orderblöcke und ihre Handelszonen leicht erkennen können. Durch die Zentralisierung dieser Funktionen in einer Klasse bleibt der Code übersichtlich und wiederverwendbar.
Neben der grundlegenden OB-Identifikation werden zusätzliche Variablen definiert, um die Fibonacci-basierte Validierung von Order Blocks zu handhaben. Zum Beispiel speichern fib_low, fib_high und die Zeitmarken fib_t1 und fib_t2 die Grenzen für Fibonacci-Retracement-Levels, während Flags wie isBullishOB, isBearishOB und tradedOB sicherstellen, dass jeder Order Block nur einmal validiert und gehandelt wird. Diese Variablen ermöglichen es dem EA, Fibonacci-Levels dynamisch zu referenzieren, um sicherzustellen, dass nur gültige Retracements (wie z.B. das 61,8%-Level, das in den Eingaben definiert ist) für Handelseinträge berücksichtigt werden. Um die Visualisierung zu verdeutlichen, definieren Konstanten wie FIB_OB_BULL, FIB_OB_BEAR und FIBO_OBJ die Namen der Chart-Objekte und stellen sicher, dass Fibonacci-Retracements beim Zeichnen unterscheidbar sind.
Schließlich wird die Verwaltung des Zustands Break of Structure (BOS) eingeführt. Die Variablen lastBOSTradeTime, Bull_BOS_traded und Bear_BOS_traded verhindern, dass doppelte Abschlüsse ausgeführt werden, wenn ein BOS-Signal auftritt. Die lastBOSTradeDirection hält fest, ob der letzte BOS-Handel aufwärts (+1) oder abwärts (-1) war, während swng_High und swng_Low die letzten Umkehrpunkte zur Strukturerkennung speichern. Die Zeitmarken bos_tH und bos_tL sind enthalten, um die genauen Zeitpunkte zu identifizieren, zu denen die Schwankungen bestätigt wurden, und um die Übereinstimmung mit den Marktstrukturregeln zu gewährleisten. Durch die globale Verwaltung dieser Zustände stellt der EA die Konsistenz zwischen verschiedenen Strategien (OB, BOS, FVG) sicher und verhindert überlappende Handelsgeschäfte, wodurch eine strukturierte Grundlage für die Handelsautomatisierung des Smart Money Concept geschaffen wird.
//--------------------------- Helpers -------------------------------// double getHigh(int i) { return iHigh(_Symbol, _Period, i); } double getLow(int i) { return iLow(_Symbol, _Period, i); } double getOpen(int i) { return iOpen(_Symbol, _Period, i); } double getClose(int i) { return iClose(_Symbol, _Period, i); } datetime getTimeBar(int i){ return iTime(_Symbol, _Period, i); } bool IsNewBar() { datetime lastbar_time = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); if(g_lastBarTime == 0) { g_lastBarTime = lastbar_time; return false; } if(g_lastBarTime != lastbar_time) { g_lastBarTime = lastbar_time; return true; } return false; } void ExecuteTrade(ENUM_ORDER_TYPE type) { double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double price = (type==ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID); double sl = (type==ORDER_TYPE_BUY) ? price - StopLoss*point : price + StopLoss*point; double tp = (type==ORDER_TYPE_BUY) ? price + TakeProfit*point : price - TakeProfit*point; sl = NormalizeDouble(sl, _Digits); tp = NormalizeDouble(tp, _Digits); trade.SetExpertMagicNumber(MagicNumber); trade.PositionOpen(_Symbol, type, In_Lot, price, sl, tp, "SMC"); }
Die Hilfsfunktionen hier bieten eine saubere und wiederverwendbare Möglichkeit zur Interaktion mit Chart-Daten. Anstatt integrierte Funktionen wie iHigh, iLow oder iClose direkt im Code aufzurufen, erleichtern Wrapper wie getHigh(), getLow() und getClose() den Zugriff auf Balkeninformationen und verbessern gleichzeitig die Lesbarkeit. Die Funktion IsNewBar() spielt eine entscheidende Rolle, wenn es darum geht, dass der EA die Logik nur einmal pro Kerze verarbeitet, um wiederholte Ausführungen innerhalb desselben Balkens zu vermeiden. Dazu wird die letzte bekannte Balkenzeit in g_lastBarTime gespeichert und mit dem Zeitstempel des aktuellen Balkens verglichen. Dieser effiziente Ansatz stellt sicher, dass Signale und Handelsgeschäfte nur dann berücksichtigt werden, wenn ein neuer Balken geöffnet wird, was für Strategien, die sich auf bestätigte Kerzenabschlüsse verlassen, von entscheidender Bedeutung ist.
Die Funktion ExecuteTrade() kapselt die gesamte Logik der Handelsausführung. Es berechnet automatisch den korrekten Einstiegskurs, Stop Loss und Take Profit auf der Grundlage des Auftragstyps (Kauf oder Verkauf) und stellt sicher, dass die Werte so normalisiert werden, dass sie der Dezimalgenauigkeit des Instruments entsprechen. Durch die Zentralisierung dieser Logik vermeidet der EA sich wiederholenden Code und reduziert Fehler bei der Eröffnung von Handelsgeschäften. Die Funktion legt auch die eindeutige MagicNumber des EA zur Nachverfolgung fest und versieht jeden Handel mit dem Kommentar „SMC“, sodass Händler die von diesem System eröffneten Positionen leicht identifizieren können.
//----------------------- Unified Swing Detection -------------------// // Detects if barIndex is a swing high and/or swing low using len bars on each side. // If swing high found -> updates fib_high/fib_tH (and swng_High/bos_tH if for BOS). // If swing low found -> updates fib_low/fib_tL (and swng_Low/bos_tL if for BOS). // return: true if at least one swing found. void DetectSwingForBar(int barIndex, SWING_TYPE type) { const int len = 5; bool isSwingH = true, isSwingL = true; for(int i = 1; i <= len; i++){ int right_bars = barIndex - i; int left_bars = barIndex + i; if(right_bars < 0) { isSwingH = false; isSwingL = false; break; } if((getHigh(barIndex) <= getHigh(right_bars)) || (left_bars < Bars(_Symbol, _Period) && getHigh(barIndex) < getHigh(left_bars))) isSwingH = false; if((getLow(barIndex) >= getLow(right_bars)) || (left_bars < Bars(_Symbol, _Period) && getLow(barIndex) > getLow(left_bars))) isSwingL = false; } // Assign with ternary operator depending on swing type if(isSwingH){ if(type == SWING_OB) { fib_high = getHigh(barIndex); fib_t1 = getTimeBar(barIndex); } else { swng_High = getHigh(barIndex); bos_tH = getTimeBar(barIndex); } } if(isSwingL){ if(type == SWING_OB) { fib_low = getLow(barIndex); fib_t2 = getTimeBar(barIndex); } else { swng_Low = getLow(barIndex); bos_tL = getTimeBar(barIndex); } } }
Die einheitliche Erkennungsfunktion der Umkehrpunkte dient dazu, potenzielle hohe und tiefe Umkehrpunkte auf dem Chart zu identifizieren, indem ein bestimmter Balken untersucht und mit einer bestimmten Anzahl von benachbarten Balken verglichen wird. Bei einem symmetrischen Bereich (len Balken auf jeder Seite) prüft die Funktion, ob der aktuelle Balken ein lokales Extremum bildet, d. h. ob sein Hoch über dem linken und rechten Balken liegt (hoher Umkehrpunkt) oder ob sein Tief unter beiden Seiten liegt (tiefer Umkehrpunkt). Wenn ein Balken auf der linken oder rechten Seite diese Bedingungen ungültig macht, wird die Umkehr-Kennzeichnung zurückgewiesen. Diese Methode stellt sicher, dass Ausschläge nicht fälschlicherweise durch geringfügige Schwankungen ausgelöst werden, sondern sich auf aussagekräftige Drehpunkte in der Marktstruktur konzentrieren.
Sobald ein Umkehrpunkt bestätigt wird, aktualisiert die Funktion die Schlüsselvariablen je nach Typ des Umkehrpunktes. Für die Erkennung von Order Blocks (SWING_OB) werden den Fibonacci-Ankerpunkten (fib_high und fib_low) hohe und tiefe Umkehrpunkte zusammen mit ihren Zeitstempeln zugeordnet, die später für die Retracement-Validierung verwendet werden. Für die BOS-Logik (Break of Structure) werden dieselben Schwankungspegel swng_High oder swng_Low zugewiesen, gepaart mit ihren jeweiligen Zeitstempeln (bos_tH oder bos_tL). Durch die Verarbeitung von OB und BOS in einer einzigen Funktion hält der EA die Erkennung von Umkehrpunkten schlank und vermeidet redundante Logik, sodass sowohl die Strukturvalidierung als auch die Fibonacci-Retracement-Setups denselben konsistenten Erkennungsprozess von Umkehrpunkten nutzen.
void DetectAndDrawOrderBlocks() { static datetime lastDetect = 0; datetime lastBar = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); // Reset OB detection on new bar if(lastDetect != lastBar) { if(OB != NULL) { delete OB; OB = NULL; } lastDetect = lastBar; } // Only detect new OB if we don't have one already if(OB == NULL) { for(int i = 1; i < 100; i++) { // Bullish OB candidate if(getOpen(i) < getClose(i) && getOpen(i+2) < getClose(i+2) && getOpen(i+3) > getClose(i+3) && getOpen(i+3) < getClose(i+2)) { OB = new COrderBlock(); OB.direction = 1; OB.time = getTimeBar(i+3); OB.high = getHigh(i+3); OB.low = getLow(i+3); OBClr = BullOB; T1 = OB.time; Print("Bullish Order Block detected at: ", TimeToString(OB.time)); break; } // Bearish OB candidate if(getOpen(i) > getClose(i) && getOpen(i+2) > getClose(i+2) && getOpen(i+3) < getClose(i+3) && getOpen(i+3) > getClose(i+2)) // Fixed condition { OB = new COrderBlock(); OB.direction = -1; OB.time = getTimeBar(i+3); OB.high = getHigh(i+3); OB.low = getLow(i+3); OBClr = BearOB; T1 = OB.time; Print("Bearish Order Block detected at: ", TimeToString(OB.time)); break; } } } if(OB == NULL) return; // Check if we already traded this OB if(lastTradedOBTime == OB.time) return; // If price retraces inside OB zone Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); bool inBullZone = (OB.direction > 0 && Ask <= OB.high && Ask >= OB.low); bool inBearZone = (OB.direction < 0 && Bid >= OB.low && Bid <= OB.high); if(!inBullZone && !inBearZone) return; // Use your DetectSwing function to find swings // We need to call it multiple times to find the most recent swings double mostRecentSwingHigh = 0; double mostRecentSwingLow = EMPTY_VALUE; datetime mostRecentSwingHighTime = 0; datetime mostRecentSwingLowTime = 0; // Scan recent bars to find the most recent swings for(int i = 0; i < 20; i++) // Check the last 20 bars { // Reset swing variables fib_high = 0; fib_low = 0; fib_t1 = 0; fib_t2 = 0; DetectSwingForBar(i, SWING_OB); if(fib_high > 0 && (mostRecentSwingHighTime == 0 || fib_t1 > mostRecentSwingHighTime)) { mostRecentSwingHigh = fib_high; mostRecentSwingHighTime = fib_t1; } if(fib_low < EMPTY_VALUE && (mostRecentSwingLowTime == 0 || fib_t2 > mostRecentSwingLowTime)) { mostRecentSwingLow = fib_low; mostRecentSwingLowTime = fib_t2; } } // Ensure we found both swing points if(mostRecentSwingHighTime == 0 || mostRecentSwingLowTime == 0) return; // Draw Fibonacci before trading to validate if(OB.direction > 0 && inBullZone) { // Draw Fibonacci from recent swing low to recent swing high ObjectDelete(0, "FIB_OB_BULL"); if(ObjectCreate(0, "FIB_OB_BULL", OBJ_FIBO, 0, mostRecentSwingLowTime, mostRecentSwingLow, mostRecentSwingHighTime, mostRecentSwingHigh)) { // Format Fibonacci ObjectSetInteger(0, "FIB_OB_BULL", OBJPROP_COLOR, clrBlack); for(int i = 0; i < ObjectGetInteger(0, "FIB_OB_BULL", OBJPROP_LEVELS); i++) { ObjectSetInteger(0, "FIB_OB_BULL", OBJPROP_LEVELCOLOR, i, clrBlack); } double entLvlBull = mostRecentSwingHigh - (mostRecentSwingHigh - mostRecentSwingLow) * (Fib_Trade_lvls / 100.0); if(Ask <= entLvlBull) { T2 = getTimeBar(0); OB.draw(T1, T2, BullOB); ExecuteTrade(ORDER_TYPE_BUY); lastTradedOBTime = OB.time; // Mark this OB as traded delete OB; OB = NULL; } } } else if(OB.direction < 0 && inBearZone) { // Draw Fibonacci from recent swing high to recent swing low ObjectDelete(0, "FIB_OB_BEAR"); if(ObjectCreate(0, "FIB_OB_BEAR", OBJ_FIBO, 0, mostRecentSwingHighTime, mostRecentSwingHigh, mostRecentSwingLowTime, mostRecentSwingLow)) { // Format Fibonacci ObjectSetInteger(0, "FIB_OB_BEAR", OBJPROP_COLOR, clrBlack); for(int i = 0; i < ObjectGetInteger(0, "FIB_OB_BEAR", OBJPROP_LEVELS); i++) { ObjectSetInteger(0, "FIB_OB_BEAR", OBJPROP_LEVELCOLOR, i, clrBlack); } double entLvlBear = mostRecentSwingLow + (mostRecentSwingHigh - mostRecentSwingLow) * (Fib_Trade_lvls / 100.0); if(Bid >= entLvlBear) { T2 = getTimeBar(0); OB.draw(T1, T2, BearOB); ExecuteTrade(ORDER_TYPE_SELL); lastTradedOBTime = OB.time; // Mark this OB as traded delete OB; OB = NULL; } } } }
Die Funktion DetectAndDrawOrder Blocks() ist für die Identifizierung, Validierung und den Handel von Order Blocks verantwortlich, wobei die Fibonacci-Konfluenz in den Entscheidungsprozess integriert wird. Zunächst wird die Erkennung bei jedem neuen Balken zurückgesetzt, und dann werden die letzten Kerzen auf Aufwärts- oder Abwärtsmuster der Order Blocks untersucht. Sobald ein gültiger Auftragsblock gefunden wurde, wird geprüft, ob der aktuelle Kurs in die Zone zurückgeht, was eine potenzielle Handelsmöglichkeit signalisiert. Vor der Ausführung ruft die Funktion die Umkehr-Erkennung auf, um den letzten hohen und den letzten tiefen Umkehrpunkt zu ermitteln und sicherzustellen, dass ein Fibonacci-Retracement zwischen diesen beiden Werten eingezeichnet werden kann.
Das Fibonacci-Tool wird dann zur Validierung des Einstiegs verwendet, wobei der Kurs an ein vordefiniertes Retracement-Level angepasst werden muss, bevor der Handel bestätigt wird. Auf diese Weise vermeidet das System verfrühte Eingaben und stellt sicher, dass Handelsgeschäfte nur dann ausgeführt werden, wenn sowohl die Zone des Order Blocks als auch das Fibonacci-Retracement übereinstimmen, wodurch die Genauigkeit und Konsistenz bei der Handelsvalidierung verstärkt wird.
//============================== FVG ================================// // Definition (ICT-style): // Let C=i, B=i+1, A=i+2. // Bullish FVG if Low(A) > High(C) -> gap [High(C), Low(A)] // Bearish FVG if High(A) < Low(C) -> gap [High(A), Low(C)] struct SFVG { int dir; // +1 bull, -1 bear datetime tLeft; // left time anchor double top; // zone top price double bot; // zone bottom price string Name() const { string k = TimeToString(tLeft, TIME_DATE|TIME_MINUTES); return (dir>0 ? "FVG_B_" : "FVG_S_") + k + "_" + IntegerToString((int)(top*1000.0)); } }; bool FVGExistsAt(const string &name){ return ObjectFind(0, name) != -1; } void DetectAndDrawFVGs() { double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int counted = 0; for(int i=2; i<MathMin(FVG_ScanBars, Bars(_Symbol, _Period))-2; i++) { // Build A,B,C double lowA = getLow(i+2); double highA = getHigh(i+2); double highC = getHigh(i); double lowC = getLow(i); // Bullish FVG: Low of A > High of C if(lowA > highC && (lowA - highC >= FVG_MinPoints * point)) { SFVG z; z.dir = +1; z.tLeft = getTimeBar(i+2); // Changed from getTimeBar to getTime z.top = lowA; z.bot = highC; DrawFVG(z); counted++; } // Bearish FVG: High of A < Low of C else if(highA < lowC && (lowC - highA >= FVG_MinPoints * point)) { SFVG z; z.dir = -1; z.tLeft = getTimeBar(i+2); // Changed from getTimeBar to getTime z.top = lowC; // Fixed: should be lowC for bearish FVG top z.bot = highA; // Fixed: should be highA for bearish FVG bottom DrawFVG(z); counted++; } if(counted > 15) break; // avoid clutter } // --- Simplified trading for FVGs --- Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // scan drawn objects and trade on first valid touch of EQ (50%) int total = ObjectsTotal(0, 0, -1); static datetime lastTradeBar = 0; if(OneTradePerBar) { datetime barNow = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); if(lastTradeBar == barNow) return; // already traded this bar } for(int idx=0; idx<total; idx++) { string name = ObjectName(0, idx); if(StringFind(name, "FVG_", 0) != 0) continue; // only our FVGs // Get object coordinates datetime t1 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 0); double y1 = ObjectGetDouble(0, name, OBJPROP_PRICE, 0); datetime t2 = (datetime)ObjectGetInteger(0, name, OBJPROP_TIME, 1); double y2 = ObjectGetDouble(0, name, OBJPROP_PRICE, 1); double top = MathMax(y1, y2); double bot = MathMin(y1, y2); bool isBull = (StringFind(name, "FVG_B_", 0) == 0); double mid = (top + bot) * 0.5; if(isBull) { // trade when Ask is inside the gap and at/under EQ if(Ask <= top && Ask >= bot && (!FVG_TradeAtEQ || Ask <= mid)) { ExecuteTrade(ORDER_TYPE_BUY); lastTradeBar = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); break; } } else { // trade when Bid is inside the gap and at/over EQ if(Bid <= top && Bid >= bot && (!FVG_TradeAtEQ || Bid >= mid)) { ExecuteTrade(ORDER_TYPE_SELL); lastTradeBar = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); break; } } } }
Diese Funktion erkennt, zeichnet und handelt Fair Value Gaps (FVGs) auf der Grundlage der ICT-Logik. Zunächst werden die letzten Balken gescannt, um Aufwärts-Lücken zu erkennen, bei denen das Tief der Kerze A höher ist als das Hoch von Kerze C, und Abwärts-Lücken, bei denen das Hoch der Kerze A niedriger ist als das Tief von Kerze C, sofern die Lücke eine Mindestgröße in Punkten erreicht. Sobald ein FVG erkannt wird, wird es in einer Struktur gespeichert, visuell auf dem Chart dargestellt und für den Handel verfolgt. Das System überwacht dann aktive FVG-Zonen und prüft, wann der Preis in die Lücke eintritt und sich am Gleichgewichtsniveau (50 % der Zone) ausrichtet, sofern dies möglich ist. Wenn die Bedingungen erfüllt sind, führt die Funktion einen Handel aus, wobei sie bei Aufwärts-FVGs kauft und bei Abwärts-FVGs verkauft, wobei sie sicherstellt, dass nur ein Handelsgeschäft pro Balken durchgeführt wird, um Overtrading zu vermeiden. Diese Kombination aus Erkennung, Visualisierung und Ausführung macht das FVG-Tool sowohl analytisch als auch direkt handelbar.
//=============================== BOS ===============================// // Use unified swings (no RSI). Trading logic mirrors your earlier code: // - Sell when price breaks above last swing high (liquidity run idea) // - Buy when price breaks below last swing low void DetectAndDrawBOS() { // Use DetectSwingForBar to find the most recent swing points double mostRecentSwingHigh = 0; double mostRecentSwingLow = EMPTY_VALUE; datetime mostRecentSwingHighTime = 0; datetime mostRecentSwingLowTime = 0; // Scan recent bars to find the most recent swings for BOS for(int i = 0; i < 20; i++) // Check the last 20 bars { // Reset swing variables swng_High = 0; swng_Low = 0; bos_tH = 0; bos_tL = 0; // Detect swing at this bar for BOS DetectSwingForBar(i, SWING_BOS); if(swng_High > 0 && (mostRecentSwingHighTime == 0 || bos_tH > mostRecentSwingHighTime)) { mostRecentSwingHigh = swng_High; mostRecentSwingHighTime = bos_tH; } if(swng_Low < EMPTY_VALUE && (mostRecentSwingLowTime == 0 || bos_tL > mostRecentSwingLowTime)) { mostRecentSwingLow = swng_Low; mostRecentSwingLowTime = bos_tL; } } // Update the global BOS variables with the most recent swings if(mostRecentSwingHighTime > 0) { if(mostRecentSwingHighTime != bos_tH) Bull_BOS_traded = false; swng_High = mostRecentSwingHigh; bos_tH = mostRecentSwingHighTime; } if(mostRecentSwingLowTime > 0) { if(mostRecentSwingLowTime != bos_tL) Bear_BOS_traded = false; swng_Low = mostRecentSwingLow; bos_tL = mostRecentSwingLowTime; } // Now check for break of structure Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Get current bar time to prevent multiple trades on same bar datetime currentBarTime = iTime(_Symbol, _Period, 0); // SELL on break above swing high if(swng_High > 0 && Ask > swng_High && Bull_BOS_traded == false) { // Check if we haven't already traded this breakout if(lastBOSTradeTime != currentBarTime || lastBOSTradeDirection != -1) { if(DrawBOSLines) DrawBOS("BOS_H_" + TimeToString(bos_tH), bos_tH, swng_High, TimeCurrent(), swng_High, BOSBear, -1); ExecuteTrade(ORDER_TYPE_BUY); // Update trade tracking lastBOSTradeTime = currentBarTime; lastBOSTradeDirection = -1; Bull_BOS_traded = true; // Reset the swing high to prevent immediate re-trading swng_High = -1.0; } } // BUY on break below swing low if(swng_Low > 0 && Bid < swng_Low && Bear_BOS_traded == false) { // Check if we haven't already traded this breakout if(lastBOSTradeTime != currentBarTime || lastBOSTradeDirection != 1) { if(DrawBOSLines) DrawBOS("BOS_L_" + TimeToString(bos_tL), bos_tL, swng_Low, TimeCurrent(), swng_Low, BOSBull, +1); ExecuteTrade(ORDER_TYPE_SELL); // Update trade tracking Bear_BOS_traded = true; lastBOSTradeTime = currentBarTime; lastBOSTradeDirection = 1; // Reset the swing low to prevent immediate re-trading swng_Low = -1.0; } } }Die BOS-Funktion erkennt und handelt BOS-Ereignisse (Break of Structure) mit Hilfe der einheitlichen Umkehr-Logik. Sie scannt die letzten 20 Balken, um den letzten hohen und den letzten tiefen Umkehrpunkt zu identifizieren, aktualisiert globale BOS-Variablen und stellt sicher, dass doppelte Handelsgeschäfte auf demselben Balken vermieden werden. Bricht der Kurs über den letzten hohen Umkehrpunkt, wird ein Kauf ausgeführt (Liquidität steigt über die Höchststände), bricht der Kurs unter den letzten tiefen Umkehrpunkt, wird verkauft. Optional können BOS-Linien zur Visualisierung eingezeichnet werden, und interne Flags verhindern ein sofortiges Re-Trading beim gleichen Ausbruch.
//---------------------------- BOS UI -------------------------------// void DrawBOS(const string name, datetime t1, double p1, datetime t2, double p2, color col, int dir) { if(ObjectFind(0, name) == -1) { ObjectCreate(0, name, OBJ_TREND, 0, t1, p1, t2, p2); ObjectSetInteger(0, name, OBJPROP_COLOR, col); ObjectSetInteger(0, name, OBJPROP_WIDTH, 2); string lbl = name + "_lbl"; ObjectCreate(0, lbl, OBJ_TEXT, 0, t2, p2); ObjectSetInteger(0, lbl, OBJPROP_COLOR, col); ObjectSetInteger(0, lbl, OBJPROP_FONTSIZE, 10); ObjectSetString(0, lbl, OBJPROP_TEXT, "Break"); ObjectSetInteger(0, lbl, OBJPROP_ANCHOR, (dir>0)?ANCHOR_RIGHT_UPPER:ANCHOR_RIGHT_LOWER); } }
Die Funktion DrawBOS ist für die visuelle Markierung eines Strukturbruchs (Break of Structure, BOS) in einem Chart verantwortlich, indem sie eine Trendlinie zwischen zwei Punkten (t1, p1) und (t2, p2) mit einer bestimmten Farbe und Breite erstellt. Wenn das Objekt mit dem angegebenen Namen noch nicht existiert, wird zunächst die Trendlinie erstellt, ihre Farbe und Dicke festgelegt und dann eine Textbeschriftung am Endpunkt mit der Angabe „Break“ hinzugefügt. Die Position der Kennzeichnung wird je nach Richtung verankert, sodass es bei einem Aufwärtstrend oben rechts und bei einem Abwärtstrend unten rechts platziert wird, sodass ein klarer visueller Hinweis auf Veränderungen der Marktstruktur direkt im Chart angezeigt wird.
void DrawFVG(const SFVG &z) { string name = z.Name(); datetime tNow = (datetime)SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE); // Delete existing object if it exists if(ObjectFind(0, name) != -1) ObjectDelete(0, name); // Create rectangle object for FVG if(!ObjectCreate(0, name, OBJ_RECTANGLE, 0, z.tLeft, z.bot, tNow, z.top)) { Print("Error creating FVG object: ", GetLastError()); return; } // Set object properties ObjectSetInteger(0, name, OBJPROP_COLOR, z.dir>0 ? BullFVG : BearFVG); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectSetInteger(0, name, OBJPROP_WIDTH, 1); ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID); // Set Z-order to make sure it's visible ObjectSetInteger(0, name, OBJPROP_ZORDER, 0); }
Die Funktion DrawFVG visualisiert ein Fair Value Gap (FVG) im Chart, indem sie zunächst prüft, ob ein Objekt mit dem Namen des FVG bereits existiert, und es dann löscht, um Duplikate zu vermeiden. Anschließend wird ein Rechteck erstellt, das sich vom linken Zeitpunkt tLeft der Lücke bis zum aktuellen Balken und vom unteren Ende bis zum oberen Ende der Lücke erstreckt. Das Rechteck wird mit einer auf der Richtung der Lücke basierenden Farbe gestaltet, gefüllt, an den hinteren Teil des Charts gesendet und mit einem festen Rahmen versehen. Wenn die Z-Reihenfolge auf 0 gesetzt wird, bleibt das FVG hinter anderen Chart-Elementen sichtbar und bietet Händlern eine klare visuelle Echtzeit-Referenz für Preisineffizienzen.
void OnTick() { if(!IsNewBar()) return; // Strategy switch if(TradeStrategy == STRAT_FVG || TradeStrategy == STRAT_AUTO) DetectAndDrawFVGs(); if(TradeStrategy == STRAT_OB || TradeStrategy == STRAT_AUTO) DetectAndDrawOrderBlocks(); if(TradeStrategy == STRAT_BOS || TradeStrategy == STRAT_AUTO) DetectAndDrawBOS(); }
Die Funktion OnTick wird bei jedem Markttick ausgeführt, aber nur, wenn ein neuer Balken gebildet wird, sodass die Berechnungen nur einmal pro Kerze durchgeführt werden. Anschließend wird die ausgewählte Handelsstrategie überprüft: Wenn Fair Value Gaps (FVG) oder der automatische Modus aktiv ist, wird DetectAndDrawFVGs aufgerufen; wenn Order Blocks (OB) oder der automatische Modus aktiv ist, wird DetectAndDrawOrder Blocks aufgerufen; und wenn Break of Structure (BOS) oder der automatische Modus aktiv ist, wird DetectAndDrawBOS aufgerufen. Diese Struktur ermöglicht es dem EA oder Indikator, verschiedene Marktstrukturen dynamisch zu erkennen und in Echtzeit auf der Grundlage der gewählten Strategie zu visualisieren.
Backtest-Ergebnisse
Die Backtests wurde für den 1H-Zeitrahmen über ein etwa zweimonatiges Testfenster (01. Juli 2025 bis 01. September 2025) ausgewertet, wobei die Standardeinstellungen mit der BOS-Strategie verwendet wurden.


Schlussfolgerung
Zusammenfassend haben wir ein einheitliches Smart Money Concepts (SMC)-Handelskonzept entwickelt, das drei wichtige Säulen integriert: Order Blocks (OBs), Break of Structure (BOS), und Fair Value Gaps (FVGs). Jedes Konzept wurde mit einer Erkennungs-, Zeichen- und Handelslogik kodiert. OBs wurden als institutionelle Fußabdrücke mit Fibonacci-Retracement-Validierung identifiziert, BOS erfassten Liquiditätsläufe, wenn der Preis hohe und tiefe Umkehrpunkte durchlief, und FVGs zeigten Ineffizienzen bei der Preislieferung auf, die oft als starke Reaktionszonen fungieren. Durch die Kombination dieser Elemente in einem einzigen System gewährleistet der Code die dynamische Erkennung von Setups mit hoher Wahrscheinlichkeit direkt auf dem Chart, komplett mit visuellen Hilfen und automatischer Ausführung.
Zusammenfassend lässt sich sagen, dass dieser einheitliche Ansatz den Händlern eine systematische Anwendung der SMC-Prinzipien ermöglicht, ohne das Rätselraten, das oft mit der manuellen Chartanalyse einhergeht. Der EA markiert und verfolgt nicht nur Marktstrukturverschiebungen, sondern führt auch Handelsgeschäfte in Echtzeit aus, wenn sich der Preis an vordefinierten SMC-Bedingungen orientiert. Dies bietet Händlern eine disziplinierte, regelbasierte Methode, die emotionale Voreingenommenheit reduziert, die Konsistenz erhöht und einen professionellen Vorteil bei der Nutzung von Chancen im institutionellen Stil unter verschiedenen Marktbedingungen bietet.
Übersetzt aus dem Englischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/en/articles/16340
Warnung: Alle Rechte sind von MetaQuotes Ltd. vorbehalten. Kopieren oder Vervielfältigen untersagt.
Dieser Artikel wurde von einem Nutzer der Website verfasst und gibt dessen persönliche Meinung wieder. MetaQuotes Ltd übernimmt keine Verantwortung für die Richtigkeit der dargestellten Informationen oder für Folgen, die sich aus der Anwendung der beschriebenen Lösungen, Strategien oder Empfehlungen ergeben.
Statistische Arbitrage durch kointegrierte Aktien (Teil 4): Modellaktualisierung in Echtzeit
Automatisieren von Handelsstrategien in MQL5 (Teil 28): Erstellen eines Price Action Bat Harmonic Patterns mit visuellem Feedback
Automatisieren von Handelsstrategien in MQL5 (Teil 29): Erstellung eines Preisaktionssystems mit dem harmonischen Muster von Gartley
MQL5-Assistenten-Techniken, die Sie kennen sollten (Teil 79): Verwendung von Gator-Oszillator und Akkumulations-/Distributions-Oszillator mit überwachtem Lernen
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Die Fair-Value-Lücke ist falsch beschrieben und dargestellt, bitte sehen Sie sich das richtige Bild in diesem Artikel an.
Wow, Ihr Artikel ist großartig. Ich weiß nur, dass es Indonesier in dem Artikel sind. Unser Konzept ist das gleiche, aber der Unterschied ist, dass ich Python für SMC+GPT verwende.
Sie irren sich, es ist das Gleiche, ich habe das FVG mit dem Preis / Candlesticks bereits innerhalb der FVG-Zone zurückgegangen dargestellt.
Sie liegen falsch oder haben Ihre Grafik schlecht vorbereitet. Da die 1. und 3. Kerze (von links) rot dargestellt sind, sind sie bärisch und bilden 2 große Lücken vor und nach der 2. Kerze (wo vermutlich das FVG stattfand).

Wenn Sie im Internet nach FVG suchen, werden Sie feststellen, dass es sich bei dieser Formation um einen großen unidirektionalen Kurssprung/eine große Lücke handelt und nicht um einen Zickzackkurs mit mehreren Sprüngen, der den gesamten Effekt für mögliche künftige Rücksetzer verdunkeln würde, weil man nicht weiß, welche (der drei Lücken) sich zuerst schließen wird (in Ihrem Bild ist es die letzte Lücke entlang der dritten Kerze, nicht die zweite - sie wird von der vierten Kerze geschlossen).