//@version=6 // ============================================================================ // GOLD SESSION FRAMEWORK v11 (XAUUSD) // v1 AVR · v2/v3 Chandelier + VP · v4 chandelier-out-of-security · v5 buffer // fix · v6 tuned defaults + VARS + CVD · v7 Anchored VWAP. // v8 = NEW module: P/B/D ZONE DETECTOR — formalizes Patrick Nill's discretionary // range/breakout model. Auto-detects consolidation ranges (Efficiency-Ratio // box/path filter), VALIDATES by ≥3 touches, freezes the box on breakout, // classifies SMALL→breakout / BIG→range (height ÷ ATR), and flags ALIGNED // (confluent) zones. Developing zone shown live. // v9 = NEW: CVD CONFLUENCE with a higher timeframe (default M10). When a ±RD // fires on the chart TF and the SAME-direction ±RD exists on the HTF inside // a tolerance window, the label is upgraded to ±CRD. rev2: the two frames are // matched by PIVOT TIME (they confirm at different lags: M3 +6 min, M10 +20 min), // so the match is judged by WHERE the divergence happened, not when it arrived. // HTF is read from CLOSED // bars only (non-repainting). Every CVD parameter is shared with §3f — only // the timeframe differs. Toggle + tolerance + late-upgrade in the inputs. // v10 = (a) DELTA SOURCE for CVD ±RD and ±CRD: candle CLV (full history) or LTF tick rule // (lower-TF close vs previous close × volume) with CLV fallback. // ⚑ rev2: bid/ask tick mode REMOVED — tick (1T) requests need an Expert+ TradingView plan // (runtime error RE10065 on Premium). Seconds LTF (e.g. 1S) may work on Premium. // ⚑ rev3: default delta source = TradingView FOOTPRINT (request.footprint, Premium feature: // buy/sell volume classified by TradingView per trade) → falls back to 1-min tick rule // → candle CLV. Delta profile uses footprint rows (delta per price row) directly. // ⚑ rev4: only ONE request.footprint() call is allowed per script (RE10047) → footprint // feeds the chart TF (RD + delta profile); the confluence TF (CRD) uses the 1-min tick rule. // (b) DELTA PROFILE: net delta per price row since the session anchor + ±DPOC lines. // (c) defaults = the user's live H1 settings (TFH1 build) (read from the chart 16 Sep 2026). // Credit: delta classification and the delta-per-price profile idea are adapted from // "Footprint IQ Pro [TradingIQ]" and "CVD Profiles [TradingIQ]" (© Trading-IQ, // TradingView open-source). Logic re-written for this framework; please keep this credit. // v11 (17 Sep 2026, level-1 fixes): tick rule carries the last sign on unchanged-close minutes (their volume was // dropped) · ±RD EMA gate compares the PIVOT bar's close with the EMA of that bar (was the current EMA) · // Chandelier sets whose TF is FASTER than the chart are disabled (request.security of a lower TF returns // only the last intrabar) · VARS alerts honour the master toggle · debug text uses the chart TF · // defaults = user's live H1 settings (TFH1 build) (read off the chart 17 Sep 2026). // VISUAL-only — location + confirmation map, NO trade engine. Walk-forward first. // ============================================================================ indicator("Gold Session Framework v11 TFH1", overlay=true, max_lines_count=500, max_boxes_count=500, max_labels_count=500, max_polylines_count=100, max_bars_back=2000) // =========================================================================== // 1. SESSION // =========================================================================== gS = "Session" asia_session = input.session("1400-2300", "Asia Session (Exchange Time)", group=gS) i_tzsel = input.string("Exchange", "Session Timezone", options=["Exchange","America/New_York","UTC","Asia/Tokyo","Asia/Bangkok","Asia/Shanghai"], group=gS, tooltip="Clip anchors ~18:00 ET. 'Exchange' = the chart symbol's own timezone.") i_minbars = input.int(3, "Min Asia bars to validate", minval=1, group=gS) tz = i_tzsel == "Exchange" ? syminfo.timezone : i_tzsel // =========================================================================== // 2. RANGE BASIS + AVR MULTIPLIERS // =========================================================================== gA = "Range Basis" atr_length = input.int(20, "Daily ATR Length", minval=1, group=gA) use_adr = input.bool(false, "Use ADR (High-Low) instead of ATR", group=gA) gU = "Upward Multipliers (x range)" up_lvl1 = input.float(0.326, "Level 1 Up", step=0.001, group=gU) up_avrm = input.float(0.600, "AVR- Up", step=0.001, group=gU) up_avr = input.float(0.850, "AVR Up", step=0.001, group=gU) up_avrp = input.float(1.100, "AVR+ Up", step=0.001, group=gU) up_max = input.float(1.350, "Max Up", step=0.001, group=gU) gD = "Downward Multipliers (x range)" dn_lvl1 = input.float(0.326, "Level 1 Down", step=0.001, group=gD) dn_avrm = input.float(0.600, "AVR- Down", step=0.001, group=gD) dn_avr = input.float(0.850, "AVR Down", step=0.001, group=gD) dn_avrp = input.float(1.100, "AVR+ Down", step=0.001, group=gD) dn_max = input.float(1.350, "Max Down", step=0.001, group=gD) // =========================================================================== // 3. DISPLAY TOGGLES (AVR) // =========================================================================== gV = "Display — AVR" show_asia = input.bool(true, "Asia box (H/L/EQ)", group=gV) show_quarts = input.bool(true, "Quarters Q1/Q3 (25/75%)", group=gV) show_l1 = input.bool(true, "Level 1 zone + red OTE", group=gV) show_consol = input.bool(true, "Consolidation band (AVR-)", group=gV) show_up = input.bool(true, "Up projections", group=gV) show_dn = input.bool(true, "Down projections", group=gV) show_labels = input.bool(true, "Right-edge labels", group=gV) show_table = input.bool(true, "Info table", group=gV) show_warn = input.bool(true, "Discretion warning label", group=gV) ote_lo = input.float(0.50, "OTE inner from", step=0.01, minval=0, maxval=1, group=gV) ote_hi = input.float(0.79, "OTE inner to", step=0.01, minval=0, maxval=1, group=gV) ext_bars = input.int(6, "Extend right (bars)", minval=0, group=gV) // =========================================================================== // 3b. STYLE — AVR lines & boxes // =========================================================================== gST = "Style — AVR Lines" c_asia = input.color(color.white, "Asia H/L", group=gST, inline="s_asia") w_asia = input.int(2, "w", minval=1, maxval=4, group=gST, inline="s_asia") c_eq = input.color(color.white, "EQ", group=gST, inline="s_eq") w_eq = input.int(2, "w", minval=1, maxval=4, group=gST, inline="s_eq") c_q = input.color(color.new(color.gray,60), "Quarters",group=gST, inline="s_q") w_q = input.int(1, "w", minval=1, maxval=4, group=gST, inline="s_q") c_am = input.color(color.rgb(200,255,0), "AVR-", group=gST, inline="s_am") w_am = input.int(1, "w", minval=1, maxval=4, group=gST, inline="s_am") c_a = input.color(color.rgb(200,255,0), "AVR", group=gST, inline="s_a") w_a = input.int(1, "w", minval=1, maxval=4, group=gST, inline="s_a") c_ap = input.color(color.rgb(200,255,0), "AVR+", group=gST, inline="s_ap") w_ap = input.int(1, "w", minval=1, maxval=4, group=gST, inline="s_ap") c_mx = input.color(color.rgb(200,255,0), "Max", group=gST, inline="s_mx") w_mx = input.int(1, "w", minval=1, maxval=4, group=gST, inline="s_mx") sty_line = input.string("Solid", "Level line style", options=["Solid","Dashed","Dotted"], group=gST) sty_band = input.string("Dashed", "EQ / Quarter style", options=["Solid","Dashed","Dotted"], group=gST) gSB = "Style — AVR Zone fills" c_l1 = input.color(color.new(color.gray,88), "Level-1 box fill", group=gSB, inline="s_l1") cb_l1 = input.color(color.new(color.gray,70), "border", group=gSB, inline="s_l1") c_ote = input.color(color.rgb(166,58,30,58), "OTE box fill", group=gSB, inline="s_ote") cb_ote = input.color(color.new(color.rgb(166,58,30),10), "border", group=gSB, inline="s_ote") c_con = input.color(color.new(color.rgb(41,128,185),92), "Consol fill", group=gSB, inline="s_con") cb_con = input.color(color.new(color.rgb(41,128,185),90), "border", group=gSB, inline="s_con") bw_box = input.int(1, "Box border width", minval=1, maxval=4, group=gSB) // =========================================================================== // 3c. CHANDELIER (multi-TF) — 3 selectable-TF instances (USER-TUNED values) // =========================================================================== gCH = "Chandelier — Shared" ch_useclose = input.bool(true, "Use close for extremum", group=gCH) ch_hlen = input.int(50, "Hurst lookback (Enhanced)", minval=10, group=gCH) ch_trth = input.float(0.60, "Hurst TREND >", step=0.05, group=gCH) ch_mrth = input.float(0.40, "Hurst MR <", step=0.05, group=gCH) g1 = "Chandelier 1" ch1_on = input.bool(false, "Enable", group=g1, inline="a") ch1_tf = input.timeframe("3", "TF", group=g1, inline="a") ch1_len = input.int(20, "len", minval=2, group=g1, inline="b") ch1_eng = input.string("Enhanced", "Engine", options=["Enhanced","Simple ATR"], group=g1, inline="b") ch1_mtr = input.float(5.618, "mTREND", step=0.1, group=g1, inline="c") ch1_mmr = input.float(3.236, "mMR", step=0.1, group=g1, inline="c") ch1_mb = input.float(6.1278, "mult base / Simple", step=0.1, group=g1) ch1_sty = input.string("Line", "Type", options=["Line","Stepline","Circles"], group=g1, inline="d") ch1_w = input.int(1, "w", minval=1, maxval=4, group=g1, inline="d") ch1_cu = input.color(color.white, "Up", group=g1, inline="e") ch1_cd = input.color(color.rgb(0,224,192), "Dn", group=g1, inline="e") ch1_sh = input.bool(false, "Flip markers", group=g1) g2 = "Chandelier 2" ch2_on = input.bool(true, "Enable", group=g2, inline="a") ch2_tf = input.timeframe("60", "TF", group=g2, inline="a") ch2_len = input.int(14, "len", minval=2, group=g2, inline="b") ch2_eng = input.string("Enhanced", "Engine", options=["Enhanced","Simple ATR"], group=g2, inline="b") ch2_mtr = input.float(5.618, "mTREND", step=0.1, group=g2, inline="c") ch2_mmr = input.float(3.236, "mMR", step=0.1, group=g2, inline="c") ch2_mb = input.float(5.0, "mult base / Simple", step=0.1, group=g2) ch2_sty = input.string("Line", "Type", options=["Line","Stepline","Circles"], group=g2, inline="d") ch2_w = input.int(1, "w", minval=1, maxval=4, group=g2, inline="d") ch2_cu = input.color(color.rgb(89,255,0), "Up", group=g2, inline="e") ch2_cd = input.color(color.rgb(255,77,0), "Dn", group=g2, inline="e") ch2_sh = input.bool(false, "Flip markers", group=g2) g3 = "Chandelier 3" ch3_on = input.bool(true, "Enable", group=g3, inline="a") ch3_tf = input.timeframe("240", "TF", group=g3, inline="a") ch3_len = input.int(14, "len", minval=2, group=g3, inline="b") ch3_eng = input.string("Enhanced", "Engine", options=["Enhanced","Simple ATR"], group=g3, inline="b") ch3_mtr = input.float(5.618, "mTREND", step=0.1, group=g3, inline="c") ch3_mmr = input.float(3.236, "mMR", step=0.1, group=g3, inline="c") ch3_mb = input.float(5.618, "mult base / Simple", step=0.1, group=g3) ch3_sty = input.string("Line", "Type", options=["Line","Stepline","Circles"], group=g3, inline="d") ch3_w = input.int(1, "w", minval=1, maxval=4, group=g3, inline="d") ch3_cu = input.color(color.rgb(89,255,0), "Up", group=g3, inline="e") ch3_cd = input.color(color.rgb(255,77,0), "Dn", group=g3, inline="e") ch3_sh = input.bool(false, "Flip markers", group=g3) // =========================================================================== // 3d. VOLUME PROFILE (single, chart-TF, KV-MACD ㉕ principle) // =========================================================================== gVP = "Volume Profile" vp_on = input.bool(true, "Enable Volume Profile", group=gVP) vp_mode = input.string("Composite", "Mode", options=["Session", "Rolling", "Composite"], group=gVP, tooltip="Session=current day (D bar). Rolling=last N bars. Composite=last N days.") vp_roll = input.int(610, "Rolling window (bars)", minval=10, maxval=1990, group=gVP) vp_days = input.int(4, "Composite sessions (days)", minval=1, group=gVP) vp_maxbars = input.int(987, "Max bars profiled (cap)", minval=10, maxval=1990, group=gVP) vp_bins = input.int(60, "Bins (rows)", minval=5, maxval=200, group=gVP) vp_va = input.float(84, "Value area %", minval=1, maxval=100, group=gVP) vp_maxwidth = input.int(60, "Profile width (bars)", minval=5, group=gVP) vp_offset = input.int(5, "Profile offset (bars right)", minval=0, group=gVP) vp_showhist = input.bool(true, "Show histogram", group=gVP) vp_shownodes= input.bool(false, "Show HVN / LVN nodes", group=gVP) vp_hvn = input.float(1.3, "HVN ≥ ×avg-bin", step=0.1, group=gVP) vp_lvn = input.float(0.5, "LVN ≤ ×avg-bin", step=0.1, group=gVP) vp_maxnodes = input.int(6, "Max nodes / side", minval=1, maxval=20, group=gVP) gVP2 = "Volume Profile — Style" vp_fill = input.color(color.new(color.gray,90), "Histogram fill", group=gVP2) vp_vafill = input.color(color.new(color.rgb(140,90,20),45), "Value-area fill", group=gVP2) vp_cpoc = input.color(color.rgb(255,0,255), "POC", group=gVP2, inline="p") vp_wpoc = input.int(1, "w", minval=1, maxval=4, group=gVP2, inline="p") vp_spoc = input.string("Dotted", "", options=["Solid","Dashed","Dotted"], group=gVP2, inline="p") vp_cva = input.color(color.rgb(0,224,192), "VAH/VAL", group=gVP2, inline="v") vp_wva = input.int(2, "w", minval=1, maxval=4, group=gVP2, inline="v") vp_sva = input.string("Solid", "", options=["Solid","Dashed","Dotted"], group=gVP2, inline="v") vp_chvn = input.color(color.new(color.green,0), "HVN", group=gVP2, inline="n") vp_clvn = input.color(color.new(color.red,0), "LVN", group=gVP2, inline="n") vp_wnode= input.int(1, "w", minval=1, maxval=4, group=gVP2, inline="n") // =========================================================================== // 3e. VALUE-AREA REVERSION SIGNALS (VARS) — ported from LuxAlgo (Fabio strat) // Session-anchored VA (own per-bar profile). Signal = break VAL/VAH → // volume slowing (absorption) → engulfing candle closes back inside VA // within N bars, with growing dominant volume. VISUAL/location only. // =========================================================================== gVR = "Value-Area Reversion (VARS)" vars_on = input.bool(true, "Enable VARS reclaim signals", group=gVR) vars_prev = input.bool(true, " • signals on PREVIOUS session VA", group=gVR) vars_curr = input.bool(true, " • signals on CURRENT session VA", group=gVR) vars_showprevva = input.bool(false, "Show previous-session VA lines", group=gVR) vars_colorcandles = input.bool(true, "Color candles on reclaim (barcolor)", group=gVR) vars_anchorHour = input.int(18, "Session anchor hour (America/New_York)", minval=0, maxval=23, group=gVR, tooltip="Fabio anchors at 18:00 ET (futures open). VARS uses its OWN session profile independent of the display VP above.") vars_maxbars = input.int(10, "Max bars to signal after breakout", minval=1, maxval=100, group=gVR) vars_rows = input.int(60, "VARS profile rows", minval=10, maxval=150, group=gVR) vars_va = input.float(70.0, "VARS value area %", minval=50.0, maxval=99.0, step=0.5, group=gVR, tooltip="Fabio/LuxAlgo default 70 (separate from the display-VP value area).") vars_cbull = input.color(color.rgb(89,255,0), "Bullish reclaim", group=gVR, inline="vc") vars_cbear = input.color(color.rgb(255,77,0), "Bearish reclaim", group=gVR, inline="vc") // =========================================================================== // 3f. CVD DIVERGENCE — ported from TradingFinder CVD Divergence [Periodic/EMA] // CVD = CLV×vol proxy. Regular divergence via fractal pivots + EMA50 gate. // Draws divergence lines + ±RD labels on price (bounded pool). VISUAL-only. // =========================================================================== gCV = "CVD Divergence" cvd_on = input.bool(true, "Enable CVD divergence", group=gCV) cvd_mode = input.string("Periodic", "Cumulative mode", options=["Periodic","EMA"], group=gCV) cvd_period = input.int(20, "CVD period", minval=1, group=gCV) cvd_n = input.int(2, "Fractal periods (pivot L/R)", minval=1, maxval=20, group=gCV) cvd_maxlen = input.int(30, "Max bars between pivots", minval=2, maxval=200, group=gCV) cvd_showlabels = input.bool(true, "Show ±RD labels", group=gCV) cvd_maxdraw = input.int(50, "Max divergences drawn (pool)", minval=5, maxval=200, group=gCV) cvd_cbull = input.color(color.rgb(21,151,25), "Bullish +RD", group=gCV, inline="cc") cvd_cbear = input.color(color.rgb(212,44,44), "Bearish -RD", group=gCV, inline="cc") // =========================================================================== // 3f-2. CVD CONFLUENCE (v9) — same ±RD on a higher TF (default M10) → ±CRD // Uses the SAME CVD settings as §3f (mode / period / fractal / max bars / // EMA50 gate); only the timeframe differs. The HTF value comes from the last // CLOSED HTF bar → no repaint, at most one HTF bar of extra lag. // =========================================================================== gCC = "CVD Confluence (v9)" cvdC_on = input.bool(true, "Enable ±CRD confluence", group=gCC) cvdC_tf = input.timeframe("1D", "Confluence timeframe", group=gCC, tooltip="ค่าคำนวณ CVD ทุกตัวใช้ชุดเดียวกับกลุ่ม CVD Divergence ด้านบน เปลี่ยนแค่กรอบเวลา") cvdC_tolmin = input.int(240, "Pivot time tolerance (minutes)", minval=0, maxval=600, group=gCC, tooltip="จุดกลับตัวของ ±RD สองกรอบเวลาต้องห่างกันไม่เกินกี่นาที จึงนับเป็นเหตุการณ์เดียวกัน · M10 ควรอย่างน้อย 20 นาที (1–2 แท่ง M10)") cvdC_arrive = input.int(12, "Late-confirm window (chart bars)", minval=1, maxval=300, group=gCC, tooltip="ยอมรอสัญญาณกรอบใหญ่ได้กี่แท่งชาร์ต หลังจาก ±RD ของชาร์ตวาดไปแล้ว · M10 ยืนยันช้ากว่า M3 ได้ถึง 30 นาที = 10 แท่ง M3 · ตั้ง 30 แท่ง = เผื่อ 90 นาที") cvdC_dbg = input.bool(true, "Show CRD debug table (why it did / did not match)", group=gCC) cvdC_conf = input.bool(true, "Closed HTF bars only (no repaint)", group=gCC) cvdC_up = input.bool(true, "Upgrade an existing ±RD label when the HTF confirms later", group=gCC, tooltip="กรอบใหญ่ยืนยันช้ากว่า (M10 ช้ากว่า M3 ประมาณ 20 นาที) ถ้าปิดตัวเลือกนี้ CRD จะเกิดน้อยมาก") cvdC_cbull = input.color(color.rgb(0,230,60), "+CRD", group=gCC, inline="cc2") cvdC_cbear = input.color(color.rgb(255,82,82), "-CRD", group=gCC, inline="cc2") cvdC_big = input.bool(true, "Emphasize ±CRD (bigger label, thicker line)", group=gCC) // =========================================================================== // 3f-3. DELTA SOURCE (v10) — how buy/sell volume is decided for CVD ±RD and ±CRD // Classification adapted from Footprint IQ Pro / CVD Profiles [TradingIQ] (© Trading-IQ). // ⚠ Lower-TF history on TradingView is limited → older bars fall back to candle CLV // (toggle below). Coverage is shown in the CRD debug table. // ⚠ Tick data is NOT used: it requires an Expert+ plan (RE10065 on Premium). // =========================================================================== gDS = "Delta Source (v10)" SRC_CLV = "Candle CLV (history)" SRC_TICK = "LTF tick rule" SRC_FP = "Footprint (Premium)" cvd_srcMode = input.string("Candle CLV (history)", "Delta source", options=[SRC_FP, SRC_TICK, SRC_CLV], group=gDS, tooltip="Footprint = ปริมาณซื้อ/ขายที่ TradingView จัดฝั่งจากการเทรดจริง (ฟีเจอร์ Volume footprint ของแพ็กเกจ Premium) · LTF tick rule = ทิศจาก close แท่งย่อยเทียบแท่งย่อยก่อนหน้า × volume · Candle CLV = สูตรเดิม v8/v9") cvd_fpTicks = input.int(100, "Footprint ticks per row", minval=1, group=gDS, tooltip="ความสูงแถวของ footprint เป็นจำนวน tick · OANDA XAUUSD tick = 0.001 → 100 tick = 0.10$ · มีผลกับ Delta Profile (ต้องเล็กกว่าแถวของโปรไฟล์)") cvd_ltfTf = input.timeframe("1", "LTF for tick rule", group=gDS, tooltip="1 นาที = ประวัติยาว ครอบคลุมดี · 1S (วินาที) ละเอียดกว่าแต่ประวัติสั้น และต้องเป็นแพ็กเกจที่รองรับ") cvd_fallback = input.bool(true, "Fall back (footprint → 1-min tick rule → candle CLV) where data is missing", group=gDS) // =========================================================================== // 3f-4. DELTA PROFILE (v10) — net delta per price row since the session anchor // Idea adapted from CVD Profiles [TradingIQ] (© Trading-IQ). Anchor = VARS session anchor. // =========================================================================== gDP = "Delta Profile (v10)" dp_on = input.bool(false, "Enable delta profile", group=gDP) dp_rowAtr = input.float(0.5, "Row height (× ATR14 at session start)", minval=0.05, step=0.05, group=gDP) dp_maxRows = input.int(120, "Max rows drawn (largest |delta| first)", minval=10, maxval=250, group=gDP) dp_width = input.int(40, "Profile width (bars)", minval=5, group=gDP) dp_offset = input.int(70, "Profile offset (bars right)", minval=0, group=gDP, tooltip="VP ใช้ offset 5 + width 60 → ตั้ง 70 เพื่อไม่ทับกัน") dp_showPoc = input.bool(false, "Show +DPOC / −DPOC (largest buy / sell delta rows)", group=gDP) dp_cPos = input.color(color.new(color.rgb(0,230,118),45), "Buy delta", group=gDP, inline="dpc") dp_cNeg = input.color(color.new(color.rgb(255,82,82),45), "Sell delta", group=gDP, inline="dpc") // =========================================================================== // 3g. ANCHORED VWAP (AVWAP) — Grateful-Futures technique (developing polylines) // Session (day open) + optional prev-day + AUTO swing-pivot anchors. // Reads trend control / dynamic S/R to pair with GEX levels. VISUAL-only. // =========================================================================== gAV = "Anchored VWAP (AVWAP)" avw_on = input.bool(true, "Enable Anchored VWAP", group=gAV) avw_src = input.source(hlc3, "Price source", group=gAV) avw_sess = input.bool(true, "Session AVWAP (from day open)", group=gAV) avw_prev = input.bool(false, "Previous-day AVWAP", group=gAV) avw_swh = input.bool(false, "Swing-High AVWAP (sell-trend anchor)", group=gAV) avw_swl = input.bool(false, "Swing-Low AVWAP (buy-trend anchor)", group=gAV) avw_piv = input.int(20, "Swing pivot length (L/R)", minval=2, maxval=100, group=gAV, tooltip="Bigger = only more significant swings re-anchor the swing AVWAPs.") avw_lbl = input.bool(true, "Curve labels", group=gAV) avw_w = input.int(2, "Curve width", minval=1, maxval=4, group=gAV) avw_c_sess = input.color(color.rgb(255,255,255), "Session", group=gAV, inline="ac") avw_c_prev = input.color(color.new(color.gray,30),"Prev-day", group=gAV, inline="ac") avw_c_swh = input.color(color.red, "Swing-High",group=gAV, inline="ac2") avw_c_swl = input.color(color.green, "Swing-Low", group=gAV, inline="ac2") // =========================================================================== // 3h. P/B/D ZONE DETECTOR — Patrick Nill range/breakout model (visual) // Range = low-efficiency (choppy) window; VALID after ≥3 touches; freeze on // breakout; SMALL(→breakout) vs BIG(→range) by height/ATR; flag ALIGNED zones. // =========================================================================== gPD = "P/B/D Zones (Patrick model)" pd_on = input.bool(true, "Enable P/B/D zone detector", group=gPD) pd_win = input.int(24, "Range window (bars)", minval=5, maxval=200, group=gPD) pd_atrlen = input.int(14, "ATR length", minval=1, group=gPD) pd_er = input.float(0.4, "Range if box/path ratio <", step=0.05, minval=0.1, maxval=0.9, group=gPD, tooltip="Efficiency ratio = window height ÷ Σ true-range. Low = choppy/range, high = trending. Lower value = stricter (only very choppy windows qualify).") pd_tol = input.float(0.25, "Touch tolerance (×ATR)", step=0.05, minval=0.0, group=gPD) pd_brk = input.float(0.5, "Breakout beyond edge (×ATR)", step=0.05, minval=0.0, group=gPD) pd_mintou = input.int(3, "Min touches to validate", minval=2, maxval=12, group=gPD) pd_maxage = input.int(89, "Max range age (bars)", minval=20, maxval=1000, group=gPD) pd_smallK = input.float(3.0, "SMALL zone height ≤ ×ATR (→breakout)", step=0.1, group=gPD) pd_bigK = input.float(6.0, "BIG zone height ≥ ×ATR (→range)", step=0.1, group=gPD) pd_align = input.bool(true, "Flag aligned/confluent zones", group=gPD) pd_atol = input.float(0.5, "Alignment tolerance (×ATR)", step=0.1, group=gPD) pd_maxz = input.int(12, "Max zones drawn (pool)", minval=2, maxval=40, group=gPD) pd_showdev= input.bool(true, "Show developing (forming) zone", group=gPD) pd_c_sm = input.color(color.new(color.aqua,80), "Small(BO) fill", group=gPD, inline="pc") pd_c_bg = input.color(color.new(color.orange,80), "Big(range) fill", group=gPD, inline="pc") pd_c_al = input.color(color.rgb(224, 64, 251, 85), "Aligned fill", group=gPD, inline="pc2") pd_c_bd = input.color(color.new(color.gray,40), "Border", group=gPD, inline="pc2") // =========================================================================== // 4. HELPER FUNCTIONS // =========================================================================== f_linestyle(s) => s == "Dashed" ? line.style_dashed : s == "Dotted" ? line.style_dotted : line.style_solid // Yang-Zhang per-bar return sigma (KV-MACD price-σ vol unit) f_yzsigma(n) => float k = 0.34 / (1.34 + (n + 1.0) / (n - 1.0)) float lo_ = math.log(open / nz(close[1], open)) float lc_ = math.log(close / open) float rs_ = math.log(high / close) * math.log(high / open) + math.log(low / close) * math.log(low / open) float vo = ta.variance(lo_, n) float vc = ta.variance(lc_, n) float vr = ta.sma(rs_, n) math.sqrt(math.max(vo + k * vc + vr, 0.0)) // Rescaled-range Hurst estimate over n bars f_hurst(n) => float mean = 0.0 for i = 0 to n - 1 mean += nz(math.log(close[i] / close[i + 1])) mean := mean / n float cum = 0.0 float mx = -1e20 float mn = 1e20 float ss = 0.0 for i = 0 to n - 1 float dev = nz(math.log(close[i] / close[i + 1])) - mean cum += dev mx := math.max(mx, cum) mn := math.min(mn, cum) ss += dev * dev float R = mx - mn float S = math.sqrt(ss / n) float rs = S > 0 ? R / S : na (na(rs) or rs <= 0) ? 0.5 : math.log(rs) / math.log(n) // STATELESS chandelier ingredients — safe to run inside request.security // (no var, no self-history). Returns [highest, lowest, band(=vol×mult)]. f_chanIng(len, useClose, enhanced, hlen, mTr, mMr, mB, trTh, mrTh) => float atrv = ta.atr(len) float volu = atrv if enhanced float sig = f_yzsigma(len) float vpx = close * sig volu := (na(vpx) or vpx <= 0) ? atrv : vpx float mult = mB if enhanced float h = f_hurst(hlen) mult := h > trTh ? mTr : (h < mrTh ? mMr : mB) float band = volu * mult float hh = useClose ? ta.highest(close, len) : ta.highest(high, len) float ll = useClose ? ta.lowest(close, len) : ta.lowest(low, len) [hh, ll, band] // STATEFUL everget recursion — runs at GLOBAL scope (var on chart timeline). // Each of the 3 call-sites gets its own persistent state. Returns [stop, dir]. f_trail(hh, ll, band) => var float ls = na var float ss = na var int dir = 1 float lb = hh - band float sb = ll + band ls := na(ls[1]) ? lb : (close[1] > ls[1] ? math.max(lb, ls[1]) : lb) ss := na(ss[1]) ? sb : (close[1] < ss[1] ? math.min(sb, ss[1]) : sb) dir := (dir == -1 and close > ss[1]) ? 1 : (dir == 1 and close < ls[1]) ? -1 : dir float st = dir > 0 ? ls : ss [st, dir] // v10 — sign of one lower-TF sample (adapted from Footprint IQ Pro [TradingIQ], © Trading-IQ) f_tickSign(float c, float b, float a, float p) => (not na(b) and c <= b) ? -1.0 : (not na(a) and c >= a) ? 1.0 : (not na(p) and c > p) ? 1.0 : (not na(p) and c < p) ? -1.0 : 0.0 // v11 — standard tick rule: an unchanged close inherits the previous sign (v10 returned 0 and dropped that minute's volume) f_tickCarry(float c, float p, float prev) => (not na(p) and c > p) ? 1.0 : (not na(p) and c < p) ? -1.0 : prev // v10 rev4 — net delta of the current HTF bar · returns [delta, code] code 1 = tick rule · 0 = none // TradingView allows only ONE request.footprint() call per script (runtime error RE10047). // That call is used by the chart TF (§13c-3). The confluence TF therefore uses the 1-min // tick rule when the source is Footprint (fpTicks kept in the signature, unused). f_ltfDelta(string srcMode, simple string ltf, simple int fpTicks, bool fallback) => float acc = na int code = 0 if srcMode == "LTF tick rule" or srcMode == "Footprint (Premium)" [lV, lC, lP] = request.security_lower_tf(syminfo.tickerid, ltf, [volume, close, close[1]], ignore_invalid_timeframe = true) int ns = array.size(lV) if code == 0 and ns > 0 acc := 0.0 float sg_ = 0.0 for i = 0 to ns - 1 sg_ := f_tickCarry(array.get(lC, i), array.get(lP, i), sg_) acc += nz(array.get(lV, i)) * sg_ code := 1 [acc, code] // CVD ±RD for ANY timeframe (v9) — identical formula to §13c, callable from // request.security so the confluence TF uses exactly the same settings. f_cvdDiv(string mode, simple int per, simple int n, simple int maxlen, string srcMode, simple string ltf, bool fallback, simple int fpTicks) => float rng_ = high - low float clv_ = rng_ > 0 ? ((close - low) - (high - close)) / rng_ : 0.0 [ld_, lc_] = f_ltfDelta(srcMode, ltf, fpTicks, fallback) float dbar_ = lc_ > 0 ? ld_ : (srcMode == "Candle CLV (history)" or fallback ? nz(volume, 0.0) * clv_ : 0.0) float hist_ = mode == "Periodic" ? math.sum(dbar_, per) : ta.ema(dbar_, per) float e50_ = ta.ema(close, 50) bool upF_ = not na(ta.pivothigh(n, n)) and close[n] > e50_[n] // v11: EMA of the pivot bar bool dnF_ = not na(ta.pivotlow(n, n)) and close[n] < e50_[n] float hiLastP_ = ta.valuewhen(upF_, high[n], 0) float hiPerP_ = ta.valuewhen(upF_, high[n], 1) float hiLastH_ = ta.valuewhen(upF_, hist_[n], 0) float hiPerH_ = ta.valuewhen(upF_, hist_[n], 1) int hiLastB_ = int(ta.valuewhen(upF_, bar_index[n], 0)) int hiPerB_ = int(ta.valuewhen(upF_, bar_index[n], 1)) bool bear_ = upF_ and hiLastH_ > 0 and hiPerH_ > 0 and (hiLastB_ - hiPerB_) < maxlen and hiLastP_ > hiPerP_ and hiLastH_ < hiPerH_ float loLastP_ = ta.valuewhen(dnF_, low[n], 0) float loPerP_ = ta.valuewhen(dnF_, low[n], 1) float loLastH_ = ta.valuewhen(dnF_, hist_[n], 0) float loPerH_ = ta.valuewhen(dnF_, hist_[n], 1) int loLastB_ = int(ta.valuewhen(dnF_, bar_index[n], 0)) int loPerB_ = int(ta.valuewhen(dnF_, bar_index[n], 1)) bool bull_ = dnF_ and loLastH_ < 0 and loPerH_ < 0 and (loLastB_ - loPerB_) < maxlen and loLastP_ < loPerP_ and loLastH_ > loPerH_ // เวลาของแท่งจุดกลับตัวที่ใช้ยืนยัน divergence (ใช้จับคู่ข้ามกรอบเวลา) float bullT_ = ta.valuewhen(dnF_, time[n], 0) float bearT_ = ta.valuewhen(upF_, time[n], 0) // คืนค่าเป็น 1.0/0.0 เพื่อให้ nz() ใช้ได้ (bool ที่เป็น na ข้าม TF มีพฤติกรรมไม่แน่นอน) [bull_ ? 1.0 : 0.0, bear_ ? 1.0 : 0.0, bullT_, bearT_] // --- VARS profile helpers (array-based → no historical-buffer issue) --- va_reset(arr, rows) => array.clear(arr) for i = 0 to rows - 1 array.push(arr, 0.0) va_add(bins, bLow, bHigh, bVol, rLow, bSize, rows) => int bc = array.size(bins) if bVol > 0 and bSize > 0 and bc > 0 int fi = math.max(0, math.min(bc - 1, int(math.floor((bLow - rLow) / bSize)))) int li = math.max(0, math.min(bc - 1, int(math.floor((bHigh - rLow) / bSize)))) if fi <= li float vpb = bVol / (li - fi + 1) for k = fi to li array.set(bins, k, array.get(bins, k) + vpb) va_levels(bins, rLow, bSize, vaPct) => int bc = array.size(bins) float tot = 0.0 float mx = 0.0 int poc = 0 if bc > 0 for k = 0 to bc - 1 float bv = array.get(bins, k) tot += bv if bv > mx mx := bv poc := k float tgt = tot * vaPct / 100.0 float acc = mx int loI = poc int hiI = poc if tot > 0 for e = 1 to bc if acc >= tgt break int li = poc - e int ui = poc + e bool cl = li >= 0 and li < bc bool cu = ui >= 0 and ui < bc float lv = cl ? array.get(bins, li) : 0.0 float uv = cu ? array.get(bins, ui) : 0.0 if cl and (not cu or lv >= uv) acc += lv loI := li else if cu acc += uv hiI := ui float val = (tot > 0 and not na(bSize)) ? rLow + loI * bSize : na float vah = (tot > 0 and not na(bSize)) ? rLow + (hiI + 1) * bSize : na [vah, val] // =========================================================================== // 5. DAILY RANGE (non-repaint: previous COMPLETED daily bar) // =========================================================================== _atrD = request.security(syminfo.tickerid, "D", ta.atr(atr_length)[1], lookahead=barmerge.lookahead_on) _adrD = request.security(syminfo.tickerid, "D", ta.sma(high - low, atr_length)[1], lookahead=barmerge.lookahead_on) dRange = use_adr ? _adrD : _atrD // =========================================================================== // 6. ASIA SESSION STATE // =========================================================================== in_asia = not na(time(timeframe.period, asia_session, tz)) is_new = in_asia and not in_asia[1] is_end = not in_asia and in_asia[1] var float a_h = na var float a_l = na var int a_n = 0 var float L_h = na var float L_l = na var float L_rng = na var int day_bi = na if is_new a_h := high a_l := low a_n := 1 L_h := na L_l := na L_rng := na else if in_asia a_h := math.max(a_h, high) a_l := math.min(a_l, low) a_n += 1 if is_end and a_n >= i_minbars L_h := a_h L_l := a_l L_rng := dRange day_bi := bar_index show = not in_asia and not na(L_h) and not na(L_rng) // =========================================================================== // 7. AVR LEVELS // =========================================================================== eq = show ? (L_h + L_l) / 2.0 : na arng = L_h - L_l q1 = show ? L_l + arng * 0.25 : na q3 = show ? L_l + arng * 0.75 : na u_l1 = show ? L_h + L_rng * up_lvl1 : na u_am = show ? L_h + L_rng * up_avrm : na u_a = show ? L_h + L_rng * up_avr : na u_ap = show ? L_h + L_rng * up_avrp : na u_mx = show ? L_h + L_rng * up_max : na d_l1 = show ? L_l - L_rng * dn_lvl1 : na d_am = show ? L_l - L_rng * dn_avrm : na d_a = show ? L_l - L_rng * dn_avr : na d_ap = show ? L_l - L_rng * dn_avrp : na d_mx = show ? L_l - L_rng * dn_max : na u_band = L_rng * up_lvl1 d_band = L_rng * dn_lvl1 u_ote_a = show ? L_h + u_band * ote_lo : na u_ote_b = show ? L_h + u_band * ote_hi : na d_ote_a = show ? L_l - d_band * ote_lo : na d_ote_b = show ? L_l - d_band * ote_hi : na cAsia = c_asia stLine = f_linestyle(sty_line) stBand = f_linestyle(sty_band) // =========================================================================== // 8. AVR PERSISTENT OBJECTS // =========================================================================== var line ln_h = na var line ln_l = na var line ln_eq = na var line ln_q1 = na var line ln_q3 = na var line ln_uam = na var line ln_ua = na var line ln_uap = na var line ln_umx = na var line ln_dam = na var line ln_da = na var line ln_dap = na var line ln_dmx = na var box bx_l1u = na var box bx_oteu = na var box bx_l1d = na var box bx_oted = na var box bx_con = na var label lb_uam = na var label lb_ua = na var label lb_uap = na var label lb_umx = na var label lb_dam = na var label lb_da = na var label lb_dap = na var label lb_dmx = na var label lb_h = na var label lb_l = na var label lb_zone = na var label lb_warn = na var table tb = na if barstate.isfirst ln_h := line.new(bar_index,na,bar_index,na, color=c_asia, width=w_asia) ln_l := line.new(bar_index,na,bar_index,na, color=c_asia, width=w_asia) ln_eq := line.new(bar_index,na,bar_index,na, color=c_eq, width=w_eq, style=stBand) ln_q1 := line.new(bar_index,na,bar_index,na, color=c_q, width=w_q, style=stBand) ln_q3 := line.new(bar_index,na,bar_index,na, color=c_q, width=w_q, style=stBand) ln_uam:= line.new(bar_index,na,bar_index,na, color=c_am, width=w_am, style=stLine) ln_ua := line.new(bar_index,na,bar_index,na, color=c_a, width=w_a, style=stLine) ln_uap:= line.new(bar_index,na,bar_index,na, color=c_ap, width=w_ap, style=stLine) ln_umx:= line.new(bar_index,na,bar_index,na, color=c_mx, width=w_mx, style=stLine) ln_dam:= line.new(bar_index,na,bar_index,na, color=c_am, width=w_am, style=stLine) ln_da := line.new(bar_index,na,bar_index,na, color=c_a, width=w_a, style=stLine) ln_dap:= line.new(bar_index,na,bar_index,na, color=c_ap, width=w_ap, style=stLine) ln_dmx:= line.new(bar_index,na,bar_index,na, color=c_mx, width=w_mx, style=stLine) bx_l1u := box.new(bar_index,na,bar_index,na, border_color=cb_l1, bgcolor=c_l1, border_width=bw_box) bx_oteu:= box.new(bar_index,na,bar_index,na, border_color=cb_ote, bgcolor=c_ote, border_width=bw_box) bx_l1d := box.new(bar_index,na,bar_index,na, border_color=cb_l1, bgcolor=c_l1, border_width=bw_box) bx_oted:= box.new(bar_index,na,bar_index,na, border_color=cb_ote, bgcolor=c_ote, border_width=bw_box) bx_con := box.new(bar_index,na,bar_index,na, border_color=cb_con, bgcolor=c_con, border_width=bw_box) lb_uam:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_am, size=size.small) lb_ua :=label.new(bar_index,na,"", style=label.style_none, textcolor=c_a, size=size.small) lb_uap:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_ap, size=size.small) lb_umx:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_mx, size=size.small) lb_dam:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_am, size=size.small) lb_da :=label.new(bar_index,na,"", style=label.style_none, textcolor=c_a, size=size.small) lb_dap:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_ap, size=size.small) lb_dmx:=label.new(bar_index,na,"", style=label.style_none, textcolor=c_mx, size=size.small) lb_h :=label.new(bar_index,na,"", style=label.style_none, textcolor=c_asia, size=size.small) lb_l :=label.new(bar_index,na,"", style=label.style_none, textcolor=c_asia, size=size.small) lb_zone:=label.new(bar_index,na,"", style=label.style_label_left, color=color.new(color.black,20), textcolor=color.white, size=size.small) lb_warn:=label.new(bar_index,na,"", style=label.style_label_down, color=color.new(color.orange,25), textcolor=color.black, size=size.tiny) tb := table.new(position.top_right, 2, 8, border_width=1, frame_color=color.new(color.gray,60), frame_width=1) // =========================================================================== // 9. AVR UPDATE HELPERS // =========================================================================== uH(l, x1, x2, y, vis) => yy = vis ? y : na line.set_xy1(l, x1, yy) line.set_xy2(l, x2, yy) uB(b, x1, x2, top, bot, vis) => if vis and not na(top) and not na(bot) box.set_left(b, x1) box.set_right(b, x2) box.set_top(b, top) box.set_bottom(b, bot) else box.set_top(b, na) box.set_bottom(b, na) uL(lb, x, y, txt, vis) => if vis and not na(y) label.set_xy(lb, x, y) label.set_text(lb, txt) else label.set_xy(lb, x, na) label.set_text(lb, "") f_row(r, k, v, kc, vc) => table.cell(tb, 0, r, k, text_color=color.white, text_size=size.small, bgcolor=kc) table.cell(tb, 1, r, v, text_color=color.white, text_size=size.small, bgcolor=vc) // =========================================================================== // 10. AVR RENDER // =========================================================================== if barstate.islast x1 = na(day_bi) ? bar_index : day_bi x2 = bar_index + ext_bars uH(ln_h, x1, x2, L_h, show and show_asia) uH(ln_l, x1, x2, L_l, show and show_asia) uH(ln_eq, x1, x2, eq, show and show_asia) uH(ln_q1, x1, x2, q1, show and show_quarts) uH(ln_q3, x1, x2, q3, show and show_quarts) uH(ln_uam, x1, x2, u_am, show and show_up) uH(ln_ua, x1, x2, u_a, show and show_up) uH(ln_uap, x1, x2, u_ap, show and show_up) uH(ln_umx, x1, x2, u_mx, show and show_up) uH(ln_dam, x1, x2, d_am, show and show_dn) uH(ln_da, x1, x2, d_a, show and show_dn) uH(ln_dap, x1, x2, d_ap, show and show_dn) uH(ln_dmx, x1, x2, d_mx, show and show_dn) uB(bx_l1u, x1, x2, u_l1, L_h, show and show_l1 and show_up) uB(bx_oteu, x1, x2, u_ote_b, u_ote_a, show and show_l1 and show_up) uB(bx_l1d, x1, x2, L_l, d_l1, show and show_l1 and show_dn) uB(bx_oted, x1, x2, d_ote_a, d_ote_b, show and show_l1 and show_dn) uB(bx_con, x1, x2, u_am, d_am, show and show_consol) uL(lb_h, x2, L_h, "Asia H", show and show_labels and show_asia) uL(lb_l, x2, L_l, "Asia L", show and show_labels and show_asia) uL(lb_uam, x2, u_am, "AVR- ↑", show and show_labels and show_up) uL(lb_ua, x2, u_a, "AVR ↑", show and show_labels and show_up) uL(lb_uap, x2, u_ap, "AVR+ ↑", show and show_labels and show_up) uL(lb_umx, x2, u_mx, "MAX ↑", show and show_labels and show_up) uL(lb_dam, x2, d_am, "AVR- ↓", show and show_labels and show_dn) uL(lb_da, x2, d_a, "AVR ↓", show and show_labels and show_dn) uL(lb_dap, x2, d_ap, "AVR+ ↓", show and show_labels and show_dn) uL(lb_dmx, x2, d_mx, "MAX ↓", show and show_labels and show_dn) // =========================================================================== // 11. AVR ZONE CLASSIFICATION + TABLE // =========================================================================== zoneTxt = "—" if show c = close zoneTxt := c > u_mx ? "▲ > MAX (OUTLIER — rare)" : c > u_ap ? "▲ AVR+ → MAX (exhaustion ↑)" : c > u_a ? "▲ AVR → AVR+ (avg expansion ↑)" : c > u_am ? "▲ AVR- → AVR ↑" : c > L_h ? "▲ Level 1 ↑ (first expansion)" : c > eq ? "◦ Upper Asia (balance)" : c > L_l ? "◦ Lower Asia (balance)" : c > d_am ? "▼ Level 1 ↓ (first expansion)" : c > d_a ? "▼ AVR- → AVR ↓" : c > d_ap ? "▼ AVR → AVR+ (avg expansion ↓)" : c > d_mx ? "▼ AVR+ → MAX (exhaustion ↓)" : "▼ < MAX (OUTLIER — rare)" if barstate.islast uL(lb_zone, bar_index + ext_bars, close, " " + zoneTxt, show and show_labels) if show_warn and show label.set_xy(lb_warn, bar_index, na(u_mx) ? high : u_mx) label.set_text(lb_warn, "ZONES = LOCATION / EXHAUSTION — NOT ENTRY") else label.set_text(lb_warn, "") label.set_xy(lb_warn, bar_index, na) if barstate.islast and show_table bg = color.new(color.black, 15) hd = color.new(cAsia, 10) table.cell(tb, 0, 0, "GOLD SESSION FRAMEWORK v11", text_color=color.white, text_size=size.small, bgcolor=hd) table.cell(tb, 1, 0, use_adr ? "ADR" : "ATR", text_color=color.white, text_size=size.small, bgcolor=hd) f_row(1, (use_adr?"ADR(":"ATR(")+str.tostring(atr_length)+")", show?str.tostring(L_rng, format.mintick):"—", bg, bg) f_row(2, "Asia H / L", show?str.tostring(L_h, format.mintick)+" / "+str.tostring(L_l, format.mintick):"—", bg, bg) f_row(3, "Asia range", show?str.tostring(arng, format.mintick):"—", bg, bg) f_row(4, "Up AVR / MAX", show?str.tostring(u_a, format.mintick)+" / "+str.tostring(u_mx, format.mintick):"—", bg, color.new(color.red,80)) f_row(5, "Dn AVR / MAX", show?str.tostring(d_a, format.mintick)+" / "+str.tostring(d_mx, format.mintick):"—", bg, color.new(color.red,80)) f_row(6, "Current zone", show?zoneTxt:"waiting Asia close", bg, color.new(color.orange,70)) table.cell(tb, 0, 7, "LOCATION/EXHAUSTION — NOT ENTRY", text_color=color.yellow, text_size=size.tiny, bgcolor=bg) table.cell(tb, 1, 7, "", bgcolor=bg) // =========================================================================== // 12. CHANDELIER — stateless ingredients via security, recursion at global scope // =========================================================================== [hh1, ll1, bd1] = request.security(syminfo.tickerid, ch1_tf, f_chanIng(ch1_len, ch_useclose, ch1_eng=="Enhanced", ch_hlen, ch1_mtr, ch1_mmr, ch1_mb, ch_trth, ch_mrth), lookahead=barmerge.lookahead_off) [hh2, ll2, bd2] = request.security(syminfo.tickerid, ch2_tf, f_chanIng(ch2_len, ch_useclose, ch2_eng=="Enhanced", ch_hlen, ch2_mtr, ch2_mmr, ch2_mb, ch_trth, ch_mrth), lookahead=barmerge.lookahead_off) [hh3, ll3, bd3] = request.security(syminfo.tickerid, ch3_tf, f_chanIng(ch3_len, ch_useclose, ch3_eng=="Enhanced", ch_hlen, ch3_mtr, ch3_mmr, ch3_mb, ch_trth, ch_mrth), lookahead=barmerge.lookahead_off) // v11: a Chandelier whose TF is faster than the chart cannot be computed here (request.security returns only the // last intrabar of the lower TF) → treated as off on that chart (e.g. Ch1 'TF 3' on the H1 pane). bool ch1_ok = ch1_on and timeframe.in_seconds(ch1_tf) >= timeframe.in_seconds() bool ch2_ok = ch2_on and timeframe.in_seconds(ch2_tf) >= timeframe.in_seconds() bool ch3_ok = ch3_on and timeframe.in_seconds(ch3_tf) >= timeframe.in_seconds() [st1, dr1] = f_trail(ch1_ok ? hh1 : na, ch1_ok ? ll1 : na, ch1_ok ? bd1 : na) [st2, dr2] = f_trail(ch2_ok ? hh2 : na, ch2_ok ? ll2 : na, ch2_ok ? bd2 : na) [st3, dr3] = f_trail(ch3_ok ? hh3 : na, ch3_ok ? ll3 : na, ch3_ok ? bd3 : na) c1 = dr1 > 0 ? ch1_cu : ch1_cd c2 = dr2 > 0 ? ch2_cu : ch2_cd c3 = dr3 > 0 ? ch3_cu : ch3_cd plot(ch1_on and ch1_sty=="Line" ? st1 : na, "Ch1 line", color=c1, linewidth=ch1_w, style=plot.style_steplinebr) plot(ch1_on and ch1_sty=="Stepline" ? st1 : na, "Ch1 step", color=c1, linewidth=ch1_w, style=plot.style_stepline, display=display.none) plot(ch1_on and ch1_sty=="Circles" ? st1 : na, "Ch1 dots", color=c1, linewidth=ch1_w, style=plot.style_circles, display=display.none) plot(ch2_on and ch2_sty=="Line" ? st2 : na, "Ch2 line", color=c2, linewidth=ch2_w, style=plot.style_steplinebr) plot(ch2_on and ch2_sty=="Stepline" ? st2 : na, "Ch2 step", color=c2, linewidth=ch2_w, style=plot.style_stepline, display=display.none) plot(ch2_on and ch2_sty=="Circles" ? st2 : na, "Ch2 dots", color=c2, linewidth=ch2_w, style=plot.style_circles, display=display.none) plot(ch3_on and ch3_sty=="Line" ? st3 : na, "Ch3 line", color=c3, linewidth=ch3_w, style=plot.style_steplinebr) plot(ch3_on and ch3_sty=="Stepline" ? st3 : na, "Ch3 step", color=c3, linewidth=ch3_w, style=plot.style_stepline, display=display.none) plot(ch3_on and ch3_sty=="Circles" ? st3 : na, "Ch3 dots", color=c3, linewidth=ch3_w, style=plot.style_circles, display=display.none) plotshape(ch1_on and ch1_sh and dr1>0 and dr1[1]<0, "Ch1 ↑", shape.triangleup, location.belowbar, ch1_cu, size=size.tiny) plotshape(ch1_on and ch1_sh and dr1<0 and dr1[1]>0, "Ch1 ↓", shape.triangledown, location.abovebar, ch1_cd, size=size.tiny) plotshape(ch2_on and ch2_sh and dr2>0 and dr2[1]<0, "Ch2 ↑", shape.triangleup, location.belowbar, ch2_cu, size=size.tiny) plotshape(ch2_on and ch2_sh and dr2<0 and dr2[1]>0, "Ch2 ↓", shape.triangledown, location.abovebar, ch2_cd, size=size.tiny) plotshape(ch3_on and ch3_sh and dr3>0 and dr3[1]<0, "Ch3 ↑", shape.triangleup, location.belowbar, ch3_cu, size=size.tiny) plotshape(ch3_on and ch3_sh and dr3<0 and dr3[1]>0, "Ch3 ↓", shape.triangledown, location.abovebar, ch3_cd, size=size.tiny) // =========================================================================== // 13. VOLUME PROFILE — OBJECT POOL (create-once, update-coords: realtime-safe) // =========================================================================== bool dB = ta.change(time("D")) != 0 var int sessN = 1 sessN := dB ? 1 : sessN + 1 stPoc = f_linestyle(vp_spoc) stVa = f_linestyle(vp_sva) var array vpBox = array.new() var array vpNode = array.new() var line vpLpoc = na var line vpLvah = na var line vpLval = na var label vpLbP = na var label vpLbH = na var label vpLbV = na if barstate.isfirst for i = 0 to vp_bins - 1 array.push(vpBox, box.new(bar_index, na, bar_index, na, border_width=1)) for i = 0 to (vp_maxnodes * 2) - 1 array.push(vpNode, line.new(bar_index, na, bar_index, na)) vpLpoc := line.new(bar_index, na, bar_index, na) vpLvah := line.new(bar_index, na, bar_index, na) vpLval := line.new(bar_index, na, bar_index, na) vpLbP := label.new(bar_index, na, "", style=label.style_label_left, size=size.tiny) vpLbH := label.new(bar_index, na, "", style=label.style_label_left, size=size.tiny) vpLbV := label.new(bar_index, na, "", style=label.style_label_left, size=size.tiny) if barstate.islast // --- hide the whole pool first --- for b in vpBox box.set_top(b, na) box.set_bottom(b, na) for l in vpNode line.set_xy1(l, bar_index, na) line.set_xy2(l, bar_index, na) line.set_xy1(vpLpoc, bar_index, na) line.set_xy2(vpLpoc, bar_index, na) line.set_xy1(vpLvah, bar_index, na) line.set_xy2(vpLvah, bar_index, na) line.set_xy1(vpLval, bar_index, na) line.set_xy2(vpLval, bar_index, na) label.set_xy(vpLbP, bar_index, na) label.set_xy(vpLbH, bar_index, na) label.set_xy(vpLbV, bar_index, na) if vp_on // --- window length (clamped to available history) --- int Nbars = vp_roll if vp_mode == "Session" Nbars := sessN else if vp_mode == "Composite" int seen = 0 int nb = 1 int scan = math.min(vp_maxbars, bar_index + 1) - 1 for i = 0 to scan if dB[i] seen += 1 if seen > vp_days break nb := i + 1 Nbars := nb Nbars := math.min(Nbars, vp_maxbars) Nbars := math.min(Nbars, bar_index + 1) Nbars := math.max(Nbars, 2) // --- price range --- float hi = high float lo = low for i = 0 to Nbars - 1 if not na(high[i]) and not na(low[i]) hi := math.max(hi, high[i]) lo := math.min(lo, low[i]) float binSize = (hi - lo) / vp_bins if binSize > 0 // --- accumulate volume into bins --- array binVol = array.new_float(vp_bins, 0.0) for i = 0 to Nbars - 1 float v = volume[i] if not na(v) and v > 0 and not na(high[i]) and not na(low[i]) int b0 = math.max(0, int(math.floor((low[i] - lo) / binSize))) int b1 = math.min(vp_bins - 1, int(math.floor((high[i] - lo) / binSize))) float vPer = v / math.max(1, b1 - b0 + 1) for b = b0 to b1 array.set(binVol, b, array.get(binVol, b) + vPer) // --- POC + totals --- int pocIdx = 0 float pocVol = 0.0 float total = 0.0 for b = 0 to vp_bins - 1 float bv = array.get(binVol, b) total += bv if bv > pocVol pocVol := bv pocIdx := b if total > 0 and pocVol > 0 float avgBin = total / vp_bins float pocPrice = lo + (pocIdx + 0.5) * binSize // --- value area expansion (larger-neighbor) --- float target = total * vp_va / 100.0 float cum = pocVol int lo_i = pocIdx int hi_i = pocIdx while cum < target and (lo_i > 0 or hi_i < vp_bins - 1) float upV = hi_i < vp_bins - 1 ? array.get(binVol, hi_i + 1) : -1.0 float dnV = lo_i > 0 ? array.get(binVol, lo_i - 1) : -1.0 if upV >= dnV hi_i += 1 cum += upV else lo_i -= 1 cum += dnV float vah = lo + (hi_i + 1) * binSize float val = lo + lo_i * binSize int rX = bar_index + vp_offset int lX = bar_index - math.min(Nbars, 300) // --- histogram → update pool boxes --- if vp_showhist for b = 0 to vp_bins - 1 box bx = array.get(vpBox, b) float bv = array.get(binVol, b) int wBars = int(math.round(bv / pocVol * vp_maxwidth)) if bv > 0 and wBars >= 1 bool inVA = b >= lo_i and b <= hi_i color fc = b == pocIdx ? color.new(vp_cpoc, 55) : inVA ? vp_vafill : vp_fill box.set_left(bx, rX) box.set_right(bx, rX + wBars) box.set_top(bx, lo + (b + 1) * binSize) box.set_bottom(bx, lo + b * binSize) box.set_bgcolor(bx, fc) box.set_border_color(bx, color.new(color.gray, 90)) // --- POC / VAH / VAL lines + labels --- line.set_xy1(vpLpoc, lX, pocPrice) line.set_xy2(vpLpoc, rX + vp_maxwidth, pocPrice) line.set_color(vpLpoc, vp_cpoc) line.set_width(vpLpoc, vp_wpoc) line.set_style(vpLpoc, stPoc) label.set_xy(vpLbP, rX + vp_maxwidth, pocPrice) label.set_text(vpLbP, "POC " + str.tostring(pocPrice, format.mintick)) label.set_textcolor(vpLbP, vp_cpoc) label.set_color(vpLbP, color.new(color.black, 30)) line.set_xy1(vpLvah, lX, vah) line.set_xy2(vpLvah, rX + vp_maxwidth, vah) line.set_color(vpLvah, vp_cva) line.set_width(vpLvah, vp_wva) line.set_style(vpLvah, stVa) label.set_xy(vpLbH, rX + vp_maxwidth, vah) label.set_text(vpLbH, "VAH") label.set_textcolor(vpLbH, vp_cva) label.set_color(vpLbH, color.new(color.black, 40)) line.set_xy1(vpLval, lX, val) line.set_xy2(vpLval, rX + vp_maxwidth, val) line.set_color(vpLval, vp_cva) line.set_width(vpLval, vp_wva) line.set_style(vpLval, stVa) label.set_xy(vpLbV, rX + vp_maxwidth, val) label.set_text(vpLbV, "VAL") label.set_textcolor(vpLbV, vp_cva) label.set_color(vpLbV, color.new(color.black, 40)) // --- HVN / LVN nodes → update pool lines --- if vp_shownodes int used = 0 int nH = 0 int nL = 0 int cap = array.size(vpNode) for b = 1 to vp_bins - 2 if used < cap float bv = array.get(binVol, b) float bp = array.get(binVol, b - 1) float bn = array.get(binVol, b + 1) float ny = lo + (b + 0.5) * binSize bool isH = nH < vp_maxnodes and bv >= vp_hvn * avgBin and bv >= bp and bv >= bn bool isL = nL < vp_maxnodes and bv <= vp_lvn * avgBin and bv <= bp and bv <= bn and bv > 0 if isH or isL line ln = array.get(vpNode, used) line.set_xy1(ln, lX, ny) line.set_xy2(ln, rX, ny) line.set_color(ln, isH ? vp_chvn : vp_clvn) line.set_width(ln, vp_wnode) line.set_style(ln, isH ? line.style_solid : line.style_dotted) used += 1 if isH nH += 1 else nL += 1 // =========================================================================== // 13b. VALUE-AREA REVERSION (VARS) — per-bar session profile + reclaim engine // =========================================================================== // current-session profile state var array va_barHigh = array.new_float() var array va_barLow = array.new_float() var array va_barUp = array.new_float() var array va_barDn = array.new_float() var array va_pVol = array.new_float() var array va_prevVol = array.new_float() var float va_low = na var float va_high = na var float va_bin = na var float va_prevLow = na var float va_prevBin = na var bool va_hasPrev = false var int va_activeAnchorTs = na var int va_anchorBI = na var int va_prevAnchorBI = na // current state machine var bool va_bearBO = false var bool va_bullBO = false var bool va_bearSlow = false var bool va_bullSlow = false var float va_lastBearVol = na var float va_lastBullVol = na var int va_bearBars = 0 var int va_bullBars = 0 // previous-session state machine var bool va_pBearBO = false var bool va_pBullBO = false var bool va_pBearSlow = false var bool va_pBullSlow = false var float va_pLastBearVol = na var float va_pLastBullVol = na var int va_pBearBars = 0 var int va_pBullBars = 0 // anchor detection (Fabio 18:00 ET style) int va_ly = year(time, "America/New_York") int va_lm = month(time, "America/New_York") int va_ld = dayofmonth(time, "America/New_York") int va_todayTs = timestamp("America/New_York", va_ly, va_lm, va_ld, vars_anchorHour, 0) int va_anchorTs = time >= va_todayTs ? va_todayTs : timestamp("America/New_York", va_ly, va_lm, va_ld - 1, vars_anchorHour, 0) bool va_newAnchor = na(va_activeAnchorTs) or va_anchorTs != va_activeAnchorTs if va_newAnchor if not na(va_activeAnchorTs) and not na(va_low) and array.size(va_pVol) > 0 va_prevVol := array.copy(va_pVol) va_prevAnchorBI := va_anchorBI va_prevLow := va_low va_prevBin := va_bin va_hasPrev := true va_activeAnchorTs := va_anchorTs va_anchorBI := bar_index array.clear(va_barHigh) array.clear(va_barLow) array.clear(va_barUp) array.clear(va_barDn) va_bearBO := false va_bullBO := false va_bearSlow := false va_bullSlow := false va_lastBearVol := na va_lastBullVol := na va_bearBars := 0 va_bullBars := 0 va_pBearBO := false va_pBullBO := false va_pBearSlow := false va_pBullSlow := false va_pLastBearVol := na va_pLastBullVol := na va_pBearBars := 0 va_pBullBars := 0 va_low := na va_high := na va_bin := na va_reset(va_pVol, vars_rows) float va_vol = nz(volume, 0.0) float va_up = close >= open ? va_vol : 0.0 float va_dn = close < open ? va_vol : 0.0 array.push(va_barHigh, high) array.push(va_barLow, low) array.push(va_barUp, va_up) array.push(va_barDn, va_dn) bool va_rangeCh = na(va_low) or low < va_low or high > va_high if va_rangeCh va_low := na(va_low) ? low : math.min(va_low, low) va_high := na(va_high) ? high : math.max(va_high, high) va_bin := math.max((va_high - va_low) / vars_rows, syminfo.mintick) va_reset(va_pVol, vars_rows) int sb = array.size(va_barHigh) for si = 0 to sb - 1 va_add(va_pVol, array.get(va_barLow, si), array.get(va_barHigh, si), array.get(va_barUp, si) + array.get(va_barDn, si), va_low, va_bin, vars_rows) else va_add(va_pVol, low, high, va_vol, va_low, va_bin, vars_rows) [va_vah, va_val] = va_levels(va_pVol, va_low, va_bin, vars_va) [va_pvah, va_pval] = va_levels(va_prevVol, va_prevLow, va_prevBin, vars_va) bool va_bullEng = close > open and close[1] < open[1] and open <= close[1] and close >= open[1] bool va_bearEng = close < open and close[1] > open[1] and open >= close[1] and close <= open[1] // current-session reclaim state machine bool va_bullReclaim = false bool va_bearReclaim = false bool va_hasVA = not na(va_val) and not na(va_vah) if va_hasVA if close < va_val va_bullBO := false va_bullBars := 0 va_bullSlow := false va_lastBullVol := na if not va_bearBO va_bearSlow := false va_lastBearVol := na va_bearBars := 1 else va_bearBars += 1 va_bearBO := true if va_dn > 0 if not na(va_lastBearVol) and va_dn < va_lastBearVol va_bearSlow := true va_lastBearVol := va_dn else if close > va_vah va_bearBO := false va_bearBars := 0 va_bearSlow := false va_lastBearVol := na if not va_bullBO va_bullSlow := false va_lastBullVol := na va_bullBars := 1 else va_bullBars += 1 va_bullBO := true if va_up > 0 if not na(va_lastBullVol) and va_up < va_lastBullVol va_bullSlow := true va_lastBullVol := va_up else va_bullReclaim := va_bullEng and va_bearBO and va_bearBars <= vars_maxbars and va_bearSlow and va_up > va_dn and va_up > nz(va_lastBearVol, 0.0) va_bearReclaim := va_bearEng and va_bullBO and va_bullBars <= vars_maxbars and va_bullSlow and va_dn > va_up and va_dn > nz(va_lastBullVol, 0.0) va_bearBO := false va_bullBO := false va_bearBars := 0 va_bullBars := 0 va_bearSlow := false va_bullSlow := false va_lastBearVol := na va_lastBullVol := na // previous-session reclaim state machine bool va_pBullReclaim = false bool va_pBearReclaim = false bool va_hasPVA = va_hasPrev and not na(va_pval) and not na(va_pvah) if va_hasPVA if close < va_pval va_pBullBO := false va_pBullBars := 0 va_pBullSlow := false va_pLastBullVol := na if not va_pBearBO va_pBearSlow := false va_pLastBearVol := na va_pBearBars := 1 else va_pBearBars += 1 va_pBearBO := true if va_dn > 0 if not na(va_pLastBearVol) and va_dn < va_pLastBearVol va_pBearSlow := true va_pLastBearVol := va_dn else if close > va_pvah va_pBearBO := false va_pBearBars := 0 va_pBearSlow := false va_pLastBearVol := na if not va_pBullBO va_pBullSlow := false va_pLastBullVol := na va_pBullBars := 1 else va_pBullBars += 1 va_pBullBO := true if va_up > 0 if not na(va_pLastBullVol) and va_up < va_pLastBullVol va_pBullSlow := true va_pLastBullVol := va_up else va_pBullReclaim := va_bullEng and va_pBearBO and va_pBearBars <= vars_maxbars and va_pBearSlow and va_up > va_dn and va_up > nz(va_pLastBearVol, 0.0) va_pBearReclaim := va_bearEng and va_pBullBO and va_pBullBars <= vars_maxbars and va_pBullSlow and va_dn > va_up and va_dn > nz(va_pLastBullVol, 0.0) va_pBearBO := false va_pBullBO := false va_pBearBars := 0 va_pBullBars := 0 va_pBearSlow := false va_pBullSlow := false va_pLastBearVol := na va_pLastBullVol := na // signals plotshape(vars_on and vars_prev and va_pBullReclaim, "PVA reclaim ↑", shape.triangleup, location.belowbar, vars_cbull, text="PVA", textcolor=color.white, size=size.small) plotshape(vars_on and vars_prev and va_pBearReclaim, "PVA reclaim ↓", shape.triangledown, location.abovebar, vars_cbear, text="PVA", textcolor=color.white, size=size.small) plotshape(vars_on and vars_curr and va_bullReclaim, "CVA reclaim ↑", shape.triangleup, location.belowbar, vars_cbull, text="CVA", textcolor=color.white, size=size.small) plotshape(vars_on and vars_curr and va_bearReclaim, "CVA reclaim ↓", shape.triangledown, location.abovebar, vars_cbear, text="CVA", textcolor=color.white, size=size.small) bool va_sigBull = (vars_prev and va_pBullReclaim) or (vars_curr and va_bullReclaim) bool va_sigBear = (vars_prev and va_pBearReclaim) or (vars_curr and va_bearReclaim) barcolor(vars_on and vars_colorcandles ? (va_sigBull ? vars_cbull : va_sigBear ? vars_cbear : na) : na, title="VARS reclaim candles") // previous-session VA lines var line va_lnPVAH = na var line va_lnPVAL = na if barstate.isfirst va_lnPVAH := line.new(bar_index, na, bar_index, na, xloc=xloc.bar_index, extend=extend.right, style=line.style_dashed, width=1) va_lnPVAL := line.new(bar_index, na, bar_index, na, xloc=xloc.bar_index, extend=extend.right, style=line.style_dashed, width=1) if barstate.islast bool va_showP = vars_on and vars_showprevva and va_hasPrev and not na(va_pvah) and not na(va_pval) int va_px1 = na(va_prevAnchorBI) ? bar_index : va_prevAnchorBI if va_showP line.set_xy1(va_lnPVAH, va_px1, va_pvah) line.set_xy2(va_lnPVAH, bar_index, va_pvah) line.set_color(va_lnPVAH, color.new(vars_cbull, 25)) line.set_xy1(va_lnPVAL, va_px1, va_pval) line.set_xy2(va_lnPVAL, bar_index, va_pval) line.set_color(va_lnPVAL, color.new(vars_cbear, 25)) else line.set_xy1(va_lnPVAH, bar_index, na) line.set_xy2(va_lnPVAH, bar_index, na) line.set_xy1(va_lnPVAL, bar_index, na) line.set_xy2(va_lnPVAL, bar_index, na) // =========================================================================== // 13c. CVD DIVERGENCE — CLV×vol proxy + fractal regular divergence (on price) // =========================================================================== float cvd_rng = high - low float cvd_clv = cvd_rng > 0 ? ((close - low) - (high - close)) / cvd_rng : 0.0 // v10 rev3 — delta source (see §3f-3): footprint → 1-min tick rule → candle CLV footprint cvd_fp = na if cvd_srcMode == SRC_FP cvd_fp := request.footprint(cvd_fpTicks, 70) bool cvd_fpOk = cvd_srcMode == SRC_FP and not na(cvd_fp) float cvd_fpD = na if cvd_fpOk cvd_fpD := footprint.delta(cvd_fp) array dp_sV = na array dp_sC = na array dp_sP = na if cvd_srcMode == SRC_TICK or (cvd_srcMode == SRC_FP and cvd_fallback) [b1, b2, b5] = request.security_lower_tf(syminfo.tickerid, cvd_ltfTf, [volume, close, close[1]], ignore_invalid_timeframe = true) dp_sV := b1 dp_sC := b2 dp_sP := b5 int cvd_ltfN = na(dp_sV) ? 0 : array.size(dp_sV) float cvd_ltfD = na if cvd_ltfN > 0 cvd_ltfD := 0.0 float cvd_sg = 0.0 for i = 0 to cvd_ltfN - 1 cvd_sg := f_tickCarry(array.get(dp_sC, i), array.get(dp_sP, i), cvd_sg) cvd_ltfD += nz(array.get(dp_sV, i)) * cvd_sg float cvd_clvDelta = nz(volume, 0.0) * cvd_clv int cvd_code = cvd_fpOk and not na(cvd_fpD) ? 2 : cvd_ltfN > 0 ? 1 : 0 float cvd_dbar = cvd_code == 2 ? cvd_fpD : cvd_code == 1 ? cvd_ltfD : (cvd_srcMode == SRC_CLV or cvd_fallback ? cvd_clvDelta : 0.0) float cvd_nCov = math.min(300, bar_index + 1) float cvd_covFp300 = math.sum(cvd_code == 2 ? 1.0 : 0.0, 300) / cvd_nCov float cvd_covAny300 = math.sum(cvd_code > 0 ? 1.0 : 0.0, 300) / cvd_nCov float cvdHist = cvd_mode == "Periodic" ? math.sum(cvd_dbar, cvd_period) : ta.ema(cvd_dbar, cvd_period) float cvdEMA = ta.ema(close, 50) bool cvd_up = close[cvd_n] > cvdEMA[cvd_n] // v11: EMA of the pivot bar (was the current EMA) bool cvd_dn = close[cvd_n] < cvdEMA[cvd_n] float cvd_upPiv = ta.pivothigh(cvd_n, cvd_n) float cvd_dnPiv = ta.pivotlow(cvd_n, cvd_n) bool cvd_upFrac = not na(cvd_upPiv) and cvd_up bool cvd_dnFrac = not na(cvd_dnPiv) and cvd_dn // bearish regular divergence (price HH + CVD LH), on up-fractal bars float cvd_hiLastP = ta.valuewhen(cvd_upFrac, high[cvd_n], 0) float cvd_hiPerP = ta.valuewhen(cvd_upFrac, high[cvd_n], 1) float cvd_hiLastH = ta.valuewhen(cvd_upFrac, cvdHist[cvd_n], 0) float cvd_hiPerH = ta.valuewhen(cvd_upFrac, cvdHist[cvd_n], 1) int cvd_hiLastB = int(ta.valuewhen(cvd_upFrac, bar_index[cvd_n], 0)) int cvd_hiPerB = int(ta.valuewhen(cvd_upFrac, bar_index[cvd_n], 1)) float cvd_hiLastT = ta.valuewhen(cvd_upFrac, time[cvd_n], 0) bool cvd_bearDiv = cvd_on and cvd_upFrac and cvd_hiLastH > 0 and cvd_hiPerH > 0 and (cvd_hiLastB - cvd_hiPerB) < cvd_maxlen and cvd_hiLastP > cvd_hiPerP and cvd_hiLastH < cvd_hiPerH // bullish regular divergence (price LL + CVD HL), on down-fractal bars float cvd_loLastP = ta.valuewhen(cvd_dnFrac, low[cvd_n], 0) float cvd_loPerP = ta.valuewhen(cvd_dnFrac, low[cvd_n], 1) float cvd_loLastH = ta.valuewhen(cvd_dnFrac, cvdHist[cvd_n], 0) float cvd_loPerH = ta.valuewhen(cvd_dnFrac, cvdHist[cvd_n], 1) int cvd_loLastB = int(ta.valuewhen(cvd_dnFrac, bar_index[cvd_n], 0)) int cvd_loPerB = int(ta.valuewhen(cvd_dnFrac, bar_index[cvd_n], 1)) float cvd_loLastT = ta.valuewhen(cvd_dnFrac, time[cvd_n], 0) bool cvd_bullDiv = cvd_on and cvd_dnFrac and cvd_loLastH < 0 and cvd_loPerH < 0 and (cvd_loLastB - cvd_loPerB) < cvd_maxlen and cvd_loLastP < cvd_loPerP and cvd_loLastH > cvd_loPerH // --- v9: the same ±RD on the confluence timeframe (default M10) ----------- // Confluence only means anything when the chart TF is FASTER than the HTF. bool cvdC_valid = cvdC_on and cvd_on and timeframe.in_seconds() < timeframe.in_seconds(cvdC_tf) [cvdC_bullRaw, cvdC_bearRaw, cvdC_bullTRaw, cvdC_bearTRaw] = request.security(syminfo.tickerid, cvdC_tf, f_cvdDiv(cvd_mode, cvd_period, cvd_n, cvd_maxlen, cvd_srcMode, cvd_ltfTf, cvd_fallback, cvd_fpTicks), lookahead=barmerge.lookahead_off) // hold the value of the LAST CLOSED HTF bar (read on the first chart bar of a new HTF bar) bool cvdC_newHTF = ta.change(time(cvdC_tf)) != 0 var bool cvdC_bullHeld = false var bool cvdC_bearHeld = false var float cvdC_bullTHeld = na var float cvdC_bearTHeld = na if cvdC_newHTF cvdC_bullHeld := nz(cvdC_bullRaw[1]) > 0.5 cvdC_bearHeld := nz(cvdC_bearRaw[1]) > 0.5 cvdC_bullTHeld := cvdC_bullTRaw[1] cvdC_bearTHeld := cvdC_bearTRaw[1] bool cvdC_bull = cvdC_valid and (cvdC_conf ? cvdC_bullHeld : nz(cvdC_bullRaw) > 0.5) bool cvdC_bear = cvdC_valid and (cvdC_conf ? cvdC_bearHeld : nz(cvdC_bearRaw) > 0.5) float cvdC_bullT = cvdC_conf ? cvdC_bullTHeld : cvdC_bullTRaw float cvdC_bearT = cvdC_conf ? cvdC_bearTHeld : cvdC_bearTRaw // rising edge = this HTF divergence just became visible on the chart bool cvdC_bullEdge = cvdC_bull and not cvdC_bull[1] bool cvdC_bearEdge = cvdC_bear and not cvdC_bear[1] // latest HTF divergence pivot time seen so far (kept until a newer one appears) var float cvdC_bullPivT = na var float cvdC_bearPivT = na if cvdC_bullEdge and not na(cvdC_bullT) cvdC_bullPivT := cvdC_bullT if cvdC_bearEdge and not na(cvdC_bearT) cvdC_bearPivT := cvdC_bearT // ⚑ rev2: the two frames confirm at different lags (M3 +2 bars = 6 min, M10 +2 bars = // 20 min, plus up to one closed HTF bar). Matching by ARRIVAL time therefore misses // real pairs — match by the PIVOT time instead, and allow a long arrival window. int cvdC_tolms = cvdC_tolmin * 60000 bool crdBullNow = cvd_bullDiv and not na(cvdC_bullPivT) and not na(cvd_loLastT) and math.abs(cvd_loLastT - cvdC_bullPivT) <= cvdC_tolms bool crdBearNow = cvd_bearDiv and not na(cvdC_bearPivT) and not na(cvd_hiLastT) and math.abs(cvd_hiLastT - cvdC_bearPivT) <= cvdC_tolms // bounded round-robin pool (protects the persistent AVR/VP objects from culling) var array cvdLn = array.new() var array