feat: separate live early-warning + combined score on the regime tab
The event study showed the breadth-divergence signal genuinely leads (warned before 7/11 drawdowns, ~6 weeks median, where the coincident baseline almost never did). Surface it live to observe before deciding how to embed it — kept separate from the index, not folded into its weights. - regime_monitor daily job now computes breadth-divergence live and attaches a separate early_warning score plus a combined blend (weighted mean, default 0.6/0.4, configurable via combined_weights) to each snapshot, including the backfill so the 7/30-day trends populate immediately. Stored in breakdown_json — no schema change. Best-effort: a breadth failure can't break the index. - get_regime_monitor returns the index, early_warning, and combined scores each with 7/30-day deltas. - Regime tab shows three gauges (generalized ScoreGauge): coincident index, early warning, and a compact combined blend. Stale snapshots render "—". Note: the daily regime job now also does a universe-wide breadth scan. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ from datetime import date, timedelta
|
||||
|
||||
from app.services.regime_monitor_service import (
|
||||
DEFAULT_CONFIG,
|
||||
_attach_early_warning,
|
||||
band_for,
|
||||
compute_regime_score,
|
||||
f2_credit_spreads,
|
||||
@@ -35,6 +36,23 @@ def test_band_for():
|
||||
assert band_for(90) == "breaking"
|
||||
|
||||
|
||||
def test_attach_early_warning_blends():
|
||||
result = {"total_score": 80.0}
|
||||
_attach_early_warning(result, 40.0, {"coincident": 0.6, "early_warning": 0.4})
|
||||
assert result["early_warning"]["score"] == 40.0
|
||||
assert result["early_warning"]["band"] == "watch"
|
||||
# combined = (80*0.6 + 40*0.4) / 1.0 = 64
|
||||
assert result["combined"]["score"] == 64.0
|
||||
assert result["combined"]["band"] == "elevated"
|
||||
|
||||
|
||||
def test_attach_early_warning_none_falls_back_to_index():
|
||||
result = {"total_score": 80.0}
|
||||
_attach_early_warning(result, None, {"coincident": 0.6, "early_warning": 0.4})
|
||||
assert result["early_warning"]["score"] is None
|
||||
assert result["combined"]["score"] == 80.0 # no early warning -> just the index
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Price sub-scores
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user