← All Analyses
NSENIFTY
Neutral

Liquidity Indicator

pradeep b
pradeep b
4w ago
Liquidity Indicator

//@version=5
indicator("Liquidity Indicator Pro", shorttitle="LIQ Pro", overlay=true, max_boxes_count=500,
max_lines_count=500, max_labels_count=500)
//
======================================================================
======
// LIQUIDITY INDICATOR PRO (v2 - decluttered)
// Only shows the strongest, most recent unswept liquidity zones instead of
// drawing a zone at every minor swing point. Equal highs/lows within
// tolerance are merged into ONE pool instead of stacking duplicate zones.
//
======================================================================
======
// ============================== INPUTS ==============================
grpSwing = "Swing Structure"
swingLen = input.int(10, "Swing Length", minval=1, group=grpSwing,
tooltip="Higher = fewer, stronger pivots (less noise). Lower = more, weaker pivots (more
clutter).")
grpLiq = "Liquidity"
showSweeps = input.bool(true, "Show Sweeps", group=grpLiq)
showStrong = input.bool(true, "Show Strong Levels", group=grpLiq)
showZones = input.bool(true, "Show Liquidity Zones", group=grpLiq)
maxZones = input.int(2, "Max Active Zones (per side)", minval=1, maxval=5,
group=grpLiq,
tooltip="Only the N most recent unswept zones per side stay on chart. Oldest is dropped
automatically.")
liqTolPct = input.float(0.08, "Equal High/Low Merge Tolerance %", minval=0.0, step=0.01,
group=grpLiq,
tooltip="New pivots within this %% of an existing zone merge into it instead of drawing a
duplicate.")
grpStruct = "Structure (BOS / CHOCH)"
showStructure = input.bool(true, "Show BOS/CHOCH", group=grpStruct)
grpFVG = "Fair Value Gap"
showFVG = input.bool(true, "Show FVG", group=grpFVG)
fvgLookback = input.int(50, "FVG Box Length (bars)", minval=5, group=grpFVG)
minFVGSizePct = input.float(0.10, "Min FVG Size %", minval=0.0, step=0.01,
group=grpFVG)
mitigateFVG = input.bool(true, "Remove FVG When Filled", group=grpFVG)
grpCol = "Colors"
sellLiqColor = input.color(color.new(color.red, 85), "Sell-Side Liquidity Zone", group=grpCol)
buyLiqColor = input.color(color.new(color.green, 85), "Buy-Side Liquidity Zone",
group=grpCol)
bosColor = input.color(color.red, "BOS Color", group=grpCol)
chochColor = input.color(color.blue, "CHOCH Color", group=grpCol)
bullFvgColor = input.color(color.new(color.green, 80), "Bullish FVG", group=grpCol)
bearFvgColor = input.color(color.new(color.red, 80), "Bearish FVG", group=grpCol)
atrVal = ta.atr(14)
// ============================== ZONE STORAGE
==============================
// arrays hold the currently ACTIVE (unswept) zones only, oldest at index 0
var float[] sellLevels = array.new_float()
var int[] sellBars = array.new_int()
var box[] sellBoxes = array.new_box()
var float[] buyLevels = array.new_float()
var int[] buyBars = array.new_int()
var box[] buyBoxes = array.new_box()
var int trendDir = 0 // 1 = bullish structure, -1 = bearish structure
// ---- helper: find index of an existing level within tolerance, else -1 ----
findNear(arr, price, tolPct) =>
idx = -1
if array.size(arr) > 0
for i = 0 to array.size(arr) - 1
lvl = array.get(arr, i)
if math.abs(price - lvl) / lvl * 100 <= tolPct
idx := i
idx
else
idx
// ============================== SWING DETECTION
==============================
ph = ta.pivothigh(high, swingLen, swingLen)
pl = ta.pivotlow(low, swingLen, swingLen)
if not na(ph)
pivotBar = bar_index - swingLen
nearIdx = findNear(sellLevels, ph, liqTolPct)
if nearIdx >= 0
// equal-high pool: extend the existing zone instead of duplicating
bx = array.get(sellBoxes, nearIdx)
box.set_right(bx, bar_index)
else
if showZones
newBox = box.new(pivotBar, ph, bar_index, ph - atrVal * 0.05,
border_color=color.red, bgcolor=sellLiqColor, extend=extend.none)
label.new(pivotBar, ph, "SELL SIDE LIQUIDITY", style=label.style_label_down,
color=color.new(color.red, 100), textcolor=color.red, size=size.small)
array.push(sellBoxes, newBox)
array.push(sellLevels, ph)
array.push(sellBars, pivotBar)
// keep only the most recent maxZones -> drop the oldest
if array.size(sellLevels) > maxZones
oldBox = array.shift(sellBoxes)
if not na(oldBox)
box.delete(oldBox)
array.shift(sellLevels)
array.shift(sellBars)
if not na(pl)
pivotBar = bar_index - swingLen
nearIdx = findNear(buyLevels, pl, liqTolPct)
if nearIdx >= 0
bx = array.get(buyBoxes, nearIdx)
box.set_right(bx, bar_index)
else
if showZones
newBox = box.new(pivotBar, pl + atrVal * 0.05, bar_index, pl,
border_color=color.green, bgcolor=buyLiqColor, extend=extend.none)
label.new(pivotBar, pl, "BUY SIDE LIQUIDITY", style=label.style_label_up,
color=color.new(color.green, 100), textcolor=color.green, size=size.small)
array.push(buyBoxes, newBox)
array.push(buyLevels, pl)
array.push(buyBars, pivotBar)
if array.size(buyLevels) > maxZones
oldBox = array.shift(buyBoxes)
if not na(oldBox)
box.delete(oldBox)
array.shift(buyLevels)
array.shift(buyBars)
// extend all still-active zones to the current bar
if showZones
if array.size(sellBoxes) > 0
for i = 0 to array.size(sellBoxes) - 1
box.set_right(array.get(sellBoxes, i), bar_index)
if array.size(buyBoxes) > 0
for i = 0 to array.size(buyBoxes) - 1
box.set_right(array.get(buyBoxes, i), bar_index)
// ============================== SWEEP DETECTION
==============================
// check every active zone (not just the latest) each bar
if array.size(sellLevels) > 0
for i = array.size(sellLevels) - 1 to 0
lvl = array.get(sellLevels, i)
if high > lvl and close < lvl
if showSweeps
label.new(bar_index, high, "SWEEP", style=label.style_label_down,
color=color.new(color.black, 0), textcolor=color.white, size=size.small)
if showStrong
label.new(bar_index, lvl, "STRONG HIGH", style=label.style_label_left,
color=color.red, textcolor=color.white, size=size.small)
if showZones
bx = array.get(sellBoxes, i)
box.set_right(bx, bar_index)
box.set_bgcolor(bx, color.new(color.red, 70))
array.remove(sellLevels, i)
array.remove(sellBars, i)
array.remove(sellBoxes, i)
alert("Sell-side liquidity swept", alert.freq_once_per_bar_close)
if array.size(buyLevels) > 0
for i = array.size(buyLevels) - 1 to 0
lvl = array.get(buyLevels, i)
if low < lvl and close > lvl
if showSweeps
label.new(bar_index, low, "SWEEP", style=label.style_label_up,
color=color.new(color.black, 0), textcolor=color.white, size=size.small)
if showStrong
label.new(bar_index, lvl, "STRONG LOW", style=label.style_label_left,
color=color.green, textcolor=color.white, size=size.small)
if showZones
bx = array.get(buyBoxes, i)
box.set_right(bx, bar_index)
box.set_bgcolor(bx, color.new(color.green, 70))
array.remove(buyLevels, i)
array.remove(buyBars, i)
array.remove(buyBoxes, i)
alert("Buy-side liquidity swept", alert.freq_once_per_bar_close)
// ============================== BOS / CHOCH
==============================
// structure is judged against the most recent (last) active zone on each side
lastSellLvl = array.size(sellLevels) > 0 ? array.get(sellLevels, array.size(sellLevels) - 1) : na
lastSellBar = array.size(sellBars) > 0 ? array.get(sellBars, array.size(sellBars) - 1) : na
lastBuyLvl = array.size(buyLevels) > 0 ? array.get(buyLevels, array.size(buyLevels) - 1) :
na
lastBuyBar = array.size(buyBars) > 0 ? array.get(buyBars, array.size(buyBars) - 1) : na
if showStructure
if not na(lastSellLvl) and ta.crossover(close, lastSellLvl)
isChoch = trendDir == -1
line.new(lastSellBar, lastSellLvl, bar_index, lastSellLvl,
color=isChoch ? chochColor : bosColor, style=line.style_dashed)
label.new(int(math.round((lastSellBar + bar_index) / 2)), lastSellLvl, isChoch ?
"CHOCH" : "BOS",
style=label.style_label_down, color=color.new(color.white, 100),
textcolor=isChoch ? chochColor : bosColor, size=size.small)
trendDir := 1
if not na(lastBuyLvl) and ta.crossunder(close, lastBuyLvl)
isChoch = trendDir == 1
line.new(lastBuyBar, lastBuyLvl, bar_index, lastBuyLvl,
color=isChoch ? chochColor : bosColor, style=line.style_dashed)
label.new(int(math.round((lastBuyBar + bar_index) / 2)), lastBuyLvl, isChoch ?
"CHOCH" : "BOS",
style=label.style_label_up, color=color.new(color.white, 100),
textcolor=isChoch ? chochColor : bosColor, size=size.small)
trendDir := -1
// ============================== FAIR VALUE GAP
==============================
var box[] bullFvgBoxes = array.new_box()
var box[] bearFvgBoxes = array.new_box()
if showFVG
bullGap = low - high[2]
if bullGap > 0 and (bullGap / close) * 100 >= minFVGSizePct
b = box.new(bar_index[2], high[2], bar_index + fvgLookback, low,
border_color=color.new(color.green, 50), bgcolor=bullFvgColor,
extend=extend.none)
array.push(bullFvgBoxes, b)
bearGap = low[2] - high
if bearGap > 0 and (bearGap / close) * 100 >= minFVGSizePct
b2 = box.new(bar_index[2], low[2], bar_index + fvgLookback, high,
border_color=color.new(color.red, 50), bgcolor=bearFvgColor, extend=extend.none)
array.push(bearFvgBoxes, b2)
if showFVG and mitigateFVG
if array.size(bullFvgBoxes) > 0
for i = array.size(bullFvgBoxes) - 1 to 0
bx = array.get(bullFvgBoxes, i)
if close < box.get_bottom(bx)
box.delete(bx)
array.remove(bullFvgBoxes, i)
if array.size(bearFvgBoxes) > 0
for i = array.size(bearFvgBoxes) - 1 to 0
bx = array.get(bearFvgBoxes, i)
if close > box.get_top(bx)
box.delete(bx)
array.remove(bearFvgBoxes, i)
// ============================== ALERTS ==============================
alertcondition(showSweeps and array.size(sellLevels) > 0, "Sell-Side Zone Active", "Sell-side
liquidity zone active")
alertcondition(showSweeps and array.size(buyLevels) > 0, "Buy-Side Zone Active",
"Buy-side liquidity zone active") 

Disclaimer

The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by GoCharting. Read more in the Terms of Use.

Comments (0)

Loading comments…