Imbalance Zone Script Summary
Creato il: 9 gennaio 2025
Creato il: 9 gennaio 2025
//@version=6
indicator('Imbalanced zone', overlay=true)
// Inputs
tf = input.timeframe('', 'TimeFrame')
penetrationRatio = input.float(title='Penetration Ratio', defval=0.2, minval=0, maxval=1, step=0.1)
reduce = input.bool(true, 'Reduce boxes')
extendBoxes = input.bool(true, 'Extend boxes')
imbalancedDownColor = input.color(color.rgb(120, 120, 120, 80), 'Down Box Color')
imbalancedDownMidLineColor = input.color(color.rgb(120, 120, 120), 'Down Mid Line Color')
imbalancedUpColor = input.color(color.rgb(120, 120, 120, 80), 'Up Box Color')
imbalancedUpMidLineColor = input.color(color.rgb(120, 120, 120), 'Up Mid Line Color')
showDailyImbalance = input.bool(false, 'Show Daily Imbalance Zone')
dailyImbalanceColor = input.color(color.rgb(252, 227, 0, 90), 'Daily Imbalance Zone Color')
dailyImbalanceHistory = input.int(5, 'Daily Imbalance Zone History')
showWeeklyImbalance = input.bool(false, 'Show Weekly Imbalance Zone')
weeklyImbalanceColor = input.color(color.rgb(120, 0, 0, 90), 'Weekly Imbalance Zone Color')
weeklyImbalanceHistory = input.int(4, 'Weekly Imbalance Zone History')
tfVi = input.timeframe('', 'Volume Imbalance TimeFrame')
showVolumeImbalance = input.bool(true, 'Show Volume Imbalance')
volumeImbalanceColor = input.color(color.rgb(33, 149, 243, 85), 'Volume Imbalance Color')
maxBarHistory = input.int(500, 'Max IPA Age')
// Arrays
var array<box> imbalancedDownBoxes = array.new_box()
var array<box> imbalancedUpBoxes = array.new_box()
var array<line> imbalancedDownMidLines = array.new_line()
var array<line> imbalancedUpMidLines = array.new_line()
var array<box> volumeImbalances = array.new_box()
var array<box> dailyImbalanceZones = array.new_box()
var array<box> weeklyImbalanceZones = array.new_box()
// Functions
findImbalance(h1, h3, l1, l3) =>
if h3 < l1 and l3 != nz(l3[1])
array.push(imbalancedDownBoxes, box.new(bar_index - 2, h3, bar_index + 20, l1, bgcolor=imbalancedDownColor, border_color=imbalancedDownColor, extend=extendBoxes ? extend.right : extend.none))
array.push(imbalancedDownMidLines, line.new(bar_index - 2, (h3 + l1) / 2, bar_index + 20, (h3 + l1) / 2, style=line.style_dotted, color=imbalancedDownMidLineColor, extend=extendBoxes ? extend.right : extend.none))
if l3 > h1 and h3 != nz(h3[1])
array.push(imbalancedUpBoxes, box.new(bar_index - 2, l3, bar_index + 20, h1, bgcolor=imbalancedUpColor, border_color=imbalancedUpColor, extend=extendBoxes ? extend.right : extend.none))
array.push(imbalancedUpMidLines, line.new(bar_index - 2, (h1 + l3) / 2, bar_index + 20, (h1 + l3) / 2, style=line.style_dotted, color=imbalancedUpMidLineColor, extend=extendBoxes ? extend.right : extend.none))
manageBoxes(boxes, midLines, isUp) =>
for i = array.size(boxes) - 1 to 0 by -1
box = array.get(boxes, i)
if box.exists()
top = box.get_top()
bottom = box.get_bottom()
invalidationLimit = (top - bottom) * penetrationRatio
box.set_right(bar_index + 20)
if i < array.size(midLines)
line = array.get(midLines, i)
if line.exists()
line.set_x2(bar_index + 20)
if (bar_index - box.get_left() > maxBarHistory)
box.delete(box)
if i < array.size(midLines)
line = array.get(midLines, i)
if line.exists()
line.delete(line)
array.remove(boxes, i)
array.remove(midLines, i)
else
if reduce and (isUp ? high > bottom : low < top)
box.set_bottom(isUp ? high : low)
if (isUp ? high >= bottom + invalidationLimit : low <= top - invalidationLimit)
box.delete(box)
if i < array.size(midLines)
line = array.get(midLines, i)
if line.exists()
line.delete(line)
array.remove(boxes, i)
array.remove(midLines, i)
// Main logic
[h1, h3, l1, l3] = request.security(syminfo.tickerid, tf, [high[1], high[3], low[1], low[3]], lookahead=barmerge.lookahead_on)
findImbalance(h1, h3, l1, l3)
manageBoxes(imbalancedUpBoxes, imbalancedUpMidLines, true)
manageBoxes(imbalancedDownBoxes, imbalancedDownMidLines, false)
// Daily Imbalance Zone
if showDailyImbalance and timeframe.isdaily
[o, c, t, tc] = request.security(syminfo.tickerid, '1D', [open, close, time, time_close], lookahead=barmerge.lookahead_on)
if o != c
array.push(dailyImbalanceZones, box.new(t, math.max(o, c), tc, math.min(o, c), xloc=xloc.bar_time, bgcolor=dailyImbalanceColor, border_color=color.rgb(0, 0, 0, 100)))
if array.size(dailyImbalanceZones) > dailyImbalanceHistory
box.delete(array.shift(dailyImbalanceZones))
// Weekly Imbalance Zone
if showWeeklyImbalance and timeframe.isweekly
[wo, wc, wt, wtc] = request.security(syminfo.tickerid, '1W', [open, close, time, time_close], lookahead=barmerge.lookahead_on)
if wo != wc
array.push(weeklyImbalanceZones, box.new(wt, math.max(wo, wc), wtc, math.min(wo, wc), xloc=xloc.bar_time, bgcolor=weeklyImbalanceColor, border_color=color.rgb(0, 0, 0, 100)))
if array.size(weeklyImbalanceZones) > weeklyImbalanceHistory
box.delete(array.shift(weeklyImbalanceZones))
// Volume Imbalance
if showVolumeImbalance
[o1, c1, o2, c2, viTime] = request.security(syminfo.tickerid, tfVi, [open[1], close[1], open[2], close[2], time[2]], lookahead=barmerge.lookahead_on)
volumeGap = o2 < c2 ? c2 < o1 and c2 < c1 : c2 > o1 and c2 > c1
if not volumeGap
volumeGap := math.min(o2, c2) > math.max(o1, c1) or math.max(o2, c2) < math.min(o1, c1)
if volumeGap
bottom = math.min(o1, c1) > math.max(o2, c2) ? math.max(o2, c2) : math.max(o1, c1)
top = math.min(o1, c1) > math.max(o2, c2) ? math.min(o1, c1) : math.min(o2, c2)
array.push(volumeImbalances, box.new(viTime, top, viTime + 20 * 60 * 1000, bottom, xloc=xloc.bar_time, bgcolor=volumeImbalanceColor, border_color=color.rgb(0, 0, 0, 100)))
for i = array.size(volumeImbalances) - 1 to 0 by -1
viBox = array.get(volumeImbalances, i)
if viBox.exists()
if low <= box.get_bottom(viBox) and high >= box.get_top(viBox)
box.delete(viBox)
array.remove(volumeImbalances, i)
else
box.set_right(viBox, time_close + 20 * 60 * 1000)
Below is an overview of how this script is structured and what it does. If you have follow-up questions or need modifications, just let me know!
This script (written in Pine Script, version 6) plots various types of “imbalances” (often called “fair value gaps”) on a TradingView chart. It also has the option to highlight daily/weekly price imbalances and a “volume imbalance” based on multi-timeframe data.
In short, the script:
tf
), drawing boxes and dotted mid-lines for each imbalance.tfVi
).You can enable or disable each part using the inputs at the top of the script.
TimeFrame (tf
)
Penetration Ratio (penetrationRatio
)
Reduce boxes (reduce
)
true
, the script will “shrink” a box (the imbalance zone) when price partially fills or penetrates it.Extend boxes (extendBoxes
)
true
, newly created boxes and lines will continue extending into the future until price invalidates them or the max bar age is reached.Down/Up Box Colors & mid-line colors
Daily/Weekly Imbalance toggles
Volume Imbalance
tfVi
) can be chosen separately from the primary price imbalance timeframe.Max IPA Age (maxBarHistory
)
Data Request
[h1, h3, l1, l3] = request.security(syminfo.tickerid, tf, [high[1], high[3], low[1], low[3]], ...)
[1]
) and three bars ago ([3]
) on the specified timeframe tf
.lookahead=barmerge.lookahead_on
allows the script to capture data without repaints, though it can behave differently depending on your preference.Logic
h3 < l1
then it’s considered a “down imbalance” (price jumped down, leaving a gap).l3 > h1
then it’s considered an “up imbalance” (price jumped up, leaving a gap).Creating Boxes & Mid-lines
box.new(...)
) that spans from bar_index - 2
to bar_index + 20
, and also creates a dotted mid-line showing the midpoint of the gap.imbalancedDownBoxes
, imbalancedUpBoxes
, etc.) so they can be managed later.The manageBoxes()
function takes care of pruning or adjusting existing imbalance boxes:
Age Out
maxBarHistory
, it’s deleted.Reduction
reduce = true
, the script shrinks the box by adjusting its top or bottom boundary.Invalidation
penetrationRatio
times the box’s height, the box is considered “filled” and is removed.This keeps the chart from accumulating old imbalance boxes indefinitely.
Check if daily timeframe
if showDailyImbalance and timeframe.isdaily
Creates boxes for daily candle bodies
[o, c, t, tc] = request.security(syminfo.tickerid, '1D', [open, close, time, time_close], ...)
open
and close
is considered an imbalance zone (in the sense of a candle body).dailyImbalanceHistory
limit.Same idea, but for weekly data:
textif showWeeklyImbalance and timeframe.isweekly [wo, wc, wt, wtc] = request.security(syminfo.tickerid, '1W', ...)
A box is drawn for each weekly candle body, with a user-defined color and history limit.
Data Request
[o1, c1, o2, c2, viTime] = request.security(...)
tfVi
), a bar or two bars ago.Volume Gap Detection
o1, c1
) and the newer candle (o2, c2
).box
that extends 20 bars into the future (though here it’s using time in milliseconds: time + 20 * 60 * 1000
for a 20-minute extension).Pruning Volume Imbalance Boxes
Adding to Your Chart
Customizing
Performance Note
request.security()
calls and draws multiple boxes, it can be somewhat heavy on resources if you enable everything or use a large maxBarHistory
. Reduce the history or disable unneeded features to lighten it.Potential Edge Cases
barmerge.lookahead_off
if you’re trying to avoid repainting.This script identifies and manages multiple types of imbalances (regular “price” FVGs, candle-body “imbalances” for daily/weekly, and volume-based imbalances). Boxes are dynamically extended, reduced, or removed based on price action and user settings.
If you have specific questions (e.g., debugging issues, repainting concerns, or ideas for further customization), feel free to ask!