# Weight Sign & Range Analysis — Domain Knowledge Punchlist

## How to read this doc

Each component has a normalised feature value (what the library passes to the dot-product)
and a **sign prior**: the sign the weight *should* have for the strategy logic to make
economic sense.

**Strategy logic reminder:**
- Score HIGH → conditions unfavourable for long entry (score stays above entry threshold).
- Score LOW → conditions favourable; crossunder triggers entry.
- Therefore: a feature that is HIGH when conditions are *good for entry* needs a **negative** weight
  (so it reduces the score and pulls it below the threshold), and vice-versa.

Normalised feature values are computed in `strategies/library_activation_scores.py`.

---

## Priority 1 — Sign is deterministic; constraining it halves the search dimension

These features have a clear economic direction. The weight range should be constrained to
one sign (positive-only or negative-only). Allowing the optimizer to search both sides
wastes half the search budget on economically backwards solutions.

| # | Parameter | Normalised feature | Economic meaning | Sign prior | Current 1D template range | Action needed |
|---|---|---|---|---|---|---|
| 1 | `i_w_bearish_engulfing` | `+score` when pattern fires (0–1) | Bearish candle pattern → unfavourable for entry → score should go UP | **Positive** | −42 to −33 ⚠️ | Currently negative — backwards. Investigate: does the optimizer use it as an inverse exit signal, or is this a genuine mistake? |
| 2 | `i_w_shooting_star` | `+score` when pattern fires (0–1) | Bearish candle pattern → unfavourable for entry → score UP | **Positive** | −60 to +40 ❌ crosses zero | Lock to positive range |
| 3 | `i_w_bullish_hammer` | `+score` when pattern fires (0–1) | Bullish reversal → score should go DOWN to encourage entry | **Negative** | −60 to +40 ❌ crosses zero | Lock to negative range |
| 4 | `i_w_bullish_engulfing` | `+score` when pattern fires (0–1) | Bullish candle → score DOWN | **Negative** | −60 to +40 ❌ crosses zero | Lock to negative range |
| 5 | `i_w_stoch_peaking` | `−1` when stoch is peaking, `0` otherwise | Stoch peaking = momentum exhaustion → entry unfavourable → score UP when peaking. −1 × negative weight = +contribution | **Negative** | −9.5 to −8.4 ✓ | Sign is correct. Consider whether the magnitude range is too narrow (LLM-narrowed). |
| 6 | `i_w_stoch_bottoming` | `+1` when stoch is bottoming, `0` otherwise | Stoch bottoming = reversal setup → favourable. +1 × positive weight = +score (score rises as stoch bottoms, then drops below threshold on entry) | **Positive** | 43.7 to 44.8 ✓ | Sign correct but range is extremely narrow (LLM-narrowed). Widen. |
| 7 | `i_w_macd_bullish` | `+1` on bullish MACD flip, `0` otherwise | MACD flipping bullish = bullish momentum → score should rise (crossunder entry follows) | **Positive** | 6.75 to 7.5 ✓ | Sign correct. Likely LLM-narrowed — widen. |

**Note on `i_w_bearish_engulfing` (item 1):** The current winner uses a *negative* weight.
This is counter-intuitive. One hypothesis: the optimizer is using it as an exit-avoidance
signal — when a bearish engulfing fires, the score drops (negative weight), which may
paradoxically trigger a crossunder exit sooner rather than later. This is worth verifying
by running a constrained test with the weight forced positive. If performance collapses,
the optimizer has found a genuine counter-intuitive use; if it's flat or better, it was a
spurious correlation.

---

## Priority 2 — Sign has a strong prior but the feature encoding may introduce a flip

These need a quick check of the normalization formula before locking in a range.

| # | Parameter | Normalised feature | Economic meaning | Sign prior | Current 1D template | Notes |
|---|---|---|---|---|---|---|
| 8 | `i_w_osc` | `(RSI − 50) / 50` → +1 overbought, −1 oversold | Low RSI (oversold) = good for entry → score should be LOW → oversold gives −1 × weight. For entry: **negative weight** pushes score down when RSI is low (bad). Hmm — this is ambiguous (see below). | Ambiguous — see notes | −1.8 to −1.7 ✓ (sign consistent) | The *direction* of RSI's effect on entry is debated. A negative weight means "high RSI lowers the score" which could represent "enter in overbought conditions" (momentum) rather than "enter oversold" (reversion). Determine which regime BTC follows. |
| 9 | `i_w_rsid_osc` | `clip(−(rsid − 42) / 28, −1, +1)` → +1 when RSI is *low* (≈14), −1 when high (≈70) | Low RSI divergence = bullish setup → score should rise to set up crossunder entry | **Positive** | 5.7 to 6.45 ✓ | Sign correct; range may be LLM-narrowed. |
| 10 | `i_w_stoch_div_osc` | `+1` when `price_roc > stoch_roc`, `−1` otherwise | Positive divergence (price rising faster than stoch) = bullish → score should rise for crossunder | **Positive** | −2.5 to −1.2 ⚠️ | Currently negative. Check: is the divergence signal convention the same in Pine and Python? Or is this an intentional sign flip? |
| 11 | `i_w_vwap_div_osc` | `clip(vwap_div_osc, −1, +1)` | Positive = price rising faster than VWAP = bullish | **Positive** | −17 to −12 ⚠️ | Negative — same question as stoch_div_osc. |
| 12 | `i_w_m3_div_osc` | `+1 / −1 / 0` 3-way sign of M3 divergence oscillator | M3 diverging positively from price = more liquidity than price reflects = bullish | **Positive** | −15 to −11.6 ⚠️ | Negative — may indicate the oscillator convention is inverted (high M3 relative to price = price will catch up = bullish). Verify sign convention in `LibraryMoneySupplyDivergence`. |
| 13 | `i_w_m2_div_osc_noOffset` | `+1 / −1 / 0` 3-way sign of M2 divergence (no lag) | Rising M2 relative to price = bullish | **Positive** | −6.8 to −5.7 ⚠️ | Negative — same question as M3. Verify convention. |

---

## Priority 3 — Macro signals; directionally clear but BTC relationship needs empirical check

These have defensible sign priors from macro theory, but BTC's correlation with macro
factors changes regimes (pre-2020 vs post-2020 ETF era). Worth validating empirically
before locking in a range.

| # | Parameter | Normalised feature | Macro theory prior | Sign prior | Current range | Notes |
|---|---|---|---|---|---|---|
| 14 | `i_w_dxy` | `−1` DXY rising, `+1` falling (already inverted in Pine) | Weak dollar = capital risk-on = BTC bullish → feature is `+1` when bullish | **Positive** | −50 to +20 ❌ | Should likely be positive-only. Range crosses zero. |
| 15 | `i_w_vix` | `1 − pctrank(VIX)` → high when VIX is low (low fear) | Low fear = risk-on = BTC bullish → feature high = score rises for crossunder | **Positive** | −50 to +30 ❌ | Theoretical prior = positive. Wide range — verify empirically. |
| 16 | `i_w_btc_dom` | `+1` BTC.D rising, `−1` falling | Rising BTC dominance = capital rotating INTO BTC from alts = bullish for BTC | **Positive** | −50 to +20 ❌ | Strong prior: positive. |
| 17 | `i_w_us10y` | `−1` yields rising, `+1` falling (already inverted in Pine) | Falling yields = risk-on = BTC bullish → feature `+1` when bullish | **Positive** | −50 to +30 ❌ | Should be positive-only. Post-2022 rate cycle makes this particularly worth validating. |
| 18 | `i_w_spy` | `+1` SPY above 200 EMA, `−1` below | SPY in bull mode = macro risk-on = BTC favourable | **Positive** | −50 to +20 ❌ | Strong prior: positive. |
| 19 | `i_w_btc_spx_corr` | Rolling 30-bar correlation, −1 to +1 | Ambiguous: high correlation can mean "BTC follows stocks up" OR "BTC is just a risk asset, not an independent store of value." No strong prior. | **Ambiguous** | −50 to +30 | Leave wide; this one genuinely needs empirical analysis. |
| 20 | `i_w_gold` | `pctrank(gold_roc_21)` → 0 to 1 | Gold rising = dollar weakness / inflation hedge = slightly bullish for BTC, but also risk-off sometimes | **Ambiguous** | −60 to +40 | Leave wide. Regime-dependent. |

---

## Priority 4 — Technical signals; sign is less obvious, leave wider

| # | Parameter | Normalised feature | Notes |
|---|---|---|---|
| 21 | `i_w_stoch` | `(stoch − 50) / 50` → +1 overbought | Positive weight = "score high when overbought → crossunder entry as stoch falls." This is a *momentum reversion* entry, not an oversold entry. Valid for BTC if you're buying after a stoch peak. Worth confirming this is the intended regime. |
| 22 | `i_w_macd_pred` | `+1` if MACD prediction > 0, else `−1` | Positive weight = bullish MACD prediction raises score → entry follows when it drops. Could represent "enter on MACD momentum reversal." |
| 23 | `i_w_m3_momentum` | `+1 / −1` sign of M3 growth rate | Rising M3 = bullish. Positive weight seems correct. Range currently extremely narrow (LLM). |
| 24 | `i_w_m2_tiny` | `+1 / −1 / 0` sign of M2 tiny-offset momentum | Similar to M3 momentum. |
| 25 | `i_w_m2_div_osc` | `+1 / −1 / 0` 3-way sign of M2 divergence with lag | Same sign-convention question as M2/M3 divergence above (item 12–13). |

---

## Parameters with fixed values (not optimized)

| Parameter | Current value | Notes |
|---|---|---|
| `i_m3_momentum_period` | `1` (fixed) | Locked to 1 bar. Worth widening to e.g. [1, 3, 7, 14] to test if longer M3 momentum lookback helps. Low cost to add to search space. |
| `i_cs_body_quality_ratio` | `0.5` (fixed) | Controls candlestick quality filter. Could be optimized but has second-order effect. |
| `i_cs_confidence_scaling_factor` | `4.0` (fixed) | Scales candlestick pattern confidence. Same — second-order. |

---

## Summary — Recommended actions in priority order

1. **Investigate `i_w_bearish_engulfing` sign** — run a test forcing it positive; check if performance changes meaningfully. This is the highest-priority anomaly.
2. **Verify divergence oscillator sign conventions** (`stoch_div_osc`, `vwap_div_osc`, `m3_div_osc`, `m2_div_osc`, `m2_div_osc_noOffset`) — confirm whether Pine and Python agree on the *direction* of these oscillators before locking in a sign.
3. **Lock candlestick pattern signs** — `bullish_hammer` and `bullish_engulfing` to negative-only; `shooting_star` to positive-only.
4. **Lock macro sign priors** — DXY, VIX, BTC.D, US10Y, SPY all have strong positive priors. Verify empirically with a scatter plot of feature vs. forward BTC return; then constrain to positive-only.
5. **Widen LLM-narrowed ranges** — `stoch_peaking`, `stoch_bottoming`, `macd_bullish`, `m3_momentum` in the 1D asset file are clearly over-fit. Reset from template.
6. **Unlock `i_m3_momentum_period`** — add values `[1, 3, 7, 14]` to the search; cheap and potentially meaningful.
