About
A fair value gap is a price range three bars in a row leave untraded. Bullish: the third bar's low is above the first bar's high, and the gap runs from that high (bottom) to that low (top). Bearish: the third bar's high is below the first bar's low, from that high (bottom) to that low (top). A gap counts only when its height is at least min_atr times the ATR at the third bar: Wilder's ATR over atr_period bars, the engine's own (the same as ctx.ind("atr")). Nothing is detected while the ATR warms up.
Filling starts with the bar after the third, and wicks count. A bullish gap fills as price trades down into it: fill = (top - lowest low since) / (top - bottom). A bearish gap fills as price trades up: fill = (highest high since - bottom) / (top - bottom). When the fill reaches fill_threshold (1.0: price has traded through the whole gap; 0.5: to its middle) the gap counts as filled, is reported on that bar and is no longer tracked. The nearest open bullish gap is the one with the highest top, the nearest bearish one the one with the lowest bottom.
The plugin setting max_open_gaps caps how many open gaps are kept per side; past it the oldest is dropped without a fill event. This plugin follows the public three bar definition and is not a copy of any charting script.
Configuration
| Field | Type | Default | Description |
|---|---|---|---|
max_open_gapsOpen gaps kept per side | numbermin 1, max 1000 | 50 | How many open gaps are kept per side. When a new one would pass the limit, the oldest open gap on that side is dropped without a fill event. |
Parameters
| Name | Type | Default | Range or options | Description |
|---|---|---|---|---|
min_atr | float | 0.25 | min 0, max 10 | The smallest gap that counts, in multiples of the ATR at the gap's third bar. 0 counts every gap. |
atr_period | int | 14 | min 1, max 500 | Bars in Wilder's ATR. Nothing is detected before it is known. |
fill_threshold | float | 1 | min 0.01, max 1 | The fill at which a gap counts as filled: 1.0 when price has traded through the whole gap, 0.5 at its middle. |
Use it in a strategy
pythonfvg = ctx.plugin_indicator("fair_value_gaps", "fvg", {"min_atr": 0.25, "fill_threshold": 0.5})
if fvg is not None and fvg.value is not None:
close = ctx.bars(1)[-1].close
for gap in fvg.filled_gaps:
# Price came back to the middle of a bullish gap and closed above its bottom.
if gap["side"] == 1 and close > gap["bottom"]:
ctx.signal("LONG")
# The same for a bearish gap: out.
elif gap["side"] == -1 and close < gap["top"]:
ctx.signal("EXIT")What it provides
valueValue | 1 when a bullish gap formed on this bar, -1 for a bearish one, else 0 (the same as `new_gap`). None during warm up. |
gap_topValue | Top and `gap_bottom` of the gap formed on this bar. None when none formed. |
bull_topValue | Top, `bull_bottom` and `bull_fill` (0 to 1) of the nearest open bullish gap. None when there is none. |
bear_topValue | Top, `bear_bottom` and `bear_fill` (0 to 1) of the nearest open bearish gap. None when there is none. |
filled_gapsValue | The gaps this bar filled, as dicts like `open_gaps` ([] for none): read their levels here, since a filled gap is no longer tracked. None during warm up. |
bull_filledValue | How many of them were bullish, and `bear_filled` how many bearish; 0 for none. None during warm up. |
open_bullValue | How many bullish gaps are open, and `open_bear` how many bearish ones. None during warm up. |
open_gapsValue | Every open gap as a dict with side, top, bottom, fill and formed_at (the time of its third bar): bullish first, then bearish, each oldest first. None during warm up. |
atrValue | The ATR the minimum size is measured with. None during warm up. |
When values are known
A gap is known at the close of its third bar; a fill is known at the close of the bar that reaches it. Nothing reported changes with later bars. Warm up: None until the ATR is known (atr_period + 1 bars).
Limits
- Fills are measured with bar highs and lows: inside one bar the plugin cannot tell whether price touched the gap before or after the bar's other extreme.
- Gaps depend on the timeframe and on the data's bar times: the same market shows different gaps on M5 and H1, and on data with other session hours.
- Only open gaps up to the cap per side are tracked; a dropped gap never reports a fill.
- A plugin indicator is not drawn on the chart and is not available in Blocks, Pine, Rust or C#; it runs on the run's own instrument only.