Fair Value Gap Retracement Strategy
Abstract This strategy identifies Fair Value Gaps (FVGs), three-candle patterns with price overlap absent between bars 1 and 3, after a minimum trending displacement, then enters on retracement into the gap zone. The mechanic relies on the hypothesis that gaps represent unfinished institutional business that attracts price on pullback; the entry-on-retracement methodology aims to lower risk compared to trend-chasing entries.
Why this might work
A Fair Value Gap is a mechanical pattern: three consecutive candles where the high of candle 1 and the low of candle 3 do not overlap (or vice versa for bearish patterns). This observation alone is not an edge; the price pattern must anchor to a market hypothesis to justify trading it.
The ICT framework asserts that FVGs represent order imbalances, clusters of institutional resting orders, that price seeks to complete on retracement [practitioner convention]. This is conceptually aligned with order-flow microstructure, which does recognize that imbalances can drive transient price movements [established in academic market microstructure but not specifically tested on FVG patterns]. Mean reversion into supply or demand zones is an established technical pattern with some support in academic pullback research [2], though most such work does not test the specific FVG construction.
The displacement requirement, a minimum directional move after the FVG forms, is a practitioner filter intended to confirm that the gap reflects genuine trend, not chop [practitioner convention]. A FVG formed in congestion may lack the "institutional conviction" claimed to drive retracement fills; displacement acts as a trend-quality gate. Whether any specific displacement threshold materially improves edge over random entries is not established here and requires empirical testing.
Retracement entry into a prior support zone is a lower-risk entry than chasing the trend itself. If the gap does attract price on pullback as hypothesized, entry near the zone preserves capital and improves risk-reward vs. breakout entries. If the hypothesis fails, the stop-loss is cleanly placed below the gap, limiting loss. This is mechanics, not promise: position sizing and stop discipline are what separate gambling from position management.
The rules
Instrument and timeframe: Any liquid tradable (equities, futures, forex). Testing should begin on 1H or 4H timeframes to generate sufficient trade samples (minimum 50 trades per test).
Fair Value Gap definition:: A 3-candle pattern where candle 1 and candle 3 do not overlap in price.
- Bullish FVG: candle 1 closes above open; candle 3 closes above open; high of candle 1 lies above low of candle 3 with no price overlap between them.
- Bearish FVG: candle 1 closes below open; candle 3 closes below open; low of candle 1 lies below high of candle 3 with no price overlap between them.
Displacement requirement:: After the 3-candle FVG pattern closes, require a minimum directional move of 0.5% of price (parameterizable) in the direction of the gap before proceeding.
- This filters out choppy or consolidating markets where FVGs may not reflect genuine institutional flow.
- Displacement is measured close-to-close from the open of candle 1 to the current close.
Entry trigger:: Once an FVG with confirmed displacement is identified, enter when price retraces into and closes within the gap zone (the price region between candle 1 and candle 3 extremes).
- Bullish FVG entry: buy on close within the gap zone (between the low of candle 3 and the high of candle 1).
- Bearish FVG entry: sell on close within the gap zone.
- Do not re-enter on a second touch of the same FVG in the same session.
Initial stop-loss:: Bullish: place stop 1 ATR (14-period) below the low of candle 3.
- Bearish: place stop 1 ATR above the high of candle 3.
- ATR-based stops account for market volatility; adjust the multiplier (0.5-2.0 ATR) based on backtest results per instrument.
Exit:: Target: 1.5x the risk (distance from entry to stop) measured in the direction of the trade, or the high of candle 1 (bullish) / low of candle 1 (bearish), whichever is closer.
- Hard stop on maximum hold time: close all positions after 50 bars in the trade regardless of P&L to avoid regime drift.
- Optional: trailing stop to the prior swing low (bullish) or swing high (bearish) once profit reaches 0.5x risk.
Position sizing:: Risk 1% of account equity per trade.
- Position size = (Account * 0.01) / (Entry price, Stop price).
- If account size changes, recalculate on each trade.
Session and time filters (optional):: For forex: trade London and New York sessions only; avoid Asia-Pacific sessions where volume and FVG follow-through may weaken.
- For equities: avoid last 30 minutes of regular trading hours to reduce end-of-day spike noise.
- Disable trading 15 minutes before major economic data releases (reduces gap-trigger false positives).
Expected trade frequency: On 1H timeframes, expect 2-4 FVG formations per day depending on volatility and consolidation. On 4H, expect 5-10 per week. High-frequency trading (every hour) requires sample sizes of at least 100-150 trades to distinguish luck from edge.
//@version=6
strategy("Fair Value Gap Retracement", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=1, commission_type=strategy.commission.percent, commission_value=0.1, slippage=2)
// Input parameters
fvgDispPercent = input.float(0.5, "Displacement Threshold (%)", minval=0.1, step=0.1)
atrLength = input.int(14, "ATR Period", minval=5)
stopAtrMult = input.float(1.0, "Stop Distance (ATR multiples)", minval=0.5, step=0.1)
targetRiskMult = input.float(1.5, "Target (Risk multiples)", minval=0.5, step=0.1)
riskPercentage = input.float(1.0, "Risk per Trade (%)", minval=0.1, maxval=5, step=0.1)
maxBarHold = input.int(50, "Max Bars in Trade", minval=5)
// ATR calculation
atr = ta.atr(atrLength)
// Detect 3-bar FVG pattern: no price overlap between candle 1 and candle 3
bullFVG = close[2] > open[2] and close[0] > open[0] and high[2] > low[0]
bearFVG = close[2] < open[2] and close[0] < open[0] and low[2] < high[0]
// Displacement confirmation: minimum trend move after FVG closes
dispThreshold = fvgDispPercent / 100
bullDisp = (close - close[2]) / close[2] > dispThreshold
bearDisp = (close[2] - close) / close[2] > dispThreshold
// State variables for FVG tracking
var bool fvgActive = false
var string fvgDir = na
var float fvgHigh = na
var float fvgLow = na
var int barCounter = 0
// Detect FVG + displacement; set active state
if bullFVG and bullDisp and not fvgActive
fvgDir := "bull"
fvgHigh := high[2]
fvgLow := low[0]
fvgActive := true
if bearFVG and bearDisp and not fvgActive
fvgDir := "bear"
fvgHigh := high[0]
fvgLow := low[2]
fvgActive := true
// Entry: price retraces into FVG zone
if fvgActive and fvgDir == "bull" and strategy.position_size == 0
if close >= fvgLow and close <= fvgHigh
stop = fvgLow - atr * stopAtrMult
target = fvgHigh + ((fvgHigh - stop) * targetRiskMult)
risk = fvgHigh - stop
qty = (strategy.equity * riskPercentage / 100) / risk
strategy.entry("Long", strategy.long, qty=qty)
strategy.exit("LongClose", "Long", stop=stop, limit=target)
fvgActive := false
fvgDir := na
if fvgActive and fvgDir == "bear" and strategy.position_size == 0
if close >= fvgLow and close <= fvgHigh
stop = fvgHigh + atr * stopAtrMult
target = fvgLow - (((stop - fvgLow)) * targetRiskMult)
risk = stop - fvgLow
qty = (strategy.equity * riskPercentage / 100) / risk
strategy.entry("Short", strategy.short, qty=qty)
strategy.exit("ShortClose", "Short", stop=stop, limit=target)
fvgActive := false
fvgDir := na
// Bar counter and timeout
barCounter := strategy.position_size != 0 ? barCounter + 1 : 0
if barCounter > maxBarHold and strategy.position_size != 0
strategy.close_all()
fvgActive := false
// Plot FVG zones
if fvgActive
if fvgDir == "bull"
box.new(bar_index - 2, fvgLow, bar_index, fvgHigh, bgcolor=color.new(color.green, 80), border_color=color.green, closed=true)
else
box.new(bar_index - 2, fvgLow, bar_index, fvgHigh, bgcolor=color.new(color.red, 80), border_color=color.red, closed=true)
How the code works
The strategy operates in two phases: pattern detection and entry execution.
Detection: Each bar, the code checks whether the past three candles form a FVG (lines checking bullFVG and bearFVG). For a bullish pattern, this requires candles 2 and 0 (counting backward) to close above their opens and to have no price overlap. It then checks displacement: has price moved at least 0.5% (default) higher since candle 2 opened (bullDisp)? If both conditions are true and no trade is active, the FVG zone is stored (high of candle 2 and low of candle 0 for bullish) and flagged as active.
Entry: On the next bar (or immediately if retracement is swift), the code checks if close enters the FVG zone. If it does, it calculates the stop loss (1 ATR below the gap for bullish trades), the target (high of candle 1 plus 1.5x risk), and the position size based on 1% account risk. The strategy.entry() function initiates the trade and strategy.exit() places the orders. The flag is then cleared, preventing re-entry on the same FVG.
Duration control: A barCounter increments each bar the trade is open. If it exceeds 50 bars, the trade is force-closed to avoid overnight or regime-drift slippage (line if barCounter > maxBarHold).
Visualization: When a FVG is active (waiting for retracement entry), a translucent box is plotted on the chart showing the gap zone. This is for manual validation only and does not affect trade logic.
Testing it honestly
Before drawing any conclusions, a trader should:
-
In-sample / out-of-sample split: Run the strategy on 60% of historical data (e.g., 18 months), note the best parameters, then retest on the remaining 40% (6 months). If the out-of-sample results are materially worse (e.g., >30% lower win rate or profit factor), the parameters are likely curve-fit and overfitted.
-
Realistic costs: Set commission at your broker's actual rate (typically 0.05-0.2% for equities, $3-5 per contract for futures). Set slippage at 2-5 pips or ticks. The strategy's stated commission (0.1%) and slippage (2 pips) are conservative; adjust down only if your broker is exceptionally cheap and your execution is exceptionally fast.
-
Minimum sample size: Require at least 50 trades per test. Fewer than 20 trades can occur by luck; fewer than 50 is statistically weak.
-
Regime testing: Test across different market regimes: trending (2020-2021 for equities), consolidating (2015-2016), and high-volatility periods (2020, 2022). A strategy that works only in trends will lose money in chop.
-
Walk-forward analysis: Use rolling windows (e.g., optimize on rolling 6-month blocks, test on the next 3 months) to see if the strategy maintains edge over time or degrades.
A few backtests showing profit does not constitute proof of edge. Thousands of traders run momentum and pullback strategies; most lose money because they underestimate costs, overestimate their own discipline, and overfit to backward-looking data. Treat backtest results as necessary but insufficient.
Limitations
-
Practitioner framework, not academic: FVG trading is part of the ICT educational canon and has no peer-reviewed empirical validation. The claimed link between FVGs and institutional order clustering is plausible but unproven. A trader funding this strategy with real capital is making an implicit bet on a practitioner hypothesis, not on established market mechanism.
-
Regime dependence: FVG retracement patterns likely perform better in trending markets with clear support/resistance levels. In choppy, range-bound markets, FVGs form frequently but price often fails to respect the zone. Likewise, in extremely strong trends, price may skip the gap entirely. No backtest here; this is expected fragility.
-
Displacement threshold is arbitrary: The 0.5% threshold is a guess. Changing it to 0.3% or 0.7% will alter entry frequency, win rate, and drawdown. Optimization on one market or timeframe may not transfer to another.
-
Stop placement underestimates vol: Using 1 ATR as a stop assumes historical volatility is a good predictor of forward volatility, which is often false. In high-volatility regimes, 1 ATR stops may be hit too frequently, causing whipsaws. In low-volatility regimes, the stop may be unnecessarily tight.
-
Target calculation is symmetric: The target is 1.5x risk, a fixed ratio. In reality, the distance to true resistance (candle 1 high) may be shorter or longer than risk warrants. Using fixed ratios sacrifices realism for objectivity and may leave money on the table or exit premature.
-
Costs are heavy: At 0.1% commission + 2 pips slippage, a short-term strategy (average 10-20 bar hold) loses 0.3-0.5% to friction per round trip. This requires a win rate above 55-60% with average win exceeding average loss just to break even. Most retail backtest results flatter to deceive.
-
Overfitting risk: Testing only one instrument or timeframe and optimizing parameters to that data will produce a strategy that fails out-of-sample. The code has many inputs (displacement threshold, ATR period, stop multiple, target multiple, risk %). A trader optimizing all of them on a 2-year history is likely fitting noise.
-
No retracement guarantee: The core assumption, that price will retrace into the gap, is not universal. In strong trends, price may skip the gap and continue higher. In reversals, the gap may be filled on the next candle, offering no entry opportunity. The strategy will sit idle or miss entries when the assumption breaks.
-
Sample size in backtest: This paper contains no backtest results by design. A trader who implements this strategy will need to run 100+ trades before assessing true performance. Most traders give up after 20-30 trades when results are negative, robbing themselves of statistical clarity.
Key definitions
Fair Value Gap: A 3-candle pattern in which the high of candle 1 and the low of candle 3 (or vice versa) do not overlap, creating a price region never filled during the pattern formation.
Displacement: The minimum directional price move required after a FVG forms, expressed as a percentage of price or a fixed ATR multiple, to confirm that the gap reflects genuine trend rather than market noise.
Retracement: A pullback or reversal in price from an extreme, returning partway or fully to a prior price level, often into a support or resistance zone.
Order imbalance: A temporary surplus of buy or sell orders at a given price level, creating transient price pressure and potentially attracting countervailing flow on retracement.
ATR (Average True Range): A volatility measure equal to the 14-period average of the true range (the greatest of: high, low, high, prior close, or low, prior close).
Risk-to-reward ratio: The ratio of the distance from entry to stop-loss (risk) to the distance from entry to profit target (reward); a 1:1.5 ratio means the profit target is 1.5 times the risk distance away.
Figures
References
[1] CME Group, "Equity Index Futures Specifications," CME Group Education. Https://www.cmegroup.com/markets/equities.html
[2] Blume, M.E., Easley, D., & O'Hara, M., "Market Statistics and Technical Analysis: The Role of Volume," The Journal of Finance, vol. 49, no. 1 (1994), pp. 153-181. Https://doi.org/10.1111/j.1540-6261.1994.tb04425.x
[3] Investopedia, "Support and Resistance," Investopedia. Https://www.investopedia.com/terms/s/support.asp
[4] Bender, J., Sun, X., Thomas, R., & Zdorovtsov, V., "The Promises and Pitfalls of Factor Timing," Research Affiliates Publications (2018). Https://www.ssrn.com/abstract=3154467
[5] Wikipedia, "Technical Analysis," Wikipedia. Https://en.wikipedia.org/wiki/Technical_analysis
[6] TradingView, "Pine Script v6 Documentation," TradingView. Https://www.tradingview.com/pine-script-docs/
Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.
Last reviewed by the PropLedger research pipeline: 2026-09-20. Educational research on historical data, not financial advice.
Keep reading
Time-of-Day Drift: A Null Benchmark
A complete, testable trading strategy: a time-of-day drift strategy as a null benchmark: what a strategy with no price structure earns, and why every other idea must beat it. Exact rules, full Pine Script code, and an honest reading of the evidence.
RSI Divergence Mechanical Strategy with Null Testing
A complete, testable trading strategy: an RSI divergence strategy subjected to an honest test: defining divergence mechanically, then measuring it against a matched null. Exact rules, full Pine Script code, and an honest reading of the evidence.
Favorite-Longshot Bias in Prediction Markets
A complete, testable trading strategy: a favorite-longshot strategy on prediction markets: the documented pricing bias at the probability extremes, fees, and rules for harvesting it within venue limits. Exact rules, full Pine Script code, and an honest reading of the evidence.