1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.
Source Code
547 lines of Pine Script v6 from indicators/liquidity-magnet.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.
liquidity-magnet.pine
//@version=6
// =============================================================================
// LIQUIDITY MAGNET v1.6.4
// =============================================================================
// v1.6.4 fixes:
// + Historical markers now placed at recordedBar (where the magnet actually
// was), not at resolvedBar (where price arrived later). No more ghost
// markers in empty chart areas.
// + If a former top was swept the same bar it stopped being top, it gets
// status=touched immediately, not pending → expired. This eliminates
// fake ✗ markers on pools that were actually swept.
// + Top selection robust even when scores are tiny: picks highest-scoring
// pool regardless of total score magnitude. Fixes NEUTRAL/0% in Replay.
// =============================================================================
indicator("Liquidity Magnet", "LM", overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500, max_bars_back=5000)
// ============================== INPUTS =======================================
gDet = "Liquidity Detection"
pivotLen = input.int(10, "Pivot Lookback", minval=2, group=gDet)
maxPools = input.int(25, "Max Active Pools", minval=5, maxval=50, group=gDet)
minAge = input.int(3, "Min Pool Age (bars)", minval=1, group=gDet)
maxAge = input.int(500, "Max Pool Age (bars)", minval=50, group=gDet)
gEq = "Equal H/L Clustering"
autoEqTol = input.bool(true, "Auto-Scale Tolerance by Timeframe", group=gEq)
manualEqTol = input.float(0.15, "Manual Tolerance %", minval=0.0, step=0.05, group=gEq)
eqBonus = input.float(1.7, "Equal H/L Bonus Mult", minval=1.0, step=0.1, group=gEq)
gDist = "Distance Filter (Log-Scale)"
autoScale = input.bool(true, "Auto-Scale by Timeframe", group=gDist)
manualLogD = input.float(0.45, "Manual Log-Distance", minval=0.05, maxval=2.0, step=0.05, group=gDist)
gScore = "Probability Scoring (Weights)"
wStrength = input.float(1.0, "Strength Weight", minval=0.0, step=0.1, group=gScore)
wProximity = input.float(1.2, "Proximity Weight", minval=0.0, step=0.1, group=gScore)
wAge = input.float(0.6, "Age Decay Weight", minval=0.0, step=0.1, group=gScore)
wMomentum = input.float(0.9, "Momentum Bias Weight", minval=0.0, step=0.1, group=gScore)
gVis = "Visualization"
showZones = input.bool(true, "Show Liquidity Zones", group=gVis)
showTop = input.bool(true, "Highlight TOP MAGNET", group=gVis)
showLabels = input.bool(true, "Show Probability Labels", group=gVis)
showDash = input.bool(true, "Show Dashboard", group=gVis)
showStats = input.bool(true, "Show Touch Stats in Dashboard", group=gVis)
showLegend = input.bool(true, "Show Marker Legend in Dashboard", group=gVis)
zoneExt = input.int(20, "Zone Extension (bars right)", minval=0, group=gVis)
gHist = "Historical Track (Bar Replay)"
showHistory = input.bool(false, "Show Historical Top Magnets", group=gHist)
trackingWindow = input.int(100, "Tracking Window (bars)", minval=20, maxval=500, group=gHist)
maxHistory = input.int(100, "Max Historical Markers", minval=10, maxval=300, group=gHist)
histMarkerSize = input.string("Tiny", "Historical Marker Size", options=["Tiny", "Small", "Normal", "Large", "Huge"], group=gHist)
gMag = "Magnet Marker & Field Line"
showMagnet = input.bool(true, "Show Magnet Marker on TOP zone", group=gMag)
magnetSize = input.string("Large", "Magnet Marker Size", options=["Tiny", "Small", "Normal", "Large", "Huge"], group=gMag)
showField = input.bool(true, "Show Magnet Field Line", group=gMag)
fieldStyle = input.string("Diagonal", "Field Line Style", options=["Diagonal", "Vertical"], group=gMag)
fieldOffset = input.int(20, "Diagonal Offset (bars right)", minval=10, maxval=100, group=gMag)
gSize = "UI Sizing"
dashPosStr = input.string("Top Right", "Dashboard Position", options=["Top Right", "Top Left", "Bottom Right", "Bottom Left", "Middle Right", "Middle Left"], group=gSize)
dashSizeStr = input.string("Small", "Dashboard Text Size", options=["Tiny", "Small", "Normal", "Large", "Huge"], group=gSize)
lblSizeStr = input.string("Small", "Zone Label Text Size", options=["Tiny", "Small", "Normal", "Large"], group=gSize)
topLblSizeStr = input.string("Normal", "TOP Label Text Size", options=["Small", "Normal", "Large", "Huge"], group=gSize)
gCol = "Colors"
colHigh = input.color(#ef4444, "Upside Liquidity", group=gCol)
colLow = input.color(#22c55e, "Downside Liquidity", group=gCol)
colTop = input.color(#f59e0b, "TOP MAGNET", group=gCol)
colField = input.color(#f59e0b, "Magnet Field Line", group=gCol)
colHistOK = input.color(#22c55e, "Historical: Touched", group=gCol)
colHistFail = input.color(#94a3b8, "Historical: Expired", group=gCol)
colDashBg = input.color(#0F172A, "Dashboard BG", group=gCol)
colDashBdr = input.color(#1e293b, "Dashboard Border", group=gCol)
// ============================== TYPES ========================================
type Pool
float price
int barIdx
bool isHigh
bool isEqual
float volAt
float score
float probPct
box bx
line ln
label lbl
type HistMagnet
float price
int recordedBar
bool isHigh
int status // 0 pending, 1 touched, 2 expired
int resolvedBar
// ============================== STATE ========================================
var array<Pool> pools = array.new<Pool>()
var array<HistMagnet> history = array.new<HistMagnet>()
var array<label> histLabels = array.new<label>()
var line fieldLn = na
var label fieldArrow = na
var label magnetMarker = na
var int touchCount = 0
var int expiredCount = 0
var float prevTopPrice = na
var bool prevTopIsHigh = false
// ============================== TA HOISTED ===================================
atrV = ta.atr(14)
momRaw = ta.ema(close, 8) - ta.ema(close, 21)
volMa = ta.sma(volume, 50)
// ============================== AUTO-SCALE BY TF =============================
tfSec = timeframe.in_seconds(timeframe.period)
autoLogD = 0.30
if tfSec >= 604800
autoLogD := 0.95
else if tfSec >= 86400
autoLogD := 0.65
else if tfSec >= 14400
autoLogD := 0.45
else if tfSec >= 3600
autoLogD := 0.30
else if tfSec >= 900
autoLogD := 0.18
else
autoLogD := 0.10
logDistMax = autoScale ? autoLogD : manualLogD
autoEqPct = 0.15
if tfSec >= 604800
autoEqPct := 10
else if tfSec >= 86400
autoEqPct := 8
else if tfSec >= 14400
autoEqPct := 5
else if tfSec >= 3600
autoEqPct := 0.8
else if tfSec >= 900
autoEqPct := 0.5
else
autoEqPct := 0.15
eqTolPct = (autoEqTol ? autoEqPct : manualEqTol) / 100.0
// ============================== HELPERS ======================================
logDist(float a, float b) =>
(a > 0 and b > 0) ? math.abs(math.log(a / b)) : 1e10
findClosestPool(float newPrice, bool isHigh) =>
idx = -1
minDist = 1e10
sz = array.size(pools)
if sz > 0
for i = 0 to sz - 1
p = array.get(pools, i)
if p.isHigh == isHigh
diff = math.abs(p.price - newPrice) / newPrice
if diff <= eqTolPct and diff < minDist
minDist := diff
idx := i
idx
clearPoolDraws(Pool p) =>
if not na(p.bx)
box.delete(p.bx)
if not na(p.ln)
line.delete(p.ln)
if not na(p.lbl)
label.delete(p.lbl)
strToSize(string s) =>
result = size.small
if s == "Tiny"
result := size.tiny
else if s == "Small"
result := size.small
else if s == "Normal"
result := size.normal
else if s == "Large"
result := size.large
else if s == "Huge"
result := size.huge
result
strToPos(string s) =>
result = position.top_right
if s == "Top Right"
result := position.top_right
else if s == "Top Left"
result := position.top_left
else if s == "Bottom Right"
result := position.bottom_right
else if s == "Bottom Left"
result := position.bottom_left
else if s == "Middle Right"
result := position.middle_right
else if s == "Middle Left"
result := position.middle_left
result
dashSize = strToSize(dashSizeStr)
lblSize = strToSize(lblSizeStr)
topLblSize = strToSize(topLblSizeStr)
magSize = strToSize(magnetSize)
histSize = strToSize(histMarkerSize)
dashPos = strToPos(dashPosStr)
// ============================== PIVOT DETECT + MERGE =========================
ph = ta.pivothigh(high, pivotLen, pivotLen)
pl = ta.pivotlow(low, pivotLen, pivotLen)
if not na(ph)
mIdx = findClosestPool(ph, true)
if mIdx >= 0
existing = array.get(pools, mIdx)
existing.isEqual := true
existing.price := math.max(existing.price, ph)
existing.volAt := existing.volAt + volume[pivotLen]
array.set(pools, mIdx, existing)
else
array.push(pools, Pool.new(ph, bar_index - pivotLen, true, false, volume[pivotLen], 0.0, 0.0, na, na, na))
if not na(pl)
mIdx = findClosestPool(pl, false)
if mIdx >= 0
existing = array.get(pools, mIdx)
existing.isEqual := true
existing.price := math.min(existing.price, pl)
existing.volAt := existing.volAt + volume[pivotLen]
array.set(pools, mIdx, existing)
else
array.push(pools, Pool.new(pl, bar_index - pivotLen, false, false, volume[pivotLen], 0.0, 0.0, na, na, na))
// ============================== PRUNE — track if prev top was swept ==========
// We need to know if previous top got SWEPT specifically (not just removed)
// to properly mark history.
prevTopWasSweptThisBar = false
ii = array.size(pools) - 1
while ii >= 0
p = array.get(pools, ii)
age = bar_index - p.barIdx
swept = (p.isHigh and high > p.price) or (not p.isHigh and low < p.price)
tooOld = age > maxAge
lDist = logDist(p.price, close)
tooFar = lDist > logDistMax
// Was this the previous top magnet?
isPrevTop = not na(prevTopPrice) and math.abs(p.price - prevTopPrice) < syminfo.mintick * 5 and p.isHigh == prevTopIsHigh
if swept
if isPrevTop
prevTopWasSweptThisBar := true
clearPoolDraws(p)
array.remove(pools, ii)
else if tooOld
clearPoolDraws(p)
array.remove(pools, ii)
else if tooFar
clearPoolDraws(p)
array.remove(pools, ii)
ii -= 1
while array.size(pools) > maxPools
pShift = array.shift(pools)
clearPoolDraws(pShift)
// ============================== SCORING ======================================
calcScore(Pool p) =>
age = bar_index - p.barIdx
lDist = logDist(p.price, close)
volFactor = (na(p.volAt) or volMa <= 0) ? 1.0 : math.min(p.volAt / volMa, 3.0)
eqMult = p.isEqual ? eqBonus : 1.0
strength = volFactor * eqMult
prox = 0.0
if lDist < 0.002
prox := 0.3
else if lDist < 0.05
prox := math.max(0.5, 1.0 - math.abs(lDist - 0.02) * 10.0)
else
prox := math.max(0.05, 1.0 - (lDist - 0.05) * 3.0) // floor at 0.05 instead of 0
ageScore = 0.0
if age < minAge
ageScore := 0.5
else if age < 50
ageScore := 1.0
else
ageScore := math.max(0.1, 1.0 - (age - 50) / 450.0)
dirToPool = p.price > close ? 1.0 : -1.0
momNorm = close > 0 ? momRaw / close : 0.0
momAlign = dirToPool * momNorm * 100.0
momScore = 1.0 + math.max(-0.5, math.min(0.5, momAlign))
rawScore = strength * wStrength + prox * wProximity + ageScore * wAge + momScore * wMomentum
math.max(rawScore, 0.01) // floor so scoring never collapses to 0
totalScore = 0.0
scoreUp = 0.0
scoreDn = 0.0
topIdx = -1
topScore = -1.0
if array.size(pools) > 0
for i = 0 to array.size(pools) - 1
p = array.get(pools, i)
p.score := calcScore(p)
array.set(pools, i, p)
totalScore += p.score
if p.score > topScore
topScore := p.score
topIdx := i
// Probabilities + bias breakdown
if totalScore > 0
for i = 0 to array.size(pools) - 1
p = array.get(pools, i)
p.probPct := (p.score / totalScore) * 100.0
array.set(pools, i, p)
if p.isHigh
scoreUp += p.score
else
scoreDn += p.score
topPrice = (topIdx >= 0 and array.size(pools) > 0) ? array.get(pools, topIdx).price : na
topProb = (topIdx >= 0 and array.size(pools) > 0) ? array.get(pools, topIdx).probPct : na
topIsHigh = (topIdx >= 0 and array.size(pools) > 0) ? array.get(pools, topIdx).isHigh : false
// ============================== MAGNET PULL ==================================
biasMag = 0.0
if not na(topPrice) and totalScore > 0
sameSidePct = topIsHigh ? scoreUp / totalScore * 100.0 : scoreDn / totalScore * 100.0
biasMag := sameSidePct
biasDir = topIsHigh ? 1 : -1
bias = biasMag * biasDir
distToTopPct = na(topPrice) ? na : (topPrice - close) / close * 100.0
// ============================== HISTORICAL TRACK =============================
topActuallyChanged = not na(prevTopPrice) and not na(topPrice) and (math.abs(prevTopPrice - topPrice) > syminfo.mintick * 5 or prevTopIsHigh != topIsHigh)
topDisappeared = not na(prevTopPrice) and na(topPrice)
if topActuallyChanged or topDisappeared
// If prev top was swept THIS bar — record as immediately touched
initialStatus = prevTopWasSweptThisBar ? 1 : 0
resBar = prevTopWasSweptThisBar ? bar_index : na
array.push(history, HistMagnet.new(prevTopPrice, bar_index, prevTopIsHigh, initialStatus, resBar))
if prevTopWasSweptThisBar
touchCount += 1
// Resolve still-pending entries
if array.size(history) > 0
for i = 0 to array.size(history) - 1
h = array.get(history, i)
if h.status == 0
barsElapsed = bar_index - h.recordedBar
touched = (h.isHigh and high >= h.price) or (not h.isHigh and low <= h.price)
if touched
h.status := 1
h.resolvedBar := bar_index
touchCount += 1
array.set(history, i, h)
else if barsElapsed >= trackingWindow
h.status := 2
h.resolvedBar := bar_index
expiredCount += 1
array.set(history, i, h)
while array.size(history) > maxHistory
array.shift(history)
prevTopPrice := topPrice
prevTopIsHigh := topIsHigh
// ============================== VISUALIZATION ================================
intensityTransp(float pct) =>
int(math.max(10, 85 - pct * 3.5))
if barstate.islast and showZones and array.size(pools) > 0
atrH = atrV * 0.04
for i = 0 to array.size(pools) - 1
p = array.get(pools, i)
clearPoolDraws(p)
isTop = (i == topIdx) and showTop
baseC = p.isHigh ? colHigh : colLow
zoneC = isTop ? colTop : color.new(baseC, intensityTransp(p.probPct))
lineC = isTop ? colTop : color.new(baseC, math.max(0, intensityTransp(p.probPct) - 30))
lineW = isTop ? 3 : 1
lineStyle = isTop ? line.style_solid : line.style_dotted
p.bx := box.new(p.barIdx, p.price + atrH, bar_index + zoneExt, p.price - atrH, border_color=color.new(zoneC, 80), bgcolor=color.new(zoneC, 70))
p.ln := line.new(p.barIdx, p.price, bar_index + zoneExt, p.price, color=lineC, width=lineW, style=lineStyle)
if showLabels
eqMark = p.isEqual ? " ⊜" : ""
topMark = isTop ? " ◆" : ""
lblTxt = str.tostring(p.probPct, "#.0") + "%" + eqMark + topMark
lblTxtCol = isTop ? color.white : color.new(color.white, 10)
curLblSize = isTop ? topLblSize : lblSize
p.lbl := label.new(bar_index + zoneExt, p.price, lblTxt, style=label.style_label_left, color=color.new(zoneC, 40), textcolor=lblTxtCol, size=curLblSize)
array.set(pools, i, p)
// ============================== MAGNET MARKER + FIELD LINE ===================
if not na(magnetMarker)
label.delete(magnetMarker)
magnetMarker := na
if not na(fieldLn)
line.delete(fieldLn)
fieldLn := na
if not na(fieldArrow)
label.delete(fieldArrow)
fieldArrow := na
if barstate.islast and not na(topPrice)
if showMagnet
magnetMarker := label.new(bar_index + zoneExt - 2, topPrice, "🧲", style=label.style_none, textcolor=colTop, size=magSize)
if showField
if fieldStyle == "Diagonal"
endX = bar_index + fieldOffset
fieldLn := line.new(bar_index, close, endX, topPrice, color=color.new(colField, 20), width=2, style=line.style_dashed)
else
fieldLn := line.new(bar_index, close, bar_index, topPrice, color=color.new(colField, 20), width=2, style=line.style_dashed)
// ============================== HISTORICAL MARKERS ===========================
// Place markers at recordedBar (where the magnet actually was), not where
// price arrived. This keeps markers anchored to real price locations.
if barstate.isconfirmed or barstate.islast
if array.size(histLabels) > 0
for i = 0 to array.size(histLabels) - 1
label.delete(array.get(histLabels, i))
array.clear(histLabels)
if showHistory and array.size(history) > 0
for i = 0 to array.size(history) - 1
h = array.get(history, i)
if h.status > 0
mark = h.status == 1 ? "✓" : "✗"
col = h.status == 1 ? colHistOK : colHistFail
lbl = label.new(h.recordedBar, h.price, mark, style=label.style_none, textcolor=col, size=histSize)
array.push(histLabels, lbl)
// ============================== DASHBOARD ====================================
var table dash = table.new(dashPos, 2, 14, bgcolor=colDashBg, border_color=colDashBdr, border_width=1, frame_color=colDashBdr, frame_width=1)
table.clear(dash, 0, 0, 1, 13)
if (barstate.isconfirmed or barstate.islast) and showDash
biasAbs = math.abs(bias)
biasLabel = "NEUTRAL"
if biasAbs > 60
biasLabel := bias > 0 ? "STRONG BULL PULL" : "STRONG BEAR PULL"
else if biasAbs > 40
biasLabel := bias > 0 ? "BULL PULL" : "BEAR PULL"
biasCol = color.rgb(148, 163, 184)
if bias > 40
biasCol := colHigh
else if bias < -40
biasCol := colLow
totalRes = touchCount + expiredCount
touchRate = totalRes > 0 ? float(touchCount) / float(totalRes) * 100.0 : na
pendingCount = 0
if array.size(history) > 0
for i = 0 to array.size(history) - 1
h = array.get(history, i)
if h.status == 0
pendingCount += 1
topPriceStr = na(topPrice) ? "—" : str.tostring(topPrice, format.mintick)
topProbStr = na(topProb) ? "—" : str.tostring(topProb, "#.0") + "%"
distStr = na(distToTopPct) ? "—" : str.tostring(distToTopPct, "+#.00") + "%"
intensityStr = str.tostring(biasAbs, "#.0") + "%"
poolsStr = str.tostring(array.size(pools))
touchRateStr = na(touchRate) ? "—" : str.tostring(touchRate, "#.0") + "% (" + str.tostring(touchCount) + "/" + str.tostring(totalRes) + ")"
logDistStr = str.tostring(logDistMax, "#.00") + (autoScale ? " (auto)" : " (manual)")
eqTolStr = str.tostring(eqTolPct * 100.0, "#.00") + "%" + (autoEqTol ? " (auto)" : " (manual)")
labelCol = color.rgb(148, 163, 184)
grayCol = color.rgb(100, 116, 139)
row = 0
table.cell(dash, 0, row, "LIQUIDITY MAGNET", text_color=colTop, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, "v1.6.4", text_color=grayCol, bgcolor=colDashBg, text_size=size.tiny)
row += 1
table.cell(dash, 0, row, "Magnet Pull", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, biasLabel, text_color=biasCol, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Pull Intensity", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, intensityStr, text_color=biasCol, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Top Target", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, topPriceStr, text_color=colTop, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Probability", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, topProbStr, text_color=colTop, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Distance", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, distStr, text_color=color.white, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Active Pools", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, poolsStr, text_color=color.white, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Log-Dist Cap", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, logDistStr, text_color=color.white, bgcolor=colDashBg, text_size=dashSize)
row += 1
table.cell(dash, 0, row, "Equal Tol", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, eqTolStr, text_color=color.white, bgcolor=colDashBg, text_size=dashSize)
row += 1
if showStats
table.cell(dash, 0, row, "Historical Touch %", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, touchRateStr, text_color=color.white, bgcolor=colDashBg, text_size=dashSize)
row += 1
if pendingCount > 0
table.cell(dash, 0, row, "Pending", text_color=labelCol, bgcolor=colDashBg, text_size=dashSize)
table.cell(dash, 1, row, str.tostring(pendingCount), text_color=grayCol, bgcolor=colDashBg, text_size=dashSize)
row += 1
if showLegend
table.cell(dash, 0, row, "Legend", text_color=grayCol, bgcolor=colDashBg, text_size=size.tiny)
table.cell(dash, 1, row, "◆ Top ⊜ Equal ✓ Touched ✗ Expired", text_color=grayCol, bgcolor=colDashBg, text_size=size.tiny)
// ============================== ALERTS =======================================
newTopMagnet = ta.change(topPrice) != 0
nearTop = not na(topPrice) and math.abs(close - topPrice) / close < 0.005
sweptTop = not na(topPrice[1]) and ((topIsHigh[1] and high > topPrice[1]) or (not topIsHigh[1] and low < topPrice[1]))
biasFlipBull = bias > 50 and bias[1] <= 50
biasFlipBear = bias < -50 and bias[1] >= -50
alertcondition(newTopMagnet, "New Top Magnet", "Liquidity Magnet: new TOP MAGNET identified")
alertcondition(nearTop, "Price Approaching Top", "Liquidity Magnet: price within 0.5% of TOP MAGNET")
alertcondition(sweptTop, "Top Magnet Touched", "Liquidity Magnet: TOP MAGNET touched by price")
alertcondition(biasFlipBull, "Strong Bull Pull", "Liquidity Magnet: magnet pull turned strongly bullish")
alertcondition(biasFlipBear, "Strong Bear Pull", "Liquidity Magnet: magnet pull turned strongly bearish")
Overview
Liquidity Magnet detects swing highs, swing lows, and equal high or low clusters, then ranks them using strength, proximity, age decay, and momentum bias. Equal-level clusters receive a bonus, and distance filters can auto-scale by timeframe. Zones, probability labels, a top-magnet marker, a field line, and a dashboard with touch statistics are optional. Historical top magnets can be tracked, but the script does not place trades or define exits.
Swing and equal-level liquidity pools
Weighted strength proximity age and momentum scoring
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Pivot Lookback
int
10
pivotLen
Max Active Pools
int
25
maxPools
Min Pool Age (bars)
int
3
minAge
Max Pool Age (bars)
int
500
maxAge
Auto-Scale Tolerance by Timeframe
bool
true
autoEqTol
Manual Tolerance %
float
0.15
manualEqTol
Equal H/L Bonus Mult
float
1.7
eqBonus
Auto-Scale by Timeframe
bool
true
autoScale
Manual Log-Distance
float
0.45
manualLogD
Strength Weight
float
1.0
wStrength
Proximity Weight
float
1.2
wProximity
Age Decay Weight
float
0.6
wAge
Show all 40 settings
Setting
Type
Default
Variable
Momentum Bias Weight
float
0.9
wMomentum
Show Liquidity Zones
bool
true
showZones
Highlight TOP MAGNET
bool
true
showTop
Show Probability Labels
bool
true
showLabels
Show Dashboard
bool
true
showDash
Show Touch Stats in Dashboard
bool
true
showStats
Show Marker Legend in Dashboard
bool
true
showLegend
Zone Extension (bars right)
int
20
zoneExt
Show Historical Top Magnets
bool
false
showHistory
Tracking Window (bars)
int
100
trackingWindow
Max Historical Markers
int
100
maxHistory
Historical Marker Size
string
Tiny
histMarkerSize
Show Magnet Marker on TOP zone
bool
true
showMagnet
Magnet Marker Size
string
Large
magnetSize
Show Magnet Field Line
bool
true
showField
Field Line Style
string
Diagonal
fieldStyle
Diagonal Offset (bars right)
int
20
fieldOffset
Dashboard Position
string
Top Right
dashPosStr
Dashboard Text Size
string
Small
dashSizeStr
Zone Label Text Size
string
Small
lblSizeStr
TOP Label Text Size
string
Normal
topLblSizeStr
Upside Liquidity
color
#ef4444
colHigh
Downside Liquidity
color
#22c55e
colLow
TOP MAGNET
color
#f59e0b
colTop
Magnet Field Line
color
#f59e0b
colField
Historical: Touched
color
#22c55e
colHistOK
Historical: Expired
color
#94a3b8
colHistFail
Dashboard BG
color
#0F172A
colDashBg
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This overlay indicator scans a pasted list of symbols for ICT liquidity sweep patterns using prior swing sweeps. The screening method looks back one, two, or three swings and can list long and short signals in a results table with adjustable rows, position, an
The Golden Bullet Strategy is an overlay signal indicator based on Smart Money Concepts and time-based liquidity models. It identifies liquidity sweeps of a designated reference session range during a specified hunt window. It then confirms Market Structure Sh
Indicatorv6SMC / ICT / price actionSessions & time
This indicator identifies fractal-based pivot highs and lows to map out market structure directly on the price chart. It detects bullish and bearish structure breaks, automatically labeling Break of Structure (BOS) and Change of Character (ChoCH) events when p
Apex Trend & Liquidity Master calculates a trend cloud using customizable moving averages expanded by a volatility multiplier directly on the main price chart. It identifies dynamic support and resistance liquidity zones from swing high and low pivots, extendi
The CISD with Fib/Range Extensions and Stats indicator tracks Change in State of Delivery (CISD) level breakouts on the price chart. It detects pullback structures filtered by ATR and volume conditions, then projects future target levels using customizable Fib
MTF State of Delivery tracks lower timeframe and higher timeframe orderflow delivery states by identifying bullish and bearish delivery levels across timeframes. It plots confirmed and pending orderflow lines directly on the price chart and provides an optiona