Files
momentum-system/storage/schema.py
T
momentum devandClaude Opus 4.8 007cd95c79 Baseline before Postgres migration (WS0)
Snapshot before the DuckDB->PostgreSQL migration. data/, archive/, the 232MB
rebuild zip, the Windows .venv, and .env are excluded via .gitignore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 23:39:29 -04:00

445 lines
12 KiB
Python

"""DuckDB schema definitions for all tables.
Milestone 1, Task 1.1
"""
SCHEMA_SQL = """
-- Symbols: universe metadata
CREATE TABLE IF NOT EXISTS symbols (
symbol VARCHAR PRIMARY KEY,
security_name VARCHAR,
exchange VARCHAR,
asset_type VARCHAR DEFAULT 'common_stock',
sector VARCHAR,
industry VARCHAR,
shares_outstanding BIGINT,
float_shares BIGINT,
market_cap DOUBLE,
is_etf BOOLEAN DEFAULT FALSE,
is_otc BOOLEAN DEFAULT FALSE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT current_timestamp,
updated_at TIMESTAMP DEFAULT current_timestamp
);
-- Trading days: market calendar
CREATE TABLE IF NOT EXISTS trading_days (
trade_date DATE PRIMARY KEY,
session_open TIMESTAMP,
session_close TIMESTAMP,
premarket_open TIMESTAMP,
afterhours_close TIMESTAMP,
is_half_day BOOLEAN DEFAULT FALSE,
is_holiday_adjacent BOOLEAN DEFAULT FALSE,
tape_regime VARCHAR, -- strong / neutral / weak
market_regime VARCHAR, -- bull / neutral / bear
volatility_regime VARCHAR, -- low / medium / high
gap_activity_level INTEGER,
momentum_density INTEGER
);
-- Daily bars
CREATE TABLE IF NOT EXISTS daily_bars (
symbol VARCHAR,
trade_date DATE,
open DOUBLE,
high DOUBLE,
low DOUBLE,
close DOUBLE,
volume BIGINT,
vwap DOUBLE,
previous_close DOUBLE,
true_range DOUBLE,
atr_14 DOUBLE,
rolling_avg_volume_20d DOUBLE,
rolling_avg_volume_50d DOUBLE,
prior_day_gain_pct DOUBLE,
multi_day_runner_flag BOOLEAN DEFAULT FALSE,
PRIMARY KEY (symbol, trade_date)
);
-- Minute bars
CREATE TABLE IF NOT EXISTS minute_bars (
symbol VARCHAR,
timestamp TIMESTAMP,
session_date DATE,
is_premarket BOOLEAN,
is_regular_hours BOOLEAN,
is_afterhours BOOLEAN,
open DOUBLE,
high DOUBLE,
low DOUBLE,
close DOUBLE,
volume BIGINT,
vwap DOUBLE,
spread_pct DOUBLE,
halt_status BOOLEAN DEFAULT FALSE,
source_provider VARCHAR DEFAULT 'synthetic',
quality_score DOUBLE,
PRIMARY KEY (symbol, timestamp)
);
-- News / catalyst events
CREATE TABLE IF NOT EXISTS news_events (
id VARCHAR,
symbol VARCHAR,
headline VARCHAR,
source VARCHAR,
published_at TIMESTAMP,
catalyst_freshness_minutes DOUBLE,
category VARCHAR,
sentiment DOUBLE,
is_earnings BOOLEAN DEFAULT FALSE,
is_offering BOOLEAN DEFAULT FALSE,
is_halt_related BOOLEAN DEFAULT FALSE,
PRIMARY KEY (id)
);
-- Halt events
CREATE TABLE IF NOT EXISTS halt_events (
id VARCHAR,
symbol VARCHAR,
halt_start TIMESTAMP,
halt_end TIMESTAMP,
halt_type VARCHAR,
price_at_halt DOUBLE,
resumed_price DOUBLE,
gap_on_resume_pct DOUBLE,
PRIMARY KEY (id)
);
-- Market context (SPY/QQQ/VIX)
CREATE TABLE IF NOT EXISTS market_context (
timestamp TIMESTAMP,
trade_date DATE,
spy_open DOUBLE,
spy_high DOUBLE,
spy_low DOUBLE,
spy_close DOUBLE,
spy_volume BIGINT,
qqq_open DOUBLE,
qqq_close DOUBLE,
spy_intraday_return_pct DOUBLE,
vix_open DOUBLE,
vix_level DOUBLE,
advance_decline_ratio DOUBLE,
up_volume_down_volume_ratio DOUBLE,
tape_regime_flag VARCHAR,
PRIMARY KEY (timestamp)
);
-- Dilution / offering events
CREATE TABLE IF NOT EXISTS dilution_events (
id VARCHAR PRIMARY KEY,
symbol VARCHAR,
event_type VARCHAR,
announced_at TIMESTAMP,
effective_date DATE,
share_count BIGINT,
price_per_share DOUBLE,
gross_proceeds DOUBLE
);
-- Short interest history
CREATE TABLE IF NOT EXISTS short_interest (
symbol VARCHAR,
report_date DATE,
short_interest_shares BIGINT,
short_interest_pct_float DOUBLE,
days_to_cover DOUBLE,
PRIMARY KEY (symbol, report_date)
);
-- Versioned feature rows
CREATE TABLE IF NOT EXISTS engineered_features (
id VARCHAR PRIMARY KEY,
timestamp TIMESTAMP,
symbol VARCHAR,
session_date DATE,
feature_version VARCHAR,
gap_pct DOUBLE,
premarket_gap_pct DOUBLE,
relative_volume DOUBLE,
time_of_day_adjusted_relative_volume DOUBLE,
float_rotation_pct DOUBLE,
vwap DOUBLE,
distance_from_vwap DOUBLE,
ema9 DOUBLE,
ema20 DOUBLE,
pullback_volume_ratio DOUBLE,
pullback_candle_type VARCHAR,
catalyst_freshness_minutes DOUBLE,
catalyst_type VARCHAR,
tape_regime VARCHAR,
spy_intraday_return DOUBLE,
vix_level DOUBLE,
metadata_json VARCHAR
);
-- Setup events
CREATE TABLE IF NOT EXISTS setup_events (
setup_id VARCHAR PRIMARY KEY,
symbol VARCHAR,
setup_time TIMESTAMP,
session_date DATE,
setup_name VARCHAR DEFAULT 'first_pullback',
setup_version VARCHAR DEFAULT 'v1',
entry_reference_price DOUBLE,
invalidation_price DOUBLE,
target_r_multiple DOUBLE DEFAULT 2.0,
impulse_start_price DOUBLE,
impulse_end_price DOUBLE,
impulse_pct DOUBLE,
pullback_low DOUBLE,
pullback_depth_pct DOUBLE,
pullback_bars INTEGER,
pullback_volume_ratio DOUBLE,
above_vwap_flag BOOLEAN,
vwap_at_trigger DOUBLE,
gap_pct DOUBLE,
relative_volume DOUBLE,
float_rotation_at_trigger DOUBLE,
catalyst_freshness_at_trigger DOUBLE,
session_minute_number INTEGER,
tape_regime_at_trigger VARCHAR,
spy_intraday_return_pct_at_trigger DOUBLE
);
-- Outcome labels
CREATE TABLE IF NOT EXISTS outcome_labels (
setup_id VARCHAR PRIMARY KEY,
label_version VARCHAR DEFAULT 'v1',
max_upside_next_5m DOUBLE,
max_upside_next_15m DOUBLE,
max_upside_next_60m DOUBLE,
max_drawdown_next_5m DOUBLE,
max_drawdown_next_15m DOUBLE,
max_drawdown_next_60m DOUBLE,
reached_1r_before_minus_1r BOOLEAN,
reached_2r_before_minus_1r BOOLEAN,
held_vwap_5m BOOLEAN,
held_vwap_15m BOOLEAN,
trend_day_flag BOOLEAN,
failed_breakout_flag BOOLEAN,
time_to_max_upside_minutes DOUBLE,
time_to_max_drawdown_minutes DOUBLE
);
-- Backtest runs
CREATE TABLE IF NOT EXISTS backtest_runs (
run_id VARCHAR PRIMARY KEY,
run_timestamp TIMESTAMP,
strategy_name VARCHAR,
strategy_version VARCHAR,
feature_version VARCHAR,
date_range_start DATE,
date_range_end DATE,
parameter_config_json VARCHAR,
summary_metrics_json VARCHAR,
total_trades INTEGER,
win_rate DOUBLE,
expectancy DOUBLE,
max_drawdown DOUBLE,
profit_factor DOUBLE
);
-- Simulated orders for paper trading
CREATE TABLE IF NOT EXISTS simulated_orders (
order_id VARCHAR PRIMARY KEY,
session_id VARCHAR,
symbol VARCHAR,
created_at TIMESTAMP,
side VARCHAR,
order_type VARCHAR,
qty INTEGER,
intended_entry DOUBLE,
stop_price DOUBLE,
target_price DOUBLE,
status VARCHAR,
strategy_name VARCHAR,
setup_id VARCHAR
);
-- Simulated fills for paper trading
CREATE TABLE IF NOT EXISTS simulated_fills (
fill_id VARCHAR PRIMARY KEY,
order_id VARCHAR,
symbol VARCHAR,
fill_time TIMESTAMP,
fill_price DOUBLE,
qty INTEGER,
slippage DOUBLE,
commission DOUBLE,
venue VARCHAR
);
-- Strategy run metadata for paper/live sessions
CREATE TABLE IF NOT EXISTS strategy_runs (
run_id VARCHAR PRIMARY KEY,
started_at TIMESTAMP,
ended_at TIMESTAMP,
mode VARCHAR,
strategy_name VARCHAR,
strategy_version VARCHAR,
config_json VARCHAR,
summary_json VARCHAR
);
-- Daily paper trading session records
CREATE TABLE IF NOT EXISTS paper_sessions (
session_id VARCHAR PRIMARY KEY,
trade_date DATE,
started_at TIMESTAMP,
ended_at TIMESTAMP,
starting_equity DOUBLE,
ending_equity DOUBLE,
realized_pnl DOUBLE,
unrealized_pnl DOUBLE,
total_orders INTEGER,
total_fills INTEGER,
total_setups INTEGER,
notes VARCHAR
);
-- Live paper-trade missed-window / late-entry audit rows
CREATE TABLE IF NOT EXISTS paper_missed_trades (
audit_id VARCHAR PRIMARY KEY,
session_id VARCHAR,
symbol VARCHAR,
setup_id VARCHAR,
reason VARCHAR,
setup_time TIMESTAMP,
evaluated_at TIMESTAMP,
attempted_entry_time TIMESTAMP,
entry_cutoff VARCHAR,
minutes_past_cutoff DOUBLE,
success_score_pct DOUBLE,
criteria_passed INTEGER,
criteria_total INTEGER,
provider_status VARCHAR,
provider_degraded_count INTEGER,
source_status VARCHAR,
source_degraded_count INTEGER,
source_backoff_count INTEGER,
created_at TIMESTAMP,
details_json VARCHAR
);
-- Raw landing: one row per source+window fetch attempt (append-only)
CREATE TABLE IF NOT EXISTS raw_fetch_attempts (
id VARCHAR PRIMARY KEY,
source VARCHAR NOT NULL,
capability VARCHAR NOT NULL,
request_window_start TIMESTAMP,
request_window_end TIMESTAMP,
fetched_at TIMESTAMP NOT NULL,
ingest_run_id VARCHAR,
http_status INTEGER,
item_count INTEGER,
error_msg VARCHAR,
payload_hash VARCHAR,
parser_version VARCHAR
);
-- Raw landing: one row per raw news item (append-only)
CREATE TABLE IF NOT EXISTS raw_news_items (
id VARCHAR PRIMARY KEY,
fetch_attempt_id VARCHAR,
source VARCHAR,
raw_url VARCHAR,
raw_title VARCHAR,
raw_published_at VARCHAR,
raw_body_snippet VARCHAR,
raw_tickers VARCHAR,
payload_hash VARCHAR,
parser_version VARCHAR,
fetched_at TIMESTAMP,
ingest_run_id VARCHAR
);
-- Telemetry events: structured observability for fetch attempts, state transitions, enrichment outcomes
CREATE TABLE IF NOT EXISTS telemetry_events (
id VARCHAR PRIMARY KEY,
event_type VARCHAR,
session_id VARCHAR,
symbol VARCHAR,
source VARCHAR,
from_state VARCHAR,
to_state VARCHAR,
reason VARCHAR,
metadata_json VARCHAR,
created_at TIMESTAMP DEFAULT current_timestamp
);
-- Scanner Snapshots - Full scan state for historical tracking
CREATE TABLE IF NOT EXISTS scanner_snapshots (
id VARCHAR PRIMARY KEY,
snapshot_time TIMESTAMP,
symbol VARCHAR,
rank INTEGER,
price DOUBLE,
gap_pct DOUBLE,
premarket_gap_pct DOUBLE,
cumulative_volume BIGINT,
minute_volume BIGINT,
premarket_volume BIGINT,
relative_volume DOUBLE,
float_rotation_pct DOUBLE,
vwap DOUBLE,
distance_from_vwap DOUBLE,
ema9 DOUBLE,
ema20 DOUBLE,
intraday_range DOUBLE,
intraday_range_vs_atr DOUBLE,
distance_to_premarket_high DOUBLE,
distance_to_premarket_low DOUBLE,
distance_to_day_high DOUBLE,
distance_to_day_low DOUBLE,
news_flag BOOLEAN,
catalyst_freshness_minutes DOUBLE,
catalyst_type VARCHAR,
float_bucket VARCHAR,
market_cap_bucket VARCHAR,
spread_pct DOUBLE,
halt_flag BOOLEAN,
dilution_risk_flag BOOLEAN,
sympathy_move_candidate_flag BOOLEAN,
lead_runner_symbol VARCHAR,
sympathy_cluster_id VARCHAR,
early_leader_flag BOOLEAN,
rank_stability DOUBLE,
momentum_score DOUBLE,
scanner_version VARCHAR
);
"""
def create_schema(con) -> None:
"""Create all tables in the DuckDB connection."""
for statement in SCHEMA_SQL.split(";"):
stmt = statement.strip()
if stmt:
con.execute(stmt)
con.execute(
"ALTER TABLE setup_events ADD COLUMN IF NOT EXISTS tape_regime_at_trigger VARCHAR"
)
con.execute(
"ALTER TABLE setup_events ADD COLUMN IF NOT EXISTS spy_intraday_return_pct_at_trigger DOUBLE"
)
con.execute(
"CREATE INDEX IF NOT EXISTS idx_raw_fetch_attempts_source_window "
"ON raw_fetch_attempts (source, capability, request_window_start, request_window_end)"
)
con.execute(
"CREATE INDEX IF NOT EXISTS idx_raw_fetch_attempts_ingest_run "
"ON raw_fetch_attempts (ingest_run_id)"
)
con.execute(
"CREATE INDEX IF NOT EXISTS idx_raw_news_items_fetch_attempt "
"ON raw_news_items (fetch_attempt_id)"
)
con.execute(
"CREATE INDEX IF NOT EXISTS idx_raw_news_items_source_published "
"ON raw_news_items (source, raw_published_at)"
)