feat: cockpit

This commit is contained in:
OpenSquared
2026-07-24 17:42:14 +02:00
parent de0675705b
commit 32f2d27782
3 changed files with 35 additions and 5 deletions

View File

@@ -302,5 +302,5 @@ def remove_simulation(sim_id: str):
@router.get("/watchlist-signals")
def watchlist_signals():
from services.database import get_latest_wavelet_signals
return {"signals": get_latest_wavelet_signals()}
from services.database import get_latest_wavelet_state_by_instrument
return {"signals": get_latest_wavelet_state_by_instrument()}

View File

@@ -3622,6 +3622,36 @@ def get_latest_wavelet_signals() -> List[Dict]:
return [dict(r) for r in rows]
def get_latest_wavelet_state_by_instrument() -> List[Dict]:
"""One row per Watchlist instrument from the most recent scan — a fired signal if this
run had one for it (any band), otherwise the fastest band's current slope/direction, so
every scanned instrument shows *something* here instead of only the ones with an active
trigger this run. get_latest_wavelet_signals() (fired-only) stays as-is for any other
caller; this is specifically for the Dashboard's Wavelets Signal card, which should
reflect the latest state per instrument, not just a list of firings."""
run_id = _latest_wavelet_run_id()
if not run_id:
return []
conn = get_conn()
rows = conn.execute(
"SELECT * FROM wavelet_watchlist_signals WHERE run_id=? AND band_label != 'ridge' "
"ORDER BY ticker, (signal_kind IS NULL), period_low_days ASC",
(run_id,),
).fetchall()
conn.close()
by_ticker: Dict[str, Dict] = {}
for r in rows:
d = dict(r)
by_ticker.setdefault(d["ticker"], d)
out = list(by_ticker.values())
# No fired signal this run for this band -> direction is null; fall back to the band's
# own slope sign so the card can still show an up/down arrow instead of a blank one.
for d in out:
if d.get("direction") is None and d.get("slope") is not None:
d["direction"] = "up" if d["slope"] > 0 else "down"
return out
def get_latest_wavelet_state() -> List[Dict]:
"""Every (ticker, band) row from the most recent cycle scan — signal or
not. Used for the rich AI chat context block (slope/energy/ridge state)."""