"""SQLite table definitions for the paper trading system.""" from __future__ import annotations import sqlite3 from pathlib import Path SCHEMA_SQL = """ CREATE TABLE IF NOT EXISTS sessions ( session_id TEXT PRIMARY KEY, session_name TEXT NOT NULL, config_path TEXT NOT NULL, initial_equity REAL NOT NULL, created_at TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', parking_preset TEXT, idle_alpha_preset TEXT, form4_sleeve_preset TEXT, ownership_sleeve_preset TEXT, risk_off_alpha_sleeve_preset TEXT ); CREATE TABLE IF NOT EXISTS strategy_states ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_id TEXT NOT NULL REFERENCES sessions(session_id), symbol TEXT NOT NULL, event_id TEXT NOT NULL, engine_id TEXT NOT NULL DEFAULT 'default', order_id TEXT, entry_date TEXT NOT NULL, stop_price REAL NOT NULL, target_price REAL NOT NULL, current_stop REAL NOT NULL, peak_price REAL NOT NULL, days_held INTEGER NOT NULL DEFAULT 0, trade_direction TEXT NOT NULL DEFAULT 'long', candidate_json TEXT NOT NULL, plan_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'open', UNIQUE(session_id, symbol, status) ); CREATE TABLE IF NOT EXISTS session_state ( session_id TEXT PRIMARY KEY REFERENCES sessions(session_id), consecutive_losses INTEGER NOT NULL DEFAULT 0, cooldown_remaining INTEGER NOT NULL DEFAULT 0, kill_switch_triggered INTEGER NOT NULL DEFAULT 0, daily_new_risk_used REAL NOT NULL DEFAULT 0.0, last_processed_date TEXT ); CREATE TABLE IF NOT EXISTS processed_events ( session_id TEXT NOT NULL, event_id TEXT NOT NULL, processed_date TEXT NOT NULL, action TEXT NOT NULL, skip_reason TEXT, PRIMARY KEY (session_id, event_id) ); CREATE TABLE IF NOT EXISTS trades ( trade_id TEXT PRIMARY KEY, session_id TEXT NOT NULL, symbol TEXT NOT NULL, engine_id TEXT, capital_bucket_id TEXT, entry_date TEXT, exit_date TEXT, entry_price REAL, exit_price REAL, exit_reason TEXT, shares INTEGER, net_pnl REAL, r_multiple REAL, holding_days INTEGER ); CREATE TABLE IF NOT EXISTS daily_snapshots ( session_id TEXT NOT NULL, date TEXT NOT NULL, equity REAL NOT NULL, cash REAL NOT NULL, market_value REAL NOT NULL, daily_pnl REAL, total_pnl REAL, drawdown_pct REAL, open_position_count INTEGER, PRIMARY KEY (session_id, date) ); CREATE TABLE IF NOT EXISTS processed_dates ( session_id TEXT NOT NULL, date TEXT NOT NULL, PRIMARY KEY (session_id, date) ); CREATE TABLE IF NOT EXISTS processed_phases ( session_id TEXT NOT NULL, date TEXT NOT NULL, phase TEXT NOT NULL, PRIMARY KEY (session_id, date, phase) ); CREATE TABLE IF NOT EXISTS parking_state ( session_id TEXT PRIMARY KEY REFERENCES sessions(session_id), symbol TEXT NOT NULL, entry_date TEXT NOT NULL, qty INTEGER NOT NULL, avg_price REAL NOT NULL, entry_value REAL NOT NULL, status TEXT NOT NULL DEFAULT 'active', peak_price REAL NOT NULL DEFAULT 0, gate_in_sgov INTEGER NOT NULL DEFAULT 0, committed_target TEXT NOT NULL DEFAULT '', pending_target TEXT NOT NULL DEFAULT '', pending_days INTEGER NOT NULL DEFAULT 0, sgov_entry_value REAL NOT NULL DEFAULT 0, sold_today INTEGER NOT NULL DEFAULT 0, overlay_brake_cooldown INTEGER NOT NULL DEFAULT 0, overlay_hold_days INTEGER NOT NULL DEFAULT 0 ); """ def create_schema(db_path: str | Path) -> None: """Initialize the SQLite database with the paper trading schema.""" conn = sqlite3.connect(str(db_path)) try: conn.executescript(SCHEMA_SQL) # Migration: add parking_preset column to existing databases try: conn.execute("ALTER TABLE sessions ADD COLUMN parking_preset TEXT") conn.commit() except Exception: pass # column already exists try: conn.execute("ALTER TABLE sessions ADD COLUMN idle_alpha_preset TEXT") conn.commit() except Exception: pass # column already exists try: conn.execute("ALTER TABLE sessions ADD COLUMN form4_sleeve_preset TEXT") conn.commit() except Exception: pass # column already exists try: conn.execute("ALTER TABLE sessions ADD COLUMN ownership_sleeve_preset TEXT") conn.commit() except Exception: pass # column already exists try: conn.execute("ALTER TABLE sessions ADD COLUMN risk_off_alpha_sleeve_preset TEXT") conn.commit() except Exception: pass # column already exists # Migration: add parking_state columns for v2 (top-up, hysteresis, etc.) for col, dtype, default in [ ("peak_price", "REAL", "0"), ("gate_in_sgov", "INTEGER", "0"), ("committed_target", "TEXT", "''"), ("pending_target", "TEXT", "''"), ("pending_days", "INTEGER", "0"), ("sgov_entry_value", "REAL", "0"), ("sold_today", "INTEGER", "0"), ("overlay_brake_cooldown", "INTEGER", "0"), ("overlay_hold_days", "INTEGER", "0"), ]: try: conn.execute(f"ALTER TABLE parking_state ADD COLUMN {col} {dtype} NOT NULL DEFAULT {default}") conn.commit() except Exception: pass for col, dtype in [ ("engine_id", "TEXT"), ("capital_bucket_id", "TEXT"), ]: try: conn.execute(f"ALTER TABLE trades ADD COLUMN {col} {dtype}") conn.commit() except Exception: pass finally: conn.close()