TQQQ-8





//@version=6
indicator("TQQQ-8", overlay=true, max_labels_count=500, scale=scale.right)
// Date : 2026-07-02
// Modified : 2026-07-07 | Average the R0 core-exit defaults: PT 6→7, SL -8→-7 (both non-binding in R0 → results byte-identical 13.06M%/342/$56.96B).
// Version  : v027
// Change   : v027 — DEFAULTS only: R0 core exits PT 6.0→7.0 and SL -8.0→-7.0 (s2_r0PT / s2_r0SL), bracket hints updated to [7]/[-7]. User 'averaged up' the range we A/B'd (PT 6↔9, SL -6↔-8). Both levels are NON-BINDING for R0 (R0 trades exit via r0RegimeChangeExit / r0FastExit before price reaches ±6-9% — proven earlier: PT 6 vs 9 and SL -6 vs -8 both gave identical results), so PT=7 / SL=-7 sit in the same dormant zone → 13.06M%/342/$56.96B byte-identical. Fast VIX Exit unchanged (16.4). No logic touched.
// v026     : REMOVE the S6 R0.3 'Buy Filters / Rebuy Blockers' section (BEHAVIOR-CHANGING — new baseline). Deleted the 4 inputs (s2_r0RebuyBlock / s2_r0RebuySuspendDays / s2_r0RebuyPtExtraDays / s2_r0RebuyPtMaxAbove), their Eff aliases, the vars (lastSellDay, r0LastSuspendDays, r0LastPtSellPx, r0RearmPending), and all logic (r0RebuyBlocked, r0PtChaseBlocked, r0RebuySuspendedNow, r0PtRebuyAbovePct, r0BuyAttempt, daysSinceR0Sell) — removed 'not r0RebuyBlocked and not r0PtChaseBlocked' from buySignalS2. This reproduces the block-OFF state the user validated: it changes EXACTLY ONE trade (a sub-2% loss flips to a sub-2% win), and every risk metric is identical — Max DD -29.1%, recovery 15d, PF 4.68→4.69, Sharpe 0.48, worst -16.9%, lose-streak 4 all unchanged. New baseline: TQQQ core 13,065,210.2% / 342 trades (was 12.9M%/342), Cont T/S $56.96B / 316t (was $55.44B). The R0 confirm-bar re-arm on R0 sells (r0BarsInRegime := 0) is KEPT — that was independent of the rebuy block. Kept lastSellBar/lastSellPrice (used elsewhere) and all RC-side waits/lifecycle lock (untouched).
// v025     : UI LAYOUT only (no logic/defaults changed → 12.9M%/342 and $55.44B/316t byte-identical). Added inline="perfStart"/"perfEnd" to the Start Date / End Date input.time fields so each date picker and its time field render side-by-side on one row instead of the time wrapping below the date. Pure rendering change; the timestamps and Use-Date-Range gating are untouched.
// v024     : UI RELOCATION only (no logic/defaults changed → 12.9M%/342 and $55.44B/316t byte-identical, user-confirmed). Moved s2_sqqqShowStats out of the 'SQQQ Flat-Period Simulation TEST' group up into the top '01 — Performance & display' section, placed directly under 'Panel 4 performance source', and renamed 'Show SQQQ trigger stats table [ON]' → 'Info Table — Panel 5 SQQQ Triggers [ON]' so it sits with the other Panel toggles. Same variable/default (true), same render logic — only the input's group + label changed.
// v023     : LABEL-ONLY refresh (no logic/defaults changed → 12.9M%/342 and $55.44B byte-identical). The 16 SQQQ trigger checkboxes ('01 — TSL only (+X%, Nt)' … '16 — PT only') carried stale numbers from an old solo-run snapshot; synced each to the current SQQQ Trigger Research table (Comp% + leg count T) so the checkboxes and the table agree: TSL +191.8/46, BM +169.9/53, RCL +171.2/19, RG +112.1/16, DSMA +76.0/10, EOD +20.3/4, SLead +33.2/3, SL +29.8/6, BB +25.3/13, GapF2 +37.2/2, Brk +5.1/3, RC -7.4/30, FV +0.5/1, V/GapF 0/0, PT +1,250.9/136. NOTE: the shown metric is now the isolated per-trigger leg-comp (what the table shows), not the old whole-equity solo-continuous return; and the frozen 01–16 rank order is now out of sync with magnitude (PT is the biggest at +1,250.9% but sits at #16) — re-ranking deferred (would touch f_sqqqRankLabel/f_sqqqRankType + the research table row order). Kept [OFF]/[ON] default hints unchanged.
// v022     : SQQQ blocklist tuning + UI polish (SQQQ-side only; TQQQ core 12.9M%/342 byte-identical, and SQQQ sim/continuous OFF ⇒ zero effect). (1) DEFAULTS: added the 3 clear near-zero cells to the blocklist so they no longer trade SQQQ — slot3 BM-R1 (+0.1%), slot4 FV-R0 (+0.5%), slot5 Brk-R2 (+1.1%), alongside the existing RC-R1/RC-R2. These yield ≈nothing so removing them barely moves the $56.36B continuous curve but cuts 3 pointless inverse-ETF exposures; slot6 still free. (2) UI: each block slot's trigger and regime dropdowns now share one row via inline="sqbN" (labels shortened to 'Block N' × '×'), instead of two stacked rows. No engine/logic change — sqqqBlockList assembly + f_sqCellBlocked unchanged.
// v021     : REMOVE two display-only diagnostic/scaffolding features (behaviour-neutral → 12.9M%/342 byte-identical, SQQQ blocklist logic unchanged). (1) Split-half view: inputs 'SQQQ show split-half (w/n)' + 'SQQQ split-half boundary date', arrays sqqqStatsTradesA/WinsA/TradesB/WinsB, helper f_sqHalfStr, the per-leg A/B increments + resets, and the s2_sqqqShowSplit branch in the research cells (cells now always show full-sample (w/n)). (2) Rule-hit diagnostics: input 'Show rule-hit diagnostics table', arrays diagExitHits/diagBlk, helpers f_diagInc/f_diagRender, the diagTable render block, the inReport block-family increments, and the diagExitHits exit increment. KEPT f_diagExitLabel (the SQQQ cell blocklist f_sqCellBlocked depends on it). Both features' results are archived in TQQQ-8_LOG.md before removal.
// v020     : CORRECT the SQQQ blocklist default. RC's losing regimes are R1 (-2.6%, 11 legs) and R2 (-11.5%, 12 legs); RC-R0 (+7.4%, 7 legs) is the keeper. The v016-v019 default (RC-R2,RC-R3) was off by one from a table-column misread — it blocked the -11.5 cell + an empty R3 cell (12 legs → 330 trades). Corrected default = slot1 RC/R1, slot2 RC/R2 (23 legs → 319 SQQQ trades). Validated: Cont T/S $56.36B (best of all configs; vs $48.56B RC-on, $52.46B RC-off, $54.87B old default), PF 4.68, Sharpe 0.48. TQQQ core untouched → 12.9M%/342 byte-identical; SQQQ sim/continuous OFF => zero effect. Engine unchanged since v019 — this is a default-value correction only.
// v019     : Behaviour-neutral refactor — moved the ALERTS block into f_emitAlerts() (defined after its globals, called once/bar) to free main-body space so the 6-slot blocklist dropdowns compile. Alerts fire identically; 12.9M%/342 byte-identical.
// v018     : SQQQ blocklist UI = 6 slots × (trigger + regime) dropdowns (~138 literals). Correct design, but only compiles together with v019's main-body refactor.
// v017     : SQQQ cell blocklist UI (8 single-cell dropdowns) — DID NOT COMPILE ('main body too long'); superseded by v018.
// v016     : SQQQ cell blocklist (Option A) via free-text input. EXCLUDE trigger x entry-regime cells from actual SQQQ trading (sim + continuous) while keeping the trigger ON and still showing them in the research table. sqqqBuyOkEff = sqqqBuyOk and not blocked. Superseded UI by v017 (mechanism unchanged).
// v015     : SQQQ research split-half (DISPLAY-ONLY, no trade/logic change → 12.9M%/342 unchanged). New toggle 'SQQQ show split-half (w/n) [OFF]' + 'SQQQ split-half boundary date' (default 2023-01-01). When ON, the R0..R4 cells show wins/legs for each time half as "wA/nA·wB/nB" (before·after the boundary) instead of the full-sample (w/n). New per-half arrays sqqqStatsTradesA/WinsA/TradesB/WinsB; helper f_sqHalfStr builds the display string. Default OFF => identical view to v014.
// v014     : SQQQ research (DISPLAY-ONLY, no trade/logic change → 12.9M%/342 unchanged). The trigger x regime cells (R0..R4) now show wins/legs instead of just the leg count, e.g. "+7.4 (5/7)" = +7.4% comp from 7 SQQQ legs of which 5 were winners (≈71% win-rate). Uses the existing per-cell sqqqStatsWins array; nothing else touched.
// v013     : SQQQ research instrument upgrade (DISPLAY-ONLY, no trade/logic change → 12.9M%/342 unchanged). The SQQQ Trigger Research table's regime columns (R0..R4) now show the leg count alongside the compounded return, e.g. "+7.4 (3)" = +7.4% comp from 3 SQQQ legs; empty cells show "-". Uses the existing per-cell sqqqStatsTrades array; nothing else touched.
// v012     : Phase 2 #2 CLARIFY-ONLY (comments only): documented the Daily-SMA-Bear Rule-1 block as a below-band gate with a max-duration safety cap, not a timer. Results byte-identical to v011.
// v011     : FIX for v010's 'main body too long' error. #14 diagnostics render/counters moved into functions (f_diagRender, f_diagInc) + collapsed to arrays. Display-only; baseline untouched.
// v010     : Phase 3 #14 (ADDITIVE / display-only): rule-hit diagnostics table (which EXIT closed each trade + which BUY-BLOCKER family suppressed buys). NOTE: v010 exceeded Pine's main-body length limit and would not compile — superseded by v011.
// v009     : Phase 3 #3 cost/slippage haircut (default OFF = baseline safe). sellDispPct = currentProfit - roundTripCost when ON; trade selection unchanged, only reported P&L haircut. OFF => byte-identical to v008.
// v008     : Phase 2 #12: removed the reporting-window state-wipe; engine warms up on all bars, 'inReport' gates only displayed stats/markers. OFF date-range => 12.9M% baseline byte-identical; only Period-Debug numbers change (now match the full-run slice).
// v007     : Phase 2 #1 VALIDATED/LOCKED: defaults Regime-aware RCL buy lock = ON, Cross-regime block bars = 21 (~3 trading days on 1h); N>=21 reproduces the 12.9M% global-lock baseline. Dropped 'TEST' from group title. Defaults only.
// v006     : Phase 2 #1 tune: added input 'Cross-regime block bars [3]' (s2_rclCrossRegimeBars). When toggle ON, block ALL regimes for the first N bars after a lifecycle sell, then arming-regime-only. Gate: ... and (not s2_rclLockRegimeAware or rclBuyLockBars <= s2_rclCrossRegimeBars or rclBuyLockSrc == curRegimeInt).
// v005     : Phase 2 #1 SAFE: v004's regime-aware lock collapsed the tuned result (12.9M% -> ~41K%) because the global lock was load-bearing for compounding. Made it an opt-in input 'Regime-aware RCL buy lock [OFF]'. Default OFF reproduces v003 exactly. ON = v004 regime-aware behavior.
// v004     : Phase 2 #1 (BEHAVIOR-CHANGING): rclBuyBlocked also required rclBuyLockSrc == curRegimeInt. Reverted to a toggle in v005 after it crashed backtest performance.
// v003     : Phase 1 (behavior-neutral): #8 collapse identical vixSma0-4/vixAboveSma1-4 to one vixSmaMaster/vixAbove; #9 remove dead rcBuyBbOkR1-4=true path (rcPendBbOk now literal true); #13 recolor Daily SMA Bear 3 Sell diamond fuchsia→navy (was indistinguishable from Gap bounce fail 2). P&L/trades identical to v002; only visible change is one diamond color.
// v002     : Phase 1 #6 (behavior-neutral): replace 7 identical ta.stoch/K/D copies (rcl0-rcl3, rcl R4, rcsl, rcbd) with one shared sharedStochK/sharedStochD. Results identical to v001.
// v001     : Fork from TQQQ-7 v100. Baseline reference: ~12.9M% 6-year (2020-2025). Phase 0 only: no logic/default changes.
// Below this line is the inherited TQQQ-7 changelog, kept for reference only.
// TQQQ-7 v100 : Set tested S6 R3.8 defaults and note 12.9M% 6-year performance.
// v099     : Cap S6 R3.8 RC Stoch Lifecycle buy lock at 42 bars.
// v098     : Set tested S6 R0.8 RC Stoch Lifecycle defaults from chart review.
// v097     : Set R4 buy-lock cap to 21 and add R0 buy-lock cap test.
// v096     : Set tested S6 R2.8 defaults and note 12.5M% 6-year performance.
// v095     : Cap S6 R2.8 RC Stoch Lifecycle buy lock at 42 bars.
// v094     : Cap S6 R4.8 RC Stoch Lifecycle buy lock at 42 bars.
// v093     : Cap S6 R1.8 RC Stoch Lifecycle buy lock at 42 bars.
// v092     : Remove TEST wording from accepted R0/R2/R3 close-up release defaults.
// v091     : Set tested S6 R4.8 RC Stoch Lifecycle defaults from chart review.
// v090     : Add default-OFF close-up confirmation for R4 RC Stoch Lifecycle buy-lock release.
// v089     : Set tested S6 R0.8 RC Stoch Lifecycle defaults from chart review.
// v088     : Add default-OFF close-up confirmation for R0 RC Stoch Lifecycle buy-lock release.
// v087     : Set tested S6 R2.8 RC Stoch Lifecycle defaults from chart review.
// v086     : Add default-OFF close-up confirmation for R2 RC Stoch Lifecycle buy-lock release.
// v085     : Set tested S6 R3.8 RC Stoch Lifecycle defaults from chart review.
// v084     : Add default-OFF close-up confirmation for R3 RC Stoch Lifecycle buy-lock release.
// v083     : Make close > prior close part of R1 RC Stoch Lifecycle buy-lock release and remove redundant release tests.
// v082     : Add default-OFF shared recovery confirmation for R1 RC Stoch Lifecycle buy-lock release.
// v081     : Set tested S6 R1.8 RC Stoch Lifecycle defaults from chart review.
// v080     : Add default-OFF close-up confirmation for R1 RC Stoch Lifecycle buy-lock release.
// v079     : Add shared recovery apply switches for daily blockers, ATR, and RC waits.
// v078     : Move Rule 1 recovery controls into shared recovery section and update 20/50 defaults.
// v077     : Remove failed 15.3.3 R3 recovery test and set R3 no-buy bars default to 50.
// v076     : Add default-OFF recovery release test for 15.3.3 Daily SMA 50/100 No-Buy R3.
// v075     : Remove inactive 15.3.2 Daily SMA 50/100 No-Buy R1 section.
// v074     : Add default-OFF recovery release test for 15.3.2 Daily SMA 50/100 No-Buy R1.
// v073     : Remove failed R1 ATR recovery release test and restore original ATR block behavior.
// v072     : Replace simple R1 ATR timed block with stochastic/price/ATR recovery release test.
// v071     : Add default-OFF timed block mode for the R1 ATR Risk Filter.
// v070     : Make Daily SMA Bear Rule 1 use block bars as a timed limit instead of a continuous below-threshold block.
// v069     : Add default-OFF intraday recovery release for Daily SMA Bear Rule 1 R1 blocks.
// v068     : Use color-only X markers below candles for buy blockers.
// v067     : Remove regime-color blocker markers; use family colors for readability.
// v066     : Combine blocker plots by family to stay under TradingView's 64-plot limit.
// v065     : Make blocker families readable by shape and regime color.
// v064     : Remove VIX-Off from visible script title.
// v063     : Rename active file/title and move full audit notes to docs/TQQQ-7_LOG.md.
// v062     : Add 12-point backtest-realism audit status note.
// v061     : Freeze TQQQ open-equity display at selected end date.
// v060     : Set tuned daily SMA and soft-trail VIX-off defaults from screenshots.
// v059     : Set tuned R3/R4 VIX-off test defaults from screenshots.
// v058     : Set tuned VIX-off test defaults from screenshots.
// v057     : Compact Panel 1 Trades row to TQQQ whole-percent summary.
// v056     : Increase SQQQ trigger research table text to normal size.
// v055     : Increase SQQQ trigger research table text size.
// v054     : Move repeated Panel 4 table rendering into helper functions.
// v053     : Hardcode blocker markers visible and document blocker color map.
// v052     : Add Panel 4 source switch for Continuous T/S performance stats.
// v051     : Move compact T/S trade win-rate summary into Panel 1.
// v050     : Add SQQQ Sim and Continuous T/S rows to Panel 4 performance stats.
// v049     : Remove temporary Continuous T/S same-bar audit to free Pine variables.
// v048     : Compact SQQQ median storage to trigger-total only.
// v047     : Fix Pine type declaration for SQQQ median helper.
// v046     : Add exact median SQQQ leg return to trigger research table.
// v045     : Freeze SQQQ open-equity display at selected backtest end date.
// v044     : Add Continuous T/S same-bar double-count audit.
// v043     : Compact Continuous T/S row formatting in Panel 1.
// v042     : Move SQQQ Trigger Research table to left side of chart.
// v041     : Remove Trade Period Debug internals and old Sell Count table rendering.
// v040     : Reduce Manual Overrides from six slots to two slots.
// v039     : Remove Trade Period Debug table rendering to free Pine local variables.
// v038     : Add continuous TQQQ/SQQQ engine and trigger/regime SQQQ stats table.
// v037     : Replace ranked SQQQ dropdown with checkboxes for combination testing.
// v036     : Rename script title/header to match VIX_TQQQ_SQQQ_Research.pine.
// v035     : Add ranked SQQQ trigger selector from single-trigger sweep.
// v034     : Hardcode SQQQ trigger test to PT exits only.
// v033     : Hardcode SQQQ trigger test to GapFail2 exits only.
// v032     : Hardcode SQQQ trigger test to GapFail exits only.

// Full audit and version notes: docs/TQQQ-8_LOG.md.
// v031     : Hardcode SQQQ trigger test to EOD exits only.
// v030     : Hardcode SQQQ trigger test to FV exits only.
// v029     : Hardcode SQQQ trigger test to V exits only.
// v028     : Hardcode SQQQ trigger test to BB exits only; add comment-only SQQQ sweep log.
// v027     : Hardcode SQQQ trigger test to RC exits only.
// v026     : Hardcode SQQQ trigger test to BM exits only.
// v025     : Hardcode SQQQ trigger test to TSL exits only.
// v024     : Hardcode SQQQ trigger test to DSMA exits only.
// v023     : Hardcode SQQQ trigger test to Brk exits only.
// v022     : Hardcode SQQQ trigger test to SLead exits only.
// v021     : Hardcode SQQQ trigger test to RCL exits only.
// v020     : Hardcode SQQQ trigger test to RG exits only.
// v019     : Hardcode first SQQQ trigger test to SL exits only.
// v018     : Add SQQQ buy trigger checkboxes by TQQQ exit label.
// v017     : Restrict SQQQ simulation buys to defensive TQQQ exits only.
// v016     : Repurpose Trade Period Debug as compact TQQQ/SQQQ trade viewer.
// v015     : Remove SQQQ debug-table columns to clear TradingView main-body limit.
// v014     : Add compact SQQQ snapshots to Trade Period Debug rows.
// v013     : Fold compact SQQQ simulation summary into Panel 1 to shorten main body.
// v012     : Simplify SQQQ simulation Panel 5 to avoid Pine local-variable limit.
// v011     : Add default-OFF SQQQ flat-period simulation with separate Panel 5.
// v010     : Lock tested R1-R4 Bars Before Buy defaults.
// v009     : Remove R0 entry test controls; add Bars Before Buy to R1-R4 entries.
// v008     : Add R0 cooldown and no-buy-last-hour entry test controls.
// v007     : Remove per-regime VIX SMA tuning fields; use shared master SMA for all regimes.
// v006     : Split shared master regime detection from per-regime VIX SMA tuning.
// v005     : Normalize R0-R4 regime settings section order and naming.
// v004     : Move R0 inputs into contiguous Strategy 6 regime settings block.
// v003     : Move R2/R3/R4 inputs into contiguous Strategy 6 regime settings blocks.
// v002     : Move R1 inputs into one contiguous Strategy 6 R1 settings block.
// v001     : Create Strategy 6 sandbox from Strategy 5 v266; start regime-based settings layout.
// Source   : Strategy 5 v266 baseline.
//
// SQQQ single-trigger sweep log, 2020-01-01 to 2025-12-31.
// TQQQ baseline: +12,925,433.5%, 356 trades, 85.4% win, B&H +386.8%.
// TQQQ sell counts by condition: use "Sell Count By Entry Regime" table Total column.
// Tested SQQQ triggers:
// 1) SL only:     +28.6%,  $128.6,  5 trades
// 2) RG only:     +66.9%,  $166.9, 19 trades
// 3) RCL only:    +75.1%,  $175.1, 10 trades
// 4) SLead only:  +31.0%,  $131.0,  4 trades
// 5) Brk only:     +5.1%,  $105.1,  3 trades
// 6) DSMA only:   +62.0%,  $162.0, 10 trades
// 7) TSL only:   +477.8%,  $577.8, 51 trades
// 8) BM only:     +79.4%,  $179.4, 59 trades
// 9) RC only:      +4.3%,  $104.3, 34 trades
// 10) BB only:    +21.4%,  $121.4,  9 trades
// 11) V only:       +0.0%,  $100.0,  0 trades
// 12) FV only:      +0.5%,  $100.5,  1 trade
// 13) EOD only:    +49.1%,  $149.1,  9 trades
// 14) GapFail only: +0.0%,  $100.0,  0 trades
// 15) GapFail2 only: +10.9%, $110.9,  3 trades
// Current test: PT only.
// ============================================================
// INPUTS — group order = first declaration (Performance & debug first)
// ============================================================
useStartDate = input.bool(false, "Use Date Range [OFF]", group="01 — Performance & display")
perfStartDate = input.time(timestamp("2020-01-01 00:00"), "Start Date", inline="perfStart", group="01 — Performance & display")
perfEndDate = input.time(timestamp("2020-12-31 23:59"), "End Date", inline="perfEnd", group="01 — Performance & display")
showInfoTable = input.bool(true, "Show Info Table [ON]", group="01 — Performance & display")
showLabels = input.bool(true, "Show Price Labels [ON]", group="01 — Performance & display")
showRegimeBackground = input.bool(true, "Show regime background tint [ON]", group="01 — Performance & display")
showInfoPanel1 = input.bool(true, "Info table — Panel 1 summary [ON]", group="01 — Performance & display")
showInfoPanel2 = input.bool(true, "Info table — Panel 2 regimes & VIX [ON]", group="01 — Performance & display")
showInfoPanel3 = input.bool(true, "Info table — Panel 3 position [ON]", group="01 — Performance & display")
showInfoPanel4 = input.bool(true, "Info table — Panel 4 performance [ON]", group="01 — Performance & display")
panel4PerfSource = input.string("TQQQ Strategy", "Panel 4 performance source", options=["TQQQ Strategy", "Continuous T/S"], group="01 — Performance & display")
s2_sqqqShowStats = input.bool(true, "Info Table — Panel 5 SQQQ Triggers [ON]", group="01 — Performance & display", tooltip="Shows the SQQQ Trigger Research table: SQQQ trade performance from each TQQQ sell label to the next TQQQ buy, including per-entry-regime returns (R0..R4).")

s2_sqqqSimEnable = input.bool(false, "Enable SQQQ Simulation [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════", tooltip="Virtual test only: buys SQQQ after selected TQQQ exits, then sells SQQQ on the next TQQQ buy.")
s2_sqqqContinuous = input.bool(false, "Trade SQQQ When TQQQ Flat [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════", tooltip="Continuous research curve: when checked, selected TQQQ sells move the combined equity into SQQQ until the next TQQQ buy.")
s2_blk1t = input.string("RC", "Block 1", inline="sqb1", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════", tooltip="Each row = one trigger × regime cell EXCLUDED from actual SQQQ trading (sim + continuous). The trigger stays ON and the cell still shows in the research table. Set either box to (none) to disable a row. Defaults block the 5 cells not worth the inverse-ETF risk: RC-R1 (-2.6%), RC-R2 (-11.5%), BM-R1 (+0.1%), FV-R0 (+0.5%), Brk-R2 (+1.1%).")
s2_blk1r = input.string("R1", "×", inline="sqb1", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk2t = input.string("RC", "Block 2", inline="sqb2", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk2r = input.string("R2", "×", inline="sqb2", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk3t = input.string("BM", "Block 3", inline="sqb3", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk3r = input.string("R1", "×", inline="sqb3", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk4t = input.string("FV", "Block 4", inline="sqb4", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk4r = input.string("R0", "×", inline="sqb4", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk5t = input.string("Brk", "Block 5", inline="sqb5", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk5r = input.string("R2", "×", inline="sqb5", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk6t = input.string("(none)", "Block 6", inline="sqb6", options=["(none)","PT","SL","TSL","BB","BM","V","RC","RG","SLead","Brk","RCL","FV","EOD","GapFail","GapFail2","DSMA"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_blk6r = input.string("(none)", "×", inline="sqb6", options=["(none)","R0","R1","R2","R3","R4"], group="══════ SQQQ Flat-Period Simulation TEST ══════")
sqqqBlockList = (s2_blk1t == "(none)" or s2_blk1r == "(none)" ? "" : s2_blk1t + "-" + s2_blk1r + ",") + (s2_blk2t == "(none)" or s2_blk2r == "(none)" ? "" : s2_blk2t + "-" + s2_blk2r + ",") + (s2_blk3t == "(none)" or s2_blk3r == "(none)" ? "" : s2_blk3t + "-" + s2_blk3r + ",") + (s2_blk4t == "(none)" or s2_blk4r == "(none)" ? "" : s2_blk4t + "-" + s2_blk4r + ",") + (s2_blk5t == "(none)" or s2_blk5r == "(none)" ? "" : s2_blk5t + "-" + s2_blk5r + ",") + (s2_blk6t == "(none)" or s2_blk6r == "(none)" ? "" : s2_blk6t + "-" + s2_blk6r + ",")
s2_sqqqAll = input.bool(false, "All ranked triggers [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════", tooltip="When checked, every ranked TQQQ sell label below can buy SQQQ.")
s2_sqqqTsl = input.bool(false, "01 — TSL only (+191.8%, 46t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqBm = input.bool(false, "02 — BM only (+169.9%, 53t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqRcl = input.bool(false, "03 — RCL only (+171.2%, 19t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqRg = input.bool(false, "04 — RG only (+112.1%, 16t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqDsma = input.bool(false, "05 — DSMA only (+76.0%, 10t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqEod = input.bool(false, "06 — EOD only (+20.3%, 4t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqSlead = input.bool(false, "07 — SLead only (+33.2%, 3t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqSl = input.bool(false, "08 — SL only (+29.8%, 6t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqBb = input.bool(false, "09 — BB only (+25.3%, 13t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqGapFail2 = input.bool(false, "10 — GapFail2 only (+37.2%, 2t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqBrk = input.bool(false, "11 — Brk only (+5.1%, 3t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqRc = input.bool(false, "12 — RC only (-7.4%, 30t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqFv = input.bool(false, "13 — FV only (+0.5%, 1t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqV = input.bool(false, "14 — V only (+0.0%, 0t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqGapFail = input.bool(false, "15 — GapFail only (+0.0%, 0t) [OFF]", group="══════ SQQQ Flat-Period Simulation TEST ══════")
s2_sqqqPt = input.bool(true, "16 — PT only (+1,250.9%, 136t) [ON]", group="══════ SQQQ Flat-Period Simulation TEST ══════")

s2_rclLockRegimeAware = input.bool(true, "Regime-aware RCL buy lock [ON]", group="══════ RC Lifecycle Lock Regime-Aware ══════", tooltip="VALIDATED default ON with Cross-regime block bars = 21. OFF = original behavior: an RC Stoch Lifecycle buy lock blocks buys in ALL regimes until it releases. ON = for the first N cross-regime bars the lock blocks all regimes, then it only blocks buys while we are still in the regime that armed it (rclBuyLockSrc == current regime); in other regimes it goes dormant but keeps counting toward its max-bar cap and watching for oversold recovery. With N=21 (~3 trading days on 1h) ON reproduces the 12.9M% baseline exactly on 2020-2025 while being bounded and never getting stuck across regimes — the live-correct behavior.")
s2_rclCrossRegimeBars = input.int(21, "Cross-regime block bars [21]", minval=0, maxval=100, group="══════ RC Lifecycle Lock Regime-Aware ══════", tooltip="Only used when 'Regime-aware RCL buy lock' is ON. After a lifecycle sell, block buys in ALL regimes for this many bars, then fall back to regime-aware (arming-regime-only). 0 = pure regime-aware from the first bar; larger = behaves like the global lock for this many bars. VALIDATED = 21 (~3 trading days on 1h): the threshold at/above which the backtest is identical to the global lock (12.9M% / 342 trades); below ~21 it drops to ~10.5M% / 338 trades. Bounded, so it can never get stuck across regimes.")

s2_costEnable = input.bool(false, "Enable cost/slippage haircut [OFF]", group="══════ Cost / Slippage Robustness TEST ══════", tooltip="Robustness check. OFF = frictionless baseline (12.9M%). ON = subtract 'Round-trip cost %' from every trade's realized return before it compounds — equity, win rate, per-regime comp, buckets and Sharpe all then reflect costs. Does NOT change which trades are taken (entries/exits use live P&L and are unchanged); it only haircuts the reported/realized P&L. Markers and labels also show the net return.")
s2_costRoundTrip = input.float(0.10, "Round-trip cost % per trade [0.10]", minval=0.0, maxval=5.0, step=0.01, group="══════ Cost / Slippage Robustness TEST ══════", tooltip="Total round-trip friction per trade (commission + bid/ask spread + slippage) as a percent subtracted from each trade's entry-to-exit return. Typical liquid-ETF retail estimate ~0.05-0.20%. Applied only when the haircut is enabled.")
// Strategy 6 shared regime map — these decide which regime is active.
s2_masterVixSmaLength = input.int(25, "Master VIX SMA Length [25]", minval=2, maxval=200, group="══════ S6 Shared 0.1 — Regime Detection ══════")
s2_masterSlopeLookback = input.int(10, "Slope Lookback [10]", minval=1, maxval=50, group="══════ S6 Shared 0.1 — Regime Detection ══════")
s2_masterR0MaxSma = input.float(13.85, "R0 Ceiling / R3-R4 Floor [13.85]", minval=5.0, maxval=30.0, step=0.05, group="══════ S6 Shared 0.1 — Regime Detection ══════")
s2_masterR1MinSma = input.float(19.8, "R1-R2 Floor [19.8]", minval=5.0, maxval=50.0, step=0.1, group="══════ S6 Shared 0.1 — Regime Detection ══════")

s2_useR0 = input.bool(true, "Enable Regime 0 [ON]", group="══════ S6 R0.2 — Entry ══════")
s2_r0ConfirmBars = input.int(3, "Bars Before Buy [3]", minval=1, maxval=20, group="══════ S6 R0.2 — Entry ══════")

s2_r0FastVixExit = input.float(16.4, "Fast VIX Exit [16.4]", minval=10.0, maxval=40.0, step=0.1, group="══════ S6 R0.5 — Core Exits ══════")
s2_r0PT = input.float(7.0, "Profit Target % [7]", minval=0.0, maxval=50.0, step=0.5, group="══════ S6 R0.5 — Core Exits ══════")
s2_r0SL = input.float(-7.0, "Stop Loss % [-7]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R0.5 — Core Exits ══════")

s2_rcBmWaitR0Enable = input.bool(true, "Enable RC BM wait R0 [ON]", group="══════ S6 R0.7 — Buy Blockers / RC Waits ══════", tooltip="Locked: after BM sell, block RC buys in chart R0 for the wait bars below.")
s2_rcBmWaitR0Bars = input.int(20, "Wait bars after BM sell [20]", minval=0, maxval=50, group="══════ S6 R0.7 — Buy Blockers / RC Waits ══════", tooltip="0 = no wait. Applies only to RC buys in chart R0 after BM sell.")

s2_rcl0R0Enable = input.bool(true, "Enable R0 RC Stoch Lifecycle [ON]", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════", tooltip="Regime 0 trade: hold while K/D embed above zone; sell on unwind + falling K/D; block all buys until oversold embed clears and K/D recover above zone low.")
s2_rcl0RcOnly = input.bool(false, "RC entries only [OFF]", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0MinBars = input.int(4, "Min bars after entry [4]", minval=1, maxval=200, inline="rcl0Bars", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0MaxBars = input.int(70, "Max bars after entry [70]", minval=1, maxval=200, inline="rcl0Bars", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0EmbedBarsHigh = input.int(9, "Embed bars above zone [9]", minval=1, maxval=20, group="══════ S6 R0.8 — RC Stoch Lifecycle ══════", tooltip="K and D both above overbought zone for this many consecutive bars arms hold-through embed.")
s2_rcl0ZoneHigh = input.float(95.0, "Overbought zone above [95]", minval=50.0, maxval=95.0, step=1.0, group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0EmbedBarsLow = input.int(3, "Embed bars below zone [3]", minval=1, maxval=20, group="══════ S6 R0.8 — RC Stoch Lifecycle ══════", tooltip="Either K or D below oversold zone for this many consecutive bars — required before buy block can release.")
s2_rcl0ZoneLow = input.float(20.0, "Oversold zone below [20]", minval=5.0, maxval=40.0, step=1.0, group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0MaxBuyLockBars = input.int(35, "Max buy-lock bars [35]", minval=1, maxval=200, group="══════ S6 R0.8 — RC Stoch Lifecycle ══════", tooltip="Safety cap: after an R0 lifecycle sell, force-release the buy lock after this many bars if the normal oversold recovery has not happened.")
s2_rcl0ReleaseCloseUp = input.bool(true, "R0 release needs close > prior close [ON]", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")
s2_rcl0ExitMarker = input.bool(true, "Show exit marker [ON]", group="══════ S6 R0.8 — RC Stoch Lifecycle ══════")

s2_useR1 = input.bool(true, "Enable Regime 1 [ON]", group="══════ S6 R1.2 — Entry ══════")
s2_r1ConfirmBars = input.int(1, "Bars Before Buy [1]", minval=1, maxval=20, group="══════ S6 R1.2 — Entry ══════")
s2_r1Cooldown = input.int(2, "Min Bars Between Trades [2]", minval=0, maxval=50, group="══════ S6 R1.2 — Entry ══════")
s2_r1NoBuyLastBar = input.bool(false, "No Buy Last Hour [OFF]", group="══════ S6 R1.2 — Entry ══════")
s2_r1BuyPct = input.float(6.0, "Buy when VIX % above SMA reaches [6]", minval=1.0, maxval=30.0, step=0.5, group="══════ S6 R1.2 — Entry ══════")

s2_r1AtrRiskFilter = input.bool(true, "Enable R1 ATR Risk Filter [ON]", group="══════ S6 R1.3 — Buy Filters ══════")
s2_r1AtrRiskLength = input.int(28, "ATR length [28]", minval=1, maxval=100, group="══════ S6 R1.3 — Buy Filters ══════")
s2_r1AtrRiskMaxPct = input.float(11.0, "Block R1 buy if ATR% above [11]", minval=0.1, maxval=30.0, step=0.1, group="══════ S6 R1.3 — Buy Filters ══════")
s2_r1AtrRiskRequireRising = input.bool(true, "Require ATR% rising [ON]", group="══════ S6 R1.3 — Buy Filters ══════")

s2_bbBuyUseR1 = input.bool(true, "Use BB buy filters [ON]", group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1Match = input.string("ANY", "Match [ANY]", options=["ALL", "ANY"], group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1Lower = input.bool(false, "Req lower BB", inline="r1a", group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1BelowMid = input.bool(false, "Below mid", inline="r1a", group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1LowerHalf = input.bool(true, "Lower ½", inline="r1a", group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1NotUpper = input.bool(false, "Not at upper", inline="r1a", group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1Lb = input.int(0, "Lower BB lookback [0]", minval=0, maxval=50, group="══════ S6 R1.4 — BB Buy Filters ══════")
s2_bbBuyR1MinBelow = input.int(0, "Min bars below mid [0]", minval=0, maxval=20, group="══════ S6 R1.4 — BB Buy Filters ══════")

s2_r1PT = input.float(1.55, "Profit Target % [1.55]", minval=0.0, maxval=30.0, step=0.25, group="══════ S6 R1.5 — Core Exits ══════")
s2_r1SL = input.float(-16.5, "Stop Loss % [-16.5]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R1.5 — Core Exits ══════")
s2_r1SellPct = input.float(-2.0, "VIX cooldown sell threshold [% vs VIX SMA] [-2]", minval=-30.0, maxval=20.0, step=0.5, group="══════ S6 R1.5 — Core Exits ══════", tooltip="Only active when R1 Exit Permissions allow VIX cooldown exit. Sell condition is VIX % vs SMA <= this threshold.")
s2_r1Eod = input.bool(false, "End of Day Sell [OFF]", group="══════ S6 R1.5 — Core Exits ══════")
s2_r1EodMinProfit = input.float(1.0, "EOD Min Profit % [1]", minval=-10.0, maxval=20.0, step=0.5, group="══════ S6 R1.5 — Core Exits ══════")

s2_bbR1Master = input.bool(true, "Enable R1 exit permissions [ON]", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1ExitPT = input.bool(true, "Allow PT exit [ON]", inline="bb1x", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1ExitBb = input.bool(true, "BB↑ [ON]", inline="bb1x", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1ExitVix = input.bool(false, "VIX cooldown [OFF]", inline="bb1x", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════", tooltip="Enables the R1 VIX cooldown sell threshold in R1.5 Core Exits.")
s2_bbR1ExitSL = input.bool(true, "SL [ON]", inline="bb1y", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1ExitEod = input.bool(false, "EOD [OFF]", inline="bb1y", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1ExitRc = input.bool(true, "RC [ON]", inline="bb1y", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1BbWait = input.bool(true, "BB↑ wait for pullback [ON]", group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")
s2_bbR1BbMaxWait = input.int(1, "BB↑ max wait bars [1]", minval=1, maxval=20, group="══════ S6 R1.6 — Exit Permissions / BB Sell ══════")

s2_rcSLeadWaitR1Enable = input.bool(true, "Enable SLead wait R1 [ON]", group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="After SLead sell, block R1-targeted buys for the R1 wait bars below.")
s2_rcSLeadWaitR1Bars = input.int(12, "Wait bars after SLead sell R1 [12]", minval=0, maxval=210, group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="0 = no wait. Applies to R1-targeted RC buys, and regular R1 buys when that option is ON.")
s2_rcSLeadRecRegularR1 = input.bool(true, "Also block regular R1 buys [ON]", group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="When ON, the SLead wait can block regular green R1 buys too, not only orange RC buys.")
s2_rcSLeadRecEnable = input.bool(true, "Enable SLead stoch recovery [ON]", group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="TEST: SLead wait starts after SLead sell, but can release early after hard wait only if SLead stochastic recovers and price confirms above BB buy mid. Re-blocks if stochastic/price weaken.")
s2_rcSLeadRecMinBars = input.int(6, "Minimum hard wait bars [6]", minval=0, maxval=210, group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════")
s2_rcSlTslWaitEnable = input.bool(true, "Enable RC SL/TSL wait R1 [ON]", group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="Locked: after SL or TSL sell, block RC buys in chart R1 for the wait bars below.")
s2_rcSlTslWaitBars = input.int(6, "Wait bars after SL/TSL sell [6]", minval=0, maxval=50, group="══════ S6 R1.7 — Buy Blockers / RC Waits ══════", tooltip="0 = no wait. Applies only to RC buys in chart R1 after SL or TSL sell.")

s2_rcl1R1Enable = input.bool(true, "Enable R1 RC Stoch Lifecycle [ON]", group="══════ S6 R1.8 — RC Stoch Lifecycle ══════", tooltip="RC trade: hold while K/D embed above zone; sell on unwind + falling K/D; block all buys until oversold embed clears and K/D recover above zone low.")
s2_rcl1RcOnly = input.bool(false, "RC entries only [OFF]", group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")
s2_rcl1MinBars = input.int(1, "Min bars after entry [1]", minval=1, maxval=200, inline="rcl1Bars", group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")
s2_rcl1MaxBars = input.int(6, "Max bars after entry [6]", minval=1, maxval=200, inline="rcl1Bars", group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")
s2_rcl1EmbedBarsHigh = input.int(3, "Embed bars above zone [3]", minval=1, maxval=20, group="══════ S6 R1.8 — RC Stoch Lifecycle ══════", tooltip="K and D both above overbought zone for this many consecutive bars arms hold-through embed.")
s2_rcl1ZoneHigh = input.float(78.0, "Overbought zone above [78]", minval=50.0, maxval=95.0, step=1.0, group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")
s2_rcl1EmbedBarsLow = input.int(3, "Embed bars below zone [3]", minval=1, maxval=20, group="══════ S6 R1.8 — RC Stoch Lifecycle ══════", tooltip="Either K or D below oversold zone for this many consecutive bars — required before buy block can release.")
s2_rcl1ZoneLow = input.float(14.0, "Oversold zone below [14]", minval=5.0, maxval=40.0, step=1.0, group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")
s2_rcl1MaxBuyLockBars = input.int(42, "Max buy-lock bars [42]", minval=1, maxval=200, group="══════ S6 R1.8 — RC Stoch Lifecycle ══════", tooltip="Safety cap: after an R1 lifecycle sell, force-release the buy lock after this many bars if the normal oversold recovery has not happened.")
s2_rcl1ExitMarker = input.bool(true, "Show exit marker [ON]", group="══════ S6 R1.8 — RC Stoch Lifecycle ══════")

s2_useR2 = input.bool(true, "Enable Regime 2 [ON]", group="══════ S6 R2.2 — Entry ══════")
s2_r2ConfirmBars = input.int(21, "Bars Before Buy [21]", minval=1, maxval=100, group="══════ S6 R2.2 — Entry ══════")
s2_r2Cooldown = input.int(10, "Min Bars Between Trades [10]", minval=0, maxval=50, group="══════ S6 R2.2 — Entry ══════")
s2_r2NoBuyLastBar = input.bool(false, "No Buy Last Hour [OFF]", group="══════ S6 R2.2 — Entry ══════")
s2_r2BuyPct = input.float(6.5, "Buy when VIX % above SMA reaches [6.5]", minval=1.0, maxval=30.0, step=0.5, group="══════ S6 R2.2 — Entry ══════")

s2_r2GuardMaster = input.bool(true, "Enable R2 Risk Guard [ON]", group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardEarlyExit = input.bool(true, "R2 Early Failure Exit [ON]", group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardEarlyBars = input.int(6, "Bars after entry [6]", minval=1, maxval=100, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardEarlyPnl = input.float(-3.1, "If trade P&L below % [-3.1]", minval=-30.0, maxval=10.0, step=0.1, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardVixWorsen = input.float(2.0, "And VIX% worsened by [2]", minval=0.0, maxval=100.0, step=0.5, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardMaxBarsExit = input.bool(true, "R2 Max Bars Exit [ON]", group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardMaxBars = input.int(21, "Max bars in R2 trade [21]", minval=1, maxval=200, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardMaxBarsPnl = input.float(1.5, "Only exit if P&L below % [1.5]", minval=-30.0, maxval=20.0, step=0.5, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardTighterSL = input.bool(false, "R2 Tighter SL Override [OFF]", group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")
s2_r2GuardSL = input.float(-2.0, "R2 Guard Stop Loss % [-2]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R2.3 — Buy Filters / Risk Guard ══════")

s2_bbBuyUseR2 = input.bool(true, "Use BB buy filters [ON]", group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2Match = input.string("ANY", "Match [ANY]", options=["ALL", "ANY"], group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2Lower = input.bool(false, "Req lower BB", inline="r2a", group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2BelowMid = input.bool(true, "Below mid", inline="r2a", group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2LowerHalf = input.bool(false, "Lower ½", inline="r2a", group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2NotUpper = input.bool(false, "Not at upper", inline="r2a", group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2Lb = input.int(0, "Lower BB lookback [0]", minval=0, maxval=50, group="══════ S6 R2.4 — BB Buy Filters ══════")
s2_bbBuyR2MinBelow = input.int(9, "Min bars below mid [9]", minval=0, maxval=20, group="══════ S6 R2.4 — BB Buy Filters ══════")

s2_r2PT = input.float(9.0, "Profit Target % [9]", minval=0.0, maxval=30.0, step=0.25, group="══════ S6 R2.5 — Core Exits ══════")
s2_r2SL = input.float(-3.0, "Stop Loss % [-3]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R2.5 — Core Exits ══════")
s2_r2SellPct = input.float(-3.0, "VIX cooldown sell threshold [% vs VIX SMA] [-3]", minval=-10.0, maxval=70.0, step=0.5, group="══════ S6 R2.5 — Core Exits ══════")
s2_r2Eod = input.bool(false, "End of Day Sell [OFF]", group="══════ S6 R2.5 — Core Exits ══════")
s2_r2EodMinProfit = input.float(1.0, "EOD Min Profit % [1]", minval=-10.0, maxval=20.0, step=0.5, group="══════ S6 R2.5 — Core Exits ══════")

s2_bbR2Master = input.bool(true, "Enable R2 exit permissions [ON]", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitPT = input.bool(true, "Allow PT exit [ON]", inline="bb2x", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitBb = input.bool(true, "BB↑ [ON]", inline="bb2x", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitVix = input.bool(false, "VIX cooldown [OFF]", inline="bb2x", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitSL = input.bool(false, "SL [OFF]", inline="bb2y", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitEod = input.bool(false, "EOD [OFF]", inline="bb2y", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2ExitRc = input.bool(true, "RC [ON]", inline="bb2y", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2BbWait = input.bool(false, "BB↑ wait for pullback [OFF]", group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")
s2_bbR2BbMaxWait = input.int(5, "BB↑ max wait bars [5]", minval=1, maxval=20, group="══════ S6 R2.6 — Exit Permissions / BB Sell ══════")

s2_rcbdR2Enable = input.bool(true, "Enable R2 RC Breakdown [ON]", group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_rcbdR2RcOnly = input.bool(false, "R2 RC entries only [OFF]", group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_rcbdR2MinBars = input.int(1, "R2 min bars after entry [1]", minval=1, maxval=200, group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_gbfR2Enable = input.bool(true, "Enable R2 gap bounce fail [ON]", group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_gbf2MinMfe = input.float(5.0, "R2 MFE arm % [5]", minval=0.0, maxval=50.0, step=0.1, group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_gbf2MinGap = input.float(3.5, "R2 gap dn % [3.5]", minval=0.0, maxval=20.0, step=0.1, group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")
s2_gbf2MinPnl = input.float(-3.0, "R2 min PnL % [-3]", minval=-50.0, maxval=50.0, step=0.1, group="══════ S6 R2.7 — RC Exit Helpers / Waits ══════")

s2_rcl2R2Enable = input.bool(true, "Enable R2 RC Stoch Lifecycle [ON]", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════", tooltip="RC trade: hold while K/D embed above zone; sell on unwind + falling K/D; block all buys until oversold embed clears and K/D recover above zone low.")
s2_rcl2RcOnly = input.bool(false, "RC entries only [OFF]", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2MinBars = input.int(2, "Min bars after entry [2]", minval=1, maxval=200, inline="rcl2Bars", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2MaxBars = input.int(28, "Max bars after entry [28]", minval=1, maxval=200, inline="rcl2Bars", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2EmbedBarsHigh = input.int(3, "Embed bars above zone [3]", minval=1, maxval=20, group="══════ S6 R2.8 — RC Stoch Lifecycle ══════", tooltip="K and D both above overbought zone for this many consecutive bars arms hold-through embed.")
s2_rcl2ZoneHigh = input.float(95.0, "Overbought zone above [95]", minval=50.0, maxval=95.0, step=1.0, group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2EmbedBarsLow = input.int(3, "Embed bars below zone [3]", minval=1, maxval=20, group="══════ S6 R2.8 — RC Stoch Lifecycle ══════", tooltip="Either K or D below oversold zone for this many consecutive bars — required before buy block can release.")
s2_rcl2ZoneLow = input.float(20.0, "Oversold zone below [20]", minval=5.0, maxval=40.0, step=1.0, group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2MaxBuyLockBars = input.int(8, "Max buy-lock bars [8]", minval=1, maxval=200, group="══════ S6 R2.8 — RC Stoch Lifecycle ══════", tooltip="Safety cap: after an R2 lifecycle sell, force-release the buy lock after this many bars if the normal oversold recovery has not happened.")
s2_rcl2ReleaseCloseUp = input.bool(true, "R2 release needs close > prior close [ON]", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")
s2_rcl2ExitMarker = input.bool(true, "Show exit marker [ON]", group="══════ S6 R2.8 — RC Stoch Lifecycle ══════")

s2_useR3 = input.bool(true, "Enable Regime 3 [ON]", group="══════ S6 R3.2 — Entry ══════")
s2_r3ConfirmBars = input.int(5, "Bars Before Buy [5]", minval=1, maxval=20, group="══════ S6 R3.2 — Entry ══════")
s2_r3Cooldown = input.int(9, "Min Bars Between Trades [9]", minval=0, maxval=50, group="══════ S6 R3.2 — Entry ══════")
s2_r3NoBuyLastBar = input.bool(false, "No Buy Last Hour [OFF]", group="══════ S6 R3.2 — Entry ══════")
s2_r3BuyPct = input.float(9.0, "Buy when VIX % above SMA reaches [9]", minval=1.0, maxval=30.0, step=0.5, group="══════ S6 R3.2 — Entry ══════")

s2_bbBuyUseR3 = input.bool(true, "Use BB buy filters [ON]", group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3Match = input.string("ANY", "Match [ANY]", options=["ALL", "ANY"], group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3Lower = input.bool(false, "Req lower BB", inline="r3a", group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3BelowMid = input.bool(true, "Below mid", inline="r3a", group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3LowerHalf = input.bool(false, "Lower ½", inline="r3a", group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3NotUpper = input.bool(false, "Not at upper", inline="r3a", group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3Lb = input.int(0, "Lower BB lookback [0]", minval=0, maxval=50, group="══════ S6 R3.4 — BB Buy Filters ══════")
s2_bbBuyR3MinBelow = input.int(0, "Min bars below mid [0]", minval=0, maxval=20, group="══════ S6 R3.4 — BB Buy Filters ══════")

s2_r3PT = input.float(1.25, "Profit Target % [1.25]", minval=0.0, maxval=30.0, step=0.25, group="══════ S6 R3.5 — Core Exits ══════")
s2_r3SL = input.float(-12.5, "Stop Loss % [-12.5]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R3.5 — Core Exits ══════")
s2_r3SellPct = input.float(-4.5, "VIX cooldown sell threshold [% vs VIX SMA] [-4.5]", minval=-10.0, maxval=20.0, step=0.5, group="══════ S6 R3.5 — Core Exits ══════")
s2_r3Eod = input.bool(true, "End of Day Sell [ON]", group="══════ S6 R3.5 — Core Exits ══════")
s2_r3EodMinProfit = input.float(0.5, "EOD Min Profit % [0.5]", minval=-10.0, maxval=20.0, step=0.5, group="══════ S6 R3.5 — Core Exits ══════")

s2_bbR3Master = input.bool(true, "Enable R3 exit permissions [ON]", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitPT = input.bool(true, "Allow PT exit [ON]", inline="bb3x", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitBb = input.bool(true, "BB↑ [ON]", inline="bb3x", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitVix = input.bool(false, "VIX cooldown [OFF]", inline="bb3x", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitSL = input.bool(true, "SL [ON]", inline="bb3y", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitEod = input.bool(true, "EOD [ON]", inline="bb3y", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3ExitRc = input.bool(true, "RC [ON]", inline="bb3y", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3BbWait = input.bool(false, "BB↑ wait for pullback [OFF]", group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")
s2_bbR3BbMaxWait = input.int(5, "BB↑ max wait bars [5]", minval=1, maxval=20, group="══════ S6 R3.6 — Exit Permissions / BB Sell ══════")

s2_rcPtWaitR3Enable = input.bool(true, "Enable RC PT wait R3 [ON]", group="══════ S6 R3.7 — Buy Blockers / RC Waits ══════", tooltip="Locked: after PT sell, block RC buys targeting R3 for the wait bars below.")
s2_rcPtWaitR3Bars = input.int(6, "Wait bars after PT sell [6]", minval=0, maxval=210, group="══════ S6 R3.7 — Buy Blockers / RC Waits ══════", tooltip="0 = no wait. Applies only to RC buys targeting R3 after PT sell.")

s2_rcl3R3Enable = input.bool(true, "Enable R3 RC Stoch Lifecycle [ON]", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════", tooltip="RC trade: hold while K/D embed above zone; sell on unwind + falling K/D; block all buys until oversold embed clears and K/D recover above zone low.")
s2_rcl3RcOnly = input.bool(false, "RC entries only [OFF]", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3MinBars = input.int(2, "Min bars after entry [2]", minval=1, maxval=200, inline="rcl3Bars", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3MaxBars = input.int(21, "Max bars after entry [21]", minval=1, maxval=200, inline="rcl3Bars", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3EmbedBarsHigh = input.int(3, "Embed bars above zone [3]", minval=1, maxval=20, group="══════ S6 R3.8 — RC Stoch Lifecycle ══════", tooltip="K and D both above overbought zone for this many consecutive bars arms hold-through embed.")
s2_rcl3ZoneHigh = input.float(78.0, "Overbought zone above [78]", minval=50.0, maxval=95.0, step=1.0, group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3EmbedBarsLow = input.int(3, "Embed bars below zone [3]", minval=1, maxval=20, group="══════ S6 R3.8 — RC Stoch Lifecycle ══════", tooltip="Either K or D below oversold zone for this many consecutive bars — required before buy block can release.")
s2_rcl3ZoneLow = input.float(20.0, "Oversold zone below [20]", minval=5.0, maxval=40.0, step=1.0, group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3MaxBuyLockBars = input.int(7, "Max buy-lock bars [7]", minval=1, maxval=200, group="══════ S6 R3.8 — RC Stoch Lifecycle ══════", tooltip="Safety cap: after an R3 lifecycle sell, force-release the buy lock after this many bars if the normal oversold recovery has not happened.")
s2_rcl3ReleaseCloseUp = input.bool(true, "R3 release needs close > prior close [ON]", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")
s2_rcl3ExitMarker = input.bool(true, "Show exit marker [ON]", group="══════ S6 R3.8 — RC Stoch Lifecycle ══════")

s2_useR4 = input.bool(true, "Enable Regime 4 [ON]", group="══════ S6 R4.2 — Entry ══════")
s2_r4ConfirmBars = input.int(2, "Bars Before Buy [2]", minval=1, maxval=20, group="══════ S6 R4.2 — Entry ══════")
s2_r4Cooldown = input.int(2, "Min Bars Between Trades [2]", minval=0, maxval=50, group="══════ S6 R4.2 — Entry ══════")
s2_r4NoBuyLastBar = input.bool(true, "No Buy Last Hour [ON]", group="══════ S6 R4.2 — Entry ══════")
s2_r4BuyPct = input.float(4.0, "Buy when VIX % above SMA reaches [4]", minval=1.0, maxval=30.0, step=0.1, group="══════ S6 R4.2 — Entry ══════")

s2_r4GuardMaster = input.bool(true, "Enable R4 Risk Guard [ON]", group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardEarlyExit = input.bool(true, "R4 Early Failure Exit [ON]", group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardEarlyBars = input.int(11, "Bars after entry [11]", minval=1, maxval=100, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardEarlyPnl = input.float(-10.0, "If trade P&L below % [-10]", minval=-30.0, maxval=10.0, step=0.5, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardVixWorsen = input.float(15.5, "And VIX% worsened by [15.5]", minval=0.0, maxval=100.0, step=0.5, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardMaxBarsExit = input.bool(false, "R4 Max Bars Exit [OFF]", group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardMaxBars = input.int(24, "Max bars in R4 trade [24]", minval=1, maxval=200, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardMaxBarsPnl = input.float(11.0, "Only exit if P&L below % [11]", minval=-30.0, maxval=20.0, step=0.5, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardTighterSL = input.bool(false, "R4 Tighter SL Override [OFF]", group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")
s2_r4GuardSL = input.float(-5.5, "R4 Guard Stop Loss % [-5.5]", minval=-30.0, maxval=-0.5, step=0.5, group="══════ S6 R4.3 — Buy Filters / Risk Guard ══════")

s2_bbBuyUseR4 = input.bool(true, "Use BB buy filters [ON]", group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4Match = input.string("ANY", "Match [ANY]", options=["ALL", "ANY"], group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4Lower = input.bool(false, "Req lower BB", inline="r4a", group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4BelowMid = input.bool(true, "Below mid", inline="r4a", group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4LowerHalf = input.bool(false, "Lower ½", inline="r4a", group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4NotUpper = input.bool(false, "Not at upper", inline="r4a", group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4Lb = input.int(0, "Lower BB lookback [0]", minval=0, maxval=50, group="══════ S6 R4.4 — BB Buy Filters ══════")
s2_bbBuyR4MinBelow = input.int(0, "Min bars below mid [0]", minval=0, maxval=20, group="══════ S6 R4.4 — BB Buy Filters ══════")

s2_r4PT = input.float(3.25, "Profit Target % [3.25]", minval=0.0, maxval=30.0, step=0.25, group="══════ S6 R4.5 — Core Exits ══════")
s2_r4SL = input.float(-11.4, "Stop Loss % [-11.4]", minval=-30.0, maxval=-0.5, step=0.1, group="══════ S6 R4.5 — Core Exits ══════")
s2_r4SellPct = input.float(-8.3, "VIX cooldown sell threshold [% vs VIX SMA] [-8.3]", minval=-15.0, maxval=20.0, step=0.1, group="══════ S6 R4.5 — Core Exits ══════")
s2_r4Eod = input.bool(true, "End of Day Sell [ON]", group="══════ S6 R4.5 — Core Exits ══════")
s2_r4EodMinProfit = input.float(7.0, "EOD Min Profit % [7]", minval=-10.0, maxval=20.0, step=0.5, group="══════ S6 R4.5 — Core Exits ══════")

s2_bbR4Master = input.bool(true, "Enable R4 exit permissions [ON]", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitPT = input.bool(true, "Allow PT exit [ON]", inline="bb4x", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitBb = input.bool(true, "BB↑ [ON]", inline="bb4x", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitVix = input.bool(true, "VIX cooldown [ON]", inline="bb4x", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitSL = input.bool(true, "SL [ON]", inline="bb4y", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitEod = input.bool(true, "EOD [ON]", inline="bb4y", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4ExitRc = input.bool(true, "RC [ON]", inline="bb4y", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4BbWait = input.bool(true, "BB↑ wait for pullback [ON]", group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")
s2_bbR4BbMaxWait = input.int(5, "BB↑ max wait bars [5]", minval=1, maxval=20, group="══════ S6 R4.6 — Exit Permissions / BB Sell ══════")

s2_rcbdR4Enable = input.bool(true, "Enable R4 RC Breakdown [ON]", group="══════ S6 R4.7 — RC Exit Helpers / Waits ══════")
s2_gbfR4Enable = input.bool(true, "Enable R4 gap bounce fail [ON]", group="══════ S6 R4.7 — RC Exit Helpers / Waits ══════")
s2_gapBounceMinMfe = input.float(1.1, "R4 MFE arm % [1.1]", minval=0.0, maxval=50.0, step=0.1, group="══════ S6 R4.7 — RC Exit Helpers / Waits ══════")
s2_gapBounceMinGap = input.float(2.5, "R4 gap dn % [2.5]", minval=0.0, maxval=20.0, step=0.1, group="══════ S6 R4.7 — RC Exit Helpers / Waits ══════")
s2_gapBounceMinPnl = input.float(-3.0, "R4 min PnL % [-3]", minval=-50.0, maxval=50.0, step=0.1, group="══════ S6 R4.7 — RC Exit Helpers / Waits ══════")

s2_rclR4Enable = input.bool(true, "Enable R4 RC Stoch Lifecycle [ON]", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════", tooltip="RC trade: hold while K/D embed above zone; sell on unwind + falling K/D; block all buys until oversold embed clears and K/D recover above zone low.")
s2_rclRcOnly = input.bool(false, "RC entries only [OFF]", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclMinBars = input.int(2, "Min bars after entry [2]", minval=1, maxval=200, inline="rclBars", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclMaxBars = input.int(11, "Max bars after entry [11]", minval=1, maxval=200, inline="rclBars", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclEmbedBarsHigh = input.int(5, "Embed bars above zone [5]", minval=1, maxval=20, group="══════ S6 R4.8 — RC Stoch Lifecycle ══════", tooltip="K and D both above overbought zone for this many consecutive bars arms hold-through embed.")
s2_rclZoneHigh = input.float(90.0, "Overbought zone above [90]", minval=50.0, maxval=95.0, step=1.0, group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclEmbedBarsLow = input.int(3, "Embed bars below zone [3]", minval=1, maxval=20, group="══════ S6 R4.8 — RC Stoch Lifecycle ══════", tooltip="Either K or D below oversold zone for this many consecutive bars — required before buy block can release.")
s2_rclZoneLow = input.float(10.0, "Oversold zone below [10]", minval=5.0, maxval=40.0, step=1.0, group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclMaxBuyLockBars = input.int(21, "Max buy-lock bars [21]", minval=1, maxval=200, group="══════ S6 R4.8 — RC Stoch Lifecycle ══════", tooltip="Safety cap: after an R4 lifecycle sell, force-release the buy lock after this many bars if the normal oversold recovery has not happened.")
s2_rclReleaseCloseUp = input.bool(false, "R4 release needs close > prior close TEST [OFF]", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")
s2_rclExitMarker = input.bool(true, "Show exit marker [ON]", group="══════ S6 R4.8 — RC Stoch Lifecycle ══════")

s2_sharedRcStochLen = input.int(21, "Shared RC StL [21]", minval=1, maxval=100, inline="sharedRcSt", group="══════ 07.1 — Shared RC Stochastic Settings ══════", tooltip="Shared by RC Stoch Lifecycle R0-R4, RC Breakdown Exit, RC Stoch Lead Exit, and Gap Bounce Fail.")
s2_sharedRcStochK = input.int(3, "StK [3]", minval=1, maxval=20, inline="sharedRcSt", group="══════ 07.1 — Shared RC Stochastic Settings ══════")
s2_sharedRcStochD = input.int(5, "StD [5]", minval=1, maxval=20, inline="sharedRcSt", group="══════ 07.1 — Shared RC Stochastic Settings ══════")

s2_rcbdRcOnly = input.bool(true, "RC entries only [ON]", group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMinBars = input.int(4, "Min bars after entry [4]", minval=1, maxval=200, inline="rcbdBars", group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMaxBars = input.int(30, "Max bars after entry [30]", minval=1, maxval=200, inline="rcbdBars", group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMaxMfe = input.float(0.5, "Only if MFE at or below % [0.5]", minval=0.0, maxval=10.0, step=0.1, group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMaxPnl = input.float(0.0, "Only if P&L at or below % [0]", minval=-50.0, maxval=10.0, step=0.5, group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMinPnl = input.float(-9.0, "Only if P&L above % [-9]", minval=-30.0, maxval=10.0, step=0.5, group="══════ 12 — RC Breakdown Exit ══════", tooltip="Skip if loss already deeper than this — let SL/RG handle.")
s2_rcbdMidLookback = input.int(4, "BB mid slope lookback [4]", minval=1, maxval=20, group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdVixWorsen = input.float(8.0, "VIX% worsened from entry by [8]", minval=0.0, maxval=100.0, step=0.5, group="══════ 12 — RC Breakdown Exit ══════")
s2_rcbdMarker = input.bool(true, "Show exit marker [ON]", group="══════ 12 — RC Breakdown Exit ══════")

s2_rcslR1Enable = input.bool(true, "Enable R1 RC Stoch Lead [ON]", inline="rcslRg1", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslR3Enable = input.bool(true, "Enable R3 RC Stoch Lead [ON]", inline="rcslRg1", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslR2Enable = input.bool(true, "Enable R2 RC Stoch Lead [ON]", inline="rcslRg2", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslR4Enable = input.bool(false, "Enable R4 RC Stoch Lead [OFF]", inline="rcslRg2", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslRcOnly = input.bool(true, "RC entries only [ON]", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslMinBars = input.int(4, "Min bars after entry [4]", minval=1, maxval=200, inline="rcslBars", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslMaxBars = input.int(15, "Max bars after entry [15]", minval=1, maxval=200, inline="rcslBars", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslExitCross = input.bool(true, "Exit on K cross below D [ON]", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslPtNotReached = input.bool(true, "Only if MFE below regime PT [ON]", group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslRequireTrailArmed = input.bool(true, "Only if soft trail armed [ON]", group="══════ 13 — RC Stoch Lead Exit ══════", tooltip="Requires soft trail already armed — exit on stoch lead instead of waiting for trail breach.")
s2_rcslMaxPnl = input.float(1.0, "Only if P&L at or below % [1]", minval=-50.0, maxval=50.0, step=0.5, group="══════ 13 — RC Stoch Lead Exit ══════")
s2_rcslMarker = input.bool(true, "Show exit marker [ON]", group="══════ 13 — RC Stoch Lead Exit ══════")

// Gap bounce fail — shared settings + R4/R2 enable lines (keys off entry regime).
s2_gbfGapBars = input.int(5, "Gap bars [5]", minval=1, maxval=50, group="14 — Gap Bounce Fail", tooltip="Bars to watch for bounce fail after gap down (both regimes).")
s2_gbfGapLow = input.bool(false, "Gap uses low [OFF]", group="14 — Gap Bounce Fail")
s2_gbfMidXdn = input.bool(false, "Mid cross dn [OFF]", group="14 — Gap Bounce Fail")
s2_gbfMidTol = input.float(0.5, "Mid tol % [0.5]", minval=0.0, maxval=5.0, step=0.1, group="14 — Gap Bounce Fail")
s2_gbfStochKmax = input.float(80.0, "K max [80]", minval=0.0, maxval=100.0, step=1.0, group="14 — Gap Bounce Fail", tooltip="Shared stoch/mid/gap settings above apply to both regimes below.")
// Daily SMA Bear Cross LOCKED ENGINE
s2_dailySmaBearEngine = input.bool(true, "Enable daily SMA bear engine [ON]", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearFilter = input.bool(true, "---- Rule 1 — BELOW % — 20/50 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearFastLen = input.int(20, "Rule 1 fast SMA [20]", minval=1, maxval=300, inline="dsma1len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearSlowLen = input.int(50, "slow [50]", minval=1, maxval=500, inline="dsma1len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearBelowPct = input.float(18.5, "Rule 1 below threshold % [18.5]", minval=0.0, maxval=50.0, step=0.1, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearBlockBars = input.int(210, "Rule 1 block bars [210]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearForceSell = input.bool(true, "Rule 1 force sell [ON]", inline="dsma1fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearR1 = input.bool(true, "R1 [ON]", inline="dsma1fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearR2 = input.bool(false, "R2 [OFF]", inline="dsma1r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearR3 = input.bool(false, "R3 [OFF]", inline="dsma1r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBearR4 = input.bool(false, "R4 [OFF]", inline="dsma1r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2Filter = input.bool(true, "---- Rule 2 — CROSS DOWN — 50/100 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2FastLen = input.int(50, "Rule 2 fast SMA [50]", minval=1, maxval=300, inline="dsma2len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2SlowLen = input.int(100, "slow [100]", minval=1, maxval=500, inline="dsma2len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2BlockBars = input.int(5, "Rule 2 block bars [5]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2ForceSell = input.bool(true, "Rule 2 force sell [ON]", inline="dsma2fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2R1 = input.bool(false, "R1 [OFF]", inline="dsma2fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2R2 = input.bool(true, "R2 [ON]", inline="dsma2r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2R3 = input.bool(false, "R3 [OFF]", inline="dsma2r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear2R4 = input.bool(false, "R4 [OFF]", inline="dsma2r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3Filter = input.bool(true, "---- Rule 3 — CROSS DOWN — 20/50 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3FastLen = input.int(20, "Rule 3 fast SMA [20]", minval=1, maxval=300, inline="dsma3len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3SlowLen = input.int(50, "slow [50]", minval=1, maxval=500, inline="dsma3len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3BlockBars = input.int(5, "Rule 3 block bars [5]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3ForceSell = input.bool(true, "Rule 3 force sell [ON]", inline="dsma3fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3R1 = input.bool(true, "R1 [ON]", inline="dsma3fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3R2 = input.bool(false, "R2 [OFF]", inline="dsma3r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3R3 = input.bool(false, "R3 [OFF]", inline="dsma3r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear3R4 = input.bool(false, "R4 [OFF]", inline="dsma3r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")

s2_dseNoBuyEnable = input.bool(false, "Enable no-buy after custom daily SMA cross down [OFF]", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════", tooltip="TEST: blocks new buys after the custom daily fast SMA crosses down the custom daily slow SMA.")
s2_dseNoBuyFastLen = input.int(50, "Fast SMA [50]", minval=1, maxval=300, inline="dsenblen", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuySlowLen = input.int(200, "Slow SMA [200]", minval=1, maxval=500, inline="dsenblen", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyBars = input.int(5, "No-buy bars after cross [5]", minval=0, maxval=500, group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyR1 = input.bool(false, "R1 [OFF]", inline="dsenb1", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyR2 = input.bool(false, "R2 [OFF]", inline="dsenb1", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyR3 = input.bool(true, "R3 [ON]", inline="dsenb2", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyR4 = input.bool(false, "R4 [OFF]", inline="dsenb2", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyRc = input.bool(true, "Apply to RC buys [ON]", inline="dsenb3", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")
s2_dseNoBuyNormal = input.bool(true, "normal buys [ON]", inline="dsenb3", group="══════ 15.1 — Daily SMA Entry Filter TEST ══════")

s2_dseR2NoBuyEnable = input.bool(true, "Enable R2 20/50 no-buy [ON]", group="══════ 15.2.1 — Daily SMA 20/50 No-Buy R2 LOCKED ══════", tooltip="Locked: after Strategy 6 detects a daily 20/50 cross down, block R2 target buys for the bars below. Applies to both RC and normal buys.")
s2_dseR2NoBuyBars = input.int(14, "R2 no-buy bars after cross [14]", minval=0, maxval=500, group="══════ 15.2.1 — Daily SMA 20/50 No-Buy R2 LOCKED ══════")

s2_dseR4NoBuyEnable = input.bool(true, "Enable R4 20/50 no-buy [ON]", group="══════ 15.2.2 — Daily SMA 20/50 No-Buy R4 LOCKED ══════", tooltip="Locked: after Strategy 6 detects a daily 20/50 cross down, block R4 target buys for the bars below. Applies to both RC and normal buys.")
s2_dseR4NoBuyBars = input.int(12, "R4 no-buy bars after cross [12]", minval=0, maxval=500, group="══════ 15.2.2 — Daily SMA 20/50 No-Buy R4 LOCKED ══════")

s2_dse50100R4Enable = input.bool(true, "Enable R4 50/100 no-buy [ON]", group="══════ 15.3.1 — Daily SMA 50/100 No-Buy R4 LOCKED ══════", tooltip="Locked: after Strategy 6 detects a daily 50/100 cross down, block R4 target buys for the bars below. Applies to both RC and normal buys.")
s2_dse50100R4Bars = input.int(14, "R4 no-buy bars after cross [14]", minval=0, maxval=500, group="══════ 15.3.1 — Daily SMA 50/100 No-Buy R4 LOCKED ══════")

s2_dse50100R3Enable = input.bool(true, "Enable R3 50/100 no-buy [ON]", group="══════ 15.3.3 — Daily SMA 50/100 No-Buy R3 LOCKED ══════", tooltip="Locked: after Strategy 6 detects a daily 50/100 cross down, block R3 target buys for the bars below. Applies to both RC and normal buys.")
s2_dse50100R3Bars = input.int(50, "R3 no-buy bars after cross [50]", minval=0, maxval=500, group="══════ 15.3.3 — Daily SMA 50/100 No-Buy R3 LOCKED ══════")

s2_dse50200R2Enable = input.bool(true, "Enable R2 50/200 no-buy [ON]", group="══════ 15.4.1 — Daily SMA 50/200 No-Buy R2 LOCKED ══════", tooltip="Locked: after Strategy 6 detects a daily 50/200 cross down, block R2 target buys for the bars below. Applies to both RC and normal buys.")
s2_dse50200R2Bars = input.int(11, "R2 no-buy bars after cross [11]", minval=0, maxval=500, group="══════ 15.4.1 — Daily SMA 50/200 No-Buy R2 LOCKED ══════")
s2_dailySmaBear4Filter = input.bool(true, "---- Rule 4 — CROSS DOWN — 50/200 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4FastLen = input.int(50, "Rule 4 fast SMA [50]", minval=1, maxval=300, inline="dsma4len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4SlowLen = input.int(200, "slow [200]", minval=1, maxval=500, inline="dsma4len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4BlockBars = input.int(7, "Rule 4 block bars [7]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4ForceSell = input.bool(true, "Rule 4 force sell [ON]", inline="dsma4fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4R1 = input.bool(true, "R1 [ON]", inline="dsma4fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4R2 = input.bool(false, "R2 [OFF]", inline="dsma4r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4R3 = input.bool(false, "R3 [OFF]", inline="dsma4r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear4R4 = input.bool(false, "R4 [OFF]", inline="dsma4r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5Filter = input.bool(true, "---- Rule 5 — CROSS DOWN — 20/200 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5FastLen = input.int(20, "Rule 5 fast SMA [20]", minval=1, maxval=300, inline="dsma5len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5SlowLen = input.int(200, "slow [200]", minval=1, maxval=500, inline="dsma5len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5BlockBars = input.int(8, "Rule 5 block bars [8]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5ForceSell = input.bool(true, "Rule 5 force sell [ON]", inline="dsma5fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5R1 = input.bool(false, "R1 [OFF]", inline="dsma5fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5R2 = input.bool(true, "R2 [ON]", inline="dsma5r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5R3 = input.bool(false, "R3 [OFF]", inline="dsma5r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear5R4 = input.bool(false, "R4 [OFF]", inline="dsma5r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6Filter = input.bool(true, "---- Rule 6 — CROSS DOWN — 20/100 enabled [ON] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6FastLen = input.int(20, "Rule 6 fast SMA [20]", minval=1, maxval=300, inline="dsma6len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6SlowLen = input.int(100, "slow [100]", minval=1, maxval=500, inline="dsma6len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6BlockBars = input.int(7, "Rule 6 block bars [7]", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6ForceSell = input.bool(true, "Rule 6 force sell [ON]", inline="dsma6fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6R1 = input.bool(true, "R1 [ON]", inline="dsma6fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6R2 = input.bool(false, "R2 [OFF]", inline="dsma6r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6R3 = input.bool(false, "R3 [OFF]", inline="dsma6r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear6R4 = input.bool(false, "R4 [OFF]", inline="dsma6r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7Filter = input.bool(false, "---- Rule 7 — CROSS DOWN — custom enabled [OFF] ----", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7FastLen = input.int(20, "Rule 7 fast SMA", minval=1, maxval=300, inline="dsma7len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7SlowLen = input.int(50, "slow", minval=1, maxval=500, inline="dsma7len", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7BlockBars = input.int(0, "Rule 7 block bars", minval=0, maxval=500, group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7ForceSell = input.bool(false, "Rule 7 force sell [OFF]", inline="dsma7fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7R1 = input.bool(false, "R1 [OFF]", inline="dsma7fs", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7R2 = input.bool(false, "R2 [OFF]", inline="dsma7r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7R3 = input.bool(false, "R3 [OFF]", inline="dsma7r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")
s2_dailySmaBear7R4 = input.bool(false, "R4 [OFF]", inline="dsma7r", group="══════ 15 — Daily SMA Bear Cross LOCKED ENGINE ══════")

// Daily SMA Bull Sell — risk-on sell suppress rules. R0 excluded by design.
s2_dailySmaBullEngine = input.bool(true, "Enable daily SMA bull sell engine [ON]", group="══════ 16 — Daily SMA Bull Sell Engine ══════")
s2_dailySmaBullMarker = input.bool(true, "Show suppressed sell markers [ON]", group="══════ 16 — Daily SMA Bull Sell Engine ══════")

s2_dailySmaBull3Sell = input.bool(false, "Enable bull sell suppress after daily cross up [OFF]", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3FastLen = input.int(10, "Fast SMA [10]", minval=1, maxval=300, inline="dsbull3len", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3SlowLen = input.int(50, "Slow SMA [50]", minval=1, maxval=500, inline="dsbull3len", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3ActiveBars = input.int(16, "Active bars after cross [16]", minval=0, maxval=500, group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3R1 = input.bool(true, "R1 [ON]", inline="dsbull3r1", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3R2 = input.bool(true, "R2 [ON]", inline="dsbull3r1", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3R3 = input.bool(true, "R3 [ON]", inline="dsbull3r2", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3R4 = input.bool(true, "R4 [ON]", inline="dsbull3r2", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnorePT = input.bool(true, "Suppress PT [ON]", inline="dsbull3ig1", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnoreVix = input.bool(false, "VIX [OFF]", inline="dsbull3ig1", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnoreBB = input.bool(false, "BB [OFF]", inline="dsbull3ig2", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnoreBM = input.bool(false, "BM [OFF]", inline="dsbull3ig2", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnoreRC = input.bool(true, "RC [ON]", inline="dsbull3ig3", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")
s2_dailySmaBull3IgnoreEOD = input.bool(false, "EOD [OFF]", inline="dsbull3ig3", group="══════ 16.1 — Daily SMA Bull Sell TEST ══════")

s2_dailySmaBullSell = input.bool(true, "Enable R2 20/50 above bull sell suppress [ON]", group="══════ 16.2.1 — Daily SMA Bull 20/50 Above R2 LOCKED ══════", tooltip="Locked: daily SMA20 at least 14.0% above SMA50, R2 only, suppresses RC sells.")
s2_dailySmaBullActiveBars = input.int(9, "R2 active bars [9]", minval=0, maxval=500, group="══════ 16.2.1 — Daily SMA Bull 20/50 Above R2 LOCKED ══════")

s2_dailySmaBull2Sell = input.bool(true, "Enable R1 20/10 cross-up bull sell suppress [ON]", group="══════ 16.2.2 — Daily SMA Bull 20/10 Cross Up R1 LOCKED ══════", tooltip="Locked: daily SMA20 crosses up SMA10, R1 only, suppresses PT sells.")
s2_dailySmaBull2ActiveBars = input.int(13, "R1 active bars [13]", minval=0, maxval=500, group="══════ 16.2.2 — Daily SMA Bull 20/10 Cross Up R1 LOCKED ══════")

s2_dailySmaBull4Sell = input.bool(true, "Enable 10/50 all-regime bull sell suppress [ON]", group="══════ 16.3.1 — Daily SMA Bull 10/50 Cross Up All Regimes LOCKED ══════", tooltip="Locked from TEST: daily SMA10 crosses up SMA50, R1/R2/R3/R4, suppresses PT and RC sells.")
s2_dailySmaBull4ActiveBars = input.int(16, "Active bars after cross [16]", minval=0, maxval=500, group="══════ 16.3.1 — Daily SMA Bull 10/50 Cross Up All Regimes LOCKED ══════")

s2_sharedRecRule1R1 = input.bool(false, "Apply to 15 Rule 1 R1 [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRec50100R4 = input.bool(false, "Apply to 15.3.1 R4 50/100 [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRec50100R3 = input.bool(false, "Apply to 15.3.3 R3 50/100 [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRec50200R2 = input.bool(false, "Apply to 15.4.1 R2 50/200 [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecAtrR1 = input.bool(false, "Apply to S6 R1.3 ATR [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecSLeadWaitR1 = input.bool(false, "Apply to S6 R1.7 SLead wait [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecSlTslWaitR1 = input.bool(false, "Apply to S6 R1.7 SL/TSL wait [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecBmWaitR0 = input.bool(false, "Apply to S6 R0.7 RC BM wait [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecPtWaitR3 = input.bool(false, "Apply to S6 R3.7 RC PT wait [OFF]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecKgtD = input.bool(true, "Recovery needs K>D [ON]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecCloseUp = input.bool(true, "Recovery needs close > prior close [ON]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecAboveBbLower = input.bool(true, "Recovery needs close > BB lower [ON]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")
s2_sharedRecBelowLastSell = input.bool(true, "Recovery needs buy <= last sell [ON]", group="══════ 16.9 — Shared Recovery / Shock Response TEST ══════")

showBbSellBands = input.bool(false, "Show BB Sell Bands [OFF]", group="---- 17 — Bollinger Display ----")
showBbBuyBands = input.bool(false, "Show BB Buy Bands [OFF]", group="---- 17 — Bollinger Display ----")
showBbUpper = input.bool(true, "Show Upper [ON]", inline="bbDisp1", group="---- 17 — Bollinger Display ----")
showBbMiddle = input.bool(true, "Show Middle [ON]", inline="bbDisp1", group="---- 17 — Bollinger Display ----")
showBbLower = input.bool(true, "Show Lower [ON]", inline="bbDisp1", group="---- 17 — Bollinger Display ----")
showBbFill = input.bool(false, "Fill Bands [OFF]", inline="bbDisp2", group="---- 17 — Bollinger Display ----")
bbDisplayTransparency = input.int(85, "Transparency [85]", minval=0, maxval=100, inline="bbDisp2", group="---- 17 — Bollinger Display ----")

// Regime Change Rules
s2_useRC = input.bool(true, "Enable Regime Change Rules [ON]", group="══════ 27 — Regime Change ══════")
s2_rcConfirmBars = input.int(3, "Confirm Bars [3]", minval=1, maxval=10, group="══════ 27 — Regime Change ══════")
// R1 → R2 : SMA peaks above 19.5, slope flips to falling (de-escalation)
s2_useRc12 = input.bool(true, "R1→R2 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc12Holding = input.string("HOLD", "R1→R2: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc12Flat = input.string("BUY", "R1→R2: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R2 → R1 : SMA resumes rising above 19.5, slope flips back up (escalation)
s2_useRc21 = input.bool(true, "R2→R1 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc21Holding = input.string("SELL", "R2→R1: If Holding [SELL]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc21Flat = input.string("BUY", "R2→R1: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R2 → R4 : SMA crosses down through 19.5, still falling (de-escalation)
s2_useRc24 = input.bool(true, "R2→R4 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc24Holding = input.string("ADAPT", "R2→R4: If Holding [ADAPT]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc24Flat = input.string("BUY", "R2→R4: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R3 → R1 : SMA crosses up through 19.5, rising (escalation)
s2_useRc31 = input.bool(true, "R3→R1 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc31Holding = input.string("HOLD", "R3→R1: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc31Flat = input.string("BUY", "R3→R1: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R3 → R4 : SMA peaks in mid-range, slope flips to falling (de-escalation)
s2_useRc34 = input.bool(true, "R3→R4 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc34Holding = input.string("HOLD", "R3→R4: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc34Flat = input.string("BUY", "R3→R4: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R4 → R3 : SMA bottoms in mid-range, slope flips to rising (escalation)
s2_useRc43 = input.bool(true, "R4→R3 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc43Holding = input.string("HOLD", "R4→R3: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc43Flat = input.string("WAIT", "R4→R3: If Flat [WAIT]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R4 → R0 : SMA crosses down through 14.5, falling (de-escalation)
s2_useRc40 = input.bool(true, "R4→R0 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc40Holding = input.string("HOLD", "R4→R0: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc40Flat = input.string("BUY", "R4→R0: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")
// R0 → R3 : SMA crosses up through 14.5, rising (escalation)
s2_useRc03 = input.bool(true, "R0→R3 Enable [ON]", group="══════ 27 — Regime Change ══════")
s2_rc03Holding = input.string("HOLD", "R0→R3: If Holding [HOLD]", options=["HOLD", "ADAPT", "SELL"], group="══════ 27 — Regime Change ══════")
s2_rc03Flat = input.string("BUY", "R0→R3: If Flat [BUY]", options=["WAIT", "BUY"], group="══════ 27 — Regime Change ══════")

// BB sell — upper band + exit gates (yellow triangle sell). Not mixed with BB buy below.
s2_bbSellMaster = input.bool(true, "Enable BB sell section [ON]", group="══════ 28 — BB sell — upper band ══════")
s2_bbSrc = input.source(close, "BB Source [close]", group="══════ 28 — BB sell — upper band ══════")
s2_bbLength = input.int(30, "BB Length [30]", minval=2, maxval=500, group="══════ 28 — BB sell — upper band ══════")
s2_bbMult = input.float(2.5, "BB StdDev Mult [2.5]", minval=0.5, maxval=5.0, step=0.1, group="══════ 28 — BB sell — upper band ══════")
s2_bbUpperMode = input.string("TOUCH", "Upper-band trigger [TOUCH]", options=["TOUCH", "CROSS"], group="══════ 28 — BB sell — upper band ══════")
s2_bbNoSellZone = input.bool(true, "No-sell zone: BB mid↑ [ON]", group="══════ 28 — BB sell — upper band ══════")
s2_bbNoSellLookback = input.int(5, "No-sell zone: BB mid slope lookback [5]", minval=1, maxval=20, group="══════ 28 — BB sell — upper band ══════")
s2_bbMidSlopeExit = input.bool(true, "BB mid slope exit [ON]", group="══════ 28 — BB sell — upper band ══════")
s2_bbMidSlopeLookback = input.int(4, "BM: slope lookback [4]", minval=1, maxval=10, group="══════ 28 — BB sell — upper band ══════")
s2_bbMidSlopeFadeRatio = input.float(0.61, "BM: fade ratio [0.61]", minval=0.1, maxval=0.9, step=0.01, group="══════ 28 — BB sell — upper band ══════")
s2_bbMidSlopeMinProfit = input.float(0.46, "BM: min profit % [0.46]", minval=-5.0, maxval=10.0, step=0.01, group="══════ 28 — BB sell — upper band ══════")

// BB buy — own band math + optional price-vs-band filters on top of regime VIX buy % (not mixed with BB sell).
s2_bbBuyMaster = input.bool(true, "Enable BB buy section [ON]", group="══════ 33 — BB buy — band definition ══════")
s2_bbBuySrc = input.source(close, "BB Source [close]", group="══════ 33 — BB buy — band definition ══════")
s2_bbBuyLength = input.int(18, "BB Length [18]", minval=2, maxval=500, group="══════ 33 — BB buy — band definition ══════")
s2_bbBuyMult = input.float(2.8, "BB StdDev Mult [2.8]", minval=0.5, maxval=5.0, step=0.1, group="══════ 33 — BB buy — band definition ══════")
s2_bbBuyLowerMode = input.string("CROSS", "Lower-band trigger [CROSS]", options=["TOUCH", "CROSS"], group="══════ 33 — BB buy — band definition ══════")
// Shared soft trailing: PT / VIX / BB upper / BM — one peak & one % until breach (arm priority PT→VI→BB→BM). Global OFF disables all regimes; per-regime master OFF ignores that regime’s toggles.
s2_st_all_master = input.bool(true, "Enable soft trailing (all regimes) [ON]", group="══════ 38 — Soft trail (global) ══════")
// --- R0 Ultra Calm ---
s2_r0st_master = input.bool(false, "Enable soft trailing for R0 entries [OFF]", group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_pt = input.bool(false, "PT [OFF]", inline="r0a", group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_ptPct = input.float(2.5, "% [2.5]", inline="r0a", minval=0.05, maxval=10.0, step=0.05, group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_vi = input.bool(false, "VI [OFF]", inline="r0b", group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_viPct = input.float(0.50, "% [0.5]", inline="r0b", minval=0.05, maxval=10.0, step=0.05, group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_bb = input.bool(false, "BB [OFF]", inline="r0c", group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_bbPct = input.float(0.50, "% [0.5]", inline="r0c", minval=0.05, maxval=10.0, step=0.05, group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_bm = input.bool(false, "BM [OFF]", inline="r0d", group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
s2_r0st_bmPct = input.float(0.50, "% [0.5]", inline="r0d", minval=0.05, maxval=10.0, step=0.05, group="══════ 39 — Soft trail — R0 Ultra Calm ══════")
// --- R1 Rising ---
s2_r1st_master = input.bool(true, "Enable soft trailing for R1 entries [ON]", group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_pt = input.bool(false, "PT [OFF]", inline="r1a", group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_ptPct = input.float(0.50, "% [0.5]", inline="r1a", minval=0.05, maxval=10.0, step=0.05, group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_vi = input.bool(false, "VI [OFF]", inline="r1b", group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_viPct = input.float(0.50, "% [0.5]", inline="r1b", minval=0.05, maxval=10.0, step=0.05, group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_bb = input.bool(false, "BB [OFF]", inline="r1c", group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_bbPct = input.float(0.50, "% [0.5]", inline="r1c", minval=0.05, maxval=10.0, step=0.05, group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_bm = input.bool(true, "BM [ON]", inline="r1d", group="══════ 40 — Soft trail — R1 Rising ══════")
s2_r1st_bmPct = input.float(0.64, "% [0.64]", inline="r1d", minval=0.05, maxval=10.0, step=0.01, group="══════ 40 — Soft trail — R1 Rising ══════")
// --- R2 Falling ---
s2_r2st_master = input.bool(true, "Enable soft trailing for R2 entries [ON]", group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_pt = input.bool(true, "PT [ON]", inline="r2a", group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_ptPct = input.float(8.7, "% [8.7]", inline="r2a", minval=0.05, maxval=20.0, step=0.05, group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_vi = input.bool(false, "VI [OFF]", inline="r2b", group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_viPct = input.float(0.50, "% [0.5]", inline="r2b", minval=0.05, maxval=10.0, step=0.05, group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_bb = input.bool(true, "BB [ON]", inline="r2c", group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_bbPct = input.float(2.0, "% [2]", inline="r2c", minval=0.05, maxval=10.0, step=0.05, group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_bm = input.bool(true, "BM [ON]", inline="r2d", group="══════ 41 — Soft trail — R2 Falling ══════")
s2_r2st_bmPct = input.float(3.50, "% [3.5]", inline="r2d", minval=0.05, maxval=10.0, step=0.05, group="══════ 41 — Soft trail — R2 Falling ══════")
// --- R3 Mid Rise ---
s2_r3st_master = input.bool(true, "Enable soft trailing for R3 entries [ON]", group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_pt = input.bool(false, "PT [OFF]", inline="r3a", group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_ptPct = input.float(1.0, "% [1]", inline="r3a", minval=0.05, maxval=10.0, step=0.05, group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_vi = input.bool(false, "VI [OFF]", inline="r3b", group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_viPct = input.float(1.0, "% [1]", inline="r3b", minval=0.05, maxval=10.0, step=0.05, group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_bb = input.bool(false, "BB [OFF]", inline="r3c", group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_bbPct = input.float(1.0, "% [1]", inline="r3c", minval=0.05, maxval=10.0, step=0.01, group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_bm = input.bool(true, "BM [ON]", inline="r3d", group="══════ 42 — Soft trail — R3 Mid Rise ══════")
s2_r3st_bmPct = input.float(4.0, "% [4]", inline="r3d", minval=0.05, maxval=10.0, step=0.05, group="══════ 42 — Soft trail — R3 Mid Rise ══════")
// --- R4 Mid Fall ---
s2_r4st_master = input.bool(true, "Enable soft trailing for R4 entries [ON]", group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_pt = input.bool(true, "PT [ON]", inline="r4a", group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_ptPct = input.float(9.0, "% [9]", inline="r4a", minval=0.05, maxval=10.0, step=0.05, group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_vi = input.bool(true, "VI [ON]", inline="r4b", group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_viPct = input.float(8.2, "% [8.2]", inline="r4b", minval=0.05, maxval=10.0, step=0.05, group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_bb = input.bool(false, "BB [OFF]", inline="r4c", group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_bbPct = input.float(0.45, "% [0.45]", inline="r4c", minval=0.05, maxval=10.0, step=0.05, group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_bm = input.bool(false, "BM [OFF]", inline="r4d", group="══════ 43 — Soft trail — R4 Mid Fall ══════")
s2_r4st_bmPct = input.float(0.50, "% [0.5]", inline="r4d", minval=0.05, maxval=10.0, step=0.05, group="══════ 43 — Soft trail — R4 Mid Fall ══════")

s2_alertMsgStyle = input.string("Full", "Alert text [Full]", options=["Full", "Compact"], group="══════ 44 — Alerts ══════")

// Manual Overrides — 2 slots. Each fires on the single intraday bar whose range covers the picked date+time.
// Priority: Manual ALWAYS wins and bypasses signalAllow, BB buy/sell filters, RC gates, SL, PT, TSL, EOD, no-buy-last-hour, first-signal-per-bar.
// Wrong-state (Buy while long / Sell while flat) → no triangle, grey "M skip" label so the attempt is visible.
// Symbol filter: a Pine indicator runs on whatever chart symbol is loaded; without this gate every slot would fire on SPY / QQQ / AAPL / anything. Bare ticker match against syminfo.ticker; empty = no filter.
s2_movSymbol = input.string("TQQQ", "Only fire on ticker [TQQQ]", group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov1En = input.bool(false, "Enable Override 1 [OFF]", group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov1T  = input.time(timestamp("2026-04-18 09:30"), "Date/Time 1", group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov1Ty = input.string("Buy", "Type 1", options=["Buy", "Sell"], group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov2En = input.bool(false, "Enable Override 2 [OFF]", group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov2T  = input.time(timestamp("2026-04-18 09:30"), "Date/Time 2", group="══════ 45 — Manual Overrides (S2) ══════")
s2_mov2Ty = input.string("Buy", "Type 2", options=["Buy", "Sell"], group="══════ 45 — Manual Overrides (S2) ══════")

s2_simIntrabar = input.bool(true, "Intrabar simulation [ON]", group="══════ 46 — Strategy 6 Near-Close Alerts ══════")
s5_nearCloseAlerts = input.bool(true, "Enable near-close auto alerts [ON]", group="══════ 46 — Strategy 6 Near-Close Alerts ══════")
s5_alertFinalMinutes = input.int(1, "Final minutes before close [1]", minval=1, maxval=30, group="══════ 46 — Strategy 6 Near-Close Alerts ══════")

rcslRcOnlyEff = s2_rcslRcOnly
rcslMinBarsEff = s2_rcslMinBars
rcslMaxBarsEff = s2_rcslMaxBars
rcslExitCrossEff = s2_rcslExitCross
rcslPtNotReachedEff = s2_rcslPtNotReached
rcslRequireTrailArmedEff = s2_rcslRequireTrailArmed
rcslMaxPnlEff = s2_rcslMaxPnl
rcslMarkerEff = s2_rcslMarker

rcl0R0EnableEff = s2_rcl0R0Enable
rcl0RcOnlyEff = s2_rcl0RcOnly
rcl0MinBarsEff = s2_rcl0MinBars
rcl0MaxBarsEff = s2_rcl0MaxBars
rcl0EmbedBarsHighEff = s2_rcl0EmbedBarsHigh
rcl0ZoneHighEff = s2_rcl0ZoneHigh
rcl0EmbedBarsLowEff = s2_rcl0EmbedBarsLow
rcl0ZoneLowEff = s2_rcl0ZoneLow
rcl0MaxBuyLockBarsEff = s2_rcl0MaxBuyLockBars
rcl0ReleaseCloseUpEff = s2_rcl0ReleaseCloseUp
rcl0ExitMarkerEff = s2_rcl0ExitMarker
rcl0BlockMarkerEff = true

rcl1R1EnableEff = s2_rcl1R1Enable
rcl1RcOnlyEff = s2_rcl1RcOnly
rcl1MinBarsEff = s2_rcl1MinBars
rcl1MaxBarsEff = s2_rcl1MaxBars
rcl1EmbedBarsHighEff = s2_rcl1EmbedBarsHigh
rcl1ZoneHighEff = s2_rcl1ZoneHigh
rcl1EmbedBarsLowEff = s2_rcl1EmbedBarsLow
rcl1ZoneLowEff = s2_rcl1ZoneLow
rcl1MaxBuyLockBarsEff = s2_rcl1MaxBuyLockBars
rcl1ExitMarkerEff = s2_rcl1ExitMarker
rcl1BlockMarkerEff = true

rcl2R2EnableEff = s2_rcl2R2Enable
rcl2RcOnlyEff = s2_rcl2RcOnly
rcl2MinBarsEff = s2_rcl2MinBars
rcl2MaxBarsEff = s2_rcl2MaxBars
rcl2EmbedBarsHighEff = s2_rcl2EmbedBarsHigh
rcl2ZoneHighEff = s2_rcl2ZoneHigh
rcl2EmbedBarsLowEff = s2_rcl2EmbedBarsLow
rcl2ZoneLowEff = s2_rcl2ZoneLow
rcl2MaxBuyLockBarsEff = s2_rcl2MaxBuyLockBars
rcl2ReleaseCloseUpEff = s2_rcl2ReleaseCloseUp
rcl2ExitMarkerEff = s2_rcl2ExitMarker
rcl2BlockMarkerEff = true

rcl3R3EnableEff = s2_rcl3R3Enable
rcl3RcOnlyEff = s2_rcl3RcOnly
rcl3MinBarsEff = s2_rcl3MinBars
rcl3MaxBarsEff = s2_rcl3MaxBars
rcl3EmbedBarsHighEff = s2_rcl3EmbedBarsHigh
rcl3ZoneHighEff = s2_rcl3ZoneHigh
rcl3EmbedBarsLowEff = s2_rcl3EmbedBarsLow
rcl3ZoneLowEff = s2_rcl3ZoneLow
rcl3MaxBuyLockBarsEff = s2_rcl3MaxBuyLockBars
rcl3ReleaseCloseUpEff = s2_rcl3ReleaseCloseUp
rcl3ExitMarkerEff = s2_rcl3ExitMarker
rcl3BlockMarkerEff = true

rclR4EnableEff = s2_rclR4Enable
rclRcOnlyEff = s2_rclRcOnly
rclMinBarsEff = s2_rclMinBars
rclMaxBarsEff = s2_rclMaxBars
rclEmbedBarsHighEff = s2_rclEmbedBarsHigh
rclZoneHighEff = s2_rclZoneHigh
rclEmbedBarsLowEff = s2_rclEmbedBarsLow
rclZoneLowEff = s2_rclZoneLow
rclMaxBuyLockBarsEff = s2_rclMaxBuyLockBars
rclReleaseCloseUpEff = s2_rclReleaseCloseUp
rclExitMarkerEff = s2_rclExitMarker
rclBlockMarkerEff = true

rcbdR4EnableEff = s2_rcbdR4Enable
rcbdRcOnlyEff = s2_rcbdRcOnly
rcbdMinBarsEff = s2_rcbdMinBars
rcbdMaxBarsEff = s2_rcbdMaxBars
rcbdMaxMfeEff = s2_rcbdMaxMfe
rcbdMaxPnlEff = s2_rcbdMaxPnl
rcbdMinPnlEff = s2_rcbdMinPnl
rcbdMidLookbackEff = s2_rcbdMidLookback
rcbdVixWorsenEff = s2_rcbdVixWorsen
rcbdMarkerEff = s2_rcbdMarker

masterVixSmaLengthEff = s2_masterVixSmaLength

masterSlopeLookbackEff = s2_masterSlopeLookback

r0MaxSmaEff = s2_masterR0MaxSma

r1MinSmaEff = s2_masterR1MinSma

dailySmaBearEngineEff = s2_dailySmaBearEngine

dailySmaBearFilterEff = dailySmaBearEngineEff and s2_dailySmaBearFilter

dailySmaBearFastLenEff = s2_dailySmaBearFastLen

dailySmaBearSlowLenEff = s2_dailySmaBearSlowLen

dailySmaBearBelowPctEff = s2_dailySmaBearBelowPct

dailySmaBearBlockBarsEff = s2_dailySmaBearBlockBars

dailySmaBearForceSellEff = s2_dailySmaBearForceSell

dailySmaBearR1Eff = s2_dailySmaBearR1

dailySmaBearR2Eff = s2_dailySmaBearR2

dailySmaBearR3Eff = s2_dailySmaBearR3

dailySmaBearR4Eff = s2_dailySmaBearR4

dailySmaBearMarkerEff = true

dailySmaBear2FilterEff = dailySmaBearEngineEff and s2_dailySmaBear2Filter

dailySmaBear2FastLenEff = s2_dailySmaBear2FastLen

dailySmaBear2SlowLenEff = s2_dailySmaBear2SlowLen

dailySmaBear2BlockBarsEff = s2_dailySmaBear2BlockBars

dailySmaBear2ForceSellEff = s2_dailySmaBear2ForceSell

dailySmaBear2R1Eff = s2_dailySmaBear2R1

dailySmaBear2R2Eff = s2_dailySmaBear2R2

dailySmaBear2R3Eff = s2_dailySmaBear2R3

dailySmaBear2R4Eff = s2_dailySmaBear2R4

dailySmaBear2MarkerEff = true

dailySmaBear3FilterEff = dailySmaBearEngineEff and s2_dailySmaBear3Filter

dailySmaBear3FastLenEff = s2_dailySmaBear3FastLen

dailySmaBear3SlowLenEff = s2_dailySmaBear3SlowLen

dailySmaBear3BlockBarsEff = s2_dailySmaBear3BlockBars

dailySmaBear3ForceSellEff = s2_dailySmaBear3ForceSell

dailySmaBear3R1Eff = s2_dailySmaBear3R1

dailySmaBear3R2Eff = s2_dailySmaBear3R2

dailySmaBear3R3Eff = s2_dailySmaBear3R3

dailySmaBear3R4Eff = s2_dailySmaBear3R4

dailySmaBear3MarkerEff = true

dailySmaBear4FilterEff = dailySmaBearEngineEff and s2_dailySmaBear4Filter

dailySmaBear4FastLenEff = s2_dailySmaBear4FastLen

dailySmaBear4SlowLenEff = s2_dailySmaBear4SlowLen

dailySmaBear4BlockBarsEff = s2_dailySmaBear4BlockBars

dailySmaBear4ForceSellEff = s2_dailySmaBear4ForceSell

dailySmaBear4R1Eff = s2_dailySmaBear4R1

dailySmaBear4R2Eff = s2_dailySmaBear4R2

dailySmaBear4R3Eff = s2_dailySmaBear4R3

dailySmaBear4R4Eff = s2_dailySmaBear4R4

dailySmaBear4MarkerEff = true

dailySmaBear5FilterEff = dailySmaBearEngineEff and s2_dailySmaBear5Filter

dailySmaBear5FastLenEff = s2_dailySmaBear5FastLen

dailySmaBear5SlowLenEff = s2_dailySmaBear5SlowLen

dailySmaBear5BlockBarsEff = s2_dailySmaBear5BlockBars

dailySmaBear5ForceSellEff = s2_dailySmaBear5ForceSell

dailySmaBear5R1Eff = s2_dailySmaBear5R1

dailySmaBear5R2Eff = s2_dailySmaBear5R2

dailySmaBear5R3Eff = s2_dailySmaBear5R3

dailySmaBear5R4Eff = s2_dailySmaBear5R4

dailySmaBear5MarkerEff = true

dailySmaBear6FilterEff = dailySmaBearEngineEff and s2_dailySmaBear6Filter

dailySmaBear6FastLenEff = s2_dailySmaBear6FastLen

dailySmaBear6SlowLenEff = s2_dailySmaBear6SlowLen

dailySmaBear6BlockBarsEff = s2_dailySmaBear6BlockBars

dailySmaBear6ForceSellEff = s2_dailySmaBear6ForceSell

dailySmaBear6R1Eff = s2_dailySmaBear6R1

dailySmaBear6R2Eff = s2_dailySmaBear6R2

dailySmaBear6R3Eff = s2_dailySmaBear6R3

dailySmaBear6R4Eff = s2_dailySmaBear6R4

dailySmaBear6MarkerEff = true

dailySmaBear7FilterEff = dailySmaBearEngineEff and s2_dailySmaBear7Filter

dailySmaBear7FastLenEff = s2_dailySmaBear7FastLen

dailySmaBear7SlowLenEff = s2_dailySmaBear7SlowLen

dailySmaBear7BlockBarsEff = s2_dailySmaBear7BlockBars

dailySmaBear7ForceSellEff = s2_dailySmaBear7ForceSell

dailySmaBear7R1Eff = s2_dailySmaBear7R1

dailySmaBear7R2Eff = s2_dailySmaBear7R2

dailySmaBear7R3Eff = s2_dailySmaBear7R3

dailySmaBear7R4Eff = s2_dailySmaBear7R4

dailySmaBear7MarkerEff = true

dailySmaBullEngineEff = s2_dailySmaBullEngine

dailySmaBullSellEff = dailySmaBullEngineEff and s2_dailySmaBullSell

dailySmaBullFastLenEff = 20

dailySmaBullSlowLenEff = 50

dailySmaBullAbovePctEff = 14.0

dailySmaBullActiveBarsEff = s2_dailySmaBullActiveBars

dailySmaBullR1Eff = false

dailySmaBullR2Eff = true

dailySmaBullR3Eff = false

dailySmaBullR4Eff = false

dailySmaBullIgnorePTEff = false

dailySmaBullIgnoreVixEff = false

dailySmaBullIgnoreBBEff = false

dailySmaBullIgnoreBMEff = false

dailySmaBullIgnoreRCEff = true

dailySmaBullIgnoreEODEff = false

dailySmaBullMarkerEff = s2_dailySmaBullMarker

dailySmaBull2SellEff = dailySmaBullEngineEff and s2_dailySmaBull2Sell

dailySmaBull2FastLenEff = 20

dailySmaBull2SlowLenEff = 10

dailySmaBull2ActiveBarsEff = s2_dailySmaBull2ActiveBars

dailySmaBull2R1Eff = true

dailySmaBull2R2Eff = false

dailySmaBull2R3Eff = false

dailySmaBull2R4Eff = false

dailySmaBull2IgnorePTEff = true

dailySmaBull2IgnoreVixEff = false

dailySmaBull2IgnoreBBEff = false

dailySmaBull2IgnoreBMEff = false

dailySmaBull2IgnoreRCEff = false

dailySmaBull2IgnoreEODEff = false

dailySmaBull2MarkerEff = s2_dailySmaBullMarker

dailySmaBull3SellEff = dailySmaBullEngineEff and s2_dailySmaBull3Sell

dailySmaBull3FastLenEff = s2_dailySmaBull3FastLen

dailySmaBull3SlowLenEff = s2_dailySmaBull3SlowLen

dailySmaBull3ActiveBarsEff = s2_dailySmaBull3ActiveBars

dailySmaBull3R1Eff = s2_dailySmaBull3R1

dailySmaBull3R2Eff = s2_dailySmaBull3R2

dailySmaBull3R3Eff = s2_dailySmaBull3R3

dailySmaBull3R4Eff = s2_dailySmaBull3R4

dailySmaBull3IgnorePTEff = s2_dailySmaBull3IgnorePT

dailySmaBull3IgnoreVixEff = s2_dailySmaBull3IgnoreVix

dailySmaBull3IgnoreBBEff = s2_dailySmaBull3IgnoreBB

dailySmaBull3IgnoreBMEff = s2_dailySmaBull3IgnoreBM

dailySmaBull3IgnoreRCEff = s2_dailySmaBull3IgnoreRC

dailySmaBull3IgnoreEODEff = s2_dailySmaBull3IgnoreEOD

dailySmaBull3MarkerEff = s2_dailySmaBullMarker

dailySmaBull4SellEff = dailySmaBullEngineEff and s2_dailySmaBull4Sell

dailySmaBull4ActiveBarsEff = s2_dailySmaBull4ActiveBars

dailySmaBull4MarkerEff = s2_dailySmaBullMarker

useR0Eff = s2_useR0

r0ConfirmBarsEff = s2_r0ConfirmBars

r0FastVixExitEff = s2_r0FastVixExit

r0PTEff = s2_r0PT

r0SLEff = s2_r0SL

useR1Eff = s2_useR1

r1ConfirmBarsEff = s2_r1ConfirmBars

r1CooldownEff = s2_r1Cooldown

r1EodEff = s2_r1Eod

r1EodMinProfitEff = s2_r1EodMinProfit

r1NoBuyLastBarEff = s2_r1NoBuyLastBar

r1BuyPctEff = s2_r1BuyPct

r1SellPctEff = s2_r1SellPct

r1PTEff = s2_r1PT

r1SLEff = s2_r1SL

r1AtrRiskFilterEff = s2_r1AtrRiskFilter

r1AtrRiskLengthEff = s2_r1AtrRiskLength

r1AtrRiskMaxPctEff = s2_r1AtrRiskMaxPct

r1AtrRiskRequireRisingEff = s2_r1AtrRiskRequireRising

r1AtrRiskMarkerEff = true

useR2Eff = s2_useR2

r2ConfirmBarsEff = s2_r2ConfirmBars

r2CooldownEff = s2_r2Cooldown

r2EodEff = s2_r2Eod

r2EodMinProfitEff = s2_r2EodMinProfit

r2NoBuyLastBarEff = s2_r2NoBuyLastBar

r2BuyPctEff = s2_r2BuyPct

r2SellPctEff = s2_r2SellPct

r2PTEff = s2_r2PT

r2SLEff = s2_r2SL

r2GuardMasterEff = s2_r2GuardMaster

r2GuardEarlyExitEff = s2_r2GuardEarlyExit

r2GuardEarlyBarsEff = s2_r2GuardEarlyBars

r2GuardEarlyPnlEff = s2_r2GuardEarlyPnl

r2GuardVixWorsenEff = s2_r2GuardVixWorsen

r2GuardMaxBarsExitEff = s2_r2GuardMaxBarsExit

r2GuardMaxBarsEff = s2_r2GuardMaxBars

r2GuardMaxBarsPnlEff = s2_r2GuardMaxBarsPnl

r2GuardTighterSLEff = s2_r2GuardTighterSL

r2GuardSLEff = s2_r2GuardSL

useR3Eff = s2_useR3

r3ConfirmBarsEff = s2_r3ConfirmBars

r3CooldownEff = s2_r3Cooldown

r3EodEff = s2_r3Eod

r3EodMinProfitEff = s2_r3EodMinProfit

r3NoBuyLastBarEff = s2_r3NoBuyLastBar

r3BuyPctEff = s2_r3BuyPct

r3SellPctEff = s2_r3SellPct

r3PTEff = s2_r3PT

r3SLEff = s2_r3SL

useR4Eff = s2_useR4

r4ConfirmBarsEff = s2_r4ConfirmBars

r4CooldownEff = s2_r4Cooldown

r4EodEff = s2_r4Eod

r4EodMinProfitEff = s2_r4EodMinProfit

r4NoBuyLastBarEff = s2_r4NoBuyLastBar

r4BuyPctEff = s2_r4BuyPct

r4SellPctEff = s2_r4SellPct

r4PTEff = s2_r4PT

r4SLEff = s2_r4SL

r4GuardMasterEff = s2_r4GuardMaster

r4GuardEarlyExitEff = s2_r4GuardEarlyExit

r4GuardEarlyBarsEff = s2_r4GuardEarlyBars

r4GuardEarlyPnlEff = s2_r4GuardEarlyPnl

r4GuardVixWorsenEff = s2_r4GuardVixWorsen

r4GuardMaxBarsExitEff = s2_r4GuardMaxBarsExit

r4GuardMaxBarsEff = s2_r4GuardMaxBars

r4GuardMaxBarsPnlEff = s2_r4GuardMaxBarsPnl

r4GuardTighterSLEff = s2_r4GuardTighterSL

r4GuardSLEff = s2_r4GuardSL

useRCEff = s2_useRC

rcConfirmBarsEff = s2_rcConfirmBars

useRc12Eff = s2_useRc12

rc12HoldingEff = s2_rc12Holding

rc12FlatEff = s2_rc12Flat

useRc21Eff = s2_useRc21

rc21HoldingEff = s2_rc21Holding

rc21FlatEff = s2_rc21Flat

useRc24Eff = s2_useRc24

rc24HoldingEff = s2_rc24Holding

rc24FlatEff = s2_rc24Flat

useRc31Eff = s2_useRc31

rc31HoldingEff = s2_rc31Holding

rc31FlatEff = s2_rc31Flat

useRc34Eff = s2_useRc34

rc34HoldingEff = s2_rc34Holding

rc34FlatEff = s2_rc34Flat

useRc43Eff = s2_useRc43

rc43HoldingEff = s2_rc43Holding

rc43FlatEff = s2_rc43Flat

useRc40Eff = s2_useRc40

rc40HoldingEff = s2_rc40Holding

rc40FlatEff = s2_rc40Flat

useRc03Eff = s2_useRc03

rc03HoldingEff = s2_rc03Holding

rc03FlatEff = s2_rc03Flat

bbSellMasterEff = s2_bbSellMaster

bbSrcEff = s2_bbSrc

bbLengthEff = s2_bbLength

bbMultEff = s2_bbMult

bbUpperModeEff = s2_bbUpperMode

bbNoSellZoneEff = s2_bbNoSellZone

bbNoSellLookbackEff = s2_bbNoSellLookback

bbMidSlopeExitEff = s2_bbMidSlopeExit

bbMidSlopeLookbackEff = s2_bbMidSlopeLookback

bbMidSlopeFadeRatioEff = s2_bbMidSlopeFadeRatio

bbMidSlopeMinProfitEff = s2_bbMidSlopeMinProfit

bbR1ExitPTEff = s2_bbR1Master and s2_bbR1ExitPT

bbR1ExitBbEff = s2_bbR1Master and s2_bbR1ExitBb

bbR1ExitVixEff = s2_bbR1Master and s2_bbR1ExitVix

bbR1ExitSLEff = s2_bbR1Master and s2_bbR1ExitSL

bbR1ExitEodEff = s2_bbR1Master and s2_bbR1ExitEod

bbR1ExitRcEff = s2_bbR1Master and s2_bbR1ExitRc

bbR1BbWaitEff = s2_bbR1BbWait

bbR1BbMaxWaitEff = s2_bbR1BbMaxWait

bbR2ExitPTEff = s2_bbR2Master and s2_bbR2ExitPT

bbR2ExitBbEff = s2_bbR2Master and s2_bbR2ExitBb

bbR2ExitVixEff = s2_bbR2Master and s2_bbR2ExitVix

bbR2ExitSLEff = s2_bbR2Master and s2_bbR2ExitSL

bbR2ExitEodEff = s2_bbR2Master and s2_bbR2ExitEod

bbR2ExitRcEff = s2_bbR2Master and s2_bbR2ExitRc

bbR2BbWaitEff = s2_bbR2BbWait

bbR2BbMaxWaitEff = s2_bbR2BbMaxWait

bbR3ExitPTEff = s2_bbR3Master and s2_bbR3ExitPT

bbR3ExitBbEff = s2_bbR3Master and s2_bbR3ExitBb

bbR3ExitVixEff = s2_bbR3Master and s2_bbR3ExitVix

bbR3ExitSLEff = s2_bbR3Master and s2_bbR3ExitSL

bbR3ExitEodEff = s2_bbR3Master and s2_bbR3ExitEod

bbR3ExitRcEff = s2_bbR3Master and s2_bbR3ExitRc

bbR3BbWaitEff = s2_bbR3BbWait

bbR3BbMaxWaitEff = s2_bbR3BbMaxWait

bbR4ExitPTEff = s2_bbR4Master and s2_bbR4ExitPT

bbR4ExitBbEff = s2_bbR4Master and s2_bbR4ExitBb

bbR4ExitVixEff = s2_bbR4Master and s2_bbR4ExitVix

bbR4ExitSLEff = s2_bbR4Master and s2_bbR4ExitSL

bbR4ExitEodEff = s2_bbR4Master and s2_bbR4ExitEod

bbR4ExitRcEff = s2_bbR4Master and s2_bbR4ExitRc

bbR4BbWaitEff = s2_bbR4BbWait

bbR4BbMaxWaitEff = s2_bbR4BbMaxWait

bbBuyMasterEff = s2_bbBuyMaster

bbBuySrcEff = s2_bbBuySrc

bbBuyLengthEff = s2_bbBuyLength

bbBuyMultEff = s2_bbBuyMult

bbBuyLowerModeEff = s2_bbBuyLowerMode

bbBuyUseR1Eff = s2_bbBuyUseR1

bbBuyR1MatchEff = s2_bbBuyR1Match

bbBuyR1LowerEff = s2_bbBuyR1Lower

bbBuyR1BelowMidEff = s2_bbBuyR1BelowMid

bbBuyR1LowerHalfEff = s2_bbBuyR1LowerHalf

bbBuyR1NotUpperEff = s2_bbBuyR1NotUpper

bbBuyR1LbEff = s2_bbBuyR1Lb

bbBuyR1MinBelowEff = s2_bbBuyR1MinBelow

bbBuyUseR2Eff = s2_bbBuyUseR2

bbBuyR2MatchEff = s2_bbBuyR2Match

bbBuyR2LowerEff = s2_bbBuyR2Lower

bbBuyR2BelowMidEff = s2_bbBuyR2BelowMid

bbBuyR2LowerHalfEff = s2_bbBuyR2LowerHalf

bbBuyR2NotUpperEff = s2_bbBuyR2NotUpper

bbBuyR2LbEff = s2_bbBuyR2Lb

bbBuyR2MinBelowEff = s2_bbBuyR2MinBelow

bbBuyUseR3Eff = s2_bbBuyUseR3

bbBuyR3MatchEff = s2_bbBuyR3Match

bbBuyR3LowerEff = s2_bbBuyR3Lower

bbBuyR3BelowMidEff = s2_bbBuyR3BelowMid

bbBuyR3LowerHalfEff = s2_bbBuyR3LowerHalf

bbBuyR3NotUpperEff = s2_bbBuyR3NotUpper

bbBuyR3LbEff = s2_bbBuyR3Lb

bbBuyR3MinBelowEff = s2_bbBuyR3MinBelow

bbBuyUseR4Eff = s2_bbBuyUseR4

bbBuyR4MatchEff = s2_bbBuyR4Match

bbBuyR4LowerEff = s2_bbBuyR4Lower

bbBuyR4BelowMidEff = s2_bbBuyR4BelowMid

bbBuyR4LowerHalfEff = s2_bbBuyR4LowerHalf

bbBuyR4NotUpperEff = s2_bbBuyR4NotUpper

bbBuyR4LbEff = s2_bbBuyR4Lb

bbBuyR4MinBelowEff = s2_bbBuyR4MinBelow

showInfoTableEff = showInfoTable
showLabelsEff = showLabels
showRegimeBackgroundEff = showRegimeBackground
sqqqSimEnableEff = s2_sqqqSimEnable
st_all_masterEff = s2_st_all_master

r0st_masterEff = s2_r0st_master

r0st_ptEff = s2_r0st_pt

r0st_ptPctEff = s2_r0st_ptPct

r0st_viEff = s2_r0st_vi

r0st_viPctEff = s2_r0st_viPct

r0st_bbEff = s2_r0st_bb

r0st_bbPctEff = s2_r0st_bbPct

r0st_bmEff = s2_r0st_bm

r0st_bmPctEff = s2_r0st_bmPct

r1st_masterEff = s2_r1st_master

r1st_ptEff = s2_r1st_pt

r1st_ptPctEff = s2_r1st_ptPct

r1st_viEff = s2_r1st_vi

r1st_viPctEff = s2_r1st_viPct

r1st_bbEff = s2_r1st_bb

r1st_bbPctEff = s2_r1st_bbPct

r1st_bmEff = s2_r1st_bm

r1st_bmPctEff = s2_r1st_bmPct

r2st_masterEff = s2_r2st_master

r2st_ptEff = s2_r2st_pt

r2st_ptPctEff = s2_r2st_ptPct

r2st_viEff = s2_r2st_vi

r2st_viPctEff = s2_r2st_viPct

r2st_bbEff = s2_r2st_bb

r2st_bbPctEff = s2_r2st_bbPct

r2st_bmEff = s2_r2st_bm

r2st_bmPctEff = s2_r2st_bmPct

r3st_masterEff = s2_r3st_master

r3st_ptEff = s2_r3st_pt

r3st_ptPctEff = s2_r3st_ptPct

r3st_viEff = s2_r3st_vi

r3st_viPctEff = s2_r3st_viPct

r3st_bbEff = s2_r3st_bb

r3st_bbPctEff = s2_r3st_bbPct

r3st_bmEff = s2_r3st_bm

r3st_bmPctEff = s2_r3st_bmPct

r4st_masterEff = s2_r4st_master

r4st_ptEff = s2_r4st_pt

r4st_ptPctEff = s2_r4st_ptPct

r4st_viEff = s2_r4st_vi

r4st_viPctEff = s2_r4st_viPct

r4st_bbEff = s2_r4st_bb

r4st_bbPctEff = s2_r4st_bbPct

r4st_bmEff = s2_r4st_bm

r4st_bmPctEff = s2_r4st_bmPct

alertMsgStyleEff = s2_alertMsgStyle

simIntrabarEff = s2_simIntrabar

nearCloseMs = s5_alertFinalMinutes * 60 * 1000
msToBarClose = time_close - timenow
nearCloseAlertWindow = barstate.isrealtime and msToBarClose >= 0 and msToBarClose <= nearCloseMs
autoAlertTimingOk = not s5_nearCloseAlerts or nearCloseAlertWindow

// Thousands separators for large % (info table Strategy / B&H; sell triangle labels)
fmtIntWithCommas(s) =>
    n = str.length(s)
    if n <= 3
        s
    else
        nmod = n % 3
        leadLen = nmod == 0 ? 3 : nmod
        out = str.substring(s, 0, leadLen)
        i = leadLen
        while i < n
            out := out + "," + str.substring(s, i, i + 3)
            i := i + 3
        out

fmtLeadingZeroDec(raw) =>
    dotIx = str.pos(raw, ".")
    intStrRaw = dotIx >= 0 ? str.substring(raw, 0, dotIx) : raw
    intStr = intStrRaw == "" ? "0" : intStrRaw
    fracStr = dotIx >= 0 ? str.substring(raw, dotIx) : ""
    intStr + fracStr

fmtPctOneDec(x) =>
    (x < 0 ? "-" : "") + fmtLeadingZeroDec(str.tostring(math.abs(x), "#.#"))

fmtPctStickerOneDecimal(x) =>
    ax = math.abs(x)
    raw = str.tostring(ax, "#.0")
    dotIx = str.pos(raw, ".")
    intStrRaw = dotIx >= 0 ? str.substring(raw, 0, dotIx) : raw
    intStr = intStrRaw == "" ? "0" : intStrRaw
    fracStr = dotIx >= 0 ? str.substring(raw, dotIx) : ".0"
    (x < 0 ? "-" : "+") + fmtIntWithCommas(intStr) + fracStr

fmtNumberOneDecimalWithCommas(x) =>
    ax = math.abs(x)
    raw = str.tostring(ax, "#.0")
    dotIx = str.pos(raw, ".")
    intStrRaw = dotIx >= 0 ? str.substring(raw, 0, dotIx) : raw
    intStr = intStrRaw == "" ? "0" : intStrRaw
    fracStr = dotIx >= 0 ? str.substring(raw, dotIx) : ".0"
    (x < 0 ? "-" : "") + fmtIntWithCommas(intStr) + fracStr

fmtAlertBuy(reasonDetail) =>
    alertMsgStyleEff == "Full" ? "BUY - " + syminfo.ticker + " - " + reasonDetail : "BUY - " + syminfo.ticker

fmtAlertSell(reasonDetail) =>
    alertMsgStyleEff == "Full" ? "SELL - " + syminfo.ticker + " - " + reasonDetail : "SELL - " + syminfo.ticker

fmtOnOff(x) =>
    x ? "ON" : "OFF"

fmtF(x) =>
    (x < 0 ? "-" : "") + fmtLeadingZeroDec(str.tostring(math.abs(x), "#.##"))

fmtI(x) =>
    str.tostring(x)

fmtShortDate(t) =>
    str.tostring(dayofmonth(t), "00") + "-" + str.tostring(month(t), "00") + "-" + str.tostring(year(t))

f_scRegIndex(r) =>
    r == 10 ? 0 : r == 1 ? 1 : r == 2 ? 2 : r == 3 ? 3 : r == 4 ? 4 : na

f_scTypeIndex(lbl) =>
    lbl == "PT" ? 0 : lbl == "SL" ? 1 : lbl == "TSL" ? 2 : lbl == "BB" ? 3 : lbl == "BM" ? 4 : lbl == "V" ? 5 : lbl == "RC" ? 6 : lbl == "RG" ? 7 : lbl == "SLead" ? 8 : lbl == "Brk" ? 9 : lbl == "RCL" ? 10 : lbl == "FV" ? 11 : lbl == "EOD" ? 12 : lbl == "GapFail" ? 13 : lbl == "GapFail2" ? 14 : lbl == "DSMA" ? 15 : lbl == "M" ? 16 : na

f_diagExitLabel(i) =>
    i == 0 ? "PT" : i == 1 ? "SL" : i == 2 ? "TSL" : i == 3 ? "BB" : i == 4 ? "BM" : i == 5 ? "V" : i == 6 ? "RC" : i == 7 ? "RG" : i == 8 ? "SLead" : i == 9 ? "Brk" : i == 10 ? "RCL" : i == 11 ? "FV" : i == 12 ? "EOD" : i == 13 ? "GapFail" : i == 14 ? "GapFail2" : i == 15 ? "DSMA" : "Manual"

// Option-A SQQQ cell blocklist: returns true when the (trigger x entry-regime) cell is listed in sqqqBlockList (assembled from the 8 dropdown slots), so actual SQQQ trading (sim + continuous) skips it. Token built as TRIGGER-Rn; matching is space-insensitive and case-insensitive. Research table stays ungated (still shows blocked cells).
f_sqCellBlocked(_typeIdx, _regIdx) =>
    _blocked = false
    _list = str.upper(str.replace_all(sqqqBlockList, " ", ""))
    if str.length(_list) > 0 and not na(_typeIdx) and not na(_regIdx)
        _tok = str.upper(f_diagExitLabel(_typeIdx) + "-R" + str.tostring(_regIdx))
        _parts = str.split(_list, ",")
        for _i = 0 to array.size(_parts) - 1
            if array.get(_parts, _i) == _tok
                _blocked := true
    _blocked

f_sqqqRankType(rankIdx) =>
    rankIdx == 0 ? 2 : rankIdx == 1 ? 4 : rankIdx == 2 ? 10 : rankIdx == 3 ? 7 : rankIdx == 4 ? 15 : rankIdx == 5 ? 12 : rankIdx == 6 ? 8 : rankIdx == 7 ? 1 : rankIdx == 8 ? 3 : rankIdx == 9 ? 14 : rankIdx == 10 ? 9 : rankIdx == 11 ? 6 : rankIdx == 12 ? 11 : rankIdx == 13 ? 5 : rankIdx == 14 ? 13 : 0

f_sqqqRankLabel(rankIdx) =>
    rankIdx == 0 ? "01 TSL" : rankIdx == 1 ? "02 BM" : rankIdx == 2 ? "03 RCL" : rankIdx == 3 ? "04 RG" : rankIdx == 4 ? "05 DSMA" : rankIdx == 5 ? "06 EOD" : rankIdx == 6 ? "07 SLead" : rankIdx == 7 ? "08 SL" : rankIdx == 8 ? "09 BB" : rankIdx == 9 ? "10 GapF2" : rankIdx == 10 ? "11 Brk" : rankIdx == 11 ? "12 RC" : rankIdx == 12 ? "13 FV" : rankIdx == 13 ? "14 V" : rankIdx == 14 ? "15 GapF" : "16 PT"

f_sqqqTriggerOn(typeIdx) =>
    s2_sqqqAll or (typeIdx == 2 and s2_sqqqTsl) or (typeIdx == 4 and s2_sqqqBm) or (typeIdx == 10 and s2_sqqqRcl) or (typeIdx == 7 and s2_sqqqRg) or (typeIdx == 15 and s2_sqqqDsma) or (typeIdx == 12 and s2_sqqqEod) or (typeIdx == 8 and s2_sqqqSlead) or (typeIdx == 1 and s2_sqqqSl) or (typeIdx == 3 and s2_sqqqBb) or (typeIdx == 14 and s2_sqqqGapFail2) or (typeIdx == 9 and s2_sqqqBrk) or (typeIdx == 6 and s2_sqqqRc) or (typeIdx == 11 and s2_sqqqFv) or (typeIdx == 5 and s2_sqqqV) or (typeIdx == 13 and s2_sqqqGapFail) or (typeIdx == 0 and s2_sqqqPt)

f_sqqqMedianByType(encodedVals, typeIdx) =>
    tmp = array.new_float()
    float med = na
    if array.size(encodedVals) > 0
        for i = 0 to array.size(encodedVals) - 1
            if array.get(encodedVals, i) >= typeIdx * 100000.0 and array.get(encodedVals, i) < (typeIdx + 1) * 100000.0
                array.push(tmp, array.get(encodedVals, i) - typeIdx * 100000.0 - 10000.0)
    if array.size(tmp) > 0
        array.sort(tmp, order.ascending)
        med := array.size(tmp) % 2 == 1 ? array.get(tmp, int(math.floor(array.size(tmp) / 2))) : (array.get(tmp, int(math.floor(array.size(tmp) / 2)) - 1) + array.get(tmp, int(math.floor(array.size(tmp) / 2)))) / 2.0
    med

f_scCellIndex(typeIdx, regIdx) =>
    typeIdx * 5 + regIdx

fmtRegimeShort(r) =>
    r == 10 ? "R0" : r == 1 ? "R1" : r == 2 ? "R2" : r == 3 ? "R3" : r == 4 ? "R4" : "?"

regimeMarkerColor(r) =>
    r == 10 ? color.white : r == 1 ? color.green : r == 2 ? color.orange : r == 3 ? color.lime : r == 4 ? color.purple : color.gray

retBucketRegIndex(r) =>
    r == 10 ? 0 : r == 1 ? 1 : r == 2 ? 2 : r == 3 ? 3 : r == 4 ? 4 : na

retBucketIndex(pct) =>
    pct < -10.0 ? 0 : pct >= 10.0 ? 21 : pct < 0.0 ? 1 + int(math.floor(pct + 10.0)) : 11 + int(math.floor(pct))

retBucketLabel(idx) =>
    idx == 0 ? "<-10%" : idx == 21 ? ">10%" : str.tostring(idx - 11) + " to " + str.tostring(idx - 10) + "%"

f_perfBucketIndex(absPct) =>
    absPct > 0.0 and absPct < 2.0 ? 0 : absPct >= 2.0 and absPct < 5.0 ? 1 : absPct >= 5.0 and absPct < 10.0 ? 2 : absPct >= 10.0 and absPct < 15.0 ? 3 : absPct >= 15.0 and absPct < 20.0 ? 4 : absPct >= 20.0 and absPct < 25.0 ? 5 : absPct >= 25.0 and absPct < 30.0 ? 6 : absPct >= 30.0 ? 7 : na

f_contRecordTrade(pct, fa, ia) =>
    array.set(ia, 0, array.get(ia, 0) + 1)
    array.set(fa, 6, array.get(fa, 6) + pct)
    array.set(fa, 7, array.get(fa, 7) + pct * pct)
    array.set(fa, 2, na(array.get(fa, 2)) ? pct : math.max(array.get(fa, 2), pct))
    array.set(fa, 3, na(array.get(fa, 3)) ? pct : math.min(array.get(fa, 3), pct))
    if pct > 0
        array.set(ia, 1, array.get(ia, 1) + 1)
        array.set(fa, 4, array.get(fa, 4) + pct)
        array.set(ia, 5, array.get(ia, 5) + 1)
        array.set(ia, 3, 0)
        array.set(ia, 6, math.max(array.get(ia, 6), array.get(ia, 5)))
        bi = f_perfBucketIndex(pct)
        if not na(bi)
            array.set(ia, 15 + bi, array.get(ia, 15 + bi) + 1)
    else if pct < 0
        array.set(ia, 2, array.get(ia, 2) + 1)
        array.set(fa, 5, array.get(fa, 5) + pct)
        array.set(ia, 3, array.get(ia, 3) + 1)
        array.set(ia, 5, 0)
        array.set(ia, 4, math.max(array.get(ia, 4), array.get(ia, 3)))
        bi = f_perfBucketIndex(-pct)
        if not na(bi)
            array.set(ia, 7 + bi, array.get(ia, 7 + bi) + 1)

f_contTrackDD(eq, fa, ia, dateVal, barVal) =>
    if eq > array.get(fa, 0)
        if array.get(ia, 23) == 1
            if array.get(ia, 27) == 1
                array.set(ia, 25, barVal - array.get(ia, 24))
                array.set(ia, 26, array.get(ia, 28))
                array.set(ia, 29, 1)
            array.set(ia, 23, 0)
            array.set(ia, 24, na)
            array.set(ia, 30, na)
            array.set(ia, 28, 0)
            array.set(ia, 27, 0)
        array.set(fa, 0, eq)
    dd = array.get(fa, 0) > 0 ? (array.get(fa, 0) - eq) / array.get(fa, 0) * 100.0 : 0.0
    if dd > 0
        if array.get(ia, 23) == 0
            array.set(ia, 23, 1)
            array.set(ia, 24, barVal)
            array.set(ia, 30, dateVal)
            array.set(ia, 28, 1)
            array.set(ia, 27, 0)
        else if dateVal != array.get(ia, 30)
            array.set(ia, 28, array.get(ia, 28) + 1)
            array.set(ia, 30, dateVal)
    if dd > array.get(fa, 1)
        array.set(fa, 1, dd)
        array.set(ia, 27, 1)
        array.set(ia, 25, na)
        array.set(ia, 26, na)
        array.set(ia, 29, 0)

f_p4Row(tbl, row, label, value, valueColor, txtSize) =>
    table.cell(tbl, 0, row, label, text_color=color.white, text_size=txtSize)
    table.cell(tbl, 1, row, value, text_color=valueColor, text_size=txtSize)
    row + 1

f_p4BucketHeader(tbl, row, txtSize) =>
    table.cell(tbl, 0, row, "Loss Buckets", text_color=color.yellow, text_size=txtSize)
    table.cell(tbl, 1, row, "Loss", text_color=color.red, text_size=txtSize)
    table.cell(tbl, 2, row, "Win", text_color=color.green, text_size=txtSize)
    row + 1

f_p4BucketRow(tbl, row, label, lossCnt, winCnt, txtSize) =>
    table.cell(tbl, 0, row, label, text_color=color.white, text_size=txtSize)
    table.cell(tbl, 1, row, str.tostring(lossCnt), text_color=lossCnt > 0 ? color.red : color.gray, text_size=txtSize)
    table.cell(tbl, 2, row, str.tostring(winCnt), text_color=winCnt > 0 ? color.green : color.gray, text_size=txtSize)
    row + 1

// ============================================================
// VIX DATA & SIGNAL (per-regime SMAs)
// ============================================================
vixClose = request.security("CBOE:VIX", timeframe.period, close, lookahead=barmerge.lookahead_off)
sqqqClose = request.security("NASDAQ:SQQQ", timeframe.period, close, barmerge.gaps_off, barmerge.lookahead_off)
vixSmaMaster = ta.sma(vixClose, masterVixSmaLengthEff)
// All regimes share the one master VIX SMA (per-regime SMAs were identical since v007), so VIX%-above-SMA is a single series too.
vixAbove = vixSmaMaster > 0 ? (vixClose - vixSmaMaster) / vixSmaMaster * 100 : 0.0

// Regime detection — shared master SMA level + slope determines the regime map.
smaRising = vixSmaMaster > vixSmaMaster[masterSlopeLookbackEff]
isR1Regime = smaRising and vixSmaMaster >= r1MinSmaEff
isR2Regime = (not smaRising) and vixSmaMaster >= r1MinSmaEff
isR3Regime = smaRising and vixSmaMaster >= r0MaxSmaEff and vixSmaMaster < r1MinSmaEff
isR4Regime = (not smaRising) and vixSmaMaster >= r0MaxSmaEff and vixSmaMaster < r1MinSmaEff
isR0Regime = vixSmaMaster < r0MaxSmaEff and not isR1Regime and not isR2Regime and not isR3Regime and not isR4Regime

// Bollinger — BB sell (upper band exits only)
bbMid = ta.sma(bbSrcEff, bbLengthEff)
gbfMidXdn = ta.crossunder(close, bbMid)
bbDev = bbMultEff * ta.stdev(bbSrcEff, bbLengthEff)
bbUpper = bbMid + bbDev
bbLower = bbMid - bbDev
bbUpperOk = not na(bbUpper)
bbUpperTouch = bbUpperOk and high >= bbUpper
bbCrossHighUpper = ta.crossover(high, bbUpper)
bbUpperCross = bbUpperOk and bbCrossHighUpper
// Bollinger — BB buy (separate definition; buy confirmations)
bbBuyMid = ta.sma(bbBuySrcEff, bbBuyLengthEff)
bbBuyDev = bbBuyMultEff * ta.stdev(bbBuySrcEff, bbBuyLengthEff)
bbBuyUpper = bbBuyMid + bbBuyDev
bbBuyLower = bbBuyMid - bbBuyDev
bbBuyOk = not na(bbBuyMid) and not na(bbBuyUpper) and not na(bbBuyLower)
bbBuyLowerTouch = bbBuyOk and low <= bbBuyLower
bbCrossLowBuyLower = ta.crossunder(low, bbBuyLower)
bbBuyLowerCross = bbBuyOk and bbCrossLowBuyLower
bbBuyLowerTrig = bbBuyLowerModeEff == "TOUCH" ? bbBuyLowerTouch : bbBuyLowerCross

dailySmaBearFast = request.security(syminfo.tickerid, "D", ta.sma(close, dailySmaBearFastLenEff), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBearSlow = request.security(syminfo.tickerid, "D", ta.sma(close, dailySmaBearSlowLenEff), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBearBelowThreshold = not na(dailySmaBearFast) and not na(dailySmaBearSlow) and dailySmaBearSlow != 0 ? dailySmaBearFast <= dailySmaBearSlow * (1 - dailySmaBearBelowPctEff / 100.0) : false
dailySmaBearPrevBelow = dailySmaBearBelowThreshold[1] == true
dailySmaBearBelowEvent = dailySmaBearBelowThreshold and not dailySmaBearPrevBelow
// #2 CLARIFIED (behavior unchanged): the daily SMA "cross" trigger is intentionally disabled (false). Rule 1 fires on the sustained BELOW-BAND state (dailySmaBearBelowThreshold), armed by the ONE-SHOT 'first bar below the band' event (dailySmaBearBelowEvent = below now AND not below last bar). Full block lifecycle is documented at the arming site near buySignalS2Raw.
dailySmaBearCrossTrigger = false
dailySmaBearBelowTrigger = dailySmaBearBelowEvent
dailySmaBear2CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear2FastLenEff), ta.sma(close, dailySmaBear2SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear2CrossEvent = dailySmaBear2CrossRaw and not dailySmaBear2CrossRaw[1]
dailySmaBear2CrossTrigger = dailySmaBear2CrossEvent
dailySmaBear2BelowTrigger = false
dailySmaBear3CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear3FastLenEff), ta.sma(close, dailySmaBear3SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear3CrossEvent = dailySmaBear3CrossRaw and not dailySmaBear3CrossRaw[1]
dailySmaBear3CrossTrigger = dailySmaBear3CrossEvent
dailySmaBear3BelowTrigger = false
dailySmaBear4CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear4FastLenEff), ta.sma(close, dailySmaBear4SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear4CrossEvent = dailySmaBear4CrossRaw and not dailySmaBear4CrossRaw[1]
dailySmaBear4CrossTrigger = dailySmaBear4CrossEvent
dailySmaBear4BelowTrigger = false
dailySmaBear5CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear5FastLenEff), ta.sma(close, dailySmaBear5SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear5CrossEvent = dailySmaBear5CrossRaw and not dailySmaBear5CrossRaw[1]
dailySmaBear5CrossTrigger = dailySmaBear5CrossEvent
dailySmaBear5BelowTrigger = false
dailySmaBear6CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear6FastLenEff), ta.sma(close, dailySmaBear6SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear6CrossEvent = dailySmaBear6CrossRaw and not dailySmaBear6CrossRaw[1]
dailySmaBear6CrossTrigger = dailySmaBear6CrossEvent
dailySmaBear6BelowTrigger = false
dailySmaBear7CrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, dailySmaBear7FastLenEff), ta.sma(close, dailySmaBear7SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBear7CrossEvent = dailySmaBear7CrossRaw and not dailySmaBear7CrossRaw[1]
dailySmaBear7CrossTrigger = dailySmaBear7CrossEvent
dailySmaBear7BelowTrigger = false
dailySmaEntryNoBuyCrossRaw = request.security(syminfo.tickerid, "D", ta.crossunder(ta.sma(close, s2_dseNoBuyFastLen), ta.sma(close, s2_dseNoBuySlowLen)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaEntryNoBuyCrossTrigger = dailySmaEntryNoBuyCrossRaw and not dailySmaEntryNoBuyCrossRaw[1]
dailySmaBullFast = request.security(syminfo.tickerid, "D", ta.sma(close, dailySmaBullFastLenEff), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBullSlow = request.security(syminfo.tickerid, "D", ta.sma(close, dailySmaBullSlowLenEff), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBullAboveThreshold = not na(dailySmaBullFast) and not na(dailySmaBullSlow) and dailySmaBullSlow != 0 ? dailySmaBullFast >= dailySmaBullSlow * (1 + dailySmaBullAbovePctEff / 100.0) : false
dailySmaBullCrossTrigger = false
dailySmaBullAboveTrigger = dailySmaBullAboveThreshold
dailySmaBull2CrossRaw = request.security(syminfo.tickerid, "D", ta.crossover(ta.sma(close, dailySmaBull2FastLenEff), ta.sma(close, dailySmaBull2SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBull2CrossEvent = dailySmaBull2CrossRaw and not dailySmaBull2CrossRaw[1]
dailySmaBull2CrossTrigger = dailySmaBull2CrossEvent
dailySmaBull2AboveTrigger = false
dailySmaBull3CrossRaw = request.security(syminfo.tickerid, "D", ta.crossover(ta.sma(close, dailySmaBull3FastLenEff), ta.sma(close, dailySmaBull3SlowLenEff)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBull3CrossEvent = dailySmaBull3CrossRaw and not dailySmaBull3CrossRaw[1]
dailySmaBull3CrossTrigger = dailySmaBull3CrossEvent
dailySmaBull3AboveTrigger = false
dailySmaBull4CrossRaw = request.security(syminfo.tickerid, "D", ta.crossover(ta.sma(close, 10), ta.sma(close, 50)), barmerge.gaps_off, barmerge.lookahead_off)
dailySmaBull4CrossTrigger = dailySmaBull4CrossRaw and not dailySmaBull4CrossRaw[1]
[dailyForensicSma20, dailyForensicSma50, dailyForensicSma100, dailyForensicSma200, dailyForensicSma20Up, dailyForensicSma50Up, dailyForensicSma100Up, dailyForensicSma200Up, dailyForensic20x50UpBars, dailyForensic20x50DnBars] = request.security(syminfo.tickerid, "D", [ta.sma(close, 20), ta.sma(close, 50), ta.sma(close, 100), ta.sma(close, 200), ta.rising(ta.sma(close, 20), 1), ta.rising(ta.sma(close, 50), 1), ta.rising(ta.sma(close, 100), 1), ta.rising(ta.sma(close, 200), 1), ta.barssince(ta.crossover(ta.sma(close, 20), ta.sma(close, 50))), ta.barssince(ta.crossunder(ta.sma(close, 20), ta.sma(close, 50)))], barmerge.gaps_off, barmerge.lookahead_off)

// BB buy pass (global scope). Rolling count of 0/1 bars: ta.sma(x, n) * n (avoids ta.sum compatibility issues).
r1BbMinBelowOk = bbBuyR1MinBelowEff <= 0 ? true : math.round(ta.sma(close < bbBuyMid ? 1.0 : 0.0, bbBuyR1MinBelowEff) * bbBuyR1MinBelowEff) == bbBuyR1MinBelowEff
r1BbCondLraw = bbBuyR1LbEff <= 0 ? bbBuyLowerTrig : math.round(ta.sma(bbBuyLowerTrig ? 1.0 : 0.0, bbBuyR1LbEff) * bbBuyR1LbEff) > 0
r1BbEnCnt = (bbBuyR1LowerEff ? 1 : 0) + (bbBuyR1BelowMidEff ? 1 : 0) + (bbBuyR1LowerHalfEff ? 1 : 0) + (bbBuyR1NotUpperEff ? 1 : 0)
r1BbPassAll = (not bbBuyR1LowerEff or r1BbCondLraw) and (not bbBuyR1BelowMidEff or close < bbBuyMid) and (not bbBuyR1LowerHalfEff or (close >= bbBuyLower and close <= bbBuyMid)) and (not bbBuyR1NotUpperEff or close < bbBuyUpper)
r1BbPassAny = (bbBuyR1LowerEff and r1BbCondLraw) or (bbBuyR1BelowMidEff and close < bbBuyMid) or (bbBuyR1LowerHalfEff and (close >= bbBuyLower and close <= bbBuyMid)) or (bbBuyR1NotUpperEff and close < bbBuyUpper)
r1BbComb = r1BbEnCnt == 0 ? true : bbBuyR1MatchEff == "ALL" ? r1BbPassAll : r1BbPassAny
r1BuyBbOk = (not bbBuyMasterEff) or (not bbBuyUseR1Eff or (bbBuyOk and r1BbMinBelowOk and r1BbComb))

r2BbMinBelowOk = bbBuyR2MinBelowEff <= 0 ? true : math.round(ta.sma(close < bbBuyMid ? 1.0 : 0.0, bbBuyR2MinBelowEff) * bbBuyR2MinBelowEff) == bbBuyR2MinBelowEff
r2BbCondLraw = bbBuyR2LbEff <= 0 ? bbBuyLowerTrig : math.round(ta.sma(bbBuyLowerTrig ? 1.0 : 0.0, bbBuyR2LbEff) * bbBuyR2LbEff) > 0
r2BbEnCnt = (bbBuyR2LowerEff ? 1 : 0) + (bbBuyR2BelowMidEff ? 1 : 0) + (bbBuyR2LowerHalfEff ? 1 : 0) + (bbBuyR2NotUpperEff ? 1 : 0)
r2BbPassAll = (not bbBuyR2LowerEff or r2BbCondLraw) and (not bbBuyR2BelowMidEff or close < bbBuyMid) and (not bbBuyR2LowerHalfEff or (close >= bbBuyLower and close <= bbBuyMid)) and (not bbBuyR2NotUpperEff or close < bbBuyUpper)
r2BbPassAny = (bbBuyR2LowerEff and r2BbCondLraw) or (bbBuyR2BelowMidEff and close < bbBuyMid) or (bbBuyR2LowerHalfEff and (close >= bbBuyLower and close <= bbBuyMid)) or (bbBuyR2NotUpperEff and close < bbBuyUpper)
r2BbComb = r2BbEnCnt == 0 ? true : bbBuyR2MatchEff == "ALL" ? r2BbPassAll : r2BbPassAny
r2BuyBbOk = (not bbBuyMasterEff) or (not bbBuyUseR2Eff or (bbBuyOk and r2BbMinBelowOk and r2BbComb))

r3BbMinBelowOk = bbBuyR3MinBelowEff <= 0 ? true : math.round(ta.sma(close < bbBuyMid ? 1.0 : 0.0, bbBuyR3MinBelowEff) * bbBuyR3MinBelowEff) == bbBuyR3MinBelowEff
r3BbCondLraw = bbBuyR3LbEff <= 0 ? bbBuyLowerTrig : math.round(ta.sma(bbBuyLowerTrig ? 1.0 : 0.0, bbBuyR3LbEff) * bbBuyR3LbEff) > 0
r3BbEnCnt = (bbBuyR3LowerEff ? 1 : 0) + (bbBuyR3BelowMidEff ? 1 : 0) + (bbBuyR3LowerHalfEff ? 1 : 0) + (bbBuyR3NotUpperEff ? 1 : 0)
r3BbPassAll = (not bbBuyR3LowerEff or r3BbCondLraw) and (not bbBuyR3BelowMidEff or close < bbBuyMid) and (not bbBuyR3LowerHalfEff or (close >= bbBuyLower and close <= bbBuyMid)) and (not bbBuyR3NotUpperEff or close < bbBuyUpper)
r3BbPassAny = (bbBuyR3LowerEff and r3BbCondLraw) or (bbBuyR3BelowMidEff and close < bbBuyMid) or (bbBuyR3LowerHalfEff and (close >= bbBuyLower and close <= bbBuyMid)) or (bbBuyR3NotUpperEff and close < bbBuyUpper)
r3BbComb = r3BbEnCnt == 0 ? true : bbBuyR3MatchEff == "ALL" ? r3BbPassAll : r3BbPassAny
r3BuyBbOk = (not bbBuyMasterEff) or (not bbBuyUseR3Eff or (bbBuyOk and r3BbMinBelowOk and r3BbComb))

r4BbMinBelowOk = bbBuyR4MinBelowEff <= 0 ? true : math.round(ta.sma(close < bbBuyMid ? 1.0 : 0.0, bbBuyR4MinBelowEff) * bbBuyR4MinBelowEff) == bbBuyR4MinBelowEff
r4BbCondLraw = bbBuyR4LbEff <= 0 ? bbBuyLowerTrig : math.round(ta.sma(bbBuyLowerTrig ? 1.0 : 0.0, bbBuyR4LbEff) * bbBuyR4LbEff) > 0
r4BbEnCnt = (bbBuyR4LowerEff ? 1 : 0) + (bbBuyR4BelowMidEff ? 1 : 0) + (bbBuyR4LowerHalfEff ? 1 : 0) + (bbBuyR4NotUpperEff ? 1 : 0)
r4BbPassAll = (not bbBuyR4LowerEff or r4BbCondLraw) and (not bbBuyR4BelowMidEff or close < bbBuyMid) and (not bbBuyR4LowerHalfEff or (close >= bbBuyLower and close <= bbBuyMid)) and (not bbBuyR4NotUpperEff or close < bbBuyUpper)
r4BbPassAny = (bbBuyR4LowerEff and r4BbCondLraw) or (bbBuyR4BelowMidEff and close < bbBuyMid) or (bbBuyR4LowerHalfEff and (close >= bbBuyLower and close <= bbBuyMid)) or (bbBuyR4NotUpperEff and close < bbBuyUpper)
r4BbComb = r4BbEnCnt == 0 ? true : bbBuyR4MatchEff == "ALL" ? r4BbPassAll : r4BbPassAny
r4BuyBbOk = (not bbBuyMasterEff) or (not bbBuyUseR4Eff or (bbBuyOk and r4BbMinBelowOk and r4BbComb))

r1AtrRisk = ta.atr(r1AtrRiskLengthEff)
r1AtrRiskPct = close != 0 ? r1AtrRisk / close * 100.0 : na
r1AtrRiskPctValid = not na(r1AtrRiskPct) and not na(r1AtrRiskPct[1])
r1AtrRiskPctRising = r1AtrRiskPctValid and r1AtrRiskPct > r1AtrRiskPct[1]
bbBuyWidthPct = bbBuyOk and bbBuyMid != 0 ? (bbBuyUpper - bbBuyLower) / bbBuyMid * 100.0 : na
bbBuyMidSlopePct = bbBuyOk and not na(bbBuyMid[bbMidSlopeLookbackEff]) and bbBuyMid[bbMidSlopeLookbackEff] != 0 ? (bbBuyMid - bbBuyMid[bbMidSlopeLookbackEff]) / bbBuyMid[bbMidSlopeLookbackEff] * 100.0 : na

// Optional Bollinger display. Reuses the strategy's BB sell/buy settings; no signal impact.
bbSellUpperPlot = plot(showBbSellBands and showBbUpper ? bbUpper : na, "BB Sell Upper", color=color.new(color.orange, 0), linewidth=1, force_overlay=true)
bbSellMidPlot = plot(showBbSellBands and showBbMiddle ? bbMid : na, "BB Sell Middle", color=color.new(color.orange, 35), linewidth=1, force_overlay=true)
bbSellLowerPlot = plot(showBbSellBands and showBbLower ? bbLower : na, "BB Sell Lower", color=color.new(color.orange, 0), linewidth=1, force_overlay=true)
bbBuyUpperPlot = plot(showBbBuyBands and showBbUpper ? bbBuyUpper : na, "BB Buy Upper", color=color.new(color.aqua, 0), linewidth=1, force_overlay=true)
bbBuyMidPlot = plot(showBbBuyBands and showBbMiddle ? bbBuyMid : na, "BB Buy Middle", color=color.new(color.aqua, 35), linewidth=1, force_overlay=true)
bbBuyLowerPlot = plot(showBbBuyBands and showBbLower ? bbBuyLower : na, "BB Buy Lower", color=color.new(color.aqua, 0), linewidth=1, force_overlay=true)
fill(bbSellUpperPlot, bbSellLowerPlot, color=showBbSellBands and showBbFill ? color.new(color.orange, bbDisplayTransparency) : na, title="BB Sell Fill")
fill(bbBuyUpperPlot, bbBuyLowerPlot, color=showBbBuyBands and showBbFill ? color.new(color.aqua, bbDisplayTransparency) : na, title="BB Buy Fill")

// ============================================================
// STRATEGY LOGIC
// ============================================================
var bool inPosition = false
var int entryRegime = 0
var float entryPrice = na
var int entryTime = na
var int entryBarIndex = na
var float entryVixPct = na
var float entryAtrPct = na
var bool entryAtrPctValid = false
var bool entryAtrPctRising = false
var float entryBbBuyWidthPct = na
var float entryBbBuyMidSlopePct = na
var string entrySignalType = ""
var string entryBearFlags = ""
var string entryBullFlags = ""
var string entryBbZone = ""
var string entryDailySmaStack = ""
var string entryDailySmaSlope = ""
var string entryDailySmaCross = ""
var float entryDailySma20v50 = na
var float entryDailySma50v100 = na
var float entryDailySma100v200 = na
var float entryDailySma20v200 = na
var string tradeBullSuppFlags = ""
var float tradeMfePct = na
var float tradeMaePct = na
var int lastSellBar = 0
var float lastSellPrice = na
var int rcPtWaitR3LastBar = na
var int rcSlTslWaitLastBar = na
var int rcBmWaitR0LastBar = na
var int rcSLeadWaitR12LastBar = na
var bool rcSLeadRecReleased = false
var int dailySmaBearBlockLeft = 0
var int dailySmaBear2BlockLeft = 0
var int dailySmaBear3BlockLeft = 0
var int dailySmaBear4BlockLeft = 0
var int dailySmaBear5BlockLeft = 0
var int dailySmaBear6BlockLeft = 0
var int dailySmaBear7BlockLeft = 0
var int dailySmaEntryNoBuyLeft = 0
var int dailySmaEntryR2NoBuyLeft = 0
var int dailySmaEntryR4NoBuyLeft = 0
var int dailySmaEntry50100R4Left = 0
var int dailySmaEntry50100R3Left = 0
var int dailySmaEntry50200R2Left = 0
var int dailySmaBullSellActiveLeft = 0
var int dailySmaBull2SellActiveLeft = 0
var int dailySmaBull3SellActiveLeft = 0
var int dailySmaBull4SellActiveLeft = 0
var int gapBounceWatchLeft = 0
var int gapBounce2WatchLeft = 0
var float compoundedValue = 100.0
var int totalTrades = 0
var int winTrades = 0
var float firstBuyPrice = na
var float endPrice = na
var bool startReached = false
var bool endReached = false
var int barsR0 = 0
var int barsR1 = 0
var int barsR2 = 0
var int barsR3 = 0
var int barsR4 = 0
var int tradesR0 = 0
var int tradesR1 = 0
var int tradesR2 = 0
var int tradesR3 = 0
var int tradesR4 = 0
var int winsR0 = 0
var int winsR1 = 0
var int winsR2 = 0
var int winsR3 = 0
var int winsR4 = 0
var float compR0 = 100.0
var float compR1 = 100.0
var float compR2 = 100.0
var float compR3 = 100.0
var float compR4 = 100.0
// Panel 4 — performance metrics adapted to Strategy 6's close-style trade stream.
var float peakEquity = 100.0
var float maxDDPct = 0.0
var bool ddActive = false
var int ddStartBar = na
var int ddLastDate = na
var int ddTradingDays = 0
var bool ddEpisodeHasMax = false
var int maxDDRecoveryBars = na
var int maxDDRecoveryDays = na
var bool maxDDRecovered = false
var float bestTradePct = na
var float worstTradePct = na
var float sumWinPct = 0.0
var float sumLossPct = 0.0
var int loseCount = 0
var int curLoseStreak = 0
var int maxLoseStreak = 0
var int curWinStreak = 0
var int maxWinStreak = 0
var float sumRet = 0.0
var float sumRetSq = 0.0
var int loss0to2Count = 0
var int loss2to5Count = 0
var int loss5to10Count = 0
var int loss10to15Count = 0
var int loss15to20Count = 0
var int loss20to25Count = 0
var int loss25to30Count = 0
var int lossOver30Count = 0
var int win0to2Count = 0
var int win2to5Count = 0
var int win5to10Count = 0
var int win10to15Count = 0
var int win15to20Count = 0
var int win20to25Count = 0
var int win25to30Count = 0
var int winOver30Count = 0
var bool sqqqInPosition = false
var float sqqqEntryPrice = na
var float sqqqEquity = 100.0
var int sqqqTrades = 0
var int sqqqWins = 0
var float lastInRangeSqqqClose = na
var float contEquity = 100.0
var int contState = 0
var float contSqqqEntryPrice = na
var int contTqqqLegs = 0
var int contSqqqLegs = 0
var int contCashLegs = 0
var array contPerfF = array.from(100.0, 0.0, na, na, 0.0, 0.0, 0.0, 0.0)
var array contPerfI = array.new_int(31, 0)
var int sqqqStatsPendType = na
var int sqqqStatsPendReg = na
var float sqqqStatsPendPrice = na
var array sqqqStatsTrades = array.new_int(80, 0)
var array sqqqStatsWins = array.new_int(80, 0)
var array sqqqStatsComp = array.new_float(80, 100.0)
var array sqqqStatsSum = array.new_float(80, 0.0)
var array sqqqStatsBest = array.new_float(80, na)
var array sqqqStatsWorst = array.new_float(80, na)
var array sqqqStatsMedVals = array.new_float()
var int r0BarsInRegime = 0
var int r1BarsInRegime = 0
var int r2BarsInRegime = 0
var int r3BarsInRegime = 0
var int r4BarsInRegime = 0
var int confirmedRegime = -1
var int newRegimeBars = 0
var bool r0Rc03Hold = false
var bool rcBuyPending = false
var int rcBuyPendingTarget = 0

// BB pullback state — armed when first BB cross detected, sell on close back below BB
var bool bbPullbackArmed = false
var int bbPullbackBars = 0

// Shared soft trailing (PT / VIX / BB / BM): one peak & stored trail % until breach
var bool softTrailArmed = false
var float softTrailPeak = na
var float softTrailPct = na
var int softTrailArmKind = 0

f_addFlag(flags, flag) =>
    str.contains(flags, flag) ? flags : flags == "" ? flag : flags + "," + flag

f_entrySignalType(isManual, isR0, isRC, isR1, isR2, isR3) =>
    isManual ? "M" : isR0 ? "R0" : isRC ? "RC" : isR1 ? "R1" : isR2 ? "R2" : isR3 ? "R3" : "R4"

f_bbEntryZone(isOk, px, lowerBand, midBand, upperBand) =>
    isOk ? px <= lowerBand ? "<=L" : px < midBand ? "L-M" : px <= upperBand ? "M-U" : ">U" : "-"

f_bearFlags(b1On, b2On, b3On, b4On, b5On, b6On, b7On) =>
    flags = ""
    flags := b1On ? f_addFlag(flags, "B1") : flags
    flags := b2On ? f_addFlag(flags, "B2") : flags
    flags := b3On ? f_addFlag(flags, "B3") : flags
    flags := b4On ? f_addFlag(flags, "B4") : flags
    flags := b5On ? f_addFlag(flags, "B5") : flags
    flags := b6On ? f_addFlag(flags, "B6") : flags
    flags := b7On ? f_addFlag(flags, "B7") : flags
    flags

f_bullFlags(er, bull1R1, bull1R2, bull1R3, bull1R4, bull2R1, bull2R2, bull2R3, bull2R4, bull3R1, bull3R2, bull3R3, bull3R4, bull1Active, bull2Active, bull3Active) =>
    flags = ""
    bullEntry1On = er == 1 ? bull1R1 : er == 2 ? bull1R2 : er == 3 ? bull1R3 : er == 4 ? bull1R4 : false
    bullEntry2On = er == 1 ? bull2R1 : er == 2 ? bull2R2 : er == 3 ? bull2R3 : er == 4 ? bull2R4 : false
    bullEntry3On = er == 1 ? bull3R1 : er == 2 ? bull3R2 : er == 3 ? bull3R3 : er == 4 ? bull3R4 : false
    flags := bullEntry1On and bull1Active ? f_addFlag(flags, "U1") : flags
    flags := bullEntry2On and bull2Active ? f_addFlag(flags, "U2") : flags
    flags := bullEntry3On and bull3Active ? f_addFlag(flags, "U3") : flags
    flags

f_suppFlags(flagsIn, supPT, supV, supBB, supBM, supRC, supEOD, supTSL) =>
    flags = flagsIn
    flags := supPT ? f_addFlag(flags, "PT") : flags
    flags := supV ? f_addFlag(flags, "V") : flags
    flags := supBB ? f_addFlag(flags, "BB") : flags
    flags := supBM ? f_addFlag(flags, "BM") : flags
    flags := supRC ? f_addFlag(flags, "RC") : flags
    flags := supEOD ? f_addFlag(flags, "EOD") : flags
    flags := supTSL ? f_addFlag(flags, "TSL") : flags
    flags

f_relPct(a, b) =>
    not na(a) and not na(b) and b != 0 ? (a - b) / b * 100.0 : na

f_dailySmaStack(s20, s50, s100, s200) =>
    na(s20) or na(s50) or na(s100) or na(s200) ? "-" : "20" + (s20 >= s50 ? ">" : "<") + "50" + (s50 >= s100 ? ">" : "<") + "100" + (s100 >= s200 ? ">" : "<") + "200"

f_dailySmaSlope(up20, up50, up100, up200) =>
    (up20 ? "+" : "-") + (up50 ? "+" : "-") + (up100 ? "+" : "-") + (up200 ? "+" : "-")

f_dailySmaCross(upBars, dnBars) =>
    upOk = not na(upBars)
    dnOk = not na(dnBars)
    not upOk and not dnOk ? "-" : upOk and (not dnOk or upBars <= dnBars) ? "20x50U " + str.tostring(upBars) + "d" : "20x50D " + str.tostring(dnBars) + "d"

f_gbf(wIn, er, mfe, prof, mid, midCu, pos, rng, en, r1, r2, r3, r4, arm, gap, gLo, bars, mXd, tol, sLen, sK, sD, km, pn) =>
    w = wIn
    rOn = er == 1 ? r1 : er == 2 ? r2 : er == 3 ? r3 : er == 4 ? r4 : false
    sc = en and pos and rng and rOn
    if sc and nz(mfe, 0) >= arm
        pc = close[1]
        if not na(pc) and pc > 0
            gp = (gLo ? low - pc : open - pc) / pc * 100
            if gp <= -gap
                w := bars
    fail = false
    if sc and w > 0
        mOk = not na(mid) and mid > 0
        mD = mOk ? math.abs(close - mid) / mid * 100 : 100.0
        bb = mOk and (mXd ? midCu : mD <= tol or close <= mid)
        k = ta.sma(ta.stoch(close, high, low, sLen), sK)
        d = ta.sma(k, sD)
        fail := bb and k < d and k < km and prof >= pn
    if w > 0 and not fail
        w -= 1
    [fail, w]

f_sx(b, st, rf, rr, rc, gbf, rcsl, rcbd, rcl, rg, so, eo) =>
    nk = not b
    b or (nk and st) or (nk and not st and rf) or (nk and not st and not rf and rr) or (nk and not st and not rf and not rr and rc) or (nk and not st and not rf and not rr and not rc and gbf) or (nk and not st and not rf and not rr and not rc and not gbf and rcsl) or (nk and not st and not rf and not rr and not rc and not gbf and not rcsl and rcbd) or (nk and not st and not rf and not rr and not rc and not gbf and not rcsl and not rcbd and rcl) or (nk and not st and not rf and not rr and not rc and not gbf and not rcsl and not rcbd and not rcl and rg) or (nk and not st and not rf and not rr and not rc and not gbf and not rcsl and not rcbd and not rcl and not rg and so) or (nk and not st and not rf and not rr and not rc and not gbf and not rcsl and not rcbd and not rcl and not rg and not so and eo)

// Bars since last entry — used by BM exit minimum hold
var int barsInTrade = 0
var bool rclEmbedArmed = false
var int rclEmbedRun = 0
var bool rcl1EmbedArmed = false
var int rcl1EmbedRun = 0
var bool rcl2EmbedArmed = false
var int rcl2EmbedRun = 0
var bool rcl3EmbedArmed = false
var int rcl3EmbedRun = 0
var bool rcl0EmbedArmed = false
var int rcl0EmbedRun = 0
var bool rclBuyLock = false
var int rclBuyLockSrc = 0
var int rclBuyLockBars = 0
var int rclOsEmbedRun = 0
var bool rclOsEmbedSeen = false
var int rcl1OsEmbedRun = 0
var bool rcl1OsEmbedSeen = false
var int rcl2OsEmbedRun = 0
var bool rcl2OsEmbedSeen = false
var int rcl3OsEmbedRun = 0
var bool rcl3OsEmbedSeen = false
var int rcl0OsEmbedRun = 0
var bool rcl0OsEmbedSeen = false
// Tracked BM slope peak — resets on each entry so peak-fade starts fresh
var float bmSlopePeakTracked = 0.0
dateOnly(t) => timestamp(year(t), month(t), dayofmonth(t), 0, 0)
barDate = dateOnly(time)
startDateOnly = dateOnly(perfStartDate)
endDateOnly = dateOnly(perfEndDate)

if useStartDate
    if barDate >= startDateOnly and not startReached
        startReached := true
        // #12: engine/position/blocker/lock state is NOT reset here anymore — it warms up by running on all bars before the window. Only the display/stats accumulators below are reset so the reporting window's numbers start fresh at the window open.
        compoundedValue := 100.0
        totalTrades := 0
        winTrades := 0
        firstBuyPrice := na
        endPrice := na
        barsR0 := 0
        barsR1 := 0
        barsR2 := 0
        barsR3 := 0
        barsR4 := 0
        tradesR0 := 0
        tradesR1 := 0
        tradesR2 := 0
        tradesR3 := 0
        tradesR4 := 0
        winsR0 := 0
        winsR1 := 0
        winsR2 := 0
        winsR3 := 0
        winsR4 := 0
        compR0 := 100.0
        compR1 := 100.0
        compR2 := 100.0
        compR3 := 100.0
        compR4 := 100.0
        peakEquity := 100.0
        maxDDPct := 0.0
        ddActive := false
        ddStartBar := na
        ddLastDate := na
        ddTradingDays := 0
        ddEpisodeHasMax := false
        maxDDRecoveryBars := na
        maxDDRecoveryDays := na
        maxDDRecovered := false
        bestTradePct := na
        worstTradePct := na
        sumWinPct := 0.0
        sumLossPct := 0.0
        loseCount := 0
        curLoseStreak := 0
        maxLoseStreak := 0
        curWinStreak := 0
        maxWinStreak := 0
        sumRet := 0.0
        sumRetSq := 0.0
        loss0to2Count := 0
        loss2to5Count := 0
        loss5to10Count := 0
        loss10to15Count := 0
        loss15to20Count := 0
        loss20to25Count := 0
        loss25to30Count := 0
        lossOver30Count := 0
        win0to2Count := 0
        win2to5Count := 0
        win5to10Count := 0
        win10to15Count := 0
        win15to20Count := 0
        win20to25Count := 0
        win25to30Count := 0
        winOver30Count := 0
        sqqqInPosition := false
        sqqqEntryPrice := na
        sqqqEquity := 100.0
        sqqqTrades := 0
        sqqqWins := 0
        lastInRangeSqqqClose := na
        contEquity := 100.0
        contState := 0
        contSqqqEntryPrice := na
        contTqqqLegs := 0
        contSqqqLegs := 0
        contCashLegs := 0
        array.set(contPerfF, 0, 100.0)
        array.set(contPerfF, 1, 0.0)
        array.set(contPerfF, 2, na)
        array.set(contPerfF, 3, na)
        array.set(contPerfF, 4, 0.0)
        array.set(contPerfF, 5, 0.0)
        array.set(contPerfF, 6, 0.0)
        array.set(contPerfF, 7, 0.0)
        array.fill(contPerfI, 0)
        array.set(contPerfI, 24, na)
        array.set(contPerfI, 25, na)
        array.set(contPerfI, 26, na)
        array.set(contPerfI, 30, na)
        sqqqStatsPendType := na
        sqqqStatsPendReg := na
        sqqqStatsPendPrice := na
        array.fill(sqqqStatsTrades, 0)
        array.fill(sqqqStatsWins, 0)
        array.fill(sqqqStatsComp, 100.0)
        array.fill(sqqqStatsSum, 0.0)
        array.fill(sqqqStatsBest, na)
        array.fill(sqqqStatsWorst, na)
        array.clear(sqqqStatsMedVals)
        // #12: regime-bar counters, rc pending, soft-trail and bb-pullback engine state are NOT reset here anymore — they warm up on all bars before the window.
    endReached := false
    if barDate <= endDateOnly
        endPrice := close
    else if not endReached
        endReached := true
else
    endPrice := close

// #12 warmup/reporting split: the engine (trades + all state) runs on ALL bars so state warms up identically to the full run. inReport = the reporting window, used only for displayed stats / equity / markers. When 'Use Date Range' is OFF, inReport is always true, so the full-data baseline is byte-identical.
inReport = (useStartDate and startReached and barDate <= endDateOnly) or not useStartDate
withinRange = true
if inReport and not na(sqqqClose)
    lastInRangeSqqqClose := sqqqClose

// No-sell zone: BB mid rising = strong TQQQ uptrend, suppress soft exits
vixSmaFalling = not smaRising
bbMidRising = bbMid > bbMid[bbNoSellLookbackEff]
bbMidSlopeVal = bbMid - bbMid[bbMidSlopeLookbackEff]
inNoSellZone = bbNoSellZoneEff and inPosition and bbMidRising

// BB upper sell exit (BB sell section) — with optional pullback wait
bbUpperHitRaw = bbUpperOk and (bbUpperModeEff == "TOUCH" ? bbUpperTouch : bbUpperCross)
bbCloseBelowUpper = bbUpperOk and close < bbUpper

// Determine if current entry regime uses pullback wait
bbWaitActive = (entryRegime == 1 and bbR1BbWaitEff) or (entryRegime == 2 and bbR2BbWaitEff) or (entryRegime == 3 and bbR3BbWaitEff) or (entryRegime == 4 and bbR4BbWaitEff)
bbWaitMaxBars = entryRegime == 1 ? bbR1BbMaxWaitEff : entryRegime == 2 ? bbR2BbMaxWaitEff : entryRegime == 3 ? bbR3BbMaxWaitEff : bbR4BbMaxWaitEff

// Arm/track pullback state
if not inPosition
    bbPullbackArmed := false
    bbPullbackBars := 0
else if bbWaitActive and bbUpperHitRaw and not bbPullbackArmed
    bbPullbackArmed := true
    bbPullbackBars := 1
else if bbPullbackArmed
    bbPullbackBars := bbPullbackBars + 1

// BB exit per regime: immediate if no wait, or pullback/max-wait if armed
bbPullbackFire = bbPullbackArmed and (bbCloseBelowUpper or bbPullbackBars >= bbWaitMaxBars)
bbR1UpperRaw = bbSellMasterEff and bbR1ExitBbEff and inPosition and entryRegime == 1 and withinRange and not inNoSellZone and (bbR1BbWaitEff ? bbPullbackFire : bbUpperHitRaw)
bbR2UpperRaw = bbSellMasterEff and bbR2ExitBbEff and inPosition and entryRegime == 2 and withinRange and not inNoSellZone and (bbR2BbWaitEff ? bbPullbackFire : bbUpperHitRaw)
bbR3UpperRaw = bbSellMasterEff and bbR3ExitBbEff and inPosition and entryRegime == 3 and withinRange and not inNoSellZone and (bbR3BbWaitEff ? bbPullbackFire : bbUpperHitRaw)
bbR4UpperRaw = bbSellMasterEff and bbR4ExitBbEff and inPosition and entryRegime == 4 and withinRange and not inNoSellZone and (bbR4BbWaitEff ? bbPullbackFire : bbUpperHitRaw)
bbAnyUpperRaw = bbR1UpperRaw or bbR2UpperRaw or bbR3UpperRaw or bbR4UpperRaw

// R0 confirm bars — count up while in the R0 regime, reset on leaving it
if isR0Regime
    r0BarsInRegime := r0BarsInRegime + 1
else
    r0BarsInRegime := 0

if isR1Regime
    r1BarsInRegime := r1BarsInRegime + 1
else
    r1BarsInRegime := 0
if isR2Regime
    r2BarsInRegime := r2BarsInRegime + 1
else
    r2BarsInRegime := 0
if isR3Regime
    r3BarsInRegime := r3BarsInRegime + 1
else
    r3BarsInRegime := 0
if isR4Regime
    r4BarsInRegime := r4BarsInRegime + 1
else
    r4BarsInRegime := 0
if inReport
    if isR0Regime
        barsR0 := barsR0 + 1
    else if isR1Regime
        barsR1 := barsR1 + 1
    else if isR2Regime
        barsR2 := barsR2 + 1
    else if isR3Regime
        barsR3 := barsR3 + 1
    else if isR4Regime
        barsR4 := barsR4 + 1

isLastHourOfDay = timeframe.isintraday and hour(time, "America/New_York") >= 15

// Regime change detection with confirmation
curRegimeInt = isR0Regime ? 10 : isR1Regime ? 1 : isR2Regime ? 2 : isR3Regime ? 3 : isR4Regime ? 4 : 0
if confirmedRegime == -1
    confirmedRegime := curRegimeInt
if curRegimeInt != confirmedRegime
    newRegimeBars := newRegimeBars + 1
else
    newRegimeBars := 0
rcJustConfirmed = newRegimeBars == rcConfirmBarsEff
prevConfirmedRegime = confirmedRegime
if rcJustConfirmed
    confirmedRegime := curRegimeInt

// Per-transition detection
isRc12 = rcJustConfirmed and prevConfirmedRegime == 1 and curRegimeInt == 2
isRc21 = rcJustConfirmed and prevConfirmedRegime == 2 and curRegimeInt == 1
isRc24 = rcJustConfirmed and prevConfirmedRegime == 2 and curRegimeInt == 4
isRc31 = rcJustConfirmed and prevConfirmedRegime == 3 and curRegimeInt == 1
isRc34 = rcJustConfirmed and prevConfirmedRegime == 3 and curRegimeInt == 4
isRc43 = rcJustConfirmed and prevConfirmedRegime == 4 and curRegimeInt == 3
isRc40 = rcJustConfirmed and prevConfirmedRegime == 4 and curRegimeInt == 10
isRc03 = rcJustConfirmed and prevConfirmedRegime == 10 and curRegimeInt == 3

// RC buy pending flag — persists until we buy or the regime changes again
if rcJustConfirmed
    rcPendSet = (prevConfirmedRegime == 1 and curRegimeInt == 2 and useRc12Eff and rc12FlatEff == "BUY") or (prevConfirmedRegime == 2 and curRegimeInt == 1 and useRc21Eff and rc21FlatEff == "BUY") or (prevConfirmedRegime == 2 and curRegimeInt == 4 and useRc24Eff and rc24FlatEff == "BUY") or (prevConfirmedRegime == 3 and curRegimeInt == 1 and useRc31Eff and rc31FlatEff == "BUY") or (prevConfirmedRegime == 3 and curRegimeInt == 4 and useRc34Eff and rc34FlatEff == "BUY") or (prevConfirmedRegime == 4 and curRegimeInt == 3 and useRc43Eff and rc43FlatEff == "BUY") or (prevConfirmedRegime == 4 and curRegimeInt == 10 and useRc40Eff and rc40FlatEff == "BUY") or (prevConfirmedRegime == 10 and curRegimeInt == 3 and useRc03Eff and rc03FlatEff == "BUY")
    rcBuyPending := rcPendSet
    if rcPendSet
        rcBuyPendingTarget := curRegimeInt
if rcBuyPending and confirmedRegime != rcBuyPendingTarget
    rcBuyPending := false
rcPendBbOk = true

// R0→R3 HOLD: suppress R0 regime-change exit until back in R0 or position closes
if isR0Regime and inPosition and entryRegime == 10
    r0Rc03Hold := false
if useRCEff and useRc03Eff and isRc03 and rc03HoldingEff == "HOLD" and inPosition and entryRegime == 10
    r0Rc03Hold := true

// Regime change sell (R1–R4; R0→R3 SELL uses R0 exit path — optional explicit RC sell below)
rcSellSignal = useRCEff and inPosition and withinRange and ((entryRegime >= 1 and entryRegime <= 4 and ((useRc12Eff and isRc12 and rc12HoldingEff == "SELL") or (useRc21Eff and isRc21 and rc21HoldingEff == "SELL") or (useRc24Eff and isRc24 and rc24HoldingEff == "SELL") or (useRc31Eff and isRc31 and rc31HoldingEff == "SELL") or (useRc34Eff and isRc34 and rc34HoldingEff == "SELL") or (useRc43Eff and isRc43 and rc43HoldingEff == "SELL") or (useRc40Eff and isRc40 and rc40HoldingEff == "SELL"))) or (entryRegime == 10 and useRc03Eff and isRc03 and rc03HoldingEff == "SELL"))

// Cooldown + last hour (regime "No Buy Last Hour" only)
r1CooldownOk = (bar_index - lastSellBar) > r1CooldownEff
r2CooldownOk = (bar_index - lastSellBar) > r2CooldownEff
r3CooldownOk = (bar_index - lastSellBar) > r3CooldownEff
r4CooldownOk = (bar_index - lastSellBar) > r4CooldownEff
r1LastHourBlock = r1NoBuyLastBarEff and isLastHourOfDay
r2LastHourBlock = r2NoBuyLastBarEff and isLastHourOfDay
r3LastHourBlock = r3NoBuyLastBarEff and isLastHourOfDay
r4LastHourBlock = r4NoBuyLastBarEff and isLastHourOfDay

// Regime change buy (flat): pending flag + BB buy check only (no last-hour / cooldown gates)
rcBuyMidHighSetup = useRCEff and rcBuyPending and rcBuyPendingTarget != 10 and not inPosition and withinRange and rcPendBbOk
rcBuyR0Setup = useRCEff and rcBuyPending and rcBuyPendingTarget == 10 and not inPosition and withinRange
rcBuyMidHigh = rcBuyMidHighSetup
rcBuyR0 = rcBuyR0Setup
rcBuySignal = rcBuyMidHigh or rcBuyR0

// R0 buy: N-bar confirmation while VIX SMA is in the ultra-calm band
r0EntrySmaOk = vixSmaMaster < r0MaxSmaEff
r0BuySetup = useR0Eff and isR0Regime and r0EntrySmaOk and r0BarsInRegime == r0ConfirmBarsEff and not inPosition and withinRange
r0BuySignal = r0BuySetup

// R1–R4 buys: VIX % vs regime SMA + optional BB buy filters
// Shared RC stochastic — one K/D reused by RC Stoch Lifecycle R0-R4, RC Stoch Lead, RC Breakdown, and shared recovery (all were previously identical copies).
sharedStochRaw = ta.stoch(close, high, low, s2_sharedRcStochLen)
sharedStochK = ta.sma(sharedStochRaw, s2_sharedRcStochK)
sharedStochD = ta.sma(sharedStochK, s2_sharedRcStochD)
r1ConfirmBarsOk = r1BarsInRegime >= r1ConfirmBarsEff
r2ConfirmBarsOk = r2BarsInRegime >= r2ConfirmBarsEff
r3ConfirmBarsOk = r3BarsInRegime >= r3ConfirmBarsEff
r4ConfirmBarsOk = r4BarsInRegime >= r4ConfirmBarsEff
sharedRecoverySoft = (not s2_sharedRecKgtD or (not na(sharedStochK) and not na(sharedStochD) and sharedStochK > sharedStochD)) and (not s2_sharedRecCloseUp or close > close[1]) and (not s2_sharedRecAboveBbLower or (bbBuyOk and close > bbBuyLower)) and (not s2_sharedRecBelowLastSell or (not na(lastSellPrice) and close <= lastSellPrice))
r1AtrRiskRiseOk = not r1AtrRiskRequireRisingEff or (r1AtrRiskPctValid and r1AtrRiskPctRising)
r1AtrRiskBlock = r1AtrRiskFilterEff and not na(r1AtrRiskPct) and r1AtrRiskPct > r1AtrRiskMaxPctEff and r1AtrRiskRiseOk and not (s2_sharedRecAtrR1 and sharedRecoverySoft)
r1BuySetup = useR1Eff and isR1Regime and r1ConfirmBarsOk and vixAbove >= r1BuyPctEff and r1CooldownOk and not r1LastHourBlock and r1BuyBbOk
r1AtrRiskBlocked = not inPosition and withinRange and r1BuySetup and r1AtrRiskBlock
r1BuySignal = r1BuySetup and not r1AtrRiskBlock
r2BuySetup = useR2Eff and isR2Regime and r2ConfirmBarsOk and vixSmaMaster >= r1MinSmaEff and vixAbove >= r2BuyPctEff and r2CooldownOk and not r2LastHourBlock and r2BuyBbOk
r2BuySignal = r2BuySetup
r3BuySetup = useR3Eff and isR3Regime and r3ConfirmBarsOk and vixAbove >= r3BuyPctEff and r3CooldownOk and not r3LastHourBlock and r3BuyBbOk
r3BuySignal = r3BuySetup
r4BuySetup = useR4Eff and isR4Regime and r4ConfirmBarsOk and vixAbove >= r4BuyPctEff and r4CooldownOk and not r4LastHourBlock and r4BuyBbOk
r4BuySignal = r4BuySetup

fearBuySignal = not inPosition and withinRange and (r1BuySignal or r2BuySignal)
midBuySignal = not inPosition and withinRange and (r3BuySignal or r4BuySignal) and not fearBuySignal

buySignalRaw = r0BuySignal or rcBuySignal or fearBuySignal or midBuySignal

if inPosition
    barsInTrade := barsInTrade + 1
    bmSlopePeakTracked := math.max(bmSlopePeakTracked, bbMidSlopeVal)

currentProfit = inPosition and not na(entryPrice) ? (close - entryPrice) / entryPrice * 100 : 0.0
// Strategy 6 human model: assume a person acts near candle close, so exits and P&L use close-based values instead of intrabar wicks.
barPnLHi = inPosition and not na(entryPrice) ? currentProfit : na
barPnLLo = inPosition and not na(entryPrice) ? currentProfit : na
if inPosition
    if not na(barPnLHi)
        tradeMfePct := na(tradeMfePct) ? barPnLHi : math.max(tradeMfePct, barPnLHi)
    if not na(barPnLLo)
        tradeMaePct := na(tradeMaePct) ? barPnLLo : math.min(tradeMaePct, barPnLLo)

// Exit params depend on entry regime
activePT = entryRegime == 10 ? r0PTEff : entryRegime == 1 ? r1PTEff : entryRegime == 2 ? r2PTEff : entryRegime == 3 ? r3PTEff : r4PTEff
activeSL = entryRegime == 10 ? r0SLEff : entryRegime == 1 ? r1SLEff : entryRegime == 2 ? (r2GuardMasterEff and r2GuardTighterSLEff ? r2GuardSLEff : r2SLEff) : entryRegime == 3 ? r3SLEff : (r4GuardMasterEff and r4GuardTighterSLEff ? r4GuardSLEff : r4SLEff)
activeSellPct = entryRegime == 1 ? r1SellPctEff : entryRegime == 2 ? r2SellPctEff : entryRegime == 3 ? r3SellPctEff : r4SellPctEff
activeVixAboveSma = entryRegime == 1 ? vixAbove : entryRegime == 2 ? vixAbove : entryRegime == 3 ? vixAbove : vixAbove
activeEod = entryRegime == 1 ? r1EodEff : entryRegime == 2 ? r2EodEff : entryRegime == 3 ? r3EodEff : entryRegime == 4 ? r4EodEff : false
activeEodMinProfit = entryRegime == 1 ? r1EodMinProfitEff : entryRegime == 2 ? r2EodMinProfitEff : entryRegime == 3 ? r3EodMinProfitEff : entryRegime == 4 ? r4EodMinProfitEff : 0.0

profitHitRaw = activePT > 0 and (not na(barPnLHi) and barPnLHi >= activePT)
profitHit = profitHitRaw and not inNoSellZone and (entryRegime != 1 or (bbSellMasterEff and bbR1ExitPTEff)) and (entryRegime != 2 or (bbSellMasterEff and bbR2ExitPTEff)) and (entryRegime != 3 or (bbSellMasterEff and bbR3ExitPTEff)) and (entryRegime != 4 or (bbSellMasterEff and bbR4ExitPTEff))

stopTrip = (not na(barPnLLo) and barPnLLo <= activeSL)
stopHit = stopTrip and (entryRegime != 1 or (bbSellMasterEff and bbR1ExitSLEff)) and (entryRegime != 2 or (bbSellMasterEff and bbR2ExitSLEff)) and (entryRegime != 3 or (bbSellMasterEff and bbR3ExitSLEff)) and (entryRegime != 4 or (bbSellMasterEff and bbR4ExitSLEff))
eodTrip = activeEod and inPosition and isLastHourOfDay and (not na(barPnLHi) and barPnLHi >= activeEodMinProfit)
eodSellRaw = eodTrip and not inNoSellZone and (entryRegime != 1 or (bbSellMasterEff and bbR1ExitEodEff)) and (entryRegime != 2 or (bbSellMasterEff and bbR2ExitEodEff)) and (entryRegime != 3 or (bbSellMasterEff and bbR3ExitEodEff)) and (entryRegime != 4 or (bbSellMasterEff and bbR4ExitEodEff))

// BB mid slope exit — peak-fade using tracked peak (resets on entry), min 2 bars in trade
bmFadingTracked = bbMidSlopeVal > 0 and bmSlopePeakTracked > 0 and bbMidSlopeVal < bmSlopePeakTracked * bbMidSlopeFadeRatioEff
bbMidSlopeExitSignal = bbMidSlopeExitEff and inPosition and entryRegime >= 1 and entryRegime <= 4 and bmFadingTracked and barsInTrade >= 2 and (not na(barPnLHi) and barPnLHi >= bbMidSlopeMinProfitEff)

// R0 exits: flatten R10 entries when chart leaves ultra-calm
r0RegimeChangeExit = entryRegime == 10 and not isR0Regime and not r0Rc03Hold
r0FastExit = entryRegime == 10 and vixClose >= r0FastVixExitEff

// R1–R4 VIX-based exits (gated per entry regime by BB toggles)
fearVixExit = entryRegime >= 1 and entryRegime <= 4 and not inNoSellZone and activeVixAboveSma <= activeSellPct and (entryRegime != 1 or (bbSellMasterEff and bbR1ExitVixEff)) and (entryRegime != 2 or (bbSellMasterEff and bbR2ExitVixEff)) and (entryRegime != 3 or (bbSellMasterEff and bbR3ExitVixEff)) and (entryRegime != 4 or (bbSellMasterEff and bbR4ExitVixEff))

if dailySmaBullSellEff and dailySmaBullCrossTrigger
    dailySmaBullSellActiveLeft := dailySmaBullActiveBarsEff
else if not dailySmaBullCrossTrigger and dailySmaBullSellActiveLeft > 0
    dailySmaBullSellActiveLeft := dailySmaBullSellActiveLeft - 1
if dailySmaBull2SellEff and dailySmaBull2CrossTrigger
    dailySmaBull2SellActiveLeft := dailySmaBull2ActiveBarsEff
else if not dailySmaBull2CrossTrigger and dailySmaBull2SellActiveLeft > 0
    dailySmaBull2SellActiveLeft := dailySmaBull2SellActiveLeft - 1
if dailySmaBull3SellEff and dailySmaBull3CrossTrigger
    dailySmaBull3SellActiveLeft := dailySmaBull3ActiveBarsEff
else if not dailySmaBull3CrossTrigger and dailySmaBull3SellActiveLeft > 0
    dailySmaBull3SellActiveLeft := dailySmaBull3SellActiveLeft - 1
if dailySmaBull4SellEff and dailySmaBull4CrossTrigger
    dailySmaBull4SellActiveLeft := dailySmaBull4ActiveBarsEff
else if not dailySmaBull4CrossTrigger and dailySmaBull4SellActiveLeft > 0
    dailySmaBull4SellActiveLeft := dailySmaBull4SellActiveLeft - 1
dailySmaBullEntryRegimeOn = entryRegime == 1 ? dailySmaBullR1Eff : entryRegime == 2 ? dailySmaBullR2Eff : entryRegime == 3 ? dailySmaBullR3Eff : entryRegime == 4 ? dailySmaBullR4Eff : false
dailySmaBullSellStateActive = dailySmaBullSellEff and inPosition and withinRange and dailySmaBullEntryRegimeOn and (dailySmaBullCrossTrigger or dailySmaBullAboveTrigger or dailySmaBullSellActiveLeft > 0)
dailySmaBull2EntryRegimeOn = entryRegime == 1 ? dailySmaBull2R1Eff : entryRegime == 2 ? dailySmaBull2R2Eff : entryRegime == 3 ? dailySmaBull2R3Eff : entryRegime == 4 ? dailySmaBull2R4Eff : false
dailySmaBull2SellStateActive = dailySmaBull2SellEff and inPosition and withinRange and dailySmaBull2EntryRegimeOn and (dailySmaBull2CrossTrigger or dailySmaBull2AboveTrigger or dailySmaBull2SellActiveLeft > 0)
dailySmaBull3EntryRegimeOn = entryRegime == 1 ? dailySmaBull3R1Eff : entryRegime == 2 ? dailySmaBull3R2Eff : entryRegime == 3 ? dailySmaBull3R3Eff : entryRegime == 4 ? dailySmaBull3R4Eff : false
dailySmaBull3SellStateActive = dailySmaBull3SellEff and inPosition and withinRange and dailySmaBull3EntryRegimeOn and (dailySmaBull3CrossTrigger or dailySmaBull3AboveTrigger or dailySmaBull3SellActiveLeft > 0)
dailySmaBull4SellStateActive = dailySmaBull4SellEff and inPosition and withinRange and entryRegime >= 1 and entryRegime <= 4 and (dailySmaBull4CrossTrigger or dailySmaBull4SellActiveLeft > 0)
dailySmaBullSuppressPT = dailySmaBullSellStateActive and dailySmaBullIgnorePTEff and profitHit
dailySmaBullSuppressVix = dailySmaBullSellStateActive and dailySmaBullIgnoreVixEff and fearVixExit
dailySmaBullSuppressEOD = dailySmaBullSellStateActive and dailySmaBullIgnoreEODEff and eodSellRaw
dailySmaBull2SuppressPT = dailySmaBull2SellStateActive and dailySmaBull2IgnorePTEff and profitHit
dailySmaBull2SuppressVix = dailySmaBull2SellStateActive and dailySmaBull2IgnoreVixEff and fearVixExit
dailySmaBull2SuppressEOD = dailySmaBull2SellStateActive and dailySmaBull2IgnoreEODEff and eodSellRaw
dailySmaBull3SuppressPT = dailySmaBull3SellStateActive and dailySmaBull3IgnorePTEff and profitHit
dailySmaBull3SuppressVix = dailySmaBull3SellStateActive and dailySmaBull3IgnoreVixEff and fearVixExit
dailySmaBull3SuppressEOD = dailySmaBull3SellStateActive and dailySmaBull3IgnoreEODEff and eodSellRaw
dailySmaBull4SuppressPT = dailySmaBull4SellStateActive and profitHit
dailySmaBull4SuppressVix = false
dailySmaBull4SuppressEOD = false
eodSell = eodSellRaw and not dailySmaBullSuppressEOD and not dailySmaBull2SuppressEOD and not dailySmaBull3SuppressEOD and not dailySmaBull4SuppressEOD

// R2/R4 Risk Guards — optional exits for regime-specific failures. Labelled RG when they trigger.
r2GuardVixDelta = not na(entryVixPct) ? activeVixAboveSma - entryVixPct : na
r2GuardEarlyTrip = r2GuardMasterEff and r2GuardEarlyExitEff and inPosition and entryRegime == 2 and barsInTrade >= r2GuardEarlyBarsEff and currentProfit <= r2GuardEarlyPnlEff and not na(r2GuardVixDelta) and r2GuardVixDelta >= r2GuardVixWorsenEff
r2GuardMaxBarsTrip = r2GuardMasterEff and r2GuardMaxBarsExitEff and inPosition and entryRegime == 2 and barsInTrade >= r2GuardMaxBarsEff and currentProfit <= r2GuardMaxBarsPnlEff
r2RiskGuardExit = withinRange and (r2GuardEarlyTrip or r2GuardMaxBarsTrip)
r4GuardVixDelta = not na(entryVixPct) ? activeVixAboveSma - entryVixPct : na
r4GuardEarlyTrip = r4GuardMasterEff and r4GuardEarlyExitEff and inPosition and entryRegime == 4 and barsInTrade >= r4GuardEarlyBarsEff and currentProfit <= r4GuardEarlyPnlEff and not na(r4GuardVixDelta) and r4GuardVixDelta >= r4GuardVixWorsenEff
r4GuardMaxBarsTrip = r4GuardMasterEff and r4GuardMaxBarsExitEff and inPosition and entryRegime == 4 and barsInTrade >= r4GuardMaxBarsEff and currentProfit <= r4GuardMaxBarsPnlEff
r4RiskGuardExit = withinRange and (r4GuardEarlyTrip or r4GuardMaxBarsTrip)
riskGuardExit = r2RiskGuardExit or r4RiskGuardExit

// --- Shared soft trailing (PT → VIX → BB → BM arm priority; one peak & one % until breach) ---
wantBbUpperForTsl = (entryRegime == 1 and bbR1UpperRaw) or (entryRegime == 2 and bbR2UpperRaw) or (entryRegime == 3 and bbR3UpperRaw) or (entryRegime == 4 and bbR4UpperRaw)
dailySmaBullSuppressBB = dailySmaBullSellStateActive and dailySmaBullIgnoreBBEff and wantBbUpperForTsl
dailySmaBullSuppressBM = dailySmaBullSellStateActive and dailySmaBullIgnoreBMEff and bbMidSlopeExitSignal
dailySmaBull2SuppressBB = dailySmaBull2SellStateActive and dailySmaBull2IgnoreBBEff and wantBbUpperForTsl
dailySmaBull2SuppressBM = dailySmaBull2SellStateActive and dailySmaBull2IgnoreBMEff and bbMidSlopeExitSignal
dailySmaBull3SuppressBB = dailySmaBull3SellStateActive and dailySmaBull3IgnoreBBEff and wantBbUpperForTsl
dailySmaBull3SuppressBM = dailySmaBull3SellStateActive and dailySmaBull3IgnoreBMEff and bbMidSlopeExitSignal
dailySmaBull4SuppressBB = false
dailySmaBull4SuppressBM = false
wantPt = profitHit and not dailySmaBullSuppressPT and not dailySmaBull2SuppressPT and not dailySmaBull3SuppressPT and not dailySmaBull4SuppressPT
wantVi = fearVixExit and not dailySmaBullSuppressVix and not dailySmaBull2SuppressVix and not dailySmaBull3SuppressVix and not dailySmaBull4SuppressVix
wantBb = wantBbUpperForTsl and not dailySmaBullSuppressBB and not dailySmaBull2SuppressBB and not dailySmaBull3SuppressBB and not dailySmaBull4SuppressBB
wantBm = bbMidSlopeExitSignal and not dailySmaBullSuppressBM and not dailySmaBull2SuppressBM and not dailySmaBull3SuppressBM and not dailySmaBull4SuppressBM

tslPTon = st_all_masterEff and (entryRegime == 10 ? (r0st_masterEff and r0st_ptEff) : entryRegime == 1 ? (r1st_masterEff and r1st_ptEff) : entryRegime == 2 ? (r2st_masterEff and r2st_ptEff) : entryRegime == 3 ? (r3st_masterEff and r3st_ptEff) : entryRegime == 4 ? (r4st_masterEff and r4st_ptEff) : false)
tslPTpct = entryRegime == 10 ? r0st_ptPctEff : entryRegime == 1 ? r1st_ptPctEff : entryRegime == 2 ? r2st_ptPctEff : entryRegime == 3 ? r3st_ptPctEff : entryRegime == 4 ? r4st_ptPctEff : 0.0
tslVIon = st_all_masterEff and (entryRegime == 10 ? (r0st_masterEff and r0st_viEff) : entryRegime == 1 ? (r1st_masterEff and r1st_viEff) : entryRegime == 2 ? (r2st_masterEff and r2st_viEff) : entryRegime == 3 ? (r3st_masterEff and r3st_viEff) : entryRegime == 4 ? (r4st_masterEff and r4st_viEff) : false)
tslVIpct = entryRegime == 10 ? r0st_viPctEff : entryRegime == 1 ? r1st_viPctEff : entryRegime == 2 ? r2st_viPctEff : entryRegime == 3 ? r3st_viPctEff : entryRegime == 4 ? r4st_viPctEff : 0.0
tslBBon = st_all_masterEff and (entryRegime == 10 ? (r0st_masterEff and r0st_bbEff) : entryRegime == 1 ? (r1st_masterEff and r1st_bbEff) : entryRegime == 2 ? (r2st_masterEff and r2st_bbEff) : entryRegime == 3 ? (r3st_masterEff and r3st_bbEff) : entryRegime == 4 ? (r4st_masterEff and r4st_bbEff) : false)
tslBBpct = entryRegime == 10 ? r0st_bbPctEff : entryRegime == 1 ? r1st_bbPctEff : entryRegime == 2 ? r2st_bbPctEff : entryRegime == 3 ? r3st_bbPctEff : entryRegime == 4 ? r4st_bbPctEff : 0.0
tslBMon = st_all_masterEff and (entryRegime == 10 ? (r0st_masterEff and r0st_bmEff) : entryRegime == 1 ? (r1st_masterEff and r1st_bmEff) : entryRegime == 2 ? (r2st_masterEff and r2st_bmEff) : entryRegime == 3 ? (r3st_masterEff and r3st_bmEff) : entryRegime == 4 ? (r4st_masterEff and r4st_bmEff) : false)
tslBMpct = entryRegime == 10 ? r0st_bmPctEff : entryRegime == 1 ? r1st_bmPctEff : entryRegime == 2 ? r2st_bmPctEff : entryRegime == 3 ? r3st_bmPctEff : entryRegime == 4 ? r4st_bmPctEff : 0.0

anySoftTslOn = tslPTon or tslVIon or tslBBon or tslBMon
softTrailRegimeOk = inPosition and anySoftTslOn

armPtSig = (entryRegime == 10 and st_all_masterEff and r0st_masterEff and r0st_ptEff and profitHitRaw and not inNoSellZone) or (entryRegime == 1 and profitHitRaw and not inNoSellZone and bbSellMasterEff and (bbR1ExitPTEff or (st_all_masterEff and r1st_masterEff and r1st_ptEff))) or (entryRegime == 2 and profitHitRaw and not inNoSellZone and bbSellMasterEff and (bbR2ExitPTEff or (st_all_masterEff and r2st_masterEff and r2st_ptEff))) or (entryRegime == 3 and profitHitRaw and not inNoSellZone and bbSellMasterEff and (bbR3ExitPTEff or (st_all_masterEff and r3st_masterEff and r3st_ptEff))) or (entryRegime == 4 and profitHitRaw and not inNoSellZone and bbSellMasterEff and (bbR4ExitPTEff or (st_all_masterEff and r4st_masterEff and r4st_ptEff)))
defPt = tslPTon and armPtSig
defVi = tslVIon and wantVi
defBb = tslBBon and wantBb
defBm = tslBMon and wantBm

if not softTrailRegimeOk
    softTrailArmed := false
    softTrailPeak := na
    softTrailPct := na
    softTrailArmKind := 0
else
    if softTrailArmed
        softTrailPeak := math.max(nz(softTrailPeak, close), close)
    else
        if defPt
            softTrailArmed := true
            softTrailPeak := close
            softTrailPct := tslPTpct
            softTrailArmKind := 1
        else if defVi
            softTrailArmed := true
            softTrailPeak := close
            softTrailPct := tslVIpct
            softTrailArmKind := 2
        else if defBb
            softTrailArmed := true
            softTrailPeak := close
            softTrailPct := tslBBpct
            softTrailArmKind := 3
        else if defBm
            softTrailArmed := true
            softTrailPeak := close
            softTrailPct := tslBMpct
            softTrailArmKind := 4

softTrailBreachedRaw = softTrailArmed and not na(softTrailPct) and softTrailPct > 0 and close <= softTrailPeak * (1.0 - softTrailPct / 100.0)
dailySmaBullSuppressSoftTrail = dailySmaBullSellStateActive and softTrailBreachedRaw and ((softTrailArmKind == 1 and dailySmaBullIgnorePTEff) or (softTrailArmKind == 2 and dailySmaBullIgnoreVixEff) or (softTrailArmKind == 3 and dailySmaBullIgnoreBBEff) or (softTrailArmKind == 4 and dailySmaBullIgnoreBMEff))
dailySmaBull2SuppressSoftTrail = dailySmaBull2SellStateActive and softTrailBreachedRaw and ((softTrailArmKind == 1 and dailySmaBull2IgnorePTEff) or (softTrailArmKind == 2 and dailySmaBull2IgnoreVixEff) or (softTrailArmKind == 3 and dailySmaBull2IgnoreBBEff) or (softTrailArmKind == 4 and dailySmaBull2IgnoreBMEff))
dailySmaBull3SuppressSoftTrail = dailySmaBull3SellStateActive and softTrailBreachedRaw and ((softTrailArmKind == 1 and dailySmaBull3IgnorePTEff) or (softTrailArmKind == 2 and dailySmaBull3IgnoreVixEff) or (softTrailArmKind == 3 and dailySmaBull3IgnoreBBEff) or (softTrailArmKind == 4 and dailySmaBull3IgnoreBMEff))
dailySmaBull4SuppressSoftTrail = dailySmaBull4SellStateActive and softTrailBreachedRaw and softTrailArmKind == 1
softTrailBreached = softTrailBreachedRaw and not dailySmaBullSuppressSoftTrail and not dailySmaBull2SuppressSoftTrail and not dailySmaBull3SuppressSoftTrail and not dailySmaBull4SuppressSoftTrail
softCompositeSell = softTrailArmed ? softTrailBreached : ((wantPt and not tslPTon) or (wantVi and not tslVIon) or (wantBb and not tslBBon) or (wantBm and not tslBMon))
profitHitForSell = wantPt and ((not softTrailArmed and not tslPTon) or (softTrailBreached and softTrailArmKind == 1))

rcslCrossDn = rcslExitCrossEff and not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK[1] >= sharedStochD[1] and sharedStochK < sharedStochD
rcslBaseOk = inPosition and withinRange and (not rcslRcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcslMinBarsEff and barsInTrade <= rcslMaxBarsEff and (not rcslRequireTrailArmedEff or softTrailArmed) and currentProfit <= rcslMaxPnlEff and rcslCrossDn
r1StochLeadExit = s2_rcslR1Enable and entryRegime == 1 and rcslBaseOk and (not rcslPtNotReachedEff or (not na(tradeMfePct) and tradeMfePct < r1PTEff))
r2StochLeadExit = s2_rcslR2Enable and entryRegime == 2 and rcslBaseOk and (not rcslPtNotReachedEff or (not na(tradeMfePct) and tradeMfePct < r2PTEff))
r3StochLeadExit = s2_rcslR3Enable and entryRegime == 3 and rcslBaseOk and (not rcslPtNotReachedEff or (not na(tradeMfePct) and tradeMfePct < r3PTEff))
r4StochLeadExit = s2_rcslR4Enable and entryRegime == 4 and rcslBaseOk and (not rcslPtNotReachedEff or (not na(tradeMfePct) and tradeMfePct < r4PTEff))
rcStochLeadExit = r1StochLeadExit or r2StochLeadExit or r3StochLeadExit or r4StochLeadExit

rcbdCrossDn = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK[1] >= sharedStochD[1] and sharedStochK < sharedStochD
rcbdVixDelta = not na(entryVixPct) ? activeVixAboveSma - entryVixPct : na
rcbdMidDown = not na(bbMid[rcbdMidLookbackEff]) and bbMid < bbMid[rcbdMidLookbackEff]
rcbdBaseOk = inPosition and withinRange and (not rcbdRcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcbdMinBarsEff and barsInTrade <= rcbdMaxBarsEff and not softTrailArmed and (not na(tradeMfePct) and tradeMfePct <= rcbdMaxMfeEff) and currentProfit <= rcbdMaxPnlEff and currentProfit >= rcbdMinPnlEff and rcbdMidDown and close < bbLower and close < open and rcbdCrossDn and not na(rcbdVixDelta) and rcbdVixDelta >= rcbdVixWorsenEff
rcbdR2BaseOk = inPosition and withinRange and (not s2_rcbdR2RcOnly or entrySignalType == "RC") and barsInTrade >= s2_rcbdR2MinBars and barsInTrade <= rcbdMaxBarsEff and not softTrailArmed and (not na(tradeMfePct) and tradeMfePct <= rcbdMaxMfeEff) and currentProfit <= rcbdMaxPnlEff and currentProfit >= rcbdMinPnlEff and rcbdMidDown and close < bbLower and close < open and rcbdCrossDn and not na(rcbdVixDelta) and rcbdVixDelta >= rcbdVixWorsenEff
rcBreakdownExit = (s2_rcbdR2Enable and entryRegime == 2 and rcbdR2BaseOk) or (rcbdR4EnableEff and entryRegime == 4 and rcbdBaseOk)

rclEmbedHighNow = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rclZoneHighEff and sharedStochD > rclZoneHighEff
rcl0EmbedHighNow = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl0ZoneHighEff and sharedStochD > rcl0ZoneHighEff
rcl1EmbedHighNow = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl1ZoneHighEff and sharedStochD > rcl1ZoneHighEff
rcl2EmbedHighNow = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl2ZoneHighEff and sharedStochD > rcl2ZoneHighEff
rcl3EmbedHighNow = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl3ZoneHighEff and sharedStochD > rcl3ZoneHighEff
if inPosition and entryRegime == 10 and rcl0R0EnableEff
    rcl0EmbedRun := rcl0EmbedHighNow ? rcl0EmbedRun + 1 : 0
    if rcl0EmbedRun >= rcl0EmbedBarsHighEff
        rcl0EmbedArmed := true
else
    rcl0EmbedRun := 0
    rcl0EmbedArmed := false
if inPosition and entryRegime == 4 and rclR4EnableEff
    rclEmbedRun := rclEmbedHighNow ? rclEmbedRun + 1 : 0
    if rclEmbedRun >= rclEmbedBarsHighEff
        rclEmbedArmed := true
else
    rclEmbedRun := 0
    rclEmbedArmed := false
if inPosition and entryRegime == 1 and rcl1R1EnableEff
    rcl1EmbedRun := rcl1EmbedHighNow ? rcl1EmbedRun + 1 : 0
    if rcl1EmbedRun >= rcl1EmbedBarsHighEff
        rcl1EmbedArmed := true
else
    rcl1EmbedRun := 0
    rcl1EmbedArmed := false
if inPosition and entryRegime == 2 and rcl2R2EnableEff
    rcl2EmbedRun := rcl2EmbedHighNow ? rcl2EmbedRun + 1 : 0
    if rcl2EmbedRun >= rcl2EmbedBarsHighEff
        rcl2EmbedArmed := true
else
    rcl2EmbedRun := 0
    rcl2EmbedArmed := false
if inPosition and entryRegime == 3 and rcl3R3EnableEff
    rcl3EmbedRun := rcl3EmbedHighNow ? rcl3EmbedRun + 1 : 0
    if rcl3EmbedRun >= rcl3EmbedBarsHighEff
        rcl3EmbedArmed := true
else
    rcl3EmbedRun := 0
    rcl3EmbedArmed := false
rcl0EmbedLost = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl0ZoneHighEff or sharedStochD < rcl0ZoneHighEff)
rcl0Falling = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK < sharedStochK[1] and sharedStochD < sharedStochD[1]
rcl0Unwind = rcl0EmbedArmed and rcl0EmbedLost and sharedStochK < sharedStochD and rcl0Falling
rcl0BaseOk = inPosition and withinRange and (not rcl0RcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcl0MinBarsEff and barsInTrade <= rcl0MaxBarsEff and rcl0Unwind
rclLockedExitR0 = rcl0R0EnableEff and entryRegime == 10 and rcl0BaseOk
rclEmbedLost = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rclZoneHighEff or sharedStochD < rclZoneHighEff)
rclFalling = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK < sharedStochK[1] and sharedStochD < sharedStochD[1]
rclUnwind = rclEmbedArmed and rclEmbedLost and sharedStochK < sharedStochD and rclFalling
rclBaseOk = inPosition and withinRange and (not rclRcOnlyEff or entrySignalType == "RC") and barsInTrade >= rclMinBarsEff and barsInTrade <= rclMaxBarsEff and rclUnwind
rclLockedExitR4 = rclR4EnableEff and entryRegime == 4 and rclBaseOk
rcl1EmbedLost = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl1ZoneHighEff or sharedStochD < rcl1ZoneHighEff)
rcl1Falling = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK < sharedStochK[1] and sharedStochD < sharedStochD[1]
rcl1Unwind = rcl1EmbedArmed and rcl1EmbedLost and sharedStochK < sharedStochD and rcl1Falling
rcl1BaseOk = inPosition and withinRange and (not rcl1RcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcl1MinBarsEff and barsInTrade <= rcl1MaxBarsEff and rcl1Unwind
rclLockedExitR1 = rcl1R1EnableEff and entryRegime == 1 and rcl1BaseOk
rcl2EmbedLost = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl2ZoneHighEff or sharedStochD < rcl2ZoneHighEff)
rcl2Falling = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK < sharedStochK[1] and sharedStochD < sharedStochD[1]
rcl2Unwind = rcl2EmbedArmed and rcl2EmbedLost and sharedStochK < sharedStochD and rcl2Falling
rcl2BaseOk = inPosition and withinRange and (not rcl2RcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcl2MinBarsEff and barsInTrade <= rcl2MaxBarsEff and rcl2Unwind
rclLockedExitR2 = rcl2R2EnableEff and entryRegime == 2 and rcl2BaseOk
rcl3EmbedLost = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl3ZoneHighEff or sharedStochD < rcl3ZoneHighEff)
rcl3Falling = not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(sharedStochD[1]) and sharedStochK < sharedStochK[1] and sharedStochD < sharedStochD[1]
rcl3Unwind = rcl3EmbedArmed and rcl3EmbedLost and sharedStochK < sharedStochD and rcl3Falling
rcl3BaseOk = inPosition and withinRange and (not rcl3RcOnlyEff or entrySignalType == "RC") and barsInTrade >= rcl3MinBarsEff and barsInTrade <= rcl3MaxBarsEff and rcl3Unwind
rclLockedExitR3 = rcl3R3EnableEff and entryRegime == 3 and rcl3BaseOk
rcLifecycleExit = rclLockedExitR4 or rclLockedExitR3 or rclLockedExitR2 or rclLockedExitR1 or rclLockedExitR0

rclLifecycleActive = rclR4EnableEff or rcl1R1EnableEff or rcl2R2EnableEff or rcl3R3EnableEff or rcl0R0EnableEff
rclOsEmbedNow = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rclZoneLowEff or sharedStochD < rclZoneLowEff)
rclOsEmbedLost = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rclZoneLowEff and sharedStochD > rclZoneLowEff
rcl1OsEmbedNow = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl1ZoneLowEff or sharedStochD < rcl1ZoneLowEff)
rcl1OsEmbedLost = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl1ZoneLowEff and sharedStochD > rcl1ZoneLowEff
rcl2OsEmbedNow = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl2ZoneLowEff or sharedStochD < rcl2ZoneLowEff)
rcl2OsEmbedLost = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl2ZoneLowEff and sharedStochD > rcl2ZoneLowEff
rcl3OsEmbedNow = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl3ZoneLowEff or sharedStochD < rcl3ZoneLowEff)
rcl3OsEmbedLost = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl3ZoneLowEff and sharedStochD > rcl3ZoneLowEff
rcl0OsEmbedNow = not na(sharedStochK) and not na(sharedStochD) and (sharedStochK < rcl0ZoneLowEff or sharedStochD < rcl0ZoneLowEff)
rcl0OsEmbedLost = not na(sharedStochK) and not na(sharedStochD) and sharedStochK > rcl0ZoneLowEff and sharedStochD > rcl0ZoneLowEff
if rclLifecycleActive
    if rclBuyLock
        rclBuyLockBars += 1
        if rclBuyLockSrc == 4
            rclOsEmbedRun := rclOsEmbedNow ? rclOsEmbedRun + 1 : 0
            if rclOsEmbedRun >= rclEmbedBarsLowEff
                rclOsEmbedSeen := true
            if (rclOsEmbedSeen and rclOsEmbedLost and sharedStochK > sharedStochD and (not rclReleaseCloseUpEff or close > close[1])) or rclBuyLockBars > rclMaxBuyLockBarsEff
                rclBuyLock := false
                rclBuyLockSrc := 0
                rclBuyLockBars := 0
                rclOsEmbedSeen := false
                rclOsEmbedRun := 0
        else if rclBuyLockSrc == 3
            rcl3OsEmbedRun := rcl3OsEmbedNow ? rcl3OsEmbedRun + 1 : 0
            if rcl3OsEmbedRun >= rcl3EmbedBarsLowEff
                rcl3OsEmbedSeen := true
            if (rcl3OsEmbedSeen and rcl3OsEmbedLost and sharedStochK > sharedStochD and (not rcl3ReleaseCloseUpEff or close > close[1])) or rclBuyLockBars > rcl3MaxBuyLockBarsEff
                rclBuyLock := false
                rclBuyLockSrc := 0
                rclBuyLockBars := 0
                rcl3OsEmbedSeen := false
                rcl3OsEmbedRun := 0
        else if rclBuyLockSrc == 1
            rcl1OsEmbedRun := rcl1OsEmbedNow ? rcl1OsEmbedRun + 1 : 0
            if rcl1OsEmbedRun >= rcl1EmbedBarsLowEff
                rcl1OsEmbedSeen := true
            if (rcl1OsEmbedSeen and rcl1OsEmbedLost and sharedStochK > sharedStochD and close > close[1]) or rclBuyLockBars > rcl1MaxBuyLockBarsEff
                rclBuyLock := false
                rclBuyLockSrc := 0
                rclBuyLockBars := 0
                rcl1OsEmbedSeen := false
                rcl1OsEmbedRun := 0
        else if rclBuyLockSrc == 2
            rcl2OsEmbedRun := rcl2OsEmbedNow ? rcl2OsEmbedRun + 1 : 0
            if rcl2OsEmbedRun >= rcl2EmbedBarsLowEff
                rcl2OsEmbedSeen := true
            if (rcl2OsEmbedSeen and rcl2OsEmbedLost and sharedStochK > sharedStochD and (not rcl2ReleaseCloseUpEff or close > close[1])) or rclBuyLockBars > rcl2MaxBuyLockBarsEff
                rclBuyLock := false
                rclBuyLockSrc := 0
                rclBuyLockBars := 0
                rcl2OsEmbedSeen := false
                rcl2OsEmbedRun := 0
        else if rclBuyLockSrc == 10
            rcl0OsEmbedRun := rcl0OsEmbedNow ? rcl0OsEmbedRun + 1 : 0
            if rcl0OsEmbedRun >= rcl0EmbedBarsLowEff
                rcl0OsEmbedSeen := true
            if (rcl0OsEmbedSeen and rcl0OsEmbedLost and sharedStochK > sharedStochD and (not rcl0ReleaseCloseUpEff or close > close[1])) or rclBuyLockBars > rcl0MaxBuyLockBarsEff
                rclBuyLock := false
                rclBuyLockSrc := 0
                rclBuyLockBars := 0
                rcl0OsEmbedSeen := false
                rcl0OsEmbedRun := 0
else
    rclBuyLock := false
    rclBuyLockSrc := 0
    rclBuyLockBars := 0
    rclOsEmbedSeen := false
    rclOsEmbedRun := 0
    rcl1OsEmbedSeen := false
    rcl1OsEmbedRun := 0
    rcl2OsEmbedSeen := false
    rcl2OsEmbedRun := 0
    rcl3OsEmbedSeen := false
    rcl3OsEmbedRun := 0
    rcl0OsEmbedSeen := false
    rcl0OsEmbedRun := 0

rcSellActiveRaw = rcSellSignal and not (entryRegime == 1 and not (bbSellMasterEff and bbR1ExitRcEff)) and not (entryRegime == 2 and not (bbSellMasterEff and bbR2ExitRcEff)) and not (entryRegime == 3 and not (bbSellMasterEff and bbR3ExitRcEff)) and not (entryRegime == 4 and not (bbSellMasterEff and bbR4ExitRcEff))
dailySmaBullSuppressRC = dailySmaBullSellStateActive and dailySmaBullIgnoreRCEff and rcSellActiveRaw
dailySmaBull2SuppressRC = dailySmaBull2SellStateActive and dailySmaBull2IgnoreRCEff and rcSellActiveRaw
dailySmaBull3SuppressRC = dailySmaBull3SellStateActive and dailySmaBull3IgnoreRCEff and rcSellActiveRaw
dailySmaBull4SuppressRC = dailySmaBull4SellStateActive and rcSellActiveRaw
dailySmaBullSellSuppressed = dailySmaBullSuppressPT or dailySmaBullSuppressVix or dailySmaBullSuppressBB or dailySmaBullSuppressBM or dailySmaBullSuppressRC or dailySmaBullSuppressEOD or dailySmaBullSuppressSoftTrail
dailySmaBull2SellSuppressed = dailySmaBull2SuppressPT or dailySmaBull2SuppressVix or dailySmaBull2SuppressBB or dailySmaBull2SuppressBM or dailySmaBull2SuppressRC or dailySmaBull2SuppressEOD or dailySmaBull2SuppressSoftTrail
dailySmaBull3SellSuppressed = dailySmaBull3SuppressPT or dailySmaBull3SuppressVix or dailySmaBull3SuppressBB or dailySmaBull3SuppressBM or dailySmaBull3SuppressRC or dailySmaBull3SuppressEOD or dailySmaBull3SuppressSoftTrail
dailySmaBull4SellSuppressed = dailySmaBull4SuppressPT or dailySmaBull4SuppressRC or dailySmaBull4SuppressSoftTrail
[gbf1Fail, gbf1W] = f_gbf(gapBounceWatchLeft, entryRegime, tradeMfePct, currentProfit, bbMid, gbfMidXdn, inPosition, withinRange, s2_gbfR4Enable, false, false, false, true, s2_gapBounceMinMfe, s2_gapBounceMinGap, s2_gbfGapLow, s2_gbfGapBars, s2_gbfMidXdn, s2_gbfMidTol, s2_sharedRcStochLen, s2_sharedRcStochK, s2_sharedRcStochD, s2_gbfStochKmax, s2_gapBounceMinPnl)
gapBounceWatchLeft := gbf1W
[gbf2Fail, gbf2W] = f_gbf(gapBounce2WatchLeft, entryRegime, tradeMfePct, currentProfit, bbMid, gbfMidXdn, inPosition, withinRange, s2_gbfR2Enable, false, true, false, false, s2_gbf2MinMfe, s2_gbf2MinGap, s2_gbfGapLow, s2_gbfGapBars, s2_gbfMidXdn, s2_gbfMidTol, s2_sharedRcStochLen, s2_sharedRcStochK, s2_sharedRcStochD, s2_gbfStochKmax, s2_gbf2MinPnl)
gapBounce2WatchLeft := gbf2W
gapBounceFailExit = gbf1Fail or gbf2Fail
if inPosition
    tradeBullSuppFlags := f_suppFlags(tradeBullSuppFlags, dailySmaBullSuppressPT or dailySmaBull2SuppressPT or dailySmaBull3SuppressPT or dailySmaBull4SuppressPT, dailySmaBullSuppressVix or dailySmaBull2SuppressVix or dailySmaBull3SuppressVix or dailySmaBull4SuppressVix, dailySmaBullSuppressBB or dailySmaBull2SuppressBB or dailySmaBull3SuppressBB or dailySmaBull4SuppressBB, dailySmaBullSuppressBM or dailySmaBull2SuppressBM or dailySmaBull3SuppressBM or dailySmaBull4SuppressBM, dailySmaBullSuppressRC or dailySmaBull2SuppressRC or dailySmaBull3SuppressRC or dailySmaBull4SuppressRC, dailySmaBullSuppressEOD or dailySmaBull2SuppressEOD or dailySmaBull3SuppressEOD or dailySmaBull4SuppressEOD, dailySmaBullSuppressSoftTrail or dailySmaBull2SuppressSoftTrail or dailySmaBull3SuppressSoftTrail or dailySmaBull4SuppressSoftTrail)
rcSellActive = rcSellActiveRaw and not dailySmaBullSuppressRC and not dailySmaBull2SuppressRC and not dailySmaBull3SuppressRC and not dailySmaBull4SuppressRC
dailySmaBearEntryRegimeOn = entryRegime == 1 ? dailySmaBearR1Eff : entryRegime == 2 ? dailySmaBearR2Eff : entryRegime == 3 ? dailySmaBearR3Eff : entryRegime == 4 ? dailySmaBearR4Eff : false
dailySmaBearStateActive = dailySmaBearFilterEff and dailySmaBearBlockBarsEff > 0 and (dailySmaBearCrossTrigger or dailySmaBearBelowTrigger)
dailySmaBearForceSellSignal1 = dailySmaBearForceSellEff and dailySmaBearStateActive and inPosition and withinRange and dailySmaBearEntryRegimeOn
dailySmaBear2EntryRegimeOn = entryRegime == 1 ? dailySmaBear2R1Eff : entryRegime == 2 ? dailySmaBear2R2Eff : entryRegime == 3 ? dailySmaBear2R3Eff : entryRegime == 4 ? dailySmaBear2R4Eff : false
dailySmaBear2StateActive = dailySmaBear2FilterEff and (dailySmaBear2CrossTrigger or dailySmaBear2BelowTrigger)
dailySmaBearForceSellSignal2 = dailySmaBear2ForceSellEff and dailySmaBear2StateActive and inPosition and withinRange and dailySmaBear2EntryRegimeOn
dailySmaBear3EntryRegimeOn = entryRegime == 1 ? dailySmaBear3R1Eff : entryRegime == 2 ? dailySmaBear3R2Eff : entryRegime == 3 ? dailySmaBear3R3Eff : entryRegime == 4 ? dailySmaBear3R4Eff : false
dailySmaBear3StateActive = dailySmaBear3FilterEff and (dailySmaBear3CrossTrigger or dailySmaBear3BelowTrigger)
dailySmaBearForceSellSignal3 = dailySmaBear3ForceSellEff and dailySmaBear3StateActive and inPosition and withinRange and dailySmaBear3EntryRegimeOn
dailySmaBear4EntryRegimeOn = entryRegime == 1 ? dailySmaBear4R1Eff : entryRegime == 2 ? dailySmaBear4R2Eff : entryRegime == 3 ? dailySmaBear4R3Eff : entryRegime == 4 ? dailySmaBear4R4Eff : false
dailySmaBear4StateActive = dailySmaBear4FilterEff and (dailySmaBear4CrossTrigger or dailySmaBear4BelowTrigger)
dailySmaBearForceSellSignal4 = dailySmaBear4ForceSellEff and dailySmaBear4StateActive and inPosition and withinRange and dailySmaBear4EntryRegimeOn
dailySmaBear5EntryRegimeOn = entryRegime == 1 ? dailySmaBear5R1Eff : entryRegime == 2 ? dailySmaBear5R2Eff : entryRegime == 3 ? dailySmaBear5R3Eff : entryRegime == 4 ? dailySmaBear5R4Eff : false
dailySmaBear5StateActive = dailySmaBear5FilterEff and (dailySmaBear5CrossTrigger or dailySmaBear5BelowTrigger)
dailySmaBearForceSellSignal5 = dailySmaBear5ForceSellEff and dailySmaBear5StateActive and inPosition and withinRange and dailySmaBear5EntryRegimeOn
dailySmaBear6EntryRegimeOn = entryRegime == 1 ? dailySmaBear6R1Eff : entryRegime == 2 ? dailySmaBear6R2Eff : entryRegime == 3 ? dailySmaBear6R3Eff : entryRegime == 4 ? dailySmaBear6R4Eff : false
dailySmaBear6StateActive = dailySmaBear6FilterEff and (dailySmaBear6CrossTrigger or dailySmaBear6BelowTrigger)
dailySmaBearForceSellSignal6 = dailySmaBear6ForceSellEff and dailySmaBear6StateActive and inPosition and withinRange and dailySmaBear6EntryRegimeOn
dailySmaBear7EntryRegimeOn = entryRegime == 1 ? dailySmaBear7R1Eff : entryRegime == 2 ? dailySmaBear7R2Eff : entryRegime == 3 ? dailySmaBear7R3Eff : entryRegime == 4 ? dailySmaBear7R4Eff : false
dailySmaBear7StateActive = dailySmaBear7FilterEff and (dailySmaBear7CrossTrigger or dailySmaBear7BelowTrigger)
dailySmaBearForceSellSignal7 = dailySmaBear7ForceSellEff and dailySmaBear7StateActive and inPosition and withinRange and dailySmaBear7EntryRegimeOn
dailySmaBearForceSellSignal = dailySmaBearForceSellSignal1 or dailySmaBearForceSellSignal2 or dailySmaBearForceSellSignal3 or dailySmaBearForceSellSignal4 or dailySmaBearForceSellSignal5 or dailySmaBearForceSellSignal6 or dailySmaBearForceSellSignal7

signalAllow = simIntrabarEff or barstate.isconfirmed

// Strategy 6: priority among branches when several are true; exits use close-based P&L to match near-close human execution.
buySignalS2Raw = signalAllow and (r0BuySignal or (not r0BuySignal and rcBuySignal) or (not r0BuySignal and not rcBuySignal and fearBuySignal) or (not r0BuySignal and not rcBuySignal and not fearBuySignal and midBuySignal))
// #2 CLARIFIED (behavior UNCHANGED — comments only). This Rule-1 block is a BELOW-BAND gate with a rarely-hit safety cap, NOT a wall-clock timer. Lifecycle:
//   ARM   : on the one-shot bar when the daily fast SMA first drops >= 'Below %' (18.5%) under the slow SMA (dailySmaBearBelowEvent), set blockLeft = 'Block bars' (210).
//   HOLD  : while price stays below the band the block stays active; the decrement near line ~2933 ticks blockLeft down only on below-band bars, so 210 counts BELOW-BAND HOURS (~32 trading days on 1h), not calendar bars.
//   RELEASE: whichever comes first — (a) price recovers above the band => the 'not belowThreshold' line below resets blockLeft to 0 immediately (the usual path, so in practice this acts as a pure below-band gate), or (b) 210 below-band bars elapse => the CAP lifts the block even if still bearish (rare; only in a prolonged deep bear).
// Read 'Block bars = 210' as a MAX-DURATION SAFETY CAP on the below-band block, NOT "block for 210 bars after the cross".
if dailySmaBearFilterEff and dailySmaBearBelowTrigger and dailySmaBearBlockBarsEff > 0
    dailySmaBearBlockLeft := dailySmaBearBlockBarsEff
if dailySmaBearFilterEff and not dailySmaBearBelowThreshold
    dailySmaBearBlockLeft := 0
dailySmaBearBlockActive = dailySmaBearStateActive or (dailySmaBearFilterEff and dailySmaBearBlockLeft > 0)
dailySmaBearTargetRegime = r0BuySignal ? 10 : rcBuySignal ? curRegimeInt : r1BuySignal ? 1 : r2BuySignal ? 2 : r3BuySignal ? 3 : r4BuySignal ? 4 : 0
dailySmaBearTargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBearR1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBearR2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBearR3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBearR4Eff : false
dailySmaBearR1RecoveryRelease = s2_sharedRecRule1R1 and dailySmaBearTargetRegime == 1 and sharedRecoverySoft
dailySmaBearBuyBlocked = buySignalS2Raw and dailySmaBearBlockActive and dailySmaBearTargetRegimeOn and not dailySmaBearR1RecoveryRelease
if dailySmaBear2FilterEff and dailySmaBear2CrossTrigger
    dailySmaBear2BlockLeft := dailySmaBear2BlockBarsEff
dailySmaBear2BlockActive = dailySmaBear2StateActive or (dailySmaBear2FilterEff and dailySmaBear2BlockLeft > 0)
dailySmaBear2TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear2R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear2R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear2R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear2R4Eff : false
dailySmaBear2BuyBlocked = buySignalS2Raw and dailySmaBear2BlockActive and dailySmaBear2TargetRegimeOn
if dailySmaBear3FilterEff and dailySmaBear3CrossTrigger
    dailySmaBear3BlockLeft := dailySmaBear3BlockBarsEff
dailySmaBear3BlockActive = dailySmaBear3StateActive or (dailySmaBear3FilterEff and dailySmaBear3BlockLeft > 0)
dailySmaBear3TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear3R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear3R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear3R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear3R4Eff : false
dailySmaBear3BuyBlocked = buySignalS2Raw and dailySmaBear3BlockActive and dailySmaBear3TargetRegimeOn
if s2_dseNoBuyEnable and dailySmaEntryNoBuyCrossTrigger
    dailySmaEntryNoBuyLeft := s2_dseNoBuyBars
dailySmaEntryNoBuyActive = s2_dseNoBuyEnable and (dailySmaEntryNoBuyCrossTrigger or dailySmaEntryNoBuyLeft > 0)
dailySmaEntryNoBuyRegimeOn = dailySmaBearTargetRegime == 1 ? s2_dseNoBuyR1 : dailySmaBearTargetRegime == 2 ? s2_dseNoBuyR2 : dailySmaBearTargetRegime == 3 ? s2_dseNoBuyR3 : dailySmaBearTargetRegime == 4 ? s2_dseNoBuyR4 : false
dailySmaEntryNoBuyKindOk = rcBuySignal ? s2_dseNoBuyRc : s2_dseNoBuyNormal
dailySmaEntryNoBuyBlocked = buySignalS2Raw and dailySmaEntryNoBuyActive and dailySmaEntryNoBuyRegimeOn and dailySmaEntryNoBuyKindOk
if s2_dseR2NoBuyEnable and dailySmaBear3CrossTrigger
    dailySmaEntryR2NoBuyLeft := s2_dseR2NoBuyBars
if s2_dseR4NoBuyEnable and dailySmaBear3CrossTrigger
    dailySmaEntryR4NoBuyLeft := s2_dseR4NoBuyBars
dailySmaEntryR2NoBuyBlocked = buySignalS2Raw and s2_dseR2NoBuyEnable and (dailySmaBear3CrossTrigger or dailySmaEntryR2NoBuyLeft > 0) and dailySmaBearTargetRegime == 2
dailySmaEntryR4NoBuyBlocked = buySignalS2Raw and s2_dseR4NoBuyEnable and (dailySmaBear3CrossTrigger or dailySmaEntryR4NoBuyLeft > 0) and dailySmaBearTargetRegime == 4
if s2_dse50100R4Enable and dailySmaBear2CrossTrigger
    dailySmaEntry50100R4Left := s2_dse50100R4Bars
if s2_dse50100R3Enable and dailySmaBear2CrossTrigger
    dailySmaEntry50100R3Left := s2_dse50100R3Bars
dailySmaEntry50100R4Blocked = buySignalS2Raw and s2_dse50100R4Enable and (dailySmaBear2CrossTrigger or dailySmaEntry50100R4Left > 0) and dailySmaBearTargetRegime == 4 and not (s2_sharedRec50100R4 and sharedRecoverySoft)
dailySmaEntry50100R3Blocked = buySignalS2Raw and s2_dse50100R3Enable and (dailySmaBear2CrossTrigger or dailySmaEntry50100R3Left > 0) and dailySmaBearTargetRegime == 3 and not (s2_sharedRec50100R3 and sharedRecoverySoft)
if s2_dse50200R2Enable and dailySmaBear4CrossTrigger
    dailySmaEntry50200R2Left := s2_dse50200R2Bars
dailySmaEntry50200R2Blocked = buySignalS2Raw and s2_dse50200R2Enable and (dailySmaBear4CrossTrigger or dailySmaEntry50200R2Left > 0) and dailySmaBearTargetRegime == 2 and not (s2_sharedRec50200R2 and sharedRecoverySoft)
if dailySmaBear4FilterEff and dailySmaBear4CrossTrigger
    dailySmaBear4BlockLeft := dailySmaBear4BlockBarsEff
dailySmaBear4BlockActive = dailySmaBear4StateActive or (dailySmaBear4FilterEff and dailySmaBear4BlockLeft > 0)
dailySmaBear4TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear4R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear4R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear4R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear4R4Eff : false
dailySmaBear4BuyBlocked = buySignalS2Raw and dailySmaBear4BlockActive and dailySmaBear4TargetRegimeOn
if dailySmaBear5FilterEff and dailySmaBear5CrossTrigger
    dailySmaBear5BlockLeft := dailySmaBear5BlockBarsEff
dailySmaBear5BlockActive = dailySmaBear5StateActive or (dailySmaBear5FilterEff and dailySmaBear5BlockLeft > 0)
dailySmaBear5TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear5R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear5R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear5R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear5R4Eff : false
dailySmaBear5BuyBlocked = buySignalS2Raw and dailySmaBear5BlockActive and dailySmaBear5TargetRegimeOn
if dailySmaBear6FilterEff and dailySmaBear6CrossTrigger
    dailySmaBear6BlockLeft := dailySmaBear6BlockBarsEff
dailySmaBear6BlockActive = dailySmaBear6StateActive or (dailySmaBear6FilterEff and dailySmaBear6BlockLeft > 0)
dailySmaBear6TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear6R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear6R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear6R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear6R4Eff : false
dailySmaBear6BuyBlocked = buySignalS2Raw and dailySmaBear6BlockActive and dailySmaBear6TargetRegimeOn
if dailySmaBear7FilterEff and dailySmaBear7CrossTrigger
    dailySmaBear7BlockLeft := dailySmaBear7BlockBarsEff
dailySmaBear7BlockActive = dailySmaBear7StateActive or (dailySmaBear7FilterEff and dailySmaBear7BlockLeft > 0)
dailySmaBear7TargetRegimeOn = dailySmaBearTargetRegime == 1 ? dailySmaBear7R1Eff : dailySmaBearTargetRegime == 2 ? dailySmaBear7R2Eff : dailySmaBearTargetRegime == 3 ? dailySmaBear7R3Eff : dailySmaBearTargetRegime == 4 ? dailySmaBear7R4Eff : false
dailySmaBear7BuyBlocked = buySignalS2Raw and dailySmaBear7BlockActive and dailySmaBear7TargetRegimeOn
// RCL buy block. Toggle OFF: lock blocks buys in ALL regimes until release = original tuned 12.9M% behavior. Toggle ON: regime-aware — for the first s2_rclCrossRegimeBars bars after the sell it still blocks all regimes (bounded cross-regime cooldown), then it only blocks re-buys while we are still in the arming regime (rclBuyLockSrc == curRegimeInt); in other regimes it goes dormant (still counts toward the max-bar cap and watches for oversold-recovery release).
rclBuyBlocked = buySignalS2Raw and rclLifecycleActive and rclBuyLock and (not s2_rclLockRegimeAware or rclBuyLockBars <= s2_rclCrossRegimeBars or rclBuyLockSrc == curRegimeInt)
ptRcRegOnInt = rcBuySignal ? (rcBuyR0 ? 10 : rcBuyPendingTarget > 0 ? rcBuyPendingTarget : curRegimeInt) : curRegimeInt
rcPtWaitR3TooSoon = s2_rcPtWaitR3Enable and s2_rcPtWaitR3Bars > 0 and not na(rcPtWaitR3LastBar) and ptRcRegOnInt == 3 and (bar_index - rcPtWaitR3LastBar) <= s2_rcPtWaitR3Bars
rcPtWaitR3Blocked = buySignalS2Raw and rcBuySignal and rcPtWaitR3TooSoon and not (s2_sharedRecPtWaitR3 and sharedRecoverySoft)
rcSlTslWaitTooSoon = s2_rcSlTslWaitEnable and s2_rcSlTslWaitBars > 0 and not na(rcSlTslWaitLastBar) and ptRcRegOnInt == 1 and (bar_index - rcSlTslWaitLastBar) <= s2_rcSlTslWaitBars
rcSlTslWaitBlocked = buySignalS2Raw and rcBuySignal and rcSlTslWaitTooSoon and not (s2_sharedRecSlTslWaitR1 and sharedRecoverySoft)
rcBmWaitR0TooSoon = s2_rcBmWaitR0Enable and s2_rcBmWaitR0Bars > 0 and not na(rcBmWaitR0LastBar) and ptRcRegOnInt == 10 and (bar_index - rcBmWaitR0LastBar) <= s2_rcBmWaitR0Bars
rcBmWaitR0Blocked = buySignalS2Raw and rcBuySignal and rcBmWaitR0TooSoon and not (s2_sharedRecBmWaitR0 and sharedRecoverySoft)
rcSLeadWaitR12TooSoon = not na(rcSLeadWaitR12LastBar) and ptRcRegOnInt == 1 and s2_rcSLeadWaitR1Enable and s2_rcSLeadWaitR1Bars > 0 and (bar_index - rcSLeadWaitR12LastBar) <= s2_rcSLeadWaitR1Bars
if s2_rcSLeadRecEnable and rcSLeadWaitR12TooSoon
    if (bar_index - rcSLeadWaitR12LastBar) <= s2_rcSLeadRecMinBars
        rcSLeadRecReleased := false
    else
        if not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(bbBuyMid) and sharedStochK > sharedStochD and sharedStochK > sharedStochK[1] and close > close[1] and close > bbBuyMid
            rcSLeadRecReleased := true
        if rcSLeadRecReleased and not na(sharedStochK) and not na(sharedStochD) and not na(sharedStochK[1]) and not na(bbBuyMid) and (((sharedStochK < sharedStochD) or (sharedStochK < sharedStochK[1])) or close < bbBuyMid) and close < close[1]
            rcSLeadRecReleased := false
else
    rcSLeadRecReleased := false
rcSLeadWaitR12Blocked = buySignalS2Raw and (rcBuySignal or (s2_rcSLeadRecRegularR1 and r1BuySignal and not rcBuySignal)) and rcSLeadWaitR12TooSoon and (not s2_rcSLeadRecEnable or not rcSLeadRecReleased) and not (s2_sharedRecSLeadWaitR1 and sharedRecoverySoft)
buySignalS2 = buySignalS2Raw and not dailySmaBearBuyBlocked and not dailySmaBear2BuyBlocked and not dailySmaBear3BuyBlocked and not dailySmaEntryNoBuyBlocked and not dailySmaEntryR2NoBuyBlocked and not dailySmaEntryR4NoBuyBlocked and not dailySmaEntry50100R4Blocked and not dailySmaEntry50100R3Blocked and not dailySmaEntry50200R2Blocked and not dailySmaBear4BuyBlocked and not dailySmaBear5BuyBlocked and not dailySmaBear6BuyBlocked and not dailySmaBear7BuyBlocked and not rclBuyBlocked and not rcPtWaitR3Blocked and not rcSlTslWaitBlocked and not rcBmWaitR0Blocked and not rcSLeadWaitR12Blocked
sellExitS2 = signalAllow and inPosition and f_sx(dailySmaBearForceSellSignal, stopHit, r0FastExit, r0RegimeChangeExit, rcSellActive, gapBounceFailExit, rcStochLeadExit, rcBreakdownExit, rcLifecycleExit, riskGuardExit, softCompositeSell, eodSell)
// #2: runs on every non-event bar, but above-band bars were already zeroed at the 'not belowThreshold' reset, so this effectively counts DOWN the 210 cap only while price remains below the band (see full lifecycle comment near buySignalS2Raw).
if not dailySmaBearBelowTrigger and dailySmaBearBlockLeft > 0
    dailySmaBearBlockLeft := dailySmaBearBlockLeft - 1
if not dailySmaBear2CrossTrigger and dailySmaBear2BlockLeft > 0
    dailySmaBear2BlockLeft := dailySmaBear2BlockLeft - 1
if not dailySmaBear3CrossTrigger and dailySmaBear3BlockLeft > 0
    dailySmaBear3BlockLeft := dailySmaBear3BlockLeft - 1
if not dailySmaBear4CrossTrigger and dailySmaBear4BlockLeft > 0
    dailySmaBear4BlockLeft := dailySmaBear4BlockLeft - 1
if not dailySmaBear5CrossTrigger and dailySmaBear5BlockLeft > 0
    dailySmaBear5BlockLeft := dailySmaBear5BlockLeft - 1
if not dailySmaBear6CrossTrigger and dailySmaBear6BlockLeft > 0
    dailySmaBear6BlockLeft := dailySmaBear6BlockLeft - 1
if not dailySmaBear7CrossTrigger and dailySmaBear7BlockLeft > 0
    dailySmaBear7BlockLeft := dailySmaBear7BlockLeft - 1
if not dailySmaEntryNoBuyCrossTrigger and dailySmaEntryNoBuyLeft > 0
    dailySmaEntryNoBuyLeft := dailySmaEntryNoBuyLeft - 1
if not dailySmaBear3CrossTrigger and dailySmaEntryR2NoBuyLeft > 0
    dailySmaEntryR2NoBuyLeft := dailySmaEntryR2NoBuyLeft - 1
if not dailySmaBear3CrossTrigger and dailySmaEntryR4NoBuyLeft > 0
    dailySmaEntryR4NoBuyLeft := dailySmaEntryR4NoBuyLeft - 1
if not dailySmaBear2CrossTrigger and dailySmaEntry50100R4Left > 0
    dailySmaEntry50100R4Left := dailySmaEntry50100R4Left - 1
if not dailySmaBear2CrossTrigger and dailySmaEntry50100R3Left > 0
    dailySmaEntry50100R3Left := dailySmaEntry50100R3Left - 1
if not dailySmaBear4CrossTrigger and dailySmaEntry50200R2Left > 0
    dailySmaEntry50200R2Left := dailySmaEntry50200R2Left - 1
// Manual Overrides — match exact intraday bar: time <= picked < time_close. Aggregate across 2 slots; inPosition/flat split selects Buy vs Sell intent. Manual wins over all automatic signals and exit gates below.
movBar(picked) => time <= picked and time_close > picked
isMov1 = s2_mov1En and movBar(s2_mov1T)
isMov2 = s2_mov2En and movBar(s2_mov2T)
isManualBuyIntent  = (isMov1 and s2_mov1Ty == "Buy")  or (isMov2 and s2_mov2Ty == "Buy")
isManualSellIntent = (isMov1 and s2_mov1Ty == "Sell") or (isMov2 and s2_mov2Ty == "Sell")
// Ticker gate — manual never fires (and never draws 'M skip' either) on a chart whose syminfo.ticker differs from s2_movSymbol.
movSymOk = s2_movSymbol == "" or syminfo.ticker == s2_movSymbol
manualBuyExec    = movSymOk and isManualBuyIntent  and not inPosition
manualSellExec   = movSymOk and isManualSellIntent and inPosition
manualBuySkipped = movSymOk and isManualBuyIntent  and inPosition
manualSellSkipped= movSymOk and isManualSellIntent and not inPosition

buySignal = manualBuyExec or buySignalS2
// Same bar as S1: do not plot/process sell when a buy raw signal is true (avoids intrabar marker glitches vs Strategy 1). Manual sell overrides all auto-exit gates; manual buy blocks any sell on same bar.
sellSignal = manualSellExec or (sellExitS2 and not buySignalRaw and not manualBuyExec)

var bool isStopExit = false
var bool isProfitExit = false
var bool isSoftTrailExit = false
var bool isVixExit = false
var bool isEodExit = false
var bool isR0RegimeExit = false
var bool isR0FastExit = false
var bool isRcSellExit = false
var bool isBbR1UpperExit = false
var bool isBbR2UpperExit = false
var bool isBbR3UpperExit = false
var bool isBbR4UpperExit = false
var bool isBbUpperExit = false
var bool isBbMidSlopeExit = false
var bool isRiskGuardExit = false
var bool isGapBounceExit = false
var bool isGapBounce2Exit = false
var bool isRcStochLeadExit = false
var bool isRcBreakdownExit = false
var bool isRclLifecycleExit = false
var bool isDailySmaBearExit = false
var bool isManualExit = false
// Manual exit tagged first and excluded from every other exit-type flag below, so the sell is accounted as "M" (close PnL) instead of SL/PT/TSL/BB/etc.
isManualExit := sellSignal and manualSellExec
isDailySmaBearExit := sellSignal and dailySmaBearForceSellSignal and not isManualExit
isGapBounceExit := sellSignal and gbf1Fail and not stopHit and not isDailySmaBearExit and not isManualExit
isGapBounce2Exit := sellSignal and gbf2Fail and not gbf1Fail and not stopHit and not isDailySmaBearExit and not isManualExit
isRcStochLeadExit := sellSignal and rcStochLeadExit and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isManualExit
isRcBreakdownExit := sellSignal and rcBreakdownExit and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isManualExit
isRclLifecycleExitR4 = sellSignal and rclLockedExitR4 and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isManualExit
isRclLifecycleExitR3 = sellSignal and rclLockedExitR3 and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isManualExit
isRclLifecycleExitR1 = sellSignal and rclLockedExitR1 and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isManualExit
isRclLifecycleExitR2 = sellSignal and rclLockedExitR2 and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isManualExit
isRclLifecycleExitR0 = sellSignal and rclLockedExitR0 and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isManualExit
isRclLifecycleExit := isRclLifecycleExitR4 or isRclLifecycleExitR3 or isRclLifecycleExitR2 or isRclLifecycleExitR1 or isRclLifecycleExitR0
isRiskGuardExit := sellSignal and riskGuardExit and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isRclLifecycleExit and not isManualExit
isSoftTrailExit := sellSignal and softTrailBreached and not stopHit and not isDailySmaBearExit and not isGapBounceExit and not isGapBounce2Exit and not isRcStochLeadExit and not isRcBreakdownExit and not isRclLifecycleExit and not isRiskGuardExit and not isManualExit
isBbR1UpperExit := sellSignal and bbR1UpperRaw and not isSoftTrailExit and not stopHit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isBbR2UpperExit := sellSignal and bbR2UpperRaw and not isSoftTrailExit and not stopHit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isBbR3UpperExit := sellSignal and bbR3UpperRaw and not isSoftTrailExit and not stopHit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isBbR4UpperExit := sellSignal and bbR4UpperRaw and not isSoftTrailExit and not stopHit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isBbUpperExit := isBbR1UpperExit or isBbR2UpperExit or isBbR3UpperExit or isBbR4UpperExit
isBbMidSlopeExit := sellSignal and bbMidSlopeExitSignal and not isSoftTrailExit and not isBbUpperExit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isStopExit := sellSignal and stopHit and not isBbUpperExit and not isBbMidSlopeExit and not isDailySmaBearExit and not isManualExit
isProfitExit := sellSignal and wantPt and not isSoftTrailExit and not stopHit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit and not r0RegimeChangeExit
isR0FastExit := sellSignal and r0FastExit and not profitHitForSell and not isSoftTrailExit and not stopHit and not isBbUpperExit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isR0RegimeExit := sellSignal and r0RegimeChangeExit and not profitHitForSell and not isSoftTrailExit and not stopHit and not r0FastExit and not rcSellActive and not isBbUpperExit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isRcSellExit := sellSignal and rcSellActive and not profitHitForSell and not isSoftTrailExit and not stopHit and not r0FastExit and not isBbUpperExit and not isDailySmaBearExit and not isManualExit
isEodExit := sellSignal and eodSell and not profitHitForSell and not isSoftTrailExit and not stopHit and not r0FastExit and not r0RegimeChangeExit and not rcSellActive and not isBbUpperExit and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit
isVixExit := sellSignal and fearVixExit and not profitHitForSell and not isSoftTrailExit and not stopHit and not eodSell and not rcSellActive and not bbAnyUpperRaw and not isDailySmaBearExit and not isRiskGuardExit and not isManualExit

// #3 robustness: realized trade return net of the optional round-trip cost/slippage haircut (entries/exits are unaffected — they use currentProfit directly). Default OFF => 0 => identical to baseline.
sellDispPct = currentProfit - (s2_costEnable ? s2_costRoundTrip : 0.0)
exitReason = isManualExit ? "M" : isDailySmaBearExit ? "DSMA" : isGapBounceExit ? "GapFail" : isGapBounce2Exit ? "GapFail2" : isRcStochLeadExit ? "SLead" : isRcBreakdownExit ? "Brk" : isRclLifecycleExit ? "RCL" : isRiskGuardExit ? "RG" : isBbMidSlopeExit ? "BM" : isBbUpperExit ? "BB" : isStopExit ? "SL" : isSoftTrailExit ? "TSL" : isProfitExit ? "PT" : isR0FastExit ? "FV" : isRcSellExit ? "RC" : isR0RegimeExit ? "RC" : isEodExit ? "EOD" : isVixExit ? "V" : "?"
sqqqBuyOk = s2_sqqqAll or (s2_sqqqTsl and isSoftTrailExit) or (s2_sqqqBm and isBbMidSlopeExit) or (s2_sqqqRcl and isRclLifecycleExit) or (s2_sqqqRg and isRiskGuardExit) or (s2_sqqqDsma and isDailySmaBearExit) or (s2_sqqqEod and isEodExit) or (s2_sqqqSlead and isRcStochLeadExit) or (s2_sqqqSl and isStopExit) or (s2_sqqqBb and isBbUpperExit) or (s2_sqqqGapFail2 and isGapBounce2Exit) or (s2_sqqqBrk and isRcBreakdownExit) or (s2_sqqqRc and (isRcSellExit or isR0RegimeExit)) or (s2_sqqqFv and isR0FastExit) or (s2_sqqqV and isVixExit) or (s2_sqqqGapFail and isGapBounceExit) or (s2_sqqqPt and isProfitExit)
// Option-A cell blocklist gate: sqqqBuyOkEff drops any (trigger x entry-regime) cell listed in s2_sqqqBlockCells. Used by the actual SQQQ sim + continuous entries; the research table stays on the ungated pending. Empty blocklist => sqqqBuyOkEff == sqqqBuyOk (baseline).
sqqqCellBlocked = sqqqBuyOk and f_sqCellBlocked(f_scTypeIndex(exitReason), f_scRegIndex(entryRegime))
sqqqBuyOkEff = sqqqBuyOk and not sqqqCellBlocked

// Regime change adapt — switch exit rules to new regime (takes effect next bar)
if useRCEff and rcJustConfirmed and inPosition and not sellSignal and entryRegime >= 1 and entryRegime <= 4
    if useRc12Eff and isRc12 and rc12HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc21Eff and isRc21 and rc21HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc24Eff and isRc24 and rc24HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc31Eff and isRc31 and rc31HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc34Eff and isRc34 and rc34HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc43Eff and isRc43 and rc43HoldingEff == "ADAPT"
        entryRegime := curRegimeInt
    if useRc40Eff and isRc40 and rc40HoldingEff == "ADAPT"
        entryRegime := curRegimeInt

if useRCEff and rcJustConfirmed and inPosition and not sellSignal and useRc03Eff and isRc03 and rc03HoldingEff == "ADAPT" and entryRegime == 10
    entryRegime := curRegimeInt
    r0Rc03Hold := false

if buySignal
    inPosition := true
    barsInTrade := 0
    bmSlopePeakTracked := 0.0
    softTrailArmed := false
    softTrailPeak := na
    softTrailPct := na
    softTrailArmKind := 0
    erNew = manualBuyExec ? (isR0Regime ? 10 : curRegimeInt) : r0BuySignal ? 10 : rcBuySignal ? curRegimeInt : r1BuySignal ? 1 : r2BuySignal ? 2 : r3BuySignal ? 3 : 4
    entryRegime := erNew
    entryPrice := close
    entryTime := time
    entryBarIndex := bar_index
    entryVixPct := erNew == 10 ? vixAbove : erNew == 1 ? vixAbove : erNew == 2 ? vixAbove : erNew == 3 ? vixAbove : vixAbove
    entryAtrPct := r1AtrRiskPct
    entryAtrPctValid := r1AtrRiskPctValid
    entryAtrPctRising := r1AtrRiskPctRising
    entryBbBuyWidthPct := bbBuyWidthPct
    entryBbBuyMidSlopePct := bbBuyMidSlopePct
    entrySignalType := f_entrySignalType(manualBuyExec, r0BuySignal, rcBuySignal, r1BuySignal, r2BuySignal, r3BuySignal)
    entryBbZone := f_bbEntryZone(bbBuyOk, close, bbBuyLower, bbBuyMid, bbBuyUpper)
    entryBearFlags := f_bearFlags(dailySmaBearFilterEff and dailySmaBearBlockActive, dailySmaBear2FilterEff and dailySmaBear2BlockActive, dailySmaBear3FilterEff and dailySmaBear3BlockActive, dailySmaBear4FilterEff and dailySmaBear4BlockActive, dailySmaBear5FilterEff and dailySmaBear5BlockActive, dailySmaBear6FilterEff and dailySmaBear6BlockActive, dailySmaBear7FilterEff and dailySmaBear7BlockActive)
    entryBullFlags := f_bullFlags(erNew, dailySmaBullR1Eff, dailySmaBullR2Eff, dailySmaBullR3Eff, dailySmaBullR4Eff, dailySmaBull2R1Eff, dailySmaBull2R2Eff, dailySmaBull2R3Eff, dailySmaBull2R4Eff, dailySmaBull3R1Eff, dailySmaBull3R2Eff, dailySmaBull3R3Eff, dailySmaBull3R4Eff, dailySmaBullSellEff and (dailySmaBullCrossTrigger or dailySmaBullAboveTrigger or dailySmaBullSellActiveLeft > 0), dailySmaBull2SellEff and (dailySmaBull2CrossTrigger or dailySmaBull2AboveTrigger or dailySmaBull2SellActiveLeft > 0), dailySmaBull3SellEff and (dailySmaBull3CrossTrigger or dailySmaBull3AboveTrigger or dailySmaBull3SellActiveLeft > 0))
    entryDailySmaStack := f_dailySmaStack(dailyForensicSma20, dailyForensicSma50, dailyForensicSma100, dailyForensicSma200)
    entryDailySmaSlope := f_dailySmaSlope(dailyForensicSma20Up, dailyForensicSma50Up, dailyForensicSma100Up, dailyForensicSma200Up)
    entryDailySmaCross := f_dailySmaCross(dailyForensic20x50UpBars, dailyForensic20x50DnBars)
    entryDailySma20v50 := f_relPct(dailyForensicSma20, dailyForensicSma50)
    entryDailySma50v100 := f_relPct(dailyForensicSma50, dailyForensicSma100)
    entryDailySma100v200 := f_relPct(dailyForensicSma100, dailyForensicSma200)
    entryDailySma20v200 := f_relPct(dailyForensicSma20, dailyForensicSma200)
    tradeBullSuppFlags := ""
    tradeMfePct := 0.0
    tradeMaePct := 0.0
    gapBounceWatchLeft := 0
    gapBounce2WatchLeft := 0
    rclEmbedArmed := false
    rclEmbedRun := 0
    rcl1EmbedArmed := false
    rcl1EmbedRun := 0
    rcl2EmbedArmed := false
    rcl2EmbedRun := 0
    rcl3EmbedArmed := false
    rcl3EmbedRun := 0
    rcl0EmbedArmed := false
    rcl0EmbedRun := 0
    rcBuyPending := false
    rcPtWaitR3LastBar := na
    rcSlTslWaitLastBar := na
    rcBmWaitR0LastBar := na
    rcSLeadWaitR12LastBar := na
    rcSLeadRecReleased := false
    if na(firstBuyPrice) and inReport
        firstBuyPrice := close

if sellSignal
    if s2_rcPtWaitR3Enable
        if isProfitExit
            rcPtWaitR3LastBar := bar_index
        else
            rcPtWaitR3LastBar := na
    if s2_rcSlTslWaitEnable
        if isStopExit or isSoftTrailExit
            rcSlTslWaitLastBar := bar_index
        else
            rcSlTslWaitLastBar := na
    if s2_rcBmWaitR0Enable
        if isBbMidSlopeExit
            rcBmWaitR0LastBar := bar_index
        else
            rcBmWaitR0LastBar := na
    if s2_rcSLeadWaitR1Enable
        if isRcStochLeadExit
            rcSLeadWaitR12LastBar := bar_index
            rcSLeadRecReleased := false
        else
            rcSLeadWaitR12LastBar := na
            rcSLeadRecReleased := false
    if isRclLifecycleExitR4
        rclBuyLock := true
        rclBuyLockSrc := 4
        rclBuyLockBars := 0
        rclOsEmbedSeen := false
        rclOsEmbedRun := 0
    else if isRclLifecycleExitR3
        rclBuyLock := true
        rclBuyLockSrc := 3
        rclBuyLockBars := 0
        rcl3OsEmbedSeen := false
        rcl3OsEmbedRun := 0
    else if isRclLifecycleExitR1
        rclBuyLock := true
        rclBuyLockSrc := 1
        rclBuyLockBars := 0
        rcl1OsEmbedSeen := false
        rcl1OsEmbedRun := 0
    else if isRclLifecycleExitR2
        rclBuyLock := true
        rclBuyLockSrc := 2
        rclBuyLockBars := 0
        rcl2OsEmbedSeen := false
        rcl2OsEmbedRun := 0
    else if isRclLifecycleExitR0
        rclBuyLock := true
        rclBuyLockSrc := 10
        rclBuyLockBars := 0
        rcl0OsEmbedSeen := false
        rcl0OsEmbedRun := 0
    barsInTrade := 0
    bmSlopePeakTracked := 0.0
    // R0 sell while still calm: restart confirm bars before any re-entry
    if entryRegime == 10 and isR0Regime
        r0BarsInRegime := 0
    if inReport
        compoundedValue := compoundedValue * (1 + sellDispPct / 100)
        totalTrades := totalTrades + 1
        if sellDispPct > 0
            winTrades := winTrades + 1
        _scTypeIdx = f_scTypeIndex(exitReason)
        _scRegIdx = f_scRegIndex(entryRegime)
        if not na(_scTypeIdx) and not na(_scRegIdx)
            if _scTypeIdx <= 15 and not na(sqqqClose)
                sqqqStatsPendType := _scTypeIdx
                sqqqStatsPendReg := _scRegIdx
                sqqqStatsPendPrice := sqqqClose
        if s2_sqqqContinuous and contState == 1
            contEquity := contEquity * (1 + sellDispPct / 100)
            contTqqqLegs := contTqqqLegs + 1
            f_contRecordTrade(sellDispPct, contPerfF, contPerfI)
            if sqqqBuyOkEff and not na(sqqqClose)
                contState := 2
                contSqqqEntryPrice := sqqqClose
            else
                contState := 0
                contSqqqEntryPrice := na
                contCashLegs := contCashLegs + 1
        if entryRegime == 10
            tradesR0 := tradesR0 + 1
            compR0 := compR0 * (1 + sellDispPct / 100)
            if sellDispPct > 0
                winsR0 := winsR0 + 1
        else if entryRegime == 1
            tradesR1 := tradesR1 + 1
            compR1 := compR1 * (1 + sellDispPct / 100)
            if sellDispPct > 0
                winsR1 := winsR1 + 1
        else if entryRegime == 2
            tradesR2 := tradesR2 + 1
            compR2 := compR2 * (1 + sellDispPct / 100)
            if sellDispPct > 0
                winsR2 := winsR2 + 1
        else if entryRegime == 3
            tradesR3 := tradesR3 + 1
            compR3 := compR3 * (1 + sellDispPct / 100)
            if sellDispPct > 0
                winsR3 := winsR3 + 1
        else if entryRegime == 4
            tradesR4 := tradesR4 + 1
            compR4 := compR4 * (1 + sellDispPct / 100)
            if sellDispPct > 0
                winsR4 := winsR4 + 1
        sumRet := sumRet + sellDispPct
        sumRetSq := sumRetSq + sellDispPct * sellDispPct
        if na(bestTradePct) or sellDispPct > bestTradePct
            bestTradePct := sellDispPct
        if na(worstTradePct) or sellDispPct < worstTradePct
            worstTradePct := sellDispPct
        if sellDispPct > 0
            sumWinPct := sumWinPct + sellDispPct
            winAbs = sellDispPct
            if winAbs > 0.0 and winAbs < 2.0
                win0to2Count := win0to2Count + 1
            else if winAbs >= 2.0 and winAbs < 5.0
                win2to5Count := win2to5Count + 1
            else if winAbs >= 5.0 and winAbs < 10.0
                win5to10Count := win5to10Count + 1
            else if winAbs >= 10.0 and winAbs < 15.0
                win10to15Count := win10to15Count + 1
            else if winAbs >= 15.0 and winAbs < 20.0
                win15to20Count := win15to20Count + 1
            else if winAbs >= 20.0 and winAbs < 25.0
                win20to25Count := win20to25Count + 1
            else if winAbs >= 25.0 and winAbs < 30.0
                win25to30Count := win25to30Count + 1
            else if winAbs >= 30.0
                winOver30Count := winOver30Count + 1
            curWinStreak := curWinStreak + 1
            curLoseStreak := 0
            if curWinStreak > maxWinStreak
                maxWinStreak := curWinStreak
        else if sellDispPct < 0
            sumLossPct := sumLossPct + sellDispPct
            loseCount := loseCount + 1
            lossAbs = -sellDispPct
            if lossAbs > 0.0 and lossAbs < 2.0
                loss0to2Count := loss0to2Count + 1
            else if lossAbs >= 2.0 and lossAbs < 5.0
                loss2to5Count := loss2to5Count + 1
            else if lossAbs >= 5.0 and lossAbs < 10.0
                loss5to10Count := loss5to10Count + 1
            else if lossAbs >= 10.0 and lossAbs < 15.0
                loss10to15Count := loss10to15Count + 1
            else if lossAbs >= 15.0 and lossAbs < 20.0
                loss15to20Count := loss15to20Count + 1
            else if lossAbs >= 20.0 and lossAbs < 25.0
                loss20to25Count := loss20to25Count + 1
            else if lossAbs >= 25.0 and lossAbs < 30.0
                loss25to30Count := loss25to30Count + 1
            else if lossAbs >= 30.0
                lossOver30Count := lossOver30Count + 1
            curLoseStreak := curLoseStreak + 1
            curWinStreak := 0
            if curLoseStreak > maxLoseStreak
                maxLoseStreak := curLoseStreak
    inPosition := false
    entryRegime := 0
    lastSellBar := bar_index
    lastSellPrice := close
    entryPrice := na
    entryTime := na
    entryBarIndex := na
    entryVixPct := na
    entryAtrPct := na
    entryAtrPctValid := false
    entryAtrPctRising := false
    entryBbBuyWidthPct := na
    entryBbBuyMidSlopePct := na
    entrySignalType := ""
    entryBearFlags := ""
    entryBullFlags := ""
    entryBbZone := ""
    entryDailySmaStack := ""
    entryDailySmaSlope := ""
    entryDailySmaCross := ""
    entryDailySma20v50 := na
    entryDailySma50v100 := na
    entryDailySma100v200 := na
    entryDailySma20v200 := na
    tradeBullSuppFlags := ""
    tradeMfePct := na
    tradeMaePct := na
    gapBounceWatchLeft := 0
    gapBounce2WatchLeft := 0
    rclEmbedArmed := false
    rclEmbedRun := 0
    rcl1EmbedArmed := false
    rcl1EmbedRun := 0
    rcl2EmbedArmed := false
    rcl2EmbedRun := 0
    rcl3EmbedArmed := false
    rcl3EmbedRun := 0
    rcl0EmbedArmed := false
    rcl0EmbedRun := 0
    r0Rc03Hold := false
    bbPullbackArmed := false
    bbPullbackBars := 0
    softTrailArmed := false
    softTrailPeak := na
    softTrailPct := na
    softTrailArmKind := 0

if inReport and buySignal
    if not na(sqqqStatsPendType) and not na(sqqqStatsPendReg) and not na(sqqqStatsPendPrice) and not na(sqqqClose) and sqqqStatsPendPrice != 0
        _sqPct = (sqqqClose / sqqqStatsPendPrice - 1.0) * 100.0
        _sqCell = f_scCellIndex(sqqqStatsPendType, sqqqStatsPendReg)
        array.push(sqqqStatsMedVals, sqqqStatsPendType * 100000.0 + _sqPct + 10000.0)
        array.set(sqqqStatsTrades, _sqCell, array.get(sqqqStatsTrades, _sqCell) + 1)
        array.set(sqqqStatsSum, _sqCell, array.get(sqqqStatsSum, _sqCell) + _sqPct)
        array.set(sqqqStatsComp, _sqCell, array.get(sqqqStatsComp, _sqCell) * (1.0 + _sqPct / 100.0))
        if _sqPct > 0
            array.set(sqqqStatsWins, _sqCell, array.get(sqqqStatsWins, _sqCell) + 1)
        _sqBest = array.get(sqqqStatsBest, _sqCell)
        _sqWorst = array.get(sqqqStatsWorst, _sqCell)
        array.set(sqqqStatsBest, _sqCell, na(_sqBest) ? _sqPct : math.max(_sqBest, _sqPct))
        array.set(sqqqStatsWorst, _sqCell, na(_sqWorst) ? _sqPct : math.min(_sqWorst, _sqPct))
    sqqqStatsPendType := na
    sqqqStatsPendReg := na
    sqqqStatsPendPrice := na
    if s2_sqqqContinuous
        if contState == 2 and not na(contSqqqEntryPrice) and not na(sqqqClose) and contSqqqEntryPrice != 0
            _contSqPct = (sqqqClose / contSqqqEntryPrice - 1.0) * 100.0
            contEquity := contEquity * (1.0 + _contSqPct / 100.0)
            contSqqqLegs := contSqqqLegs + 1
            f_contRecordTrade(_contSqPct, contPerfF, contPerfI)
            contSqqqEntryPrice := na
        contState := 1

if sqqqSimEnableEff and inReport and buySignal and sqqqInPosition and not na(sqqqEntryPrice) and not na(sqqqClose)
    sqqqTradePct = (sqqqClose / sqqqEntryPrice - 1.0) * 100.0
    sqqqEquity := sqqqEquity * (1.0 + sqqqTradePct / 100.0)
    sqqqTrades := sqqqTrades + 1
    if sqqqTradePct > 0
        sqqqWins := sqqqWins + 1
    sqqqInPosition := false
    sqqqEntryPrice := na

if sqqqSimEnableEff and inReport and sellSignal and not sqqqInPosition and not na(sqqqClose) and sqqqBuyOkEff
    sqqqInPosition := true
    sqqqEntryPrice := sqqqClose

tqqqDisplayClose = useStartDate and not na(endPrice) ? endPrice : close
tqqqDisplayProfit = inPosition and not na(entryPrice) and entryPrice != 0 and not na(tqqqDisplayClose) ? (tqqqDisplayClose - entryPrice) / entryPrice * 100 : 0.0
sqqqDisplayClose = useStartDate ? lastInRangeSqqqClose : sqqqClose
sqqqOpenEquity = sqqqInPosition and not na(sqqqEntryPrice) and sqqqEntryPrice != 0 and not na(sqqqDisplayClose) ? sqqqEquity * (sqqqDisplayClose / sqqqEntryPrice) : sqqqEquity
contOpenEquity = not s2_sqqqContinuous ? na : contState == 1 and inPosition ? contEquity * (1 + tqqqDisplayProfit / 100) : contState == 2 and not na(contSqqqEntryPrice) and contSqqqEntryPrice != 0 and not na(sqqqDisplayClose) ? contEquity * (sqqqDisplayClose / contSqqqEntryPrice) : contEquity
if s2_sqqqContinuous and inReport and not na(contOpenEquity)
    f_contTrackDD(contOpenEquity, contPerfF, contPerfI, barDate, bar_index)

// ============================================================
// VISUAL OUTPUT — exact same pattern as VIX_TQQQ_Strategy.pine:
//   plotshape (triangle) + label.new(bar_index, low/high, style=label.style_none, yloc)
// ============================================================

// Regime tint first, then shapes — clearer stacking on the overlay pane.
regimeBgColor = showRegimeBackgroundEff ? (isR0Regime ? color.new(#FFFFFF, 88) : isR1Regime ? color.new(#00FF00, 88) : isR2Regime ? color.new(#FF6600, 88) : isR3Regime ? color.new(#00FFFF, 88) : isR4Regime ? color.new(#FF00FF, 88) : na) : na
bgcolor(regimeBgColor, title="Regime BG")

// force_overlay=true pins each shape to the chart's main overlay so it cannot be routed to the indicator's own draggable scale. location.belowbar/abovebar attaches the shape directly to the bar.
// Automatic triangles are gated off when a manual override fires on the same bar so only the yellow manual triangle shows.
// BLOCKER MARKER SYSTEM — documented in docs/TQQQ-7_LOG.md.
// X = buy blocked. Color = blocker family.
// Blue X = Daily SMA Bear / Daily SMA Entry no-buy blockers from sections 15 / 15.3 / 15.4.
// Orange X = RC wait blockers from S6 R0.7 / S6 R1.7 / S6 R3.7.
// Purple X = ATR / volatility blocker from S6 R1.3.
// Yellow X = RC Stoch Lifecycle buy block from S6 R0.8 / R1.8 / R2.8 / R3.8 / R4.8.
// Circle = sell-suppression / hold-longer markers.
buyAtOrBelowLastSell = na(lastSellPrice) or close <= lastSellPrice
// #12: trade markers only draw inside the reporting window (inReport). The engine still runs on all bars underneath; this just keeps the chart looking like the selected window.
plotshape(inReport and buySignal and not rcBuySignal and not manualBuyExec and buyAtOrBelowLastSell, "Buy Signal", shape.triangleup, location.belowbar, color=#006400, size=size.normal, force_overlay=true)
plotshape(inReport and buySignal and not rcBuySignal and not manualBuyExec and not buyAtOrBelowLastSell, "Buy Signal higher than prior sell", shape.triangleup, location.belowbar, color=color.orange, size=size.normal, force_overlay=true)
plotchar(inReport and buySignal and rcBuySignal and not manualBuyExec and buyAtOrBelowLastSell, "RC Buy at/below prior sell", "△", location.belowbar, color=color.green, size=size.normal, force_overlay=true)
plotchar(inReport and buySignal and rcBuySignal and not manualBuyExec and not buyAtOrBelowLastSell, "RC Buy", "△", location.belowbar, color=color.orange, size=size.normal, force_overlay=true)
dailySmaBlockAny = dailySmaBearBuyBlocked or dailySmaBear2BuyBlocked or dailySmaBear3BuyBlocked or dailySmaBear4BuyBlocked or dailySmaBear5BuyBlocked or dailySmaBear6BuyBlocked or dailySmaBear7BuyBlocked or dailySmaEntryNoBuyBlocked or dailySmaEntryR2NoBuyBlocked or dailySmaEntryR4NoBuyBlocked or dailySmaEntry50100R4Blocked or dailySmaEntry50100R3Blocked or dailySmaEntry50200R2Blocked
rcWaitBlockAny = rcPtWaitR3Blocked or rcSlTslWaitBlocked or rcBmWaitR0Blocked or rcSLeadWaitR12Blocked
plotshape(inReport and r1AtrRiskMarkerEff and r1AtrRiskBlocked, "R1 ATR Block", shape.xcross, location.belowbar, color=color.purple, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBlockAny, "Daily SMA / No-Buy Block", shape.xcross, location.belowbar, color=color.blue, size=size.small, force_overlay=true)
plotshape(inReport and (rclBlockMarkerEff or rcl0BlockMarkerEff or rcl1BlockMarkerEff or rcl2BlockMarkerEff or rcl3BlockMarkerEff) and rclBuyBlocked, "RC stoch lifecycle buy block", shape.xcross, location.belowbar, color=color.yellow, size=size.small, force_overlay=true)
plotshape(inReport and rcWaitBlockAny, "RC Wait Block", shape.xcross, location.belowbar, color=color.orange, size=size.small, force_overlay=true)
dailySmaBullAnySuppressed = dailySmaBullSellSuppressed or dailySmaBull2SellSuppressed or dailySmaBull3SellSuppressed or dailySmaBull4SellSuppressed
dailySmaBullSuppressedColor = dailySmaBull4SellSuppressed ? color.aqua : dailySmaBull3SellSuppressed ? color.olive : dailySmaBull2SellSuppressed ? color.green : color.lime
plotshape(inReport and dailySmaBullMarkerEff and dailySmaBullAnySuppressed, "Daily SMA Bull Sell Suppressed", shape.circle, location.abovebar, color=dailySmaBullSuppressedColor, size=size.tiny, force_overlay=true)
plotshape(inReport and s2_gbfR4Enable and isGapBounceExit, "Gap bounce fail", shape.diamond, location.abovebar, color=color.orange, size=size.small, force_overlay=true)
plotshape(inReport and s2_gbfR2Enable and isGapBounce2Exit, "Gap bounce fail 2", shape.diamond, location.abovebar, color=color.fuchsia, size=size.small, force_overlay=true)
plotshape(inReport and rcslMarkerEff and isRcStochLeadExit, "RC stoch lead", shape.circle, location.abovebar, color=color.lime, size=size.tiny, force_overlay=true)
plotshape(inReport and rcbdMarkerEff and isRcBreakdownExit, "RC breakdown", shape.circle, location.abovebar, color=color.yellow, size=size.tiny, force_overlay=true)
plotshape(inReport and rclExitMarkerEff and isRclLifecycleExitR4, "RC stoch lifecycle R4 sell", shape.circle, location.abovebar, color=color.fuchsia, size=size.tiny, force_overlay=true)
plotshape(inReport and rcl0ExitMarkerEff and isRclLifecycleExitR0, "RC stoch lifecycle R0 sell", shape.circle, location.abovebar, color=color.fuchsia, size=size.tiny, force_overlay=true)
plotshape(inReport and rcl1ExitMarkerEff and isRclLifecycleExitR1, "RC stoch lifecycle R1 sell", shape.circle, location.abovebar, color=color.fuchsia, size=size.tiny, force_overlay=true)
plotshape(inReport and rcl2ExitMarkerEff and isRclLifecycleExitR2, "RC stoch lifecycle R2 sell", shape.circle, location.abovebar, color=color.fuchsia, size=size.tiny, force_overlay=true)
plotshape(inReport and rcl3ExitMarkerEff and isRclLifecycleExitR3, "RC stoch lifecycle R3 sell", shape.circle, location.abovebar, color=color.fuchsia, size=size.tiny, force_overlay=true)

// Red triangle DOWN — positive sell; Blue triangle DOWN — negative sell
plotshape(inReport and sellSignal and sellDispPct >= 0 and not isSoftTrailExit and not isManualExit, "Sell +", shape.triangledown, location.abovebar, color=color.red, size=size.normal, force_overlay=true)
plotshape(inReport and sellSignal and sellDispPct < 0 and not isSoftTrailExit and not isManualExit, "Sell -", shape.triangledown, location.abovebar, color=color.blue, size=size.normal, force_overlay=true)
plotshape(inReport and isSoftTrailExit, "Sell TSL", shape.triangledown, location.abovebar, color=sellDispPct < 0 ? color.blue : #CC5500, size=size.normal, force_overlay=true)
plotshape(inReport and dailySmaBearMarkerEff and sellSignal and dailySmaBearForceSellSignal1, "Daily SMA Bear Sell", shape.diamond, location.abovebar, color=color.yellow, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear2MarkerEff and sellSignal and dailySmaBearForceSellSignal2, "Daily SMA Bear 2 Sell", shape.diamond, location.abovebar, color=color.teal, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear3MarkerEff and sellSignal and dailySmaBearForceSellSignal3, "Daily SMA Bear 3 Sell", shape.diamond, location.abovebar, color=color.navy, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear4MarkerEff and sellSignal and dailySmaBearForceSellSignal4, "Daily SMA Bear 4 Sell", shape.diamond, location.abovebar, color=color.aqua, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear5MarkerEff and sellSignal and dailySmaBearForceSellSignal5, "Daily SMA Bear 5 Sell", shape.diamond, location.abovebar, color=color.silver, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear6MarkerEff and sellSignal and dailySmaBearForceSellSignal6, "Daily SMA Bear 6 Sell", shape.diamond, location.abovebar, color=color.gray, size=size.small, force_overlay=true)
plotshape(inReport and dailySmaBear7MarkerEff and sellSignal and dailySmaBearForceSellSignal7, "Daily SMA Bear 7 Sell", shape.diamond, location.abovebar, color=color.maroon, size=size.small, force_overlay=true)

// Manual Overrides — yellow triangles, distinct from every automatic marker; grey 'M skip' attempt label drawn on wrong-state bars.
plotshape(inReport and manualBuyExec,  "Manual Buy",  shape.triangleup,   location.belowbar, color=color.yellow, size=size.normal, force_overlay=true)
plotshape(inReport and manualSellExec, "Manual Sell", shape.triangledown, location.abovebar, color=color.yellow, size=size.normal, force_overlay=true)

// Regime change digit — anchored to the bottom of the pane (original behavior), one digit per regime change.
regimeChanged = curRegimeInt != curRegimeInt[1]
plotchar(regimeChanged and (isR0Regime), "→R0", "0", location.bottom, color=#FFFFFF, size=size.small, force_overlay=true)
plotchar(regimeChanged and (isR1Regime), "→R1", "1", location.bottom, color=#00FF00, size=size.small, force_overlay=true)
plotchar(regimeChanged and (isR2Regime), "→R2", "2", location.bottom, color=#FF6600, size=size.small, force_overlay=true)
plotchar(regimeChanged and (isR3Regime), "→R3", "3", location.bottom, color=#00FFFF, size=size.small, force_overlay=true)
plotchar(regimeChanged and (isR4Regime), "→R4", "4", location.bottom, color=#FF00FF, size=size.small, force_overlay=true)

// Buy price text. Manual: yellow callout at the bar. Automatic: yloc.belowbar + blank lines — hollow △ needs 4, solid △ needs 2 (plotchar vs plotshape height differs).
if buySignal and showLabelsEff and inReport
    buyPrefix    = manualBuyExec ? "M " : ""
    buyBoxColor  = manualBuyExec ? color.yellow            : color.new(color.green, 100)
    buyTextColor = manualBuyExec ? color.black             : color.white
    buyStyle     = manualBuyExec ? label.style_label_up    : label.style_none
    buyReason    = manualBuyExec ? "M" : entrySignalType
    buyVsSellPct = not na(lastSellPrice) and lastSellPrice != 0 ? (close - lastSellPrice) / lastSellPrice * 100.0 : na
    buyVsSellTxt = na(buyVsSellPct) ? "" : " " + fmtPctStickerOneDecimal(buyVsSellPct) + "%"
    buyTextLead  = manualBuyExec ? "" : rcBuySignal ? "\n\n\n\n" : "\n\n"
    buyText      = buyTextLead + buyPrefix + str.tostring(close, "#.##") + "\n" + buyReason + buyVsSellTxt
    label.new(bar_index, low, buyText, color=buyBoxColor, textcolor=buyTextColor, style=buyStyle, size=size.normal, yloc=yloc.belowbar, force_overlay=true)

// Sell price + exit type text. Manual: yellow callout at the bar. Automatic: yloc.abovebar + trailing blank lines — text sits above solid △ (2 lines); hollow △ slot reserved at 4 if added later.
if sellSignal and showLabelsEff and inReport
    exitType      = exitReason + " "
    sellTextCore  = str.tostring(close, "#.##") + "\n" + exitType + fmtPctStickerOneDecimal(sellDispPct) + "%"
    sellTextTrail = isManualExit ? "" : "\n\n"
    sellText      = sellTextCore + sellTextTrail
    sellBoxColor  = isManualExit ? color.yellow           : color.new(color.red, 100)
    sellTextColor = isManualExit ? color.black            : color.white
    sellStyle     = isManualExit ? label.style_label_down : label.style_none
    label.new(bar_index, high, sellText, color=sellBoxColor, textcolor=sellTextColor, style=sellStyle, size=size.normal, yloc=yloc.abovebar, force_overlay=true)

// Manual Overrides — wrong-state attempts (Buy while long / Sell while flat). Solid white callout box with a pointer at the bar and black text so the skip is impossible to miss.
if (manualBuySkipped or manualSellSkipped) and showLabelsEff and inReport
    skipText  = manualBuySkipped ? "M skip\n(in pos)" : "M skip\n(flat)"
    skipYloc  = manualBuySkipped ? yloc.belowbar : yloc.abovebar
    skipRef   = manualBuySkipped ? low : high
    skipStyle = manualBuySkipped ? label.style_label_up : label.style_label_down
    label.new(bar_index, skipRef, skipText, color=color.white, textcolor=color.black, style=skipStyle, size=size.normal, yloc=skipYloc, force_overlay=true)

// ============================================================
// INFO TABLE
// ============================================================
bhPrice = not na(endPrice) ? endPrice : close
buyHoldPL = not na(firstBuyPrice) ? (bhPrice - firstBuyPrice) / firstBuyPrice * 100 : 0.0
bhEndValue = 100 * (1 + buyHoldPL / 100)

openMultiplier = inPosition ? (1 + tqqqDisplayProfit / 100) : 1.0
stratValue = compoundedValue * openMultiplier

// Panel 4 drawdown uses close-based equity while holding, matching Strategy 6's human near-close execution.
if inReport
    barHiEquity = inPosition and not na(barPnLHi) ? compoundedValue * (1 + barPnLHi / 100) : stratValue
    barLoEquity = inPosition and not na(barPnLLo) ? compoundedValue * (1 + barPnLLo / 100) : stratValue
    if barHiEquity > peakEquity
        if ddActive
            if ddEpisodeHasMax
                maxDDRecoveryBars := bar_index - ddStartBar
                maxDDRecoveryDays := ddTradingDays
                maxDDRecovered := true
            ddActive := false
            ddStartBar := na
            ddLastDate := na
            ddTradingDays := 0
            ddEpisodeHasMax := false
        peakEquity := barHiEquity
    ddCandidate = peakEquity > 0 ? (peakEquity - barLoEquity) / peakEquity * 100.0 : 0.0
    if ddCandidate > 0
        if not ddActive
            ddActive := true
            ddStartBar := bar_index
            ddLastDate := barDate
            ddTradingDays := 1
            ddEpisodeHasMax := false
        else if barDate != ddLastDate
            ddTradingDays := ddTradingDays + 1
            ddLastDate := barDate
    if ddCandidate > maxDDPct
        maxDDPct := ddCandidate
        ddEpisodeHasMax := true
        maxDDRecoveryBars := na
        maxDDRecoveryDays := na
        maxDDRecovered := false
stratPL = stratValue - 100.0
winRate = totalTrades > 0 ? winTrades / totalTrades * 100 : 0.0

startDateStr = str.tostring(dayofmonth(perfStartDate), "00") + "-" + str.tostring(month(perfStartDate), "00") + "-" + str.tostring(year(perfStartDate))
endDateStr = str.tostring(dayofmonth(perfEndDate), "00") + "-" + str.tostring(month(perfEndDate), "00") + "-" + str.tostring(year(perfEndDate))
regimeStr = isR0Regime ? "0: ULTRA CALM" : isR1Regime ? "1: RISING" : isR2Regime ? "2: FALLING" : isR3Regime ? "3: MID RISE" : isR4Regime ? "4: MID FALL" : "UNKNOWN"
regimeColor = isR0Regime ? color.white : isR1Regime ? color.green : isR2Regime ? color.orange : isR3Regime ? color.lime : color.purple

var table infoTable = na
var int infoTableRowCount = 0
var table regimeTable = na
if barstate.islast
    infoRowsNeed = (showInfoPanel1 ? 8 : 0) + (showInfoPanel3 ? 2 : 0) + (showInfoPanel4 ? 20 : 0)
    wantInfoTable = showInfoTableEff and infoRowsNeed > 0
    if wantInfoTable
        if na(infoTable) or infoTableRowCount != infoRowsNeed
            if not na(infoTable)
                table.delete(infoTable)
            infoTable := table.new(position.top_right, 7, infoRowsNeed, bgcolor=color.new(color.black, 70))
            infoTableRowCount := infoRowsNeed
        displaySma = isR0Regime ? vixSmaMaster : isR1Regime ? vixSmaMaster : isR2Regime ? vixSmaMaster : isR3Regime ? vixSmaMaster : vixSmaMaster
        displayAboveSma = isR0Regime ? vixAbove : isR1Regime ? vixAbove : isR2Regime ? vixAbove : isR3Regime ? vixAbove : vixAbove
        displayBuyPct = isR1Regime ? r1BuyPctEff : isR2Regime ? r2BuyPctEff : isR3Regime ? r3BuyPctEff : isR4Regime ? r4BuyPctEff : 999.0
        tNorm = size.normal
        tSmall = size.small
        int r = 0
        if showInfoPanel1
            table.cell(infoTable, 0, r, "Strategy 6", text_color=color.yellow, text_size=tNorm)
            table.cell(infoTable, 1, r, "", text_color=color.gray, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, useStartDate ? startDateStr : "All data", text_color=color.white, text_size=tNorm)
            table.cell(infoTable, 1, r, useStartDate ? endDateStr : "-> now", text_color=color.white, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, not na(firstBuyPrice) ? "$" + str.tostring(firstBuyPrice, "#.##") : "", text_color=color.gray, text_size=tNorm)
            table.cell(infoTable, 1, r, not na(endPrice) ? "$" + str.tostring(endPrice, "#.##") : "", text_color=color.gray, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "Trades", text_color=color.white, text_size=tNorm)
            sqqqWinRate = sqqqTrades > 0 ? sqqqWins / sqqqTrades * 100.0 : 0.0
            tradesText = "T " + str.tostring(totalTrades) + "/" + str.tostring(winRate, "#") + "%"
            tradesText := sqqqSimEnableEff ? tradesText + " | S " + str.tostring(sqqqTrades) + "/" + str.tostring(sqqqWinRate, "#") + "%" : tradesText
            table.cell(infoTable, 1, r, tradesText, text_color=color.white, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "B&H", text_color=color.white, text_size=tNorm)
            table.cell(infoTable, 1, r, fmtPctStickerOneDecimal(buyHoldPL) + "% ($" + str.tostring(bhEndValue, "#.##") + ")", text_color=buyHoldPL >= 0 ? color.green : color.red, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "Strategy", text_color=color.yellow, text_size=tNorm)
            table.cell(infoTable, 1, r, fmtPctStickerOneDecimal(stratPL) + "% ($" + fmtNumberOneDecimalWithCommas(stratValue) + ")", text_color=stratPL >= 0 ? color.green : color.red, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "SQQQ Sim", text_color=color.yellow, text_size=tNorm)
            table.cell(infoTable, 1, r, sqqqSimEnableEff ? fmtPctStickerOneDecimal(sqqqOpenEquity - 100.0) + "% ($" + fmtNumberOneDecimalWithCommas(sqqqOpenEquity) + ") " + str.tostring(sqqqTrades) + "t" : "OFF", text_color=sqqqSimEnableEff ? sqqqOpenEquity >= 100.0 ? color.green : color.red : color.gray, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "Cont T/S", text_color=color.yellow, text_size=tNorm)
            table.cell(infoTable, 1, r, s2_sqqqContinuous ? fmtPctStickerOneDecimal(contOpenEquity - 100.0) + "% | $" + fmtNumberOneDecimalWithCommas(contOpenEquity) : "OFF", text_color=s2_sqqqContinuous ? contOpenEquity >= 100.0 ? color.green : color.red : color.gray, text_size=tNorm)
            r += 1
        if showInfoPanel3
            table.cell(infoTable, 0, r, "Position", text_color=color.white, text_size=tNorm)
            posTag = entryRegime == 10 ? " [0]" : " [" + str.tostring(entryRegime) + "]"
            posText = inPosition ? ("YES @ " + str.tostring(entryPrice, "#.##") + posTag) : "NO"
            posColor = inPosition ? (entryRegime == 10 ? color.white : entryRegime == 1 ? color.green : entryRegime == 2 ? color.orange : entryRegime == 3 ? color.lime : color.purple) : color.gray
            table.cell(infoTable, 1, r, posText, text_color=posColor, text_size=tNorm)
            r += 1
            table.cell(infoTable, 0, r, "Profit", text_color=color.white, text_size=tNorm)
            table.cell(infoTable, 1, r, inPosition ? fmtPctStickerOneDecimal(currentProfit) + "%" : "-", text_color=currentProfit >= 0 ? color.green : color.red, text_size=tNorm)
            r += 1
        if showInfoPanel4
            useContP4 = panel4PerfSource == "Continuous T/S" and s2_sqqqContinuous
            p4Trades = useContP4 ? array.get(contPerfI, 0) : totalTrades
            winCount = useContP4 ? array.get(contPerfI, 1) : totalTrades - loseCount
            p4LoseCount = useContP4 ? array.get(contPerfI, 2) : loseCount
            avgWin = winCount > 0 ? (useContP4 ? array.get(contPerfF, 4) : sumWinPct) / winCount : 0.0
            avgLoss = p4LoseCount > 0 ? (useContP4 ? array.get(contPerfF, 5) : sumLossPct) / p4LoseCount : 0.0
            profitFactor = (useContP4 ? array.get(contPerfF, 5) : sumLossPct) < 0 ? (useContP4 ? array.get(contPerfF, 4) : sumWinPct) / (-(useContP4 ? array.get(contPerfF, 5) : sumLossPct)) : na
            meanRet = p4Trades > 0 ? (useContP4 ? array.get(contPerfF, 6) : sumRet) / p4Trades : 0.0
            varRet = p4Trades > 1 ? ((useContP4 ? array.get(contPerfF, 7) : sumRetSq) / p4Trades) - meanRet * meanRet : 0.0
            stdRet = varRet > 0 ? math.sqrt(varRet) : 0.0
            sharpeTrade = stdRet > 0 ? meanRet / stdRet : na
            pfStr = na(profitFactor) ? "-" : fmtF(profitFactor)
            pfColor = na(profitFactor) ? color.gray : (profitFactor >= 1.5 ? color.green : profitFactor >= 1.0 ? color.yellow : color.red)
            shStr = na(sharpeTrade) ? "-" : fmtF(sharpeTrade)
            shColor = na(sharpeTrade) ? color.gray : (sharpeTrade >= 0.2 ? color.green : sharpeTrade >= 0.0 ? color.yellow : color.red)
            bestStr = na(useContP4 ? array.get(contPerfF, 2) : bestTradePct) ? "-" : fmtPctStickerOneDecimal(useContP4 ? array.get(contPerfF, 2) : bestTradePct) + "%"
            worstStr = na(useContP4 ? array.get(contPerfF, 3) : worstTradePct) ? "-" : fmtPctStickerOneDecimal(useContP4 ? array.get(contPerfF, 3) : worstTradePct) + "%"
            table.cell(infoTable, 0, r, useContP4 ? "Performance C T/S" : "Performance TQQQ", text_color=color.yellow, text_size=tNorm)
            table.cell(infoTable, 1, r, "", text_color=color.gray, text_size=tNorm)
            r += 1
            r := f_p4Row(infoTable, r, "Max Drawdown", fmtPctOneDec(-(useContP4 ? array.get(contPerfF, 1) : maxDDPct)) + "%", color.red, tNorm)
            maxDDRecoveryStr = useContP4 ? (array.get(contPerfI, 29) == 1 ? str.tostring(array.get(contPerfI, 25)) + " bars / " + str.tostring(array.get(contPerfI, 26)) + " days" : array.get(contPerfI, 27) == 1 ? "open " + str.tostring(bar_index - array.get(contPerfI, 24)) + " bars / " + str.tostring(array.get(contPerfI, 28)) + " days" : "-") : maxDDRecovered ? str.tostring(maxDDRecoveryBars) + " bars / " + str.tostring(maxDDRecoveryDays) + " days" : ddEpisodeHasMax ? "open " + str.tostring(bar_index - ddStartBar) + " bars / " + str.tostring(ddTradingDays) + " days" : "-"
            r := f_p4Row(infoTable, r, "Max DD Recovery", maxDDRecoveryStr, (useContP4 ? array.get(contPerfI, 29) == 1 : maxDDRecovered) ? color.aqua : color.orange, tNorm)
            r := f_p4Row(infoTable, r, "Profit Factor", pfStr, pfColor, tNorm)
            r := f_p4Row(infoTable, r, "Sharpe (trade)", shStr, shColor, tNorm)
            r := f_p4Row(infoTable, r, "Best Trade", bestStr, na(useContP4 ? array.get(contPerfF, 2) : bestTradePct) ? color.gray : (useContP4 ? array.get(contPerfF, 2) : bestTradePct) >= 0 ? color.green : color.red, tNorm)
            r := f_p4Row(infoTable, r, "Worst Trade", worstStr, na(useContP4 ? array.get(contPerfF, 3) : worstTradePct) ? color.gray : (useContP4 ? array.get(contPerfF, 3) : worstTradePct) >= 0 ? color.green : color.red, tNorm)
            r := f_p4Row(infoTable, r, "Avg Win", winCount > 0 ? fmtPctStickerOneDecimal(avgWin) + "%" : "-", winCount > 0 ? color.green : color.gray, tNorm)
            r := f_p4Row(infoTable, r, "Avg Loss", p4LoseCount > 0 ? fmtPctStickerOneDecimal(avgLoss) + "%" : "-", p4LoseCount > 0 ? color.red : color.gray, tNorm)
            r := f_p4Row(infoTable, r, "Max Win Streak", str.tostring(useContP4 ? array.get(contPerfI, 6) : maxWinStreak), color.green, tNorm)
            r := f_p4Row(infoTable, r, "Max Lose Streak", str.tostring(useContP4 ? array.get(contPerfI, 4) : maxLoseStreak), color.red, tNorm)
            r := f_p4BucketHeader(infoTable, r, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 0-2%", useContP4 ? array.get(contPerfI, 7) : loss0to2Count, useContP4 ? array.get(contPerfI, 15) : win0to2Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 2-5%", useContP4 ? array.get(contPerfI, 8) : loss2to5Count, useContP4 ? array.get(contPerfI, 16) : win2to5Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 5-10%", useContP4 ? array.get(contPerfI, 9) : loss5to10Count, useContP4 ? array.get(contPerfI, 17) : win5to10Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 10-15%", useContP4 ? array.get(contPerfI, 10) : loss10to15Count, useContP4 ? array.get(contPerfI, 18) : win10to15Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 15-20%", useContP4 ? array.get(contPerfI, 11) : loss15to20Count, useContP4 ? array.get(contPerfI, 19) : win15to20Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 20-25%", useContP4 ? array.get(contPerfI, 12) : loss20to25Count, useContP4 ? array.get(contPerfI, 20) : win20to25Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win 25-30%", useContP4 ? array.get(contPerfI, 13) : loss25to30Count, useContP4 ? array.get(contPerfI, 21) : win25to30Count, tNorm)
            r := f_p4BucketRow(infoTable, r, "Loss/Win >30%", useContP4 ? array.get(contPerfI, 14) : lossOver30Count, useContP4 ? array.get(contPerfI, 22) : winOver30Count, tNorm)
    else
        if not na(infoTable)
            table.delete(infoTable)
            infoTable := na
            infoTableRowCount := 0
    if showInfoTableEff and showInfoPanel2
        if na(regimeTable)
            regimeTable := table.new(position.bottom_right, 5, 7, bgcolor=color.new(color.black, 70), frame_color=color.gray, frame_width=1)
        totalRegimeBars = barsR0 + barsR1 + barsR2 + barsR3 + barsR4
        r0TimePct = totalRegimeBars > 0 ? barsR0 / totalRegimeBars * 100 : 0.0
        r1TimePct = totalRegimeBars > 0 ? barsR1 / totalRegimeBars * 100 : 0.0
        r2TimePct = totalRegimeBars > 0 ? barsR2 / totalRegimeBars * 100 : 0.0
        r3TimePct = totalRegimeBars > 0 ? barsR3 / totalRegimeBars * 100 : 0.0
        r4TimePct = totalRegimeBars > 0 ? barsR4 / totalRegimeBars * 100 : 0.0
        r0WR = tradesR0 > 0 ? winsR0 / tradesR0 * 100 : 0.0
        r1WR = tradesR1 > 0 ? winsR1 / tradesR1 * 100 : 0.0
        r2WR = tradesR2 > 0 ? winsR2 / tradesR2 * 100 : 0.0
        r3WR = tradesR3 > 0 ? winsR3 / tradesR3 * 100 : 0.0
        r4WR = tradesR4 > 0 ? winsR4 / tradesR4 * 100 : 0.0
        r0PL = compR0 - 100.0
        r1PL = compR1 - 100.0
        r2PL = compR2 - 100.0
        r3PL = compR3 - 100.0
        r4PL = compR4 - 100.0
        table.cell(regimeTable, 0, 0, "Regime Performance", text_color=color.yellow, text_size=size.large)
        table.merge_cells(regimeTable, 0, 0, 4, 0)
        table.cell(regimeTable, 0, 1, "Regime", text_color=color.aqua, text_size=size.normal)
        table.cell(regimeTable, 1, 1, "%Time", text_color=color.aqua, text_size=size.normal)
        table.cell(regimeTable, 2, 1, "Trades", text_color=color.aqua, text_size=size.normal)
        table.cell(regimeTable, 3, 1, "WinRate", text_color=color.aqua, text_size=size.normal)
        table.cell(regimeTable, 4, 1, "P&L", text_color=color.aqua, text_size=size.normal)
        table.cell(regimeTable, 0, 2, "R0", text_color=color.white, text_size=size.normal)
        table.cell(regimeTable, 1, 2, fmtPctOneDec(r0TimePct) + "%", text_color=color.white, text_size=size.normal)
        table.cell(regimeTable, 2, 2, str.tostring(tradesR0), text_color=color.white, text_size=size.normal)
        table.cell(regimeTable, 3, 2, fmtPctOneDec(r0WR) + "%", text_color=color.white, text_size=size.normal)
        table.cell(regimeTable, 4, 2, (r0PL >= 0 ? "+" : "") + fmtPctOneDec(r0PL) + "%", text_color=r0PL >= 0 ? color.white : color.red, text_size=size.normal)
        table.cell(regimeTable, 0, 3, "R1", text_color=color.green, text_size=size.normal)
        table.cell(regimeTable, 1, 3, fmtPctOneDec(r1TimePct) + "%", text_color=color.green, text_size=size.normal)
        table.cell(regimeTable, 2, 3, str.tostring(tradesR1), text_color=color.green, text_size=size.normal)
        table.cell(regimeTable, 3, 3, fmtPctOneDec(r1WR) + "%", text_color=color.green, text_size=size.normal)
        table.cell(regimeTable, 4, 3, (r1PL >= 0 ? "+" : "") + fmtPctOneDec(r1PL) + "%", text_color=r1PL >= 0 ? color.green : color.red, text_size=size.normal)
        table.cell(regimeTable, 0, 4, "R2", text_color=color.orange, text_size=size.normal)
        table.cell(regimeTable, 1, 4, fmtPctOneDec(r2TimePct) + "%", text_color=color.orange, text_size=size.normal)
        table.cell(regimeTable, 2, 4, str.tostring(tradesR2), text_color=color.orange, text_size=size.normal)
        table.cell(regimeTable, 3, 4, fmtPctOneDec(r2WR) + "%", text_color=color.orange, text_size=size.normal)
        table.cell(regimeTable, 4, 4, (r2PL >= 0 ? "+" : "") + fmtPctOneDec(r2PL) + "%", text_color=r2PL >= 0 ? color.orange : color.red, text_size=size.normal)
        table.cell(regimeTable, 0, 5, "R3", text_color=color.lime, text_size=size.normal)
        table.cell(regimeTable, 1, 5, fmtPctOneDec(r3TimePct) + "%", text_color=color.lime, text_size=size.normal)
        table.cell(regimeTable, 2, 5, str.tostring(tradesR3), text_color=color.lime, text_size=size.normal)
        table.cell(regimeTable, 3, 5, fmtPctOneDec(r3WR) + "%", text_color=color.lime, text_size=size.normal)
        table.cell(regimeTable, 4, 5, (r3PL >= 0 ? "+" : "") + fmtPctOneDec(r3PL) + "%", text_color=r3PL >= 0 ? color.lime : color.red, text_size=size.normal)
        table.cell(regimeTable, 0, 6, "R4", text_color=color.purple, text_size=size.normal)
        table.cell(regimeTable, 1, 6, fmtPctOneDec(r4TimePct) + "%", text_color=color.purple, text_size=size.normal)
        table.cell(regimeTable, 2, 6, str.tostring(tradesR4), text_color=color.purple, text_size=size.normal)
        table.cell(regimeTable, 3, 6, fmtPctOneDec(r4WR) + "%", text_color=color.purple, text_size=size.normal)
        table.cell(regimeTable, 4, 6, (r4PL >= 0 ? "+" : "") + fmtPctOneDec(r4PL) + "%", text_color=r4PL >= 0 ? color.purple : color.red, text_size=size.normal)
    else if not na(regimeTable)
        table.delete(regimeTable)
        regimeTable := na

// ============================================================
// SQQQ TRIGGER / REGIME RESEARCH TABLE
// ============================================================
var table sqqqStatsTable = na
if barstate.islast
    if s2_sqqqShowStats
        if na(sqqqStatsTable)
            sqqqStatsTable := table.new(position.middle_left, 14, 18, bgcolor=color.new(color.black, 72), frame_color=color.gray, frame_width=1)
        table.cell(sqqqStatsTable, 0, 0, "SQQQ Trigger Research", text_color=color.yellow, text_size=size.normal)
        table.merge_cells(sqqqStatsTable, 0, 0, 13, 0)
        table.cell(sqqqStatsTable, 0, 1, "Trigger", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 1, 1, "ON", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 2, 1, "T", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 3, 1, "Win%", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 4, 1, "MaxW", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 5, 1, "MaxL", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 6, 1, "Avg", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 7, 1, "MED", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 8, 1, "Comp", text_color=color.aqua, text_size=size.normal)
        table.cell(sqqqStatsTable, 9, 1, "R0", text_color=color.white, text_size=size.normal)
        table.cell(sqqqStatsTable, 10, 1, "R1", text_color=color.green, text_size=size.normal)
        table.cell(sqqqStatsTable, 11, 1, "R2", text_color=color.orange, text_size=size.normal)
        table.cell(sqqqStatsTable, 12, 1, "R3", text_color=color.lime, text_size=size.normal)
        table.cell(sqqqStatsTable, 13, 1, "R4", text_color=color.purple, text_size=size.normal)
        for rankIdx = 0 to 15
            typeIdx = f_sqqqRankType(rankIdx)
            tr = 0
            wn = 0
            sm = 0.0
            cp = 100.0
            float bw = na
            float wl = na
            r0Ret = 0.0
            r1Ret = 0.0
            r2Ret = 0.0
            r3Ret = 0.0
            r4Ret = 0.0
            int n0 = 0
            int n1 = 0
            int n2 = 0
            int n3 = 0
            int n4 = 0
            int w0 = 0
            int w1 = 0
            int w2 = 0
            int w3 = 0
            int w4 = 0
            for regIdx = 0 to 4
                cell = f_scCellIndex(typeIdx, regIdx)
                cTr = array.get(sqqqStatsTrades, cell)
                cCp = array.get(sqqqStatsComp, cell)
                cWn = array.get(sqqqStatsWins, cell)
                tr += cTr
                wn += cWn
                sm += array.get(sqqqStatsSum, cell)
                cp := cp * (cCp / 100.0)
                cBest = array.get(sqqqStatsBest, cell)
                cWorst = array.get(sqqqStatsWorst, cell)
                bw := na(cBest) ? bw : na(bw) ? cBest : math.max(bw, cBest)
                wl := na(cWorst) ? wl : na(wl) ? cWorst : math.min(wl, cWorst)
                if regIdx == 0
                    r0Ret := cCp - 100.0
                    n0 := cTr
                    w0 := cWn
                else if regIdx == 1
                    r1Ret := cCp - 100.0
                    n1 := cTr
                    w1 := cWn
                else if regIdx == 2
                    r2Ret := cCp - 100.0
                    n2 := cTr
                    w2 := cWn
                else if regIdx == 3
                    r3Ret := cCp - 100.0
                    n3 := cTr
                    w3 := cWn
                else
                    r4Ret := cCp - 100.0
                    n4 := cTr
                    w4 := cWn
            rowIdx = rankIdx + 2
            wr = tr > 0 ? wn * 100.0 / tr : na
            avg = tr > 0 ? sm / tr : na
            med = f_sqqqMedianByType(sqqqStatsMedVals, typeIdx)
            compRet = cp - 100.0
            isOn = f_sqqqTriggerOn(typeIdx)
            table.cell(sqqqStatsTable, 0, rowIdx, f_sqqqRankLabel(rankIdx), text_color=tr > 0 ? color.white : color.gray, text_size=size.normal)
            table.cell(sqqqStatsTable, 1, rowIdx, isOn ? "ON" : "-", text_color=isOn ? color.lime : color.gray, text_size=size.normal)
            table.cell(sqqqStatsTable, 2, rowIdx, str.tostring(tr), text_color=tr > 0 ? color.white : color.gray, text_size=size.normal)
            table.cell(sqqqStatsTable, 3, rowIdx, na(wr) ? "-" : fmtPctOneDec(wr), text_color=na(wr) ? color.gray : wr >= 50 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 4, rowIdx, na(bw) ? "-" : fmtPctStickerOneDecimal(bw), text_color=na(bw) ? color.gray : color.green, text_size=size.normal)
            table.cell(sqqqStatsTable, 5, rowIdx, na(wl) ? "-" : fmtPctStickerOneDecimal(wl), text_color=na(wl) ? color.gray : wl >= 0 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 6, rowIdx, na(avg) ? "-" : fmtPctStickerOneDecimal(avg), text_color=na(avg) ? color.gray : avg >= 0 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 7, rowIdx, na(med) ? "-" : fmtPctStickerOneDecimal(med), text_color=na(med) ? color.gray : med >= 0 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 8, rowIdx, fmtPctStickerOneDecimal(compRet), text_color=compRet >= 0 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 9, rowIdx, n0 > 0 ? fmtPctStickerOneDecimal(r0Ret) + " (" + str.tostring(w0) + "/" + str.tostring(n0) + ")" : "-", text_color=n0 == 0 ? color.gray : r0Ret >= 0 ? color.white : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 10, rowIdx, n1 > 0 ? fmtPctStickerOneDecimal(r1Ret) + " (" + str.tostring(w1) + "/" + str.tostring(n1) + ")" : "-", text_color=n1 == 0 ? color.gray : r1Ret >= 0 ? color.green : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 11, rowIdx, n2 > 0 ? fmtPctStickerOneDecimal(r2Ret) + " (" + str.tostring(w2) + "/" + str.tostring(n2) + ")" : "-", text_color=n2 == 0 ? color.gray : r2Ret >= 0 ? color.orange : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 12, rowIdx, n3 > 0 ? fmtPctStickerOneDecimal(r3Ret) + " (" + str.tostring(w3) + "/" + str.tostring(n3) + ")" : "-", text_color=n3 == 0 ? color.gray : r3Ret >= 0 ? color.lime : color.red, text_size=size.normal)
            table.cell(sqqqStatsTable, 13, rowIdx, n4 > 0 ? fmtPctStickerOneDecimal(r4Ret) + " (" + str.tostring(w4) + "/" + str.tostring(n4) + ")" : "-", text_color=n4 == 0 ? color.gray : r4Ret >= 0 ? color.purple : color.red, text_size=size.normal)
    else
        if not na(sqqqStatsTable)
            table.delete(sqqqStatsTable)
            sqqqStatsTable := na

// ============================================================
// ALERTS
// Strategy 6: automatic alerts can be restricted to the final N minutes of the live candle.
// Historical markers/performance use close-based human execution. Manual override alerts are not gated.
// ============================================================
// #main-body budget: the whole alert block lives inside f_emitAlerts() (defined here, after all referenced globals exist) so its ~28 statements + long label strings do NOT count toward Pine's main-body size limit. Behaviour is identical — it is called unconditionally once per bar below, exactly as the top-level if-blocks were.
f_emitAlerts() =>
    if autoAlertTimingOk and r0BuySignal and buySignal
        r0BuyReason = "Regime 0 ULTRA CALM at " + str.tostring(close, "#.##") + " (VIX SMA " + str.tostring(vixSmaMaster, "#.##") + " < " + fmtPctOneDec(r0MaxSmaEff) + ")"
        alert(fmtAlertBuy(r0BuyReason), alert.freq_once_per_bar)
    if autoAlertTimingOk and fearBuySignal and buySignal
        regLabel = isR1Regime ? "Regime 1 RISING" : "Regime 2 FALLING"
        alertPct = isR1Regime ? vixAbove : vixAbove
        fearBuyReason = regLabel + " — VIX +" + fmtPctOneDec(alertPct) + "% above SMA at " + str.tostring(close, "#.##")
        alert(fmtAlertBuy(fearBuyReason), alert.freq_once_per_bar)
    if autoAlertTimingOk and midBuySignal and buySignal
        regLabel = isR3Regime ? "Regime 3 MID RISE" : "Regime 4 MID FALL"
        alertPct = isR3Regime ? vixAbove : vixAbove
        midBuyReason = regLabel + " — VIX +" + fmtPctOneDec(alertPct) + "% above SMA at " + str.tostring(close, "#.##")
        alert(fmtAlertBuy(midBuyReason), alert.freq_once_per_bar)
    if autoAlertTimingOk and rcBuySignal and buySignal
        rcFrom = prevConfirmedRegime == 1 ? "R1" : prevConfirmedRegime == 2 ? "R2" : prevConfirmedRegime == 3 ? "R3" : prevConfirmedRegime == 4 ? "R4" : "R0"
        rcTo = curRegimeInt == 1 ? "R1" : curRegimeInt == 2 ? "R2" : curRegimeInt == 3 ? "R3" : curRegimeInt == 4 ? "R4" : curRegimeInt == 10 ? "R0" : "?"
        rcBuyReason = "REGIME CHANGE " + rcFrom + "→" + rcTo + " at " + str.tostring(close, "#.##")
        alert(fmtAlertBuy(rcBuyReason), alert.freq_once_per_bar)
    // Manual BUY — separate alert so the user sees 'MANUAL BUY' in the alert log instead of nothing. Reminder: TradingView still requires creating an alert on the indicator (Add alert → condition 'Any alert() function call'); without that, every alert() below is silent.
    if manualBuyExec
        alert(fmtAlertBuy("MANUAL BUY at " + str.tostring(close, "#.##")), alert.freq_once_per_bar)
    if autoAlertTimingOk and sellSignal and not manualSellExec
        exitLabel = isBbMidSlopeExit ? "BB MID SLOPE" : isBbR1UpperExit ? "BOLLINGER UPPER (R1)" : isBbR2UpperExit ? "BOLLINGER UPPER (R2)" : isBbR3UpperExit ? "BOLLINGER UPPER (R3)" : isBbR4UpperExit ? "BOLLINGER UPPER (R4)" : isStopExit ? "STOP LOSS" : isProfitExit ? "PROFIT TARGET" : isR0FastExit ? "FAST VIX EXIT" : isRcStochLeadExit ? "RC STOCH LEAD" : isRcBreakdownExit ? "RC BREAKDOWN" : isRclLifecycleExit ? "RC STOCH LIFECYCLE" : isRcSellExit ? "REGIME CHANGE SELL" : isR0RegimeExit ? "REGIME CHANGE" : isEodExit ? "END OF DAY" : "VIX CALMED"
        sellReason = exitLabel + " at " + str.tostring(close, "#.##") + " (" + fmtPctStickerOneDecimal(sellDispPct) + "%)"
        alert(fmtAlertSell(sellReason), alert.freq_once_per_bar)
    if manualSellExec
        alert(fmtAlertSell("MANUAL SELL at " + str.tostring(close, "#.##")), alert.freq_once_per_bar)
f_emitAlerts()





Views: 0

Scroll to Top