feat(phase6): per-feature signal attribution in log-odds space
CI/CD / build-and-push (push) Successful in 1m56s
CI/CD / build-and-push (push) Successful in 1m56s
Adds feat_fg_lo / feat_mom_lo / feat_news_lo / feat_mfld_lo / feat_btc_dom_lo to every trade, all normalized to log-odds contribution for direct comparability. - fg / mom / btc_dom: raw probability-delta × 2 → log-odds - news / mfld: already log-odds (LOGODDS_WEIGHT already applied), no scaling - btc_dom tracked separately in bayesian.py instead of bundled in total_adj - reasoning string updated to fg_lo= / mom_lo= notation for self-documentation Schema: 5 new DOUBLE PRECISION columns + 2 partial indexes Stack: TradingSignal → Order → Trade → save_trade all carry feat fields Startup: backfill_feature_columns() recovers fg/mom/news/mfld from old reasoning strings (×2 applied to fg/mom); btc_dom_lo stays NULL for legacy API: /api/metrics/features — triggered/material split per feature with two-level thresholds (0.05 for fg/mom/btc_dom, 0.10 for news/mfld) API: /api/trades/legacy — exposes pre-Phase-1 trades (edge_net IS NULL) API: _enrich_trade backward-compat: reads DB columns first, falls back to reasoning regex with unit conversion for pre-Phase-6 trades Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -160,6 +160,16 @@ class TradingSignal:
|
||||
family_key: str = ""
|
||||
# ── Phase 4: regime ──────────────────────────────────────────────────────
|
||||
regime_min_edge: float = 0.10
|
||||
# ── Phase 6: per-feature log-odds contributions ───────────────────────────
|
||||
# All values are in log-odds space for direct comparability.
|
||||
# feat_fg_lo / feat_mom_lo: probability-delta × 2 → log-odds.
|
||||
# feat_news_lo / feat_mfld_lo: already log-odds (no scaling).
|
||||
# feat_btc_dom_lo: btc-dominance probability-delta × 2 → log-odds.
|
||||
feat_fg_lo: float = 0.0
|
||||
feat_mom_lo: float = 0.0
|
||||
feat_news_lo: float = 0.0
|
||||
feat_mfld_lo: float = 0.0
|
||||
feat_btc_dom_lo: float = 0.0
|
||||
|
||||
|
||||
class BayesianStrategy:
|
||||
@@ -379,11 +389,14 @@ class BayesianStrategy:
|
||||
adjustments.append(_fg_contribution)
|
||||
|
||||
# Signal 3: BTC dominance — hurts altcoins when high
|
||||
_btc_dom_contribution = 0.0
|
||||
if (is_eth or is_altcoin or is_general_crypto) and ext.btc_dominance > 55:
|
||||
adjustments.append(-0.03 if is_price_above else 0.03)
|
||||
_btc_dom_contribution = -0.03 if is_price_above else 0.03
|
||||
adjustments.append(_btc_dom_contribution)
|
||||
sources.append(f"BTC dom: {ext.btc_dominance:.1f}% (high → alt pressure)")
|
||||
elif (is_eth or is_altcoin or is_general_crypto) and ext.btc_dominance < 45:
|
||||
adjustments.append(0.03 if is_price_above else -0.03)
|
||||
_btc_dom_contribution = 0.03 if is_price_above else -0.03
|
||||
adjustments.append(_btc_dom_contribution)
|
||||
sources.append(f"BTC dom: {ext.btc_dominance:.1f}% (low → alt season)")
|
||||
|
||||
# Signal 4: GNews sentiment (politics only, budget-gated)
|
||||
@@ -448,12 +461,19 @@ class BayesianStrategy:
|
||||
if manifold_log_adj != 0.0:
|
||||
confidence = min(confidence_cap, confidence + 0.08)
|
||||
|
||||
# Per-feature contribution string for audit logging
|
||||
# Per-feature log-odds contributions (Phase 6).
|
||||
# fg / mom / btc_dom: probability-delta × 2 → log-odds.
|
||||
# news / mfld: already log-odds (LOGODDS_WEIGHT already applied).
|
||||
feat_fg_lo = _fg_contribution * 2
|
||||
feat_mom_lo = _momentum_contribution * 2
|
||||
feat_news_lo = news_log_adj
|
||||
feat_mfld_lo = manifold_log_adj
|
||||
feat_btc_dom_lo = _btc_dom_contribution * 2
|
||||
|
||||
feat_str = (
|
||||
f"fg={_fg_contribution:+.3f} "
|
||||
f"mom={_momentum_contribution:+.3f} "
|
||||
f"mfld={manifold_log_adj:+.4f} "
|
||||
f"news={news_log_adj:+.4f}"
|
||||
f"fg_lo={feat_fg_lo:+.4f} mom_lo={feat_mom_lo:+.4f} "
|
||||
f"news_lo={feat_news_lo:+.4f} mfld_lo={feat_mfld_lo:+.4f} "
|
||||
f"btc_dom_lo={feat_btc_dom_lo:+.4f}"
|
||||
)
|
||||
|
||||
# ── Phase 5: structured audit log ────────────────────────────────────
|
||||
@@ -496,8 +516,7 @@ class BayesianStrategy:
|
||||
f"regime_min={regime_min:.2f} | days={days} | "
|
||||
f"family={family} | "
|
||||
f"Direction={direction} | "
|
||||
f"fg={_fg_contribution:+.4f} mom={_momentum_contribution:+.4f} "
|
||||
f"news={news_log_adj:+.4f} mfld={manifold_log_adj:+.4f} | "
|
||||
f"{feat_str} | "
|
||||
f"Signals: {', '.join(sources[1:])}"
|
||||
)
|
||||
|
||||
@@ -535,6 +554,12 @@ class BayesianStrategy:
|
||||
family_key=family,
|
||||
# Phase 4 new fields
|
||||
regime_min_edge=regime_min,
|
||||
# Phase 6 new fields — all in log-odds space
|
||||
feat_fg_lo=feat_fg_lo,
|
||||
feat_mom_lo=feat_mom_lo,
|
||||
feat_news_lo=feat_news_lo,
|
||||
feat_mfld_lo=feat_mfld_lo,
|
||||
feat_btc_dom_lo=feat_btc_dom_lo,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user