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
- The gapThree 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.
- The entryA 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.
- The stopBeyond the first candle: its low for a long, its high for a short.
- The targetTwice the distance from the entry to the stop.
- The clockNo 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:
//@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 costs | 0.005% a side | 0.025% a side | 0.075% a side | |
|---|---|---|---|---|
| Average trade | −0.012% | −0.022% | −0.062% | −0.162% |
| Trades that made money | 37.2% | 37.0% | 35.5% | 28.9% |
| Tickers that made money | 4 of 10 | 2 of 10 | 0 of 10 | 0 of 10 |
Ticker by ticker, net over the whole period:
| Ticker | Trades | Won | Before costs | 0.005% a side | 0.025% a side |
|---|---|---|---|---|---|
| QQQ | 193 | 39.4% | +1.8% | −0.2% | −7.6% |
| SPY | 226 | 37.6% | +1.0% | −1.3% | −9.8% |
| IWM | 198 | 39.4% | +3.7% | +1.7% | −6.1% |
| DIA | 205 | 36.6% | −1.8% | −3.8% | −11.4% |
| NVDA | 193 | 34.7% | −10.2% | −11.9% | −18.5% |
| TSLA | 170 | 35.9% | −0.8% | −2.4% | −8.9% |
| AAPL | 176 | 40.3% | −4.2% | −5.9% | −12.3% |
| MSFT | 178 | 32.0% | −12.3% | −13.8% | −19.8% |
| AMZN | 180 | 35.6% | −1.2% | −3.0% | −9.7% |
| META | 166 | 40.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 ended | Trades | Share |
|---|---|---|
| At the stop | 1,102 | 58% |
| At the target, twice the risk | 483 | 26% |
| At the end of the session | 300 | 16% |
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:
| Sessions | Trades | Average trade | Won |
|---|---|---|---|
| 28 July → 22 September | 1,253 | −0.014% | 37.0% |
| 23 September → 20 October | 632 | −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.
Not on its own, in our test. Across 1,885 trades the average was −0.01% before costs, and four of the ten tickers made money before costs. At 0.025% a side, all ten lost. The test covers twelve weeks, so a longer history could read differently, but the pattern alone showed no edge.
Because the moves are small. On 5-minute bars the stop sat a median 0.22% from the entry, so a 2:1 target was about 0.45% away. A round trip at 0.025% a side costs 0.05%, and the average trade was already slightly below zero before any cost.
No. A price gap is a jump between two candles: one candle's low is above the previous candle's high, so nothing traded in between. A fair value gap spans three candles: the middle one moves so far that the first and third candles' ranges do not overlap, even though the middle candle traded through the space between them.
A fair value gap that price later closes through. Traders then read it the other way round: a bullish gap broken to the downside is treated as resistance when price comes back to it. We did not test inverse gaps on this page.
Mark the gap when the third candle closes, place a limit order at its edge, and attach the stop and target to that entry with strategy.exit. Set commission and slippage in strategy(), close intraday trades before the bell, and judge the result on dates you held out. The script on this page does all of that.
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.