Fair Value Gaps
All plugins

Plugin libraryMarket structure

Plugin

Fair Value Gaps

Three bar fair value gaps with a minimum size in ATR: the nearest open gap on each side, how far each is filled, and an event when one is filled.

IndicatorNo networkDesktop onlyv1.0.0

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

FieldTypeDefaultDescription
max_open_gapsOpen gaps kept per sidenumbermin 1, max 100050How 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

NameTypeDefaultRange or optionsDescription
min_atrfloat0.25min 0, max 10The smallest gap that counts, in multiples of the ATR at the gap's third bar. 0 counts every gap.
atr_periodint14min 1, max 500Bars in Wilder's ATR. Nothing is detected before it is known.
fill_thresholdfloat1min 0.01, max 1The 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

valueValue1 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_topValueTop and `gap_bottom` of the gap formed on this bar. None when none formed.
bull_topValueTop, `bull_bottom` and `bull_fill` (0 to 1) of the nearest open bullish gap. None when there is none.
bear_topValueTop, `bear_bottom` and `bear_fill` (0 to 1) of the nearest open bearish gap. None when there is none.
filled_gapsValueThe 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_filledValueHow many of them were bullish, and `bear_filled` how many bearish; 0 for none. None during warm up.
open_bullValueHow many bullish gaps are open, and `open_bear` how many bearish ones. None during warm up.
open_gapsValueEvery 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.
atrValueThe 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.
OrionQuant