refactor(schema): split persistence schema — core GA + strategy_crypto paper

- multi_swarm_core/persistence/schema.py: rimuove tabelle paper_trading_*
  (5 CREATE TABLE + 3 indici idx_paper_*). Restano solo le tabelle GA universali
  (runs, generations, genomes, evaluations, cost_records, adversarial_findings).
- strategy_crypto/backend/schema.py NEW: PAPER_SCHEMA_SQL standalone + init_schema()
  con mkdir parent, scrive su state/strategy_crypto.db.

Ownership: ogni strategia possiede il proprio schema, isolato dal core.
Pattern replicabile per strategy_forex, strategy_equity, ecc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal Pastro
2026-05-15 17:46:50 +00:00
parent cd4c3131d9
commit 08f1585ab2
2 changed files with 86 additions and 61 deletions
@@ -77,68 +77,7 @@ CREATE TABLE IF NOT EXISTS adversarial_findings (
FOREIGN KEY (run_id) REFERENCES runs(id) FOREIGN KEY (run_id) REFERENCES runs(id)
); );
CREATE TABLE IF NOT EXISTS paper_trading_runs (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
started_at TEXT NOT NULL,
stopped_at TEXT,
status TEXT NOT NULL DEFAULT 'running',
initial_capital REAL NOT NULL,
config_json TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS paper_trading_positions (
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
qty REAL NOT NULL,
entry_price REAL NOT NULL,
entry_ts TEXT NOT NULL,
PRIMARY KEY (paper_run_id, symbol),
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
qty REAL NOT NULL,
entry_price REAL NOT NULL,
exit_price REAL NOT NULL,
entry_ts TEXT NOT NULL,
exit_ts TEXT NOT NULL,
pnl REAL NOT NULL,
fees REAL NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_equity (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
ts TEXT NOT NULL,
equity REAL NOT NULL,
cash REAL NOT NULL,
positions_value REAL NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_ticks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
ts TEXT NOT NULL,
bar_ts TEXT NOT NULL,
close_price REAL NOT NULL,
signal TEXT NOT NULL,
action_taken TEXT NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE INDEX IF NOT EXISTS idx_evaluations_fitness ON evaluations(run_id, fitness DESC); CREATE INDEX IF NOT EXISTS idx_evaluations_fitness ON evaluations(run_id, fitness DESC);
CREATE INDEX IF NOT EXISTS idx_genomes_generation ON genomes(run_id, generation_idx); CREATE INDEX IF NOT EXISTS idx_genomes_generation ON genomes(run_id, generation_idx);
CREATE INDEX IF NOT EXISTS idx_cost_run ON cost_records(run_id); CREATE INDEX IF NOT EXISTS idx_cost_run ON cost_records(run_id);
CREATE INDEX IF NOT EXISTS idx_paper_trades_run ON paper_trading_trades(paper_run_id, exit_ts);
CREATE INDEX IF NOT EXISTS idx_paper_equity_run ON paper_trading_equity(paper_run_id, ts);
CREATE INDEX IF NOT EXISTS idx_paper_ticks_run ON paper_trading_ticks(paper_run_id, ts);
""" """
@@ -0,0 +1,86 @@
"""Schema SQLite per le tabelle paper-trading della strategia crypto.
Owned dal member strategy_crypto: il DDL e' standalone rispetto al core,
e scrive su un database dedicato (state/strategy_crypto.db) separato dal
runs.db del core GA. Pattern replicabile per future strategie.
"""
from __future__ import annotations
import sqlite3
from pathlib import Path
PAPER_SCHEMA_SQL = """
CREATE TABLE IF NOT EXISTS paper_trading_runs (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
started_at TEXT NOT NULL,
stopped_at TEXT,
status TEXT NOT NULL DEFAULT 'running',
initial_capital REAL NOT NULL,
config_json TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS paper_trading_positions (
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
qty REAL NOT NULL,
entry_price REAL NOT NULL,
entry_ts TEXT NOT NULL,
PRIMARY KEY (paper_run_id, symbol),
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_trades (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
qty REAL NOT NULL,
entry_price REAL NOT NULL,
exit_price REAL NOT NULL,
entry_ts TEXT NOT NULL,
exit_ts TEXT NOT NULL,
pnl REAL NOT NULL,
fees REAL NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_equity (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
ts TEXT NOT NULL,
equity REAL NOT NULL,
cash REAL NOT NULL,
positions_value REAL NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE TABLE IF NOT EXISTS paper_trading_ticks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
paper_run_id TEXT NOT NULL,
symbol TEXT NOT NULL,
ts TEXT NOT NULL,
bar_ts TEXT NOT NULL,
close_price REAL NOT NULL,
signal TEXT NOT NULL,
action_taken TEXT NOT NULL,
FOREIGN KEY (paper_run_id) REFERENCES paper_trading_runs(id)
);
CREATE INDEX IF NOT EXISTS idx_paper_trades_run ON paper_trading_trades(paper_run_id, exit_ts);
CREATE INDEX IF NOT EXISTS idx_paper_equity_run ON paper_trading_equity(paper_run_id, ts);
CREATE INDEX IF NOT EXISTS idx_paper_ticks_run ON paper_trading_ticks(paper_run_id, ts);
"""
def init_schema(db_path: Path | str) -> None:
"""Crea (se mancanti) le tabelle paper_trading_* sul db indicato."""
Path(db_path).parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(str(db_path))
try:
conn.executescript(PAPER_SCHEMA_SQL)
conn.commit()
finally:
conn.close()