XAULearn

GEX + EFP Basis Matrix v29 · ซอร์สโค้ด

Pine Script ต้นฉบับ

ไฟล์นี้ถูกคัดลอกจากต้นฉบับใน G:\Trader\PineSCript\ ตอนสร้างเว็บ จึงเป็นโค้ดชุดเดียวกับที่ทำงานอยู่บนชาร์ตจริง ณ วันที่ปรับปรุง

Gex_EFP_Matrix_v29.pine 2,465 บรรทัด 170 KB ต้นฉบับแก้ไขล่าสุด 12 สิงหาคม 2569 ดาวน์โหลด .pine

Pine Script ยังไม่มีไวยากรณ์เฉพาะสำหรับตัวไฮไลต์ที่ใช้ จึงไฮไลต์ด้วยไวยากรณ์ TypeScript ซึ่งใกล้เคียงกันพอที่จะอ่านง่าย ตัวเลขบรรทัดตรงกับไฟล์จริง ใช้อ้างอิงในบทเรียนได้ เช่น gex-v29.pine:120

สารบัญส่วนของโค้ด (29)
  1. 134 §1 INPUTS
  2. 452 §2 TYPES + FUNCTIONS
  3. 577 §3 RS DATA FETCH (7 calls — _efp_fut_h4 H4 restored in v21 revised)
  4. 595 §4 BASIS ENGINE + COMEX CIRCUIT BREAKER TIERS
  5. 729 §5 SPOTEX LEVELS
  6. 757 §6 GEX PHYSICS ENGINE + VWAP (London daily-reset fix) + ALMA
  7. 855 §5b DUAL-SYSTEM SD LEVELS
  8. 896 §7 GVZ VOLATILITY REGIME
  9. 912 §8 DXY MACRO FILTER [v19 fix: fully implemented — was stub in v18]
  10. 930 §9 MLMI COMPUTATION (k=987, momentumWindow=10, session-aware decay)
  11. 967 §10 SMI COMPUTATION (K=10, D=3, EMA=3 — OB=+40, OS=-40)
  12. 986 §11 QUANTALGO VOLUME INTELLIGENCE
  13. 1081 §11b BUBBLE CONTEXT — LTF INTRABAR POSITION → AMT EVENT CLASSIFIER [v26]
  14. 1213 §12 AMT PATTERN ENGINE — SOVEREIGN §24b ADAPTED
  15. 1364 §13 CONFLUENCE CHECKS
  16. 1387 §14 SQUEEZE + BUBBLE PROXIMITY
  17. 1429 §15 REGIME FSM [v19: ATR-based breakout fallback]
  18. 1459 §16 REGIME CONFIDENCE SCORE [v19: CB tier penalty added]
  19. 1511 §FRZ FROZEN ZONE DISPLAY — ported from QC_BasisMatrix v8.4 §13
  20. 1589 §14b SQUEEZE LABELS [v22 new] — label.new() → 0 plot-budget units
  21. 1667 §16c EXPANSION SCORE + MR-INTO-TREND [v27] — DISPLAY-ONLY (label → 0 budget)
  22. 1748 §17 SIGNAL LOGIC — Priority Gate C/D > A/B > E/F (+MLMI/SMI+DXY gates)
  23. 1848 §K K-MEANS CLUSTER VP (unchanged from v18)
  24. 1859 §18 CHART LINES + LABELS + CVP (barstate.islast)
  25. 2176 §19 CHART PLOTS + SIGNALS
  26. 2230 §19b NO-VOLUME WARNING TABLE
  27. 2246 §20 ALERTS (all const string — CE10123 compliant)
  28. 2285 §19 REGIME MATRIX + Γ-PROXY [v28] — DISPLAY-ONLY (one table → 0 plot-budget)
  29. 2438 §19c DEEP-FIB PREMIUM / DISCOUNT [v29] — box/line/label only → 0 plot-budget
//@version=6
// ╔═══════════════════════════════════════════════════════════════════════════════════╗
// ║  Gex and EFP Basis Matrix | GEX+ALMA+AMT Sovereign+MLMI+SMI+g3+YZsqz | XAUUSD ║
// ║  Pine Script v6 | CE:0 RE:0 CW:0 | BUDGET: 19/64u declared  ~64/64u total       ║
// ║  Production Grade: CME/COMEX + LBMA Gold Desk Standard                          ║
// ╚═══════════════════════════════════════════════════════════════════════════════════╝
//
//  CHANGES v28 → v29   (all DISPLAY-ONLY · 0 plot-budget · file stays 63/64)
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v29-1] §19 ACTION AUTO-FLIP on Γ conflict — the headline verb now FLIPS
//                       (FOLLOW↔FADE/RANGE, MR-FADE↔FOLLOW/BREAK) + route + colour when
//                       the Γ-proxy strongly overrides the direction cell (|Γ-score| ≥
//                       i_rm_gth), with i_rm_hyst-bar hysteresis to kill flicker. Toggle
//                       i_rm_autoflip (default ON). OFF = v28 (headline stays, ⚠ tag only).
//                       Same info — removes the mis-read that "FOLLOW + Γ⚠fade-risk" caused.
//  [v29-2] §19 ADX/DI rows (i_rm_adx, default OFF) — ta.dmi → 2 table rows (ADX strength
//                       + DI± direction). ⚠ read WITH DI, never a lone gate (ER lesson).
//  [v29-3] §19c DEEP-FIB PREMIUM/DISCOUNT (i_rm_fib, default OFF) — swing range split into
//                       PREMIUM(upper/sell) / DISCOUNT(lower/buy) + deep 0.705–0.886 zones
//                       (Kmer 'trade from discount'). box/line/label only. Isolated block.
//                       All three: own toggles, own prefixes, NO existing logic touched,
//                       NO plot/fill/alert added → no RE10140 risk.
//
//  CHANGES v27 → v28
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v28-1] §19 REGIME MATRIX + Γ-PROXY — NEW, group ⑳. DISPLAY-ONLY (one table → 0
//                       plot-budget; file stays 63/64). Unifies Direction × Volatility
//                       into the 6-regime matrix (Bull/Sideways/Bear × Quiet/Volatile)
//                       with a per-cell prescription (follow full / ×0.6 / MR-fade @VA /
//                       STAND ASIDE / preserve ×0.5) + EA routing. Direction = close vs
//                       EMA200 baseline + slope; Volatility = YZ ratio expansion / GVZ
//                       elevated-extreme. Plus a POS/NEG-GAMMA PROXY (NOT real dealer
//                       gamma — gold has no options chain; a vol-behaviour footprint):
//                       5 orthogonal votes → signed Γ-score →
//                         VarianceRatio VR(k) (replaces Hurst) · RV−GVZ (realized vs
//                         implied) · YZ fast/slow · trend-efficiency ER · vs g1 flip.
//                       pos-Γ = vol dampening → fade/failed BO; neg-Γ = amplifying →
//                       follow/trend. Γ tag flags fade-vs-trend conflict on the action.
//                       Black table bg (default), adjustable size + position (default
//                       Top Left). Toggle i_rm_on. NOT entry — no gate/conf_score touched
//                       (port to gate → walk-forward OOS first). M5 defaults.
//
//  CHANGES v26 → v27
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v27-1] §16c EXPANSION SCORE + MR-INTO-TREND — NEW, group ⑲. DISPLAY-ONLY.
//                       Two reads from the "3 primitives" framework, as labels only:
//                       • EXPANSION = breakout trigger — bar range ≥ i_exp_thr × the
//                         i_exp_len-bar average range → "EXP▲/▼ N×" marker (dir by
//                         candle). The volatility-expansion counterpart to the ⑰ squeeze
//                         (compression) detector.
//                       • MR-INTO-TREND = buy-the-dip WITH the trend — inside regime ±1,
//                         price retests the g1 flip level (broken resistance→support in an
//                         uptrend / support→resistance in a downtrend) → "MR→trend BUY/
//                         SELL" label + pullback-depth% in tooltip (deeper = higher prob).
//                         The systematic answer to "never fade AGAINST the trend": this
//                         fades TOWARD it.
//                       Uses only label.new (0 plot-budget — file is at 63/64). Dedup via
//                       i_dedup; expansion fires on fresh onset only. Toggles: i_xmt_on +
//                       i_exp_lbl / i_mrt_lbl. NOT an entry — no gate/conf_score touched
//                       (any port to entry logic → walk-forward OOS first). M5 defaults.
//
//  CHANGES v25 → v26
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v26-1] §11b BUBBLE CONTEXT ENGINE (LTF Position → AMT event) — NEW, group ⑬b.
//                       Upgrades the ⑫ volume bubbles: previously they only reported
//                       size + BUY/SELL side. Now, on each classified bubble bar, the
//                       engine pulls lower-TF intrabar bars (request.security_lower_tf),
//                       bins them into the candle's high→low range, finds the volume POC
//                       (the intrabar cluster), reads the net delta AT that cluster, and
//                       combines {candle direction × cluster side × cluster position} to
//                       NAME the event exactly per the AMT reference cards:
//                         Bullish candle → cluster TOP+sell = rejection · TOP+buy =
//                           abs-contrarian (both bearish/red) · MID buy = acceptance buy ·
//                           BOT sell = abs-continue (both bullish/green).
//                         Bearish candle = mirror image.
//                       Draws: (a) a position DOT at the true cluster price (colored by
//                       cluster side buy/sell), (b) a CONTEXT LABEL naming the pattern,
//                       colored by OUTCOME (green=bullish, red=bearish), placed below the
//                       low (bullish outcome) / above the high (bearish outcome).
//                       Toggles: master (i_bctx_on), labels (i_bctx_lbl), dot (i_bctx_dot),
//                       LTF res (i_bctx_ltf, def "1"), bins (20), top/bot zone (.66/.34),
//                       size gate (Medium+), colors, size, side-arrow. M5 defaults.
//                       + 2 alerts (reversal UP / DOWN). DISPLAY-ONLY: touches no gate /
//                       conf_score / entry logic (any port to entry → walk-forward OOS).
//                       Proxy caveat: LTF wick-weighted delta = eyes, not a validated edge.
//
//  CHANGES v24 → v25
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v25-1] §12 AMT ACCEPTANCE LABELS: "Accept Buy" / "Accept Sell" text labels added
//                       alongside the existing "●" dot for ACCEPTANCE BUY/SELL patterns.
//                       Text uses size.tiny (matches normal chart labels). Dot (●) at
//                       _emj_sz_resolved unchanged. Text label added to _amt_lbs array
//                       (cap 400 preserved).
//  [v25-2] INPUT DEFAULTS updated to match preferred configuration:
//                       EFP Basis Mode: SESSION (was ORIGINAL)
//                       PBV L1: 1.71% (was 2.150%), PBV L2: 2.1278% (was 3.414%),
//                       PBV L3: 3.618% (was 3.730%)
//                       Explosion (g3): 5.0 (was 4.236)
//                       CB Signal Gate: true (was false)
//                       Show gFlip g1 Labels: false (was true)
//                       Show SpotEx ATM: false (was true)
//                       Show Gamma Wall Labels: false (was true)
//                       Show Explosion Labels: false (was true)
//                       Show PHI System: false (was true)
//                       Show EM +/-2sigma: true (was false)
//                       ALMA L1/L2/L3 Width: 1 (was 2)
//                       QA Small Percentile: 90 (was 75), Medium Percentile: 93 (was 90)
//                       Show Small Clusters: false (was true)
//
//  CHANGES v23 → v24  (prior changelog preserved)
//  ─────────────────────────────────────────────────────────────────────────────────
//  [v23-1] §14  : Squeeze false-positive filters added (2-layer)
//                 Filter 1: Min Compression Duration — sqz_dur[1] >= i_sqz_min_dur
//                 Filter 2: YZ Ratio Expansion Confirmation — _yz_ratio > _yz_ratio[1]
//  [v23-2] §17  : alert titles/messages updated
//  CHANGES v23 → v24  : max_boxes_count=500, MLMI array cap (preserved)
//  CHANGES v22 → v23  : Squeeze false-positive filters (preserved)
//  CHANGES v21 → v22  : YZ-based Squeeze Detector + 2 alerts (preserved)
//  CHANGES v18 → v21  : table fix, London VWAP reset, basis_cv abs, DXY filter,
//                       cond_I/J dedup, GOFO input, COMEX CB tiers, ATR fallback,
//                       Globex open, conf_score CB penalty (all preserved)
// ─────────────────────────────────────────────────────────────────────────────────

indicator(
     title      = "Gex and EFP Basis Matrix v29 | GEX+ALMA+AMT Sovereign+MLMI+SMI+g3+YZsqz+BubbleCtx+ExpMRT+RegimeMatrix | XAUUSD",
     shorttitle = "GEX+EFP Matrix v29",
     overlay    = true,
     max_lines_count  = 500,
     max_labels_count = 500,
     max_boxes_count  = 500,
     max_bars_back    = 2000)

// ═══════════════════════════════════════════════════════════════════════════════
// §1  INPUTS
// ═══════════════════════════════════════════════════════════════════════════════
const string G_FEED = "① BASIS MATRIX"
string i_efp_mode  = input.string("SESSION","EFP Basis Mode",options=["ORIGINAL","SESSION","1-MINUTE"],group=G_FEED)
string i_fut_sym   = input.symbol("COMEX:GC1!","Futures Ticker (COMEX)",group=G_FEED)
string i_gvz_sym   = input.symbol("CBOE:GVZ",  "GVZ Vol Index (CBOE)", group=G_FEED)
int    i_basis_len = input.int(200, "Basis SMA Length",group=G_FEED,minval=20)
float  i_block     = input.float(25.0,"COMEX Strike Block ($)",group=G_FEED,step=5.0)
float  i_sd_mult   = input.float(1.618,"SD Level phi (sigma)",group=G_FEED,step=0.001)
float  i_pbv_1     = input.float(1.71,  "PBV L1 % (1.71)",  group=G_FEED,step=0.001)
float  i_pbv_2     = input.float(2.1278,"PBV L2 % (2.1278)",group=G_FEED,step=0.001)
float  i_pbv_3     = input.float(3.618, "PBV L3 % (3.618)", group=G_FEED,step=0.001)
float  i_gofo_rate = input.float(4.20,"GOFO Rate % (1-month)",group=G_FEED,step=0.05,minval=0.0,maxval=20.0,tooltip="1-month Gold Forward Offered Rate. Update daily from LBMA GOFO page.")

const string G_GEX = "② GEX PHYSICS (Yang-Zhang)"
int   i_vol_lb     = input.int(600,  "YZ Lookback (bars)",group=G_GEX,minval=50)
float i_vol_mult   = input.float(5.0,"Implied Vol Multiplier",group=G_GEX,step=0.1)
string i_sigma_mode= input.string("FIBONACCI","sigma Level Mode",group=G_GEX,options=["FIBONACCI","GAUSSIAN"])
float i_g1         = input.float(1.618,"Zero Gamma Flip",group=G_GEX,step=0.001)
float i_g2         = input.float(3.236,"Gamma Wall",group=G_GEX,step=0.001)
float i_g3         = input.float(5.0,  "Explosion",group=G_GEX,step=0.001)
float i_sig_floor  = input.float(2.0, "Sigma Floor (xATR14)",group=G_GEX,step=0.1)

const string G_VOL = "③ GVZ REGIME FILTER"
bool  i_gvz_en     = input.bool(true, "Enable GVZ Filter",group=G_VOL)
float i_gvz_norm   = input.float(24.0,"GVZ Normal Threshold",group=G_VOL,step=1.0)
float i_gvz_elev   = input.float(32.0,"GVZ Elevated Threshold",group=G_VOL,step=1.0)
float i_gvz_ext    = input.float(42.0,"GVZ Extreme Threshold",group=G_VOL,step=1.0)

const string G_DXY = "④ DXY MACRO FILTER"
bool  i_dxy_en     = input.bool(true,"Enable DXY Filter",group=G_DXY)
int   i_dxy_roc    = input.int(5,"DXY ROC Period (bars)",group=G_DXY,minval=2,maxval=20)
float i_dxy_thr    = input.float(0.3,"DXY ROC Threshold (%)",group=G_DXY,step=0.1)

const string G_CB = "⑤ COMEX CIRCUIT BREAKER (Awareness)"
bool  i_show_cb    = input.bool(true, "Show CB Tier Lines",group=G_CB,tooltip="COMEX Globex rule 589: ±3/±6/±9% from prior settle triggers halts. Displayed as awareness only — does NOT block signals unless CB Gate enabled.")
bool  i_cb_gate    = input.bool(true, "Enable CB Signal Gate (blocks MR inside ±3%)",group=G_CB,tooltip="When enabled, MR signals are blocked if price is within the ±3% CB tier band. Recommended: OFF for scalping, ON for swing.")
color i_cb_t1_col  = input.color(color.new(#FF9800,40),"CB Tier 1 (±3%) Color",group=G_CB)
color i_cb_t2_col  = input.color(color.new(#FF1744,40),"CB Tier 2 (±6%) Color",group=G_CB)
color i_cb_t3_col  = input.color(color.new(#D500F9,35),"CB Tier 3 (±9%) Color",group=G_CB)

const string G_EXEC = "⑥ EXECUTION"
float i_tol        = input.float(3.0,"Zone Tolerance ($)",group=G_EXEC,step=0.5)
float i_body_min   = input.float(0.40,"Min Candle Body Ratio",group=G_EXEC,step=0.05)
int   i_evt_win    = input.int(5,"Event Window (bars)",group=G_EXEC,minval=1,maxval=20)
float i_prox_mult  = input.float(1.5,"Bubble Proximity Mult",group=G_EXEC,step=0.1)
int   i_dedup      = input.int(5,"Dedup Window (bars)",group=G_EXEC,minval=1,maxval=20)
bool  i_prio_gate  = input.bool(true,"Signal Priority Gate C/D>A/B>E/F",group=G_EXEC)
int   i_out_bars   = input.int(2,"Regime Hysteresis (bars)",group=G_EXEC,minval=1,maxval=5)
int   i_n_str      = input.int(2,"N Strikes to show",group=G_EXEC,minval=1,maxval=4)
bool  i_sess_filt  = input.bool(true,"No MR 00-02:59 UTC",group=G_EXEC)

const string G_VIS = "⑦ VISUALIZATION"
bool  i_show_map   = input.bool(true, "Show Regime Heatmap",group=G_VIS)
bool  i_show_g1    = input.bool(false,"Show gFlip g1 Labels",group=G_VIS)
bool  i_show_atm   = input.bool(false,"Show SpotEx ATM",group=G_VIS)
bool  i_show_vwap  = input.bool(true, "Show VWAP Label",group=G_VIS)
bool  i_show_dvwap = input.bool(false,"Show Daily VWAP (secondary)",group=G_VIS)
bool  i_rich_lbl   = input.bool(true, "Rich Strike Labels",group=G_VIS)
bool  i_show_g2    = input.bool(false,"Show Gamma Wall Labels (2x)",group=G_VIS)
bool  i_show_g3    = input.bool(false,"Show Explosion Labels (3x)",group=G_VIS)
bool  i_show_sd    = input.bool(true, "Show SD/PBV Levels",group=G_VIS)
bool  i_show_phi   = input.bool(false,"  Show PHI System (1.618sigma)",group=G_VIS)
bool  i_show_delta_sys = input.bool(true,"  Show DELTA System (25D/15D/5D)",group=G_VIS)
string i_sd_signal = input.string("DELTA","  Signal Source (cond_C/D)",group=G_VIS,options=["PHI","DELTA"])
bool  i_show_str   = input.bool(true, "Show SpotEx Strikes",group=G_VIS)
bool  i_show_em    = input.bool(true, "Show Expected Move +/-1sigma",group=G_VIS)
bool  i_show_em2   = input.bool(true, "Show Expected Move +/-2sigma",group=G_VIS)
bool  i_show_rr    = input.bool(true, "Show Risk Reversal Label",group=G_VIS)
bool  i_show_vpin  = input.bool(true, "Show VPIN Proxy Label",group=G_VIS)
color i_c_g1       = input.color(color.new(color.gray,40),"gFlip color",group=G_VIS)
color i_c_g2u      = input.color(color.new(#FF1744,0),"Wall+2x",group=G_VIS)
color i_c_g2d      = input.color(color.new(#00E676,0),"Wall-2x",group=G_VIS)
color i_c_g3       = input.color(color.new(#D500F9,0),"Explosion 3x",group=G_VIS)
color i_c_sd       = input.color(color.new(#FF9800,40),"SD Level",group=G_VIS)
color i_c_pbv      = input.color(color.new(#CE93D8,40),"PBV Level",group=G_VIS)
color i_c_buy      = input.color(#00E676,"BUY Signal",group=G_VIS)
color i_c_sell     = input.color(#FF1744,"SELL Signal",group=G_VIS)

const string G_STR_COL = "⑦ VISUALIZATION — SPOTEX COLORS"
color i_cc_line    = input.color(color.new(#00BCD4,50),"Call Line",group=G_STR_COL)
color i_cp_line    = input.color(color.new(#00BCD4,50),"Put Line",group=G_STR_COL)
color i_c_blk_ln   = input.color(color.new(#FF1744,35),"Blocked Line",group=G_STR_COL)
color i_cc_bg_norm = input.color(color.new(#FF9800,50),"Call Label BG (Normal)",group=G_STR_COL)
color i_cc_bg_med  = input.color(color.new(#FF9800,20),"Call Label BG (Med)",group=G_STR_COL)
color i_cc_bg_str  = input.color(color.new(#FF1744,10),"Call Label BG (Strong)",group=G_STR_COL)
color i_cp_bg_norm = input.color(color.new(#B0BEC5,50),"Put Label BG (Normal)",group=G_STR_COL)
color i_cp_bg_med  = input.color(color.new(#00BCD4,20),"Put Label BG (Med)",group=G_STR_COL)
color i_cp_bg_str  = input.color(color.new(#00E676,10),"Put Label BG (Strong)",group=G_STR_COL)
color i_c_blk_bg   = input.color(color.new(#FF1744,40),"Blocked Label BG",group=G_STR_COL)
color i_cc_txt_norm= input.color(#607D8B,"Call Text (Normal)",group=G_STR_COL)
color i_cc_txt_med = input.color(#FF9800,"Call Text (Med)",group=G_STR_COL)
color i_cc_txt_str = input.color(#FF1744,"Call Text (Strong)",group=G_STR_COL)
color i_cp_txt_norm= input.color(#607D8B,"Put Text (Normal)",group=G_STR_COL)
color i_cp_txt_med = input.color(#00BCD4,"Put Text (Med)",group=G_STR_COL)
color i_cp_txt_str = input.color(#00E676,"Put Text (Strong)",group=G_STR_COL)
color i_c_blk_txt  = input.color(#FF1744,"Blocked Text",group=G_STR_COL)

const string G_STYL = "⑧ LINE STYLE — PHI System"
color  i_phi_col   = input.color(color.new(#FF9800,25),"PHI Line Color",group=G_STYL)
int    i_phi_width = input.int(1,"PHI Line Width (1-4)",group=G_STYL,minval=1,maxval=4)
string i_phi_style = input.string("Dotted","PHI Line Style",group=G_STYL,options=["Solid","Dashed","Dotted"])
int    i_phi_lbl_tr= input.int(75,"PHI Label Transparency",group=G_STYL,minval=0,maxval=100)

const string G_STYL2 = "⑧ LINE STYLE — DELTA System"
float  i_delta_dte  = input.float(1.0," DELTA DTE (days)",group=G_STYL2,step=0.25,minval=0.1,maxval=5.0)
float  i_skew_15d_p = input.float(1.29,"15D Put  Skew x",group=G_STYL2,step=0.01,minval=0.8,maxval=2.0)
float  i_skew_15d_c = input.float(1.27,"15D Call Skew x",group=G_STYL2,step=0.01,minval=0.8,maxval=2.0)
float  i_skew_5d_p  = input.float(1.21," 5D Put  Skew x",group=G_STYL2,step=0.01,minval=0.8,maxval=2.0)
float  i_skew_5d_c  = input.float(1.23," 5D Call Skew x",group=G_STYL2,step=0.01,minval=0.8,maxval=2.0)
color  i_d25_col    = input.color(color.new(#FF6F00,5), "25D Color",group=G_STYL2)
int    i_d25_width  = input.int(1,"25D Width (1-4)",group=G_STYL2,minval=1,maxval=4)
string i_d25_style  = input.string("Dotted","25D Style",group=G_STYL2,options=["Solid","Dashed","Dotted"])
int    i_d25_lbl_tr = input.int(50,"25D Label Transparency",group=G_STYL2,minval=0,maxval=100)
color  i_d15_col    = input.color(color.new(#FFA726,35),"15D Color",group=G_STYL2)
int    i_d15_width  = input.int(1,"15D Width (1-4)",group=G_STYL2,minval=1,maxval=4)
string i_d15_style  = input.string("Dotted","15D Style",group=G_STYL2,options=["Solid","Dashed","Dotted"])
int    i_d15_lbl_tr = input.int(65,"15D Label Transparency",group=G_STYL2,minval=0,maxval=100)
color  i_d5_col     = input.color(color.new(#90A4AE,55)," 5D Color",group=G_STYL2)
int    i_d5_width   = input.int(1," 5D Width (1-4)",group=G_STYL2,minval=1,maxval=4)
string i_d5_style   = input.string("Dotted"," 5D Style",group=G_STYL2,options=["Solid","Dashed","Dotted"])
int    i_d5_lbl_tr  = input.int(75," 5D Label Transparency",group=G_STYL2,minval=0,maxval=100)
string i_sd_lbl_sz  = input.string("Tiny","SD/Delta Label Size",group=G_STYL2,options=["Tiny","Small","Normal"])
color  i_d35_col    = input.color(color.new(#FF5722,50),"35D Color",group=G_STYL2)
color  i_d45_col    = input.color(color.new(#E64A19,50),"45D Color",group=G_STYL2)
bool   i_show_fill  = input.bool(true,"Show Delta Zone Fills",group=G_STYL2)
color  i_fill_5_15  = input.color(color.new(#90A4AE,90),"Fill 5D-15D", group=G_STYL2)
color  i_fill_15_25 = input.color(color.new(#FFA726,90),"Fill 15D-25D",group=G_STYL2)
color  i_fill_25_35 = input.color(color.new(#FF6F00,90),"Fill 25D-35D",group=G_STYL2)
color  i_fill_35_45 = input.color(color.new(#FF1744,90),"Fill 35D-45D",group=G_STYL2)

const string G_BAND = "⑨ GEX BANDS — Continuous History"
bool   i_show_g1_band = input.bool(true,"Show gFlip g1 Band (+/-1.618sigma)",group=G_BAND)
color  i_band_g1_col  = input.color(color.new(#00BCD4,20),"g1 Band Color",group=G_BAND)
int    i_band_g1_w    = input.int(1,"g1 Width (1-4)",group=G_BAND,minval=1,maxval=4)
bool   i_show_g2_band = input.bool(true,"Show gWall g2 Band (+/-3.414sigma)",group=G_BAND)
color  i_band_g2u_col = input.color(color.new(#FF1744,30),"g2+ Call Wall Color",group=G_BAND)
color  i_band_g2d_col = input.color(color.new(#00E676,30),"g2- Put Wall Color", group=G_BAND)
int    i_band_g2_w    = input.int(1,"g2 Width (1-4)",group=G_BAND,minval=1,maxval=4)
bool   i_show_g3_band = input.bool(true,"Show gExp g3 Band (+/-5sigma)",group=G_BAND)
color  i_band_g3_col  = input.color(color.new(#D500F9,40),"g3 Explosion Color",group=G_BAND)
int    i_band_g3_w    = input.int(1,"g3 Width (1-4)",group=G_BAND,minval=1,maxval=4)
string i_band_g1_sty  = input.string("Dotted","g1 Band Style",group=G_BAND,options=["Solid","Dashed","Dotted"])
string i_band_g2_sty  = input.string("Dotted","g2 Band Style",group=G_BAND,options=["Solid","Dashed","Dotted"])
string i_band_g3_sty  = input.string("Dotted","g3 Band Style",group=G_BAND,options=["Solid","Dashed","Dotted"])

const string G_CVP  = "⑩ K-MEANS CLUSTER VP"
bool   i_show_cvp   = input.bool(true, "Show K-Means Cluster VP",group=G_CVP)
int    i_cvp_lb     = input.int(377,   "Lookback Period (bars)",group=G_CVP,minval=50,maxval=2000)
int    i_n_clusters = input.int(5,     "Number of Clusters",group=G_CVP,minval=2,maxval=10)
int    i_km_iter    = input.int(50,    "K-Means Iterations",group=G_CVP,minval=10,maxval=200)
color  i_cvp_col    = input.color(color.new(#FFD700,30),"Cluster Line Color",group=G_CVP)
bool   i_cvp_label  = input.bool(true,"Show Cluster Labels",group=G_CVP)
bool   i_cvp_dots   = input.bool(true,"Highlight Price at Cluster Level",group=G_CVP)
int    i_cvp_ext    = input.int(50,"Cluster Line Extension (bars)",group=G_CVP,minval=10,maxval=500)
int    i_cvp_line_w = input.int(1,"Cluster Line Width (1-4)",group=G_CVP,minval=1,maxval=4)
string i_cvp_poc_sty= input.string("Dotted","POC Line Style",group=G_CVP,options=["Solid","Dashed","Dotted"])
string i_cvp_clus_sty=input.string("Dotted","Cluster Line Style",group=G_CVP,options=["Solid","Dashed","Dotted"])
string i_cvp_lbl_sz = input.string("Tiny","Cluster Label Size",group=G_CVP,options=["Tiny","Small","Normal"])
string i_cvp_dot_sz2= input.string("small","CVP Dot Size (near cluster)",group=G_CVP,options=["tiny","small","normal"])
color  i_cvp_poc_col= input.color(color.new(#FF6F00,0),"POC Star Color",group=G_CVP)

const string G_ALMA = "⑪ ALMA MOVING AVERAGES"
bool  i_show_alma  = input.bool(true,"Show ALMA Lines",group=G_ALMA)
int   i_al1_len    = input.int(59,   "L1 Length (Fast)",group=G_ALMA,minval=2)
float i_al1_offset = input.float(0.85,"L1 Offset (0-1)",group=G_ALMA,step=0.01,minval=0.0,maxval=1.0)
float i_al1_sigma  = input.float(6.0, "L1 Sigma",group=G_ALMA,step=0.5,minval=1.0)
color i_al1_col    = input.color(color.new(#00FF88,0),"L1 Color (Fast)",group=G_ALMA)
int   i_al1_w      = input.int(1,"L1 Width (1-4)",group=G_ALMA,minval=1,maxval=4)
int   i_al2_len    = input.int(125,  "L2 Length (Medium)",group=G_ALMA,minval=2)
float i_al2_offset = input.float(0.85,"L2 Offset",group=G_ALMA,step=0.01,minval=0.0,maxval=1.0)
float i_al2_sigma  = input.float(6.0, "L2 Sigma",group=G_ALMA,step=0.5,minval=1.0)
color i_al2_col    = input.color(color.new(#FFCC00,0),"L2 Color (Med)",group=G_ALMA)
int   i_al2_w      = input.int(1,"L2 Width (1-4)",group=G_ALMA,minval=1,maxval=4)
int   i_al3_len    = input.int(215,  "L3 Length (Slow)",group=G_ALMA,minval=2)
float i_al3_offset = input.float(0.85,"L3 Offset",group=G_ALMA,step=0.01,minval=0.0,maxval=1.0)
float i_al3_sigma  = input.float(6.0, "L3 Sigma",group=G_ALMA,step=0.5,minval=1.0)
color i_al3_col    = input.color(color.new(#FF0044,0),"L3 Color (Slow)",group=G_ALMA)
int   i_al3_w      = input.int(1,"L3 Width (1-4)",group=G_ALMA,minval=1,maxval=4)

const string G_QA = "⑫ VOLUME INTELLIGENCE (QuantAlgo Consensus)"
int   i_qa_short   = input.int(20,  "Short Window",group=G_QA,minval=5,maxval=100)
int   i_qa_mid     = input.int(50,  "Medium Window",group=G_QA,minval=10,maxval=300)
int   i_qa_long    = input.int(100, "Long Window",group=G_QA,minval=20,maxval=500)
float i_qa_sm_pct  = input.float(90.0,"Small Percentile",group=G_QA,step=1.0,minval=50.0,maxval=95.0)
float i_qa_md_pct  = input.float(93.0,"Medium Percentile",group=G_QA,step=1.0,minval=60.0,maxval=98.0)
float i_qa_bg_pct  = input.float(97.0,"Big Percentile",group=G_QA,step=1.0,minval=70.0,maxval=99.9)
bool  i_qa_show_sm = input.bool(false,"Show Small Clusters",group=G_QA)
bool  i_qa_show_md = input.bool(true,"Show Medium Clusters",group=G_QA)
bool  i_qa_show_bg = input.bool(true,"Show Big Clusters",group=G_QA)
color i_qa_c_buy   = input.color(color.new(#00E676,20),"Bubble BUY Color",group=G_QA)
color i_qa_c_sell  = input.color(color.new(#FF1744,20),"Bubble SELL Color",group=G_QA)
color i_qa_c_mix   = input.color(color.new(#FFD700,30),"Bubble MIXED Color",group=G_QA)
bool  i_qa_show_lbl= input.bool(true, "Show Numbers in Bubbles",group=G_QA,tooltip="Text inside each bubble: Volume / Delta / Ratio")
string i_qa_lbl_cnt= input.string("Volume","Bubble Text",group=G_QA,options=["Volume","Delta","Ratio","Vol+Delta","Vol+Ratio"],tooltip="Volume: raw bar vol\nDelta: net buy-sell (proxy)\nRatio: x SMA50\nVol+Delta / Vol+Ratio: two lines")

const string G_AMT = "⑬ AMT PATTERN ENGINE (Sovereign 24b)"
bool  i_show_amt   = input.bool(true,"Show AMT Patterns",group=G_AMT)
bool  i_amt_rej    = input.bool(true,"  Show Rejection  (reversal wick)",group=G_AMT)
bool  i_amt_abs    = input.bool(true,"  Show Absorption (continuation)",group=G_AMT)
bool  i_amt_ctr    = input.bool(true,"  Show Contrarian (exhaustion warn)",group=G_AMT)
bool  i_amt_acc    = input.bool(true,"  Show Acceptance (balanced)",group=G_AMT)
bool  i_amt_ice    = input.bool(true,"  Show Iceberg at GEX zones (signal)",group=G_AMT)
bool  i_ice_strikes= input.bool(true,"  Show Iceberg warning at SpotEx",group=G_AMT)
float i_amt_wick_rej=input.float(0.40,"Rejection Wick % (of range)",group=G_AMT,step=0.05,minval=0.20,maxval=0.80)
float i_amt_vol_dom =input.float(1.50,"Absorption Dominance Ratio",group=G_AMT,step=0.10,minval=1.10,maxval=3.00)
float i_ice_mass   = input.float(1.8,"Iceberg Mass Threshold (xSMA50)",group=G_AMT,step=0.1,minval=1.2,maxval=3.0)
color i_amt_rej_col= input.color(color.new(#9C27B0,0),"Rejection Color",group=G_AMT)
color i_amt_abs_col= input.color(color.new(#00BCD4,0),"Absorption Color",group=G_AMT)
color i_amt_ice_col= input.color(color.new(#FFD700,0),"Iceberg Color",group=G_AMT)
string i_amt_emj_sz= input.string("Large","AMT Symbol Size (Rejection/Absorption/Iceberg)",group=G_AMT,options=["Small","Normal","Large","Huge"],tooltip="Size of emoji symbols on chart: Rejection / Absorption / Iceberg")

// [v26] BUBBLE CONTEXT — Lower-TF intrabar POSITION → AMT event classifier
const string G_BCTX = "⑬b BUBBLE CONTEXT (LTF Position Engine)"
bool   i_bctx_on   = input.bool(true, "Enable Bubble Context (LTF position → pattern)", group=G_BCTX, tooltip="Upgrades the ⑫ volume bubbles: pulls lower-TF intrabar data to find WHERE inside the current candle the volume/delta cluster sits, then names the AMT event.\n\nBullish candle → cluster at BOTTOM (sellers absorbed)=abs-continue · MID buy=acceptance buy · TOP buy=abs-contrarian · TOP sell=rejection.\nBearish candle = mirror image.")
bool   i_bctx_lbl  = input.bool(true, "  Show Context Labels (abs-continue / acceptance / rejection …)", group=G_BCTX)
bool   i_bctx_dot  = input.bool(true, "  Show Position Dot (bubble at LTF cluster, colored by side)", group=G_BCTX)
string i_bctx_ltf  = input.timeframe("1", "LTF Resolution (intrabar)", group=G_BCTX, tooltip="Lower timeframe used to locate the intrabar cluster. MUST be ≤ chart TF.\nM5 chart: 1 = 5 intrabars · 15S = 20 (finer, needs seconds data) · 5S = 60.")
int    i_bctx_bins = input.int(20, "Position Bins (vertical resolution)", group=G_BCTX, minval=4, maxval=50, tooltip="The candle's high→low range is split into this many horizontal price bins; the bin holding the most LTF volume = the cluster (mini volume-profile POC).")
float  i_bctx_top  = input.float(0.66, "Top Zone Threshold (frac of range)", group=G_BCTX, minval=0.50, maxval=0.90, step=0.01, tooltip="Cluster fraction ≥ this = TOP zone (upper wick / distribution).")
float  i_bctx_bot  = input.float(0.34, "Bottom Zone Threshold (frac of range)", group=G_BCTX, minval=0.10, maxval=0.50, step=0.01, tooltip="Cluster fraction ≤ this = BOTTOM zone (lower wick / accumulation).")
string i_bctx_gate = input.string("Medium+", "Min Bubble Size to Classify", group=G_BCTX, options=["Small+","Medium+","Big only"], tooltip="Only classify bars where a ⑫ volume bubble of at least this tier is visible.")
color  i_bctx_up   = input.color(color.new(#00E676,0), "Bullish-Outcome Label Color", group=G_BCTX, tooltip="Color for abs-continue / acceptance on a bullish candle, and rejection / abs-contrarian on a bearish candle.")
color  i_bctx_dn   = input.color(color.new(#FF1744,0), "Bearish-Outcome Label Color", group=G_BCTX)
string i_bctx_sz   = input.string("Small","Context Label Size",group=G_BCTX,options=["Tiny","Small","Normal","Large"])
bool   i_bctx_arrow= input.bool(true, "  Prefix side arrow on label (▲buy / ▼sell)", group=G_BCTX)

const string G_MOM = "⑭ MOMENTUM — MLMI + SMI"
int   i_mlmi_k     = input.int(987, "MLMI Neighbors (k)",group=G_MOM,minval=10,maxval=2000)
int   i_mlmi_mw    = input.int(10,  "MLMI Momentum Window",group=G_MOM,minval=5,maxval=50)
int   i_mlmi_cap   = input.int(2500,"MLMI Max Stored Trades (perf cap)",group=G_MOM,minval=987,maxval=10000,tooltip="[v24] Bounds the kNN trade memory so the array cannot grow unbounded → kills execution-timeout / array-size RE on deep history.\nKeeps the most-recent N crossover trades. Must be >= k (987). 2500 >> k so prediction is functionally unchanged.")
bool  i_mlmi_gate  = input.bool(true,"Enable MLMI/SMI Signal Gate",group=G_MOM)
int   i_mlmi_d_lon = input.int(8,   "MLMI Decay LON+NY (bars)",group=G_MOM,minval=3,maxval=20)
int   i_mlmi_d_asia= input.int(5,   "MLMI Decay ASIA (bars)",group=G_MOM,minval=2,maxval=15)
int   i_mlmi_expire= input.int(21,  "MLMI Expire (bars)",group=G_MOM,minval=5,maxval=50)
int   i_smi_k      = input.int(10,  "SMI %K Length",group=G_MOM,minval=1,maxval=50)
int   i_smi_d      = input.int(3,   "SMI %D Length",group=G_MOM,minval=1,maxval=20)
int   i_smi_ema    = input.int(3,   "SMI EMA Length",group=G_MOM,minval=1,maxval=20)
float i_smi_ob     = input.float(40.0, "SMI Overbought Level",group=G_MOM,step=1.0)
float i_smi_os     = input.float(-40.0,"SMI Oversold Level",group=G_MOM,step=1.0)

const string G_EMAV = "⑮ EXPECTED MOVE — Annualized Vol"
bool  i_show_em3   = input.bool(true,"Show EM +/-3sigma Band (99.7%)",group=G_EMAV)
color i_c_em3      = input.color(color.new(#FF1744,30),"EM +/-3sigma Color",group=G_EMAV)
bool  i_show_em_lbl= input.bool(true,"Show EM Probability Labels",group=G_EMAV)
bool  i_show_yz_av = input.bool(true,"Show YZ Realized Vol Band",group=G_EMAV)

const string G_QBLK = "⑯ EFP + Q-BLOCK GRID"
bool  i_show_qblk  = input.bool(true,"Show Q-Block Grid Lines",group=G_QBLK)
bool  i_show_basis = input.bool(true,"Show EFP Basis Labels on Chart",group=G_QBLK)
color i_qblk_w0_col= input.color(color.new(#607D8B,30),"W0 ATM Color",group=G_QBLK)
color i_qblk_wu_col= input.color(color.new(#FF1744,40),"W+1/+2 Call Color",group=G_QBLK)
color i_qblk_wd_col= input.color(color.new(#00E676,40),"W-1/-2 Put Color",group=G_QBLK)
int   i_qblk_w     = input.int(1,"Q-Block Line Width",group=G_QBLK,minval=1,maxval=3)

const string G_SQZ = "⑰ SQUEEZE DETECTOR (Yang-Zhang)"
bool   i_sqz_en      = input.bool(true,   "Enable Squeeze Labels",                    group=G_SQZ)
int    i_sqz_yz_fast = input.int(20,      "YZ Fast Window (bars)",                    group=G_SQZ, minval=5, maxval=100, tooltip="Short-window realized vol — responds quickly to compression onset")
int    i_sqz_yz_slow = input.int(100,     "YZ Slow Window (bars)",                    group=G_SQZ, minval=20, maxval=500, tooltip="Long-window structural baseline vol — sets the compression floor")
float  i_sqz_ratio   = input.float(0.7,   "Compression Ratio Threshold",              group=G_SQZ, step=0.05, minval=0.3, maxval=0.95, tooltip="Squeeze ON when fast YZ < slow YZ × this ratio. Lower = tighter squeeze required")
int    i_sqz_min_dur = input.int(3,       "Min Compression Bars (Filter ①)",          group=G_SQZ, minval=1, maxval=20,  tooltip="Squeeze must be compressed for at least this many bars before release is valid. Eliminates 1-2 bar transient false signals")
string i_sqz_up_txt  = input.string("SqUp","Bull Label Text",                         group=G_SQZ)
string i_sqz_dn_txt  = input.string("SqDn","Bear Label Text",                         group=G_SQZ)
color  i_sqz_up_col  = input.color(color.new(#00E676,0), "SqUp Color",                group=G_SQZ)
color  i_sqz_dn_col  = input.color(color.new(#FF1744,0), "SqDn Color",                group=G_SQZ)
int    i_sqz_lbl_tr  = input.int(20,      "Label Background Transparency (0-100)",    group=G_SQZ, minval=0, maxval=100)
string i_sqz_lbl_sz  = input.string("Small","Label Size",                             group=G_SQZ, options=["Tiny","Small","Normal","Large"])
string i_sqz_txt_sz  = input.string("Small","Text Size",                              group=G_SQZ, options=["Tiny","Small","Normal"])
float  i_sqz_offset  = input.float(0.5,   "Label Offset (x ATR14)",                  group=G_SQZ, step=0.1, minval=0.0, maxval=5.0)

const string G_FRZ = "⑱ FROZEN ZONE DISPLAY (BasisMatrix §13)"
bool  i_show_frz   = input.bool(true,  "Show Supply/Demand Frozen Zones", group=G_FRZ)
float i_frz_mult   = input.float(2.0,  "Zone Sensitivity (×σ basis)",     group=G_FRZ, step=0.1)
float i_frz_vfac   = input.float(1.5,  "Volume Spike Factor",              group=G_FRZ, step=0.1)
int   i_frz_warmup = input.int(10,     "Warmup (bars)",                    group=G_FRZ, minval=0, maxval=100)

// [v27] EXPANSION SCORE + MR-INTO-TREND — display-only (label only → 0 plot-budget)
const string G_XMT = "⑲ EXPANSION + MR-INTO-TREND (display)"
bool  i_xmt_on     = input.bool(true,  "Enable Expansion / MR-into-Trend module", group=G_XMT, tooltip="Two reads from the 3-primitives framework:\n• EXPANSION = breakout trigger (this bar's range ≫ trailing average).\n• MR-into-TREND = buy-the-dip WITH the trend (pullback/retest to the g1 flip level inside an established trend — NOT a fade against it).\nDISPLAY-ONLY: no gate / conf_score / entry touched.")
bool  i_exp_lbl    = input.bool(true,  "  Show Expansion labels", group=G_XMT)
int   i_exp_len    = input.int(5,      "  Expansion avg window (bars)", group=G_XMT, minval=2, maxval=100, tooltip="Trailing bars for the average range. Transcript: last 5 candles avg 1%, 6th = 2% → expansion.")
float i_exp_thr    = input.float(2.0,  "  Expansion multiple (× avg range)", group=G_XMT, step=0.1, minval=1.1, tooltip="Flag EXPANSION when this bar's range ≥ this × average range.")
bool  i_mrt_lbl    = input.bool(true,  "  Show MR-into-Trend labels", group=G_XMT)
int   i_mrt_look   = input.int(20,     "  Retrace lookback (bars)", group=G_XMT, minval=5, maxval=200, tooltip="Bars used to find the recent swing extreme for the pullback-depth read shown in the tooltip.")
color i_xmt_up     = input.color(color.new(#00E676,0), "  Bullish label color", group=G_XMT)
color i_xmt_dn     = input.color(color.new(#FF1744,0), "  Bearish label color", group=G_XMT)
color i_exp_col    = input.color(color.new(#FFD700,0), "  Expansion label color", group=G_XMT)
string i_xmt_sz    = input.string("Small","  Label size",group=G_XMT,options=["Tiny","Small","Normal","Large"])

// [v28] REGIME MATRIX + Γ-PROXY — display-only (one table → 0 plot-budget)
const string G_RM = "⑳ REGIME MATRIX + Γ-PROXY (display)"
bool   i_rm_on     = input.bool(true, "Enable Regime Matrix + Γ-proxy", group=G_RM, tooltip="Unifies direction × volatility into the 6-regime matrix + a POSITIVE/NEGATIVE-gamma PROXY, and prescribes fade / follow / stand-aside.\n\nΓ-proxy = a VOL-BEHAVIOUR proxy, NOT real dealer gamma (gold spot has no options chain). It reads the FOOTPRINT gamma leaves: vol dampening (pos-Γ → fade, failed breakouts) vs amplification (neg-Γ → follow, trends). Eyes, not a validated edge.\nDISPLAY-ONLY — no gate / conf_score / entry touched.")
int    i_rm_dir_len= input.int(200, "  Direction baseline EMA (bars)", group=G_RM, minval=20, maxval=1000, tooltip="Bull if close>baseline & rising, Bear if close<baseline & falling, else Sideways.")
int    i_rm_dir_sl = input.int(20,  "  Baseline slope lookback (bars)", group=G_RM, minval=2, maxval=200)
int    i_rm_vr_k   = input.int(6,   "  Variance Ratio k", group=G_RM, minval=2, maxval=50, tooltip="VR(k)=Var(k-bar ret)/(k·Var(1-bar ret)). >1 trending (neg-Γ) · <1 mean-revert (pos-Γ). Replaces Hurst (same persistence read; Hurst still lives in QC).")
int    i_rm_vr_len = input.int(100, "  Variance Ratio window", group=G_RM, minval=20, maxval=500)
int    i_rm_er_len = input.int(20,  "  Trend-efficiency (ER) window", group=G_RM, minval=5, maxval=200, tooltip="Kaufman efficiency = |net move| / path. High=follow-through (neg-Γ), low=chop/failed-BO (pos-Γ). Used only as ONE Γ-vote (not a direction gate — that's the ER lesson).")
int    i_rm_rv_len = input.int(20,  "  Realized-vol window (vs GVZ)", group=G_RM, minval=10, maxval=200, tooltip="Annualized realized vol compared to GVZ implied. RV≫GVZ = vol-amplifying (neg-Γ); RV≪GVZ = dampening (pos-Γ). The honest IV-vs-RV analog.")
string i_rm_pos    = input.string("Top Left", "  Table position", group=G_RM, options=["Top Left","Top Center","Top Right","Middle Left","Middle Right","Bottom Left","Bottom Center","Bottom Right"])
string i_rm_sz     = input.string("Small", "  Table text size", group=G_RM, options=["Tiny","Small","Normal","Large"])
color  i_rm_bg     = input.color(color.new(color.black, 0), "  Table background", group=G_RM)
// [v29] auto-flip ACTION when Γ overrides the direction-follow
bool   i_rm_autoflip = input.bool(true, "  Auto-flip ACTION on Γ conflict [v29]", group=G_RM, tooltip="When the Γ-proxy strongly contradicts the direction cell (POS-Γ under a FOLLOW/SHORT-TREND cell, or NEG-Γ under an MR-FADE cell), flip the ACTION headline (FADE/RANGE ↔ FOLLOW/BREAK) + route + colour. OFF = v28 behaviour (headline stays, only a ⚠ tag). Info is identical either way — this only removes the mis-read.")
int    i_rm_gth      = input.int(2, "  Γ-conflict threshold |score|", group=G_RM, minval=1, maxval=5, tooltip="Flip only when |Γ-score| ≥ this (2 = POS/NEG-Γ, 3 = strong).")
int    i_rm_hyst     = input.int(3, "  Flip hysteresis (bars)", group=G_RM, minval=1, maxval=50, tooltip="Conflict must persist this many bars before the headline flips — kills flicker.")
// [v29] ADX / DI — isolated, table rows only (0 plot-budget)
bool   i_rm_adx      = input.bool(false, "  Show ADX/DI rows [v29]", group=G_RM, tooltip="Adds ADX (trend strength) + DI+/DI− (direction) rows to the table. ⚠ ADX is direction-agnostic — read it WITH DI, never as a lone gate (the ER lesson). Display-only.")
int    i_rm_adx_len  = input.int(14, "  ADX/DI length", group=G_RM, minval=2, maxval=100)
int    i_rm_adx_sm   = input.int(14, "  ADX smoothing", group=G_RM, minval=2, maxval=100)
float  i_rm_adx_str  = input.float(25.0, "  ADX strong level", group=G_RM, minval=10.0, maxval=60.0)
// [v29] deep-Fib premium / discount — isolated, box/line/label only (0 plot-budget)
bool   i_rm_fib      = input.bool(false, "  Show deep-Fib premium/discount [v29]", group=G_RM, tooltip="Splits a swing range into PREMIUM (upper — sell) / DISCOUNT (lower — buy) with the deep 0.705–0.886 zones (Kmer 'trade from discount'). Drawn as boxes on price (line/box/label = 0 plot-budget). Display-only.")
int    i_rm_fib_len  = input.int(60, "  Fib swing lookback (bars)", group=G_RM, minval=10, maxval=500)
float  i_rm_fib_lo   = input.float(0.705, "  Deep-Fib low", group=G_RM, minval=0.5, maxval=0.8, step=0.001)
float  i_rm_fib_hi   = input.float(0.886, "  Deep-Fib high", group=G_RM, minval=0.7, maxval=0.95, step=0.001)
color  i_rm_fib_disc = input.color(color.new(#26A69A,0), "  Discount zone (buy) color", group=G_RM)
color  i_rm_fib_prem = input.color(color.new(#EF5350,0), "  Premium zone (sell) color", group=G_RM)
// ═══════════════════════════════════════════════════════════════════════════════
// §2  TYPES + FUNCTIONS
// ═══════════════════════════════════════════════════════════════════════════════
type MLMIData
    array<float> parameter1
    array<float> parameter2
    array<float> priceArray
    array<float> resultArray

method mlmi_store(MLMIData d, float p1, float p2) =>
    d.parameter1.push(d.parameter1.get(d.parameter1.size() - 1))
    d.parameter2.push(d.parameter2.get(d.parameter2.size() - 1))
    d.priceArray.push(d.priceArray.get(d.priceArray.size() - 1))
    d.resultArray.push(close >= d.priceArray.get(d.priceArray.size() - 1) ? 1.0 : -1.0)
    d.parameter1.set(d.parameter1.size() - 1, p1)
    d.parameter2.set(d.parameter2.size() - 1, p2)
    d.priceArray.set(d.priceArray.size() - 1, close)
    // [v24-2] RE-FIX: bound kNN memory — drop oldest trades beyond cap (keeps recent regime)
    int _cap = math.max(i_mlmi_cap, i_mlmi_k)
    if d.parameter1.size() > _cap
        d.parameter1.shift()
        d.parameter2.shift()
        d.priceArray.shift()
        d.resultArray.shift()

method mlmi_predict(MLMIData d, float p1, float p2, int k) =>
    distances = array.new_float(0)
    int n = d.parameter1.size() - 1
    for i = 0 to n
        float dist = math.sqrt(math.pow(p1 - d.parameter1.get(i), 2.0) + math.pow(p2 - d.parameter2.get(i), 2.0))
        distances.push(dist)
    sortedD = distances.copy()
    sortedD.sort()
    selected = sortedD.slice(0, math.min(k, sortedD.size()))
    float maxDist = selected.max()
    neighbors = array.new_float(0)
    for i = 0 to distances.size() - 1
        if distances.get(i) <= maxDist
            neighbors.push(d.resultArray.get(i))
    neighbors.sum()

f_alma(float src, int len, float off, float sig) =>
    float _m = off * float(len - 1)
    float _s = float(len) / sig
    float _ws = 0.0
    float _wv = 0.0
    for _i = 0 to len - 1
        float _w = math.exp(-math.pow(float(_i) - _m, 2.0) / (2.0 * math.pow(_s, 2.0)))
        _wv += src[len - 1 - _i] * _w
        _ws += _w
    _ws > 0.0 ? _wv / _ws : src

f_ls(string s) =>
    switch s
        "Solid"  => line.style_solid
        "Dotted" => line.style_dotted
        =>          line.style_dashed

f_lsz(string s) =>
    switch s
        "Small"  => size.small
        "Normal" => size.normal
        =>          size.tiny

f_dsz(string s) =>
    switch s
        "tiny"   => size.tiny
        "normal" => size.normal
        =>          size.small

// Yang-Zhang realized volatility estimator (gold desk standard)
f_yz(_len, _mult) =>
    float _c_ret = math.log(math.max(close / math.max(open,  syminfo.mintick), syminfo.mintick))  // log(Close/Open)
    float _o_ret = math.log(math.max(open  / math.max(nz(close[1], close), syminfo.mintick), syminfo.mintick))  // log(Open/Close_prev)
    float _ho    = math.log(math.max(high  / math.max(open,  syminfo.mintick), syminfo.mintick))
    float _lo    = math.log(math.max(low   / math.max(open,  syminfo.mintick), syminfo.mintick))
    float _v_c   = ta.variance(_c_ret, _len)   // V_close
    float _v_o   = ta.variance(_o_ret, _len)   // V_overnight
    float _vrs   = ta.sma((_ho * (_ho - _c_ret)) + (_lo * (_lo - _c_ret)), _len)
    float _k     = 0.34 / (1.34 + float(_len + 1) / float(math.max(_len - 1, 1)))
    float _vyz   = _v_o + _k * _v_c + (1.0 - _k) * _vrs
    math.sqrt(math.max(_vyz, 0.0)) * close * _mult

f_touch(float price, float target) => math.abs(price - target) <= i_tol

f_dir_score(bool _is_buy, bool _bub_b3, bool _bub_s3, bool _gvz_c, bool _gvz_n, bool _gvz_el, bool _gvz_ex, string _sig_rg, bool _is_l, bool _is_n, bool _is_a, bool _dxy_pb, bool _dxy_ps, bool _frm_ok, bool _sqz_u, bool _sqz_d, float _b_dev) =>
    int sc = 50
    sc := sc + (_is_buy  and _bub_b3 ? 12 : 0)
    sc := sc - (_is_buy  and _bub_s3 ? 10 : 0)
    sc := sc + (not _is_buy and _bub_s3 ? 12 : 0)
    sc := sc - (not _is_buy and _bub_b3 ? 10 : 0)
    sc := sc + (_gvz_c ? 12 : _gvz_n ? 6 : _gvz_el ? -8 : _gvz_ex ? -20 : 0)
    sc := sc + (_sig_rg == "COMPRESSED" ? 8 : _sig_rg == "NORMAL" ? 4 : _sig_rg == "EXPANDING" ? -5 : -12)
    sc := sc + (_is_l ? 8 : _is_n ? 4 : _is_a ? -8 : 0)
    sc := sc - (_is_buy  and _dxy_pb ? 10 : 0)
    sc := sc - (not _is_buy and _dxy_ps ? 10 : 0)
    sc := sc + (_frm_ok ? 5 : -10)
    sc := sc + (_is_buy  and _sqz_u ? 8 : 0)
    sc := sc + (not _is_buy and _sqz_d ? 8 : 0)
    sc := sc + (_b_dev < 1.0 ? 5 : _b_dev > 2.0 ? -5 : 0)
    math.min(95, math.max(5, sc))

f_body(float o, float c, float h, float l) =>
    float rng = math.max(math.abs(h - l), syminfo.mintick)
    math.abs(c - o) / rng

f_emaema(float src, int len) =>
    ta.ema(ta.ema(src, len), len)

f_qa_cons(bool pS, bool pM, bool pL) =>
    int hits = (pS ? 1 : 0) + (pM ? 1 : 0) + (pL ? 1 : 0)
    hits >= 2

// QuantAlgo volume formatter (K/M/B)
f_qa_fmtn(float v) =>
    float av  = math.abs(v)
    string sg = v < 0.0 ? "-" : ""
    string result = sg + str.tostring(av, "#")
    if av >= 1000000000.0
        result := sg + str.tostring(av / 1000000000.0, "#.##") + "B"
    else if av >= 1000000.0
        result := sg + str.tostring(av / 1000000.0, "#.##") + "M"
    else if av >= 1000.0
        result := sg + str.tostring(av / 1000.0, "#.##") + "K"
    result
// ═══════════════════════════════════════════════════════════════════════════════
// §3  RS DATA FETCH  (7 calls — _efp_fut_h4 H4 restored in v21 revised)
// ═══════════════════════════════════════════════════════════════════════════════
float fut_live    = request.security(i_fut_sym, timeframe.period, close,    barmerge.gaps_off, barmerge.lookahead_off, ignore_invalid_symbol=true)
float fut_d       = request.security(i_fut_sym, "D",             close[1],  barmerge.gaps_off, barmerge.lookahead_off, ignore_invalid_symbol=true)
float spt_d       = request.security(syminfo.tickerid, "D",      close[1],  barmerge.gaps_off, barmerge.lookahead_off)
float gvz_d       = request.security(i_gvz_sym, "D",             close[1],  barmerge.gaps_off, barmerge.lookahead_off, ignore_invalid_symbol=true)
float fut_1m      = na  // not fetched; see basis_1m below
float _efp_fut_h4 = request.security(i_fut_sym, "240", close[1], barmerge.gaps_off, barmerge.lookahead_off, ignore_invalid_symbol=true)
float _efp_spt_h4 = request.security(syminfo.tickerid, "240",    close[1],  barmerge.gaps_off, barmerge.lookahead_off)
float dxy_raw     = request.security("TVC:DXY", "D",              close[1], barmerge.gaps_off, barmerge.lookahead_off, ignore_invalid_symbol=true)

float fut_now  = nz(fut_live, close)
float d_spt    = nz(spt_d,  close)
float d_fut    = nz(fut_d,  fut_now)
float gvz_v    = nz(gvz_d,  18.0)
float basis_1m = fut_now - close  // fut_1m RS removed (saves 6 plot-budget units); equivalent to raw_basis

// ═══════════════════════════════════════════════════════════════════════════════
// §4  BASIS ENGINE + COMEX CIRCUIT BREAKER TIERS
// ═══════════════════════════════════════════════════════════════════════════════
float raw_basis  = fut_now - close
float b_mean     = ta.sma(raw_basis, i_basis_len)
float b_std      = ta.stdev(raw_basis, i_basis_len)
float p_std      = ta.stdev(fut_now, i_basis_len)
float atr14      = ta.atr(14)
float vol_sma50  = ta.sma(volume, 50)

int   _hm       = hour(time,"UTC+0") * 100 + minute(time,"UTC+0")
bool  _is_asia  = _hm >= 2000 or _hm < 300
bool  _is_lon   = _hm >= 300  and _hm < 800
bool  _is_ny    = _hm >= 800  and _hm < 1700
int   _cur_sess = _is_ny ? 3 : _is_lon ? 2 : 1

// LBMA and CME NY Fix windows (UTC)
int  _fix_hm    = _hm
bool in_lbma_am = _fix_hm >= 1000 and _fix_hm < 1030
bool in_lbma_pm = _fix_hm >= 1500 and _fix_hm < 1515
bool in_fix     = in_lbma_am or in_lbma_pm
bool in_pre_fix = (_fix_hm >= 930 and _fix_hm < 1000) or (_fix_hm >= 1430 and _fix_hm < 1500)
bool is_globex_open = dayofweek == dayofweek.sunday and _hm >= 2300
string fix_lbl  = in_lbma_am ? "AM FIX" : in_lbma_pm ? "PM FIX" : in_pre_fix ? "PRE-FIX" : is_globex_open ? "GLOBEX OPEN" : ""

bool  _sess_ok_mr = not i_sess_filt or not _is_asia

var int   _last_s = 0
var float _frozen = na
if na(_frozen) and not na(raw_basis)
    _frozen := raw_basis

bool is_new_day = dayofmonth != dayofmonth[1] or month != month[1] or year != year[1]

int  _prev_sess = _last_s
if _cur_sess != _last_s
    _last_s  := _cur_sess
    _frozen  := nz(raw_basis, nz(b_mean, 0.0))
float fb = nz(_frozen, nz(b_mean, 0.0))

var float _snap_asia = na
var float _snap_lon  = na
var float _snap_ny   = na
var string _sess_lbl = "--"

bool _sess_flip = _cur_sess != 0 and _cur_sess != _prev_sess
if _sess_flip
    if _cur_sess == 1
        _sess_lbl  := "ASIA"
        _snap_asia := nz(raw_basis, 0.0)
    else if _cur_sess == 2
        _sess_lbl := "LON"
        _snap_lon := nz(raw_basis, 0.0)
    else if _cur_sess == 3
        _sess_lbl := "NY"
        _snap_ny  := nz(raw_basis, 0.0)

float _snap_sess = _cur_sess == 3 ? nz(_snap_ny, nz(raw_basis, fb)) : _cur_sess == 2 ? nz(_snap_lon, nz(raw_basis, fb)) : nz(_snap_asia, nz(raw_basis, fb))

float _rb_safe  = nz(raw_basis, nz(raw_basis[1], nz(raw_basis[2], 0.0)))
float _bv_raw   = _rb_safe - nz(_rb_safe[5], _rb_safe)
float basis_vel = b_std > 0.0 ? _bv_raw / b_std : 0.0
bool  basis_conv= (raw_basis > 0 and basis_vel < -0.2) or (raw_basis < 0 and basis_vel > 0.2)
bool  basis_divg= (raw_basis > 0 and basis_vel > 0.2)  or (raw_basis < 0 and basis_vel < -0.2)
string basis_trend_s = basis_conv ? "CONV" : basis_divg ? "DIV" : "FLAT"

var float[] _sz_asia = array.new_float(0)
var float[] _sz_lon  = array.new_float(0)
var float[] _sz_ny   = array.new_float(0)
if barstate.isconfirmed and not na(raw_basis)
    if _is_asia
        array.push(_sz_asia, raw_basis)
        if array.size(_sz_asia) > 60
            array.shift(_sz_asia)
    else if _is_lon
        array.push(_sz_lon, raw_basis)
        if array.size(_sz_lon) > 60
            array.shift(_sz_lon)
    else
        array.push(_sz_ny, raw_basis)
        if array.size(_sz_ny) > 60
            array.shift(_sz_ny)
float[] _cur_sarr = _cur_sess == 3 ? _sz_ny : _cur_sess == 2 ? _sz_lon : _sz_asia
float _sess_mean  = array.size(_cur_sarr) > 1 ? array.avg(_cur_sarr)    : nz(b_mean, fb)
float _sess_std   = array.size(_cur_sarr) > 1 ? array.stdev(_cur_sarr) : nz(b_std, 0.5)
float sess_z      = _sess_std > 0.0 ? (_rb_safe - _sess_mean) / _sess_std : 0.0
bool  sess_z_ext  = math.abs(sess_z) >= 2.0

float _gofo_rate_dec = i_gofo_rate / 100.0
float gofo_carry     = close * _gofo_rate_dec * (30.0 / 365.0)
float gofo_excess    = _rb_safe - gofo_carry
bool  gofo_backw     = gofo_excess < -nz(b_std, 0.5) * 0.3
bool  gofo_cont      = gofo_excess > nz(b_std,  0.5) * 0.3
string gofo_regime   = gofo_backw ? "BACKWRD" : gofo_cont ? "CNTNG+" : "FAIR"

float bm = switch i_efp_mode
    "SESSION"  => _snap_sess
    "1-MINUTE" => basis_1m
    => nz(b_mean, fb)

float basis_cv     = math.abs(bm) > 0.001 ? math.abs(b_std / bm) : 1.0
bool  basis_stable = basis_cv <= 0.5
string basis_qual  = basis_stable ? "STABLE" : "UNSTABLE"
float _basis_delta = _rb_safe - fb
bool  is_divergent = b_std > 0.0 and math.abs(_basis_delta) >= b_std * 1.5

float _cb_settle  = nz(d_fut, close)  // prior COMEX futures settlement
float cb_t1_u     = _cb_settle * 1.03
float cb_t1_d     = _cb_settle * 0.97
float cb_t2_u     = _cb_settle * 1.06
float cb_t2_d     = _cb_settle * 0.94
float cb_t3_u     = _cb_settle * 1.09
float cb_t3_d     = _cb_settle * 0.91
bool cb_t1_active = close > cb_t1_u or close < cb_t1_d
bool cb_t2_active = close > cb_t2_u or close < cb_t2_d
bool cb_t3_active = close > cb_t3_u or close < cb_t3_d
string cb_tier_str = cb_t3_active ? "CB-T3 ±9%" : cb_t2_active ? "CB-T2 ±6%" : cb_t1_active ? "CB-T1 ±3%" : "CB:NORM"
color  cb_tier_col = cb_t3_active ? #D500F9 : cb_t2_active ? #FF1744 : cb_t1_active ? #FF9800 : #00E676

float _efp_orig = not na(_efp_fut_h4) and not na(_efp_spt_h4)
     ? _efp_fut_h4 - _efp_spt_h4
     : nz(d_fut, close) - nz(d_spt, close)
float bm_h4         = _efp_orig
float fut_impl_h4   = close + bm_h4
float base_block_h4 = math.round(fut_impl_h4 / i_block) * i_block
float qb_h4_u2 = base_block_h4 + (i_block * 2.0) - bm_h4
float qb_h4_u1 = base_block_h4 + i_block          - bm_h4
float qb_h4_0  = base_block_h4                    - bm_h4
float qb_h4_d1 = base_block_h4 - i_block          - bm_h4
float qb_h4_d2 = base_block_h4 - (i_block * 2.0)  - bm_h4
float basis_drift     = bm - bm_h4
string basis_mode_str = math.abs(basis_drift) > b_std * 0.5 ? "DRIFT $" + str.tostring(math.abs(basis_drift),"#.##") : "STABLE"

float efp_d = d_fut - d_spt
// ═══════════════════════════════════════════════════════════════════════════════
// §5  SPOTEX LEVELS
// ═══════════════════════════════════════════════════════════════════════════════
float implied_spot = fut_now - bm

float _atm_c = math.ceil(fut_now  / i_block) * i_block
float _atm_p = math.floor(fut_now / i_block) * i_block

float sp_c1 = _atm_c                   - bm
float sp_c2 = (_atm_c + i_block)       - bm
float sp_c3 = (_atm_c + i_block * 2.0) - bm
float sp_c4 = (_atm_c + i_block * 3.0) - bm
float sp_p1 = _atm_p                   - bm
float sp_p2 = (_atm_p - i_block)       - bm
float sp_p3 = (_atm_p - i_block * 2.0) - bm
float sp_p4 = (_atm_p - i_block * 3.0) - bm

float sd_u = implied_spot + p_std * i_sd_mult
float sd_d = implied_spot - p_std * i_sd_mult

float _pbv_anc = d_spt + efp_d
float pbv_l1_u = _pbv_anc * (1.0 + i_pbv_1 / 100.0) - efp_d
float pbv_l1_d = _pbv_anc * (1.0 - i_pbv_1 / 100.0) - efp_d
float pbv_l2_u = _pbv_anc * (1.0 + i_pbv_2 / 100.0) - efp_d
float pbv_l2_d = _pbv_anc * (1.0 - i_pbv_2 / 100.0) - efp_d
float pbv_l3_u = _pbv_anc * (1.0 + i_pbv_3 / 100.0) - efp_d
float pbv_l3_d = _pbv_anc * (1.0 - i_pbv_3 / 100.0) - efp_d

// ═══════════════════════════════════════════════════════════════════════════════
// §6  GEX PHYSICS ENGINE + VWAP (London daily-reset fix) + ALMA
// ═══════════════════════════════════════════════════════════════════════════════
bool is_lon_open = _hm == 300
var float _lv_pv = 0.0
var float _lv_v  = 0.0
var bool  _lon_started = false

if is_new_day
    _lv_pv       := 0.0
    _lv_v        := 0.0
    _lon_started := false

if is_lon_open or (not _lon_started and _is_lon)
    _lv_pv := hlc3 * volume
    _lv_v  := volume
    _lon_started := true
else if _lon_started
    _lv_pv += hlc3 * volume
    _lv_v  += volume
float lon_vwap = _lv_v > 0.0 ? _lv_pv / _lv_v : hlc3

var float _dv_pv = 0.0
var float _dv_v  = 0.0
if is_new_day
    _dv_pv := 0.0
    _dv_v  := 0.0
_dv_pv += hlc3 * volume
_dv_v  += volume
float daily_vwap = _dv_v > 0.0 ? _dv_pv / _dv_v : hlc3
float anchor     = _lon_started ? lon_vwap : daily_vwap

float sigma_raw       = f_yz(i_vol_lb, i_vol_mult)
float sigma_floor_val = nz(atr14, sigma_raw) * i_sig_floor
float sigma           = math.max(sigma_raw, sigma_floor_val)

float sigma_pct   = anchor > 0 ? sigma / anchor * 100.0 : 0.0
string sig_regime = sigma_pct < 0.8 ? "COMPRESSED" : sigma_pct < 1.5 ? "NORMAL" : sigma_pct < 2.5 ? "EXPANDING" : "EXTREME"
color  sig_r_col  = sigma_pct < 0.8 ? #00BCD4 : sigma_pct < 1.5 ? #B0BEC5 : sigma_pct < 2.5 ? #FF9800 : #FF1744

float _g1_eff  = i_sigma_mode == "GAUSSIAN" ? 1.0 : i_g1
float _g2_eff  = i_sigma_mode == "GAUSSIAN" ? 2.0 : i_g2
float _g3_eff  = i_sigma_mode == "GAUSSIAN" ? 3.0 : i_g3
string _prob_g1= i_sigma_mode == "GAUSSIAN" ? "68.3%" : "89.4%"
string _prob_g2= i_sigma_mode == "GAUSSIAN" ? "95.5%" : "99.9%"

float g1_up = anchor + sigma * _g1_eff
float g1_dn = anchor - sigma * _g1_eff
float g2_up = anchor + sigma * _g2_eff
float g2_dn = anchor - sigma * _g2_eff
float g3_up = anchor + sigma * _g3_eff
float g3_dn = anchor - sigma * _g3_eff

float frame_width = g1_up - g1_dn
bool  frame_ok    = frame_width >= i_tol * 4.0

float em_1sigma  = gvz_v > 0.0 and not na(gvz_d) ? close * (gvz_v / 100.0) / math.sqrt(252.0) : sigma * 4.8
float em_upper   = anchor + em_1sigma
float em_lower   = anchor - em_1sigma
float em_upper_2 = anchor + em_1sigma * 2.0
float em_lower_2 = anchor - em_1sigma * 2.0
float em_upper_3 = anchor + em_1sigma * 3.0
float em_lower_3 = anchor - em_1sigma * 3.0
float yz_band_u  = anchor + sigma * 1.0
float yz_band_d  = anchor - sigma * 1.0

float _gvz_roc_em = gvz_v > 0.0 and gvz_v[1] > 0.0 ? gvz_v - gvz_v[1] : 0.0
float _price_roc  = close > 0.0 and close[5] > 0.0 ? (close - close[5]) / close[5] * 100.0 : 0.0
bool  rr_put_skew  = _gvz_roc_em > 0.5 and _price_roc < -0.1
bool  rr_call_skew = _gvz_roc_em < -0.5 and _price_roc > 0.1
string rr_str = rr_put_skew ? "PUT SKEW (RR-)" : rr_call_skew ? "CALL SKEW (RR+)" : "NEUTRAL"
color  rr_col = rr_put_skew ? color.new(#FF1744,0) : rr_call_skew ? color.new(#00E676,0) : color.new(#B0BEC5,0)

float _buy_vol   = close >= open ? volume : 0.0
float _sell_vol  = close < open  ? volume : 0.0
float _bv_ema    = ta.ema(_buy_vol,  20)
float _sv_ema    = ta.ema(_sell_vol, 20)
float _tot_ema   = math.max(_bv_ema + _sv_ema, 1.0)
float vpin_proxy = (_bv_ema - _sv_ema) / _tot_ema
bool  vpin_bull  = vpin_proxy > 0.2
bool  vpin_bear  = vpin_proxy < -0.2
string vpin_str  = vpin_bull ? "INST BUY " + str.tostring(vpin_proxy * 100,"#") + "%" : vpin_bear ? "INST SELL " + str.tostring(math.abs(vpin_proxy) * 100,"#") + "%" : "BALANCED"
color  vpin_col  = vpin_bull ? color.new(#00E676,0) : vpin_bear ? color.new(#FF1744,0) : color.new(#B0BEC5,0)

float alma_l1 = i_show_alma ? f_alma(close, i_al1_len, i_al1_offset, i_al1_sigma) : na
float alma_l2 = i_show_alma ? f_alma(close, i_al2_len, i_al2_offset, i_al2_sigma) : na
float alma_l3 = i_show_alma ? f_alma(close, i_al3_len, i_al3_offset, i_al3_sigma) : na
bool  alma_bull    = not na(alma_l1) and alma_l1 > alma_l2 and alma_l2 > alma_l3
bool  alma_bear    = not na(alma_l1) and alma_l1 < alma_l2 and alma_l2 < alma_l3
string alma_regime  = alma_bull ? "BULL" : alma_bear ? "BEAR" : "MIXED"
color  alma_reg_col = alma_bull ? #00FF88 : alma_bear ? #FF0044 : #B0BEC5

float qb_0  = math.round(fut_now / i_block) * i_block - bm
float qb_u1 = qb_0 + i_block
float qb_u2 = qb_0 + i_block * 2.0
float qb_d1 = qb_0 - i_block
float qb_d2 = qb_0 - i_block * 2.0

// ═══════════════════════════════════════════════════════════════════════════════
// §5b  DUAL-SYSTEM SD LEVELS
// ═══════════════════════════════════════════════════════════════════════════════
float sd_phi_u = implied_spot + p_std * i_sd_mult
float sd_phi_d = implied_spot - p_std * i_sd_mult

float sigma_delta = gvz_v > 0.0 and not na(gvz_d) ?
     close * (gvz_v / 100.0) / math.sqrt(252.0) * math.sqrt(math.max(i_delta_dte, 0.1)) :
     sigma * 4.8

float _sd_45d_u = anchor + sigma_delta * 0.125
float _sd_45d_d = anchor - sigma_delta * 0.125
float _sd_35d_u = anchor + sigma_delta * 0.385
float _sd_35d_d = anchor - sigma_delta * 0.385
float _sd_25d_u = anchor + sigma_delta * 0.674
float _sd_25d_d = anchor - sigma_delta * 0.674
float _sd_15d_u = anchor + sigma_delta * 1.036 * i_skew_15d_c
float _sd_15d_d = anchor - sigma_delta * 1.036 * i_skew_15d_p
float _sd_5d_u  = anchor + sigma_delta * 1.645 * i_skew_5d_c
float _sd_5d_d  = anchor - sigma_delta * 1.645 * i_skew_5d_p

if i_sd_signal == "DELTA"
    sd_u := _sd_25d_u
    sd_d := _sd_25d_d
else
    sd_u := sd_phi_u
    sd_d := sd_phi_d

bool _sd_25d_u_in_frame = _sd_25d_u < g1_up and _sd_25d_u > g1_dn
bool _sd_25d_d_in_frame = _sd_25d_d > g1_dn and _sd_25d_d < g1_up
bool _sd_15d_u_in_frame = _sd_15d_u < g1_up and _sd_15d_u > g1_dn
bool _sd_15d_d_in_frame = _sd_15d_d > g1_dn and _sd_15d_d < g1_up
bool _sd_phi_u_in_frame = sd_phi_u < g1_up and sd_phi_u > g1_dn
bool _sd_phi_d_in_frame = sd_phi_d > g1_dn and sd_phi_d < g1_up
bool _sd_25d_u_conf = math.abs(g3_up - _sd_25d_u) <= i_tol * 2.5
bool _sd_25d_d_conf = math.abs(g3_dn - _sd_25d_d) <= i_tol * 2.5
bool _sd_phi_u_conf = math.abs(g3_up - sd_phi_u)  <= i_tol * 2.5
bool _sd_phi_d_conf = math.abs(g3_dn - sd_phi_d)  <= i_tol * 2.5
bool _using_delta_sig = i_sd_signal == "DELTA"
bool _show_phi_sys    = i_show_sd and i_show_phi
bool _show_delta_sys  = i_show_sd and i_show_delta_sys
// ═══════════════════════════════════════════════════════════════════════════════
// §7  GVZ VOLATILITY REGIME
// ═══════════════════════════════════════════════════════════════════════════════
float gvz_sma = ta.sma(gvz_v, 20)
float gvz_z   = gvz_sma > 0 ? (gvz_v - gvz_sma) / math.max(ta.stdev(gvz_v, 20), 0.001) : 0.0
bool gvz_compressed = not na(gvz_d) and gvz_v < i_gvz_norm
bool gvz_normal     = not na(gvz_d) and gvz_v >= i_gvz_norm and gvz_v < i_gvz_elev
bool gvz_elevated   = not na(gvz_d) and gvz_v >= i_gvz_elev and gvz_v < i_gvz_ext
bool gvz_extreme    = not na(gvz_d) and gvz_v >= i_gvz_ext
bool gvz_spiking    = gvz_z > 1.5 and not gvz_compressed
bool gvz_crisis     = gvz_z > 2.5
bool gvz_block_mr   = i_gvz_en and (gvz_extreme or gvz_crisis)
bool gvz_reduce_mr  = i_gvz_en and (gvz_elevated or gvz_spiking)
string gvz_tier     = gvz_extreme ? "EXTREME" : gvz_elevated ? "ELEVATED" : gvz_normal ? "NORMAL" : "COMPRESSED"
color  gvz_tier_col = gvz_extreme ? #FF1744 : gvz_elevated ? #FF9800 : gvz_normal ? #B0BEC5 : #00BCD4

// ═══════════════════════════════════════════════════════════════════════════════
// §8  DXY MACRO FILTER  [v19 fix: fully implemented — was stub in v18]
// ═══════════════════════════════════════════════════════════════════════════════
float dxy_now   = nz(dxy_raw, 100.0)
var float _dxy_prev = na
var float _dxy_d1   = na
if is_new_day and dxy_now > 0.0
    _dxy_prev := _dxy_d1
    _dxy_d1   := dxy_now
float _dxy_ref  = nz(_dxy_prev, dxy_now)
float dxy_roc   = _dxy_ref > 0.0 ? (dxy_now - _dxy_ref) / _dxy_ref * 100.0 : 0.0
bool  dxy_bull         = i_dxy_en and dxy_roc >  i_dxy_thr
bool  dxy_bear         = i_dxy_en and dxy_roc < -i_dxy_thr
bool  dxy_penalise_buy  = dxy_bull   // DXY rising → headwind for Gold long
bool  dxy_penalise_sell = dxy_bear   // DXY falling → headwind for Gold short
color dxy_col = dxy_bull ? color.new(#FF1744,0) : dxy_bear ? color.new(#00E676,0) : color.new(#B0BEC5,0)
string dxy_str = dxy_bull ? "DXY+" + str.tostring(dxy_roc,"#.##") + "% BEARISH XAU" : dxy_bear ? "DXY" + str.tostring(dxy_roc,"#.##") + "% BULLISH XAU" : "DXY NEUTRAL"

// ═══════════════════════════════════════════════════════════════════════════════
// §9  MLMI COMPUTATION  (k=987, momentumWindow=10, session-aware decay)
// ═══════════════════════════════════════════════════════════════════════════════
float _ml_ma_q  = ta.wma(close, 5)
float _ml_ma_s  = ta.wma(close, 20)
float _ml_rsi_q = ta.wma(ta.rsi(close, 5),  i_mlmi_mw)
float _ml_rsi_s = ta.wma(ta.rsi(close, 20), i_mlmi_mw)
bool  _ml_pos   = ta.crossover(_ml_ma_q,  _ml_ma_s)
bool  _ml_neg   = ta.crossunder(_ml_ma_q, _ml_ma_s)

var MLMIData _mlmi_data = MLMIData.new(
     array.new_float(1, 0.0), array.new_float(1, 0.0),
     array.new_float(1, 0.0), array.new_float(1, 0.0))

if _ml_pos or _ml_neg
    _mlmi_data.mlmi_store(_ml_rsi_s, _ml_rsi_q)

float mlmi_prediction = _mlmi_data.mlmi_predict(_ml_rsi_s, _ml_rsi_q, i_mlmi_k)
float mlmi_pred_ma    = ta.wma(mlmi_prediction, 20)

var int _mlmi_cross_bar = -999
if _ml_pos or _ml_neg
    _mlmi_cross_bar := bar_index

int  _mlmi_age       = bar_index - _mlmi_cross_bar
int  _mlmi_decay_win = _is_asia ? i_mlmi_d_asia : i_mlmi_d_lon
bool mlmi_fresh      = _mlmi_age <= _mlmi_decay_win
bool mlmi_valid      = _mlmi_age <= i_mlmi_expire
bool mlmi_bull       = mlmi_prediction > 0.0
bool mlmi_bear       = mlmi_prediction < 0.0
bool mlmi_neutral    = mlmi_prediction == 0.0   // initial warmup state only

bool _mlmi_c_gate = not i_mlmi_gate or mlmi_neutral or (mlmi_fresh and mlmi_bull)
bool _mlmi_d_gate = not i_mlmi_gate or mlmi_neutral or (mlmi_fresh and mlmi_bear)
bool _mlmi_a_gate = not i_mlmi_gate or mlmi_neutral or (mlmi_valid and mlmi_bull)
bool _mlmi_b_gate = not i_mlmi_gate or mlmi_neutral or (mlmi_valid and mlmi_bear)

// ═══════════════════════════════════════════════════════════════════════════════
// §10  SMI COMPUTATION  (K=10, D=3, EMA=3 — OB=+40, OS=-40)
// ═══════════════════════════════════════════════════════════════════════════════
float _smi_hh  = ta.highest(high, i_smi_k)
float _smi_ll  = ta.lowest(low,   i_smi_k)
float _smi_rng = _smi_hh - _smi_ll
float _smi_rel = close - (_smi_hh + _smi_ll) / 2.0
float _smi_num = f_emaema(_smi_rel, i_smi_d)
float _smi_den = f_emaema(_smi_rng, i_smi_d)
float smi      = _smi_den > 0.0 ? 200.0 * _smi_num / _smi_den : 0.0
float smi_ema  = ta.ema(smi, i_smi_ema)

bool smi_overbought = smi >= i_smi_ob
bool smi_oversold   = smi <= i_smi_os
bool smi_bull_cross = ta.crossover(smi,  smi_ema)
bool smi_bear_cross = ta.crossunder(smi, smi_ema)

bool _smi_g_gate = not i_mlmi_gate or smi_bull_cross or smi_oversold
bool _smi_h_gate = not i_mlmi_gate or smi_bear_cross or smi_overbought
// ═══════════════════════════════════════════════════════════════════════════════
// §11  QUANTALGO VOLUME INTELLIGENCE
// ═══════════════════════════════════════════════════════════════════════════════
float _qa_rng      = math.max(high - low, syminfo.mintick)
float _qa_buy_vol  = volume * ((close - low)  / _qa_rng)
float _qa_sell_vol = volume * ((high - close) / _qa_rng)
float _qa_net_dlt  = _qa_buy_vol - _qa_sell_vol
float _qa_abs_dlt  = math.abs(_qa_net_dlt)

float _dSS = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_short, i_qa_sm_pct)
float _dSM = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_mid,   i_qa_sm_pct)
float _dSL = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_long,  i_qa_sm_pct)
float _dMS = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_short, i_qa_md_pct)
float _dMM = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_mid,   i_qa_md_pct)
float _dML = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_long,  i_qa_md_pct)
float _dBS = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_short, i_qa_bg_pct)
float _dBM = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_mid,   i_qa_bg_pct)
float _dBL = ta.percentile_linear_interpolation(_qa_abs_dlt, i_qa_long,  i_qa_bg_pct)

bool _qa_big   = f_qa_cons(_qa_abs_dlt >= _dBS, _qa_abs_dlt >= _dBM, _qa_abs_dlt >= _dBL)
bool _qa_med   = not _qa_big   and f_qa_cons(_qa_abs_dlt >= _dMS, _qa_abs_dlt >= _dMM, _qa_abs_dlt >= _dML)
bool _qa_small = not _qa_big   and not _qa_med and f_qa_cons(_qa_abs_dlt >= _dSS, _qa_abs_dlt >= _dSM, _qa_abs_dlt >= _dSL)

bool _qa_is_buy  = _qa_net_dlt > 0.0
bool _qa_is_sell = _qa_net_dlt < 0.0
color _qa_bub_col = _qa_is_buy ? i_qa_c_buy : _qa_is_sell ? i_qa_c_sell : i_qa_c_mix

bool qa_big_bull  = _qa_big  and _qa_is_buy
bool qa_big_bear  = _qa_big  and _qa_is_sell
bool qa_any_bull  = (_qa_big or _qa_med or _qa_small) and _qa_is_buy
bool qa_any_bear  = (_qa_big or _qa_med or _qa_small) and _qa_is_sell
bool qa_bull_3    = qa_any_bull  or qa_any_bull[1]  or qa_any_bull[2]
bool qa_bear_3    = qa_any_bear  or qa_any_bear[1]  or qa_any_bear[2]
bool qa_big_bull3 = qa_big_bull  or qa_big_bull[1]  or qa_big_bull[2]
bool qa_big_bear3 = qa_big_bear  or qa_big_bear[1]  or qa_big_bear[2]

float _qa_avg_vol   = ta.sma(volume, i_qa_mid)
float _qa_vol_ratio = _qa_avg_vol > 0.0 ? volume / _qa_avg_vol : 0.0

bool _qa_vis_sm  = _qa_small and i_qa_show_sm
bool _qa_vis_md  = _qa_med   and i_qa_show_md
bool _qa_vis_bg  = _qa_big   and i_qa_show_bg
bool _qa_any_vis = _qa_vis_sm or _qa_vis_md or _qa_vis_bg

bool _qa_t0 = _qa_any_vis and _qa_vol_ratio < 2.5
bool _qa_t1 = _qa_any_vis and _qa_vol_ratio >= 2.5  and _qa_vol_ratio < 4.0
bool _qa_t2 = _qa_any_vis and _qa_vol_ratio >= 4.0  and _qa_vol_ratio < 6.5
bool _qa_t3 = _qa_any_vis and _qa_vol_ratio >= 6.5  and _qa_vol_ratio < 10.0
bool _qa_t4 = _qa_any_vis and _qa_vol_ratio >= 10.0

float _qa_plot_y = _qa_any_vis ? (_qa_is_sell ? high : low) : na

var array<label> _qa_lbs = array.new_label()
if _qa_any_vis and i_qa_show_lbl
    string _qa_fv   = f_qa_fmtn(volume)
    string _qa_fdlt = _qa_net_dlt >= 0.0 ? "+" + f_qa_fmtn(_qa_net_dlt) : f_qa_fmtn(_qa_net_dlt)
    string _qa_rx   = str.tostring(_qa_vol_ratio, "#.#") + "x"
    string _qa_txt  = switch i_qa_lbl_cnt
        "Delta"     => _qa_fdlt
        "Ratio"     => _qa_rx
        "Vol+Delta" => _qa_fv + "\n" + _qa_fdlt
        "Vol+Ratio" => _qa_fv + "\n" + _qa_rx
        =>             _qa_fv
    int    _qa_clvl = _qa_vis_bg ? 3 : _qa_vis_md ? 2 : 1
    string _qa_lvl  = _qa_clvl == 3 ? "BIG" : _qa_clvl == 2 ? "MEDIUM" : "SMALL"
    string _qa_side = _qa_is_buy ? "BUY" : _qa_is_sell ? "SELL" : "MIXED"
    bool   _dS = _qa_clvl == 3 ? _qa_abs_dlt >= _dBS : _qa_clvl == 2 ? _qa_abs_dlt >= _dMS : _qa_abs_dlt >= _dSS
    bool   _dM = _qa_clvl == 3 ? _qa_abs_dlt >= _dBM : _qa_clvl == 2 ? _qa_abs_dlt >= _dMM : _qa_abs_dlt >= _dSM
    bool   _dL = _qa_clvl == 3 ? _qa_abs_dlt >= _dBL : _qa_clvl == 2 ? _qa_abs_dlt >= _dML : _qa_abs_dlt >= _dSL
    string _qa_dwin = (_dS ? "S" : "·") + " " + (_dM ? "M" : "·") + " " + (_dL ? "L" : "·")
    string _qa_tip = "── " + _qa_lvl + " " + _qa_side + " ──" +
         "\nVolume: " + _qa_fv +
         "\nDelta:  " + _qa_fdlt +
         "\nRatio:  " + str.tostring(_qa_vol_ratio, "#.##") + "x" +
         "\nMethod: Delta Only (wick-weighted M5 proxy)" +
         "\nDelta Windows: [" + _qa_dwin + "]" +
         "\n─────────────────────" +
         "\nSess: " + (_is_lon ? "LONDON" : _is_ny ? "NY" : "ASIA") +
         "\nMLMI: " + (mlmi_fresh ? "FRESH" : mlmi_valid ? "VALID" : "EXPIRED") +
         "  SMI: " + str.tostring(smi, "#.1") +
         "\nDXY: " + dxy_str +
         "\nCB Tier: " + cb_tier_str +
         "\nNote: Pine proxy +/-20% vs tick data"
    array.push(_qa_lbs, label.new(bar_index, _qa_plot_y, _qa_txt,
         style     = label.style_label_center,
         color     = color.new(chart.fg_color, 100),
         textcolor = chart.fg_color,
         size      = size.small,
         tooltip   = _qa_tip))
    if array.size(_qa_lbs) > 400
        label.delete(array.shift(_qa_lbs))

var float _qa_cum_vol = 0.0
_qa_cum_vol += nz(volume)

// ═══════════════════════════════════════════════════════════════════════════════
// §11b  BUBBLE CONTEXT — LTF INTRABAR POSITION → AMT EVENT CLASSIFIER   [v26]
// ─────────────────────────────────────────────────────────────────────────────
// Upgrades the ⑫ volume bubbles: the whole-bar delta only tells BUY vs SELL.
// Here we drill into the current candle with lower-TF bars, locate the price bin
// with the largest |delta| (the biggest intrabar order-flow imbalance = the cluster),
// read the net delta AT that cluster, and — combined with candle direction and WHERE the
// cluster sits (top wick / body / bottom wick) — name the AMT event:
//   abs-continue · acceptance · abs-contrarian · rejection
// Display-only: touches no gate / conf_score / entry logic.
// ─────────────────────────────────────────────────────────────────────────────
// 2 lower-TF pulls only (plot-budget: each request.security_lower_tf costs 1 plot unit;
// the file sits near the 64 ceiling → we drop the separate volume pull and weight the
// cluster by |delta| instead — which also better matches what a "bubble" is: the price
// where the biggest order-flow IMBALANCE happened, not merely the busiest price).
// Net delta is computed inside the LTF context via wick-weighting.
array<float> _ltf_price = request.security_lower_tf(syminfo.tickerid, i_bctx_ltf, hl2)
array<float> _ltf_dlt   = request.security_lower_tf(syminfo.tickerid, i_bctx_ltf,
     volume * ((close - low) / math.max(high - low, syminfo.mintick))
   - volume * ((high - close) / math.max(high - low, syminfo.mintick)))

bool _bctx_gate_ok = switch i_bctx_gate
    "Small+"   => _qa_vis_sm or _qa_vis_md or _qa_vis_bg
    "Big only" => _qa_vis_bg
    =>            _qa_vis_md or _qa_vis_bg
bool _bctx_run = i_bctx_on and _bctx_gate_ok and barstate.isconfirmed

// hoisted for optional alerts
string _bctx_pat      = ""
bool   _bctx_out_bull = false
bool   _bctx_is_rev   = false
bool   _bctx_fired    = false

var array<label> _bctx_lbs = array.new_label()
if _bctx_run and array.size(_ltf_price) > 0
    int   _n    = i_bctx_bins
    float _clo  = low
    float _crng = math.max(high - low, syminfo.mintick)
    array<float> _binA = array.new_float(_n, 0.0)   // |delta| weight per bin
    array<float> _binD = array.new_float(_n, 0.0)   // signed delta per bin
    int _m = math.min(array.size(_ltf_price), array.size(_ltf_dlt))
    if _m > 0
        for _j = 0 to _m - 1
            float _p = array.get(_ltf_price, _j)
            float _d = array.get(_ltf_dlt,   _j)
            if not na(_p) and not na(_d)
                int _bi = math.floor((_p - _clo) / _crng * _n)
                _bi := math.max(0, math.min(_n - 1, _bi))
                array.set(_binA, _bi, array.get(_binA, _bi) + math.abs(_d))
                array.set(_binD, _bi, array.get(_binD, _bi) + _d)
    // POC = bin with the largest |delta| (biggest intrabar order-flow imbalance)
    int   _poc  = 0
    float _pocv = -1.0
    for _bi = 0 to _n - 1
        float _bv = array.get(_binA, _bi)
        if _bv > _pocv
            _pocv := _bv
            _poc  := _bi
    if _pocv > 0.0
        float _poc_frac = (_poc + 0.5) / _n
        float _poc_y    = _clo + _poc_frac * _crng
        float _poc_dlt  = array.get(_binD, _poc)
        bool  _poc_buy  = _poc_dlt > 0.0
        bool  _poc_sell = _poc_dlt < 0.0
        string _zone = _poc_frac >= i_bctx_top ? "TOP" : _poc_frac <= i_bctx_bot ? "BOT" : "MID"
        bool _bull = close >= open
        // ── classification ──────────────────────────────────────────────
        if _bull
            if _zone == "TOP"
                _bctx_pat := _poc_sell ? "rejection" : "abs-contrarian"
                _bctx_out_bull := false
            else if _zone == "MID"
                _bctx_pat := _poc_buy ? "acceptance buy" : "abs-continue"
                _bctx_out_bull := true
            else
                _bctx_pat := _poc_sell ? "abs-continue" : "acceptance buy"
                _bctx_out_bull := true
        else
            if _zone == "BOT"
                _bctx_pat := _poc_buy ? "rejection" : "abs-contrarian"
                _bctx_out_bull := true
            else if _zone == "MID"
                _bctx_pat := _poc_sell ? "acceptance sell" : "abs-continue"
                _bctx_out_bull := false
            else
                _bctx_pat := _poc_buy ? "abs-continue" : "acceptance sell"
                _bctx_out_bull := false
        _bctx_is_rev := (_bull and not _bctx_out_bull) or (not _bull and _bctx_out_bull)
        _bctx_fired  := _bctx_pat != ""
        // ── drawing ─────────────────────────────────────────────────────
        color _bctx_out_col = _bctx_out_bull ? i_bctx_up : i_bctx_dn
        color _bctx_side_col= _poc_buy ? i_qa_c_buy : _poc_sell ? i_qa_c_sell : i_qa_c_mix
        string _bctx_side_s = _poc_buy ? "BUY" : _poc_sell ? "SELL" : "MIXED"
        string _bctx_szr = switch i_bctx_sz
            "Tiny"   => size.tiny
            "Normal" => size.normal
            "Large"  => size.large
            =>          size.small
        float _bctx_off = nz(atr14, 5.0) * 0.6
        string _bctx_tt = "── BUBBLE CONTEXT ──" +
             "\nPattern: " + _bctx_pat + (_bctx_is_rev ? "  (reversal)" : "  (continuation)") +
             "\nCandle: " + (_bull ? "BULLISH" : "BEARISH") +
             "\nCluster: " + _zone + " zone @ $" + str.tostring(_poc_y, "#.##") +
             " (" + str.tostring(_poc_frac * 100.0, "#") + "% of range)" +
             "\nCluster side: " + _bctx_side_s + "   Δ " + str.tostring(_poc_dlt, format.volume) +
             "\nLTF: " + i_bctx_ltf + "  bins " + str.tostring(_n) +
             "\nBias: expect " + (_bctx_out_bull ? "UP ▲" : "DOWN ▼") +
             "\nNote: LTF intrabar proxy — eyes, not a validated edge"
        // position dot at the true LTF cluster (colored by cluster side)
        if i_bctx_dot
            array.push(_bctx_lbs, label.new(bar_index, _poc_y, "●",
                 style     = label.style_label_center,
                 color     = color.new(color.black, 100),
                 textcolor = _bctx_side_col,
                 size      = _bctx_szr,
                 tooltip   = _bctx_tt))
            if array.size(_bctx_lbs) > 300
                label.delete(array.shift(_bctx_lbs))
        // context text tag — above high (bearish outcome) / below low (bullish outcome)
        if i_bctx_lbl
            string _arw = i_bctx_arrow ? (_poc_buy ? "▲ " : _poc_sell ? "▼ " : "◆ ") : ""
            array.push(_bctx_lbs, label.new(bar_index,
                 _bctx_out_bull ? low - _bctx_off : high + _bctx_off,
                 _arw + _bctx_pat,
                 style     = _bctx_out_bull ? label.style_label_up : label.style_label_down,
                 color     = color.new(_bctx_out_col, 82),
                 textcolor = _bctx_out_col,
                 size      = _bctx_szr,
                 tooltip   = _bctx_tt))
            if array.size(_bctx_lbs) > 300
                label.delete(array.shift(_bctx_lbs))

// ═══════════════════════════════════════════════════════════════════════════════
// §12  AMT PATTERN ENGINE — SOVEREIGN §24b ADAPTED
// ═══════════════════════════════════════════════════════════════════════════════
float _amt_rng      = math.max(high - low, syminfo.mintick)
float _amt_bvol     = volume * ((close - low)  / _amt_rng)
float _amt_svol     = volume * ((high - close) / _amt_rng)
float _amt_wick_up  = (high - math.max(close, open)) / _amt_rng
float _amt_wick_dn  = (math.min(close, open) - low)  / _amt_rng
bool  _amt_is_bull  = close >= open
float _amt_body_top = math.max(close, open)
float _amt_body_bot = math.min(close, open)
float _amt_mass     = vol_sma50 > 0.0 ? volume / vol_sma50 : 1.0
bool  _amt_hv       = i_show_amt and _amt_mass >= i_ice_mass

string _bpat     = ""
float  _b_y      = na
color  _b_col    = na
string _b_sig    = ""
string _b_emj    = ""
string _b_acc_txt = ""

float  _atr_off = nz(atr14, 5.0) * 0.5

if _amt_hv
    if _amt_is_bull
        if i_amt_rej and _amt_wick_up >= i_amt_wick_rej
            _bpat  := "REJECTION SELL"
            _b_y   := high + _atr_off
            _b_col := color.new(i_amt_rej_col, 0)
            _b_sig := "SELL"
            _b_emj := "⛔"
        else if i_amt_ctr and _amt_svol > _amt_bvol * (i_amt_vol_dom * 0.8) and _amt_wick_up >= 0.12
            _bpat  := "CONTRARIAN WARN"
            _b_y   := high + _atr_off * 0.6
            _b_col := color.new(#009688, 0)
            _b_sig := "WARN"
            _b_emj := "⚠"
        else if i_amt_abs and _amt_bvol > _amt_svol * i_amt_vol_dom and _amt_wick_dn >= 0.12
            _bpat  := "ABSORPTION BUY"
            _b_y   := low - _atr_off
            _b_col := color.new(i_amt_abs_col, 20)
            _b_sig := "BUY"
            _b_emj := "🧽"
        else if i_amt_acc
            _bpat     := "ACCEPTANCE BUY"
            _b_y      := low - _atr_off * 0.5
            _b_col    := color.new(#00BCD4, 0)
            _b_sig    := "BUY"
            _b_emj    := "●"
            _b_acc_txt := "Accept Buy"
    else
        if i_amt_rej and _amt_wick_dn >= i_amt_wick_rej
            _bpat  := "REJECTION BUY"
            _b_y   := low - _atr_off
            _b_col := color.new(#009688, 0)
            _b_sig := "BUY"
            _b_emj := "⛔"
        else if i_amt_ctr and _amt_bvol > _amt_svol * (i_amt_vol_dom * 0.8) and _amt_wick_dn >= 0.12
            _bpat  := "CONTRARIAN WARN"
            _b_y   := low - _atr_off * 0.6
            _b_col := color.new(i_amt_rej_col, 0)
            _b_sig := "WARN"
            _b_emj := "⚠"
        else if i_amt_abs and _amt_svol > _amt_bvol * i_amt_vol_dom and _amt_wick_up >= 0.12
            _bpat  := "ABSORPTION SELL"
            _b_y   := high + _atr_off
            _b_col := color.new(i_amt_abs_col, 60)
            _b_sig := "SELL"
            _b_emj := "🧽"
        else if i_amt_acc
            _bpat     := "ACCEPTANCE SELL"
            _b_y      := high + _atr_off * 0.5
            _b_col    := color.new(#E91E63, 0)
            _b_sig    := "SELL"
            _b_emj    := "●"
            _b_acc_txt := "Accept Sell"

var array<label> _amt_lbs = array.new_label()
if _amt_hv and _bpat != "" and not na(_b_y)
    float  _bint = _amt_mass
    string _btt  = _bpat + " [" + _b_sig + "]" +
         "\nBuy:  " + str.tostring(_amt_bvol, format.volume) +
         "  Sell: " + str.tostring(_amt_svol, format.volume) +
         "\nWick+: " + str.tostring(_amt_wick_up * 100.0, "#.#") + "%" +
         "  Wick-: " + str.tostring(_amt_wick_dn * 100.0, "#.#") + "%" +
         "\nMass: " + str.tostring(_bint, "#.1") + "x SMA50" +
         "\nMLMI: " + (mlmi_fresh ? "FRESH" : mlmi_valid ? "VALID" : "EXPIRED") +
         "  SMI: "  + str.tostring(smi, "#.1")
    string _emj_sz_resolved = switch i_amt_emj_sz
        "Small"  => size.small
        "Normal" => size.normal
        "Huge"   => size.huge
        =>          size.large
    array.push(_amt_lbs, label.new(bar_index, _b_y, _b_emj,
         style    = label.style_label_center,
         color    = color.new(color.black, 100),
         textcolor= _b_col,
         size     = _emj_sz_resolved,
         tooltip  = _btt))
    if array.size(_amt_lbs) > 400
        label.delete(array.shift(_amt_lbs))
    // [v25-1] Acceptance text label — "Accept Buy" / "Accept Sell" at size.tiny
    if _b_acc_txt != ""
        array.push(_amt_lbs, label.new(bar_index, _b_y, _b_acc_txt,
             style     = _b_sig == "BUY" ? label.style_label_up : label.style_label_down,
             color     = color.new(_b_col, 75),
             textcolor = _b_col,
             size      = size.tiny,
             tooltip   = _btt))
        if array.size(_amt_lbs) > 400
            label.delete(array.shift(_amt_lbs))
// Iceberg at GEX zones
bool ice_g1_up = i_amt_ice and math.abs(close - g1_up) <= i_tol * 1.5 and _amt_mass >= i_ice_mass and close <= g1_up
bool ice_g1_dn = i_amt_ice and math.abs(close - g1_dn) <= i_tol * 1.5 and _amt_mass >= i_ice_mass and close >= g1_dn
bool ice_g2_up = i_amt_ice and math.abs(close - g2_up) <= i_tol * 1.5 and _amt_mass >= i_ice_mass
bool ice_g2_dn = i_amt_ice and math.abs(close - g2_dn) <= i_tol * 1.5 and _amt_mass >= i_ice_mass
bool ice_sell_signal = ice_g1_up or ice_g2_up
bool ice_buy_signal  = ice_g1_dn or ice_g2_dn

var array<label> _ice_lbs = array.new_label()
if ice_buy_signal
    string _iz_nm = ice_g1_dn ? "g1 $" + str.tostring(g1_dn,"#.##") : "g2 $" + str.tostring(g2_dn,"#.##")
    string _iz_tt = "ICEBERG ORDER — SUPPORT ZONE\nZone: " + _iz_nm +
         "\nMass: " + str.tostring(_amt_mass,"#.1") + "x SMA50" +
         "\nPattern: Hidden institutional BUY at GEX support" +
         "\nCB Tier: " + cb_tier_str
    string _ize_sz = i_amt_emj_sz == "Huge" ? size.huge : i_amt_emj_sz == "Large" ? size.large : i_amt_emj_sz == "Normal" ? size.normal : size.small
    array.push(_ice_lbs, label.new(bar_index, low - nz(atr14,5.0) * 0.3, "❄️",
         style    = label.style_label_center,
         color    = color.new(color.black, 100),
         textcolor= i_amt_ice_col,
         size     = _ize_sz,
         tooltip  = _iz_tt))
    if array.size(_ice_lbs) > 200
        label.delete(array.shift(_ice_lbs))
if ice_sell_signal
    string _iz_nm = ice_g1_up ? "g1 $" + str.tostring(g1_up,"#.##") : "g2 $" + str.tostring(g2_up,"#.##")
    string _iz_tt = "ICEBERG ORDER — RESISTANCE ZONE\nZone: " + _iz_nm +
         "\nMass: " + str.tostring(_amt_mass,"#.1") + "x SMA50" +
         "\nPattern: Hidden institutional SELL at GEX resistance" +
         "\nCB Tier: " + cb_tier_str
    string _ize_sz = i_amt_emj_sz == "Huge" ? size.huge : i_amt_emj_sz == "Large" ? size.large : i_amt_emj_sz == "Normal" ? size.normal : size.small
    array.push(_ice_lbs, label.new(bar_index, high + nz(atr14,5.0) * 0.3, "❄️",
         style    = label.style_label_center,
         color    = color.new(color.black, 100),
         textcolor= i_amt_ice_col,
         size     = _ize_sz,
         tooltip  = _iz_tt))
    if array.size(_ice_lbs) > 200
        label.delete(array.shift(_ice_lbs))

// ═══════════════════════════════════════════════════════════════════════════════
// §13  CONFLUENCE CHECKS
// ═══════════════════════════════════════════════════════════════════════════════
float _conf_tol  = i_tol * 2.5
bool sd_u_in_frame = sd_u < g1_up and sd_u > g1_dn
bool sd_d_in_frame = sd_d > g1_dn and sd_d < g1_up
bool sd_near_c1    = math.abs(sd_u - sp_c1) <= i_tol
bool sd_near_p1    = math.abs(sd_d - sp_p1) <= i_tol
bool pbv1_u_conf   = math.abs(g2_up - pbv_l1_u) <= _conf_tol
bool pbv1_d_conf   = math.abs(g2_dn - pbv_l1_d) <= _conf_tol
bool sd_u_conf     = math.abs(g3_up - sd_u)     <= _conf_tol
bool sd_d_conf     = math.abs(g3_dn - sd_d)     <= _conf_tol
bool pbv2_u_conf   = math.abs(g3_up - pbv_l2_u) <= _conf_tol
bool pbv2_d_conf   = math.abs(g3_dn - pbv_l2_d) <= _conf_tol
bool pbv3_u_conf   = math.abs(g3_up - pbv_l3_u) <= _conf_tol
bool pbv3_d_conf   = math.abs(g3_dn - pbv_l3_d) <= _conf_tol
bool exp_conf_up   = sd_u_conf or pbv2_u_conf or pbv3_u_conf
bool exp_conf_dn   = sd_d_conf or pbv2_d_conf or pbv3_d_conf

string _sd_sig_tag = _using_delta_sig ? " 25D" : " SD1.618s"
string _exp_tag_u  = sd_u_conf and pbv2_u_conf ? " SD+PBV" : sd_u_conf ? _sd_sig_tag : pbv2_u_conf ? " PBV" + str.tostring(i_pbv_2,"#.###") + "%" : pbv3_u_conf ? " PBV3" + str.tostring(i_pbv_3,"#.###") + "%" : ""
string _exp_tag_d  = sd_d_conf and pbv2_d_conf ? " SD+PBV" : sd_d_conf ? _sd_sig_tag : pbv2_d_conf ? " PBV" + str.tostring(i_pbv_2,"#.###") + "%" : pbv3_d_conf ? " PBV3" + str.tostring(i_pbv_3,"#.###") + "%" : ""

// ═══════════════════════════════════════════════════════════════════════════════
// §14  SQUEEZE + BUBBLE PROXIMITY
// ═══════════════════════════════════════════════════════════════════════════════
float body_r      = f_body(open, close, high, low)
bool  valid_body  = body_r >= i_body_min
float prox_zone   = math.max(i_tol * i_prox_mult, nz(atr14, i_tol) * 0.3)
bool  near_g1_up  = math.abs(close - g1_up) <= prox_zone
bool  near_g1_dn  = math.abs(close - g1_dn) <= prox_zone

bool _sqz_co = ta.crossover(close,  anchor)
bool sqz_up  = _sqz_co and _qa_abs_dlt > _dMS
bool _sqz_cu = ta.crossunder(close, anchor)
bool sqz_dn  = _sqz_cu and _qa_abs_dlt > _dMS

// [v23] YZ-based Squeeze — Yang-Zhang realized vol, consistent with GEX physics
float _yz_fast    = f_yz(i_sqz_yz_fast, 1.0)
float _yz_slow    = f_yz(i_sqz_yz_slow, 1.0)
float _yz_ratio   = _yz_slow > 0.0 ? _yz_fast / _yz_slow : 1.0
bool  sqz_on      = _yz_fast < _yz_slow * i_sqz_ratio
var bool _sqz_prev = false
bool  sqz_fire    = not sqz_on and _sqz_prev
_sqz_prev        := sqz_on
var int _sqz_dur = 0
_sqz_dur := sqz_on ? _sqz_dur + 1 : 0
bool _sqz_dur_ok     = _sqz_dur[1] >= i_sqz_min_dur
bool _sqz_ratio_exp  = _yz_ratio > nz(_yz_ratio[1], _yz_ratio)
bool  sqz_yz_bull = sqz_fire and close >= anchor and _sqz_dur_ok and _sqz_ratio_exp
bool  sqz_yz_bear = sqz_fire and close <  anchor and _sqz_dur_ok and _sqz_ratio_exp

var int _age_up = 999
var int _age_dn = 999
if qa_any_bull or sqz_up
    _age_up := 0
else
    _age_up := math.min(_age_up + 1, 999)
if qa_any_bear or sqz_dn
    _age_dn := 0
else
    _age_dn := math.min(_age_dn + 1, 999)

bool recent_bull = _age_up <= i_evt_win
bool recent_dn   = _age_dn <= i_evt_win
// ═══════════════════════════════════════════════════════════════════════════════
// §15  REGIME FSM  [v19: ATR-based breakout fallback]
// ═══════════════════════════════════════════════════════════════════════════════
bool inside_frame = close > g1_dn and close < g1_up
var int _out_cnt = 0
if inside_frame
    _out_cnt := 0
else
    _out_cnt := _out_cnt + 1
bool hyst_confirmed = _out_cnt >= i_out_bars

float _atr_mom = nz(atr14, 1.0)
bool  _atr_bo_up = not inside_frame and close > g1_up and (close - g1_up) > _atr_mom * 0.5
bool  _atr_bo_dn = not inside_frame and close < g1_dn and (g1_dn - close) > _atr_mom * 0.5
bool eff_bo_bull = recent_bull or _atr_bo_up
bool eff_bo_bear = recent_dn   or _atr_bo_dn

var int regime   = 0
var int _reg_prv = 0
_reg_prv := regime
if inside_frame
    regime := 0
else if close > g1_up and eff_bo_bull and hyst_confirmed
    regime := 1
else if close < g1_dn and eff_bo_bear and hyst_confirmed
    regime := -1

float bo_gate_up = g1_up + i_tol * 0.5
float bo_gate_dn = g1_dn - i_tol * 0.5

// ═══════════════════════════════════════════════════════════════════════════════
// §16  REGIME CONFIDENCE SCORE  [v19: CB tier penalty added]
// ═══════════════════════════════════════════════════════════════════════════════
int conf_score = 50
if gvz_compressed
    conf_score := conf_score + 15
if gvz_normal
    conf_score := conf_score + 10
if gvz_elevated
    conf_score := conf_score - 10
if gvz_extreme
    conf_score := conf_score - 25
if sig_regime == "COMPRESSED"
    conf_score := conf_score + 10
if sig_regime == "NORMAL"
    conf_score := conf_score + 5
if sig_regime == "EXPANDING"
    conf_score := conf_score - 5
if sig_regime == "EXTREME"
    conf_score := conf_score - 15
if frame_width > sigma * 0.5
    conf_score := conf_score + 10
if not frame_ok
    conf_score := conf_score - 20
if _is_lon
    conf_score := conf_score + 10
if _is_ny
    conf_score := conf_score + 5
if _is_asia
    conf_score := conf_score - 10
if mlmi_fresh and mlmi_bull and regime == -1
    conf_score := conf_score + 8
if mlmi_fresh and mlmi_bear and regime == 1
    conf_score := conf_score + 8
if mlmi_valid and not mlmi_fresh
    conf_score := conf_score - 3
if gvz_spiking
    conf_score := conf_score - 8
if dxy_bear and regime == 1
    conf_score := conf_score + 6
if dxy_bull and regime == -1
    conf_score := conf_score + 6
if cb_t3_active
    conf_score := conf_score - 20
else if cb_t2_active
    conf_score := conf_score - 10
else if cb_t1_active
    conf_score := conf_score - 5
conf_score := math.min(100, math.max(0, conf_score))

color  conf_col = conf_score >= 75 ? #00E676 : conf_score >= 50 ? #FFD700 : conf_score >= 30 ? #FF9800 : #FF1744
string conf_str = str.tostring(conf_score) + "/100"
// ═══════════════════════════════════════════════════════════════════════════════
// §FRZ  FROZEN ZONE DISPLAY — ported from QC_BasisMatrix v8.4 §13
//       [v24-1] max_boxes_count=500 now declared in indicator() → FRZ_MAX honored.
// ═══════════════════════════════════════════════════════════════════════════════
float frz_liq_top  = implied_spot + b_std * i_frz_mult
float frz_liq_bot  = implied_spot - b_std * i_frz_mult
bool  frz_high_vol = volume > vol_sma50 * i_frz_vfac
bool  frz_ready    = i_show_frz and bar_index >= i_frz_warmup

bool frz_pass_sell = frz_ready and close >= frz_liq_top and frz_high_vol
bool frz_pass_buy  = frz_ready and close <= frz_liq_bot and frz_high_vol
bool frz_trig_sell = frz_pass_sell and not frz_pass_sell[1]
bool frz_trig_buy  = frz_pass_buy  and not frz_pass_buy[1]

const int FRZ_MAX = 500
var array<box> frz_sell_zones = array.new<box>()
var array<box> frz_buy_zones  = array.new<box>()

bool frz_can_sell = frz_trig_sell and array.size(frz_sell_zones) < FRZ_MAX
bool frz_can_buy  = frz_trig_buy  and array.size(frz_buy_zones)  < FRZ_MAX

if frz_can_sell and array.size(frz_sell_zones) > 0
    if (bar_index - box.get_left(array.last(frz_sell_zones))) <= 3
        frz_can_sell := false
if frz_can_buy and array.size(frz_buy_zones) > 0
    if (bar_index - box.get_left(array.last(frz_buy_zones))) <= 3
        frz_can_buy := false

if frz_can_sell
    float _s_top = high
    float _s_bot = math.max(math.max(close, frz_liq_top), _s_top - atr14 * 2.0)
    if _s_top > _s_bot
        array.push(frz_sell_zones, box.new(
             bar_index, _s_top, bar_index + 5, _s_bot,
             border_color = color.new(color.red,   40),
             border_style = line.style_solid,
             bgcolor      = color.new(color.red,   70),
             text         = "Supply\n(Frozen)",
             text_color   = color.new(color.white, 20),
             text_size    = size.tiny))

if frz_can_buy
    float _b_bot = low
    float _b_top = math.min(math.min(close, frz_liq_bot), _b_bot + atr14 * 2.0)
    if _b_top > _b_bot
        array.push(frz_buy_zones, box.new(
             bar_index, _b_top, bar_index + 5, _b_bot,
             border_color = color.new(color.green, 40),
             border_style = line.style_solid,
             bgcolor      = color.new(color.green, 70),
             text         = "Demand\n(Frozen)",
             text_color   = color.new(color.white, 20),
             text_size    = size.tiny,
             text_valign  = text.align_bottom))

if array.size(frz_sell_zones) > 0
    for _fi = array.size(frz_sell_zones) - 1 to 0
        box _fb = array.get(frz_sell_zones, _fi)
        if close > box.get_top(_fb)
            box.set_bgcolor(_fb,      color.new(color.gray, 90))
            box.set_border_color(_fb, color.new(color.gray, 85))
            box.set_text(_fb, "")
            box.set_right(_fb, bar_index)
            array.remove(frz_sell_zones, _fi)
        else
            box.set_right(_fb, bar_index + 3)

if array.size(frz_buy_zones) > 0
    for _fi = array.size(frz_buy_zones) - 1 to 0
        box _fb = array.get(frz_buy_zones, _fi)
        if close < box.get_bottom(_fb)
            box.set_bgcolor(_fb,      color.new(color.gray, 90))
            box.set_border_color(_fb, color.new(color.gray, 85))
            box.set_text(_fb, "")
            box.set_right(_fb, bar_index)
            array.remove(frz_buy_zones, _fi)
        else
            box.set_right(_fb, bar_index + 3)
// ═══════════════════════════════════════════════════════════════════════════════
// §14b  SQUEEZE LABELS  [v22 new]  — label.new() → 0 plot-budget units
// ═══════════════════════════════════════════════════════════════════════════════
var array<label> _sqz_lbs = array.new_label()

if i_sqz_en and (sqz_yz_bull or sqz_yz_bear)
    string _slsz = switch i_sqz_lbl_sz
        "Tiny"   => size.tiny
        "Normal" => size.normal
        "Large"  => size.large
        =>          size.small
    string _stsz = switch i_sqz_txt_sz
        "Tiny"   => size.tiny
        "Normal" => size.normal
        =>          size.small
    float _sqz_off = nz(atr14, 5.0) * i_sqz_offset
    string _reg_tag = regime == 1 ? "TREND UP" : regime == -1 ? "TREND DN" : "MR ZONE"
    string _sess_tag = _is_lon ? "LON" : _is_ny ? "NY" : "ASIA"
    string _dur_tag  = str.tostring(_sqz_dur[1] > 0 ? _sqz_dur[1] : 1) + " bars"

    if sqz_yz_bull
        string _tip = "SQUEEZE RELEASE — BULL (YZ v24)" +
             "\n────────────────────" +
             "\nYZ fast(" + str.tostring(i_sqz_yz_fast) + "): " + str.tostring(_yz_fast,"#.####") +
             "   slow(" + str.tostring(i_sqz_yz_slow) + "): " + str.tostring(_yz_slow,"#.####") +
             "\nRatio: " + str.tostring(_yz_ratio * 100.0,"#.#") + "% (threshold " + str.tostring(i_sqz_ratio * 100.0,"#") + "%)" +
             "\nCompressed for: " + _dur_tag + " (min " + str.tostring(i_sqz_min_dur) + "✓)" +
             "\nRatio expanding: " + (_sqz_ratio_exp ? "YES ✓" : "NO") +
             "\nClose vs anchor: +" + str.tostring(close - anchor,"#.##") +
             "\n────────────────────" +
             "\nSigma regime: " + sig_regime +
             "   GVZ: " + gvz_tier +
             "\nSession: " + _sess_tag +
             "   Regime: " + _reg_tag +
             "\nConf score: " + conf_str +
             "\n────────────────────" +
             "\nCB tier: " + cb_tier_str +
             "\nDXY: " + (dxy_bull ? "BULL" : dxy_bear ? "BEAR" : "NEUTRAL") +
             "\nNote: confirm with cond_G (Breakout BUY) or QA Big Bull"
        array.push(_sqz_lbs, label.new(
             bar_index, low - _sqz_off,
             i_sqz_up_txt,
             style     = label.style_label_up,
             color     = color.new(i_sqz_up_col, i_sqz_lbl_tr),
             textcolor = i_sqz_up_col,
             size      = _slsz,
             tooltip   = _tip))

    if sqz_yz_bear
        string _tip = "SQUEEZE RELEASE — BEAR (YZ v24)" +
             "\n────────────────────" +
             "\nYZ fast(" + str.tostring(i_sqz_yz_fast) + "): " + str.tostring(_yz_fast,"#.####") +
             "   slow(" + str.tostring(i_sqz_yz_slow) + "): " + str.tostring(_yz_slow,"#.####") +
             "\nRatio: " + str.tostring(_yz_ratio * 100.0,"#.#") + "% (threshold " + str.tostring(i_sqz_ratio * 100.0,"#") + "%)" +
             "\nCompressed for: " + _dur_tag + " (min " + str.tostring(i_sqz_min_dur) + "✓)" +
             "\nRatio expanding: " + (_sqz_ratio_exp ? "YES ✓" : "NO") +
             "\nClose vs anchor: " + str.tostring(close - anchor,"#.##") +
             "\n────────────────────" +
             "\nSigma regime: " + sig_regime +
             "   GVZ: " + gvz_tier +
             "\nSession: " + _sess_tag +
             "   Regime: " + _reg_tag +
             "\nConf score: " + conf_str +
             "\n────────────────────" +
             "\nCB tier: " + cb_tier_str +
             "\nDXY: " + (dxy_bull ? "BULL" : dxy_bear ? "BEAR" : "NEUTRAL") +
             "\nNote: confirm with cond_H (Breakout SELL) or QA Big Bear"
        array.push(_sqz_lbs, label.new(
             bar_index, high + _sqz_off,
             i_sqz_dn_txt,
             style     = label.style_label_down,
             color     = color.new(i_sqz_dn_col, i_sqz_lbl_tr),
             textcolor = i_sqz_dn_col,
             size      = _slsz,
             tooltip   = _tip))

    if array.size(_sqz_lbs) > 400
        label.delete(array.shift(_sqz_lbs))
// ═══════════════════════════════════════════════════════════════════════════════
// §16c  EXPANSION SCORE + MR-INTO-TREND   [v27]  — DISPLAY-ONLY (label → 0 budget)
// ─────────────────────────────────────────────────────────────────────────────
// Two reads from the "3 primitives" framework, as VISUAL flags only (no entry):
//  • EXPANSION = the breakout trigger — this bar's range ≫ its trailing average
//    (transcript: 5 candles avg 1%, 6th moves 2% = volatility expansion).
//  • MR-INTO-TREND = buy-the-dip WITH the trend — inside an established trend
//    (regime ±1) price RETESTS the g1 flip level (broken resistance→support in
//    an uptrend; broken support→resistance in a downtrend). This is fading
//    toward the trend, the systematic opposite of fading against it.
// Touches NO gate / conf_score / entry — labels only.
// ═══════════════════════════════════════════════════════════════════════════════
float _xmt_rng   = high - low
float _xmt_avg   = ta.sma(_xmt_rng, i_exp_len)
float _xmt_score = _xmt_avg > 0.0 ? _xmt_rng / _xmt_avg : 0.0
bool  _exp_fire  = i_xmt_on and _xmt_score >= i_exp_thr
bool  _exp_up    = _exp_fire and close >= open
bool  _exp_dn    = _exp_fire and close <  open
bool  _exp_up_f  = _exp_up and not _exp_up[1]
bool  _exp_dn_f  = _exp_dn and not _exp_dn[1]

float _mrt_hi    = ta.highest(high, i_mrt_look)
float _mrt_lo    = ta.lowest(low,   i_mrt_look)
bool  _mrt_buy   = i_xmt_on and regime == 1  and f_touch(low, g1_up)  and close >= g1_up - i_tol
bool  _mrt_sell  = i_xmt_on and regime == -1 and f_touch(high, g1_dn) and close <= g1_dn + i_tol
float _mrt_imp_u = _mrt_hi - g1_up
float _mrt_imp_d = g1_dn - _mrt_lo
float _mrt_depth = _mrt_buy and _mrt_imp_u > 0.0 ? (_mrt_hi - low) / _mrt_imp_u : _mrt_sell and _mrt_imp_d > 0.0 ? (high - _mrt_lo) / _mrt_imp_d : na
var int _mrt_lastb = -999
var int _mrt_lasts = -999
bool _mrt_buy_f  = _mrt_buy  and (bar_index - _mrt_lastb) >= i_dedup
bool _mrt_sell_f = _mrt_sell and (bar_index - _mrt_lasts) >= i_dedup
if _mrt_buy_f
    _mrt_lastb := bar_index
if _mrt_sell_f
    _mrt_lasts := bar_index

string _xmt_szr = switch i_xmt_sz
    "Tiny"   => size.tiny
    "Normal" => size.normal
    "Large"  => size.large
    =>          size.small
float _xmt_off = nz(atr14, 5.0) * 0.55

var array<label> _xmt_lbs = array.new_label()
if i_xmt_on and i_exp_lbl and _exp_up_f
    array.push(_xmt_lbs, label.new(bar_index, low - _xmt_off, "EXP▲ " + str.tostring(_xmt_score, "#.#") + "×",
         style     = label.style_label_up,
         color     = color.new(i_exp_col, 78),
         textcolor = i_exp_col,
         size      = _xmt_szr,
         tooltip   = "EXPANSION (bull) — breakout trigger\nRange: " + str.tostring(_xmt_rng, format.mintick) + "  (" + str.tostring(_xmt_score, "#.##") + "× " + str.tostring(i_exp_len) + "-bar avg)\nRegime: " + (regime == 1 ? "TREND-UP" : regime == -1 ? "TREND-DN" : "MR ZONE") + "\nConf: " + conf_str))
    if array.size(_xmt_lbs) > 300
        label.delete(array.shift(_xmt_lbs))
if i_xmt_on and i_exp_lbl and _exp_dn_f
    array.push(_xmt_lbs, label.new(bar_index, high + _xmt_off, "EXP▼ " + str.tostring(_xmt_score, "#.#") + "×",
         style     = label.style_label_down,
         color     = color.new(i_exp_col, 78),
         textcolor = i_exp_col,
         size      = _xmt_szr,
         tooltip   = "EXPANSION (bear) — breakout trigger\nRange: " + str.tostring(_xmt_rng, format.mintick) + "  (" + str.tostring(_xmt_score, "#.##") + "× " + str.tostring(i_exp_len) + "-bar avg)\nRegime: " + (regime == 1 ? "TREND-UP" : regime == -1 ? "TREND-DN" : "MR ZONE") + "\nConf: " + conf_str))
    if array.size(_xmt_lbs) > 300
        label.delete(array.shift(_xmt_lbs))
if i_xmt_on and i_mrt_lbl and _mrt_buy_f
    array.push(_xmt_lbs, label.new(bar_index, low - _xmt_off, "MR→trend BUY",
         style     = label.style_label_up,
         color     = color.new(i_xmt_up, 74),
         textcolor = i_xmt_up,
         size      = _xmt_szr,
         tooltip   = "MR-INTO-TREND (buy the dip WITH the uptrend)\nRetest of g1 flip $" + str.tostring(g1_up, format.mintick) + " (broken resistance → support)\nPullback depth: " + str.tostring(nz(_mrt_depth) * 100.0, "#") + "% of impulse (deeper = higher prob)\nNOT an entry — visual flag. Conf: " + conf_str))
    if array.size(_xmt_lbs) > 300
        label.delete(array.shift(_xmt_lbs))
if i_xmt_on and i_mrt_lbl and _mrt_sell_f
    array.push(_xmt_lbs, label.new(bar_index, high + _xmt_off, "MR→trend SELL",
         style     = label.style_label_down,
         color     = color.new(i_xmt_dn, 74),
         textcolor = i_xmt_dn,
         size      = _xmt_szr,
         tooltip   = "MR-INTO-TREND (sell the rip WITH the downtrend)\nRetest of g1 flip $" + str.tostring(g1_dn, format.mintick) + " (broken support → resistance)\nPullback depth: " + str.tostring(nz(_mrt_depth) * 100.0, "#") + "% of impulse (deeper = higher prob)\nNOT an entry — visual flag. Conf: " + conf_str))
    if array.size(_xmt_lbs) > 300
        label.delete(array.shift(_xmt_lbs))
// ═══════════════════════════════════════════════════════════════════════════════
// §17  SIGNAL LOGIC — Priority Gate C/D > A/B > E/F  (+MLMI/SMI+DXY gates)
// ═══════════════════════════════════════════════════════════════════════════════
var int _last_A = -999, var int _last_B = -999
var int _last_C = -999, var int _last_D = -999
var int _last_E = -999, var int _last_F = -999
var int _last_G = -999, var int _last_H = -999
var int _last_I = -999, var int _last_J = -999
var int _last_K = -999, var int _last_L = -999
var int _last_M = -999, var int _last_N = -999
f_dedup(int last_bar) => (bar_index - last_bar) >= i_dedup

bool cb_mr_block = i_cb_gate and cb_t1_active

bool mr_gate_ok     = not gvz_block_mr and frame_ok and _sess_ok_mr and not cb_mr_block
bool mr_buy_ok      = mr_gate_ok and not dxy_penalise_buy
bool mr_sell_ok     = mr_gate_ok and not dxy_penalise_sell

bool _raw_C = regime == 0 and sd_d_in_frame and mr_buy_ok
     and f_touch(low, sd_d) and close > sd_d - i_tol
     and not qa_bear_3 and f_dedup(_last_C) and _mlmi_c_gate
if _raw_C
    _last_C := bar_index

bool _raw_D = regime == 0 and sd_u_in_frame and mr_sell_ok
     and f_touch(high, sd_u) and close < sd_u + i_tol
     and not qa_bull_3 and f_dedup(_last_D) and _mlmi_d_gate
if _raw_D
    _last_D := bar_index

bool _raw_A = regime == 0 and inside_frame and mr_buy_ok
     and not sd_d_in_frame and f_touch(low, g1_dn)
     and close > g1_dn - i_tol and not qa_bear_3
     and f_dedup(_last_A) and _mlmi_a_gate
if _raw_A
    _last_A := bar_index

bool _raw_B = regime == 0 and inside_frame and mr_sell_ok
     and not sd_u_in_frame and f_touch(high, g1_up)
     and close < g1_up + i_tol and not qa_bull_3
     and f_dedup(_last_B) and _mlmi_b_gate
if _raw_B
    _last_B := bar_index

bool _raw_E = regime == 0 and inside_frame and mr_buy_ok
     and not sd_near_p1 and f_touch(low, sp_p1)
     and close > sp_p1 - i_tol and not qa_bear_3 and f_dedup(_last_E)
if _raw_E
    _last_E := bar_index

bool _raw_F = regime == 0 and inside_frame and mr_sell_ok
     and not sd_near_c1 and f_touch(high, sp_c1)
     and close < sp_c1 + i_tol and not qa_bull_3 and f_dedup(_last_F)
if _raw_F
    _last_F := bar_index

bool cond_C = _raw_C
bool cond_D = _raw_D
bool cond_A = _raw_A and (not i_prio_gate or not _raw_C)
bool cond_B = _raw_B and (not i_prio_gate or not _raw_D)
bool cond_E = _raw_E and (not i_prio_gate or (not _raw_C and not _raw_A))
bool cond_F = _raw_F and (not i_prio_gate or (not _raw_D and not _raw_B))

bool cond_G = close > bo_gate_up and qa_bull_3 and qa_big_bull3
     and hyst_confirmed and not qa_bear_3 and not gvz_block_mr
     and frame_ok and f_dedup(_last_G) and _smi_g_gate
if cond_G
    _last_G := bar_index

bool cond_H = close < bo_gate_dn and qa_bear_3 and qa_big_bear3
     and hyst_confirmed and not qa_bull_3 and not gvz_block_mr
     and frame_ok and f_dedup(_last_H) and _smi_h_gate
if cond_H
    _last_H := bar_index

bool _raw_I = near_g1_up and qa_bear_3 and not qa_bull_3 and qa_big_bear3 and not cond_G and f_dedup(_last_I)
bool _raw_J = near_g1_dn and qa_bull_3 and not qa_bear_3 and qa_big_bull3 and not cond_H and f_dedup(_last_J)
bool cond_I = _raw_I
bool cond_J = _raw_J
if cond_I
    _last_I := bar_index
if cond_J
    _last_J := bar_index

bool cond_K = regime == -1 and f_touch(low,  g2_dn) and close > g2_dn - i_tol and not gvz_extreme and f_dedup(_last_K)
if cond_K
    _last_K := bar_index
bool cond_L = regime == 1  and f_touch(high, g2_up) and close < g2_up + i_tol and not gvz_extreme and f_dedup(_last_L)
if cond_L
    _last_L := bar_index
bool cond_M = regime == -1 and exp_conf_dn and f_touch(low,  g3_dn) and close > g3_dn - i_tol and f_dedup(_last_M)
if cond_M
    _last_M := bar_index
bool cond_N = regime == 1  and exp_conf_up and f_touch(high, g3_up) and close < g3_up + i_tol and f_dedup(_last_N)
if cond_N
    _last_N := bar_index

bool any_mr_buy  = cond_A or cond_C or cond_E
bool any_mr_sell = cond_B or cond_D or cond_F

// ═══════════════════════════════════════════════════════════════════════════════
// §K  K-MEANS CLUSTER VP  (unchanged from v18)
// ═══════════════════════════════════════════════════════════════════════════════
var float[] _cvp_prices = array.new_float(0)
if barstate.isconfirmed and i_show_cvp
    array.push(_cvp_prices, close)
    if array.size(_cvp_prices) > i_cvp_lb
        array.shift(_cvp_prices)

var float[] _cvp_centroids = array.new_float(0)
var int[]   _cvp_counts    = array.new_int(0)
// ═══════════════════════════════════════════════════════════════════════════════
// §18  CHART LINES + LABELS + CVP  (barstate.islast)
// ═══════════════════════════════════════════════════════════════════════════════
var array<line>     _all_lines  = array.new_line()
var array<label>    _all_labels = array.new_label()
var array<line>     _cvp_lines  = array.new_line()
var array<label>    _cvp_lbls   = array.new_label()
var array<linefill> _all_fills  = array.new_linefill()

if barstate.islast
    for _l  in _all_lines
        line.delete(_l)
    for _lb in _all_labels
        label.delete(_lb)
    for _l  in _cvp_lines
        line.delete(_l)
    for _lb in _cvp_lbls
        label.delete(_lb)
    for _f  in _all_fills
        linefill.delete(_f)
    array.clear(_all_lines)
    array.clear(_all_labels)
    array.clear(_cvp_lines)
    array.clear(_cvp_lbls)
    array.clear(_all_fills)

    int    _lx0 = bar_index - 250
    int    _lx1 = bar_index + 70
    int    _lxl = bar_index + 4
    string _sz  = size.tiny

    if i_show_cb and not na(_cb_settle)
        array.push(_all_lines, line.new(_lx0,cb_t1_u,_lx1,cb_t1_u,color=i_cb_t1_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,cb_t1_d,_lx1,cb_t1_d,color=i_cb_t1_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,cb_t1_u,"CB-T1 +3%  $"+str.tostring(cb_t1_u,"#.##")+"  [COMEX halt awareness]",color=color.new(i_cb_t1_col,75),textcolor=i_cb_t1_col,style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,cb_t1_d,"CB-T1 -3%  $"+str.tostring(cb_t1_d,"#.##")+"  [COMEX halt awareness]",color=color.new(i_cb_t1_col,75),textcolor=i_cb_t1_col,style=label.style_label_left,size=_sz))
        array.push(_all_lines, line.new(_lx0,cb_t2_u,_lx1,cb_t2_u,color=i_cb_t2_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,cb_t2_d,_lx1,cb_t2_d,color=i_cb_t2_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,cb_t2_u,"CB-T2 +6%  $"+str.tostring(cb_t2_u,"#.##"),color=color.new(i_cb_t2_col,75),textcolor=i_cb_t2_col,style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,cb_t2_d,"CB-T2 -6%  $"+str.tostring(cb_t2_d,"#.##"),color=color.new(i_cb_t2_col,75),textcolor=i_cb_t2_col,style=label.style_label_left,size=_sz))
        array.push(_all_lines, line.new(_lx0,cb_t3_u,_lx1,cb_t3_u,color=i_cb_t3_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,cb_t3_d,_lx1,cb_t3_d,color=i_cb_t3_col,style=line.style_dashed,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,cb_t3_u,"CB-T3 +9%  $"+str.tostring(cb_t3_u,"#.##")+"  [EXTREME HALT]",color=color.new(i_cb_t3_col,75),textcolor=i_cb_t3_col,style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,cb_t3_d,"CB-T3 -9%  $"+str.tostring(cb_t3_d,"#.##")+"  [EXTREME HALT]",color=color.new(i_cb_t3_col,75),textcolor=i_cb_t3_col,style=label.style_label_left,size=_sz))

    if i_ice_strikes
        bool _ice_c1 = math.abs(close - sp_c1) <= i_tol * 1.5 and _amt_mass >= i_ice_mass
        bool _ice_p1 = math.abs(close - sp_p1) <= i_tol * 1.5 and _amt_mass >= i_ice_mass
        string _ize_sz = i_amt_emj_sz == "Huge" ? size.huge : i_amt_emj_sz == "Large" ? size.large : i_amt_emj_sz == "Normal" ? size.normal : size.small
        if _ice_c1
            array.push(_all_labels, label.new(_lxl, sp_c1, "❄️",
                 style    = label.style_label_center,
                 color    = color.new(color.black, 100),
                 textcolor= i_amt_ice_col,
                 size     = _ize_sz,
                 tooltip  = "ICEBERG WARN: CALL+1 $" + str.tostring(sp_c1,"#.##") + "  [SpotEx resistance]"))
        if _ice_p1
            array.push(_all_labels, label.new(_lxl, sp_p1, "❄️",
                 style    = label.style_label_center,
                 color    = color.new(color.black, 100),
                 textcolor= i_amt_ice_col,
                 size     = _ize_sz,
                 tooltip  = "ICEBERG WARN: PUT-1 $" + str.tostring(sp_p1,"#.##") + "  [SpotEx support]"))

    if i_show_g1_band
        string _ru = regime == 1 ? "  TREND UP - NO MR" : regime == -1 ? "  TREND DN - below frame" : "  [MR FRAME UPPER]"
        string _rd = regime == -1 ? "  TREND DN - NO MR" : regime == 1  ? "  TREND UP - above frame" : "  [MR FRAME LOWER]"
        string _m_tag_u = not mlmi_valid ? "  MLMI:EXP" : mlmi_fresh ? "  MLMI:FRESH" : "  MLMI:STALE"
        string _cb_tag = cb_t1_active ? "  " + cb_tier_str : ""
        array.push(_all_labels, label.new(_lxl+2, g1_up, "gFLIP +" + str.tostring(_g1_eff,"#.###") + "x  $" + str.tostring(g1_up,"#.##") + _ru + _m_tag_u + _cb_tag, color=color.new(i_band_g1_col,75), textcolor=i_band_g1_col, style=label.style_label_left, size=_sz))
        array.push(_all_labels, label.new(_lxl+2, g1_dn, "gFLIP -" + str.tostring(_g1_eff,"#.###") + "x  $" + str.tostring(g1_dn,"#.##") + _rd, color=color.new(i_band_g1_col,75), textcolor=i_band_g1_col, style=label.style_label_left, size=_sz))
    if i_show_g2_band
        string _g2u_r = regime == 1  ? "  MR-BLK" : gvz_block_mr ? "  GVZ" : "  [MR SELL if touch]"
        string _g2d_r = regime == -1 ? "  MR-BLK" : gvz_block_mr ? "  GVZ" : "  [MR BUY if touch]"
        array.push(_all_labels, label.new(_lxl+2, g2_up, "gWALL +" + str.tostring(_g2_eff,"#.###") + "x CALL WALL  $" + str.tostring(g2_up,"#.##") + _g2u_r, color=color.new(i_band_g2u_col,75), textcolor=i_band_g2u_col, style=label.style_label_left, size=_sz))
        array.push(_all_labels, label.new(_lxl+2, g2_dn, "gWALL -" + str.tostring(_g2_eff,"#.###") + "x PUT  WALL  $" + str.tostring(g2_dn,"#.##") + _g2d_r, color=color.new(i_band_g2d_col,75), textcolor=i_band_g2d_col, style=label.style_label_left, size=_sz))
    if i_show_g3_band
        array.push(_all_labels, label.new(_lxl+2, g3_up, "gEXP  +" + str.tostring(_g3_eff,"#.###") + "x EXPLOSION  $" + str.tostring(g3_up,"#.##") + (exp_conf_up ? "  SD+PBV CONF" : "") + "  [STRONG SELL]", color=color.new(i_band_g3_col,75), textcolor=i_band_g3_col, style=label.style_label_left, size=_sz))
        array.push(_all_labels, label.new(_lxl+2, g3_dn, "gEXP  -" + str.tostring(_g3_eff,"#.###") + "x EXPLOSION  $" + str.tostring(g3_dn,"#.##") + (exp_conf_dn ? "  SD+PBV CONF" : "") + "  [STRONG BUY]",  color=color.new(i_band_g3_col,75), textcolor=i_band_g3_col, style=label.style_label_left, size=_sz))

    if i_show_basis
        color _eq = basis_stable ? #00E676 : #FF9800
        color _ez = math.abs(sess_z) >= 2.0 ? #FF9800 : #00E676
        string _el = "EFP " + _sess_lbl + " Z=" + str.tostring(sess_z,"#.##") + "s  " + gofo_regime + "  " + basis_trend_s + (in_fix ? "  FIX" : "") + "  GOFO " + str.tostring(i_gofo_rate,"#.##") + "%"
        array.push(_all_labels, label.new(bar_index+2, anchor + p_std*(i_sd_mult+0.3), _el, style=label.style_label_left, size=size.tiny, color=in_fix ? color.new(#FFD700,50) : color.new(_eq,65), textcolor=in_fix ? #FFD700 : _eq))
        if sess_z_ext
            array.push(_all_labels, label.new(bar_index-5, anchor + p_std*i_sd_mult*1.1, "EFP ARB Z=" + str.tostring(sess_z,"#.##") + "s  " + (sess_z > 0 ? "PREMIUM" : "DISCOUNT"), style=label.style_label_left, size=size.tiny, color=color.new(sess_z > 0 ? #FF1744 : #00E676,55), textcolor=sess_z > 0 ? #FF1744 : #00E676))

    if i_show_sd
        if _show_phi_sys
            string _sdlsz = f_lsz(i_sd_lbl_sz)
            string _pu_fr = _sd_phi_u_in_frame ? " [IN FRAME]" : " [out]"
            string _pd_fr = _sd_phi_d_in_frame ? " [IN FRAME]" : " [out]"
            array.push(_all_lines, line.new(_lx0, sd_phi_u, _lx1, sd_phi_u, color=i_phi_col, style=line.style_dotted, width=1, extend=extend.right))
            array.push(_all_lines, line.new(_lx0, sd_phi_d, _lx1, sd_phi_d, color=i_phi_col, style=line.style_dotted, width=1, extend=extend.right))
            array.push(_all_labels, label.new(_lxl, sd_phi_u, "+" + str.tostring(i_sd_mult,"#.###") + "s phi  $" + str.tostring(sd_phi_u,"#.##") + (_sd_phi_u_conf ? "  g3" : "") + (_using_delta_sig ? "" : "  [SIG]") + _pu_fr, color=color.new(i_phi_col,i_phi_lbl_tr), textcolor=i_phi_col, style=label.style_label_left, size=_sdlsz))
            array.push(_all_labels, label.new(_lxl, sd_phi_d, "-" + str.tostring(i_sd_mult,"#.###") + "s phi  $" + str.tostring(sd_phi_d,"#.##") + (_sd_phi_d_conf ? "  g3" : "") + (_using_delta_sig ? "" : "  [SIG]") + _pd_fr, color=color.new(i_phi_col,i_phi_lbl_tr), textcolor=i_phi_col, style=label.style_label_left, size=_sdlsz))

        if _show_delta_sys
            color  _c25 = i_d25_col
            color  _c15 = i_d15_col
            color  _c5  = i_d5_col
            string _sdlsz = f_lsz(i_sd_lbl_sz)
            line l_45u = line.new(_lx0,_sd_45d_u,_lx1,_sd_45d_u,color=i_d45_col,style=line.style_dotted,width=1,extend=extend.right)
            line l_45d = line.new(_lx0,_sd_45d_d,_lx1,_sd_45d_d,color=i_d45_col,style=line.style_dotted,width=1,extend=extend.right)
            array.push(_all_lines, l_45u)
            array.push(_all_lines, l_45d)
            line l_35u = line.new(_lx0,_sd_35d_u,_lx1,_sd_35d_u,color=i_d35_col,style=line.style_dotted,width=1,extend=extend.right)
            line l_35d = line.new(_lx0,_sd_35d_d,_lx1,_sd_35d_d,color=i_d35_col,style=line.style_dotted,width=1,extend=extend.right)
            array.push(_all_lines, l_35u)
            array.push(_all_lines, l_35d)
            line l_25u = line.new(_lx0,_sd_25d_u,_lx1,_sd_25d_u,color=_c25,style=line.style_dotted,width=1,extend=extend.right)
            line l_25d = line.new(_lx0,_sd_25d_d,_lx1,_sd_25d_d,color=_c25,style=line.style_dotted,width=1,extend=extend.right)
            array.push(_all_lines, l_25u)
            array.push(_all_lines, l_25d)
            line l_15u = line.new(_lx0,_sd_15d_u,_lx1,_sd_15d_u,color=_c15,style=line.style_dotted,width=1,extend=extend.right)
            line l_15d = line.new(_lx0,_sd_15d_d,_lx1,_sd_15d_d,color=_c15,style=line.style_dotted,width=1,extend=extend.right)
            array.push(_all_lines, l_15u)
            array.push(_all_lines, l_15d)
            line l_5u  = line.new(_lx0,_sd_5d_u,_lx1,_sd_5d_u,color=_c5,style=line.style_dotted,width=1,extend=extend.right)
            line l_5d  = line.new(_lx0,_sd_5d_d,_lx1,_sd_5d_d,color=_c5,style=line.style_dotted,width=1,extend=extend.right)
            array.push(_all_lines, l_5u)
            array.push(_all_lines, l_5d)
            if i_show_fill
                array.push(_all_fills, linefill.new(l_5u,  l_15u, i_fill_5_15))
                array.push(_all_fills, linefill.new(l_15u, l_25u, i_fill_15_25))
                array.push(_all_fills, linefill.new(l_25u, l_35u, i_fill_25_35))
                array.push(_all_fills, linefill.new(l_35u, l_45u, i_fill_35_45))
                array.push(_all_fills, linefill.new(l_5d,  l_15d, i_fill_5_15))
                array.push(_all_fills, linefill.new(l_15d, l_25d, i_fill_15_25))
                array.push(_all_fills, linefill.new(l_25d, l_35d, i_fill_25_35))
                array.push(_all_fills, linefill.new(l_35d, l_45d, i_fill_35_45))
            string _25u_fr = _sd_25d_u_in_frame ? " [IN FRAME]" : " [out]"
            string _25d_fr = _sd_25d_d_in_frame ? " [IN FRAME]" : " [out]"
            string _25_sig = _using_delta_sig ? "  [SIG]" : ""
            array.push(_all_labels, label.new(_lxl, _sd_25d_u, "+25D  $" + str.tostring(_sd_25d_u,"#.##") + "  0.674s" + _25_sig + (_sd_25d_u_conf ? "  g3" : "") + _25u_fr, color=color.new(_c25,i_d25_lbl_tr), textcolor=_c25, style=label.style_label_left, size=_sdlsz))
            array.push(_all_labels, label.new(_lxl, _sd_25d_d, "-25D  $" + str.tostring(_sd_25d_d,"#.##") + "  0.674s" + _25_sig + (_sd_25d_d_conf ? "  g3" : "") + _25d_fr, color=color.new(_c25,i_d25_lbl_tr), textcolor=_c25, style=label.style_label_left, size=_sdlsz))
            string _15u_fr = _sd_15d_u_in_frame ? " [IN FRAME]" : " [out]"
            string _15d_fr = _sd_15d_d_in_frame ? " [IN FRAME]" : " [out]"
            string _15u_tag = i_skew_15d_c != 1.0 ? "x" + str.tostring(i_skew_15d_c,"#.##") : ""
            string _15d_tag = i_skew_15d_p != 1.0 ? "x" + str.tostring(i_skew_15d_p,"#.##") : ""
            array.push(_all_labels, label.new(_lxl, _sd_15d_u, "+15D  $" + str.tostring(_sd_15d_u,"#.##") + "  1.036s" + _15u_tag + _15u_fr, color=color.new(_c15,i_d15_lbl_tr), textcolor=_c15, style=label.style_label_left, size=_sdlsz))
            array.push(_all_labels, label.new(_lxl, _sd_15d_d, "-15D  $" + str.tostring(_sd_15d_d,"#.##") + "  1.036s" + _15d_tag + _15d_fr, color=color.new(_c15,i_d15_lbl_tr), textcolor=_c15, style=label.style_label_left, size=_sdlsz))
            string _5u_fr  = _sd_5d_u < g1_up and _sd_5d_u > g1_dn ? " [IN FRAME]" : " [out]"
            string _5d_fr  = _sd_5d_d > g1_dn and _sd_5d_d < g1_up ? " [IN FRAME]" : " [out]"
            array.push(_all_labels, label.new(_lxl, _sd_5d_u, " +5D  $" + str.tostring(_sd_5d_u,"#.##") + "  1.645s", color=color.new(_c5,i_d5_lbl_tr), textcolor=_c5, style=label.style_label_left, size=_sdlsz))
            array.push(_all_labels, label.new(_lxl, _sd_5d_d, " -5D  $" + str.tostring(_sd_5d_d,"#.##") + "  1.645s", color=color.new(_c5,i_d5_lbl_tr), textcolor=_c5, style=label.style_label_left, size=_sdlsz))

        array.push(_all_lines, line.new(_lx0,pbv_l1_u,_lx1,pbv_l1_u,color=i_c_pbv,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,pbv_l1_d,_lx1,pbv_l1_d,color=i_c_pbv,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,pbv_l1_u,"PBV L1+" + str.tostring(i_pbv_1,"#.###") + "%  $" + str.tostring(pbv_l1_u,"#.##") + (pbv1_u_conf ? "  g2" : ""),color=color.new(i_c_pbv,80),textcolor=i_c_pbv,style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,pbv_l1_d,"PBV L1-" + str.tostring(i_pbv_1,"#.###") + "%  $" + str.tostring(pbv_l1_d,"#.##") + (pbv1_d_conf ? "  g2" : ""),color=color.new(i_c_pbv,80),textcolor=i_c_pbv,style=label.style_label_left,size=_sz))
        array.push(_all_lines, line.new(_lx0,pbv_l2_u,_lx1,pbv_l2_u,color=color.new(i_c_pbv,30),style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,pbv_l2_d,_lx1,pbv_l2_d,color=color.new(i_c_pbv,30),style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,pbv_l2_u,"PBV L2+" + str.tostring(i_pbv_2,"#.###") + "%  $" + str.tostring(pbv_l2_u,"#.##") + (pbv2_u_conf ? "  g3" : ""),color=color.new(i_c_pbv,85),textcolor=color.new(i_c_pbv,30),style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,pbv_l2_d,"PBV L2-" + str.tostring(i_pbv_2,"#.###") + "%  $" + str.tostring(pbv_l2_d,"#.##") + (pbv2_d_conf ? "  g3" : ""),color=color.new(i_c_pbv,85),textcolor=color.new(i_c_pbv,30),style=label.style_label_left,size=_sz))
        array.push(_all_lines, line.new(_lx0,pbv_l3_u,_lx1,pbv_l3_u,color=color.new(i_c_pbv,20),style=line.style_dotted,width=2,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,pbv_l3_d,_lx1,pbv_l3_d,color=color.new(i_c_pbv,20),style=line.style_dotted,width=2,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,pbv_l3_u,"PBV L3+" + str.tostring(i_pbv_3,"#.###") + "%  $" + str.tostring(pbv_l3_u,"#.##") + (pbv3_u_conf ? "  g3 CONF [Explosion]" : "  [Explosion Tier]"),color=color.new(i_c_pbv,75),textcolor=color.new(i_c_pbv,10),style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,pbv_l3_d,"PBV L3-" + str.tostring(i_pbv_3,"#.###") + "%  $" + str.tostring(pbv_l3_d,"#.##") + (pbv3_d_conf ? "  g3 CONF [Explosion]" : "  [Explosion Tier]"),color=color.new(i_c_pbv,75),textcolor=color.new(i_c_pbv,10),style=label.style_label_left,size=_sz))

    if i_show_str
        bool _blk_c = regime == 1
        bool _blk_p = regime == -1
        color _cc1 = _blk_c ? i_c_blk_ln : i_cc_line
        color _cp1 = _blk_p ? i_c_blk_ln : i_cp_line
        array.push(_all_lines, line.new(_lx0,sp_c1,_lx1,sp_c1,color=_cc1,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,sp_p1,_lx1,sp_p1,color=_cp1,style=line.style_dotted,width=1,extend=extend.right))
        float _b_dev  = b_std > 0.0 ? math.abs(raw_basis - b_mean) / b_std : 0.0
        int _sc_sell = f_dir_score(false,qa_bull_3,qa_bear_3,gvz_compressed,gvz_normal,gvz_elevated,gvz_extreme,sig_regime,_is_lon,_is_ny,_is_asia,dxy_penalise_buy,dxy_penalise_sell,frame_ok,sqz_up,sqz_dn,_b_dev)
        int _sc_buy  = f_dir_score(true, qa_bull_3,qa_bear_3,gvz_compressed,gvz_normal,gvz_elevated,gvz_extreme,sig_regime,_is_lon,_is_ny,_is_asia,dxy_penalise_buy,dxy_penalise_sell,frame_ok,sqz_up,sqz_dn,_b_dev)
        string _sell_grade = _sc_sell >= 70 ? "SELL " : _sc_sell >= 50 ? "sell " : "wk "
        string _buy_grade  = _sc_buy  >= 70 ? "BUY  " : _sc_buy  >= 50 ? "buy  " : "wk  "
        string _qa_s  = qa_big_bear3 ? " QA-BIG" : qa_any_bear ? " qa-sm" : ""
        string _qa_b  = qa_big_bull3 ? " QA-BIG" : qa_any_bull ? " qa-sm" : ""
        string _mlm_s = mlmi_fresh ? (mlmi_bear ? " ML:BEAR" : " ML:--") : ""
        string _mlm_b = mlmi_fresh ? (mlmi_bull ? " ML:BULL" : " ML:--") : ""
        string _smi_s = smi_overbought ? " SMI:OB" : smi_bear_cross ? " SMI:Xdn" : ""
        string _smi_b = smi_oversold   ? " SMI:OS" : smi_bull_cross  ? " SMI:Xup" : ""
        string _gvz_s = gvz_compressed ? " sGVZ" : gvz_extreme ? " GVZ!" : gvz_elevated ? " GVZ~" : ""
        string _dxy_s = dxy_bull ? " DXY+" : dxy_bear ? " DXY-" : ""
        string _sess  = _is_lon ? " LON" : _is_ny ? " NY" : " ASIA"
        string _sc1 = "CALL+1  $" + str.tostring(sp_c1,"#.##") + "  " + (_blk_c ? "MR-BLK" : (_sell_grade + str.tostring(_sc_sell) + "%" + (i_rich_lbl ? _qa_s + _gvz_s + _dxy_s + _smi_s + _mlm_s + _sess : "")))
        string _sp1 = "PUT-1   $" + str.tostring(sp_p1,"#.##") + "  " + (_blk_p ? "MR-BLK" : (_buy_grade  + str.tostring(_sc_buy)  + "%" + (i_rich_lbl ? _qa_b + _gvz_s + _dxy_s + _smi_b + _mlm_b + _sess : "")))
        color _lc1 = _blk_c ? i_c_blk_bg : _sc_sell >= 70 ? i_cc_bg_str : _sc_sell >= 50 ? i_cc_bg_med : i_cc_bg_norm
        color _lcp = _blk_p ? i_c_blk_bg : _sc_buy  >= 70 ? i_cp_bg_str : _sc_buy  >= 50 ? i_cp_bg_med : i_cp_bg_norm
        color _tc1 = _blk_c ? i_c_blk_txt : _sc_sell >= 70 ? i_cc_txt_str : _sc_sell >= 50 ? i_cc_txt_med : i_cc_txt_norm
        color _tcp = _blk_p ? i_c_blk_txt : _sc_buy  >= 70 ? i_cp_txt_str : _sc_buy  >= 50 ? i_cp_txt_med : i_cp_txt_norm
        array.push(_all_labels, label.new(_lxl,sp_c1,_sc1,color=_lc1,textcolor=_tc1,style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,sp_p1,_sp1,color=_lcp,textcolor=_tcp,style=label.style_label_left,size=_sz))
        if i_n_str >= 2
            array.push(_all_lines, line.new(_lx0,sp_c2,_lx1,sp_c2,color=color.new(_cc1,35),style=line.style_dotted,width=1,extend=extend.right))
            array.push(_all_lines, line.new(_lx0,sp_p2,_lx1,sp_p2,color=color.new(_cp1,35),style=line.style_dotted,width=1,extend=extend.right))
            array.push(_all_labels, label.new(_lxl,sp_c2,"CALL+2  $"+str.tostring(sp_c2,"#.##"),color=color.new(_cc1,85),textcolor=color.new(_tc1,30),style=label.style_label_left,size=_sz))
            array.push(_all_labels, label.new(_lxl,sp_p2,"PUT-2   $"+str.tostring(sp_p2,"#.##"),color=color.new(_cp1,85),textcolor=color.new(_tcp,30),style=label.style_label_left,size=_sz))
        if i_n_str >= 3
            array.push(_all_lines, line.new(_lx0,sp_c3,_lx1,sp_c3,color=color.new(_cc1,55),style=line.style_dotted,width=1,extend=extend.right))
            array.push(_all_lines, line.new(_lx0,sp_p3,_lx1,sp_p3,color=color.new(_cp1,55),style=line.style_dotted,width=1,extend=extend.right))
        if i_n_str >= 4
            array.push(_all_lines, line.new(_lx0,sp_c4,_lx1,sp_c4,color=color.new(_cc1,65),style=line.style_dotted,width=1,extend=extend.right))
            array.push(_all_lines, line.new(_lx0,sp_p4,_lx1,sp_p4,color=color.new(_cp1,65),style=line.style_dotted,width=1,extend=extend.right))

    if cond_I
        float _sbuy = sp_c1 + i_tol
        array.push(_all_lines, line.new(_lx0,_sbuy,_lx1,_sbuy,color=#FFD700,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,_sbuy,"gSTOP BUY  $"+str.tostring(_sbuy,"#.##"),color=color.new(#FFD700,75),textcolor=#FFD700,style=label.style_label_left,size=_sz))
    if cond_J
        float _ssell = sp_p1 - i_tol
        array.push(_all_lines, line.new(_lx0,_ssell,_lx1,_ssell,color=#FFD700,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,_ssell,"gSTOP SELL  $"+str.tostring(_ssell,"#.##"),color=color.new(#FFD700,75),textcolor=#FFD700,style=label.style_label_left,size=_sz))

    if i_show_em
        color _em_c1 = color.new(#00BCD4,30)
        string _ep   = gvz_v > 0.0 and not na(gvz_d) ? str.tostring(gvz_v,"#.1") + "% GVZ" : "YZ fallback"
        array.push(_all_lines, line.new(_lx0,em_upper,_lx1,em_upper,color=_em_c1,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,em_lower,_lx1,em_lower,color=_em_c1,style=line.style_dotted,width=1,extend=extend.right))
        if i_show_em_lbl
            array.push(_all_labels, label.new(_lxl,em_upper,"EM+1s 68.3%  $"+str.tostring(em_upper,"#.##")+"  +/-$"+str.tostring(em_1sigma,"#.##")+" ["+_ep+"]",color=color.new(#00BCD4,75),textcolor=color.new(#00BCD4,0),style=label.style_label_left,size=_sz))
            array.push(_all_labels, label.new(_lxl,em_lower,"EM-1s 68.3%  $"+str.tostring(em_lower,"#.##"),color=color.new(#00BCD4,75),textcolor=color.new(#00BCD4,0),style=label.style_label_left,size=_sz))
    if i_show_em2
        array.push(_all_lines, line.new(_lx0,em_upper_2,_lx1,em_upper_2,color=color.new(#00BCD4,50),style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,em_lower_2,_lx1,em_lower_2,color=color.new(#00BCD4,50),style=line.style_dotted,width=1,extend=extend.right))
        if i_show_em_lbl
            array.push(_all_labels, label.new(_lxl,em_upper_2,"EM+2s 95.5%  $"+str.tostring(em_upper_2,"#.##"),color=color.new(#00BCD4,80),textcolor=color.new(#00BCD4,25),style=label.style_label_left,size=_sz))
            array.push(_all_labels, label.new(_lxl,em_lower_2,"EM-2s 95.5%  $"+str.tostring(em_lower_2,"#.##"),color=color.new(#00BCD4,80),textcolor=color.new(#00BCD4,25),style=label.style_label_left,size=_sz))
    if i_show_em3
        array.push(_all_lines, line.new(_lx0,em_upper_3,_lx1,em_upper_3,color=color.new(i_c_em3,20),style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,em_lower_3,_lx1,em_lower_3,color=color.new(i_c_em3,20),style=line.style_dotted,width=1,extend=extend.right))
        if i_show_em_lbl
            array.push(_all_labels, label.new(_lxl,em_upper_3,"EM+3s 99.7%  $"+str.tostring(em_upper_3,"#.##")+"  TAIL RISK",color=color.new(i_c_em3,70),textcolor=i_c_em3,style=label.style_label_left,size=_sz))
            array.push(_all_labels, label.new(_lxl,em_lower_3,"EM-3s 99.7%  $"+str.tostring(em_lower_3,"#.##")+"  TAIL RISK",color=color.new(i_c_em3,70),textcolor=i_c_em3,style=label.style_label_left,size=_sz))
    if i_show_yz_av
        color _yz_col = color.new(#CE93D8,55)
        array.push(_all_lines, line.new(_lx0,yz_band_u,_lx1,yz_band_u,color=_yz_col,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_lines, line.new(_lx0,yz_band_d,_lx1,yz_band_d,color=_yz_col,style=line.style_dotted,width=1,extend=extend.right))
        array.push(_all_labels, label.new(_lxl,yz_band_u,"YZ s+  $"+str.tostring(yz_band_u,"#.##")+"  [Realized Vol]",color=color.new(#CE93D8,80),textcolor=color.new(#CE93D8,20),style=label.style_label_left,size=_sz))
        array.push(_all_labels, label.new(_lxl,yz_band_d,"YZ s-  $"+str.tostring(yz_band_d,"#.##")+"  [Realized Vol]",color=color.new(#CE93D8,80),textcolor=color.new(#CE93D8,20),style=label.style_label_left,size=_sz))

    string _mlmi_tag = mlmi_fresh ? " ML:F" : mlmi_valid ? " ML:S" : " ML:X"
    string _smi_tag  = smi_overbought ? " SMI:OB" : smi_oversold ? " SMI:OS" : " SMI:" + str.tostring(smi,"#.0")
    string _dxy_tag  = dxy_bull ? " DXY:BEAR-XAU" : dxy_bear ? " DXY:BULL-XAU" : ""
    string _cb_reg   = cb_t1_active ? "  " + cb_tier_str : ""
    string _sfx      = conf_str + _mlmi_tag + _smi_tag + _dxy_tag + _cb_reg
    string _reg_txt  = switch regime
        1  => "g TREND UP  TGT $" + str.tostring(g2_up,"#.##") + "  MR@CALL+1  CONF:" + _sfx
        -1 => "g TREND DN  TGT $" + str.tostring(g2_dn,"#.##") + "  MR@PUT-1   CONF:" + _sfx
        =>    "g MR ZONE  CALL+1 $" + str.tostring(sp_c1,"#.##") + " / PUT-1 $" + str.tostring(sp_p1,"#.##") + "  CONF:" + _sfx
    color _reg_col = switch regime
        1  => color(#00E5FF)
        -1 => color(#FF6F00)
        =>    color(#00E676)
    array.push(_all_labels, label.new(bar_index+2, close, _reg_txt, color=color.new(_reg_col,40), textcolor=_reg_col, style=label.style_label_left, size=size.small))

    int _np = array.size(_cvp_prices)
    if i_show_cvp and _np >= math.max(i_n_clusters * 3, 15)
        float _pmin = array.min(_cvp_prices)
        float _pmax = array.max(_cvp_prices)
        float _prng = math.max(_pmax - _pmin, syminfo.mintick * 10)
        int   _nc   = i_n_clusters
        array.clear(_cvp_centroids)
        array.clear(_cvp_counts)
        for _k = 0 to _nc - 1
            array.push(_cvp_centroids, _pmin + _prng * (float(_k) + 0.5) / float(_nc))
            array.push(_cvp_counts, 0)
        for _iter = 0 to i_km_iter - 1
            float[] _sums = array.new_float(_nc, 0.0)
            int[]   _cnts = array.new_int(_nc, 0)
            for _pi = 0 to _np - 1
                float _px = array.get(_cvp_prices, _pi)
                int   _bk = 0
                float _bd = math.abs(_px - array.get(_cvp_centroids, 0))
                for _k = 1 to _nc - 1
                    float _d = math.abs(_px - array.get(_cvp_centroids, _k))
                    if _d < _bd
                        _bd := _d
                        _bk := _k
                array.set(_sums, _bk, array.get(_sums, _bk) + _px)
                array.set(_cnts, _bk, array.get(_cnts, _bk) + 1)
            for _k = 0 to _nc - 1
                if array.get(_cnts, _k) > 0
                    array.set(_cvp_centroids, _k, array.get(_sums, _k) / float(array.get(_cnts, _k)))
            if _iter == i_km_iter - 1
                for _k = 0 to _nc - 1
                    array.set(_cvp_counts, _k, array.get(_cnts, _k))
        int   _poc_k   = 0
        int   _poc_cnt = 0
        for _k = 0 to _nc - 1
            if array.get(_cvp_counts, _k) > _poc_cnt
                _poc_cnt := array.get(_cvp_counts, _k)
                _poc_k   := _k
        int[] _sorted_idx = array.new_int(_nc, 0)
        for _k = 0 to _nc - 1
            array.set(_sorted_idx, _k, _k)
        for _i = 0 to _nc - 2
            for _j = 0 to _nc - _i - 2
                int _ia = array.get(_sorted_idx, _j)
                int _ib = array.get(_sorted_idx, _j + 1)
                if array.get(_cvp_centroids, _ia) > array.get(_cvp_centroids, _ib)
                    array.set(_sorted_idx, _j, _ib)
                    array.set(_sorted_idx, _j + 1, _ia)
        int _lx_start = bar_index - i_cvp_lb
        int _lx_end   = bar_index + i_cvp_ext
        for _r = 0 to _nc - 1
            int   _k      = array.get(_sorted_idx, _r)
            float _lev    = array.get(_cvp_centroids, _k)
            int   _cnt    = array.get(_cvp_counts, _k)
            bool  _is_poc = _k == _poc_k
            float _dens   = _np > 0 ? float(_cnt) / float(_np) * 100.0 : 0.0
            color _lc     = _is_poc ? color.new(i_cvp_poc_col,0) : color.new(i_cvp_col,40)
            int   _lw     = _is_poc ? math.max(i_cvp_line_w+1,2) : i_cvp_line_w
            string _cvp_s = _is_poc ? i_cvp_poc_sty : i_cvp_clus_sty
            array.push(_cvp_lines, line.new(_lx_start,_lev,_lx_end,_lev,color=_lc,style=f_ls(_cvp_s),width=_lw,extend=extend.none))
            if i_cvp_label
                string _lt = "C" + str.tostring(_r+1) + (_is_poc ? " POC" : "") + "  $" + str.tostring(_lev,"#.##") + "  " + str.tostring(_dens,"#.0") + "%"
                array.push(_cvp_lbls, label.new(_lx_end+2,_lev,_lt,color=color.new(_lc,60),textcolor=_lc,style=label.style_label_left,size=f_lsz(i_cvp_lbl_sz)))
            if i_cvp_dots and math.abs(close - _lev) <= i_tol * 2.0
                array.push(_cvp_lbls, label.new(bar_index,_lev,"",style=label.style_circle,color=_is_poc ? i_cvp_poc_col : i_cvp_col,size=f_dsz(i_cvp_dot_sz2)))
// ═══════════════════════════════════════════════════════════════════════════════
// §19  CHART PLOTS + SIGNALS
// ═══════════════════════════════════════════════════════════════════════════════
plot(i_show_g1_band ? g1_up : na, "Gamma Flip (+)",  color=i_band_g1_col,  linewidth=i_band_g1_w, style=plot.style_line)
plot(i_show_g1_band ? g1_dn : na, "Gamma Flip (-)",  color=i_band_g1_col,  linewidth=i_band_g1_w, style=plot.style_line)
plot(i_show_g2_band ? g2_up : na, "Call Wall (+)",   color=i_band_g2u_col, linewidth=i_band_g2_w, style=plot.style_line)
plot(i_show_g2_band ? g2_dn : na, "Put Wall (-)",    color=i_band_g2d_col, linewidth=i_band_g2_w, style=plot.style_line)
plot(i_show_g3_band ? g3_up : na, "Explosion (+)", color=i_band_g3_col, linewidth=i_band_g3_w, style=plot.style_line)
plot(i_show_g3_band ? g3_dn : na, "Explosion (-)", color=i_band_g3_col, linewidth=i_band_g3_w, style=plot.style_line)

plot(i_show_alma ? alma_l1 : na, "ALMA L1 (Fast)", color=i_al1_col, linewidth=i_al1_w, style=plot.style_line)
plot(i_show_alma ? alma_l2 : na, "ALMA L2 (Med)",  color=i_al2_col, linewidth=i_al2_w, style=plot.style_line)
plot(i_show_alma ? alma_l3 : na, "ALMA L3 (Slow)", color=i_al3_col, linewidth=i_al3_w, style=plot.style_line)

plot(i_show_qblk ? qb_h4_u2 : na, "Q-Block +2", color=color.new(color.red,  50), style=plot.style_circles)
plot(i_show_qblk ? qb_h4_u1 : na, "Q-Block +1", color=color.new(color.red,  20), style=plot.style_circles)
plot(i_show_qblk ? qb_h4_0  : na, "Q-Block W0", color=color.new(color.gray, 10), style=plot.style_circles, linewidth=2)
plot(i_show_qblk ? qb_h4_d1 : na, "Q-Block -1", color=color.new(color.teal, 20), style=plot.style_circles)
plot(i_show_qblk ? qb_h4_d2 : na, "Q-Block -2", color=color.new(color.teal, 50), style=plot.style_circles)

plot(i_show_vwap  ? lon_vwap   : na, "London VWAP",  color=color.new(#FFD700,30), linewidth=1, style=plot.style_line)

var array<label> _sig_stop_lbs = array.new_label()
var array<label> _sig_exp_lbs  = array.new_label()
if cond_I
    array.push(_sig_stop_lbs, label.new(bar_index, high, "gSTOP BUY",
         style=label.style_label_down, color=color.new(#FFD700,20),
         textcolor=color.black, size=size.tiny,
         tooltip="gSTOP BUY — Wrong-dir Bear QA at g1_up"))
if cond_J
    array.push(_sig_stop_lbs, label.new(bar_index, low, "gSTOP SELL",
         style=label.style_label_up, color=color.new(#FFD700,20),
         textcolor=color.black, size=size.tiny,
         tooltip="gSTOP SELL — Wrong-dir Bull QA at g1_dn"))
if array.size(_sig_stop_lbs) > 100
    label.delete(array.shift(_sig_stop_lbs))
if cond_M
    array.push(_sig_exp_lbs, label.new(bar_index, low, "gEXP ▲",
         style=label.style_label_up, color=color.new(#D500F9,0),
         textcolor=color.white, size=size.large,
         tooltip="gEXP STRONG BUY — SD/PBV confluence at g3_dn. Regime=DN."))
if cond_N
    array.push(_sig_exp_lbs, label.new(bar_index, high, "gEXP ▼",
         style=label.style_label_down, color=color.new(#D500F9,0),
         textcolor=color.white, size=size.large,
         tooltip="gEXP STRONG SELL — SD/PBV confluence at g3_up. Regime=UP."))
if array.size(_sig_exp_lbs) > 100
    label.delete(array.shift(_sig_exp_lbs))

plotshape((_qa_t0 or _qa_t1) ? _qa_plot_y : na, title="QA Bubble 1-2 (<4x)", style=shape.circle, location=location.absolute, color=_qa_bub_col, size=size.normal, text="", textcolor=color.new(color.white,100))
plotshape(_qa_t2 ? _qa_plot_y : na, title="QA Bubble 3 (4-6.5x)",  style=shape.circle, location=location.absolute, color=_qa_bub_col, size=size.large,  text="", textcolor=color.new(color.white,100))
plotshape(_qa_t3 ? _qa_plot_y : na, title="QA Bubble 4 (6.5-10x)", style=shape.circle, location=location.absolute, color=_qa_bub_col, size=size.large,  text="", textcolor=color.new(color.white,100))
plotshape(_qa_t4 ? _qa_plot_y : na, title="QA Bubble 5 (10x+)",    style=shape.circle, location=location.absolute, color=_qa_bub_col, size=size.huge,   text="", textcolor=color.new(color.white,100))

// ═══════════════════════════════════════════════════════════════════════════════
// §19b  NO-VOLUME WARNING TABLE
// ═══════════════════════════════════════════════════════════════════════════════
var table _qa_warn_tbl = table.new(position.middle_center, 1, 1, bgcolor=color.new(color.red, 100))

if barstate.islast
    if _qa_cum_vol == 0.0
        table.cell(_qa_warn_tbl, 0, 0,
             "\n  NO VOLUME DATA  \n\n  GEX+EFP Matrix Volume Bubbles requires volume data.  \n\n  Switch to a symbol with volume on exchange.  \n",
             text_color = chart.fg_color,
             text_size  = size.large,
             bgcolor    = #FF0000)
    else
        table.cell(_qa_warn_tbl, 0, 0, "",
             text_color = color.new(color.red, 100),
             bgcolor    = color.new(color.red, 100))
// ═══════════════════════════════════════════════════════════════════════════════
// §20  ALERTS  (all const string — CE10123 compliant)
// ═══════════════════════════════════════════════════════════════════════════════
alertcondition(cond_A, title="[GEX+EFP Matrix] g MR BUY — Gamma Flip (MLMI stale gate)",       message="GEX+EFP Matrix — gFLIP MR BUY at g1_dn. MLMI valid. Priority Gate: Tier 2.")
alertcondition(cond_B, title="[GEX+EFP Matrix] g MR SELL — Gamma Flip (MLMI stale gate)",      message="GEX+EFP Matrix — gFLIP MR SELL at g1_up. MLMI valid. Priority Gate: Tier 2.")
alertcondition(cond_C, title="[GEX+EFP Matrix] g SD MR BUY — 25D/PHI (MLMI fresh gate)",       message="GEX+EFP Matrix — gSD MR BUY. MLMI fresh confirmed. Tier 1 priority.")
alertcondition(cond_D, title="[GEX+EFP Matrix] g SD MR SELL — 25D/PHI (MLMI fresh gate)",      message="GEX+EFP Matrix — gSD MR SELL. MLMI fresh confirmed. Tier 1 priority.")
alertcondition(cond_E, title="[GEX+EFP Matrix] g STRIKE MR BUY — Put-1",                       message="GEX+EFP Matrix — gSTRIKE MR BUY at Put-1. Tier 3 fallback.")
alertcondition(cond_F, title="[GEX+EFP Matrix] g STRIKE MR SELL — Call+1",                     message="GEX+EFP Matrix — gSTRIKE MR SELL at Call+1. Tier 3 fallback.")
alertcondition(cond_G, title="[GEX+EFP Matrix] g BREAKOUT BUY (SMI gate)",                     message="GEX+EFP Matrix — gBO BUY. QA Big Bull + SMI confirmed. Target Wall 2x.")
alertcondition(cond_H, title="[GEX+EFP Matrix] g BREAKOUT SELL (SMI gate)",                    message="GEX+EFP Matrix — gBO SELL. QA Big Bear + SMI confirmed. Target Wall 2x.")
alertcondition(cond_I, title="[GEX+EFP Matrix] g STOP BUY PENDING",                            message="GEX+EFP Matrix — Wrong-dir QA Bear at g1_up. STOP BUY pending.")
alertcondition(cond_J, title="[GEX+EFP Matrix] g STOP SELL PENDING",                           message="GEX+EFP Matrix — Wrong-dir QA Bull at g1_dn. STOP SELL pending.")
alertcondition(cond_K, title="[GEX+EFP Matrix] g WALL BUY | Regime=DN",                        message="GEX+EFP Matrix — gWALL MR BUY at gamma wall -2x in downtrend.")
alertcondition(cond_L, title="[GEX+EFP Matrix] g WALL SELL | Regime=UP",                       message="GEX+EFP Matrix — gWALL MR SELL at gamma wall +2x in uptrend.")
alertcondition(cond_M, title="[GEX+EFP Matrix] g EXPLOSION STRONG BUY",                        message="GEX+EFP Matrix — gEXP STRONG BUY. SD/PBV confluence + Regime=DN.")
alertcondition(cond_N, title="[GEX+EFP Matrix] g EXPLOSION STRONG SELL",                       message="GEX+EFP Matrix — gEXP STRONG SELL. SD/PBV confluence + Regime=UP.")
alertcondition(gvz_extreme and not gvz_extreme[1],   title="[GEX+EFP Matrix] GVZ EXTREME — MR Blocked",    message="GEX+EFP Matrix — GVZ EXTREME. All MR signals blocked.")
alertcondition(gvz_crisis  and not gvz_crisis[1],    title="[GEX+EFP Matrix] GVZ CRISIS SPIKE",            message="GEX+EFP Matrix — GVZ crisis Z>2.5s. Stand aside.")
alertcondition(is_lon_open,                           title="[GEX+EFP Matrix] London Open — VWAP Reset",    message="GEX+EFP Matrix — London 03:00 UTC. VWAP reset. Highest signal quality window.")
alertcondition(qa_any_bull and not qa_any_bull[1],    title="[GEX+EFP Matrix] QA Bubble BULL | Watch BO",   message="GEX+EFP Matrix — QuantAlgo BULL delta cluster. Watch g1_up for BO.")
alertcondition(qa_any_bear and not qa_any_bear[1],    title="[GEX+EFP Matrix] QA Bubble BEAR | Watch BO",   message="GEX+EFP Matrix — QuantAlgo BEAR delta cluster. Watch g1_dn for BO.")
alertcondition(qa_big_bull  and not qa_big_bull[1],   title="[GEX+EFP Matrix] QA BIG BULL Cluster",         message="GEX+EFP Matrix — QuantAlgo BIG BULL cluster. Top 3% delta percentile.")
alertcondition(qa_big_bear  and not qa_big_bear[1],   title="[GEX+EFP Matrix] QA BIG BEAR Cluster",         message="GEX+EFP Matrix — QuantAlgo BIG BEAR cluster. Top 3% delta percentile.")
alertcondition(ice_buy_signal  and not ice_buy_signal[1],   title="[GEX+EFP Matrix] ICEBERG BUY at GEX Zone",   message="GEX+EFP Matrix — Iceberg mass order at g1_dn or g2_dn. Bullish.")
alertcondition(ice_sell_signal and not ice_sell_signal[1],  title="[GEX+EFP Matrix] ICEBERG SELL at GEX Zone",  message="GEX+EFP Matrix — Iceberg mass order at g1_up or g2_up. Bearish.")
// [v26-1] Bubble-Context reversal alerts removed to stay within the 64-plot budget
//         (each alertcondition = 1 plot count; file was at 63/64). The §11b engine
//         still computes _bctx_fired / _bctx_is_rev / _bctx_out_bull — re-add these two
//         alerts only if you free 2 plot units elsewhere (e.g. disable 2 unused alerts).
alertcondition(_ml_pos and mlmi_fresh,                title="[GEX+EFP Matrix] MLMI FRESH BULL Cross",       message="GEX+EFP Matrix — MLMI k=987 fresh bullish WMA crossover. Decay window active.")
alertcondition(_ml_neg and mlmi_fresh,                title="[GEX+EFP Matrix] MLMI FRESH BEAR Cross",       message="GEX+EFP Matrix — MLMI k=987 fresh bearish WMA crossover. Decay window active.")
alertcondition(smi_bull_cross and smi_oversold,       title="[GEX+EFP Matrix] SMI BULL Cross from OS",      message="GEX+EFP Matrix — SMI K=10 bullish cross from oversold. BO BUY gate open.")
alertcondition(smi_bear_cross and smi_overbought,     title="[GEX+EFP Matrix] SMI BEAR Cross from OB",      message="GEX+EFP Matrix — SMI K=10 bearish cross from overbought. BO SELL gate open.")
alertcondition(cb_t1_active and not cb_t1_active[1],  title="[GEX+EFP Matrix] COMEX CB TIER-1 BREACH ±3%",  message="GEX+EFP Matrix — COMEX circuit breaker Tier 1 (±3%) breached. Elevated halt risk.")
alertcondition(dxy_bull and not dxy_bull[1],           title="[GEX+EFP Matrix] DXY BULL TURN — Bearish XAU", message="GEX+EFP Matrix — DXY ROC exceeded threshold bearish for Gold. BUY signals penalised.")
alertcondition(sqz_yz_bull, title="[GEX+EFP Matrix] SQUEEZE RELEASE BULL",  message="GEX+EFP Matrix — YZ squeeze released BULL. Close above VWAP anchor. Confirm with cond_G Breakout BUY or QA Big Bull cluster.")
alertcondition(sqz_yz_bear, title="[GEX+EFP Matrix] SQUEEZE RELEASE BEAR",  message="GEX+EFP Matrix — YZ squeeze released BEAR. Close below VWAP anchor. Confirm with cond_H Breakout SELL or QA Big Bear cluster.")

// ═══════════════════════════════════════════════════════════════════════════════
// §19  REGIME MATRIX + Γ-PROXY   [v28]  — DISPLAY-ONLY (one table → 0 plot-budget)
// ─────────────────────────────────────────────────────────────────────────────
// Direction × Volatility → the 6-regime matrix (which setup / how much / or step
// aside). Plus a POSITIVE/NEGATIVE-gamma PROXY: not real dealer gamma (gold spot
// has no options chain) but the vol-behaviour FOOTPRINT gamma leaves —
//   pos-Γ = vol dampening → fade, failed breakouts · neg-Γ = amplifying → follow.
// Five orthogonal votes → signed Γ-score. Touches NO gate / conf_score / entry.
// ═══════════════════════════════════════════════════════════════════════════════
float _rm_base  = ta.ema(close, i_rm_dir_len)
float _rm_slope = _rm_base - _rm_base[i_rm_dir_sl]
int   _rm_dir   = (close > _rm_base and _rm_slope > 0.0) ? 1 : (close < _rm_base and _rm_slope < 0.0) ? -1 : 0
bool  _rm_volat = _yz_ratio > 1.0 or gvz_elevated or gvz_extreme

float _rm_lr1  = math.log(close / math.max(close[1], syminfo.mintick))
float _rm_lrk  = math.log(close / math.max(close[i_rm_vr_k], syminfo.mintick))
float _rm_var1 = ta.variance(_rm_lr1, i_rm_vr_len)
float _rm_vark = ta.variance(_rm_lrk, i_rm_vr_len)
float _rm_vr   = _rm_var1 > 0.0 ? _rm_vark / (i_rm_vr_k * _rm_var1) : 1.0
float _rm_tfm  = math.max(timeframe.in_seconds(timeframe.period) / 60.0, 1.0)
float _rm_byr  = 252.0 * 1440.0 / _rm_tfm
float _rm_rv   = ta.stdev(_rm_lr1, i_rm_rv_len) * math.sqrt(_rm_byr) * 100.0
float _rm_rvgz = _rm_rv - gvz_v
float _rm_ernum= math.abs(close - close[i_rm_er_len])
float _rm_erden= math.sum(math.abs(close - close[1]), i_rm_er_len)
float _rm_er   = _rm_erden > 0.0 ? _rm_ernum / _rm_erden : 0.0
bool  _rm_inframe = close > g1_dn and close < g1_up

int _rm_v_vr = _rm_vr   > 1.1  ? 1 : _rm_vr   < 0.9  ? -1 : 0
int _rm_v_rv = _rm_rvgz > 1.0  ? 1 : _rm_rvgz < -1.0 ? -1 : 0
int _rm_v_yz = _yz_ratio> 1.0  ? 1 : _yz_ratio< i_sqz_ratio ? -1 : 0
int _rm_v_er = _rm_er   > 0.40 ? 1 : _rm_er   < 0.25 ? -1 : 0
int _rm_v_g1 = _rm_inframe ? -1 : 1
int    _rm_gsc = _rm_v_vr + _rm_v_rv + _rm_v_yz + _rm_v_er + _rm_v_g1
string _rm_gst = _rm_gsc >= 2 ? "NEG-Γ" : _rm_gsc <= -2 ? "POS-Γ" : "NEUTRAL"
color  _rm_gcl = _rm_gsc >= 2 ? #EF9800 : _rm_gsc <= -2 ? #26A69A : #9aa4b2

string _rm_act = _rm_dir == 1 and not _rm_volat ? "FOLLOW" : _rm_dir == 1 and _rm_volat ? "FOLLOW" : _rm_dir == -1 and not _rm_volat ? "SHORT-TREND" : _rm_dir == -1 and _rm_volat ? "PRESERVE" : _rm_dir == 0 and not _rm_volat ? "MR-FADE" : "STAND ASIDE"
string _rm_pr  = _rm_dir == 1 and not _rm_volat ? "full size" : _rm_dir == 1 and _rm_volat ? "size ×0.6 · wide" : _rm_dir == -1 and not _rm_volat ? "rare" : _rm_dir == -1 and _rm_volat ? "size ×0.5" : _rm_dir == 0 and not _rm_volat ? "@VA edge" : "no edge"
string _rm_rt  = _rm_act == "MR-FADE" ? "→GexCluster" : _rm_act == "STAND ASIDE" ? "→paper" : _rm_act == "PRESERVE" ? "→caution" : "→DeskTrend"
bool   _rm_fadectx = _rm_act == "MR-FADE"
string _rm_gtag = _rm_fadectx and _rm_gst == "POS-Γ" ? "  Γ✓" : _rm_fadectx and _rm_gst == "NEG-Γ" ? "  Γ⚠trend" : (not _rm_fadectx and _rm_act != "STAND ASIDE") and _rm_gst == "NEG-Γ" ? "  Γ✓" : (not _rm_fadectx and _rm_act != "STAND ASIDE") and _rm_gst == "POS-Γ" ? "  Γ⚠fade-risk" : ""

// [v29] auto-flip the ACTION headline when Γ strongly overrides the direction cell
bool   _rm_toFade = (_rm_act == "FOLLOW" or _rm_act == "SHORT-TREND") and _rm_gsc <= -i_rm_gth
bool   _rm_toFoll = (_rm_act == "MR-FADE") and _rm_gsc >= i_rm_gth
bool   _rm_conf   = _rm_toFade or _rm_toFoll
var int _rm_cdur  = 0
_rm_cdur := _rm_conf ? _rm_cdur + 1 : 0
bool   _rm_flip   = i_rm_autoflip and _rm_conf and _rm_cdur >= i_rm_hyst
string _rm_eact   = _rm_flip and _rm_toFade ? "FADE/RANGE" : _rm_flip and _rm_toFoll ? "FOLLOW/BREAK" : _rm_act
string _rm_epr    = _rm_flip and _rm_toFade ? "fade→POC/VWAP" : _rm_flip and _rm_toFoll ? "follow breakout" : _rm_pr
string _rm_ert    = _rm_flip and _rm_toFade ? "→GexCluster" : _rm_flip and _rm_toFoll ? "→DeskTrend" : _rm_rt
string _rm_enote  = _rm_flip ? "  (Γ override)" : _rm_gtag
color  _rm_eactc  = _rm_flip and _rm_toFade ? #FFD700 : _rm_flip and _rm_toFoll ? #26A69A : _rm_act == "STAND ASIDE" ? #EF9800 : _rm_act == "MR-FADE" ? #FFD700 : _rm_dir == -1 ? #EF5350 : #26A69A

// [v29] ADX / DI (global — ta.* must run every bar)
[_rm_dip, _rm_dim, _rm_adxv] = ta.dmi(i_rm_adx_len, i_rm_adx_sm)

// [v29] deep-Fib swing range + premium/discount zone levels
float _rm_swh = ta.highest(high, i_rm_fib_len)
float _rm_swl = ta.lowest(low,   i_rm_fib_len)
float _rm_swr = math.max(_rm_swh - _rm_swl, syminfo.mintick)
float _rm_eq  = _rm_swl + _rm_swr * 0.5
float _rm_disc_hi = _rm_swh - i_rm_fib_lo * _rm_swr
float _rm_disc_lo = _rm_swh - i_rm_fib_hi * _rm_swr
float _rm_prem_lo = _rm_swl + i_rm_fib_lo * _rm_swr
float _rm_prem_hi = _rm_swl + i_rm_fib_hi * _rm_swr

_rm_pos_r = switch i_rm_pos
    "Top Center"    => position.top_center
    "Top Right"     => position.top_right
    "Middle Left"   => position.middle_left
    "Middle Right"  => position.middle_right
    "Bottom Left"   => position.bottom_left
    "Bottom Center" => position.bottom_center
    "Bottom Right"  => position.bottom_right
    =>                 position.top_left
string _rm_sz_r = switch i_rm_sz
    "Tiny"   => size.tiny
    "Normal" => size.normal
    "Large"  => size.large
    =>          size.small

var table _rm_t = table.new(_rm_pos_r, 4, 13, border_width=1, frame_color=color.new(#2c3440, 0), frame_width=1)
if barstate.islast
    table.clear(_rm_t, 0, 0, 3, 12)
    if i_rm_on
        color _bg  = i_rm_bg
        color _mut = #7f8b99
        bool  _aBQ = _rm_dir == 1  and not _rm_volat
        bool  _aBV = _rm_dir == 1  and _rm_volat
        bool  _aSQ = _rm_dir == 0  and not _rm_volat
        bool  _aSV = _rm_dir == 0  and _rm_volat
        bool  _aRQ = _rm_dir == -1 and not _rm_volat
        bool  _aRV = _rm_dir == -1 and _rm_volat
        table.cell(_rm_t, 0, 0, "REGIME v29", text_color=#8b98a8, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 0, "", bgcolor=_bg)
        table.cell(_rm_t, 2, 0, "", bgcolor=_bg)
        table.cell(_rm_t, 3, 0, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 1, "", bgcolor=_bg)
        table.cell(_rm_t, 1, 1, "BULL", text_color=#26A69A, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 1, "SIDE", text_color=#9aa4b2, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 1, "BEAR", text_color=#EF5350, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 0, 2, "QUIET", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 2, "follow",  text_color=_aBQ ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aBQ ? color.new(#26A69A,45) : _bg)
        table.cell(_rm_t, 2, 2, "MR-fade", text_color=_aSQ ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aSQ ? color.new(#FF9800,45) : _bg)
        table.cell(_rm_t, 3, 2, "short-tr",text_color=_aRQ ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aRQ ? color.new(#EF5350,45) : _bg)
        table.cell(_rm_t, 0, 3, "VOLAT", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 3, "foll ×.6", text_color=_aBV ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aBV ? color.new(#26A69A,35) : _bg)
        table.cell(_rm_t, 2, 3, "ASIDE",    text_color=_aSV ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aSV ? color.new(#FF1744,35) : _bg)
        table.cell(_rm_t, 3, 3, "×0.5",     text_color=_aRV ? color.white : _mut, text_size=_rm_sz_r, bgcolor=_aRV ? color.new(#EF5350,35) : _bg)
        table.cell(_rm_t, 0, 4, "Γ-PROXY", text_color=#8b98a8, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 4, _rm_gst, text_color=_rm_gcl, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 4, (_rm_gsc > 0 ? "+" : "") + str.tostring(_rm_gsc) + "/5", text_color=_rm_gcl, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 4, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 5, "VR" + str.tostring(i_rm_vr_k), text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 5, str.tostring(_rm_vr, "#.##"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 5, _rm_v_vr == 1 ? "▲neg" : _rm_v_vr == -1 ? "▼pos" : "·", text_color=_rm_v_vr == 1 ? #EF9800 : _rm_v_vr == -1 ? #26A69A : _mut, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 5, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 6, "RV−GVZ", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 6, (_rm_rvgz >= 0.0 ? "+" : "") + str.tostring(_rm_rvgz, "#.#"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 6, _rm_v_rv == 1 ? "▲neg" : _rm_v_rv == -1 ? "▼pos" : "·", text_color=_rm_v_rv == 1 ? #EF9800 : _rm_v_rv == -1 ? #26A69A : _mut, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 6, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 7, "YZ f/s", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 7, str.tostring(_yz_ratio, "#.##"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 7, _rm_v_yz == 1 ? "▲neg" : _rm_v_yz == -1 ? "▼pos" : "·", text_color=_rm_v_yz == 1 ? #EF9800 : _rm_v_yz == -1 ? #26A69A : _mut, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 7, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 8, "trend-ER", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 8, str.tostring(_rm_er, "#.##"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 8, _rm_v_er == 1 ? "▲neg" : _rm_v_er == -1 ? "▼pos" : "·", text_color=_rm_v_er == 1 ? #EF9800 : _rm_v_er == -1 ? #26A69A : _mut, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 8, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 9, "vs g1", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 9, _rm_inframe ? "inside" : "outside", text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 2, 9, _rm_v_g1 == 1 ? "▲neg" : "▼pos", text_color=_rm_v_g1 == 1 ? #EF9800 : #26A69A, text_size=_rm_sz_r, bgcolor=_bg)
        table.cell(_rm_t, 3, 9, "", bgcolor=_bg)
        table.cell(_rm_t, 0, 10, "ACTION", text_color=#8b98a8, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 1, 10, _rm_eact + " · " + _rm_epr + " " + _rm_ert + _rm_enote, text_color=_rm_eactc, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
        table.cell(_rm_t, 2, 10, "", bgcolor=_bg)
        table.cell(_rm_t, 3, 10, "", bgcolor=_bg)
        if i_rm_adx
            bool   _rm_diUp  = _rm_dip >= _rm_dim
            string _rm_adxs  = _rm_adxv >= i_rm_adx_str ? "strong" : _rm_adxv < 20.0 ? "weak" : "mid"
            color  _rm_adxc  = _rm_adxv >= i_rm_adx_str ? #FFD700 : _mut
            table.cell(_rm_t, 0, 11, "ADX" + str.tostring(i_rm_adx_len), text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
            table.cell(_rm_t, 1, 11, str.tostring(_rm_adxv, "#"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
            table.cell(_rm_t, 2, 11, _rm_adxs, text_color=_rm_adxc, text_size=_rm_sz_r, bgcolor=_bg)
            table.cell(_rm_t, 3, 11, "", bgcolor=_bg)
            table.cell(_rm_t, 0, 12, "DI ±", text_color=_mut, text_size=_rm_sz_r, bgcolor=_bg, text_halign=text.align_left)
            table.cell(_rm_t, 1, 12, "+" + str.tostring(_rm_dip, "#") + " / −" + str.tostring(_rm_dim, "#"), text_color=#c9d1d9, text_size=_rm_sz_r, bgcolor=_bg)
            table.cell(_rm_t, 2, 12, _rm_diUp ? "up ▲" : "dn ▼", text_color=_rm_diUp ? #26A69A : #EF5350, text_size=_rm_sz_r, bgcolor=_bg)
            table.cell(_rm_t, 3, 12, "", bgcolor=_bg)

// ═══════════════════════════════════════════════════════════════════════════════
// §19c  DEEP-FIB PREMIUM / DISCOUNT   [v29]  — box/line/label only → 0 plot-budget
// ─────────────────────────────────────────────────────────────────────────────
// Splits a swing range into PREMIUM (upper — sell) / DISCOUNT (lower — buy) with the
// deep 0.705–0.886 zones (Kmer "trade from discount, not premium"). Isolated block,
// own toggle, own handles — touches no existing logic.
// ═══════════════════════════════════════════════════════════════════════════════
var box   _rm_disc_bx = na
var box   _rm_prem_bx = na
var line  _rm_eq_ln   = na
var label _rm_disc_lb = na
var label _rm_prem_lb = na
if barstate.islast
    box.delete(_rm_disc_bx)
    box.delete(_rm_prem_bx)
    line.delete(_rm_eq_ln)
    label.delete(_rm_disc_lb)
    label.delete(_rm_prem_lb)
    if i_rm_fib
        int _fx0 = bar_index - math.min(i_rm_fib_len, 300)
        int _fx1 = bar_index + 8
        _rm_disc_bx := box.new(_fx0, _rm_disc_hi, _fx1, _rm_disc_lo, border_color=color.new(i_rm_fib_disc, 45), border_style=line.style_dotted, border_width=1, bgcolor=color.new(i_rm_fib_disc, 88))
        _rm_prem_bx := box.new(_fx0, _rm_prem_hi, _fx1, _rm_prem_lo, border_color=color.new(i_rm_fib_prem, 45), border_style=line.style_dotted, border_width=1, bgcolor=color.new(i_rm_fib_prem, 88))
        _rm_eq_ln   := line.new(_fx0, _rm_eq, _fx1, _rm_eq, color=color.new(#9aa4b2, 30), style=line.style_dashed, width=1)
        _rm_disc_lb := label.new(_fx1, (_rm_disc_hi + _rm_disc_lo) / 2.0, "DISCOUNT buy " + str.tostring(i_rm_fib_lo, "#.###") + "-" + str.tostring(i_rm_fib_hi, "#.###"), style=label.style_label_left, color=color.new(i_rm_fib_disc, 80), textcolor=i_rm_fib_disc, size=size.tiny)
        _rm_prem_lb := label.new(_fx1, (_rm_prem_hi + _rm_prem_lo) / 2.0, "PREMIUM sell", style=label.style_label_left, color=color.new(i_rm_fib_prem, 80), textcolor=i_rm_fib_prem, size=size.tiny)

// == END Gex and EFP Basis Matrix v29 | +§19 auto-flip + ADX/DI + deep-Fib | CE:0 RE:0 ==