The rules at a glance
- The gap: three candles in a row where the third candle's low is above the first candle's high (bullish), or its high is below the first candle's low (bearish), and the middle candle closes in the direction of the gap
- Size check: the gap must be at least 0.3 × the 14-period ATR, so tiny gaps are ignored
- Entry: a limit order at the near edge of the gap (or at its middle), waiting for the price to come back
- Stop loss: beyond the far side of the gap, plus a quarter of the ATR
- Target: twice the risk (2R)
- Filters: only longs above the 200 EMA and shorts below it; the order is cancelled if it hasn't filled within 20 candles
What a fair value gap is
Take any three candles in a row. Normally the wicks of the first and third candles overlap: the price traded through the same area more than once. Now and then the middle candle moves so far, so quickly, that they don't. In an up-move, the third candle's low stays above the first candle's high, and between them is a band of prices that only the middle candle traded through. That band is the fair value gap, often shortened to FVG. Some traders call it an imbalance or an inefficiency.
The idea, popularised by the Inner Circle Trader (ICT) community, is that the move was one-sided: buyers were so keen that sellers barely got a look-in. Price often comes back into the gap later, and a gap left by a strong move in an uptrend can act as support on the way back. A bearish gap is the mirror image: the third candle's high stays below the first candle's low.
How to spot one on a chart
- Find a strong candle that moves well beyond the ones around it. SMC traders call this the displacement candle. The script only checks that this middle candle closes in the direction of the gap; the size check below does the rest.
- Look at the candle before it and the candle after it.
- For a bullish gap, check that the low of the candle after is higher than the high of the candle before. The space between those two prices is the gap.
- Check the size. A gap of one or two pips on a 15-minute chart is noise. These rules want at least 0.3 × the 14-period ATR.
The halfway point of the gap has its own name in ICT teaching: consequent encroachment, or CE. Some traders enter there instead of at the edge. The script lets you choose either.
The rules, step by step
1. Trade with the trend
Only take bullish gaps when the price is above the 200 EMA, and bearish gaps when it's below. The idea is that a gap against the bigger trend is more likely to be run straight through; turning the filter off in the script shows whether that holds on your market.
2. Place a limit order at the edge of the gap
When the third candle closes and the gap is confirmed, place a buy limit at the top of a bullish gap (the third candle's low). You're waiting for the price to come back to you; you don't chase it.
3. Put the stop beyond the far side
The stop goes below the bottom of the gap (the first candle's high), minus a quarter of the ATR. If the price falls right through the gap, the idea that it's support is wrong.
4. Aim for twice the risk
The target is 2R. Some SMC traders aim for the last swing high instead. The script only uses a fixed R multiple, so you can test 1.5R or 3R in its settings, but not a swing-high target.
5. Cancel stale orders
If the price hasn't come back within 20 candles, cancel the order. An old gap is a different setup from a fresh one.
Worked example: EURUSD, 15-minute chart
EURUSD is rising. A strong bullish candle jumps from 1.1669 to 1.1696, and the candle after it has a low of 1.1684, while the candle before it had a high of 1.1671. That leaves a 13-pip gap, comfortably above 0.3 × the ATR of 8.5 pips. Assume the price is above the 200 EMA, as the default setting requires. A buy limit goes at 1.1684, the top of the gap.
| EURUSD long | |
|---|---|
| Entry (buy limit at the gap top) | 1.1684 |
| Stop loss | 1.1669 (gap bottom 1.1671 minus a quarter of the ATR), 15 pips away |
| Target (2R) | 1.1714, 30 pips away |
| Account and risk | $10,000, risking 1% = $100 |
| Lot size | $100 ÷ (15 pips × $10) = 0.66 lots |
| Loss if the stop is hit | $99.00 |
| Profit at the target | $198.00 |
The price drifts higher for a while, then pulls back. 8 candles (two hours) after the gap formed, a candle dips to 1.1682 and fills the limit order. It never closes below the gap, and 7 candles after the fill the target is reached. Plenty of gaps go the other way: the price comes back, fills the order and keeps falling. The stop is there for those.
FVG or order block?
Both mark the place where a strong move started, and the two often overlap. An order block is a candle: the last opposite candle before the move. A fair value gap is a gap between candles inside the move. When the order block and the gap sit together, many SMC traders treat that as a stronger level. The two scripts on this site let you test each one on its own.
A gap also often appears right after a liquidity sweep or a change of character, as the move away from the sweep gets going. Waiting for that sequence (sweep, strong move, gap, return to the gap) is one of the most common SMC setups. It gives fewer trades than the gap alone; test whether it gives better ones.
On gold, the FVG + order block strategy only takes a gap that starts at an order block, after a break of structure.
Risk management
- Risk the same small amount every time. 0.5% to 1%. Gap sizes vary a lot, so the lot size has to change with the stop distance.
- Accept that some orders never fill. The strongest moves often don't come back. Missing them is part of trading limit orders.
- Watch news candles. A data release can leave a big gap that the price never returns to, or one it slices straight through. Check the economic calendar.
- Know your break-even win rate. At 2R it's about 33% before costs. The risk-reward calculator shows it for other targets.
Common mistakes
- Calling every small gap an FVG. On a 1-minute chart there are gaps everywhere. The size check is there to filter them.
- Trading gaps against the trend. A bullish gap in a downtrend is often just a pause before the next leg down.
- Moving the order deeper after it misses. If the price didn't come back, the setup is gone.
- Stops inside the gap. Price often trades through most of the gap before turning. A stop in the middle gets hit on normal moves.
- Forgetting the timeframe. A gap on the 4-hour chart and a gap on the 5-minute chart aren't the same thing. Trade gaps on the timeframe you tested.
Backtest it yourself on TradingView
This page doesn't quote a win rate or a profit figure, and you should be wary of anyone who does without showing the test. Results change with the market, the dates, the data feed and the costs you put in. The honest way is to run the test yourself, and the free script below does the work in a couple of minutes.
- Open the chart. On TradingView, open EURUSD on the 15-minute chart.
- Add the script. Open the Pine Editor from the Pine icon in the panel on the right of the chart (older layouts have it as a tab under the chart), delete the code that's already there, paste this strategy's code and click "Add to chart".
- Put in your costs. Open the strategy's settings and go to Properties. Enter your broker's commission and a little slippage. A test without costs flatters every strategy, and short-term ones most of all.
- Read the Strategy Tester. The panel under the chart shows the net profit, the maximum drawdown, the profit factor, the number of trades and a list of every trade. Click a few trades and check on the chart that each one follows the rules. Trade sizes are shown in units rather than lots: 100,000 units is one lot of a forex pair, and 100 ounces is one lot of gold.
- Change one setting at a time. Compare the edge entry with the midpoint (CE) entry first. Then try the minimum gap size (0.2 to 0.6 × ATR), the number of candles the order waits, the stop buffer and the 200 EMA filter on and off. Run the same settings on GBPUSD and XAUUSD.
As a rough guide, don't trust a result with fewer than 100 trades, a profit factor under 1 once costs are in, or a drawdown you couldn't sit through with real money. Settings tuned to look good on one stretch of history often fail on the next, so check the same settings on dates you didn't tune them on, then demo trade the strategy for a few weeks. How much history you can test depends on your TradingView plan: the free plan loads 5,000 candles, which is a few months of 15-minute candles but years of daily ones.
The script sizes each trade from the stop loss and your risk percentage, starts with $10,000 and assumes 1:100 leverage (a 1% margin setting), so the tester doesn't flag margin calls on normal forex trade sizes. Change these under Properties to match your account. By default TradingView fills orders at the open of the candle after the signal, so the fill can differ a little from the signal candle's close. Because entries are limit orders, the fill is almost always at your limit price, or better if a candle opens beyond it.
Download the free Pine Script and PDF
The script is written in Pine Script version 6 for this guide and follows the rules above. It can't read the economic calendar, so skipping news days is up to you. It's free to use, change and share. The PDF is a one-page cheat sheet with the rules, a worked example, the lot size maths and a checklist, to keep next to your chart.
Show the code (Pine Script v6, 80 lines)
//@version=6
// Fair Value Gap strategy by PipLedger (https://pipledgerfx.com/fair-value-gap-strategy)
// Finds three-candle fair value gaps (FVGs) and buys or sells the first return into the gap with a limit order.
// Free to use and change. For education and backtesting only; not financial advice.
strategy("PipLedger: Fair Value Gap", shorttitle="FVG", overlay=true, initial_capital=10000, pyramiding=0, default_qty_type=strategy.fixed, default_qty_value=1, margin_long=1, margin_short=1, currency=currency.USD)
// ---------- Inputs
minGap = input.float(0.3, "Minimum gap size (x ATR 14)", minval=0.0, step=0.05)
entryAt = input.string("Gap edge", "Entry price", options=["Gap edge", "Gap middle (CE)"])
validFor = input.int(20, "Candles the gap stays valid", minval=1)
stopBuf = input.float(0.25, "Stop buffer beyond the gap (x ATR)", minval=0.0, step=0.05)
rr = input.float(2.0, "Target (R multiple)", minval=0.5, step=0.25)
useTrend = input.bool(true, "Only trade in the direction of the 200 EMA")
riskPct = input.float(1.0, "Risk per trade (% of equity)", minval=0.1, maxval=5.0, step=0.1)
// ---------- Helpers
fx = strategy.convert_to_account(1.0) // one unit of the chart's quote currency in account currency (1 on USD-quoted charts)
calcQty(float entry, float stop) =>
float dist = math.abs(entry - stop)
dist > 0 and not na(fx) ? strategy.equity * riskPct / 100 / (dist * syminfo.pointvalue * fx) : 0.0
atr = ta.atr(14)
ema200 = ta.ema(close, 200)
// ---------- Gaps, checked when the third candle closes
// bullish: the third candle's low is above the first candle's high, and the middle candle is bullish
bullGap = low > high[2] and close[1] > open[1] and low - high[2] >= minGap * atr
bearGap = high < low[2] and close[1] < open[1] and low[2] - high >= minGap * atr
var float gTop = na
var float gBot = na
var int gDir = 0 // 1 = a buy order waits in a bullish gap, -1 = a sell order waits in a bearish gap
var int gBar = na
flat = strategy.position_size == 0
// a waiting order is dropped once a trade is open, when the gap expires, or when a candle closes through the gap
if not flat
gDir := 0
if gDir == 1 and (bar_index - gBar >= validFor or close < gBot)
strategy.cancel("Long")
gDir := 0
if gDir == -1 and (bar_index - gBar >= validFor or close > gTop)
strategy.cancel("Short")
gDir := 0
newLong = flat and bullGap and (not useTrend or close > ema200)
newShort = flat and bearGap and (not useTrend or close < ema200)
// ---------- Orders: a limit order at the gap edge (or its middle), stop beyond the far side of the gap
if newLong
strategy.cancel("Short")
gTop := low
gBot := high[2]
gDir := 1
gBar := bar_index
float px = entryAt == "Gap edge" ? gTop : (gTop + gBot) / 2
float sl = gBot - atr * stopBuf
float q = calcQty(px, sl)
if q > 0
strategy.entry("Long", strategy.long, qty=q, limit=px)
strategy.exit("Long exit", "Long", stop=sl, limit=px + (px - sl) * rr)
else if newShort
strategy.cancel("Long")
gTop := low[2]
gBot := high
gDir := -1
gBar := bar_index
float px = entryAt == "Gap edge" ? gBot : (gTop + gBot) / 2
float sl = gTop + atr * stopBuf
float q = calcQty(px, sl)
if q > 0
strategy.entry("Short", strategy.short, qty=q, limit=px)
strategy.exit("Short exit", "Short", stop=sl, limit=px - (sl - px) * rr)
// ---------- Chart
plot(gDir != 0 ? gTop : na, "Gap top", color=color.new(color.orange, 0), style=plot.style_linebr)
plot(gDir != 0 ? gBot : na, "Gap bottom", color=color.new(color.orange, 40), style=plot.style_linebr)
plot(useTrend ? ema200 : na, "200 EMA", color=color.new(color.gray, 0))
plotshape(newLong, "Bullish gap", shape.triangleup, location.belowbar, color.teal, size=size.small)
plotshape(newShort, "Bearish gap", shape.triangledown, location.abovebar, color.red, size=size.small)Trading this from India
Residents can trade EURUSD, GBPUSD and USDJPY futures and options on NSE and BSE through a SEBI-registered broker. The contracts are quoted the same way as the spot pair, one lot is 1,000 units of the base currency, and they're cash-settled in rupees. They trade only from 9 a.m. to 7:30 p.m. IST, volumes are thin and not every broker offers them, so check the hours and the spread first. Trading forex or CFDs with offshore online platforms isn't allowed for residents under FEMA, even if the app is easy to download. Details are in is forex trading legal in India.
Related strategies: liquidity sweep, order block, BOS and CHoCH, ICT kill zones, XAUUSD FVG + order block. All 34 strategies are compared on one page in forex trading strategies.