feat: curve regime
This commit is contained in:
@@ -310,6 +310,20 @@ def init_db():
|
||||
"ALTER TABLE instrument_overrides ADD COLUMN name TEXT",
|
||||
"ALTER TABLE instrument_overrides ADD COLUMN yf_ticker TEXT",
|
||||
"ALTER TABLE instrument_overrides ADD COLUMN category TEXT",
|
||||
# Curve Regime — one row per Watchlist ticker, overwritten every refresh pass (see
|
||||
# services/wavelet_scheduler.py, same cadence as the wavelet cache). Instrument-level
|
||||
# regime (services.curve_regime), NOT the global macro regime shown elsewhere. Feeds
|
||||
# the Dashboard's "Curve Regime" card so it never needs a live classify call per view.
|
||||
"""CREATE TABLE IF NOT EXISTS curve_regime_cache (
|
||||
ticker TEXT PRIMARY KEY,
|
||||
computed_at TEXT DEFAULT (datetime('now')),
|
||||
regime_key TEXT,
|
||||
regime_label TEXT,
|
||||
score REAL,
|
||||
direction TEXT,
|
||||
profile_json TEXT,
|
||||
has_options_data INTEGER DEFAULT 0
|
||||
)""",
|
||||
]:
|
||||
try:
|
||||
c.execute(_sql)
|
||||
@@ -3721,6 +3735,48 @@ def get_wavelet_decomposition_cache(ticker: str) -> Optional[Dict]:
|
||||
return d
|
||||
|
||||
|
||||
def save_curve_regime_cache(ticker: str, classification: Dict) -> None:
|
||||
top = classification.get("top_match") or {}
|
||||
conn = get_conn()
|
||||
conn.execute(
|
||||
"INSERT INTO curve_regime_cache (ticker, computed_at, regime_key, regime_label, score, direction, profile_json, has_options_data) "
|
||||
"VALUES (?, datetime('now'), ?, ?, ?, ?, ?, ?) "
|
||||
"ON CONFLICT(ticker) DO UPDATE SET computed_at=excluded.computed_at, regime_key=excluded.regime_key, "
|
||||
"regime_label=excluded.regime_label, score=excluded.score, direction=excluded.direction, "
|
||||
"profile_json=excluded.profile_json, has_options_data=excluded.has_options_data",
|
||||
(
|
||||
ticker.upper(), top.get("key"), top.get("label"), top.get("score"),
|
||||
(classification.get("profile") or {}).get("direction"),
|
||||
json.dumps(classification), 1 if classification.get("has_options_data") else 0,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_all_curve_regime_cache() -> List[Dict]:
|
||||
"""One row per Watchlist ticker, in Watchlist sort order — a data=None placeholder for
|
||||
any ticker never successfully classified yet, same "always show every Watchlist
|
||||
instrument" convention as get_latest_wavelet_state_by_instrument()."""
|
||||
conn = get_conn()
|
||||
rows = conn.execute("SELECT * FROM curve_regime_cache").fetchall()
|
||||
conn.close()
|
||||
by_ticker = {r["ticker"]: dict(r) for r in rows}
|
||||
out: List[Dict] = []
|
||||
for item in get_instruments_watchlist():
|
||||
ticker = item["ticker"].upper()
|
||||
row = by_ticker.get(ticker)
|
||||
if row:
|
||||
row["profile"] = json.loads(row.pop("profile_json")).get("profile") if row.get("profile_json") else None
|
||||
out.append(row)
|
||||
else:
|
||||
out.append({
|
||||
"ticker": ticker, "computed_at": None, "regime_key": None, "regime_label": None,
|
||||
"score": None, "direction": None, "profile": None, "has_options_data": 0,
|
||||
})
|
||||
return out
|
||||
|
||||
|
||||
# ── AI Chat widget — persisted conversation ────────────────────────────────────
|
||||
|
||||
def save_chat_message(session_id: str, role: str, content: str) -> None:
|
||||
|
||||
Reference in New Issue
Block a user