feat: cockpit

This commit is contained in:
OpenSquared
2026-07-24 11:46:37 +02:00
parent ae732c5822
commit 35a00f43c3
6 changed files with 201 additions and 13 deletions

View File

@@ -287,6 +287,13 @@ def init_db():
drivers_json TEXT,
updated_at TEXT DEFAULT (datetime('now'))
)""",
# "Quick add from Watchlist" (Instrument Analysis picker) — name/yf_ticker/category
# let a row stand in for a full instruments.json entry when the instrument doesn't
# have one yet, instead of only overriding an existing one. See
# services.instrument_service._load_configs()'s second merge pass.
"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",
]:
try:
c.execute(_sql)
@@ -3406,15 +3413,20 @@ def rename_instrument_watchlist(ticker: str, name: str) -> bool:
def get_instrument_overrides() -> Dict[str, Dict]:
"""All overrides keyed by instrument_id (upper), for merging onto instruments.json
at catalog-load time in services/instrument_service.py."""
at catalog-load time in services/instrument_service.py. name/yf_ticker/category are
only set for "quick add from Watchlist" rows (see set_instrument_override_quick_add) —
they let a row stand in for a whole instruments.json entry that doesn't exist yet."""
conn = get_conn()
rows = conn.execute("SELECT instrument_id, saxo_quote_symbol, drivers_json FROM instrument_overrides").fetchall()
rows = conn.execute(
"SELECT instrument_id, saxo_quote_symbol, drivers_json, name, yf_ticker, category FROM instrument_overrides"
).fetchall()
conn.close()
out = {}
for r in rows:
out[r["instrument_id"]] = {
"saxo_quote_symbol": r["saxo_quote_symbol"],
"drivers": json.loads(r["drivers_json"]) if r["drivers_json"] else None,
"name": r["name"], "yf_ticker": r["yf_ticker"], "category": r["category"],
}
return out
@@ -3444,6 +3456,28 @@ def set_instrument_override_drivers(instrument_id: str, drivers: List[Dict]) ->
conn.close()
def set_instrument_override_quick_add(instrument_id: str, name: str, yf_ticker: str, category: str, saxo_quote_symbol: Optional[str]) -> None:
""""Quick add from Watchlist" — instruments_watchlist has a ticker with no
instruments.json counterpart, so the user picked it straight from Instrument
Analysis's picker instead of hand-authoring a catalog entry. name/yf_ticker/category
make this row stand in for a full entry (services.instrument_service._load_configs()
synthesizes one with generic chart/drivers defaults when it finds these set on an id
that isn't in instruments.json)."""
instrument_id = instrument_id.upper()
saxo_quote_symbol = (saxo_quote_symbol or "").strip().upper() or None
conn = get_conn()
conn.execute(
"INSERT INTO instrument_overrides (instrument_id, name, yf_ticker, category, saxo_quote_symbol, updated_at) "
"VALUES (?, ?, ?, ?, ?, datetime('now')) "
"ON CONFLICT(instrument_id) DO UPDATE SET name = excluded.name, yf_ticker = excluded.yf_ticker, "
"category = excluded.category, saxo_quote_symbol = COALESCE(instrument_overrides.saxo_quote_symbol, excluded.saxo_quote_symbol), "
"updated_at = excluded.updated_at",
(instrument_id, name, yf_ticker, category, saxo_quote_symbol),
)
conn.commit()
conn.close()
# ── Wavelets — saved simulation/optimization runs ─────────────────────────────
def save_wavelet_simulation(name: str, form: Dict, results: Optional[List[Dict]] = None,