feat: cockpit

This commit is contained in:
OpenSquared
2026-07-24 15:52:58 +02:00
parent 3ec0c024ad
commit 7cb81cbd65
6 changed files with 211 additions and 19 deletions

View File

@@ -72,6 +72,34 @@ async def instrument_snapshot(
return snapshot
@router.get("/{instrument_id}/wavelet-cache")
def wavelet_cache(instrument_id: str) -> Dict[str, Any]:
"""Latest full band decomposition for this instrument, from the same per-cycle scan
that feeds the Dashboard's Wavelets Signal card (services.wavelet_signals.
scan_watchlist_wavelet_signals) — NOT a live recompute. Instrument Analysis's Wavelet
tab reads this by default so opening it never triggers its own analysis and always
agrees with the Signal card; "Start analyse" is still there for an on-demand live run
with custom parameters, which does NOT overwrite this cache.
Looked up by the Cockpit Watchlist ticker the cache is keyed on, normalized via the
same yfinance-suffix stripping instrument_service uses elsewhere (EURUSD=X -> EURUSD)
— a quick-added instrument's id already equals its Watchlist ticker verbatim, but a
curated one (EURUSD=X) doesn't."""
from services.instrument_service import _base_ticker
from services.database import get_wavelet_decomposition_cache
cached = get_wavelet_decomposition_cache(_base_ticker(instrument_id))
if not cached or not cached.get("decomposition"):
raise HTTPException(status_code=404, detail=f"Aucune décomposition wavelet en cache pour '{instrument_id}'")
return {
"computed_at": cached["computed_at"],
"method": cached["method"],
"wavelet": cached["wavelet"],
"num_levels": cached["num_levels"],
"lookback_days": cached["lookback_days"],
**cached["decomposition"],
}
@router.post("/{instrument_id}/narrative")
async def generate_narrative(
instrument_id: str,