Fair Value Gap Signals [UAlgo]Fair Value Gap Signals is a price action indicator that detects bullish and bearish Fair Value Gaps and then tracks how price behaves inside those gaps over time. Instead of only drawing static imbalance boxes, the script treats each FVG as a stateful object with live metrics, lifecycle states, mitigation logic, and optional rejection signals. This makes it useful for traders who want both structural FVG mapping and real time interaction analysis after the gap is created.
The indicator runs on price ( overlay=true ) and automatically identifies classic 3 candle FVG formations. Each detected gap is stored in an internal object with its own box, CE midline, metric bars, status, and signal label handling. As price revisits a gap, the script measures how deeply price penetrates the zone, how much volume is accumulated during tests, and how strong the test candles are in terms of directional body expansion (velocity style scoring).
A key design goal of this script is practical decision support. It can show:
Fresh gaps
Testing behavior
Filled or invalidated gaps
Rejection events (potential reversal signals)
Live VVD style metrics (Velocity, Volume, Depth / Safety) inside the FVG
It also includes an ATR filter to ignore small gaps, visibility limits to keep charts clean, optional CE midline plotting, and alert conditions for major gap events.
🔹 Features
🔸 1) Automatic Bullish and Bearish FVG Detection
The script detects standard 3 candle Fair Value Gaps using simple price displacement logic:
Bullish FVG when current low is above high from two bars ago
Bearish FVG when current high is below low from two bars ago
When a gap is confirmed, it is stored as a custom Gap object and immediately drawn on the chart with its own box, CE midline, and metric containers.
🔸 2) Stateful FVG Lifecycle Tracking
Each gap is tracked through multiple statuses instead of being treated as a static box:
Fresh
Testing
Tested
Rejected
Filled
This allows the indicator to model how price interacts with a gap over time and not just where the gap originally formed.
🔸 3) Configurable Mitigation Method (Close or Wick)
Users can choose how FVG mitigation is confirmed:
Close means invalidation requires a close through the far boundary
Wick means a wick touch through the far boundary is enough
This is a very useful option because traders often use different mitigation definitions depending on instrument and timeframe.
🔸 4) ATR Based Gap Size Filter
An optional ATR filter removes smaller gaps that may be insignificant in volatile conditions. When enabled, the script ignores bullish or bearish FVGs whose size is smaller than the current ATR value (using the chosen ATR length).
This helps reduce noise and keeps the display focused on stronger imbalances.
🔸 5) CE Midline (Consequent Encroachment) Support
Each FVG can display a dotted midline representing the center of the gap (Consequent Encroachment). This gives traders an additional reference inside the imbalance and is commonly used as a reaction level in ICT style workflows.
The CE line can be turned on or off with a dedicated input.
🔸 6) VVD Metrics Inside Each Gap (Velocity, Volume, Depth)
One of the strongest features of this script is the live metric visualization inside every active gap. The indicator tracks and displays three bar style metric boxes:
Velocity
Volume
Depth (rendered as a safety style score from penetration depth)
These metrics update as price tests the gap and provide a quick visual estimate of test quality, participation, and penetration risk.
🔸 7) Rejection Signal Detection with Context
When price enters a gap and then rejects from it with sufficient test volume, the script can print a directional signal label. Bullish gaps can generate Buy or Strong Buy labels and bearish gaps can generate Sell or Strong Sell labels.
Signal strength is influenced by the velocity metric, and the tooltip includes extra details such as velocity score, volume score, safety score, and test count.
🔸 8) Test Counting and Multi Test Awareness
The indicator keeps track of how many times a gap has been tested. This can help traders distinguish first touch behavior from repeated interactions that may weaken the setup.
The test count can also be displayed as text inside the main FVG box when metrics are enabled.
🔸 9) Visibility Control for Cleaner Charts
To avoid clutter, the script limits how many active bullish and bearish gaps are visually displayed at once using Max Visible FVGs . It scans from newest to oldest and only shows the most recent valid gaps per side.
Older or non visible gaps still exist in logic and continue updating internally, but their visuals are hidden.
🔸 10) Smart Object Cleanup and Retained Signal Labels
The script enforces an internal gap limit and removes older gap objects when needed. Gap boxes, CE lines, and metric boxes are deleted during cleanup, while rejection labels are intentionally allowed to remain on the chart for historical context.
This gives users a cleaner display while preserving past signal markers.
🔸 11) Alert Conditions for Key FVG Events
Built in alert conditions are provided for:
New FVG formed
FVG testing (price enters a gap)
FVG filled (mitigated / invalidated)
FVG rejection signal (potential reversal)
This makes the script suitable for active monitoring across multiple charts or watchlists.
🔹 Calculations
1) Bullish and Bearish FVG Detection Logic
The script uses classic 3 candle gap conditions:
bool fvgBull = low > high
bool fvgBear = high < low
Interpretation:
A bullish FVG exists when the current candle low leaves a gap above the high from two bars ago.
A bearish FVG exists when the current candle high leaves a gap below the low from two bars ago.
When detected, the script creates a Gap object and stores:
Top boundary
Bottom boundary
Direction
Origin index
Status and metrics
Visual objects (main box, metric boxes, midline, label handle)
2) ATR Filter for Minimum Gap Size
If the ATR filter is enabled, the script compares gap size with ATR and rejects undersized gaps:
float atrVal = ta.atr(atrLength)
float gapSizeBull = low - high
float gapSizeBear = low - high
if fvgBull and gapSizeBull < atrVal
fvgBull := false
if fvgBear and gapSizeBear < atrVal
fvgBear := false
This creates a volatility adjusted threshold for FVG relevance.
3) Gap Object Initialization and Visual Construction
When a new gap is created, the setup method initializes both state and visuals:
Main FVG box
CE midline
Three metric boxes (Vel, Vol, Dpt)
The main box is drawn from the origin index to a small forward projection:
g.paramBox := box.new(left = idx, top = top, right = bar_index + 5, bottom = bottom, ...)
The CE line is placed at the midpoint:
float midY = (top + bottom) / 2
The metric area is split into three horizontal segments inside the gap height so each metric can expand in width over time.
4) Gap Status Model and State Transitions
Each gap starts as Fresh . As price interacts with the gap, the script can move it through:
Testing when price enters the zone
Tested when price leaves after a test
Rejected when rejection conditions are met
Filled when mitigation occurs
This logic is implemented inside the update() method, which runs every bar for each stored gap.
5) Test Detection and First Touch Handling
The script avoids counting the forming bar as a test:
bool canTest = bar_index > g.index + 1
A gap is considered under test when the current candle range overlaps the gap:
bool isInside = canTest and (h >= g.bottom and l <= g.top)
When price first enters a fresh gap:
if g.status == "Fresh"
g.status := "Testing"
g.testCount := 1
g.testStartVolume := volume
eventCode := 1
This event code is later used for the FVG Testing alert condition.
6) Velocity Metric Calculation
Velocity is a bar quality style score calculated during gap tests. It combines body dominance and a directional bonus:
float bodyRatio = math.abs(close - open) / barRange
Directional bonus:
Bullish gap gets bonus if the test candle closes bullish
Bearish gap gets bonus if the test candle closes bearish
float currentVelocity = math.min(bodyRatio + directionBonus, 1.0)
The gap stores the maximum velocity observed across all tests:
if currentVelocity > g.maxVelocity
g.maxVelocity := currentVelocity
Interpretation:
Higher velocity suggests stronger directional response while testing the gap.
7) Volume Metric Calculation
During tests, the script accumulates test volume:
if isInside
g.testVolume += volume
Later, it compares the accumulated test volume to an expected volume estimate:
float expectedVol = volAvg * math.max(1, (bar_index - g.index) / 2)
float volScore = math.min(g.testVolume / expectedVol, 1.0)
This creates a normalized volume score used in both the metric bar length and the rejection label tooltip.
8) Depth Metric and Safety Score Calculation
Depth tracks how far price penetrates into the gap during tests.
For bullish gaps:
Depth is measured from gap top downward when price dips below the top boundary.
For bearish gaps:
Depth is measured from gap bottom upward when price rises above the bottom boundary.
Examples:
if g.isBullish
if l < g.top
currentDepth := g.top - l
else
if h > g.bottom
currentDepth := h - g.bottom
The maximum penetration depth is stored:
if currentDepth > g.maxDepth
g.maxDepth := currentDepth
The displayed metric is a safety style score:
float depthRatio = g.maxDepth / gapSize
float safetyScore = math.max(0.0, 1.0 - depthRatio)
Interpretation:
Deeper penetration reduces safety score and may imply weaker rejection quality.
9) Fill / Mitigation Logic (Close or Wick)
A gap is marked Filled when price crosses the far boundary in the inverse direction, according to the selected mitigation method:
if mitType == "Close"
filledInverse := g.isBullish ? (close < g.bottom) : (close > g.top)
else
filledInverse := g.isBullish ? (l < g.bottom) : (h > g.top)
When filled:
Status becomes Filled
Gap is deactivated
Event code becomes 2
Gap visuals are deleted
This event code feeds the FVG Filled alert condition.
10) Rejection Signal Logic
Rejection is checked only while the gap is active and price is inside the gap. The script also requires enough accumulated test volume:
if isInside and g.testVolume > volAvg * 0.5
Rejection condition:
Bullish gap rejection if price probes below the gap top and closes back above the gap top
Bearish gap rejection if price probes above the gap bottom and closes back below the gap bottom
bool rejected = g.isBullish ? (l < g.top and close > g.top) : (h > g.bottom and close < g.bottom)
When rejection is confirmed:
Gap status becomes Rejected
Optional signal label is drawn (Buy, Strong Buy, Sell, Strong Sell)
Event code becomes 3
This event code feeds the FVG Rejection Signal alert condition.
11) Signal Strength and Tooltip Metrics
When a rejection signal is printed, the script builds a tooltip with normalized scores:
Velocity score from maxVelocity
Volume score from testVolume versus expectedVol
Safety score from gap penetration depth
Test count
It also upgrades the signal text to Strong Buy or Strong Sell when max velocity exceeds 0.6:
if g.maxVelocity > 0.6
icon := g.isBullish ? "Strong Buy" : "Strong Sell"
This provides a compact label with deeper context available on hover.
12) Visibility Limiting and Render Hiding
The script iterates through gaps from newest to oldest and shows only the most recent active bullish and bearish gaps up to maxVisible per side. Non visible gaps are not deleted, but their visuals are hidden by setting colors and text to na .
This is useful for traders who want a focused view of current opportunities without losing older gap state tracking in the background.
13) Metric Bar Rendering Logic
Each metric box grows horizontally from the gap origin according to a normalized score:
Velocity length from maxVelocity
Volume length from volScore
Depth / Safety length from safetyScore
Example:
int len1 = int(math.max(1, maxWidth * velScore))
g.rankBox1.set_right(g.index + len1)
If metric display is disabled, the script hides the metric boxes and text while keeping the gap logic active.
14) Array Cleanup and Object Management
The script enforces a strict gap storage limit with GAP_LIMIT . When exceeded, the oldest gap is removed and its visuals are deleted:
if gaps.size() > GAP_LIMIT
gaps.cleanup()
The cleanup method deletes:
Main gap box
CE midline
Velocity metric box
Volume metric box
Depth metric box
Rejection info labels are intentionally preserved for historical review.
15) Alert Conditions
The script exposes four alert conditions:
alertcondition(fvgBull or fvgBear, "New FVG Formed", ...)
alertcondition(anyTesting, "FVG Testing", ...)
alertcondition(anyFilled, "FVG Filled", ...)
alertcondition(anySignal, "FVG Rejection Signal", ...)
These alerts are driven by the live event codes returned from each gap's update() call and make the indicator suitable for workflow automation.
Wskaźnik Pine Script®






















