GUIDE · TESTING A STRATEGY

Does the fair value gap strategy work?

Not on its own, in our test. We ran the textbook fair value gap retest on ten heavily traded US stocks and ETFs, on 5-minute bars from 28 July 2026 to 20 October 2026: 1,885 trades, 37.2% of them winners with the target at twice the risk, and an average trade of −0.01% before any costs. At 0.025% a side, every one of the ten lost money.

What a fair value gap is

A fair value gap is a three-candle pattern in which the middle candle moves so far that the first and third candles' ranges do not overlap. In a bullish one the third candle's low is above the first candle's high; in a bearish one the third candle's high is below the first candle's low. The space between them is the gap, and the usual trade waits for price to come back into it and enters in the direction of the move that made it.

It is not a price gap, where one candle opens beyond the last and nothing trades in between. Inside a fair value gap the middle candle did trade; it just moved fast. How to read one on a chart, with a script that shades them and marks the first retest, is in the fair value gap concept.

The rules we tested

  1. The gap
    Three candles of one session. Bullish when the third candle's low is above the first candle's high; bearish when the third candle's high is below the first candle's low.
  2. The entry
    A limit order at the gap's near edge, the third candle's low for a long or its high for a short, placed when the third candle closes. It waits 12 bars, an hour, for price to come back.
  3. The stop
    Beyond the first candle: its low for a long, its high for a short.
  4. The target
    Twice the distance from the entry to the stop.
  5. The clock
    No new gaps in the last hour, everything closed at the open of the session's last bar, one trade at a time.

Each trade used the whole account, and the fills follow TradingView's rules: a limit fills at its price, or at the open if the open is already past it, and inside a candle price is taken to reach the nearer extreme first. Here is the script, ready for TradingView's Pine Editor:

Fair value gap retest, Pine v6
//@version=6
strategy("Fair value gap retest", overlay=true, initial_capital=100000,
     default_qty_type=strategy.percent_of_equity, default_qty_value=100,
     margin_long=0, margin_short=0,
     commission_type=strategy.commission.percent, commission_value=0.025, slippage=1)

fromDate  = input.time(timestamp("2026-07-28"), "Test from")
toDate    = input.time(timestamp("2026-10-21"), "Test to")
rr        = input.float(2.0, "Target, times the risk", minval=0.5)
maxWait   = input.int(12, "Bars a gap waits for price to come back", minval=1)
lastEntry = input.int(66, "No new gaps after this bar of the session")
flatBar   = input.int(76, "Close everything on this bar of the session")

inWindow = time >= fromDate and time < toDate

// bars since the session opened: 0 is the first 5-minute bar of the day
var int barOfDay = 0
barOfDay := timeframe.change("D") ? 0 : barOfDay + 1

var float zEntry = na
var float zStop = na
var int zDir = 0
var int zBar = 0

flat = strategy.position_size == 0

// three candles of one session. Bullish: the third candle's low is above the first candle's
// high. Bearish: the third candle's high is below the first candle's low.
if flat and inWindow and barOfDay >= 2 and barOfDay <= lastEntry
    if low > high[2]
        strategy.cancel_all()
        zDir := 1
        zEntry := low
        zStop := low[2]
        zBar := bar_index
        strategy.entry("Long", strategy.long, limit=zEntry)
        strategy.exit("Long out", "Long", stop=zStop, limit=zEntry + rr * (zEntry - zStop))
    else if high < low[2]
        strategy.cancel_all()
        zDir := -1
        zEntry := high
        zStop := high[2]
        zBar := bar_index
        strategy.entry("Short", strategy.short, limit=zEntry)
        strategy.exit("Short out", "Short", stop=zStop, limit=zEntry - rr * (zStop - zEntry))

// a gap price has not come back to within maxWait bars is dropped
if flat and zDir != 0 and (bar_index - zBar >= maxWait or barOfDay > lastEntry)
    strategy.cancel_all()
    zDir := 0

// flat before the close: the order fills at the open of the session's last bar
if barOfDay >= flatBar
    strategy.close_all()

As printed it charges 0.025% commission and one tick of slippage a side, close to the third column below. Set both to zero to see the first.

The result

All ten tickers together, 1,885 trades over 60 sessions, at four levels of cost per side:

Before costs0.005% a side0.025% a side0.075% a side
Average trade−0.012%−0.022%−0.062%−0.162%
Trades that made money37.2%37.0%35.5%28.9%
Tickers that made money4 of 102 of 100 of 100 of 10

Ticker by ticker, net over the whole period:

TickerTradesWonBefore costs0.005% a side0.025% a side
QQQ19339.4%+1.8%−0.2%−7.6%
SPY22637.6%+1.0%−1.3%−9.8%
IWM19839.4%+3.7%+1.7%−6.1%
DIA20536.6%−1.8%−3.8%−11.4%
NVDA19334.7%−10.2%−11.9%−18.5%
TSLA17035.9%−0.8%−2.4%−8.9%
AAPL17640.3%−4.2%−5.9%−12.3%
MSFT17832.0%−12.3%−13.8%−19.8%
AMZN18035.6%−1.2%−3.0%−9.7%
META16640.4%+2.0%+0.3%−6.2%

Before costs four tickers made a little and six lost, which is what no edge looks like. At 0.075% a side, our tester's default, all ten lost between −20.5% and −32.9%.

Why it lost

How the trade endedTradesShare
At the stop1,10258%
At the target, twice the risk48326%
At the end of the session30016%

With the target at twice the risk, trades that end at either one break even when one in three reaches the target. Here 26% did, and the trades closed at the end of the session did not make up the rest. The win rate of 37.2% counts those small closing gains as wins, which is why it sits above the one in three while the average trade sits below zero.

Costs then do the rest. The stop sat a median 0.22% from the entry, so the target was about 0.45% away. A round trip at 0.025% a side costs 0.05%, a ninth of the target, on trades that were already slightly negative. Commission and slippage, and how to set them in Pine, are in commission and slippage, explained.

Early and late

The rules were fixed before the test, so nothing was tuned, but a pattern with an edge should show it in both parts of the period. Before costs:

SessionsTradesAverage tradeWon
28 July → 22 September1,253−0.014%37.0%
23 September → 20 October632−0.006%37.5%

Neither part made money. Only QQQ and IWM were positive in both, by at most 0.03% a trade, less than a round trip at 0.025% a side.

What the test leaves out

Twelve weeks is one stretch of one market, and ten tickers are not every market: futures traders run the same pattern on ES and NQ, where costs are lower. The test also takes the bare pattern. Traders who use fair value gaps usually add context: the trend on a higher timeframe, a sweep of an earlier high or low first, certain hours of the day. We did not test those. Any of them could change the answer, and each is one more setting that can fit the past by chance, so judge it on dates you held out, as in out-of-sample testing.

To run the script on TradingView, open a 5-minute chart of any of the ten. The Basic plan's 5,000 candles reach back about 64 sessions, enough for the dates in the script. TradingView's prices come from its own feed, so expect small differences in the trades. The free Pine Script audit reads your own version for the usual mistakes before you test it, and the free tester runs it with costs and holds the last stretch out.

Questions

In our test, 37%. The textbook retest, with the target at twice the risk, won 701 of 1,885 trades on 5-minute bars of ten US stocks and ETFs from 28 July to 20 October 2026. Only 26% of trades reached the target, short of the one in three a 2:1 target needs to break even, and the average trade was −0.01% before costs.

Sources: our 5-minute bars from the consolidated tape of all US exchanges, regular session, 28 July 2026 to 20 October 2026. Fills follow TradingView's Pine Script manual, “Strategies” (limit orders, the price path inside a candle), read on 20 October 2026, and its pricing page for the candles each plan loads. The numbers are our own calculation, run on 21 October 2026. A backtest describes the past; it is not a forecast or advice. TradingView belongs to its owner, and Alpha Charts is not affiliated with it.