Smart Money Dashboard plots key Smart Money Concepts on the price chart, including Order Blocks with mitigation tracking, Fair Value Gaps, and Equal Highs or Lows sweeps.
//@version=6
// ============================================================================
// Smart Money Dashboard [WavesUnchained]
// Version: 2.0.0
// Author: WavesUnchained
// Build: 2026-02-23 00:00:00
// ============================================================================
// Comprehensive smart money analysis combining CVD, structural patterns,
// liquidity mapping, and multi-timeframe confluence into a directional bias.
//
// Features:
// ✓ CVD with delta divergence detection
// ✓ Directional bias scoring (-100 to +100)
// ✓ Order Blocks with mitigation tracking
// ✓ Fair Value Gaps with fill tracking
// ✓ Equal Highs/Lows with sweep + reclaim signals
// ✓ Nearest-level awareness (distance in ATR)
// ✓ Session context (Asia range, London/NY kill zones)
// ✓ Multi-timeframe structural confluence
//
// ============================================================================
indicator("Smart Money Dashboard [WavesUnchained]", "SMD v2", overlay=true,
max_boxes_count=200, max_lines_count=200, max_labels_count=100)
// ============================================================================
// USER INPUTS
// ============================================================================
var g1 = "CVD / Order Flow"
enableCVD = input.bool(true, "Enable CVD Analysis", group=g1)
cvdLen = input.int(20, "CVD EMA Length", group=g1, minval=5, maxval=100)
divLookback = input.int(20, "Divergence Lookback", group=g1, minval=10, maxval=50)
var g2 = "SMC Patterns"
enableOB = input.bool(true, "Show Order Blocks", group=g2)
enableFVG = input.bool(true, "Show Fair Value Gaps", group=g2)
maxOBs = input.int(5, "Max Order Blocks", group=g2, minval=1, maxval=20)
maxFVGs = input.int(3, "Max FVGs", group=g2, minval=1, maxval=10)
obDispMult = input.float(1.2, "OB Displacement ATR x", group=g2, minval=0.5, maxval=3.0, step=0.1)
var g3 = "Liquidity"
enableLiq = input.bool(true, "Show Equal Highs/Lows", group=g3)
liqLookback = input.int(15, "Pivot Lookback", group=g3, minval=5, maxval=50)
eqlTolerance = input.float(0.05, "Equal Level Tolerance %", group=g3, minval=0.01, maxval=0.5, step=0.01)
reclaimBars = input.int(5, "Reclaim Window (bars)", group=g3, minval=1, maxval=20)
var g4 = "Sessions"
enableSessions = input.bool(true, "Show Session Context", group=g4)
sessionTZ = input.string("UTC", "Timezone",
options=["UTC","America/New_York","America/Chicago","Europe/London","Europe/Berlin","Asia/Tokyo"], group=g4)
asiaStartH = input.int(0, "Asia Start Hour", group=g4, minval=0, maxval=23)
asiaEndH = input.int(8, "Asia End Hour", group=g4, minval=0, maxval=23)
londonKZStartH = input.int(7, "London KZ Start", group=g4, minval=0, maxval=23)
londonKZEndH = input.int(10, "London KZ End", group=g4, minval=0, maxval=23)
nyKZStartH = input.int(12, "NY KZ Start", group=g4, minval=0, maxval=23)
nyKZEndH = input.int(15, "NY KZ End", group=g4, minval=0, maxval=23)
var g5 = "Multi-Timeframe"
enableHTF = input.bool(true, "Enable HTF Confluence", group=g5)
htfTimeframe = input.timeframe("240", "HTF Timeframe", group=g5)
var g6 = "Display"
showDashboard = input.bool(true, "Show Dashboard", group=g6)
showFlowBG = input.bool(true, "CVD Background", group=g6)
showAsiaRange = input.bool(true, "Show Asia Range", group=g6)
// ============================================================================
// TYPES
// ============================================================================
type OBLevel
int barIdx
float hi
float lo
string obType
bool mitigated
type FVGLevel
int barIdx
float hi
float lo
string fvgType
bool filled
type LiqLevel
float price
int lastBar
int touchCount
bool swept
int sweepBar
bool reclaimed
string reclaimDir
// ============================================================================
// CVD + DELTA DIVERGENCE
// ============================================================================
barRange = high - low
barDelta = barRange > 0 ? volume * (2.0 * (close - low) / barRange - 1.0) : 0.0
cvd = ta.cum(barDelta)
cvdEMA = ta.ema(cvd, cvdLen)
cvdTrend = cvd > cvdEMA ? 1 : -1
priceAtHigh = high >= ta.highest(high, divLookback)
cvdAtHigh = cvd >= ta.highest(cvd, divLookback)
priceAtLow = low <= ta.lowest(low, divLookback)
cvdAtLow = cvd <= ta.lowest(cvd, divLookback)
bearishDiv = priceAtHigh and not cvdAtHigh
bullishDiv = priceAtLow and not cvdAtLow
bullVolSum = math.sum(close > open ? volume : 0.0, cvdLen)
bearVolSum = math.sum(close <= open ? volume : 0.0, cvdLen)
totalVolSum = bullVolSum + bearVolSum
flowPct = totalVolSum > 0 ? math.round(math.max(bullVolSum, bearVolSum) / totalVolSum * 100) : 50
flowDir = totalVolSum > 0 ? (bullVolSum > bearVolSum ? 1 : -1) : 0
// ============================================================================
// ORDER BLOCKS
// ============================================================================
var array<OBLevel> obLevels = array.new<OBLevel>()
atr14 = ta.atr(14)
displacement = atr14 * obDispMult
if close - close[1] > displacement and close[1] < open[1]
array.unshift(obLevels, OBLevel.new(bar_index - 1, high[1], low[1], "BULLISH", false))
if array.size(obLevels) > maxOBs * 2
array.pop(obLevels)
if close[1] - close > displacement and close[1] > open[1]
array.unshift(obLevels, OBLevel.new(bar_index - 1, high[1], low[1], "BEARISH", false))
if array.size(obLevels) > maxOBs * 2
array.pop(obLevels)
for ob in obLevels
if not ob.mitigated
if ob.obType == "BULLISH" and low < ob.lo
ob.mitigated := true
else if ob.obType == "BEARISH" and high > ob.hi
ob.mitigated := true
activeOBs() =>
result = array.new<OBLevel>()
count = 0
for ob in obLevels
if not ob.mitigated and count < maxOBs
array.push(result, ob)
count += 1
result
// ============================================================================
// FAIR VALUE GAPS
// ============================================================================
var array<FVGLevel> fvgLevels = array.new<FVGLevel>()
if low > high[2]
array.unshift(fvgLevels, FVGLevel.new(bar_index - 1, low, high[2], "BULLISH", false))
if array.size(fvgLevels) > maxFVGs * 2
array.pop(fvgLevels)
if high < low[2]
array.unshift(fvgLevels, FVGLevel.new(bar_index - 1, low[2], high, "BEARISH", false))
if array.size(fvgLevels) > maxFVGs * 2
array.pop(fvgLevels)
for fvg in fvgLevels
if not fvg.filled
if fvg.fvgType == "BULLISH" and low <= fvg.hi
fvg.filled := true
else if fvg.fvgType == "BEARISH" and high >= fvg.lo
fvg.filled := true
unfilledFVGs() =>
result = array.new<FVGLevel>()
count = 0
for fvg in fvgLevels
if not fvg.filled and count < maxFVGs
array.push(result, fvg)
count += 1
result
// ============================================================================
// EQUAL HIGHS / LOWS + SWEEP + RECLAIM
// ============================================================================
var array<LiqLevel> equalHighs = array.new<LiqLevel>()
var array<LiqLevel> equalLows = array.new<LiqLevel>()
tolerance = close * eqlTolerance / 100
swingHigh = ta.pivothigh(high, liqLookback, liqLookback)
swingLow = ta.pivotlow(low, liqLookback, liqLookback)
if not na(swingHigh)
found = false
for lvl in equalHighs
if math.abs(lvl.price - swingHigh) <= tolerance
lvl.touchCount += 1
lvl.lastBar := bar_index
found := true
break
if not found
array.push(equalHighs, LiqLevel.new(swingHigh, bar_index, 1, false, 0, false, ""))
if array.size(equalHighs) > 20
array.shift(equalHighs)
if not na(swingLow)
found = false
for lvl in equalLows
if math.abs(lvl.price - swingLow) <= tolerance
lvl.touchCount += 1
lvl.lastBar := bar_index
found := true
break
if not found
array.push(equalLows, LiqLevel.new(swingLow, bar_index, 1, false, 0, false, ""))
if array.size(equalLows) > 20
array.shift(equalLows)
// Sweep + Reclaim detection
sweepReclaimBull = false
sweepReclaimBear = false
for lvl in equalHighs
if not lvl.swept and lvl.touchCount >= 2 and high > lvl.price
lvl.swept := true
lvl.sweepBar := bar_index
if lvl.swept and not lvl.reclaimed and bar_index > lvl.sweepBar and bar_index <= lvl.sweepBar + reclaimBars and close < lvl.price
lvl.reclaimed := true
lvl.reclaimDir := "BEARISH"
sweepReclaimBear := true
for lvl in equalLows
if not lvl.swept and lvl.touchCount >= 2 and low < lvl.price
lvl.swept := true
lvl.sweepBar := bar_index
if lvl.swept and not lvl.reclaimed and bar_index > lvl.sweepBar and bar_index <= lvl.sweepBar + reclaimBars and close > lvl.price
lvl.reclaimed := true
lvl.reclaimDir := "BULLISH"
sweepReclaimBull := true
// ============================================================================
// SESSION CONTEXT
// ============================================================================
curHour = hour(time, sessionTZ)
isAsia = curHour >= asiaStartH and curHour < asiaEndH
isLondonKZ = curHour >= londonKZStartH and curHour < londonKZEndH
isNYKZ = curHour >= nyKZStartH and curHour < nyKZEndH
isKillZone = isLondonKZ or isNYKZ
var float asiaHigh = na
var float asiaLow = na
var int asiaBarStart = na
if isAsia
if not isAsia[1]
asiaHigh := high
asiaLow := low
asiaBarStart := bar_index
else
asiaHigh := math.max(asiaHigh, high)
asiaLow := math.min(asiaLow, low)
sessionName = isNYKZ ? "NY Kill Zone" :
isLondonKZ ? "London KZ" :
isAsia ? "Asia" :
curHour >= asiaEndH and curHour < londonKZStartH ? "Pre-London" :
curHour >= londonKZEndH and curHour < nyKZStartH ? "London" :
curHour >= nyKZEndH ? "NY" : "Off-Hours"
// ============================================================================
// MULTI-TIMEFRAME CONFLUENCE
// ============================================================================
f_htfData() =>
[close, open, ta.atr(14), ta.ema(close, 21)]
[htfC, htfO, htfATR14, htfEMA21] = request.security(syminfo.tickerid, htfTimeframe,
f_htfData(), lookahead=barmerge.lookahead_off)
htfTrend = enableHTF ? (nz(htfC) > nz(htfEMA21) ? 1 : -1) : 0
htfHasDisp = math.abs(nz(htfC) - nz(htfO)) > nz(htfATR14) * 1.0
htfDispDir = enableHTF and htfHasDisp ? (htfC > htfO ? 1 : -1) : 0
// ============================================================================
// NEAREST LEVEL CALCULATION
// ============================================================================
curActiveOBs = activeOBs()
curFVGs = unfilledFVGs()
nearestOBDist = 999.0
nearestOBType = ""
if array.size(curActiveOBs) > 0
for i = 0 to array.size(curActiveOBs) - 1
ob = array.get(curActiveOBs, i)
mid = (ob.hi + ob.lo) / 2
dist = math.abs(close - mid)
if atr14 > 0 and dist / atr14 < nearestOBDist
nearestOBDist := dist / atr14
nearestOBType := ob.obType
nearestFVGDist = 999.0
nearestFVGType = ""
if array.size(curFVGs) > 0
for i = 0 to array.size(curFVGs) - 1
fvg = array.get(curFVGs, i)
mid = (fvg.hi + fvg.lo) / 2
dist = math.abs(close - mid)
if atr14 > 0 and dist / atr14 < nearestFVGDist
nearestFVGDist := dist / atr14
nearestFVGType := fvg.fvgType
nearestLiqUpDist = 999.0
for lvl in equalHighs
if not lvl.swept and lvl.touchCount >= 2
dist = math.abs(close - lvl.price)
if atr14 > 0 and dist / atr14 < nearestLiqUpDist
nearestLiqUpDist := dist / atr14
nearestLiqDnDist = 999.0
for lvl in equalLows
if not lvl.swept and lvl.touchCount >= 2
dist = math.abs(close - lvl.price)
if atr14 > 0 and dist / atr14 < nearestLiqDnDist
nearestLiqDnDist := dist / atr14
// ============================================================================
// DIRECTIONAL BIAS SCORING (-100 to +100)
// ============================================================================
bias = 0.0
// CVD trend (weight: 20)
if enableCVD
bias += cvdTrend == 1 ? 20.0 : -20.0
// Divergence override (weight: 15)
if bearishDiv
bias -= 15.0
if bullishDiv
bias += 15.0
// Flow imbalance (weight: 10)
if flowDir != 0 and flowPct >= 60
bias += flowDir == 1 ? 10.0 : -10.0
// OB proximity (weight: 15)
if nearestOBDist < 2.0
bias += nearestOBType == "BULLISH" ? 15.0 : -15.0
// FVG proximity (weight: 10)
if nearestFVGDist < 2.0
bias += nearestFVGType == "BULLISH" ? 10.0 : -10.0
// Sweep + reclaim (weight: 15)
if sweepReclaimBull
bias += 15.0
if sweepReclaimBear
bias -= 15.0
// Kill zone amplifier
if isKillZone
bias *= 1.1
// HTF alignment (weight: 15)
if enableHTF and htfTrend != 0
bias += htfTrend == 1 ? 10.0 : -10.0
if htfDispDir != 0
bias += htfDispDir == 1 ? 5.0 : -5.0
bias := math.max(-100.0, math.min(100.0, bias))
biasDirection = bias >= 25 ? "BULLISH" : bias <= -25 ? "BEARISH" : "NEUTRAL"
biasStrength = math.abs(bias)
// ============================================================================
// SIGNAL GENERATION
// ============================================================================
strongBullish = bias >= 50 and isKillZone
strongBearish = bias <= -50 and isKillZone
sweepEntry = (sweepReclaimBull and bias > 0) or (sweepReclaimBear and bias < 0)
// ============================================================================
// GLOBAL SCOPE VISUALS
// ============================================================================
bgcolor(enableCVD and showFlowBG ?
(cvdTrend == 1 ? color.new(color.green, 93) :
cvdTrend == -1 ? color.new(color.red, 93) : na) : na,
title="CVD Background")
bgcolor(enableSessions and isKillZone ? color.new(color.orange, 95) : na,
title="Kill Zone")
plotshape(sweepReclaimBull, "Sweep+Reclaim Bull", shape.labelup,
location.belowbar, #00bfa5, size=size.small, text="S+R", textcolor=color.white)
plotshape(sweepReclaimBear, "Sweep+Reclaim Bear", shape.labeldown,
location.abovebar, #e040fb, size=size.small, text="S+R", textcolor=color.white)
plotshape(enableCVD and bullishDiv, "Bull Divergence", shape.xcross,
location.belowbar, #0ea5e9, size=size.tiny)
plotshape(enableCVD and bearishDiv, "Bear Divergence", shape.xcross,
location.abovebar, #0ea5e9, size=size.tiny)
// ============================================================================
// VISUALIZATIONS - drawn on last bar
// ============================================================================
if barstate.islast
if enableOB and array.size(curActiveOBs) > 0
displayCount = math.min(array.size(curActiveOBs), maxOBs)
for i = 0 to displayCount - 1
ob = array.get(curActiveOBs, i)
obCol = ob.obType == "BULLISH" ? color.new(color.green, 75) : color.new(color.red, 75)
box.new(ob.barIdx, ob.hi, bar_index + 10, ob.lo,
border_color=obCol, bgcolor=obCol, border_width=2, extend=extend.right)
labelText = ob.obType == "BULLISH" ? "OB+" : "OB-"
label.new(ob.barIdx, ob.obType == "BULLISH" ? ob.lo : ob.hi, labelText,
color=obCol, textcolor=color.white,
style=ob.obType == "BULLISH" ? label.style_label_up : label.style_label_down,
size=size.small)
if enableFVG and array.size(curFVGs) > 0
displayCount = math.min(array.size(curFVGs), maxFVGs)
for i = 0 to displayCount - 1
fvg = array.get(curFVGs, i)
fvgCol = fvg.fvgType == "BULLISH" ? color.new(color.blue, 85) : color.new(color.orange, 85)
box.new(fvg.barIdx, fvg.hi, bar_index + 10, fvg.lo,
border_color=fvgCol, bgcolor=fvgCol, border_width=1,
border_style=line.style_dashed, extend=extend.right)
label.new(fvg.barIdx, fvg.fvgType == "BULLISH" ? fvg.lo : fvg.hi, "FVG",
color=fvgCol, textcolor=color.white,
style=fvg.fvgType == "BULLISH" ? label.style_label_up : label.style_label_down,
size=size.tiny)
if enableLiq
if array.size(equalHighs) > 0
for i = 0 to math.min(array.size(equalHighs) - 1, 4)
lvl = array.get(equalHighs, i)
if lvl.touchCount >= 2 and not lvl.swept
line.new(lvl.lastBar - liqLookback, lvl.price, bar_index + 5, lvl.price,
color=color.new(color.red, 50), style=line.style_dashed, width=1)
if array.size(equalLows) > 0
for i = 0 to math.min(array.size(equalLows) - 1, 4)
lvl = array.get(equalLows, i)
if lvl.touchCount >= 2 and not lvl.swept
line.new(lvl.lastBar - liqLookback, lvl.price, bar_index + 5, lvl.price,
color=color.new(color.green, 50), style=line.style_dashed, width=1)
if enableSessions and showAsiaRange and not na(asiaHigh) and not na(asiaLow) and not na(asiaBarStart)
box.new(math.max(asiaBarStart, bar_index - 500), asiaHigh, bar_index, asiaLow,
border_color=color.new(color.blue, 60), bgcolor=color.new(color.blue, 92),
border_width=1, border_style=line.style_dotted, text="Asia Range",
text_color=color.new(color.blue, 40), text_size=size.tiny)
// ============================================================================
// DASHBOARD
// ============================================================================
if showDashboard and barstate.islast
var table dash = table.new(position.top_right, 3, 14,
border_width=1, border_color=color.new(color.gray, 50),
frame_width=1, frame_color=color.new(color.gray, 70))
// Row 0: Header
biasCol = biasDirection == "BULLISH" ? color.new(color.green, 20) :
biasDirection == "BEARISH" ? color.new(color.red, 20) : color.new(color.gray, 40)
table.cell(dash, 0, 0, "SMART MONEY",
text_color=color.white, bgcolor=biasCol,
text_size=size.normal, text_halign=text.align_center)
table.merge_cells(dash, 0, 0, 2, 0)
// Row 1: Directional Bias
table.cell(dash, 0, 1, "Bias", text_color=color.gray, text_size=size.small)
biasText = biasDirection + " " + str.tostring(math.round(bias))
table.cell(dash, 1, 1, biasText,
text_color=bias >= 25 ? color.lime : bias <= -25 ? color.red : color.gray,
text_size=size.small)
table.merge_cells(dash, 1, 1, 2, 1)
// Row 2: CVD
cvdText = cvdTrend == 1 ? "RISING" : "FALLING"
divText = bearishDiv ? " [DIV]" : bullishDiv ? " [DIV]" : ""
table.cell(dash, 0, 2, "CVD", text_color=color.gray, text_size=size.small)
table.cell(dash, 1, 2, cvdText + divText,
text_color=cvdTrend == 1 ? color.lime : color.red,
text_size=size.small)
table.merge_cells(dash, 1, 2, 2, 2)
// Row 3: Flow
table.cell(dash, 0, 3, "Flow", text_color=color.gray, text_size=size.small)
table.cell(dash, 1, 3, str.tostring(flowPct) + "% " + (flowDir == 1 ? "BUY" : "SELL"),
text_color=flowDir == 1 ? color.lime : color.red,
text_size=size.small)
table.merge_cells(dash, 1, 3, 2, 3)
// Row 4: Separator
table.cell(dash, 0, 4, "", bgcolor=color.new(color.gray, 80))
table.merge_cells(dash, 0, 4, 2, 4)
// Row 5: Nearest OB
table.cell(dash, 0, 5, "OB", text_color=color.gray, text_size=size.small)
if nearestOBDist < 999.0
obDistText = (nearestOBType == "BULLISH" ? "+" : "-") + " " + str.tostring(nearestOBDist, "#.#") + " ATR"
table.cell(dash, 1, 5, obDistText,
text_color=nearestOBType == "BULLISH" ? color.lime : color.red,
text_size=size.small)
else
table.cell(dash, 1, 5, "None", text_color=color.new(color.gray, 50), text_size=size.small)
table.merge_cells(dash, 1, 5, 2, 5)
// Row 6: Nearest FVG
table.cell(dash, 0, 6, "FVG", text_color=color.gray, text_size=size.small)
if nearestFVGDist < 999.0
fvgDistText = (nearestFVGType == "BULLISH" ? "+" : "-") + " " + str.tostring(nearestFVGDist, "#.#") + " ATR"
table.cell(dash, 1, 6, fvgDistText,
text_color=nearestFVGType == "BULLISH" ? color.lime : color.red,
text_size=size.small)
else
table.cell(dash, 1, 6, "None", text_color=color.new(color.gray, 50), text_size=size.small)
table.merge_cells(dash, 1, 6, 2, 6)
// Row 7: Nearest Liquidity
table.cell(dash, 0, 7, "Liq", text_color=color.gray, text_size=size.small)
liqText = ""
liqColor = color.gray
if nearestLiqUpDist < nearestLiqDnDist and nearestLiqUpDist < 999.0
liqText := "EQH " + str.tostring(nearestLiqUpDist, "#.#") + " ATR"
liqColor := color.red
else if nearestLiqDnDist < 999.0
liqText := "EQL " + str.tostring(nearestLiqDnDist, "#.#") + " ATR"
liqColor := color.green
else
liqText := "None"
table.cell(dash, 1, 7, liqText, text_color=liqColor, text_size=size.small)
table.merge_cells(dash, 1, 7, 2, 7)
// Row 8: Sweep+Reclaim
table.cell(dash, 0, 8, "S+R", text_color=color.gray, text_size=size.small)
srText = sweepReclaimBull ? "BULL RECLAIM" : sweepReclaimBear ? "BEAR RECLAIM" : "---"
srCol = sweepReclaimBull ? color.lime : sweepReclaimBear ? color.red : color.new(color.gray, 50)
table.cell(dash, 1, 8, srText, text_color=srCol, text_size=size.small)
table.merge_cells(dash, 1, 8, 2, 8)
// Row 9: Separator
table.cell(dash, 0, 9, "", bgcolor=color.new(color.gray, 80))
table.merge_cells(dash, 0, 9, 2, 9)
// Row 10: Session
table.cell(dash, 0, 10, "Session", text_color=color.gray, text_size=size.small)
sessCol = isKillZone ? color.new(color.orange, 20) : color.new(color.gray, 60)
table.cell(dash, 1, 10, sessionName,
text_color=color.white, bgcolor=sessCol,
text_size=size.small, text_halign=text.align_center)
table.merge_cells(dash, 1, 10, 2, 10)
// Row 11: HTF
if enableHTF
htfText = htfTrend == 1 ? "BULL" : "BEAR"
htfDispText = htfDispDir == 1 ? " [DISP+]" : htfDispDir == -1 ? " [DISP-]" : ""
table.cell(dash, 0, 11, "HTF " + htfTimeframe, text_color=color.gray, text_size=size.small)
table.cell(dash, 1, 11, htfText + htfDispText,
text_color=htfTrend == 1 ? color.lime : color.red,
text_size=size.small)
else
table.cell(dash, 0, 11, "", text_size=size.tiny)
table.cell(dash, 1, 11, "", text_size=size.tiny)
table.merge_cells(dash, 1, 11, 2, 11)
// Row 12: Separator
table.cell(dash, 0, 12, "", bgcolor=color.new(color.gray, 80))
table.merge_cells(dash, 0, 12, 2, 12)
// Row 13: Signal
signal = strongBullish ? "LONG SETUP" :
strongBearish ? "SHORT SETUP" :
sweepEntry ? "SWEEP ENTRY" :
biasStrength >= 50 ? "BUILDING" : "NO SETUP"
sigCol = strongBullish ? color.new(color.green, 20) :
strongBearish ? color.new(color.red, 20) :
sweepEntry ? color.new(color.purple, 20) :
biasStrength >= 50 ? color.new(color.yellow, 40) : color.new(color.gray, 60)
table.cell(dash, 0, 13, "Signal", text_color=color.gray, text_size=size.small)
table.cell(dash, 1, 13, signal,
text_color=color.white, bgcolor=sigCol,
text_size=size.normal, text_halign=text.align_center)
table.merge_cells(dash, 1, 13, 2, 13)
// ============================================================================
// ALERTS
// ============================================================================
alertcondition(strongBullish and not strongBullish[1],
"Strong Bullish Setup", "Smart Money: Strong bullish setup in kill zone")
alertcondition(strongBearish and not strongBearish[1],
"Strong Bearish Setup", "Smart Money: Strong bearish setup in kill zone")
alertcondition(sweepReclaimBull,
"Bullish Sweep Reclaim", "Smart Money: Bullish sweep and reclaim detected")
alertcondition(sweepReclaimBear,
"Bearish Sweep Reclaim", "Smart Money: Bearish sweep and reclaim detected")
alertcondition(bearishDiv and not bearishDiv[1],
"Bearish CVD Divergence", "Smart Money: Bearish CVD divergence at high")
alertcondition(bullishDiv and not bullishDiv[1],
"Bullish CVD Divergence", "Smart Money: Bullish CVD divergence at low")
Overview
Smart Money Dashboard analyzes Cumulative Volume Delta for divergence and combines multi-timeframe structure with session kill zones to derive a directional bias score. Inputs allow full customization of module settings, timeframes, and visual displays. Designed as an overlay dashboard, its volume delta metrics rely on available broker volume data.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Enable CVD Analysis
bool
true
enableCVD
CVD EMA Length
int
20
cvdLen
Divergence Lookback
int
20
divLookback
Show Order Blocks
bool
true
enableOB
Show Fair Value Gaps
bool
true
enableFVG
Max Order Blocks
int
5
maxOBs
Max FVGs
int
3
maxFVGs
OB Displacement ATR x
float
1.2
obDispMult
Show Equal Highs/Lows
bool
true
enableLiq
Pivot Lookback
int
15
liqLookback
Equal Level Tolerance %
float
0.05
eqlTolerance
Reclaim Window (bars)
int
5
reclaimBars
Show all 25 settings
Setting
Type
Default
Variable
Show Session Context
bool
true
enableSessions
Timezone
string
UTC
sessionTZ
Asia Start Hour
int
0
asiaStartH
Asia End Hour
int
8
asiaEndH
London KZ Start
int
7
londonKZStartH
London KZ End
int
10
londonKZEndH
NY KZ Start
int
12
nyKZStartH
NY KZ End
int
15
nyKZEndH
Enable HTF Confluence
bool
true
enableHTF
HTF Timeframe
timeframe
240
htfTimeframe
Show Dashboard
bool
true
showDashboard
CVD Background
bool
true
showFlowBG
Show Asia Range
bool
true
showAsiaRange
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 runs a CRT state engine on the price chart. It can analyze draw-on-liquidity pivots, a session state machine, and optional 1AM, 5AM, and 9AM CRT models. Optional modules track market structure, liquidity pools, volume-profile levels, and
Indicatorv5SMC / ICT / price actionSessions & time
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
The indicator detects liquidity sweeps across key price levels and calculates a cumulative volume delta proxy. It uses pivot high and low lookbacks to identify swing points, marking sweeps when price breaks beyond a level and quickly closes back inside. Featur
This indicator detects and draws the first Fair Value Gap (FVG) that forms in each hourly session based on a selected lower timeframe, with specialized handling for Regular Trading Hours (RTH) confluence windows. It draws FVG range boxes, midpoint lines, hourl
This indicator identifies Break of Structure (BOS) and Market Structure Shift (MSS) zones, plotting automated bracket levels on the price chart. It triggers signals when a reversal breaks a swing point formed inside an opposing zone, projecting stop loss and t
Equity Intraday Analyst is a comprehensive intraday overlay indicator for US equities and ETFs. It evaluates multi-EMA ribbons, session-anchored VWAP bands, OBV trends, momentum oscillators, TTM Squeeze, and optional market breadth indicators like NYSE TICK an