Spaces:
Running
Running
| -- ============================================================ | |
| -- Stock Signal SQLite Schema | |
| -- Consolidated schema | |
| -- | |
| -- This replaces the older schema.sql + phase2/phase3/phase4 | |
| -- migration chain for NEW database initialization. | |
| -- | |
| -- Canonical lifecycle: | |
| -- prediction -> resolution -> metrics -> retrain flag | |
| -- ============================================================ | |
| -- ============================================================ | |
| -- 1. PREDICTIONS | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS predictions ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| -- Model / feature provenance | |
| model_version TEXT NOT NULL, | |
| feature_version TEXT NOT NULL, | |
| -- Prediction timing | |
| prediction_date DATE NOT NULL, | |
| prediction_timestamp TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| -- Stock | |
| symbol TEXT NOT NULL, | |
| -- Model output | |
| predicted_probability REAL NOT NULL, | |
| "rank" INTEGER NOT NULL, | |
| -- Target contract | |
| target_threshold REAL NOT NULL DEFAULT 0.03, | |
| target_horizon_days INTEGER NOT NULL DEFAULT 5, | |
| -- Price at prediction time | |
| prediction_close REAL, | |
| -- Resolution / forward evaluation | |
| entry_date DATE, | |
| entry_open REAL, | |
| max_close_5d REAL, | |
| evaluation_end_date DATE, | |
| actual_return REAL, | |
| actual_label INTEGER, | |
| resolved_at TIMESTAMP, | |
| created_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| -- One prediction per symbol/model/date. | |
| CONSTRAINT uq_predictions_date_symbol_model | |
| UNIQUE (prediction_date, symbol, model_version), | |
| CONSTRAINT predictions_probability_check | |
| CHECK ( | |
| predicted_probability >= 0 | |
| AND predicted_probability <= 1 | |
| ), | |
| -- Binary classification target. | |
| CONSTRAINT predictions_actual_label_check | |
| CHECK (actual_label IS NULL OR actual_label IN (0, 1)), | |
| -- Target contract validation. | |
| CONSTRAINT predictions_target_threshold_check | |
| CHECK (target_threshold >= 0), | |
| CONSTRAINT predictions_target_horizon_check | |
| CHECK (target_horizon_days > 0), | |
| -- Rank must be positive. | |
| CONSTRAINT predictions_rank_check | |
| CHECK ("rank" > 0) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_predictions_date | |
| ON predictions (prediction_date); | |
| CREATE INDEX IF NOT EXISTS idx_predictions_symbol | |
| ON predictions (symbol); | |
| CREATE INDEX IF NOT EXISTS idx_predictions_unresolved | |
| ON predictions (prediction_date, symbol) | |
| WHERE actual_label IS NULL; | |
| CREATE INDEX IF NOT EXISTS idx_predictions_resolution | |
| ON predictions (prediction_date, symbol, actual_label); | |
| CREATE INDEX IF NOT EXISTS idx_predictions_model_date | |
| ON predictions (model_version, prediction_date); | |
| -- ============================================================ | |
| -- 2. JOB RUNS | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS job_runs ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| job_name TEXT NOT NULL, | |
| run_date DATE NOT NULL, | |
| started_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| finished_at TIMESTAMP, | |
| status TEXT NOT NULL | |
| CHECK ( | |
| status IN ( | |
| 'RUNNING', | |
| 'SUCCESS', | |
| 'FAILED', | |
| 'SKIPPED' | |
| ) | |
| ), | |
| rows_processed INTEGER NOT NULL DEFAULT 0, | |
| total_rows INTEGER NOT NULL DEFAULT 0, | |
| resolved_rows INTEGER NOT NULL DEFAULT 0, | |
| failed_rows INTEGER NOT NULL DEFAULT 0, | |
| last_updated_at TIMESTAMP, | |
| error_message TEXT | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_job_runs_name_date | |
| ON job_runs (job_name, run_date); | |
| -- Cross-process lease locks for singleton SQLite jobs. The token prevents an | |
| -- expired owner from releasing a newer owner's lease. | |
| CREATE TABLE IF NOT EXISTS job_locks ( | |
| lock_name TEXT PRIMARY KEY, | |
| owner_token TEXT NOT NULL, | |
| locked_until TIMESTAMP NOT NULL | |
| ); | |
| -- ============================================================ | |
| -- 3. PREDICTION METRICS | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS prediction_metrics ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| window_start DATE NOT NULL, | |
| window_end DATE NOT NULL, | |
| prediction_days INTEGER NOT NULL, | |
| resolved_predictions INTEGER NOT NULL, | |
| precision REAL, | |
| pr_auc REAL, | |
| hit_rate REAL, | |
| positive_rate REAL, | |
| average_return REAL, | |
| metrics_json TEXT NOT NULL DEFAULT '{}', | |
| calculated_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| model_version TEXT NOT NULL, | |
| CONSTRAINT prediction_metrics_window_uq | |
| UNIQUE (model_version, window_start, window_end), | |
| CONSTRAINT prediction_metrics_window_ck | |
| CHECK (window_start <= window_end), | |
| CONSTRAINT prediction_metrics_prediction_days_ck | |
| CHECK (prediction_days > 0), | |
| CONSTRAINT prediction_metrics_resolved_ck | |
| CHECK (resolved_predictions >= 0) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_prediction_metrics_window_end | |
| ON prediction_metrics (window_end DESC); | |
| -- ============================================================ | |
| -- 4. RETRAIN FLAGS | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS retrain_flags ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| model_version TEXT NOT NULL, | |
| triggered_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| metric_window_start DATE NOT NULL, | |
| metric_window_end DATE NOT NULL, | |
| baseline_precision REAL NOT NULL, | |
| current_precision REAL NOT NULL, | |
| deterioration REAL NOT NULL, | |
| deterioration_threshold REAL NOT NULL DEFAULT 0.15, | |
| status TEXT NOT NULL DEFAULT 'PENDING' | |
| CHECK ( | |
| status IN ( | |
| 'PENDING', | |
| 'ACKNOWLEDGED', | |
| 'RESOLVED', | |
| 'IGNORED' | |
| ) | |
| ), | |
| reason TEXT NOT NULL, | |
| resolved_at TIMESTAMP, | |
| notes TEXT, | |
| CONSTRAINT retrain_flags_window_uq | |
| UNIQUE (model_version, metric_window_start, metric_window_end) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_retrain_flags_status | |
| ON retrain_flags (status, triggered_at DESC); | |
| -- ============================================================ | |
| -- END OF CONSOLIDATED SCHEMA | |
| -- ============================================================ | |
| -- ============================================================ | |
| -- 5. MARKET DATA REGISTRY AND YFINANCE OHLCV | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS market_tickers ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| symbol TEXT NOT NULL UNIQUE, | |
| yfinance_symbol TEXT NOT NULL UNIQUE, | |
| market TEXT NOT NULL CHECK (market IN ('NSE', 'US', 'CONTEXT')), | |
| name TEXT, | |
| industry TEXT, | |
| active BOOLEAN NOT NULL DEFAULT TRUE, | |
| created_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| updated_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')) | |
| ); | |
| CREATE TABLE IF NOT EXISTS market_ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, | |
| high REAL NOT NULL, | |
| low REAL NOT NULL, | |
| close REAL NOT NULL, | |
| volume INTEGER, | |
| source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_market_ohlcv_ticker_date | |
| ON market_ohlcv (ticker_id, trading_date DESC); | |
| -- ============================================================ | |
| -- 6. MARKET DATA BY DATASET | |
| -- | |
| -- The legacy market_ohlcv table remains only as a migration source for an | |
| -- existing installation. New reads and writes use these dataset tables. | |
| -- ============================================================ | |
| CREATE TABLE IF NOT EXISTS ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, | |
| volume INTEGER, source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE TABLE IF NOT EXISTS nifty_ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, | |
| volume INTEGER, source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE TABLE IF NOT EXISTS india_vix_ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, | |
| volume INTEGER, source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE TABLE IF NOT EXISTS us_stocks_ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, | |
| volume INTEGER, source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE TABLE IF NOT EXISTS macro_ohlcv ( | |
| ticker_id INTEGER NOT NULL REFERENCES market_tickers(id) ON DELETE CASCADE, | |
| macro_type TEXT NOT NULL CHECK (macro_type IN ('gold', 'brent_crude_oil', 'usd_inr')), | |
| trading_date DATE NOT NULL, | |
| open REAL NOT NULL, high REAL NOT NULL, low REAL NOT NULL, close REAL NOT NULL, | |
| volume INTEGER, source TEXT NOT NULL DEFAULT 'yfinance', | |
| fetched_at TIMESTAMP NOT NULL DEFAULT (STRFTIME('%Y-%m-%dT%H:%M:%fZ', 'now')), | |
| PRIMARY KEY (ticker_id, trading_date) | |
| ); | |
| CREATE VIEW IF NOT EXISTS all_market_ohlcv AS | |
| SELECT ticker_id, trading_date, open, high, low, close, volume, source, fetched_at FROM ohlcv | |
| UNION ALL SELECT ticker_id, trading_date, open, high, low, close, volume, source, fetched_at FROM nifty_ohlcv | |
| UNION ALL SELECT ticker_id, trading_date, open, high, low, close, volume, source, fetched_at FROM india_vix_ohlcv | |
| UNION ALL SELECT ticker_id, trading_date, open, high, low, close, volume, source, fetched_at FROM us_stocks_ohlcv | |
| UNION ALL SELECT ticker_id, trading_date, open, high, low, close, volume, source, fetched_at FROM macro_ohlcv; | |
| -- Copy legacy data exactly once when upgrading an existing database. | |
| INSERT OR IGNORE INTO ohlcv SELECT o.* FROM market_ohlcv o JOIN market_tickers t ON t.id = o.ticker_id WHERE t.market = 'NSE'; | |
| INSERT OR IGNORE INTO nifty_ohlcv SELECT o.* FROM market_ohlcv o JOIN market_tickers t ON t.id = o.ticker_id WHERE t.symbol = 'NIFTY'; | |
| INSERT OR IGNORE INTO india_vix_ohlcv SELECT o.* FROM market_ohlcv o JOIN market_tickers t ON t.id = o.ticker_id WHERE t.symbol = 'INDIA_VIX'; | |
| INSERT OR IGNORE INTO us_stocks_ohlcv SELECT o.* FROM market_ohlcv o JOIN market_tickers t ON t.id = o.ticker_id WHERE t.market = 'US'; | |
| INSERT OR IGNORE INTO macro_ohlcv (ticker_id, macro_type, trading_date, open, high, low, close, volume, source, fetched_at) | |
| SELECT o.ticker_id, CASE t.symbol WHEN 'GOLD' THEN 'gold' WHEN 'BRENT' THEN 'brent_crude_oil' WHEN 'USDINR' THEN 'usd_inr' END, | |
| o.trading_date, o.open, o.high, o.low, o.close, o.volume, o.source, o.fetched_at | |
| FROM market_ohlcv o JOIN market_tickers t ON t.id = o.ticker_id WHERE t.symbol IN ('GOLD', 'BRENT', 'USDINR'); | |
| -- Derived feature data lives in Parquet beside this database, under | |
| -- data/db/feature_store (or the equivalent directory for DATABASE_URL). | |