// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © AlphaX
//@version=6
indicator("[ A L P H A X ] Structure Flow Pro", shorttitle="AlphaX SFP",
overlay=true, max_boxes_count=500, max_lines_count=500, max_labels_count=500, max_bars_back=500)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ INPUTS ═══════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// ── Market Structure ──────────────────────────────────────────────────────────
pivotLen = input.int(7, "Pivot Lookback", minval=3, maxval=21, group="Market Structure")
msbZScore = input.float(0.5, "MSB Momentum Z-Score", minval=0.1, maxval=3.0, step=0.1, group="Market Structure")
showMSB = input.bool(true, "Show MSB Lines & Labels", group="Market Structure")
showStructure = input.bool(true, "Show Structure Swings", group="Market Structure")
bmsEnabled = input.bool(true, "Detect Break of Market Structure (BMS)", group="Market Structure")
// ── Order Blocks ──────────────────────────────────────────────────────────────
obCount = input.int(10, "Max Active OBs", minval=1, maxval=100, group="Order Blocks")
obLookback = input.int(10, "OB Lookback (candles)", minval=3, maxval=20, group="Order Blocks")
extendBroken = input.bool(false, "Extend Broken OBs", group="Order Blocks")
hideOverlaps = input.bool(false, "Hide Overlapping OBs", group="Order Blocks")
obMode = input.string("Historical", "Display Mode",
options=["Historical","Present"], group="Order Blocks")
hpzThresh = input.float(75.0, "HPZ Threshold Score (%)", minval=50, maxval=95, step=5, group="Order Blocks")
showPOC = input.bool(true, "Show OB Point of Control", group="Order Blocks")
// ── Liquidity & Imbalance ─────────────────────────────────────────────────────
showFVG = input.bool(true, "Show Fair Value Gaps (FVG)", group="Liquidity & Imbalance")
fvgMinSize = input.float(0.05, "Min FVG Size (ATR × factor)", minval=0.01, maxval=1.0, step=0.01, group="Liquidity & Imbalance")
showLiqSweep = input.bool(true, "Show Liquidity Sweeps", group="Liquidity & Imbalance")
sweepLookback = input.int(20, "Sweep Lookback (bars)", minval=5, maxval=50, group="Liquidity & Imbalance")
showEQL = input.bool(true, "Show Equal Highs / Lows", group="Liquidity & Imbalance")
eqlTolerance = input.float(0.1, "EQL Tolerance (ATR × factor)", minval=0.01, maxval=0.5, step=0.01, group="Liquidity & Imbalance")
// ── Smart Money Confluence (SMC) ─────────────────────────────────────────────
smcEnabled = input.bool(true, "Enable SMC Confluence Engine", group="Smart Money Confluence")
minSMCScore = input.int(30, "Min SMC Score to Signal", minval=10, maxval=80, group="Smart Money Confluence")
cooldownBars = input.int(3, "Signal Cooldown (bars)", minval=1, maxval=20, group="Smart Money Confluence")
useVolFilter = input.bool(false, "Require Volume Confirmation", group="Smart Money Confluence")
volMinRatio = input.float(0.7, "Min Volume Ratio", minval=0.3, maxval=2.0, step=0.1, group="Smart Money Confluence")
// ── Sessions ──────────────────────────────────────────────────────────────────
showSessions = input.bool(true, "Show Session Ranges", group="Sessions")
showLondon = input.bool(false, "London Session", group="Sessions")
londonSess = input.session("0800-1700:1234567", "London Time", group="Sessions")
londonCol = input.color(#3b82f6, "London Color", group="Sessions", inline="London")
showNY = input.bool(false, "New York Session", group="Sessions")
nySess = input.session("1300-2200:1234567", "New York Time", group="Sessions")
nyCol = input.color(#f97316, "New York Color", group="Sessions", inline="NY")
showTokyo = input.bool(false, "Tokyo Session", group="Sessions")
tokyoSess = input.session("0000-0900:1234567", "Tokyo Time", group="Sessions")
tokyoCol = input.color(#f43f5e, "Tokyo Color", group="Sessions", inline="Tokyo")
showSydney = input.bool(false, "Sydney Session", group="Sessions")
sydneySess = input.session("2100-0600:1234567", "Sydney Time", group="Sessions")
sydneyCol = input.color(#eab308, "Sydney Color", group="Sessions", inline="Sydney")
// ── Dashboard ─────────────────────────────────────────────────────────────────
showDash = input.bool(true, "Show Dashboard", group="Dashboard")
dashPos = input.string("Top Right", "Position",
options=["Top Left","Top Right","Bottom Left","Bottom Right"], group="Dashboard")
dashSizeInp = input.string("Small", "Size",
options=["Tiny","Small","Normal","Large"], group="Dashboard")
// ── Appearance ────────────────────────────────────────────────────────────────
labelSizeInp = input.string("Small", "Label Size",
options=["Tiny","Small","Normal"], group="Appearance")
// ── Colors ────────────────────────────────────────────────────────────────────
colBullPrimary = input.color(#c8e624, "Bull Primary", group="Colors")
colBullBright = input.color(#d4f03a, "Bull Bright", group="Colors")
colBullDim = input.color(#9ab81c, "Bull Dim", group="Colors")
colBearPrimary = input.color(#ff1744, "Bear Primary", group="Colors")
colBearBright = input.color(#ff5252, "Bear Bright", group="Colors")
colBearDim = input.color(#d50032, "Bear Dim", group="Colors")
colNeutral = input.color(#555555, "Neutral", group="Colors")
colNeutralLight = input.color(#888888, "Neutral Light", group="Colors")
colTextLight = input.color(#cccccc, "Text Light", group="Colors")
colDashBg = input.color(#1a1a1a, "Dashboard Background",group="Colors")
colFVGBull = input.color(#c8e624, "FVG Bull Color", group="Colors")
colFVGBear = input.color(#ff1744, "FVG Bear Color", group="Colors")
colSweep = input.color(color.rgb(40, 41, 40, 19), "Liquidity Sweep", group="Colors")
colEQL = input.color(#9c27b0, "Equal Hi/Lo", group="Colors")
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ TYPE DEFINITIONS ══════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
type OrderBlock
box boxId
label labelId
line pocLineId
float qualityScore
float top
float bottom
bool isBull
bool isHPZ
bool mitigated
int mitigationBar
int birthBar
type FVG
box boxId
float top
float bottom
bool isBull
bool filled
int birthBar
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ HELPERS ══════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
getLabelSize(sz) =>
switch sz
"Tiny" => size.tiny
"Small" => size.small
"Normal" => size.normal
=> size.small
getDashSize(sz) =>
switch sz
"Tiny" => size.tiny
"Small" => size.small
"Normal" => size.normal
"Large" => size.large
=> size.small
getDashPos(p) =>
switch p
"Top Left" => position.top_left
"Top Right" => position.top_right
"Bottom Left" => position.bottom_left
"Bottom Right" => position.bottom_right
=> position.top_right
labelSize = getLabelSize(labelSizeInp)
dashTextSize = getDashSize(dashSizeInp)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ CORE CALCULATIONS ════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
atrVal = ta.atr(14)
float priceChange = ta.change(close)
float avgChange = ta.sma(priceChange, 50)
float stdChange = ta.stdev(priceChange, 50)
float momentumZ = stdChange > 0 ? (priceChange - avgChange) / stdChange : 0.0
float volPercent = ta.percentrank(volume, 100)
volSMA = ta.sma(volume, 20)
volRatio = volSMA > 0 ? volume / volSMA : 1.0
volOK = not useVolFilter or volRatio >= volMinRatio
// Candle metrics
candleBody = math.abs(close - open)
candleRange = high - low
bodyRatio = candleRange > 0 ? candleBody / candleRange : 0.0
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ PIVOT DETECTION ══════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
float ph = ta.pivothigh(high, pivotLen, pivotLen)
float pl = ta.pivotlow(low, pivotLen, pivotLen)
var float lastPh = na
var float lastPl = na
var int lastPhIdx = na
var int lastPlIdx = na
// Swing tracking for structure drawing
var float prevSwingHigh = na
var float prevSwingLow = na
var int prevSwingHighIdx = na
var int prevSwingLowIdx = na
var float currSwingHigh = na
var float currSwingLow = na
var int currSwingHighIdx = na
var int currSwingLowIdx = na
if not na(ph)
prevSwingHigh := currSwingHigh
prevSwingHighIdx := currSwingHighIdx
currSwingHigh := ph
currSwingHighIdx := bar_index - pivotLen
lastPh := ph
lastPhIdx := bar_index - pivotLen
if not na(pl)
prevSwingLow := currSwingLow
prevSwingLowIdx := currSwingLowIdx
currSwingLow := pl
currSwingLowIdx := bar_index - pivotLen
lastPl := pl
lastPlIdx := bar_index - pivotLen
// ── Structure Swing Lines ────────────────────────────────────────────────────
if showStructure and not na(ph) and not na(prevSwingHigh) and not na(prevSwingHighIdx)
line.new(prevSwingHighIdx, prevSwingHigh, bar_index - pivotLen, ph,
color=color.new(colBearDim, 60), style=line.style_dotted, width=1)
if showStructure and not na(pl) and not na(prevSwingLow) and not na(prevSwingLowIdx)
line.new(prevSwingLowIdx, prevSwingLow, bar_index - pivotLen, pl,
color=color.new(colBullDim, 60), style=line.style_dotted, width=1)
// ── Swing High/Low Labels ────────────────────────────────────────────────────
if showStructure and not na(ph)
label.new(bar_index - pivotLen, ph, "H",
style=label.style_label_down, color=color.new(colBearDim, 80),
textcolor=colBearDim, size=size.tiny, yloc=yloc.price)
if showStructure and not na(pl)
label.new(bar_index - pivotLen, pl, "L",
style=label.style_label_up, color=color.new(colBullDim, 80),
textcolor=colBullDim, size=size.tiny, yloc=yloc.price)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ MARKET STRUCTURE BREAK ═══════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
bool isMSBBull = not na(lastPh) and close > lastPh and close[1] <= lastPh and momentumZ > msbZScore
bool isMSBBear = not na(lastPl) and close < lastPl and close[1] >= lastPl and momentumZ < -msbZScore
// Break of Market Structure (confirmed with body close)
bool isBMSBull = bmsEnabled and not na(lastPh) and close > lastPh and close[1] <= lastPh and candleBody / candleRange > 0.5
bool isBMSBear = bmsEnabled and not na(lastPl) and close < lastPl and close[1] >= lastPl and candleBody / candleRange > 0.5
if showMSB and isMSBBull and not na(lastPhIdx)
int mid = math.round(math.avg(lastPhIdx, bar_index))
line.new(lastPhIdx, lastPh, bar_index, lastPh,
color=color.new(colBullPrimary, 0), width=2)
label.new(mid, lastPh, "MSB ▲",
color=color.new(colBullPrimary, 100),
textcolor=colBullPrimary,
style=label.style_label_down, size=labelSize)
if showMSB and isMSBBear and not na(lastPlIdx)
int mid = math.round(math.avg(lastPlIdx, bar_index))
line.new(lastPlIdx, lastPl, bar_index, lastPl,
color=color.new(colBearPrimary, 0), width=2)
label.new(mid, lastPl, "MSB ▼",
color=color.new(colBearPrimary, 100),
textcolor=colBearPrimary,
style=label.style_label_up, size=labelSize)
// BMS is a stronger label
if showMSB and isBMSBull and not isMSBBull and not na(lastPhIdx)
label.new(bar_index, lastPh, "BMS",
color=color.new(colBullBright, 85),
textcolor=colBullBright,
style=label.style_label_down, size=size.tiny)
if showMSB and isBMSBear and not isMSBBear and not na(lastPlIdx)
label.new(bar_index, lastPl, "BMS",
color=color.new(colBearBright, 85),
textcolor=colBearBright,
style=label.style_label_up, size=size.tiny)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ ORDER BLOCK ENGINE ════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
var obArray = array.new<OrderBlock>()
// Mitigation stats
var float totalMitigated = 0.0
var float totalOBs = 0.0
if isMSBBull or isMSBBear
int obIdx = 0
for i = 1 to obLookback
if (isMSBBull and close[i] < open[i]) or (isMSBBear and close[i] > open[i])
obIdx := i
break
if obIdx > 0
float obTop = high[obIdx]
float obBottom = low[obIdx]
float obPOC = math.avg(obTop, obBottom)
float obSize = obTop - obBottom
// Enhanced Quality Score (0-100)
// Factors: momentum strength, volume, body ratio, ob size relative to ATR, z-score magnitude
float baseScore = math.min(100.0,
(math.abs(momentumZ) * 15.0) +
(volPercent * 0.4) +
(bodyRatio * 20.0) +
(obSize / atrVal * 10.0))
float score = math.max(0.0, math.min(100.0, baseScore))
bool isHPZ = score >= hpzThresh
color baseColor = isMSBBull ? colBullPrimary : colBearPrimary
color hpzColor = isMSBBull ? colBullBright : colBearBright
// Overlap check
bool overlapping = false
if hideOverlaps and obArray.size() > 0
for i = 0 to obArray.size() - 1
OrderBlock o = obArray.get(i)
if not o.mitigated
if (obTop <= o.top and obTop >= o.bottom) or (obBottom <= o.top and obBottom >= o.bottom)
overlapping := true
break
if not overlapping
box obBox = na
label obLabel = na
line obPoc = na
if isHPZ
obBox := box.new(bar_index[obIdx], obTop, bar_index + 20, obBottom,
border_color=color.new(hpzColor, 30),
bgcolor=color.new(hpzColor, 82),
border_width=1, border_style=line.style_dashed)
if showPOC
obPoc := line.new(bar_index[obIdx], obPOC, bar_index + 20, obPOC,
color=color.new(hpzColor, 35), width=1, style=line.style_dashed)
else
obBox := box.new(bar_index[obIdx], obTop, bar_index + 20, obBottom,
border_color=color.new(baseColor, 55),
bgcolor=color.new(baseColor, 88),
border_style=line.style_dashed, border_width=1)
if showPOC
obPoc := line.new(bar_index[obIdx], obPOC, bar_index + 20, obPOC,
color=color.new(baseColor, 65), style=line.style_dashed, width=1)
string scoreLabel = str.tostring(score, "#") + "%" + (isHPZ ? " ⬡HPZ" : "")
obLabel := label.new(bar_index + 22, obPOC, scoreLabel,
color=color.new(baseColor, 100),
textcolor=isHPZ ? hpzColor : baseColor,
style=label.style_none, size=size.tiny, textalign=text.align_left)
OrderBlock newOB = OrderBlock.new(
obBox, obLabel, obPoc,
score, obTop, obBottom,
isMSBBull, isHPZ, false, 0, bar_index[obIdx])
obArray.push(newOB)
totalOBs += 1.0
if isMSBBull
lastPh := na
else
lastPl := na
// ── OB Dynamic Management ────────────────────────────────────────────────────
if obArray.size() > 0
for i = obArray.size() - 1 to 0
OrderBlock ob = obArray.get(i)
if not ob.mitigated
ob.boxId.set_right(bar_index + 20)
ob.labelId.set_x(bar_index + 22)
if showPOC and not na(ob.pocLineId)
ob.pocLineId.set_x2(bar_index + 20)
bool isMitigated = ob.isBull ? low < ob.bottom : high > ob.top
if isMitigated
ob.mitigated := true
ob.mitigationBar := bar_index
totalMitigated += 1.0
if obMode == "Present"
ob.boxId.delete()
ob.labelId.delete()
if not na(ob.pocLineId)
ob.pocLineId.delete()
else
ob.boxId.set_bgcolor(color.new(colNeutral, 90))
ob.boxId.set_border_color(color.new(colNeutral, 70))
ob.labelId.set_textcolor(color.new(colNeutral, 50))
if not na(ob.pocLineId)
ob.pocLineId.set_color(color.new(colNeutral, 80))
ob.boxId.set_right(bar_index)
ob.labelId.set_x(bar_index)
if not na(ob.pocLineId)
ob.pocLineId.set_x2(bar_index)
else
bool shouldExtend = extendBroken and (bar_index - ob.mitigationBar <= 50)
if obMode == "Present"
ob.boxId.delete()
ob.labelId.delete()
if not na(ob.pocLineId)
ob.pocLineId.delete()
else if shouldExtend
ob.boxId.set_right(bar_index + 20)
ob.labelId.set_x(bar_index + 22)
if not na(ob.pocLineId)
ob.pocLineId.set_x2(bar_index + 20)
if obArray.size() > obCount
OrderBlock oldOB = obArray.shift()
oldOB.boxId.delete()
oldOB.labelId.delete()
if not na(oldOB.pocLineId)
oldOB.pocLineId.delete()
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ FAIR VALUE GAPS ══════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
var fvgArray = array.new<FVG>()
// Detect FVG on bar_index - 1 (middle candle)
float fvgMinSz = atrVal * fvgMinSize
// Bullish FVG: gap between high[2] and low[0] — price ran up fast
bool bullFVG = low > high[2] and (low - high[2]) >= fvgMinSz
// Bearish FVG: gap between low[2] and high[0]
bool bearFVG = high < low[2] and (low[2] - high) >= fvgMinSz
if showFVG and bullFVG
float top = low
float bottom = high[2]
box b = box.new(bar_index - 2, top, bar_index + 30, bottom,
border_color=color.new(colFVGBull, 50),
bgcolor=color.new(colFVGBull, 91),
border_width=1, border_style=line.style_dotted)
fvgArray.push(FVG.new(b, top, bottom, true, false, bar_index))
if showFVG and bearFVG
float top = low[2]
float bottom = high
box b = box.new(bar_index - 2, top, bar_index + 30, bottom,
border_color=color.new(colFVGBear, 50),
bgcolor=color.new(colFVGBear, 91),
border_width=1, border_style=line.style_dotted)
fvgArray.push(FVG.new(b, top, bottom, false, false, bar_index))
// Extend and fill FVGs
if showFVG and fvgArray.size() > 0
for i = fvgArray.size() - 1 to 0
FVG fvg = fvgArray.get(i)
if not fvg.filled
fvg.boxId.set_right(bar_index + 30)
// Filled when price trades into the gap
bool filled = fvg.isBull ? low <= fvg.top : high >= fvg.bottom
if filled
fvg.filled := true
fvg.boxId.set_bgcolor(color.new(colNeutral, 93))
fvg.boxId.set_border_color(color.new(colNeutral, 75))
fvg.boxId.set_right(bar_index)
if fvgArray.size() > 50
FVG old = fvgArray.shift()
old.boxId.delete()
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ LIQUIDITY SWEEPS ═════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// A liquidity sweep: wick breaks previous high/low pivot then price reverses inside
var float sweepHigh = ta.highest(high, sweepLookback)
var float sweepLow = ta.lowest(low, sweepLookback)
// Bullish sweep: wick below recent low + close back above it
bool bullSweep = showLiqSweep and
low < ta.lowest(low[1], sweepLookback) and
close > ta.lowest(low[1], sweepLookback) and
close > open
// Bearish sweep: wick above recent high + close back below
bool bearSweep = showLiqSweep and
high > ta.highest(high[1], sweepLookback) and
close < ta.highest(high[1], sweepLookback) and
close < open
if bullSweep
label.new(bar_index, low,
text="⚡",
style=label.style_label_up,
color=color.new(colSweep, 0),
textcolor=colSweep,
size=labelSize,
yloc=yloc.belowbar)
if bearSweep
label.new(bar_index, high,
text="⚡",
style=label.style_label_down,
color=color.new(colSweep, 0),
textcolor=colSweep,
size=labelSize,
yloc=yloc.abovebar)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ EQUAL HIGHS / LOWS ═══════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
eqlTol = atrVal * eqlTolerance
if showEQL and not na(ph) and not na(prevSwingHigh)
if math.abs(ph - prevSwingHigh) <= eqlTol
line.new(prevSwingHighIdx, prevSwingHigh, bar_index - pivotLen, ph,
color=color.new(colEQL, 30), style=line.style_dotted, width=2)
label.new(math.round(math.avg(prevSwingHighIdx, bar_index - pivotLen)), ph,
"EQH", color=color.new(colEQL, 85), textcolor=colEQL,
style=label.style_label_down, size=size.tiny)
if showEQL and not na(pl) and not na(prevSwingLow)
if math.abs(pl - prevSwingLow) <= eqlTol
line.new(prevSwingLowIdx, prevSwingLow, bar_index - pivotLen, pl,
color=color.new(colEQL, 30), style=line.style_dotted, width=2)
label.new(math.round(math.avg(prevSwingLowIdx, bar_index - pivotLen)), pl,
"EQL", color=color.new(colEQL, 85), textcolor=colEQL,
style=label.style_label_up, size=size.tiny)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ SMC CONFLUENCE SCORING ══════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// Count active HPZ OBs nearby (within 2x ATR)
int nearBullHPZ = 0
int nearBearHPZ = 0
if obArray.size() > 0
for i = 0 to obArray.size() - 1
OrderBlock ob = obArray.get(i)
if not ob.mitigated and ob.isHPZ
if ob.isBull and close >= ob.bottom - atrVal * 2 and close <= ob.top + atrVal * 2
nearBullHPZ += 1
if not ob.isBull and close >= ob.bottom - atrVal * 2 and close <= ob.top + atrVal * 2
nearBearHPZ += 1
// Count unfilled FVGs below (bull) / above (bear) as draw-on-liquidity
int fvgBullBelow = 0
int fvgBearAbove = 0
if fvgArray.size() > 0
for i = 0 to fvgArray.size() - 1
FVG fvg = fvgArray.get(i)
if not fvg.filled
if fvg.isBull and fvg.top < close
fvgBullBelow += 1
if not fvg.isBull and fvg.bottom > close
fvgBearAbove += 1
calcBullSMC() =>
float s = 0.0
// MSB or BMS signal (core)
s += isMSBBull ? 30.0 : isBMSBull ? 20.0 : 0.0
// Liquidity sweep at lows (smart money accumulation)
s += bullSweep ? 20.0 : 0.0
// Near bullish HPZ OB
s += nearBullHPZ >= 2 ? 18.0 : nearBullHPZ == 1 ? 10.0 : 0.0
// FVG imbalance above as magnet
s += fvgBearAbove >= 2 ? 10.0 : fvgBearAbove == 1 ? 5.0 : 0.0
// Momentum Z-score confirmation
s += momentumZ > 2.0 ? 12.0 : momentumZ > 1.0 ? 7.0 : momentumZ > 0.5 ? 3.0 : 0.0
// Volume confirmation
s += volRatio > 2.0 ? 8.0 : volRatio > 1.3 ? 5.0 : volRatio > 1.0 ? 2.0 : 0.0
// Candle body
s += close > open and bodyRatio > 0.6 ? 6.0 : close > open ? 3.0 : 0.0
// Penalties
s -= momentumZ < -1.0 ? 10.0 : 0.0
s -= nearBearHPZ >= 2 ? 8.0 : 0.0
math.max(0.0, math.min(100.0, s))
calcBearSMC() =>
float s = 0.0
s += isMSBBear ? 30.0 : isBMSBear ? 20.0 : 0.0
s += bearSweep ? 20.0 : 0.0
s += nearBearHPZ >= 2 ? 18.0 : nearBearHPZ == 1 ? 10.0 : 0.0
s += fvgBullBelow >= 2 ? 10.0 : fvgBullBelow == 1 ? 5.0 : 0.0
s += momentumZ < -2.0 ? 12.0 : momentumZ < -1.0 ? 7.0 : momentumZ < -0.5 ? 3.0 : 0.0
s += volRatio > 2.0 ? 8.0 : volRatio > 1.3 ? 5.0 : volRatio > 1.0 ? 2.0 : 0.0
s += close < open and bodyRatio > 0.6 ? 6.0 : close < open ? 3.0 : 0.0
s -= momentumZ > 1.0 ? 10.0 : 0.0
s -= nearBullHPZ >= 2 ? 8.0 : 0.0
math.max(0.0, math.min(100.0, s))
bullSMC = smcEnabled ? calcBullSMC() : 0.0
bearSMC = smcEnabled ? calcBearSMC() : 0.0
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ SMC SIGNAL GENERATION ════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
bullSignalRaw = smcEnabled and bullSMC >= minSMCScore and volOK and
(isMSBBull or bullSweep)
bearSignalRaw = smcEnabled and bearSMC >= minSMCScore and volOK and
(isMSBBear or bearSweep)
var int lastBullBar = -999
var int lastBearBar = -999
bullCoolOK = bar_index - lastBullBar >= cooldownBars
bearCoolOK = bar_index - lastBearBar >= cooldownBars
bullSignal = bullSignalRaw and bullCoolOK
bearSignal = bearSignalRaw and bearCoolOK
if bullSignal
lastBullBar := bar_index
if bearSignal
lastBearBar := bar_index
// Signal tier
bullTier = bullSMC >= 70 ? "S" : bullSMC >= 55 ? "A" : "B"
bearTier = bearSMC >= 70 ? "S" : bearSMC >= 55 ? "A" : "B"
// ── Entry Labels ──────────────────────────────────────────────────────────────
if bullSignal
string confText = str.tostring(bullSMC, "#")
string entryTxt = "▲ " + bullTier + "-SMC (" + confText + ")"
color bgClr = bullSMC >= 70 ? color.new(colBullBright, 5) :
bullSMC >= 55 ? color.new(colBullPrimary, 10) :
color.new(colBullDim, 15)
label.new(bar_index, low,
text=entryTxt, yloc=yloc.belowbar,
color=bgClr, textcolor=colDashBg,
size=labelSize, style=label.style_label_up)
if bearSignal
string confText = str.tostring(bearSMC, "#")
string entryTxt = "▼ " + bearTier + "-SMC (" + confText + ")"
color bgClr = bearSMC >= 70 ? color.new(colBearBright, 5) :
bearSMC >= 55 ? color.new(colBearPrimary, 10) :
color.new(colBearDim, 15)
label.new(bar_index, high,
text=entryTxt, yloc=yloc.abovebar,
color=bgClr, textcolor=#ffffff,
size=labelSize, style=label.style_label_down)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ SESSIONS ════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
drawSession(bool show, string sessStr, color col, string name) =>
var box sBox = na
var label sLabel = na
var float sHigh = na
var float sLow = na
inSession = not na(time(timeframe.period, sessStr))
isStart = inSession and not inSession[1]
if show and inSession
if isStart
sHigh := high
sLow := low
sBox := box.new(bar_index, sHigh, bar_index, sLow,
border_color=col, border_style=line.style_dotted,
bgcolor=color.new(col, 92))
sLabel := label.new(bar_index, sHigh, name,
style=label.style_none, textcolor=col, size=size.small, textalign=text.align_center)
else
sHigh := math.max(sHigh, high)
sLow := math.min(sLow, low)
sBox.set_top(sHigh)
sBox.set_bottom(sLow)
sBox.set_right(bar_index)
sLabel.set_xy(math.round(math.avg(sBox.get_left(), bar_index)), sHigh)
float(na)
if showSessions
drawSession(showLondon, londonSess, londonCol, "London")
drawSession(showNY, nySess, nyCol, "New York")
drawSession(showTokyo, tokyoSess, tokyoCol, "Tokyo")
drawSession(showSydney, sydneySess, sydneyCol, "Sydney")
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ DASHBOARD ════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// Count active HPZs
int activeHPZ = 0
int activeOBs = 0
if obArray.size() > 0
for i = 0 to obArray.size() - 1
OrderBlock ob = obArray.get(i)
if not ob.mitigated
activeOBs += 1
if ob.isHPZ
activeHPZ += 1
float reliability = totalOBs > 0 ? (totalMitigated / totalOBs) * 100.0 : 0.0
// Unfilled FVG count
int activeFVGs = 0
if fvgArray.size() > 0
for i = 0 to fvgArray.size() - 1
if not fvgArray.get(i).filled
activeFVGs += 1
var table dash = na
if showDash
dash := table.new(getDashPos(dashPos), 2, 30,
bgcolor=color.new(colDashBg, 0),
border_width=1,
border_color=color.new(colNeutral, 70),
frame_width=2,
frame_color=color.new(colBullPrimary, 60))
if showDash and barstate.islast
color secBg = color.new(#222222, 0)
// ── HEADER ────────────────────────────────────────────────────────────────
table.cell(dash, 0, 0, "AlphaX S T R U C T U R E F L O W",
text_color=colBullPrimary, text_size=dashTextSize,
bgcolor=color.new(#111111, 0), text_halign=text.align_center)
table.cell(dash, 1, 0, "PRO",
text_color=color.new(colBullDim, 0), text_size=size.tiny,
bgcolor=color.new(#111111, 0), text_halign=text.align_center)
// ── SECTION: MARKET STRUCTURE ─────────────────────────────────────────────
table.cell(dash, 0, 1, "─── MARKET STRUCTURE ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 1, "", bgcolor=secBg)
// MSB status
msbTxt = isMSBBull ? "▲ BULL MSB" : isMSBBear ? "▼ BEAR MSB" : "— NONE"
msbClr = isMSBBull ? colBullPrimary : isMSBBear ? colBearPrimary : colNeutral
msbBg = isMSBBull ? color.new(colBullPrimary, 88) : isMSBBear ? color.new(colBearPrimary, 88) : color.new(colDashBg, 0)
table.cell(dash, 0, 2, "MSB STATUS", text_color=colTextLight, text_size=dashTextSize, bgcolor=msbBg)
table.cell(dash, 1, 2, msbTxt, text_color=msbClr, text_size=dashTextSize, bgcolor=msbBg)
// BMS
bmsTxt = isBMSBull ? "▲ BULL BREAK" : isBMSBear ? "▼ BEAR BREAK" : "— NONE"
bmsClr = isBMSBull ? colBullBright : isBMSBear ? colBearBright : colNeutral
table.cell(dash, 0, 3, "BMS (BODY)", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 3, bmsTxt, text_color=bmsClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// Momentum Z
zTxt = momentumZ > 2.0 ? "▲▲ STRONG" : momentumZ > 1.0 ? "▲ MODERATE" :
momentumZ > 0.3 ? "▲ MILD" : momentumZ < -2.0 ? "▼▼ STRONG" :
momentumZ < -1.0 ? "▼ MODERATE" : momentumZ < -0.3 ? "▼ MILD" : "— FLAT"
zClr = momentumZ > 1.0 ? colBullBright : momentumZ > 0.3 ? colBullPrimary :
momentumZ < -1.0 ? colBearBright : momentumZ < -0.3 ? colBearPrimary : colNeutralLight
table.cell(dash, 0, 4, "MOMENTUM Z", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 4, zTxt + " (" + str.tostring(momentumZ, "#.##") + ")", text_color=zClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ── SECTION: ORDER BLOCKS ─────────────────────────────────────────────────
table.cell(dash, 0, 5, "─── ORDER BLOCKS ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 5, "", bgcolor=secBg)
table.cell(dash, 0, 6, "ACTIVE OBs", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 6, str.tostring(activeOBs), text_color=colNeutralLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
hpzTxtDash = activeHPZ > 0 ? str.tostring(activeHPZ) + " ⬡ ACTIVE" : "— NONE"
hpzClrDash = activeHPZ > 0 ? colBullBright : colNeutral
hpzBgDash = activeHPZ > 0 ? color.new(colBullPrimary, 92) : color.new(colDashBg, 0)
table.cell(dash, 0, 7, "HPZ OBs", text_color=colTextLight, text_size=dashTextSize, bgcolor=hpzBgDash)
table.cell(dash, 1, 7, hpzTxtDash, text_color=hpzClrDash, text_size=dashTextSize, bgcolor=hpzBgDash)
relClr = reliability > 65 ? colBullPrimary : reliability > 40 ? colBullDim : colBearDim
table.cell(dash, 0, 8, "OB RELIABILITY", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 8, str.tostring(reliability, "#.#") + "%", text_color=relClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ── SECTION: LIQUIDITY & IMBALANCE ────────────────────────────────────────
table.cell(dash, 0, 9, "─── LIQUIDITY & IMBALANCE ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 9, "", bgcolor=secBg)
// Sweep status
sweepTxt = bullSweep ? "⚡ BULL SWEEP" : bearSweep ? "⚡ BEAR SWEEP" : "— NONE"
sweepClr = bullSweep or bearSweep ? colSweep : colNeutral
sweepBg = bullSweep or bearSweep ? color.new(colSweep, 88) : color.new(colDashBg, 0)
table.cell(dash, 0, 10, "LIQ SWEEP", text_color=colTextLight, text_size=dashTextSize, bgcolor=sweepBg)
table.cell(dash, 1, 10, sweepTxt, text_color=sweepClr, text_size=dashTextSize, bgcolor=sweepBg)
// FVG
fvgClr = activeFVGs > 3 ? colBullBright : activeFVGs > 0 ? colBullPrimary : colNeutral
table.cell(dash, 0, 11, "OPEN FVGs", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 11, str.tostring(activeFVGs) + " unfilled", text_color=fvgClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// FVG draw on liquidity
drawOnLiqTxt = fvgBearAbove > 0 and fvgBullBelow > 0 ? "↕ BOTH SIDES" :
fvgBearAbove > 0 ? "▲ DRAW UP (" + str.tostring(fvgBearAbove) + ")" :
fvgBullBelow > 0 ? "▼ DRAW DOWN (" + str.tostring(fvgBullBelow) + ")" : "— NONE"
drawClr = fvgBearAbove > 0 and fvgBullBelow == 0 ? colBullDim :
fvgBullBelow > 0 and fvgBearAbove == 0 ? colBearDim : colNeutralLight
table.cell(dash, 0, 12, "DRAW ON LIQ", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 12, drawOnLiqTxt, text_color=drawClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ── SECTION: SMC CONFLUENCE ───────────────────────────────────────────────
table.cell(dash, 0, 13, "─── SMC CONFLUENCE ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 13, "", bgcolor=secBg)
// Bull SMC score
bTier = bullSMC >= 70 ? "S-TIER" : bullSMC >= 55 ? "A-TIER" : bullSMC >= minSMCScore ? "B-TIER" : "LOW"
bClr = bullSMC >= 70 ? colBullBright : bullSMC >= 55 ? colBullPrimary : bullSMC >= minSMCScore ? colBullDim : colNeutral
table.cell(dash, 0, 14, "BULL SMC SCORE", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 14, str.tostring(bullSMC, "#") + "% [" + bTier + "]", text_color=bClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// Bear SMC score
sTier = bearSMC >= 70 ? "S-TIER" : bearSMC >= 55 ? "A-TIER" : bearSMC >= minSMCScore ? "B-TIER" : "LOW"
sClr = bearSMC >= 70 ? colBearBright : bearSMC >= 55 ? colBearPrimary : bearSMC >= minSMCScore ? colBearDim : colNeutral
table.cell(dash, 0, 15, "BEAR SMC SCORE", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 15, str.tostring(bearSMC, "#") + "% [" + sTier + "]", text_color=sClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// Near HPZ confluence
hpzConfTxt = nearBullHPZ > 0 and nearBearHPZ > 0 ? "⬡ BOTH SIDES" :
nearBullHPZ > 0 ? "⬡ BULL ZONE (" + str.tostring(nearBullHPZ) + ")" :
nearBearHPZ > 0 ? "⬡ BEAR ZONE (" + str.tostring(nearBearHPZ) + ")" : "— NONE"
hpzConfClr = nearBullHPZ > nearBearHPZ ? colBullPrimary :
nearBearHPZ > nearBullHPZ ? colBearPrimary : colNeutralLight
table.cell(dash, 0, 16, "HPZ PROXIMITY", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 16, hpzConfTxt, text_color=hpzConfClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ── SECTION: MARKET CONDITIONS ────────────────────────────────────────────
table.cell(dash, 0, 17, "─── MARKET CONDITIONS ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 17, "", bgcolor=secBg)
// Volume
volTxt = volRatio > 2.0 ? "SPIKE ×" + str.tostring(volRatio, "#.##") :
volRatio > 1.3 ? "HIGH ×" + str.tostring(volRatio, "#.##") :
volRatio > 0.7 ? "NORMAL ×" + str.tostring(volRatio, "#.##") : "DRY ×" + str.tostring(volRatio, "#.##")
volClr = volRatio > 2.0 ? colBullBright : volRatio > 1.3 ? colBullPrimary :
volRatio > 0.7 ? colNeutralLight : colNeutral
table.cell(dash, 0, 18, "VOLUME", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 18, volTxt, text_color=volClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ATR
table.cell(dash, 0, 19, "ATR (14)", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 19, str.tostring(atrVal, format.mintick), text_color=colNeutralLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// Body Ratio
bodyTxt = bodyRatio > 0.7 ? "STRONG" : bodyRatio > 0.4 ? "MODERATE" : "WEAK / INDECISION"
bodyClr = bodyRatio > 0.7 ? colBullPrimary : bodyRatio > 0.4 ? colNeutralLight : colBearDim
table.cell(dash, 0, 20, "CANDLE BODY", text_color=colTextLight, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
table.cell(dash, 1, 20, bodyTxt + " (" + str.tostring(bodyRatio * 100, "#") + "%)", text_color=bodyClr, text_size=dashTextSize, bgcolor=color.new(colDashBg, 0))
// ── SECTION: SIGNAL ───────────────────────────────────────────────────────
table.cell(dash, 0, 21, "─── ACTIVE SIGNAL ───",
text_color=color.new(colNeutral, 20), text_size=size.tiny,
bgcolor=secBg, text_halign=text.align_center)
table.cell(dash, 1, 21, "", bgcolor=secBg)
sigTxt = bullSignal ? "▲ LONG (" + bullTier + ")" : bearSignal ? "▼ SHORT (" + bearTier + ")" : "— NONE"
sigClr = bullSignal ? colBullPrimary : bearSignal ? colBearPrimary : colNeutral
sigBg = bullSignal ? color.new(colBullPrimary, 85) : bearSignal ? color.new(colBearPrimary, 85) : color.new(colDashBg, 0)
table.cell(dash, 0, 22, "SIGNAL", text_color=colTextLight, text_size=dashTextSize, bgcolor=sigBg)
table.cell(dash, 1, 22, sigTxt, text_color=sigClr, text_size=dashTextSize, bgcolor=sigBg)
// ═══════════════════════════════════════════════════════════════════════════════
// ═══════════════════════════ ALERTS ═══════════════════════════════════════════
// ═══════════════════════════════════════════════════════════════════════════════
// MSB Alerts
alertcondition(isMSBBull,
title="Bull Market Structure Break",
message="[AlphaX SFP] BULL MSB — {{ticker}} {{interval}} @ {{close}}")
alertcondition(isMSBBear,
title="Bear Market Structure Break",
message="[AlphaX SFP] BEAR MSB — {{ticker}} {{interval}} @ {{close}}")
// BMS Alerts
alertcondition(isBMSBull,
title="Bull Break of Market Structure (Body Close)",
message="[AlphaX SFP] BULL BMS (body close) — {{ticker}} {{interval}} @ {{close}}")
alertcondition(isBMSBear,
title="Bear Break of Market Structure (Body Close)",
message="[AlphaX SFP] BEAR BMS (body close) — {{ticker}} {{interval}} @ {{close}}")
// SMC Confluence Signals
alertcondition(bullSignal and bullSMC >= 70,
title="S-Tier Bull SMC Signal",
message="[AlphaX SFP] S-TIER BULL SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bullSignal and bullSMC >= 55 and bullSMC < 70,
title="A-Tier Bull SMC Signal",
message="[AlphaX SFP] A-TIER BULL SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bullSignal and bullSMC < 55,
title="B-Tier Bull SMC Signal",
message="[AlphaX SFP] B-TIER BULL SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bearSignal and bearSMC >= 70,
title="S-Tier Bear SMC Signal",
message="[AlphaX SFP] S-TIER BEAR SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bearSignal and bearSMC >= 55 and bearSMC < 70,
title="A-Tier Bear SMC Signal",
message="[AlphaX SFP] A-TIER BEAR SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bearSignal and bearSMC < 55,
title="B-Tier Bear SMC Signal",
message="[AlphaX SFP] B-TIER BEAR SMC — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bullSignal or bearSignal,
title="Any SMC Signal",
message="[AlphaX SFP] SMC signal — {{ticker}} {{interval}} @ {{close}}")
// Liquidity Sweep Alerts
alertcondition(bullSweep,
title="Bull Liquidity Sweep",
message="[AlphaX SFP] BULL liquidity sweep — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bearSweep,
title="Bear Liquidity Sweep",
message="[AlphaX SFP] BEAR liquidity sweep — {{ticker}} {{interval}} @ {{close}}")
// FVG Alerts
alertcondition(bullFVG,
title="Bullish Fair Value Gap",
message="[AlphaX SFP] Bull FVG formed — {{ticker}} {{interval}} @ {{close}}")
alertcondition(bearFVG,
title="Bearish Fair Value Gap",
message="[AlphaX SFP] Bear FVG formed — {{ticker}} {{interval}} @ {{close}}")
// HPZ Alert
alertcondition(isMSBBull and nearBullHPZ > 0,
title="Bull MSB + HPZ Confluence",
message="[AlphaX SFP] Bull MSB at HPZ zone — {{ticker}} {{interval}} @ {{close}}")
alertcondition(isMSBBear and nearBearHPZ > 0,
title="Bear MSB + HPZ Confluence",
message="[AlphaX SFP] Bear MSB at HPZ zone — {{ticker}} {{interval}} @ {{close}}")
Show all 904 lines