You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.4 KiB
Python

"""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
);
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
);
"""
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
# 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"),
]:
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()