The Anatomy of a 3-Candle Fair Value Gap (FVG)
In Smart Money Concepts (SMC), a Fair Value Gap represents an acute price imbalance caused by large institutional market orders exhausting resting limit orders. The imbalance is mathematically defined across a 3-candle sequence:
- Bullish FVG: Candle 1 High is strictly less than Candle 3 Low (Gap = Low_3 - High_1 > 0).
- Bearish FVG: Candle 1 Low is strictly greater than Candle 3 High (Gap = Low_1 - High_3 > 0).
When the intervening Candle 2 possesses significant displacement (long candle body with minimal wicks), market makers are obligated to re-auction price into this imbalance to deliver equilibrium before continuation.
Production Python Script: Multi-Pair FVG Scanner
import MetaTrader5 as mt5
import pandas as pd
from datetime import datetime
def scan_fvgs(symbol: str, timeframe=mt5.TIMEFRAME_H1, num_candles: int = 100):
rates = mt5.copy_rates_from_pos(symbol, timeframe, 0, num_candles)
if rates is None or len(rates) < 3:
return []
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
unmitigated_fvgs = []
for i in range(1, len(df) - 1):
c1 = df.iloc[i - 1]
c2 = df.iloc[i]
c3 = df.iloc[i + 1]
# Bullish FVG check
if c3['low'] > c1['high']:
gap_size = (c3['low'] - c1['high']) / mt5.symbol_info(symbol).point
# Check subsequent mitigation
subsequent_lows = df.iloc[i + 2:]['low'] if i + 2 < len(df) else []
mitigated = any(low <= c1['high'] for low in subsequent_lows)
if not mitigated and gap_size >= 10.0:
unmitigated_fvgs.append({
'type': 'BULLISH',
'symbol': symbol,
'top': c3['low'],
'bottom': c1['high'],
'gap_points': gap_size,
'created_at': c2['time']
})
# Bearish FVG check
elif c1['low'] > c3['high']:
gap_size = (c1['low'] - c3['high']) / mt5.symbol_info(symbol).point
subsequent_highs = df.iloc[i + 2:]['high'] if i + 2 < len(df) else []
mitigated = any(high >= c1['low'] for high in subsequent_highs)
if not mitigated and gap_size >= 10.0:
unmitigated_fvgs.append({
'type': 'BEARISH',
'symbol': symbol,
'top': c1['low'],
'bottom': c3['high'],
'gap_points': gap_size,
'created_at': c2['time']
})
return unmitigated_fvgs
if __name__ == "__main__":
mt5.initialize()
watchlist = ["EURUSD", "GBPUSD", "USDJPY", "XAUUSD", "US30"]
for sym in watchlist:
gaps = scan_fvgs(sym)
print(f"[{sym}] Active Unmitigated FVGs: {len(gaps)}")
for g in gaps[-3:]:
print(f" -> {g['type']} Gap: {g['bottom']:.5f} to {g['top']:.5f} ({g['gap_points']:.1f} pts)")
mt5.shutdown()
High-Probability FVG Execution Confluence Checklist
- Time-of-Day Filter: The imbalance must originate within London Killzone (07:00–10:00 GMT) or New York Open (13:00–16:00 GMT).
- Higher-Timeframe Alignment: Only enter Bullish FVGs when Daily and H4 Market Structure reflects bullish Change of Character (CHoCH).
- Discount / Premium Arrays: Long entries into Bullish FVGs must reside below the 50% dealing range equilibrium of the current swing leg.