Eine inverse Fair-Value-Lücke (IFVG) tritt auf, wenn der Preis zu einer zuvor identifizierten Fair-Value-Lücke zurückkehrt und diese nicht beachtet, anstatt die erwartete unterstützende oder widerstandsfähige Reaktion zu zeigen. Dieses Versagen kann auf eine mögliche Änderung der Marktrichtung hinweisen und einen konträren Handelsvorteil bieten. In diesem Artikel werde ich meinen selbst entwickelten Ansatz zur Quantifizierung und Nutzung der inversen Fair-Value-Lücke als Strategie für MetaTrader 5-Expertenberater vorstellen.
Strategiemotivation
Zuerst Fair-Value-Lücken (FVGs) verstehen
Um die Intuition hinter einer „inversen Fair-Value-Lücke“ vollständig zu verstehen, ist es hilfreich, zunächst zu erklären, was eine Standard-Fair-Value-Lücke (FVG) darstellt. Eine Fair-Value-Lücke wird normalerweise innerhalb eines Preismusters mit drei Kerzen definiert.

Ein FVG tritt auf, wenn der Körper von Kerze B (und oft auch die Dochte) den Marktpreis abrupt nach oben oder unten treibt, sodass eine „Lücke“ zurückbleibt. Genauer gesagt: Wenn der Tiefstwert von Kerze C bei einer starken Aufwärtsbewegung höher ist als der Höchstwert von Kerze A, wird der Abstand zwischen diesen beiden Preispunkten als Fair-Value-Lücke betrachtet. Diese Lücke spiegelt eine Zone der Ineffizienz oder des Ungleichgewichts auf dem Markt wider – einen Bereich, in dem Trades keine angemessene beidseitige Beteiligung erhielten, weil sich der Preis zu schnell in eine Richtung bewegte. Händler gehen oft davon aus, dass der institutionelle Auftragsfluss diese Verschiebung verursacht hat und „Fußabdrücke“ der Aktivität des großen Geldes hinterlassen hat.
Die gängige Logik ist, dass der Preis irgendwann oft zu diesen Lücken zurückkehrt, um sie zu „füllen“. Das Füllen der Lücke kann als die Art und Weise des Marktes angesehen werden, den zuvor einseitigen Auftragsfluss auszugleichen. Händler, die diesem Prinzip folgen, warten oft darauf, dass der Preis diese Lücke erneut erreicht, und suchen nach einer Reaktion, die eine Fortsetzung in die ursprüngliche Richtung oder manchmal eine Umkehr bestätigt.
Was ist eine inverse Fair-Value-Lücke?
Das Konzept einer „inversen Fair-Value-Lücke“ baut auf dieser Idee auf, nähert sich ihr jedoch aus einer konträren oder umgekehrten Perspektive. Anstatt die Fair-Value-Lücke als Zone zur Bestätigung einer Fortsetzung in die ursprüngliche Richtung zu verwenden, könnte eine inverse FVG-Strategie genau diese Lücke verwenden, um vorherzusehen, wo der Markt möglicherweise nicht weitermachen und möglicherweise umkehren könnte.
Um beispielsweise eine bärische inverse Fair-Value-Lücke zu erkennen, können Sie diese Schritte befolgen:
- Identifizieren Sie eine bullische FVG.
- Der Preis kehrt in die FVG-Zone zurück.
- Beobachten Sie, wie sich der Preis verhält, anstatt sie als Unterstützung zu betrachten. Wenn es nicht gelingt, nach oben zu starten, und stattdessen durch die Lücke gehandelt wird, als ob sie keine sinnvolle Unterstützung bietet, könnte dieses Versagen eine Momentumverschiebung signalisieren.
- Gehen Sie short und gehen Sie davon aus, dass die Unfähigkeit, die FVG als Sprungbrett für höhere Preise zu verwenden, bedeutet, dass der Markt jetzt nach unten tendieren könnte.
Die Intuition hinter inversen Fair-Value-Gaps
Institutionelle Fußabdrücke und Ausfallpunkte: Die zugrunde liegende Annahme hinter Fair-Value-Gaps ist, dass große, erfahrene Akteure das anfängliche Ungleichgewicht verursacht haben.
Wenn der Preis in diese Zonen zurückkehrt, ist dies oft ein Test:
Wenn die großen Akteure bei diesen Preisen immer noch Wert sehen, können ihre verbleibenden Aufträge den Preis stützen oder ihm widerstehen und eine Reaktion auslösen. Wenn der Preis stattdessen direkt durch die FVG schneidet, ohne eine starke Erholung oder Fortsetzung, deutet dies darauf hin, dass diese großen Aufträge möglicherweise ausgeführt oder storniert wurden oder diese Zone nicht mehr verteidigen. Dies kann auf eine Änderung der Marktabsicht hinweisen.
Frühzeitiges Erkennen von Schwäche oder Stärke: Indem sie sich darauf konzentrieren, was nicht passiert, wenn der Preis in die Lücke zurückkehrt, können Händler subtile Hinweise auf die zugrunde liegende Stärke oder Schwäche erhalten. Wenn ein bullischer Markt keinen Auftrieb aus einer bekannten Ineffizienzzone (der bullischen FVG) erhält, kann dies eine frühzeitige Warnung sein, dass die bullische Erzählung an Schwung verlieren könnte.
Ergänzt traditionelle FVG-Strategien: Traditionelle FVG-Strategien basieren auf der Annahme einer Neugewichtung, gefolgt von einer Fortsetzung in die ursprüngliche Richtung. Märkte sind jedoch dynamisch und nicht jede Lückenfüllung führt zu einer Wiederaufnahme des vorherigen Trends. Der inverse FVG-Ansatz kann einem Händler einen zusätzlichen „Vorteil“ verschaffen, indem er Situationen identifiziert, in denen das normale Spielbuch versagt und daher ein konträrer Schritt eine höhere Wahrscheinlichkeit und ein besseres Risiko/Ertrags-Verhältnis haben kann.
Das Konzept der inversen Fair-Value-Gaps basiert auf der Erkenntnis, dass Märkte Bereiche früherer Ungleichgewichte ständig testen und erneut testen. Während sich der traditionelle FVG-Handel auf eine erfolgreiche Neugewichtung und Fortsetzung konzentriert, gewinnt der inverse Ansatz einen Vorteil, indem er erkennt, wann dieser Neugewichtungsprozess nicht das erwartete Ergebnis bringt. Dieser Perspektivwechsel verwandelt eine möglicherweise verpasste Gelegenheit – oder sogar ein Verlustgeschäft – in ein konträres Setup mit einem potenziell hohen Vorteil. In einem Marktumfeld, in dem die Erwartung des Unerwarteten oft belohnt wird, fügt das inverse FVG-Konzept dem Arsenal an technischen Analysetechniken eines Händlers ein zusätzliches Werkzeug hinzu.
Strategieentwicklung
Ähnlich wie diskretionäre Händler Fair-Value-Gaps nutzen, werden auch inverse Fair-Value-Gaps aktiv gehandelt, da zur Identifizierung gültiger Muster anspruchsvolle Kriterien erforderlich sind. Der Handel mit jedem einzelnen inversen Fair-Value-Gap ohne Unterscheidung würde wahrscheinlich zu einer Random-Walk-Performance führen, da die meisten Gaps nicht mit der strategischen Intuition übereinstimmen, die ich zuvor besprochen habe. Um die von diskretionären Händlern in Betracht gezogenen Feature-Setups zu quantifizieren, habe ich umfangreiche Feature-Tests durchgeführt und die folgenden Regeln festgelegt:
Ausrichtung auf den Makrotrend: Der Preis sollte dem übergreifenden Makrotrend folgen, der durch seine Position relativ zum gleitenden Durchschnitt von 400 Perioden bestimmt wird.
Angemessene Auswahl des Zeitrahmens: Es sollte ein kurzer Zeitrahmen, z. B. 1 bis 5 Minuten, verwendet werden, da das Konzept der „Ausführung von Aufträgen“ innerhalb einer kurzen Dauer erfolgt. Für die Zwecke dieses Artikels wird ein 3-Minuten-Zeitrahmen verwendet.
Fokus auf den aktuellsten Fair-Value-Gap: Nur der aktuellste Fair-Value-Gap (FVG) wird berücksichtigt, da er die höchste Bedeutung für die Widerspiegelung der aktuellen Marktbedingungen hat.
Validierung der Fair Value Gap Size: Die FVG darf im Vergleich zu den umgebenden Kerzen weder zu groß noch zu klein sein. Eine zu kleine Lücke hat nicht die Bedeutung, um als zuverlässiges Unterstützungs- oder Widerstandsniveau zu fungieren, während eine zu große Lücke wahrscheinlich durch ein Nachrichtenereignis verursacht wird, das das Umkehrsignal verzögern kann. Um sicherzustellen, dass die FVG aussagekräftig ist, werden bestimmte Schwellenwerte festgelegt, um jede Lücke zu validieren.
Kontrollierte Größe der Ausbruchskerze: Ebenso sollte die Ausbruchskerze nicht übermäßig groß sein, da Einträge auf Kerzenschlüssen basieren. Große Ausbruchskerzen können zu späten Signalen führen, was die Strategie vermeiden soll.
Rechtzeitige Preisumkehr und Ausbruch: Innerhalb einer bestimmten Zeit nach der Bildung einer FVG muss der Preis zur Lücke zurückkehren und mit einer geschlossenen Kerze von der gegenüberliegenden Kante ausbrechen. Dies wird erreicht, indem nur die jüngste FVG innerhalb eines kurzen Rückblickzeitraums untersucht wird.
Bestätigung der Ausbruchsstärke: Die FVG sollte mit einem vorherigen Ablehnungsniveau übereinstimmen, um sicherzustellen, dass ein Ausbruch der FVG eine erhöhte Stärke in die entsprechende Richtung signalisiert.
Ich ermutige die Leser, auf diesem Strategierahmen aufzubauen und ihn mit ihrer Kreativität zu verbessern.
Hier sind einige meiner Vorschläge:
Die Stärke des IFVG wird durch die Anzahl der Ablehnungskerzen um den FVG-Bereich herum bestimmt. Sie können die Differenz dieser Zahlen als Regel zur Bewertung verwenden.
In diesem Artikel haben wir uns nur auf die maximalen Ausbruchspunkte konzentriert. Manchmal kann die Ausbruchskerze jedoch zu klein sein, was auf eine schwache Ausbruchsstärke hinweist, die sich negativ auf die Trendfortsetzung auswirken könnte. Sie können auch erwägen, einen Schwellenwert für die minimalen Ausbruchspunkte hinzuzufügen.
Die Ausstiegsregel wird durch Take-Profit und Stop-Loss definiert. Alternativ können Sie das Ausstiegsniveau basierend auf relevanten Schlüsselniveaus für beide Richtungen über einen bestimmten Rückblickzeitraum festlegen oder eine feste Ausstiegszeit festlegen.
Fazit
In diesem Artikel habe ich meinen selbst entwickelten Ansatz zur Quantifizierung und Nutzung inverser Fair-Value-Gaps als Strategie für MetaTrader 5-Expert Advisors vorgestellt und Strategiemotivation, -entwicklung und -tests behandelt. Diese Strategie weist ein hohes Rentabilitätspotenzial auf und hat in den letzten fünf Jahren mit mehr als 400 Trades konstant gute Ergebnisse erzielt. Weitere Modifikationen sind möglich, um diese Strategie an verschiedene Wertpapiere und Zeitrahmen anzupassen. Der vollständige Code ist unten angehängt und Sie können ihn gerne in Ihre eigenen Handelsentwicklungen integrieren.
Download MetaTrader5 Code
Der Code
// FAIR VALUE CAP
//NQ-3
string previousGapObjName = "";
double previousGapHigh = 0.0;
double previousGapLow = 0.0;
int LastGapIndex = 0;
double gapHigh = 0.0;
double gapLow = 0.0;
double gap = 0.0;
double lott= 0.1;
ulong buypos = 0, sellpos = 0;
double anyGap = 0.0;
double anyGapHigh = 0.0;
double anyGapLow = 0.0;
int barsTotal = 0;
int newFVGformed = 0;
int currentFVGstatus = 0;
int handleMa;
#include <Trade/Trade.mqh>
CTrade trade;
input int gapMaxPoint = 1100;
input int gapMinPoint = 500;
input int startHour = 14;
input int endHour = 19;
input int maxBreakoutPoints =400;
input int MaPeriods = 400;
input int lookBack = 16;
input int tpp = 2500;
input int slp = 1700;
input int Magic = 0;
//+------------------------------------------------------------------+
//| Initializer function |
//+------------------------------------------------------------------+
int OnInit()
{
trade.SetExpertMagicNumber(Magic);
handleMa =iMA(_Symbol,PERIOD_CURRENT,MaPeriods,0,MODE_SMA,PRICE_CLOSE);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Destructor function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| OnTick function |
//+------------------------------------------------------------------+
void OnTick()
{
int bars = iBars(_Symbol,PERIOD_CURRENT);
if (barsTotal!= bars){
barsTotal = bars;
double ma[];
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
CopyBuffer(handleMa,BASE_LINE,1,1,ma);
if (IsBrokenLow()&&sellpos == buypos&&newFVGformed ==1&&bid<ma[0]){
executeSell();
newFVGformed =0;
}
else if (IsBrokenUp()&&sellpos == buypos&&newFVGformed ==1&&ask>ma[0]){
executeBuy();
newFVGformed =0;
}
getFVG();
if(buypos>0&&(!PositionSelectByTicket(buypos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
buypos = 0;
}
if(sellpos>0&&(!PositionSelectByTicket(sellpos)|| PositionGetInteger(POSITION_MAGIC) != Magic)){
sellpos = 0;
}
}
}
//+------------------------------------------------------------------+
//| To get the most recent Fair Value Gap (FVG) |
//+------------------------------------------------------------------+
void getFVG()
{
// Loop through the bars to find the most recent FVG
for (int i = 1; i < 3; i++)
{
datetime currentTime = iTime(_Symbol,PERIOD_CURRENT, i);
datetime previousTime = iTime(_Symbol,PERIOD_CURRENT, i + 2);
// Get the high and low of the current and previous bars
double currentLow = iLow(_Symbol,PERIOD_CURRENT, i);
double previousHigh = iHigh(_Symbol,PERIOD_CURRENT, i+2);
double currentHigh = iHigh(_Symbol,PERIOD_CURRENT, i);
double previousLow = iLow(_Symbol,PERIOD_CURRENT, i+2);
anyGap = MathAbs(previousLow - currentHigh);
// Check for an upward gap
if (currentLow > previousHigh)
{
anyGapHigh = currentLow;
anyGapLow = previousHigh;
//Check for singular
if (LastGapIndex != i){
if (IsGapValid()){
gapHigh = currentLow;
gapLow = previousHigh;
gap = anyGap;
currentFVGstatus = 1;//bullish FVG
DrawGap(previousTime,currentTime,gapHigh,gapLow);
LastGapIndex = i;
newFVGformed =1;
return;
}
}
}
// Check for a downward gap
else if (currentHigh < previousLow)
{
anyGapHigh = previousLow;
anyGapLow = currentHigh;
if (LastGapIndex != i){
if(IsGapValid()){
gapHigh = previousLow;
gapLow = currentHigh;
gap = anyGap;
currentFVGstatus = -1;
DrawGap(previousTime,currentTime,gapHigh,gapLow);
LastGapIndex = i;
newFVGformed =1;
return;
}
}
}
}
}
//+------------------------------------------------------------------+
//| Function to draw the FVG gap on the chart |
//+------------------------------------------------------------------+
void DrawGap(datetime timeStart, datetime timeEnd, double gaphigh, double gaplow)
{
// Delete the previous gap object if it exists
if (previousGapObjName != "")
{
ObjectDelete(0, previousGapObjName);
}
// Generate a new name for the gap object
previousGapObjName = "FVG_" + IntegerToString(TimeCurrent());
// Create a rectangle object to highlight the gap
ObjectCreate(0, previousGapObjName, OBJ_RECTANGLE, 0, timeStart, gaphigh, timeEnd, gaplow);
// Set the properties of the rectangle
ObjectSetInteger(0, previousGapObjName, OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, previousGapObjName, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, previousGapObjName, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, previousGapObjName, OBJPROP_RAY, false);
// Update the previous gap information
previousGapHigh = gaphigh;
previousGapLow = gaplow;
}
//+------------------------------------------------------------------+
//| Function to validate the FVG gap |
//+------------------------------------------------------------------+
bool IsGapValid(){
if (anyGap<=gapMaxPoint*_Point && anyGap>=gapMinPoint*_Point&&IsReacted()) return true;
else return false;
}
//+------------------------------------------------------------------+
//| Check for gap reaction to validate its strength |
//+------------------------------------------------------------------+
bool IsReacted(){
int count1 = 0;
int count2 = 0;
for (int i = 4; i < lookBack; i++){
double aLow = iLow(_Symbol,PERIOD_CURRENT,i);
double aHigh = iHigh(_Symbol,PERIOD_CURRENT,i);
if (aHigh<anyGapHigh&&aHigh>anyGapLow&&aLow<anyGapLow){
count1++;
}
else if (aLow<anyGapHigh&&aLow>anyGapLow&&aHigh>anyGapHigh){
count2++;
}
}
if (count1>=2||count2>=2) return true;
else return false;
}
//+------------------------------------------------------------------+
//| Check if price broke out to the upside of the gap |
//+------------------------------------------------------------------+
bool IsBrokenUp(){
int lastClosedIndex = 1;
double lastOpen = iOpen(_Symbol, PERIOD_CURRENT, lastClosedIndex);
double lastClose = iClose(_Symbol, PERIOD_CURRENT, lastClosedIndex);
if (lastOpen < gapHigh && lastClose > gapHigh&&(lastClose-gapHigh)<maxBreakoutPoints*_Point)
{
if(currentFVGstatus==-1){
return true;}
}
return false;
}
//+------------------------------------------------------------------+
//| Check if price broke out to the downside of the gap |
//+------------------------------------------------------------------+
bool IsBrokenLow(){
int lastClosedIndex = 1;
double lastOpen = iOpen(_Symbol, PERIOD_CURRENT, lastClosedIndex);
double lastClose = iClose(_Symbol, PERIOD_CURRENT, lastClosedIndex);
if (lastOpen > gapLow && lastClose < gapLow&&(gapLow -lastClose)<maxBreakoutPoints*_Point)
{
if(currentFVGstatus==1){
return true;}
}
return false;
}
//+------------------------------------------------------------------+
//| Store order ticket number into buypos/sellpos variables |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) {
if (trans.type == TRADE_TRANSACTION_ORDER_ADD) {
COrderInfo order;
if (order.Select(trans.order)) {
if (order.Magic() == Magic) {
if (order.OrderType() == ORDER_TYPE_BUY) {
buypos = order.Ticket();
} else if (order.OrderType() == ORDER_TYPE_SELL) {
sellpos = order.Ticket();
}
}
}
}
}
//+------------------------------------------------------------------+
//| Execute sell trade function |
//+------------------------------------------------------------------+
void executeSell() {
if (IsWithinTradingHours()){
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
bid = NormalizeDouble(bid,_Digits);
double tp = bid - tpp * _Point;
tp = NormalizeDouble(tp, _Digits);
double sl = bid + slp * _Point;
sl = NormalizeDouble(sl, _Digits);
trade.Sell(lott,_Symbol,bid,sl,tp);
sellpos = trade.ResultOrder();
}
}
//+------------------------------------------------------------------+
//| Execute buy trade function |
//+------------------------------------------------------------------+
void executeBuy() {
if (IsWithinTradingHours()){
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
ask = NormalizeDouble(ask,_Digits);
double tp = ask + tpp * _Point;
tp = NormalizeDouble(tp, _Digits);
double sl = ask - slp * _Point;
sl = NormalizeDouble(sl, _Digits);
trade.Buy(lott,_Symbol,ask,sl,tp);
buypos= trade.ResultOrder();
}
}
//+------------------------------------------------------------------+
//| Check if is trading hours |
//+------------------------------------------------------------------+
bool IsWithinTradingHours()
{
datetime currentTime = TimeTradeServer();
MqlDateTime timeStruct;
TimeToStruct(currentTime, timeStruct);
int currentHour = timeStruct.hour;
if (currentHour >= startHour && currentHour < endHour)
return true;
else
return false;
}
