# Strategy Backlog

Work top-down. Items higher in the list = higher ROI or blocking something else.
No numbers — re-order freely by dragging lines.

---

## Immediate — Blocking / High Risk of Wasted Work

**~~[GUARD] Params parity: propagate missing fields to all params files~~** ✅ DONE (2026-04-01)
All 20 active params files now have all 46 WEIGHT_COLS. Added 13 missing keys (10 RSID divergence signals + `i_w_oi_roc`, `i_w_usdt_d`, `i_w_basis`) to 19 files using BTC 4H ranges as defaults. Legacy `BINANCE-SOLUSD_4H.json` (hyphen) deleted.

**~~[GUARD] Pine file validation: check before optimization runs start~~** ✅ DONE (2026-04-01)
`tools/check_pine.py` — static analyzer (request.security count, plot/plotchar count, sentinel status). Note: undeclared identifier / syntax errors cannot be caught statically — only TradingView's compiler can catch those, which is why the sentinel + TV paste step exists. `auto_optimize_loop.py` now warns with 10s countdown if Pine was modified since last TV validation. `/checkPine` command created. Run `python3 tools/check_pine.py --mark-valid` after confirming Pine compiles in TV.

**~~[GUARD] Warn user before DB-invalidating implementation changes~~** ✅ DONE (2026-04-01)
`/planChange` command created in `.claude/commands/planChange.md`. Classifies proposed changes as DB-invalidating vs DB-safe, shows batching checklist, and prompts for confirmation before proceeding. Also: `auto_optimize_loop.py` now warns with 10s countdown when a winner file exists but the DB is empty for that combo (stale baseline risk).

---

## High Priority — Workflow & Observability

**~~[CMD] Create `.claude/commands/` folder with core slash commands~~** ✅ DONE (2026-04-01)
All 8 commands live in `.claude/commands/`: `/checkPine`, `/planChange`, `/reset`, `/generatePresets`, `/compareTrades`, `/lockParams`, `/sweepDashboard`, `/dailyUpdate` (on-demand, token cost TBD — check usage % in mobile app before/after first run).
Still to add: `/rescore`, `/commitAndPush`

**~~[DASH] Fix SHAP dashboard markdown table rendering~~** ✅ DONE (2026-04-01)
`results/shap_importance.md` renders as a blob of text in VSCode markdown preview. The table delimiter rows likely have wrong pipe/spacing. Locate and fix the table formatting. Quick bug fix.

**~~[OPT] Add SHAP auto-run to end of `auto_optimize_loop.py`~~** ✅ DONE (2026-04-01)
`auto_optimize_loop.py` calls `shap_feature_importance.py` at the end of every run (guarded by `--no_dashboard`). `results/shap_importance.md` is always current after each run.

**[GUARD] `auto_optimize_loop.py` startup: detect stale-winner / no-DB mismatch** _(already in High Priority section below — keep there)_

**~~[BUG] Regime filter: `i_regime_window=0` should disable min-score optimization~~** ✅ DONE (2026-04-01)
`optimize_strategy.py`: after building param lists, if `i_regime_window` is locked to `[0]`, `i_regime_entry_min_score` is fixed to `[-1000.0]`. Eliminates 13 wasted search dimensions per run.

**~~[DASH] SHAP: improve verdict labels for locked/missing signals~~** ✅ DONE (2026-04-01)
`shap_feature_importance.py`: `_load_param_lock_status()` reads all 20 params JSONs; verdict logic now shows **DISABLED** (locked=0 everywhere), **REPLACE** (disabled + weak), and **⚠️ MISSING FROM SOME PARAMS** suffix. STRONG/MODERATE/WEAK unchanged for active signals.

---

## High Priority — Strategy Quality

**~~[OPT] Fix GPU pre-filter baseline oscillating between iterations~~** ✅ DONE (2026-04-01)
`auto_optimize_loop.py`: `global_best_calmar` is now updated with `max(global_best_calmar, new_calmar)` so the GPU pre-filter floor only ever rises, never drops when a new winner has higher Composite but lower Calmar.

**~~[OPT] Guard `auto_optimize_loop` against stale-winner / no-DB mismatch~~** ✅ DONE (2026-04-01)
Implemented as part of the DB-invalidating change guard. 10s countdown warning at startup when winner file exists but DB has 0 rows for this combo.

**[STRATEGY] Phase 4 — Dual-weight system (bull/bear regime param sets)**
_[See other docs — this approach may have been argued against elsewhere with reasoning provided]_
Train two param sets per asset/TF: bull params (IS bars where regime_score > threshold) and bear/neutral params. At runtime, switch based on current regime score.
- Option A: pre-filter CSV rows by regime before calling optimize_strategy.py
- Store as `optimization_winner_<ASSET>_<TF>_bull.csv` / `_bear.csv`
- Update validate_strategy.py and oos_dashboard.py for regime-switching
- Pine: dual input groups + `var` regime state variable
_Spec: `docs/strategyActivation/spec_regime_and_dual_weights_roadmap.md` Phase 4_

**~~[SIGNAL] Derivatives signals batch (OI ROC, USDT.D, Spot-Perp Basis)~~** ✅ DONE (2026-03-28)
Added `i_w_oi_roc` (perp volume ROC as OI proxy), `i_w_usdt_d` (USDT dominance ROC, inverted), `i_w_basis` (spot-perp basis %). All live in Pine, Python, params JSONs, and BTC CSVs re-exported. request.security() budget: 39/40 (1 slot headroom). `qqq_close` removed to free budget (i_w_qqq_spy_ratio zeroed in Pine; weight still optimizable but signal=0).

**[SIGNAL] Next on-chain + sentiment signal batch (batch with one re-export)**
_OOS trade research (2026-04-02) identified three high-priority additions. Batch with D1 (sub-TF RSI) for a single Pine edit → TV re-export cycle._
- `i_w_fear_greed` — Crypto Fear & Greed Index (`ALTERNATIVE:BTC_FEAR_AND_GREED_INDEX`). Normalize: extreme greed (>80) → -1, extreme fear (<20) → +1 (contrarian). Directly captures ATH retail euphoria that the IS optimizer underweights via VIX/DXY. Budget: 37/40 → 38/40.
- `i_w_exchange_netflow` — BTC flowing to/from exchanges. Outflows = whales self-custodying (bullish); inflows = sell pressure. Available via CoinMetrics on TV. Direct on-chain fingerprint of whale distribution at ATH. Budget: 38/40 → 39/40.
- `i_w_rsi_4h` (on 12H/1D charts) / `i_w_rsi_12h` (on 1D chart) — sub-TF RSI via `request.security()`. Acts as lower-TF confirmation gate: if 4H RSI is overbought when 12H wants to enter, suppresses the entry. Directly addresses the ATH long entries on slow TFs (1D entered $121K, 12H entered $112K) while fast TFs were already bearish. One new `request.security()` call per TF that needs it.
- `i_w_puell_multiple` — miner revenue / 365d avg. High = miners well-paid, sell less; low = miner capitulation. Available via `GLASSNODE:BTC_PUELL_MULTIPLE` or similar.
- `i_w_fed_net_liq` — Fed balance sheet net liquidity (WALCL − WTREGEN − RRPONTSYD). Was previously live but removed to stay under request.security() budget. **Batch this with the next re-export**: restore 3 FRED calls in Pine, add `fed_net_liq_norm` to Python + data CSVs, unlock params JSONs. Current budget: **37/40** (3 slots free — exactly enough, but leaves 0 headroom). Consider freeing 1 more slot first.
- **Rename `i_w_basis` → `i_w_spot_perp_basis`** (or similar) — current name is ambiguous. Batch this Pine variable rename + plotchar label update with the next re-export cycle to avoid a standalone DB reset.
- **Budget note**: current request.security() count is 37/40 (3 slots free). Fear & Greed + exchange netflow = 2 slots → 39/40. Must free ≥1 more slot before adding fed_net_liq on top, or ≥2 for all of the above.

**~~[SIGNAL] Divergences as multi-bar regime windows (RSID phase)~~** ✅ DONE (2026-04-02)
`i_div_window` param added to `generate_signals()` and all 23 params JSONs. When > 1, rolling-max extends RSID divergence flags ({0,1} binary) for N bars so a divergence that fired recently stays "active". GPU path uses raw signals as a window=1 approximation; CPU verification applies the correct per-sample window. Range 1–20 bars, step 1.
_Remaining_: Ternary divergence signals (stoch_div_norm, m3_div_norm, m2_div_norm) need separate forward-fill logic (can't use simple rolling max on -1/0/+1). Deferred.

**~~[SIGNAL] US 2-year yield (US02Y) and/or yield curve spread (2Y-10Y) as Fed expectations signals~~** ✅ DONE (2026-03-26)
Added `i_w_us2y` (14-bar ROC sign, inverted) and `i_w_yield_curve` (sign of US10Y−US02Y). Both live in Pine, Python, and all 20 params JSONs.

**~~[SIGNAL] QQQ/SPY ratio as macro signal~~** ✅ DONE (2026-03-26)
Added `i_w_qqq_spy_ratio` (14-bar ROC sign of QQQ/SPY ratio). Live in Pine, Python, and all 20 params JSONs. BTC CSVs re-exported; alts pending.

**[SIGNAL] M2/M3 multi-offset slope signals**
From MainStrategy.pine: M2 with offsets 0, 65, 72, 84 days and M3 with offsets 0 and 48 days. The signal is slope direction (up/down) at each offset — BTC price often correlates with M2/M3 slope with N days of delay. Add these as additional plotchar exports and optimizer weight targets. Relatively small Pine change; Python side just adds more `i_w_*` columns.

---

## Medium Priority — Optimizer Improvements

**[OPT] Regime values (21, 30) are timeframe-agnostic — should vary by TF**
The MVRV regime thresholds (bull/bear/sideways color bands) were eyeballed on the 1D/12H BTC chart. These same values are used on all TFs but don't correspond well to price direction on 4H.
Decision: **Option A — user eyeballs per-TF starting values**. This avoids adding 2 params to the search space. User needs to look at each TF chart and provide threshold values for 4H, 6H, 8H, 12H (1D is fine with 21/30). Once values are provided, update `config.py` with a per-TF dict and update `auto_optimize_loop.py` to pass the right thresholds.
_Blocked on: **James** to provide eyeballed threshold values per timeframe (4H, 6H, 8H, 12H) by looking at each chart._

**~~[OPT] Surface non-winner rows from DB sorted by any metric~~** ✅ DONE (2026-04-01)
`tools/query_db.py` created. Supports `--asset`, `--tf`, `--sort`, `--top`, `--min-trades`, `--subperiod-only`, `--out` (CSV export), `--show-weights`. See `tools/README.md` for full usage.

**[RESEARCH] Run query_db.py analysis across all 20 combos**
Use `tools/query_db.py` to explore the DB and answer:
- Are there param sets with strong Calmar/Sortino across multiple assets? → Universal signal candidates for locking.
- Do top-N rows per combo cluster in weight space, or scatter? → Determines if one weight set could serve all TFs per asset.
- Do non-winner rows with good metrics share consistent weight signs? → Better starting ranges for next optimization cycle.
Start with: `python3 tools/query_db.py --asset COINBASE_BTCUSD --tf 4H --top 50 --sort calmar_ratio --subperiod-only --out results/candidates_btc4h.csv`

**[WORKFLOW] Automated workflows as skills/hooks (new signal, lock signal, add indicator)**
Document and implement step-by-step workflows for common multi-step operations so they are followed consistently and reduce the implement→break→fix→reset→optimize→TV mismatch cycles. Start with the most frequently used:
1. **Add new signal workflow**: Pine edit → static check (plot count, request.security) → TV paste + confirm → reset DB (prompt) → optimize short run → compareTrades → if match, commit
2. **Lock signal to zero workflow**: update params JSON → update SHAP verdict → no DB reset needed
3. **Remove signal workflow**: safety checklist from CLAUDE.md (is it a condition gate?) → Pine edit → TV paste + confirm → reset DB → optimize
Implement as `.claude/commands/` skills or as a prompted checklist that Claude follows automatically.

**[OPT] True Optuna TPE integration (warm-start from DB history)**
`--search optuna` does NOT use Optuna's TPE sampler. It computes p5–p95 biased ranges from DB history, then does numpy random sampling within those ranges. True TPE maintains a probabilistic model over the objective and proposes new trials by maximizing Expected Improvement.
- Replace biased-range numpy sampling with `optuna.create_study(sampler=TPESampler)` + `study.optimize()`
- Warm-start by loading top rows from DB via `study.add_trial()` at startup
- Expected: 15–25% fewer evaluations to find equivalent-quality winner
- Requires bridging the GPU batch evaluator into Optuna's per-trial API (~3–5 days)

**~~[OPT] Walk-Forward Temporal Robustness Rescore (WFO) — highest OOS impact~~** ✅ DONE (2026-04-01)
OOS dashboard showed 18/20 combos negative — dominant failure mode is **temporal overfitting** (params tuned to 2017–2024 bull run fail in 2024+ bear/sideways period).
Implemented as a **temporal robustness rescore** (WFO Phase 1): after each IS optimization run, the top 200 IS Composite candidates are re-evaluated across 4 OOS folds within the IS window (2021 bull, 2022 bear, 2023 recovery, 2024H1 mixed). WFO score = mean(OOS Calmar across folds with ≥2 trades). WFO winner saved alongside IS winner as `*_wfo.csv`.
- `config.py`: `WFO_FOLDS`, `WFO_MIN_OOS_TRADES`, `WFO_MIN_VALID_FOLDS`, `WFO_TOP_N`
- `tools/auto_optimize_loop.py`: `_wfo_score_one` worker, WFO rescore in `verify_top_results`, `wfo_score` column in DB, `global_wfo_best_row` tracking, summary output
- `tools/wfo_rescore.py`: standalone tool for retrospective DB analysis — `python3 tools/wfo_rescore.py --asset COINBASE_BTCUSD --timeframe 4H`
- **Note**: this is a temporal robustness check within IS (not true holdout). True holdout is still 2024-10-01+ OOS dashboard. Phase 2 would switch winner selection from IS Composite to WFO score (after validating Phase 1 improves OOS dashboard metrics).

**[OPT] Universal per-timeframe weights (cross-asset pooled optimization)**
Rather than optimizing each asset independently (4 separate BTC/ETH/SOL/LINK runs per TF), optimize a single weight set per TF that must perform across all 4 assets simultaneously. Scoring target = average Composite across all assets at that TF.
- Attacks **asset overfitting** (params tuned to BTC's 2017–2024 idiosyncrasies fail on ETH/SOL/LINK)
- Complementary to WFO (which attacks temporal overfitting): combining both is the long-term goal
- Natural hypothesis to test: do 1D+12H weights cluster together? Do 4H+6H+8H cluster? Could yield 2 universal weight sets covering all TFs.
- Implementation: new `run_pooled.py` that concatenates all 4 asset CSVs, calls optimize_strategy.py with combined data, scores average Composite. Medium complexity (~3–5 days).
- Expected: more conservative weights, better OOS generalization than per-asset; ~4× slower per TF run
- Priority: after WFO (WFO hits temporal overfitting, the current dominant failure)

**[OPT] CMA-ES sampler for late-stage refinement**
After TPE finds a promising region, CMA-ES models correlations between the 48 parameters and refines efficiently.
- Add `--search cmaes` mode using Optuna's `CmaEsSampler` (or `CatCMA` for mixed int/float)
- Workflow: 4h random/TPE → seed CMA-ES from top result → 2h CMA-ES refinement pass
- Expected: 5–15% Composite improvement on late-stage refinement runs
- Complexity: Low (~1–2 days once true Optuna TPE is in place)

**[OPT] L1 sparsity penalty on composite score**
Add a small L1 penalty (proportional to sum of |weights|) to the composite scoring function to discourage large-magnitude solutions that tend to overfit.
```python
l1_penalty = lambda_l1 * sum(abs(params[k]) for k in params if 'i_w_' in k)
composite_penalized = composite - l1_penalty  # in config.py
```
- Tune λ ∈ [0.001, 0.01] via sensitivity sweep (a few short test runs)
- Expected: 20–30% reduction in mean absolute weight; improved OOS generalization
- Complexity: Very low (half day)

**[OPT] Signal importance-guided pruning**
`tools/shap_feature_importance.py` and per-run MDI importance reports already exist but their output has not been acted on.
- Run `python3 tools/shap_feature_importance.py` on BTC 4H DB (216k rows) → SHAP ranking of all 46 signals
- Review `results/reports/optuna_importance_COINBASE_BTCUSD_4H.md` for MDI ranking
- Identify bottom 10–15 signals contributing <1% cumulative importance
- Ablation test: optimize with those signals zeroed out; if Composite ≥95% of baseline → remove permanently
- Benefit: smaller search space, faster convergence, less overfitting surface
- Complexity: Low (already implemented) — just need to run and act on results

**~~[METRIC] Composite metric: Calmar × log(trades/floor) to reward higher trade counts~~** ✅ DONE
Implemented as `Calmar × (1 + min(log(trades/floor), log(4)))` with dynamic IS trade floor `max(10, round(4 × is_years))`. Capped at log(4) bonus to prevent runaway trade-count gaming. Lives in `config.py:composite_score()`.

**~~[OPT] Optuna biased-range sampling~~** ✅ DONE (but see True TPE item above)
Implemented `--search optuna` mode: computes p5–p95 ranges from top 10% of DB history, biases 50% of GPU samples toward those ranges. **Note**: this is a biased-range heuristic, NOT true Optuna TPE. True TPE (with probabilistic model + Expected Improvement) is a separate backlog item with additional convergence benefit.

**~~[METRIC] Evaluate Calmar ratio vs Sortino as primary optimization metric~~** ✅ DONE (2026-03-23)
Switched to Calmar. Evidence: BTC 6H Sortino-optimized winner had P&L=570% vs Calmar-era winner P&L=1,460% — Sortino was gamed by low-return/low-vol params. Changed `OPTIMIZATION_METRIC` in `auto_optimize_loop.py`, DB percentile rank, and DB write filter to all use Calmar.

**~~[OPT] LLM-guided narrowing re-evaluation~~** ✅ REMOVED
Fully stripped from `auto_optimize_loop.py`. Optuna biased sampling achieves the same goal (steering search toward promising regions) more reliably and without the over-narrowing risk. Not worth re-adding.

---

## Medium Priority — Dashboard & Observability

**[DASH] OOS dashboard: show WFO fold breakdown per combo**
Now that WFO rescore runs automatically, surface fold-level Calmar (2021/2022/2023/2024H1) in a dashboard table for the WFO winner of each combo. Would make it easy to spot combos that only work in bull markets vs all-weather params. Dependent on WFO Phase 1 producing enough winner data across all 20 combos.

**[DASH] Search space size tracking**
Track the effective search space size over time as params are tightened, and surface this in the sweep or SHAP dashboard. Rather than raw septillion-scale numbers, show relative percentages: "tightening param X reduces search space by 12%". Would help contextualize lock/tighten decisions.

---

## Medium Priority — Signal Quality

**[SIGNAL] ROC signal candidates from SHAP analysis**
SHAP suggests rate-of-change signals may be more predictive than level signals. Candidates worth testing: `rsid_osc_roc`, `macd_roc` (instead of `macd_bullish` binary), `m2_div_osc_roc`, `stoch_div_roc`, `spy_roc`, `gold_roc`, `dxy_roc`, `fed_net_liq_roc`, `yield_curve_roc`, `stoch_roc`, `qqq_close_roc`. Each requires a Pine plotchar export + Python column + params JSON entry. Approaching the 64-slot limit — must batch with slot-freeing removals and be strategic about which to add.
_Dependency: 64-slot workaround (second indicator file) or freeing existing slots first._

**[SIGNAL] 64-plot slot workaround: second indicator/strategy file**
We are near/at the 64-plotchar export limit. A second Pine indicator file can export additional variables — when both are applied to the chart, TradingView includes both in the CSV export. This unblocks adding new signals without having to remove existing ones. Implement as `indicators/ActivationScoresAux.pine` that exports overflow signals.

**[SIGNAL] RSI Divergence library investigation**
`libraries/LibraryRSIDivergence.pine` was the first library written and may have bugs/broken functionality limiting its effectiveness. Do a thorough review: test each exported function against known divergence patterns, compare with a reference implementation. Fix any bugs found. Potential: the rsid_osc signal is consistently negative in top performers — understanding why could unlock better divergence detection.

**[SIGNAL] ETH-specific MVRV for ETH combos**
GLASSNODE:ETH_MARKETCAP + COINMETRICS:ETH_MARKETCAPREAL likely available free on TV. Would give ETH a native MVRV rather than using BTC's as a proxy. Add as a conditional in Pine (use ETH MVRV when ticker = ETH, BTC MVRV otherwise). Medium Pine complexity.

---

## Lower Priority — DB & Infrastructure

**[DB] Add composite index (schema_ver, pnl_dd_percentile) to sweep_results**
`mine_sweep_db.py` does `SELECT * WHERE schema_ver=3` then filters top-quartile in pandas. A composite index would push the percentile filter into SQLite. Not needed until DB exceeds ~1M rows (~375 bytes/row → ~375 MB), but worth doing before then.

---

## Lower Priority — Repo Health

**[REPO] Move `generate_pine_presets.py` call from `run_all_crypto.py` to `auto_optimize_loop.py`**
Currently only `run_all_crypto.py` auto-calls `generate_pine_presets.py`. Should move to end of `auto_optimize_loop.py` (called once after the run completes) so any optimization run updates the presets. Verify this is safe for single-combo runs (partial preset update is fine — other presets are unchanged).
Also update CLAUDE.md workflow note to reflect this.

**[REPO] Consolidate two backlog files**
There are two backlog.md files (root and docs/). Consolidate into one.
_Note: User prefers to handle this manually — just flag the existence of the duplicate._

**[REPO] Add `tools/README.md` entries for undocumented tools**
`rescore.py`, `reset_results.py`, and likely others are not documented in `tools/README.md`. Add brief entries for each.

**[REPO] pine-def.txt still in repo root**
Should move to `docs/` or delete if no longer needed as a reference.

**[REPO] Reorganize strategies/ Pine files**
`strategies/` mixes active `.py` files with `.pine` files and historical baselines. Move Pine files to `strategies/pine/` with `archive/` subfolder. No Python imports affected.

**[REPO] Move indicators/ and libraries/ under a single pine/ top-level directory**
Both contain Pine Script files only. A single `pine/indicators/` and `pine/libraries/` structure is cleaner.

**[REPO] Add README.md directory structure section**
After restructuring stabilises, add a directory tree to root README.md for new contributor orientation.
_Note: `/updateProjectStructure` command (see CMD items) could generate this automatically._

---

## Future / Speculative

**[WFO] Per-TF fold window sizing**
Current WFO uses fixed one-year folds for all timeframes. Low-frequency TFs (4H, 12H, 1D) trade ~6-9 times/year — often below the 10-trade floor per fold — meaning only 1-2 of 6 folds qualify for scoring. Better approach: scale fold window length to the TF (e.g. 2-year folds for 12H/1D) so slower strategies accumulate enough trades per fold to be fairly judged. Requires refactoring `WFO_FOLDS` to be TF-aware rather than a single shared constant.
_Context: 2026-04-11 analysis — after fixing WFO_MIN_OOS_TRADES=MIN_ABS_TRADES, 6H gets 2 qualifying folds, 4H/12H likely get 0-1. Accepted trade-off for now (Option A: run more optuna, use IS-composite winner when no WFO winner exists). Revisit when WFO robustness becomes the primary bottleneck._

**[STRATEGY] Short signals for bear regime**
When regime score is bearish, enter short rather than suppressing entries. Natural Phase 4+ extension. Requires Pine short logic + separate bear-regime optimization pass.

**[STRATEGY] Multi-timeframe confirmation (higher-TF gate)**
Use a higher TF activation score as a regime gate for a lower TF's entries. E.g., BTC 1D regime must be bullish before BTC 4H entries fire.

**[STRATEGY] Multi-timeframe confirmation (lower-TF gate / D2)**
Inverse of the above: require sub-TF confirmation before a slow-TF entry fires. E.g., compute full 4H activation_score_poc on the 12H chart via `request.security()`. If 4H score is negative (bearish), block 12H entry. Directly addresses Oct 2025 ATH entries: 1D entered $121K and 12H entered $112K while 4H was already bearish. More powerful than D1 (which just adds 4H RSI as a weight) but requires Pine complexity and is near the 64-slot limit. Implement after D1 (sub-TF RSI) is validated.
_Context: OOS trade research 2026-04-02 — 12H and 1D had largest ATH losses while 4H/6H did not enter at the top._
w
**[STRATEGY] Hard regime gates for extreme conditions (Option E)**
Boolean entry suppression (bypasses weight system) for extreme macro/sentiment regimes:
- VIX pctrank > 70 (spike regime) → no new longs
- Fear & Greed > 80 (extreme greed) → no new longs
- OI ROC strongly negative (mass deleveraging) → no new longs
Different from soft weights (Option B): combines signals multiplicatively rather than additively, can't be neutralized by other bullish weights. Risk: introduces non-optimizable thresholds that may not generalize. Implement only if Option A (div window) + Option B/C/D1 signals prove insufficient. Also requires Pine equivalent for TV parity.
_Context: IS optimizer systematically underweights VIX/DXY (ranked WEAK in SHAP) because during 2017-2025 IS these were noise; OOS they were regime indicators._

**[STRATEGY] Additional on-chain signals**
Candidates: Puell Multiple, STH/LTH realized price ratio, exchange netflow. Each requires a new TV export if added — batch with the next re-export.

---
_Last updated: 2026-04-02 (session 12 — OOS trade research, div window, backlog D2+E+B/C/D1 batch)_
