140 lines
4.8 KiB
Python
140 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
|
|
from backend.database.migrations.runner import Migration
|
|
|
|
|
|
def upgrade(connection: sqlite3.Connection) -> None:
|
|
statements = (
|
|
"""
|
|
CREATE TABLE screener_factor_snapshots (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
trade_date TEXT NOT NULL,
|
|
version TEXT NOT NULL,
|
|
observed_at TEXT NOT NULL,
|
|
state TEXT NOT NULL CHECK (state IN ('final', 'archive')),
|
|
source_set_json TEXT NOT NULL,
|
|
coverage_json TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
UNIQUE (trade_date, version)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE screener_factor_values (
|
|
snapshot_id INTEGER NOT NULL
|
|
REFERENCES screener_factor_snapshots(id) ON DELETE CASCADE,
|
|
identifier TEXT NOT NULL,
|
|
code TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
sector TEXT,
|
|
listed_days INTEGER NOT NULL,
|
|
is_st INTEGER NOT NULL CHECK (is_st IN (0, 1)),
|
|
payload_json TEXT NOT NULL,
|
|
PRIMARY KEY (snapshot_id, identifier)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE screener_runs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
owner_user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
|
mode TEXT NOT NULL CHECK (mode IN ('stage', 'curated', 'custom')),
|
|
strategy_id TEXT NOT NULL,
|
|
strategy_name TEXT NOT NULL,
|
|
strategy_version INTEGER NOT NULL,
|
|
selection_date TEXT NOT NULL,
|
|
factor_snapshot_id INTEGER NOT NULL
|
|
REFERENCES screener_factor_snapshots(id) ON DELETE RESTRICT,
|
|
status TEXT NOT NULL CHECK (
|
|
status IN (
|
|
'pending', 'running', 'completed', 'no_signal',
|
|
'data_incomplete', 'failed'
|
|
)
|
|
),
|
|
started_at TEXT,
|
|
completed_at TEXT,
|
|
coverage REAL NOT NULL DEFAULT 0 CHECK (coverage >= 0 AND coverage <= 1),
|
|
missing_fields_json TEXT NOT NULL DEFAULT '[]',
|
|
result_json TEXT NOT NULL DEFAULT '[]',
|
|
error_message TEXT NOT NULL DEFAULT ''
|
|
)
|
|
""",
|
|
"""
|
|
CREATE UNIQUE INDEX screener_runs_idempotency_idx ON screener_runs (
|
|
mode, strategy_id, selection_date, strategy_version,
|
|
factor_snapshot_id, COALESCE(owner_user_id, 0)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE custom_screener_strategies (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
version INTEGER NOT NULL DEFAULT 1,
|
|
formula_json TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE (user_id, name)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE strategy_tracks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
run_id INTEGER NOT NULL REFERENCES screener_runs(id) ON DELETE CASCADE,
|
|
identifier TEXT NOT NULL,
|
|
code TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
sector TEXT,
|
|
selection_date TEXT NOT NULL,
|
|
strategy_name TEXT NOT NULL,
|
|
entry_price REAL NOT NULL CHECK (entry_price > 0),
|
|
added_at TEXT NOT NULL,
|
|
UNIQUE (user_id, run_id, identifier)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE strategy_track_bars (
|
|
track_id INTEGER NOT NULL REFERENCES strategy_tracks(id) ON DELETE CASCADE,
|
|
trade_date TEXT NOT NULL,
|
|
open REAL NOT NULL,
|
|
high REAL NOT NULL,
|
|
low REAL NOT NULL,
|
|
close REAL NOT NULL,
|
|
PRIMARY KEY (track_id, trade_date)
|
|
)
|
|
""",
|
|
"""
|
|
CREATE TABLE strategy_track_events (
|
|
track_id INTEGER NOT NULL REFERENCES strategy_tracks(id) ON DELETE CASCADE,
|
|
milestone TEXT NOT NULL CHECK (milestone IN ('t1', 't5')),
|
|
created_at TEXT NOT NULL,
|
|
PRIMARY KEY (track_id, milestone)
|
|
)
|
|
""",
|
|
)
|
|
for statement in statements:
|
|
connection.execute(statement)
|
|
|
|
|
|
def downgrade(connection: sqlite3.Connection) -> None:
|
|
for table in (
|
|
"strategy_track_events",
|
|
"strategy_track_bars",
|
|
"strategy_tracks",
|
|
"custom_screener_strategies",
|
|
"screener_runs",
|
|
"screener_factor_values",
|
|
"screener_factor_snapshots",
|
|
):
|
|
connection.execute(f"DROP TABLE {table}")
|
|
|
|
|
|
MIGRATION = Migration(
|
|
version=7,
|
|
name="create_deterministic_screener",
|
|
signature="screener:v1:factors-runs-custom-tracking",
|
|
upgrade=upgrade,
|
|
downgrade=downgrade,
|
|
)
|