Indicator · Pine Script v6 · On the chart

SMC Confluence Engine v4

by shubhamtaywade82

Scores smart money confluence across a four-layer timeframe stack on the price chart.

View on GitHub

Archived by its author

GitHub stars1on the repository
Pine versionv6current
Lines of code807
Settings40inputs
LicenceNone statedfile: MPL-2.0
Last update5 months ago31 May 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

807 lines of Pine Script v6 from indicators/smc/smc_confluence_engine.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

smc_confluence_engine.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © shubhamtaywade82

// ============================================================
// SMC Confluence Engine v4 [nemesis] — 4-Layer MTF Engine
// Pine Script v6 | indicator() | overlay=true
// ============================================================
// CRITICAL UPGRADE from v3:
//   v3 had ONE flat HTF filter — a single EMA crossover gate.
//   v4 enforces the correct 4-layer timeframe hierarchy:
//
//   LAYER A — 🟥 HTF BIAS (4H + 1D)
//     • 4H EMA9/21 bias direction
//     • 4H premium / discount zone (50-bar range midpoint)
//     • Hard block if 4H bias is neutral — NO TRADE
//
//   LAYER B — 🟧 SETUP TIMEFRAME (1H)
//     • 1H BOS / CHoCH detection via confirmed pivots
//     • 1H structure trend (HH/HL vs LH/LL)
//     • Confirms trade is planned — aligns with 4H
//     • Hard block if 1H structure disagrees with 4H bias
//
//   LAYER C — 🟨 ENTRY TIMEFRAME (15m)
//     • 15m Order Block presence (price near active OB)
//     • 15m Liquidity sweep (recent stop hunt)
//     • Defines the entry zone precision
//     • Adds to score; trade blocked without ≥1 active
//
//   LAYER D — 🟩 EXECUTION TIMEFRAME (5m — chart TF)
//     • 5m CHoCH trigger (mandatory, same as v3)
//     • 5m OB tap
//     • 5m liq sweep, VP, session, trendline confluence
//
// SIGNAL FIRES ONLY WHEN:
//   4H bias aligned AND 1H structure confirms AND
//   15m zone present AND 5m CHoCH trigger
//
// SCORE 0–8:
//   +1  4H bias aligned
//   +1  4H in discount (long) / premium (short)
//   +1  1H CHoCH/BOS confirmed
//   +1  1H structure trend aligns
//   +1  15m OB active
//   +1  15m sweep recent
//   +1  5m OB tap
//   +1  5m extra confluence (VP / Session / TL)
// ============================================================

//@version=6
indicator(
     title            = "SMC Confluence Engine v4 [nemesis]",
     shorttitle       = "SMC-CE v4",
     overlay          = true,
     max_bars_back    = 500,
     max_labels_count = 300,
     max_lines_count  = 500,
     max_boxes_count  = 150
 )

// ════════════════════════════════════════════════════════════
// ░░  INPUTS
// ════════════════════════════════════════════════════════════

// ── 4-Layer MTF Config (NEW) ──────────────────────────────
grp_mtf = "🗂 MTF Stack (4-Layer)"
htf_tf       = input.timeframe("240", "Layer A — HTF Bias TF",    group=grp_mtf,
                 tooltip="Default 4H. Use 240 for 4H, D for daily.")
setup_tf     = input.timeframe("60",  "Layer B — Setup TF",       group=grp_mtf,
                 tooltip="Default 1H.")
entry_tf     = input.timeframe("15",  "Layer C — Entry Zone TF",  group=grp_mtf,
                 tooltip="Default 15m.")
// Layer D = chart timeframe (execution = 5m)

htf_ema_fast = input.int(9,   "HTF EMA Fast",   minval=3, group=grp_mtf)
htf_ema_slow = input.int(21,  "HTF EMA Slow",   minval=5, group=grp_mtf)
htf_swing    = input.int(5,   "HTF Pivot Swing Length", minval=2, maxval=20, group=grp_mtf)
htf_pd_len   = input.int(50,  "HTF Premium/Discount Lookback", minval=10, maxval=200, group=grp_mtf)

setup_swing  = input.int(5,   "Setup Pivot Swing Length", minval=2, maxval=20, group=grp_mtf)

entry_ob_pct = input.float(0.3,"Entry OB Zone Proximity %", minval=0.05, step=0.05, group=grp_mtf,
                 tooltip="Price within this % of 15m OB midpoint counts as 'in zone'.")
entry_liq_lb = input.int(10,  "Entry Sweep Lookback (bars on entry TF)", minval=3, maxval=50, group=grp_mtf)

show_htf_lines = input.bool(true, "Show 4H EMA lines", group=grp_mtf)
show_4h_zones  = input.bool(true, "Show Premium/Discount zone", group=grp_mtf)

// ── Layer D: SMC (5m chart) ───────────────────────────────
grp_smc = "🟩 Layer D — 5m SMC"
smc_swing    = input.int(10,   "Swing Length (BOS/CHoCH)", minval=3, maxval=50,  group=grp_smc)
ob_body_pct  = input.float(0.3,"OB Min Body %",            minval=0.05,step=0.05,group=grp_smc)
ob_expire    = input.int(50,   "OB Expires (bars)",        minval=5, maxval=300, group=grp_smc)
liq_lookback = input.int(20,   "Liquidity Swing Lookback", minval=5, maxval=100, group=grp_smc)
liq_wick_pct = input.float(0.1,"Sweep Min Wick %",        minval=0.02,step=0.02,group=grp_smc)
show_ob      = input.bool(true,"Show Order Block Boxes",   group=grp_smc)
show_bos     = input.bool(true,"Show BOS/CHoCH Lines",     group=grp_smc)
show_liq     = input.bool(true,"Show Liquidity Sweeps",    group=grp_smc)

// ── Market Structure ──────────────────────────────────────
grp_ms = "📐 5m Market Structure"
ms_swing     = input.int(10,   "Structure Swing Length",  minval=3, maxval=30, group=grp_ms)
show_ms      = input.bool(true,"Show HH/HL/LH/LL",        group=grp_ms)
show_ms_line = input.bool(true,"Show Structure Lines",    group=grp_ms)

// ── Trendlines ────────────────────────────────────────────
grp_tl = "📏 Trendlines"
tl_pivot_len  = input.int(10,    "Pivot Length",  minval=3, maxval=30, group=grp_tl)
tl_retest_pct = input.float(0.15,"Retest Zone %", minval=0.02,step=0.02,group=grp_tl)
show_tl       = input.bool(true, "Show Lines",    group=grp_tl)
show_tl_break = input.bool(true, "Show Labels",   group=grp_tl)

// ── Session Levels ────────────────────────────────────────
grp_sess = "🕐 Session Levels"
show_pdh_pdl = input.bool(true,"Show PDH/PDL",  group=grp_sess)
sess_liq_pct = input.float(0.1,"Level Zone %",  minval=0.02,step=0.02,group=grp_sess)
asia_sess    = input.session("0000-0800","Asia",   group=grp_sess)
london_sess  = input.session("0800-1600","London", group=grp_sess)
ny_sess      = input.session("1300-2100","NY",     group=grp_sess)

// ── Volume Profile ────────────────────────────────────────
grp_vp = "📊 Volume Profile"
vp_bars      = input.int(100,  "Lookback",   minval=20,maxval=500, group=grp_vp)
vp_rows      = input.int(24,   "Rows",       minval=10,maxval=50,  group=grp_vp)
poc_zone_pct = input.float(0.2,"POC Zone %", minval=0.05,step=0.05,group=grp_vp)
show_vp      = input.bool(true,"Show Lines", group=grp_vp)

// ── Signal Engine ─────────────────────────────────────────
grp_sig = "🚀 Signal Engine"
min_score    = input.int(5,    "Min Score (0–8)", minval=0,maxval=8, group=grp_sig,
                 tooltip="Recommended ≥5. With 4 mandatory gates each worth 1pt, minimum meaningful score is 4. Score 6+ = high conviction.")
sig_cooldown = input.int(5,    "Cooldown (bars)", minval=1,maxval=30,group=grp_sig)
show_signals = input.bool(true,"Show Entry Labels",group=grp_sig)
show_score   = input.bool(true,"Show Score",       group=grp_sig)

// ── Visuals ───────────────────────────────────────────────
grp_vis = "🎨 Visuals"
bull_col  = input.color(#00c4ff,"Bullish Color", group=grp_vis)
bear_col  = input.color(#ff3d3d,"Bearish Color", group=grp_vis)
show_dash = input.bool(true,"Show Dashboard",    group=grp_vis)

// ════════════════════════════════════════════════════════════
// ░░  BASE
// ════════════════════════════════════════════════════════════
atr14      = ta.atr(14)
vol_sma    = ta.sma(volume, 20)
is_new_day = ta.change(dayofweek) != 0

// ════════════════════════════════════════════════════════════
// ░░  LAYER A — 4H BIAS
// ════════════════════════════════════════════════════════════
// Non-repainting: lookahead_off on all security calls.
// 4H EMA9/21 gives direction; pivot BOS confirms the break.
// Premium/discount: price vs midpoint of 50-bar high/low range.

htf_ema_f  = request.security(syminfo.tickerid, htf_tf,
                 ta.ema(close, htf_ema_fast), lookahead=barmerge.lookahead_off)
htf_ema_s  = request.security(syminfo.tickerid, htf_tf,
                 ta.ema(close, htf_ema_slow), lookahead=barmerge.lookahead_off)
htf_close  = request.security(syminfo.tickerid, htf_tf,
                 close, lookahead=barmerge.lookahead_off)
htf_high50 = request.security(syminfo.tickerid, htf_tf,
                 ta.highest(high, htf_pd_len), lookahead=barmerge.lookahead_off)
htf_low50  = request.security(syminfo.tickerid, htf_tf,
                 ta.lowest(low, htf_pd_len),  lookahead=barmerge.lookahead_off)
htf_ph     = request.security(syminfo.tickerid, htf_tf,
                 ta.pivothigh(high, htf_swing, htf_swing), lookahead=barmerge.lookahead_off)
htf_pl     = request.security(syminfo.tickerid, htf_tf,
                 ta.pivotlow(low, htf_swing, htf_swing),   lookahead=barmerge.lookahead_off)

// Track last confirmed 4H pivot levels
var float htf_last_ph = na
var float htf_last_pl = na

if not na(htf_ph)
    htf_last_ph := htf_ph
if not na(htf_pl)
    htf_last_pl := htf_pl

// 4H structural bias via EMA stack + pivot break
htf_ema_bull = htf_ema_f > htf_ema_s
htf_ema_bear = htf_ema_f < htf_ema_s

// Additional pivot BOS confirmation (price closed beyond last 4H swing)
htf_bos_bull = not na(htf_last_ph) and htf_close > htf_last_ph
htf_bos_bear = not na(htf_last_pl) and htf_close < htf_last_pl

// Persistent 4H bias — latches on confirmed direction, cleared to 0 when both disagree
var int htf_bias = 0
if htf_ema_bull and htf_bos_bull
    htf_bias := 1
else if htf_ema_bear and htf_bos_bear
    htf_bias := -1
// If EMA and BOS disagree → bias stays last known (momentum persists)
// Only explicitly reset to 0 if neither condition has ever been met
if na(htf_last_ph) and na(htf_last_pl)
    htf_bias := 0

// 4H Premium / Discount zone
htf_range_mid = (htf_high50 + htf_low50) / 2.0
htf_in_discount = htf_close < htf_range_mid   // buy zone for longs
htf_in_premium  = htf_close > htf_range_mid   // sell zone for shorts

// HARD BLOCK: 4H bias must be defined
// If EMA9 == EMA21 (flat) or insufficient history, bias = 0 → no trade
htf_defined = htf_bias != 0
htf_ok_long  = htf_bias == 1
htf_ok_short = htf_bias == -1

// Plot 4H EMAs (extended to the right for reference)
var line htf_ema_f_line = na
var line htf_ema_s_line = na

if show_htf_lines and barstate.islast
    line.delete(htf_ema_f_line)
    line.delete(htf_ema_s_line)
    htf_ema_f_line := line.new(bar_index - 5, htf_ema_f, bar_index + 20, htf_ema_f,
         color=color.new(bull_col, 30), width=1, style=line.style_dashed, extend=extend.right)
    htf_ema_s_line := line.new(bar_index - 5, htf_ema_s, bar_index + 20, htf_ema_s,
         color=color.new(bear_col, 30), width=1, style=line.style_dashed, extend=extend.right)

// Premium / Discount zone boxes (live, refreshed each bar)
var box pd_prem_box = na
var box pd_disc_box = na

if show_4h_zones and not na(htf_high50) and not na(htf_low50) and barstate.islast
    box.delete(pd_prem_box)
    box.delete(pd_disc_box)
    _left = bar_index - htf_pd_len
    pd_prem_box := box.new(_left, htf_high50, bar_index + 10, htf_range_mid,
         bgcolor=color.new(bear_col, 92), border_color=color.new(bear_col, 60), border_width=1)
    pd_disc_box := box.new(_left, htf_range_mid, bar_index + 10, htf_low50,
         bgcolor=color.new(bull_col, 92), border_color=color.new(bull_col, 60), border_width=1)

// ════════════════════════════════════════════════════════════
// ░░  LAYER B — 1H STRUCTURE (SETUP TF)
// ════════════════════════════════════════════════════════════
// 1H must show a CHoCH or BOS in the same direction as 4H bias.
// We track 1H pivot BOS direction and EMA trend independently.

h1_ema_f   = request.security(syminfo.tickerid, setup_tf,
                 ta.ema(close, htf_ema_fast), lookahead=barmerge.lookahead_off)
h1_ema_s   = request.security(syminfo.tickerid, setup_tf,
                 ta.ema(close, htf_ema_slow), lookahead=barmerge.lookahead_off)
h1_close   = request.security(syminfo.tickerid, setup_tf,
                 close, lookahead=barmerge.lookahead_off)
h1_ph      = request.security(syminfo.tickerid, setup_tf,
                 ta.pivothigh(high, setup_swing, setup_swing), lookahead=barmerge.lookahead_off)
h1_pl      = request.security(syminfo.tickerid, setup_tf,
                 ta.pivotlow(low, setup_swing, setup_swing),   lookahead=barmerge.lookahead_off)

var float h1_last_ph  = na
var float h1_last_pl  = na
var int   h1_bias     = 0

if not na(h1_ph)
    h1_last_ph := h1_ph
if not na(h1_pl)
    h1_last_pl := h1_pl

// 1H BOS: close through last swing level
h1_bos_bull = not na(h1_last_ph) and h1_close > h1_last_ph and h1_ema_f > h1_ema_s
h1_bos_bear = not na(h1_last_pl) and h1_close < h1_last_pl and h1_ema_f < h1_ema_s

// 1H CHoCH: BOS against prior bias (structure shift)
h1_choch_bull = not na(h1_last_ph) and h1_close > h1_last_ph and h1_bias == -1
h1_choch_bear = not na(h1_last_pl) and h1_close < h1_last_pl and h1_bias ==  1

if h1_bos_bull or h1_choch_bull
    h1_bias := 1
if h1_bos_bear or h1_choch_bear
    h1_bias := -1

h1_ema_trend = h1_ema_f > h1_ema_s ? 1 : h1_ema_f < h1_ema_s ? -1 : 0

// HARD BLOCK: 1H structure must align with 4H bias
h1_ok_long  = h1_bias ==  1 and h1_ema_trend ==  1
h1_ok_short = h1_bias == -1 and h1_ema_trend == -1

// ════════════════════════════════════════════════════════════
// ░░  LAYER C — 15m ENTRY ZONE
// ════════════════════════════════════════════════════════════
// Defines the precision entry. At minimum 1 of (OB or sweep) must be present.
// Fetches 15m data and checks for:
//   Active OB: approximated by last opposing candle near current price on 15m
//   Recent sweep: wick-beyond-swing on 15m

m15_close   = request.security(syminfo.tickerid, entry_tf,
                 close, lookahead=barmerge.lookahead_off)
m15_high    = request.security(syminfo.tickerid, entry_tf,
                 high,  lookahead=barmerge.lookahead_off)
m15_low     = request.security(syminfo.tickerid, entry_tf,
                 low,   lookahead=barmerge.lookahead_off)
m15_open    = request.security(syminfo.tickerid, entry_tf,
                 open,  lookahead=barmerge.lookahead_off)

// 15m OB detection (approximation using confirmed 15m bars):
// Bullish OB on 15m: last 15m bar was bearish AND current 15m close > prior 15m high
//   → price broke up through a bearish candle = the OB is the bearish candle
// We look at [1] to get the confirmed prior bar
m15_bull_ob_active = m15_open[1] > m15_close[1] and           // prior 15m bar was bearish
                     m15_close > m15_high[1] and               // current 15m broke above it
                     math.abs(m15_close - m15_open[1]) /
                     math.max(m15_high[1] - m15_low[1], 0.001) >= 0.3 and  // body ≥ 30% range
                     math.abs(close - (m15_high[1] + m15_low[1]) / 2) /
                     close * 100 <= entry_ob_pct               // 5m price near 15m OB midpoint

m15_bear_ob_active = m15_open[1] < m15_close[1] and           // prior 15m bar was bullish
                     m15_close < m15_low[1] and                // current 15m broke below it
                     math.abs(m15_close - m15_open[1]) /
                     math.max(m15_high[1] - m15_low[1], 0.001) >= 0.3 and
                     math.abs(close - (m15_high[1] + m15_low[1]) / 2) /
                     close * 100 <= entry_ob_pct

// 15m sweep detection: wick pierced beyond swing + close recovered
m15_swing_hi = request.security(syminfo.tickerid, entry_tf,
                   ta.highest(high, entry_liq_lb), lookahead=barmerge.lookahead_off)
m15_swing_lo = request.security(syminfo.tickerid, entry_tf,
                   ta.lowest(low, entry_liq_lb),   lookahead=barmerge.lookahead_off)

m15_sweep_bull = m15_low  < m15_swing_lo[1] and m15_close > m15_swing_lo[1]
m15_sweep_bear = m15_high > m15_swing_hi[1] and m15_close < m15_swing_hi[1]

// Track recency on LTF (5m) bars
var int last_m15_bull_ob  = -999
var int last_m15_bear_ob  = -999
var int last_m15_bull_sw  = -999
var int last_m15_bear_sw  = -999

if m15_bull_ob_active
    last_m15_bull_ob := bar_index
if m15_bear_ob_active
    last_m15_bear_ob := bar_index
if m15_sweep_bull
    last_m15_bull_sw := bar_index
if m15_sweep_bear
    last_m15_bear_sw := bar_index

// Active within last 3 × smc_swing bars
m15_ob_bull_ok  = (bar_index - last_m15_bull_ob) <= smc_swing * 3
m15_ob_bear_ok  = (bar_index - last_m15_bear_ob) <= smc_swing * 3
m15_sw_bull_ok  = (bar_index - last_m15_bull_sw) <= smc_swing * 3
m15_sw_bear_ok  = (bar_index - last_m15_bear_sw) <= smc_swing * 3

// HARD BLOCK: at least 1 entry zone signal required (OB or sweep)
m15_zone_long  = m15_ob_bull_ok or m15_sw_bull_ok
m15_zone_short = m15_ob_bear_ok or m15_sw_bear_ok

// ════════════════════════════════════════════════════════════
// ░░  LAYER D — 5m EXECUTION (existing SMC engine, unchanged)
// ════════════════════════════════════════════════════════════

ph = ta.pivothigh(high, smc_swing, smc_swing)
pl = ta.pivotlow(low,   smc_swing, smc_swing)

var float last_ph = na; var float last_pl = na
var int   last_ph_bar = -999; var int last_pl_bar = -999
var int   ph_age = 0; var int pl_age = 0

ph_age := ph_age + 1; pl_age := pl_age + 1

if not na(ph)
    last_ph := ph; last_ph_bar := bar_index - smc_swing; ph_age := 0
if not na(pl)
    last_pl := pl; last_pl_bar := bar_index - smc_swing; pl_age := 0

ph_valid = not na(last_ph) and ph_age <= ob_expire
pl_valid = not na(last_pl) and pl_age <= ob_expire

var int structure_bias = 0

bos_bull   = ph_valid and close > last_ph and close[1] <= last_ph
bos_bear   = pl_valid and close < last_pl and close[1] >= last_pl
choch_bull = ph_valid and close > last_ph and close[1] <= last_ph and structure_bias == -1
choch_bear = pl_valid and close < last_pl and close[1] >= last_pl and structure_bias ==  1

if bos_bull or choch_bull
    structure_bias := 1
if bos_bear or choch_bear
    structure_bias := -1

// BOS / CHoCH lines (center text on line)
var int last_bos_bull_lbl = -999; var int last_bos_bear_lbl = -999
int bos_gap = math.max(3, smc_swing)

if show_bos
    if choch_bull
        _b = math.max(last_ph_bar, bar_index - 100)
        line.new(_b, last_ph, bar_index, last_ph, color=color.new(bull_col, 0), width=1, style=line.style_solid)
        label.new(math.round((_b + bar_index) / 2), last_ph, "CHoCH",
             style=label.style_none, textcolor=color.new(bull_col, 0), size=size.small, yloc=yloc.price)
        last_bos_bull_lbl := bar_index
    if choch_bear
        _b = math.max(last_pl_bar, bar_index - 100)
        line.new(_b, last_pl, bar_index, last_pl, color=color.new(bear_col, 0), width=1, style=line.style_solid)
        label.new(math.round((_b + bar_index) / 2), last_pl, "CHoCH",
             style=label.style_none, textcolor=color.new(bear_col, 0), size=size.small, yloc=yloc.price)
        last_bos_bear_lbl := bar_index
    if bos_bull and not choch_bull and (bar_index - last_bos_bull_lbl) >= bos_gap
        _b = math.max(last_ph_bar, bar_index - 100)
        line.new(_b, last_ph, bar_index, last_ph, color=color.new(bull_col, 50), width=1, style=line.style_dashed)
        label.new(math.round((_b + bar_index) / 2), last_ph, "BOS",
             style=label.style_none, textcolor=color.new(bull_col, 20), size=size.small, yloc=yloc.price)
        last_bos_bull_lbl := bar_index
    if bos_bear and not choch_bear and (bar_index - last_bos_bear_lbl) >= bos_gap
        _b = math.max(last_pl_bar, bar_index - 100)
        line.new(_b, last_pl, bar_index, last_pl, color=color.new(bear_col, 50), width=1, style=line.style_dashed)
        label.new(math.round((_b + bar_index) / 2), last_pl, "BOS",
             style=label.style_none, textcolor=color.new(bear_col, 20), size=size.small, yloc=yloc.price)
        last_bos_bear_lbl := bar_index

// 5m Order Blocks
impulse_body_pct = math.abs(close - open) / close * 100

var float bull_ob_hi = na; var float bull_ob_lo = na
var int   bull_ob_bar = -999; var int bull_ob_age = 0
var float bear_ob_hi = na; var float bear_ob_lo = na
var int   bear_ob_bar = -999; var int bear_ob_age = 0

bull_ob_age := bull_ob_age + 1; bear_ob_age := bear_ob_age + 1

if (bos_bull or choch_bull) and impulse_body_pct >= ob_body_pct and close[1] < open[1]
    bull_ob_hi := high[1]; bull_ob_lo := low[1]; bull_ob_bar := bar_index - 1; bull_ob_age := 0
if (bos_bear or choch_bear) and impulse_body_pct >= ob_body_pct and close[1] > open[1]
    bear_ob_hi := high[1]; bear_ob_lo := low[1]; bear_ob_bar := bar_index - 1; bear_ob_age := 0

bull_ob_valid = not na(bull_ob_hi) and bull_ob_age <= ob_expire and close >= bull_ob_lo * 0.998
bear_ob_valid = not na(bear_ob_hi) and bear_ob_age <= ob_expire and close <= bear_ob_hi * 1.002

in_bull_ob = bull_ob_valid and low  <= bull_ob_hi and high >= bull_ob_lo
in_bear_ob = bear_ob_valid and high >= bear_ob_lo and low  <= bear_ob_hi

var box bull_ob_box = na; var box bear_ob_box = na

if show_ob and bull_ob_valid and not na(bull_ob_hi)
    box.delete(bull_ob_box)
    bull_ob_box := box.new(bull_ob_bar, bull_ob_hi, bar_index, bull_ob_lo,
         border_color=color.new(bull_col, 20), bgcolor=color.new(bull_col, 85), border_width=1)
if show_ob and bear_ob_valid and not na(bear_ob_hi)
    box.delete(bear_ob_box)
    bear_ob_box := box.new(bear_ob_bar, bear_ob_hi, bar_index, bear_ob_lo,
         border_color=color.new(bear_col, 20), bgcolor=color.new(bear_col, 85), border_width=1)

// 5m Liquidity sweeps
liq_hi = ta.highest(high, liq_lookback); liq_lo = ta.lowest(low, liq_lookback)
liq_sweep_bull = low  < liq_lo[1] - liq_lo[1] * (liq_wick_pct/100) and close > liq_lo[1]
liq_sweep_bear = high > liq_hi[1] + liq_hi[1] * (liq_wick_pct/100) and close < liq_hi[1]

var int last_bull_sw = -999; var int last_bear_sw = -999
var int last_liq_bull_lbl = -999; var int last_liq_bear_lbl = -999
int liq_gap = math.max(3, smc_swing)

if liq_sweep_bull then last_bull_sw := bar_index
if liq_sweep_bear then last_bear_sw := bar_index
recent_bull_sweep = (bar_index - last_bull_sw) <= smc_swing * 2
recent_bear_sweep = (bar_index - last_bear_sw) <= smc_swing * 2

if show_liq and liq_sweep_bull and (bar_index - last_liq_bull_lbl) >= liq_gap
    label.new(bar_index, low, "•", style=label.style_none, textcolor=color.new(color.purple, 0), size=size.normal)
    label.new(bar_index, low - atr14*0.3, "Sell-side", style=label.style_none, textcolor=color.new(color.purple,30), size=size.small)
    last_liq_bull_lbl := bar_index
if show_liq and liq_sweep_bear and (bar_index - last_liq_bear_lbl) >= liq_gap
    label.new(bar_index, high, "•", style=label.style_none, textcolor=color.new(color.orange, 0), size=size.normal)
    label.new(bar_index, high + atr14*0.3, "Buy-side", style=label.style_none, textcolor=color.new(color.orange,30), size=size.small)
    last_liq_bear_lbl := bar_index

// 5m Market Structure labels
ms_ph = ta.pivothigh(high, ms_swing, ms_swing); ms_pl = ta.pivotlow(low, ms_swing, ms_swing)
var float prev_ms_ph = na; var float prev_ms_pl = na
ms_hh = not na(ms_ph) and not na(prev_ms_ph) and ms_ph > prev_ms_ph
ms_lh = not na(ms_ph) and not na(prev_ms_ph) and ms_ph < prev_ms_ph
ms_hl = not na(ms_pl) and not na(prev_ms_pl) and ms_pl > prev_ms_pl
ms_ll = not na(ms_pl) and not na(prev_ms_pl) and ms_pl < prev_ms_pl
var float last_ms_ph_val = na; var float last_ms_pl_val = na
if not na(ms_ph) then prev_ms_ph := last_ms_ph_val; last_ms_ph_val := ms_ph
if not na(ms_pl) then prev_ms_pl := last_ms_pl_val; last_ms_pl_val := ms_pl
var int last_ms_lbl = -999; int ms_gap = math.max(3, ms_swing)
if show_ms and (bar_index - ms_swing - last_ms_lbl) >= ms_gap
    if ms_hh then label.new(bar_index - ms_swing, ms_ph, "HH", style=label.style_none, textcolor=color.new(bull_col,20), size=size.small, yloc=yloc.abovebar); last_ms_lbl := bar_index - ms_swing
    if ms_lh then label.new(bar_index - ms_swing, ms_ph, "LH", style=label.style_none, textcolor=color.new(bear_col,20), size=size.small, yloc=yloc.abovebar); last_ms_lbl := bar_index - ms_swing
    if ms_hl then label.new(bar_index - ms_swing, ms_pl, "HL", style=label.style_none, textcolor=color.new(bull_col,20), size=size.small, yloc=yloc.belowbar); last_ms_lbl := bar_index - ms_swing
    if ms_ll then label.new(bar_index - ms_swing, ms_pl, "LL", style=label.style_none, textcolor=color.new(bear_col,20), size=size.small, yloc=yloc.belowbar); last_ms_lbl := bar_index - ms_swing
var int ms_trend = 0
if ms_hh or ms_hl then ms_trend := 1
if ms_lh or ms_ll then ms_trend := -1
var line ms_ph_line = na; var line ms_pl_line = na
if show_ms_line
    if not na(ms_ph)
        line.delete(ms_ph_line)
        ms_ph_line := line.new(bar_index-ms_swing-ms_swing, nz(prev_ms_ph,ms_ph), bar_index-ms_swing, ms_ph, color=color.new(bear_col,50), width=1, style=line.style_dashed)
    if not na(ms_pl)
        line.delete(ms_pl_line)
        ms_pl_line := line.new(bar_index-ms_swing-ms_swing, nz(prev_ms_pl,ms_pl), bar_index-ms_swing, ms_pl, color=color.new(bull_col,50), width=1, style=line.style_dashed)

// ── Trendlines ────────────────────────────────────────────
tl_ph = ta.pivothigh(high, tl_pivot_len, tl_pivot_len); tl_pl = ta.pivotlow(low, tl_pivot_len, tl_pivot_len)
var float tl_ph1 = na; var int tl_ph1_bar = -999; var float tl_ph2 = na; var int tl_ph2_bar = -999
var float tl_pl1 = na; var int tl_pl1_bar = -999; var float tl_pl2 = na; var int tl_pl2_bar = -999
if not na(tl_ph) then tl_ph2 := tl_ph1; tl_ph2_bar := tl_ph1_bar; tl_ph1 := tl_ph; tl_ph1_bar := bar_index - tl_pivot_len
if not na(tl_pl) then tl_pl2 := tl_pl1; tl_pl2_bar := tl_pl1_bar; tl_pl1 := tl_pl; tl_pl1_bar := bar_index - tl_pivot_len
tl_bear_slope = not na(tl_ph1) and not na(tl_ph2) and tl_ph1_bar != tl_ph2_bar ? (tl_ph1 - tl_ph2) / (tl_ph1_bar - tl_ph2_bar) : na
tl_bull_slope = not na(tl_pl1) and not na(tl_pl2) and tl_pl1_bar != tl_pl2_bar ? (tl_pl1 - tl_pl2) / (tl_pl1_bar - tl_pl2_bar) : na
tl_bear_val   = not na(tl_bear_slope) ? tl_ph1 + tl_bear_slope * (bar_index - tl_ph1_bar) : na
tl_bull_val   = not na(tl_bull_slope) ? tl_pl1 + tl_bull_slope * (bar_index - tl_pl1_bar) : na
tl_bear_break = not na(tl_bear_val) and close > tl_bear_val and close[1] <= tl_bear_val[1]
tl_bull_break = not na(tl_bull_val) and close < tl_bull_val and close[1] >= tl_bull_val[1]
var bool tl_bear_broken = false; var bool tl_bull_broken = false
var bool tl_bear_retested = false; var bool tl_bull_retested = false
var int tl_bear_break_bar = -999; var int tl_bull_break_bar = -999
if not na(tl_ph) then tl_bear_broken := false; tl_bear_retested := false; tl_bear_break_bar := -999
if not na(tl_pl) then tl_bull_broken := false; tl_bull_retested := false; tl_bull_break_bar := -999
if tl_bear_break then tl_bear_broken := true; tl_bear_retested := false; tl_bear_break_bar := bar_index
if tl_bull_break then tl_bull_broken := true; tl_bull_retested := false; tl_bull_break_bar := bar_index
tl_bear_retest = tl_bear_broken and not tl_bear_retested and not na(tl_bear_val) and (bar_index - tl_bear_break_bar) > 1 and math.abs(close - tl_bear_val)/close*100 <= tl_retest_pct and close > tl_bear_val
tl_bull_retest = tl_bull_broken and not tl_bull_retested and not na(tl_bull_val) and (bar_index - tl_bull_break_bar) > 1 and math.abs(close - tl_bull_val)/close*100 <= tl_retest_pct and close < tl_bull_val
if tl_bear_retest then tl_bear_retested := true
if tl_bull_retest then tl_bull_retested := true
var line tl_bear_line = na; var line tl_bull_line = na
if show_tl
    if not na(tl_ph1) and not na(tl_ph2)
        line.delete(tl_bear_line)
        tl_bear_line := line.new(tl_ph2_bar, tl_ph2, bar_index, tl_bear_val, color=color.new(bear_col,30), width=1, style=tl_bear_broken ? line.style_dashed : line.style_solid, extend=extend.right)
    if not na(tl_pl1) and not na(tl_pl2)
        line.delete(tl_bull_line)
        tl_bull_line := line.new(tl_pl2_bar, tl_pl2, bar_index, tl_bull_val, color=color.new(bull_col,30), width=1, style=tl_bull_broken ? line.style_dashed : line.style_solid, extend=extend.right)
if show_tl_break
    if tl_bear_break then label.new(bar_index, tl_bear_val, "◆  Break", style=label.style_none, textcolor=color.new(bull_col,0), size=size.small, yloc=yloc.belowbar)
    if tl_bull_break then label.new(bar_index, tl_bull_val, "◆  Break", style=label.style_none, textcolor=color.new(bear_col,0), size=size.small, yloc=yloc.abovebar)
    if tl_bear_retest then label.new(bar_index, tl_bear_val, "●  Retest", style=label.style_none, textcolor=color.new(bull_col,0), size=size.small, yloc=yloc.belowbar)
    if tl_bull_retest then label.new(bar_index, tl_bull_val, "●  Retest", style=label.style_none, textcolor=color.new(bear_col,0), size=size.small, yloc=yloc.abovebar)

// ── Session Levels ────────────────────────────────────────
var float day_high = high; var float day_low = low; var float pdh = na; var float pdl = na
if is_new_day then pdh := day_high; pdl := day_low; day_high := high; day_low := low
else then day_high := math.max(day_high, high); day_low := math.min(day_low, low)
in_asia   = not na(time(timeframe.period, asia_sess))
in_london = not na(time(timeframe.period, london_sess))
in_ny     = not na(time(timeframe.period, ny_sess))
var float asia_hi = na; var float asia_lo = na
var float london_hi = na; var float london_lo = na
var float ny_hi = na; var float ny_lo = na
var bool was_asia = false; var bool was_london = false; var bool was_ny = false
if in_asia then asia_hi := na(asia_hi) or not was_asia ? high : math.max(asia_hi,high); asia_lo := na(asia_lo) or not was_asia ? low : math.min(asia_lo,low); was_asia := true
else if was_asia then was_asia := false
if in_london then london_hi := na(london_hi) or not was_london ? high : math.max(london_hi,high); london_lo := na(london_lo) or not was_london ? low : math.min(london_lo,low); was_london := true
else if was_london then was_london := false
if in_ny then ny_hi := na(ny_hi) or not was_ny ? high : math.max(ny_hi,high); ny_lo := na(ny_lo) or not was_ny ? low : math.min(ny_lo,low); was_ny := true
else if was_ny then was_ny := false
var line pdh_line = na; var line pdl_line = na
if show_pdh_pdl and not na(pdh) and barstate.islast
    line.delete(pdh_line); line.delete(pdl_line)
    pdh_line := line.new(bar_index-50, pdh, bar_index+20, pdh, color=color.new(bear_col,20), width=1, style=line.style_dotted, extend=extend.right)
    pdl_line := line.new(bar_index-50, pdl, bar_index+20, pdl, color=color.new(bull_col,20), width=1, style=line.style_dotted, extend=extend.right)
pdh_sweep = not na(pdh) and high > pdh*(1+sess_liq_pct/100) and close < pdh
pdl_sweep = not na(pdl) and low  < pdl*(1-sess_liq_pct/100) and close > pdl
near_pdh = not na(pdh) and math.abs(close-pdh)/close*100 <= sess_liq_pct
near_pdl = not na(pdl) and math.abs(close-pdl)/close*100 <= sess_liq_pct
near_sess_hi = (not na(asia_hi) and math.abs(close-asia_hi)/close*100 <= sess_liq_pct) or (not na(london_hi) and math.abs(close-london_hi)/close*100 <= sess_liq_pct)
near_sess_lo = (not na(asia_lo) and math.abs(close-asia_lo)/close*100 <= sess_liq_pct) or (not na(london_lo) and math.abs(close-london_lo)/close*100 <= sess_liq_pct)
sess_level_bull = near_pdl or near_sess_lo or pdl_sweep
sess_level_bear = near_pdh or near_sess_hi or pdh_sweep

// ── Volume Profile ────────────────────────────────────────
vp_high = ta.highest(high, vp_bars); vp_low = ta.lowest(low, vp_bars)
var float poc = na; var float vah = na; var float val_line = na
var float max_vol = 0.0; var float max_vol_price = na
if bar_index >= vp_bars
    max_vol := 0.0; max_vol_price := close
    for i = 0 to vp_bars - 1
        if volume[i] > max_vol then max_vol := volume[i]; max_vol_price := (high[i]+low[i]+close[i])/3.0
    poc := max_vol_price
    float ws = 0.0; float wv = 0.0; float ws2 = 0.0
    for i = 0 to vp_bars - 1
        float tp = (high[i]+low[i]+close[i])/3.0; ws += tp*volume[i]; wv += volume[i]; ws2 += tp*tp*volume[i]
    float wm = wv > 0 ? ws/wv : close; float vr = wv > 0 ? ws2/wv - wm*wm : 0.0; float sg = vr > 0 ? math.sqrt(vr) : atr14
    vah := wm + sg; val_line := wm - sg
near_poc = not na(poc) and math.abs(close-poc)/close*100 <= poc_zone_pct
near_vah = not na(vah) and math.abs(close-vah)/close*100 <= poc_zone_pct
near_val = not na(val_line) and math.abs(close-val_line)/close*100 <= poc_zone_pct
vp_bull_conf = near_poc or near_val; vp_bear_conf = near_poc or near_vah
var line poc_line = na; var line vah_line = na; var line val_line2 = na
if show_vp and not na(poc) and barstate.islast
    line.delete(poc_line); line.delete(vah_line); line.delete(val_line2)
    poc_line  := line.new(bar_index-vp_bars, poc,      bar_index, poc,      color=color.new(color.yellow,20), width=2, style=line.style_solid)
    vah_line  := line.new(bar_index-vp_bars, vah,      bar_index, vah,      color=color.new(bear_col,40), width=1, style=line.style_dashed)
    val_line2 := line.new(bar_index-vp_bars, val_line, bar_index, val_line, color=color.new(bull_col,40), width=1, style=line.style_dashed)

// ════════════════════════════════════════════════════════════
// ░░  4-LAYER SIGNAL ENGINE
// ════════════════════════════════════════════════════════════
// ALL 4 MANDATORY GATES MUST PASS — no signal otherwise
// Score adds 2 bonus points on top of the 4 mandatory pts

// ── Gate checks ───────────────────────────────────────────
gate_a_long  = htf_ok_long    // 4H bias = bull
gate_a_short = htf_ok_short   // 4H bias = bear
gate_b_long  = h1_ok_long     // 1H structure = bull
gate_b_short = h1_ok_short    // 1H structure = bear
gate_c_long  = m15_zone_long  // 15m OB or sweep active
gate_c_short = m15_zone_short
gate_d_long  = choch_bull     // 5m CHoCH trigger
gate_d_short = choch_bear

all_gates_long  = gate_a_long  and gate_b_long  and gate_c_long  and gate_d_long
all_gates_short = gate_a_short and gate_b_short and gate_c_short and gate_d_short

// ── Scoring (0–8): 4 gates = mandatory pts, 4 bonus pts ──
// Gate pts (1 each, only counted when gate passes)
long_ga = gate_a_long  ? 1 : 0   // 4H bias
long_gb = gate_b_long  ? 1 : 0   // 1H structure
long_gc = gate_c_long  ? 1 : 0   // 15m zone
long_gd = gate_d_long  ? 1 : 0   // 5m CHoCH

// Bonus pts (quality boosters)
long_b1 = htf_in_discount ? 1 : 0              // 4H price in discount zone (accumulation)
long_b2 = in_bull_ob       ? 1 : 0              // 5m OB tap
long_b3 = (vp_bull_conf or sess_level_bull) ? 1 : 0   // VP or session confluence
long_b4 = (tl_bear_retest or recent_bull_sweep) ? 1 : 0 // TL retest or 5m sweep

short_ga = gate_a_short ? 1 : 0
short_gb = gate_b_short ? 1 : 0
short_gc = gate_c_short ? 1 : 0
short_gd = gate_d_short ? 1 : 0

short_b1 = htf_in_premium ? 1 : 0
short_b2 = in_bear_ob     ? 1 : 0
short_b3 = (vp_bear_conf or sess_level_bear) ? 1 : 0
short_b4 = (tl_bull_retest or recent_bear_sweep) ? 1 : 0

long_score  = long_ga  + long_gb  + long_gc  + long_gd  + long_b1  + long_b2  + long_b3  + long_b4
short_score = short_ga + short_gb + short_gc + short_gd + short_b1 + short_b2 + short_b3 + short_b4

var int last_sig_bar = -999
cooldown_ok = (bar_index - last_sig_bar) >= sig_cooldown

// Signal only fires when ALL 4 gates pass + score ≥ min
long_signal  = all_gates_long  and long_score  >= min_score and cooldown_ok
short_signal = all_gates_short and short_score >= min_score and cooldown_ok

if long_signal or short_signal
    last_sig_bar := bar_index

// ════════════════════════════════════════════════════════════
// ░░  SIGNAL LABELS
// ════════════════════════════════════════════════════════════
// Global series: UDFs that use values fed by request.security() fail bundled-ref analysis.
gate_breakdown_long_txt =
     "4H" + (gate_a_long ? "✓" : "✗") + " 1H" + (gate_b_long ? "✓" : "✗") +
     " 15m" + (gate_c_long ? "✓" : "✗") + " 5m" + (gate_d_long ? "✓" : "✗")

gate_breakdown_short_txt =
     "4H" + (gate_a_short ? "✓" : "✗") + " 1H" + (gate_b_short ? "✓" : "✗") +
     " 15m" + (gate_c_short ? "✓" : "✗") + " 5m" + (gate_d_short ? "✓" : "✗")

if show_signals and long_signal
    _col = long_score >= 7 ? color.new(bull_col, 0) :
           long_score >= 5 ? color.new(bull_col, 15) : color.new(bull_col, 30)
    _txt = "▲ LONG" + (show_score ? " [" + str.tostring(long_score) + "/8]" : "") +
           "\n" + gate_breakdown_long_txt +
           (long_b1==1?" PD":"") + (long_b2==1?" OB":"") +
           (long_b3==1?" VP/SESS":"") + (long_b4==1?" TL/LIQ":"")
    label.new(bar_index, low - atr14 * 1.2, _txt,
         style=label.style_label_up, color=_col, textcolor=color.white, size=size.normal)

if show_signals and short_signal
    _col = short_score >= 7 ? color.new(bear_col, 0) :
           short_score >= 5 ? color.new(bear_col, 15) : color.new(bear_col, 30)
    _txt = "▼ SHORT" + (show_score ? " [" + str.tostring(short_score) + "/8]" : "") +
           "\n" + gate_breakdown_short_txt +
           (short_b1==1?" PD":"") + (short_b2==1?" OB":"") +
           (short_b3==1?" VP/SESS":"") + (short_b4==1?" TL/LIQ":"")
    label.new(bar_index, high + atr14 * 1.2, _txt,
         style=label.style_label_down, color=_col, textcolor=color.white, size=size.normal)

// ════════════════════════════════════════════════════════════
// ░░  PLOTS
// ════════════════════════════════════════════════════════════
[st_val, st_dir] = ta.supertrend(3.0, 10)
plot(st_dir < 0 ? st_val : na, "ST Bull", color=color.new(bull_col,50), linewidth=1, style=plot.style_linebr)
plot(st_dir > 0 ? st_val : na, "ST Bear", color=color.new(bear_col,50), linewidth=1, style=plot.style_linebr)

// Background: show 4H bias (darkest = strongest signal)
bgcolor(htf_bias ==  1 and h1_bias ==  1 ? color.new(bull_col, 95) :
        htf_bias == -1 and h1_bias == -1 ? color.new(bear_col, 95) :
        htf_bias ==  1                   ? color.new(bull_col, 98) :
        htf_bias == -1                   ? color.new(bear_col, 98) : na,
        title="4H+1H Bias BG")

barcolor(structure_bias ==  1 ? color.new(bull_col, 65) :
         structure_bias == -1 ? color.new(bear_col, 65) : na)

// ════════════════════════════════════════════════════════════
// ░░  DASHBOARD — 4-LAYER VIEW
// ════════════════════════════════════════════════════════════
var table dash = table.new(position.top_right, 3, 18,
     bgcolor=color.new(#0d0d0d, 5),
     border_color=color.new(#2a2a2a, 30), border_width=1,
     frame_color=color.new(#3a3a3a, 20), frame_width=1)

dc(c, r, t, bg, tc) =>
    table.cell(dash, c, r, t, bgcolor=bg, text_color=tc, text_size=size.small)

if show_dash and barstate.islast
    pos = color.new(#00c87a, 20); neg = color.new(#ff3d3d, 20)
    neu = color.new(#3a3a3a, 40); hd  = color.new(#1a1a2e, 10)
    blk = color.new(#ff0000, 5)   // hard-block color
    wht = color.white

    dc(0, 0, "SMC-CE v4 [4-TF]", hd,  wht)
    dc(1, 0, "BULL",              hd,  wht)
    dc(2, 0, "BEAR",              hd,  wht)

    // ── LAYER A: 4H ──────────────────────────────────────
    dc(0, 1, "🟥 4H BIAS", hd, wht)
    dc(1, 1, "", hd, wht); dc(2, 1, "", hd, wht)

    dc(0, 2, "  EMA+BOS",   neu, wht)
    dc(1, 2, htf_bias ==  1 ? "BULL ✓" : htf_bias == 0 ? "NEUTRAL ⚠" : "—",
             htf_bias ==  1 ? pos : htf_bias == 0 ? color.new(color.yellow,30) : neu, wht)
    dc(2, 2, htf_bias == -1 ? "BEAR ✓" : htf_bias == 0 ? "NEUTRAL ⚠" : "—",
             htf_bias == -1 ? neg : htf_bias == 0 ? color.new(color.yellow,30) : neu, wht)

    dc(0, 3, "  P/D Zone",  neu, wht)
    dc(1, 3, htf_in_discount ? "Discount ✓" : "Premium",
             htf_in_discount ? pos : color.new(color.orange,30), wht)
    dc(2, 3, htf_in_premium ? "Premium ✓" : "Discount",
             htf_in_premium ? neg : color.new(color.orange,30), wht)

    dc(0, 4, "  Gate A",    neu, wht)
    dc(1, 4, gate_a_long  ? "PASS ✓" : "BLOCK ✗", gate_a_long  ? pos : blk, wht)
    dc(2, 4, gate_a_short ? "PASS ✓" : "BLOCK ✗", gate_a_short ? neg : blk, wht)

    // ── LAYER B: 1H ──────────────────────────────────────
    dc(0, 5, "🟧 1H SETUP", hd, wht)
    dc(1, 5, "", hd, wht); dc(2, 5, "", hd, wht)

    dc(0, 6, "  BOS/CHoCH",  neu, wht)
    dc(1, 6, h1_bias ==  1 ? "BULL ✓" : "—", h1_bias ==  1 ? pos : neu, wht)
    dc(2, 6, h1_bias == -1 ? "BEAR ✓" : "—", h1_bias == -1 ? neg : neu, wht)

    dc(0, 7, "  EMA Trend",  neu, wht)
    dc(1, 7, h1_ema_trend ==  1 ? "UP ✓" : "—", h1_ema_trend ==  1 ? pos : neu, wht)
    dc(2, 7, h1_ema_trend == -1 ? "DOWN ✓" : "—", h1_ema_trend == -1 ? neg : neu, wht)

    dc(0, 8, "  Gate B",     neu, wht)
    dc(1, 8, gate_b_long  ? "PASS ✓" : "BLOCK ✗", gate_b_long  ? pos : blk, wht)
    dc(2, 8, gate_b_short ? "PASS ✓" : "BLOCK ✗", gate_b_short ? neg : blk, wht)

    // ── LAYER C: 15m ─────────────────────────────────────
    dc(0, 9, "🟨 15m ENTRY", hd, wht)
    dc(1, 9, "", hd, wht); dc(2, 9, "", hd, wht)

    dc(0,10, "  OB Zone",   neu, wht)
    dc(1,10, m15_ob_bull_ok ? "ACTIVE ✓" : "—", m15_ob_bull_ok ? pos : neu, wht)
    dc(2,10, m15_ob_bear_ok ? "ACTIVE ✓" : "—", m15_ob_bear_ok ? neg : neu, wht)

    dc(0,11, "  LIQ Sweep", neu, wht)
    dc(1,11, m15_sw_bull_ok ? "RECENT ✓" : "—", m15_sw_bull_ok ? pos : neu, wht)
    dc(2,11, m15_sw_bear_ok ? "RECENT ✓" : "—", m15_sw_bear_ok ? neg : neu, wht)

    dc(0,12, "  Gate C",    neu, wht)
    dc(1,12, gate_c_long  ? "PASS ✓" : "BLOCK ✗", gate_c_long  ? pos : blk, wht)
    dc(2,12, gate_c_short ? "PASS ✓" : "BLOCK ✗", gate_c_short ? neg : blk, wht)

    // ── LAYER D: 5m ──────────────────────────────────────
    dc(0,13, "🟩 5m TRIGGER", hd, wht)
    dc(1,13, "", hd, wht); dc(2,13, "", hd, wht)

    dc(0,14, "  CHoCH",      neu, wht)
    dc(1,14, choch_bull ? "FIRED ✓" : "—", choch_bull ? pos : neu, wht)
    dc(2,14, choch_bear ? "FIRED ✓" : "—", choch_bear ? neg : neu, wht)

    dc(0,15, "  Gate D",     neu, wht)
    dc(1,15, gate_d_long  ? "PASS ✓" : "WAIT", gate_d_long  ? pos : neu, wht)
    dc(2,15, gate_d_short ? "PASS ✓" : "WAIT", gate_d_short ? neg : neu, wht)

    // ── Final output ──────────────────────────────────────
    dc(0,16, "⭐ Score",      hd, wht)
    dc(1,16, str.tostring(long_score)  + "/8",
             long_score  >= 6 ? pos : long_score  >= 4 ? color.new(color.orange,30) : neu, wht)
    dc(2,16, str.tostring(short_score) + "/8",
             short_score >= 6 ? neg : short_score >= 4 ? color.new(color.orange,30) : neu, wht)

    dc(0,17, "🚀 SIGNAL",    hd, wht)
    dc(1,17, long_signal  ? "▲ LONG"  : all_gates_long  ? "READY" : "BLOCKED",
             long_signal  ? pos : all_gates_long  ? color.new(bull_col,40) : neu, wht)
    dc(2,17, short_signal ? "▼ SHORT" : all_gates_short ? "READY" : "BLOCKED",
             short_signal ? neg : all_gates_short ? color.new(bear_col,40) : neu, wht)

// ════════════════════════════════════════════════════════════
// ░░  ALERTS
// ════════════════════════════════════════════════════════════
alertcondition(long_signal,
     "▲ LONG [4-TF Aligned]",
     "SMC-CE v4 ▲ LONG | 4H+1H+15m+5m aligned | Score: " + str.tostring(long_score) + "/8 | Close: {{close}}")
alertcondition(short_signal,
     "▼ SHORT [4-TF Aligned]",
     "SMC-CE v4 ▼ SHORT | 4H+1H+15m+5m aligned | Score: " + str.tostring(short_score) + "/8 | Close: {{close}}")
alertcondition(long_signal  and long_score  >= 7, "🔥 HIGH CONV LONG (7+)",  "SMC-CE v4 🔥 LONG score≥7 | Close: {{close}}")
alertcondition(short_signal and short_score >= 7, "🔥 HIGH CONV SHORT (7+)", "SMC-CE v4 🔥 SHORT score≥7 | Close: {{close}}")
alertcondition(htf_bias != htf_bias[1] and htf_bias == 1,  "4H → BULLISH", "4H bias shifted BULLISH | Close: {{close}}")
alertcondition(htf_bias != htf_bias[1] and htf_bias == -1, "4H → BEARISH", "4H bias shifted BEARISH | Close: {{close}}")
alertcondition(h1_choch_bull, "1H CHoCH ↑ — Setup forming", "1H CHoCH bullish — watch for 15m zone | Close: {{close}}")
alertcondition(h1_choch_bear, "1H CHoCH ↓ — Setup forming", "1H CHoCH bearish — watch for 15m zone | Close: {{close}}")
alertcondition(liq_sweep_bull, "💧 5m Sell-side swept", "5m sell-side liquidity taken | Close: {{close}}")
alertcondition(liq_sweep_bear, "💧 5m Buy-side swept",  "5m buy-side liquidity taken | Close: {{close}}")
alertcondition(pdh_sweep, "⚠ PDH Swept", "PDH swept — reversal watch | Close: {{close}}")
alertcondition(pdl_sweep, "⚠ PDL Swept", "PDL swept — reversal watch | Close: {{close}}")

Overview

A 4-hour EMA bias and premium or discount zone set direction, 1-hour structure confirms it, 15-minute order blocks and liquidity sweeps define the entry zone, and a chart-timeframe change of character is the trigger, for a score out of eight. It also draws structure points, trendlines and previous day and session levels. This is the earlier version of the v5 script.

Details

Published by

shubhamtaywade82 on GitHub

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

SMC / ICT / price action, Support & resistance

Markets

Any symbol

Timeframes

M1-M5, M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Layer A — HTF Bias TFtimeframe240htf_tf
Layer B — Setup TFtimeframe60setup_tf
Layer C — Entry Zone TFtimeframe15entry_tf
HTF EMA Fastint9htf_ema_fast
HTF EMA Slowint21htf_ema_slow
HTF Pivot Swing Lengthint5htf_swing
HTF Premium/Discount Lookbackint50htf_pd_len
Setup Pivot Swing Lengthint5setup_swing
Entry OB Zone Proximity %float0.3entry_ob_pct
Entry Sweep Lookback (bars on entry TF)int10entry_liq_lb
Show 4H EMA linesbooltrueshow_htf_lines
Show Premium/Discount zonebooltrueshow_4h_zones
Show all 40 settings
SettingTypeDefaultVariable
Swing Length (BOS/CHoCH)int10smc_swing
OB Min Body %float0.3ob_body_pct
OB Expires (bars)int50ob_expire
Liquidity Swing Lookbackint20liq_lookback
Sweep Min Wick %float0.1liq_wick_pct
Show Order Block Boxesbooltrueshow_ob
Show BOS/CHoCH Linesbooltrueshow_bos
Show Liquidity Sweepsbooltrueshow_liq
Structure Swing Lengthint10ms_swing
Show HH/HL/LH/LLbooltrueshow_ms
Show Structure Linesbooltrueshow_ms_line
Pivot Lengthint10tl_pivot_len
Retest Zone %float0.15tl_retest_pct
Show Linesbooltrueshow_tl
Show Labelsbooltrueshow_tl_break
Show PDH/PDLbooltrueshow_pdh_pdl
Level Zone %float0.1sess_liq_pct
Asiasession0000-0800asia_sess
Londonsession0800-1600london_sess
NYsession1300-2100ny_sess
Lookbackint100vp_bars
Rowsint24vp_rows
POC Zone %float0.2poc_zone_pct
Show Linesbooltrueshow_vp
Min Score (0–8)int5min_score
Cooldown (bars)int5sig_cooldown
Show Entry Labelsbooltrueshow_signals
Show Scorebooltrueshow_score
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.

Similar Pine Scripts

ICT Equal Highs and Lows

by ArunKBhaskar
575 stars

This overlay indicator finds pivot highs and lows on the price chart and compares the last two highs and the last two lows. When the percentage difference between a pair is below the Equal HL threshold, it treats them as equal levels and draws a box. Left and

Indicator v5 SMC / ICT / price actionSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of ICT Equal Highs and Lows

DE-tracker

by Allen1212
303 stars

This indicator plots labels on the TradingView price chart to mark ARK Invest's buy and sell trades for the DE stock. Buy transactions appear in green with X1 or X2 multipliers showing the number of ARK ETFs involved on the same day; sells appear in red. The m

Indicator v4 Support & resistanceSMC / ICT / price action
Updated 2 years ago · None stated GitHub repository of DE-tracker

This Pine Script indicator plots a ZigZag on the price chart. It identifies reversal points when price moves more than a set percentage from the last pivot. The script calculates forecasts using zigzag data and labels detected geometric patterns including harm

Indicator v4 TrendSupport & resistance

Golden Bullet Strategy

by TradersPost
218 stars

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

Indicator v6 SMC / ICT / price actionSessions & time
Updated 3 months ago · None stated GitHub repository of Golden Bullet Strategy

Open Source Fractal

by cantolab
183 stars

This indicator implements the Fractal Model concept to plot market structure shifts, liquidity sweeps, and Change in State of Delivery (CISD) levels. It overlays custom higher-timeframe candle previews, open prices, and time markers directly on the price chart

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · MIT GitHub repository of Open Source Fractal

Swing Failure Signals

by Ganador1
154 stars

This indicator calculates pivot highs and pivot lows to detect liquidity sweeps and Swing Failure Patterns. It identifies when price breaks past recent key swing highs or lows within a configurable historical window, then looks for a quick reversal or change i

Indicator v6 SMC / ICT / price actionSupport & resistance
Updated 2 months ago · Apache-2.0 GitHub repository of Swing Failure Signals

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers