Indicators··7 min read

Fair Value Gap Marker with Mitigation Tracking

1 references, link-verified · inline [n] markersEditor of record: Shane CantyStandards review editorial standard · audit log

Fair value gaps (FVGs) are unfilled price discontinuities that form when one candle's range does not overlap the prior candle's range, leaving a void in the order book. This indicator automatically identifies gaps that exceed a user-defined size threshold, marks their boundaries on the chart, and tracks whether price has returned to "fill" or mitigate each gap. Traders and market microstructure analysts use gap markers to identify potential support and resistance levels where liquidity may be clustered.

//@version=6
indicator("Fair Value Gap Marker with Mitigation Tracking", overlay=true)

// Input parameters
gapThresholdTicks = input.int(5, title="Gap Threshold (ticks)", minval=1)
showOpenGapsOnly = input.bool(false, title="Show Open Gaps Only")
gapLineWidth = input.int(2, title="Gap Line Width", minval=1, maxval=5)
bullGapColor = input.color(color.new(color.green, 60), title="Bullish Gap Color")
bearGapColor = input.color(color.new(color.red, 60), title="Bearish Gap Color")
mitigatedColor = input.color(color.new(color.gray, 60), title="Mitigated Gap Color")
showLabels = input.bool(true, title="Show Gap Labels")

// Convert gap threshold from ticks to price units (approximation based on syminfo.pointvalue)
gapThreshold = gapThresholdTicks * syminfo.pointvalue

// Variables to track gaps
var array<float> gapHighs = array.new<float>()
var array<float> gapLows = array.new<float>()
var array<bool> isBullish = array.new<bool>()
var array<bool> isMitigated = array.new<bool>()
var array<int> gapBarIndex = array.new<int>()
var array<line> gapLines = array.new<line>()
var array<label> gapLabels = array.new<label>()

// Identify and record fair value gaps
if bar_index > 0
    // Check for bullish gap: current bar's low > previous bar's high
    if close[1] < open and open > high[1] and (open - high[1]) >= gapThreshold
        array.push(gapHighs, high[1])
        array.push(gapLows, open)
        array.push(isBullish, true)
        array.push(isMitigated, false)
        array.push(gapBarIndex, bar_index - 1)
    
    // Check for bearish gap: current bar's high < previous bar's low
    if close[1] > open and open < low[1] and (low[1] - open) >= gapThreshold
        array.push(gapHighs, close[1])
        array.push(gapLows, low[1])
        array.push(isBullish, false)
        array.push(isMitigated, false)
        array.push(gapBarIndex, bar_index - 1)

// Check for gap mitigation (price fills the gap)
for i = 0 to array.size(gapHighs) - 1
    if not array.get(isMitigated, i)
        gapHigh = array.get(gapHighs, i)
        gapLow = array.get(gapLows, i)
        
        if low <= gapHigh and high >= gapLow
            array.set(isMitigated, i, true)

// Draw gap lines and labels
for i = 0 to array.size(gapHighs) - 1
    if not showOpenGapsOnly or not array.get(isMitigated, i)
        gapHigh = array.get(gapHighs, i)
        gapLow = array.get(gapLows, i)
        barIdx = array.get(gapBarIndex, i)
        isBull = array.get(isBullish, i)
        isMit = array.get(isMitigated, i)
        
        // Draw line for gap zone
        lineColor = isMit ? mitigatedColor : (isBull ? bullGapColor : bearGapColor)
        newLine = line.new(barIdx, gapHigh, bar_index, gapHigh, 
                          xloc=xloc.bar_index, color=lineColor, width=gapLineWidth, style=line.style_dashed)
        newLine2 = line.new(barIdx, gapLow, bar_index, gapLow, 
                           xloc=xloc.bar_index, color=lineColor, width=gapLineWidth, style=line.style_dashed)
        
        if showLabels
            labelText = isMit ? "FVG [M]" : (isBull ? "FVG ↑" : "FVG ↓")
            newLabel = label.new(bar_index, gapHigh + (gapHigh - gapLow) * 0.5, labelText, 
                                xloc=xloc.bar_index, color=lineColor, style=label.style_label_left, textcolor=color.white)

How the code works

The indicator maintains four parallel arrays tracking all detected fair value gaps: their top boundary (gapHighs), bottom boundary (gapLows), whether they are bullish or bearish gaps (isBullish), and whether price has mitigated them (isMitigated). On each bar, the script compares the current candle's open price against the prior candle's high and low. If a gap size exceeds the user-specified threshold (measured in ticks, then converted to price units), a new gap record is appended to each array. Simultaneously, the script loops through all stored gaps and checks if the current bar's price range overlaps the gap zone; if overlap occurs, the gap is marked mitigated. Lines are drawn at both the gap's top and bottom boundaries using dashed styling, and labels optionally mark each gap as bullish up or bearish down, or mitigated (M). Open mitigation markers appear in gray; unmitigated gaps retain their original color. The showOpenGapsOnly toggle reduces clutter by hiding filled gaps from the chart.

Reading it on a chart

A bullish fair value gap appears as a pair of dashed green lines marking the void created when price gaps upward; this gap is a zone where institutional orders might be clustered below the breakout level. A bearish gap (dashed red lines) marks a downside gap; liquidity concentration lies above the breakdown. When price later touches or crosses the gap zone, the lines change to gray and the label appends [M] to signal mitigation. Traders who believe price reverts to fill gaps watch for these milestones; those who trade breakout momentum view unmitigated gaps as proof of directional strength. The gap threshold input allows users to filter out noise: setting it higher (10+ ticks on large-cap equities) excludes overnight or minor gaps and reveals only structural discontinuities; setting it lower (2-3 ticks on micro-cap or low-liquidity instruments) captures tighter voids.

Limitations

Fair value gaps lack a theoretical foundation in market microstructure; the idea that gaps "must" be filled rests on practitioner convention, not empirical evidence linking gap presence to predictable price return. No published peer-reviewed study confirms that gap-fill probability or timing is statistically predictable from gap size alone. Price may fail to revisit a gap for weeks or indefinitely, especially after a major earnings or economic announcement; the threshold setting is arbitrary and no optimization method is established. The indicator does not account for order book depth, volatility regimes, or macroeconomic events that render liquidity clustering irrelevant. High-frequency moves or limit-up/limit-down halts may cause gaps to be created and filled within a single bar, evading detection. Repainting does not occur (the script only checks historical bars and marks gaps only when they are complete), but the mitigation definition (any price touch of the zone) may be too lenient in choppy markets where intrabar wicks graze the gap but do not represent true order flow. Finally, this is a marker only; it provides no signal for position entry, exit, or sizing, and should not be treated as a complete trading system.

Key definitions

Fair Value Gap (FVG): An unfilled price discontinuity formed when consecutive candles do not overlap, leaving a zone in the order book where trades did not occur, commonly hypothesized to represent clustering of pending limit orders.

Gap Mitigation: The event in which price enters and fills (or touches) the gap zone, potentially triggering execution of orders that were waiting in that zone.

Bullish Gap: A gap formed when price opens above the prior candle's high, creating an upward void; conventionally interpreted as a potential support or liquidity level on any pullback.

Bearish Gap: A gap formed when price opens below the prior candle's low, creating a downward void; conventionally interpreted as a potential resistance or liquidity level on any rally.

Threshold (Ticks): The minimum gap size, expressed in price increments, required before the indicator records a gap; filters out minor intrabar noise.

Liquidity Clustering: The practitioner belief that pending limit orders accumulate at price levels where prior trading activity ceased, especially unfilled gaps.

References


Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard.

Last reviewed by the PropLedger research pipeline: 2026-09-13. Educational research on historical data, not financial advice.

Educational research on historical data only. Not investment advice, not a signal, and never a performance promise. Past results do not predict future performance. Every reference is link-verified before publication and every paper is re-audited weekly against the library's editorial standard. Found an error? Email support@prop-ledger.org and the paper is corrected or withdrawn.