Saxo connector

This commit is contained in:
OpenSquared
2026-07-18 17:14:13 +02:00
parent 91054979ec
commit bff2f70781
10 changed files with 826 additions and 2 deletions

View File

@@ -44,6 +44,36 @@ def init_db():
created_at TEXT DEFAULT (datetime('now'))
)""")
c.execute("""CREATE TABLE IF NOT EXISTS saxo_auth (
id INTEGER PRIMARY KEY CHECK (id = 1),
access_token TEXT,
refresh_token TEXT,
expires_at TEXT,
refresh_expires_at TEXT,
environment TEXT DEFAULT 'sim',
updated_at TEXT DEFAULT (datetime('now'))
)""")
c.execute("""CREATE TABLE IF NOT EXISTS saxo_option_snapshots (
id TEXT PRIMARY KEY,
symbol TEXT NOT NULL,
snapshot_date TEXT NOT NULL,
spot REAL,
expiry_date TEXT NOT NULL,
strike REAL NOT NULL,
option_type TEXT NOT NULL,
bid REAL,
ask REAL,
mid REAL,
volatility_pct REAL,
delta REAL,
gamma REAL,
theta REAL,
vega REAL,
created_at TEXT DEFAULT (datetime('now'))
)""")
c.execute("CREATE INDEX IF NOT EXISTS idx_saxo_snap_symbol_date ON saxo_option_snapshots(symbol, snapshot_date)")
c.execute("""CREATE TABLE IF NOT EXISTS strategy_scenarios (
id TEXT PRIMARY KEY,
symbol TEXT NOT NULL,
@@ -6017,3 +6047,72 @@ def delete_saved_strategy(strategy_id: str) -> bool:
deleted = cur.rowcount > 0
conn.close()
return deleted
# ── Saxo OpenAPI: OAuth tokens & option snapshots ─────────────────────────────
def save_saxo_tokens(access_token: str, refresh_token: str, expires_at: str, refresh_expires_at: str, environment: str = "sim"):
conn = get_conn()
conn.execute("""INSERT INTO saxo_auth (id, access_token, refresh_token, expires_at, refresh_expires_at, environment, updated_at)
VALUES (1, ?, ?, ?, ?, ?, datetime('now'))
ON CONFLICT(id) DO UPDATE SET
access_token=excluded.access_token, refresh_token=excluded.refresh_token,
expires_at=excluded.expires_at, refresh_expires_at=excluded.refresh_expires_at,
environment=excluded.environment, updated_at=datetime('now')""",
(access_token, refresh_token, expires_at, refresh_expires_at, environment))
conn.commit()
conn.close()
def get_saxo_tokens() -> Optional[Dict[str, Any]]:
conn = get_conn()
row = conn.execute("SELECT * FROM saxo_auth WHERE id=1").fetchone()
conn.close()
return dict(row) if row else None
def clear_saxo_tokens():
conn = get_conn()
conn.execute("DELETE FROM saxo_auth WHERE id=1")
conn.commit()
conn.close()
def save_saxo_snapshot_rows(rows: List[Dict[str, Any]]):
if not rows:
return
import uuid
conn = get_conn()
conn.executemany("""INSERT INTO saxo_option_snapshots (
id, symbol, snapshot_date, spot, expiry_date, strike, option_type,
bid, ask, mid, volatility_pct, delta, gamma, theta, vega
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)""", [
(
f"SNAP-{uuid.uuid4().hex[:12]}",
r["symbol"], r["snapshot_date"], r.get("spot"), r["expiry_date"], r["strike"], r["option_type"],
r.get("bid"), r.get("ask"), r.get("mid"), r.get("volatility_pct"),
r.get("delta"), r.get("gamma"), r.get("theta"), r.get("vega"),
)
for r in rows
])
conn.commit()
conn.close()
def get_saxo_snapshots(symbol: Optional[str] = None, date_from: Optional[str] = None, date_to: Optional[str] = None) -> List[Dict[str, Any]]:
conn = get_conn()
query = "SELECT * FROM saxo_option_snapshots WHERE 1=1"
params: List[Any] = []
if symbol:
query += " AND symbol=?"
params.append(symbol)
if date_from:
query += " AND snapshot_date>=?"
params.append(date_from)
if date_to:
query += " AND snapshot_date<=?"
params.append(date_to)
query += " ORDER BY snapshot_date DESC, expiry_date, strike LIMIT 5000"
rows = conn.execute(query, params).fetchall()
conn.close()
return [dict(r) for r in rows]