feat: cockpit
This commit is contained in:
@@ -274,6 +274,19 @@ def init_db():
|
||||
horizon_days INTEGER,
|
||||
indicators_json TEXT DEFAULT '{}'
|
||||
)""",
|
||||
# Instrument Analysis — per-instrument overrides (Saxo quote link, custom drivers)
|
||||
# that must survive a deploy. backend/config/instruments.json is baked into the
|
||||
# Docker image and gets reset to its git-tracked contents on every
|
||||
# `docker compose up --build` (deploy/update.sh) — see project_saxo_quote_source
|
||||
# memory. Merged on top of the static instruments.json catalog at read time by
|
||||
# services/instrument_service.py, same pattern as instruments_watchlist's
|
||||
# saxo_quote_symbol column (already SQLite-backed, already durable).
|
||||
"""CREATE TABLE IF NOT EXISTS instrument_overrides (
|
||||
instrument_id TEXT PRIMARY KEY,
|
||||
saxo_quote_symbol TEXT,
|
||||
drivers_json TEXT,
|
||||
updated_at TEXT DEFAULT (datetime('now'))
|
||||
)""",
|
||||
]:
|
||||
try:
|
||||
c.execute(_sql)
|
||||
@@ -3388,6 +3401,49 @@ def rename_instrument_watchlist(ticker: str, name: str) -> bool:
|
||||
return changed
|
||||
|
||||
|
||||
# ── Instrument Analysis overrides — Saxo link + drivers, kept in SQLite (survives a ──
|
||||
# ── deploy rebuild, unlike backend/config/instruments.json which is baked into the image)
|
||||
|
||||
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."""
|
||||
conn = get_conn()
|
||||
rows = conn.execute("SELECT instrument_id, saxo_quote_symbol, drivers_json 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,
|
||||
}
|
||||
return out
|
||||
|
||||
|
||||
def set_instrument_override_saxo_symbol(instrument_id: str, saxo_symbol: Optional[str]) -> None:
|
||||
instrument_id = instrument_id.upper()
|
||||
saxo_symbol = (saxo_symbol or "").strip().upper() or None
|
||||
conn = get_conn()
|
||||
conn.execute(
|
||||
"INSERT INTO instrument_overrides (instrument_id, saxo_quote_symbol, updated_at) VALUES (?, ?, datetime('now')) "
|
||||
"ON CONFLICT(instrument_id) DO UPDATE SET saxo_quote_symbol = excluded.saxo_quote_symbol, updated_at = excluded.updated_at",
|
||||
(instrument_id, saxo_symbol),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def set_instrument_override_drivers(instrument_id: str, drivers: List[Dict]) -> None:
|
||||
instrument_id = instrument_id.upper()
|
||||
conn = get_conn()
|
||||
conn.execute(
|
||||
"INSERT INTO instrument_overrides (instrument_id, drivers_json, updated_at) VALUES (?, ?, datetime('now')) "
|
||||
"ON CONFLICT(instrument_id) DO UPDATE SET drivers_json = excluded.drivers_json, updated_at = excluded.updated_at",
|
||||
(instrument_id, json.dumps(drivers)),
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
# ── Wavelets — saved simulation/optimization runs ─────────────────────────────
|
||||
|
||||
def save_wavelet_simulation(name: str, form: Dict, results: Optional[List[Dict]] = None,
|
||||
|
||||
Reference in New Issue
Block a user