feat: cockpit
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user