-- Migration: ML Predictions Tracking Table -- Description: Store ML model predictions and outcomes for performance analysis -- Created: 2025-10-15 -- ML Predictions tracking table CREATE TABLE IF NOT EXISTS ml_predictions ( id SERIAL PRIMARY KEY, model_name VARCHAR(50) NOT NULL, features JSONB NOT NULL, predicted_action SMALLINT NOT NULL, -- 0=Buy, 1=Sell, 2=Hold confidence REAL NOT NULL, symbol VARCHAR(20) NOT NULL, prediction_timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Outcome tracking (filled later) actual_action SMALLINT, pnl DECIMAL(15, 2), outcome_recorded_at TIMESTAMPTZ, -- Constraints CONSTRAINT ml_predictions_action_check CHECK (predicted_action BETWEEN 0 AND 2), CONSTRAINT ml_predictions_confidence_check CHECK (confidence BETWEEN 0.0 AND 1.0) ); -- Indexes for performance CREATE INDEX IF NOT EXISTS idx_ml_predictions_model ON ml_predictions(model_name); CREATE INDEX IF NOT EXISTS idx_ml_predictions_symbol ON ml_predictions(symbol); CREATE INDEX IF NOT EXISTS idx_ml_predictions_timestamp ON ml_predictions(prediction_timestamp); CREATE INDEX IF NOT EXISTS idx_ml_predictions_outcome ON ml_predictions(outcome_recorded_at) WHERE outcome_recorded_at IS NOT NULL; -- Model performance materialized view CREATE MATERIALIZED VIEW IF NOT EXISTS ml_model_performance AS SELECT model_name, COUNT(*) as total_predictions, COUNT(actual_action) as predictions_with_outcomes, SUM(CASE WHEN predicted_action = actual_action THEN 1 ELSE 0 END) as correct_predictions, CASE WHEN COUNT(actual_action) > 0 THEN SUM(CASE WHEN predicted_action = actual_action THEN 1 ELSE 0 END)::FLOAT / COUNT(actual_action) ELSE 0.0 END as accuracy, AVG(pnl) as avg_pnl, STDDEV(pnl) as stddev_pnl, CASE WHEN STDDEV(pnl) > 0 THEN AVG(pnl) / STDDEV(pnl) * SQRT(252) ELSE 0.0 END as sharpe_ratio -- Annualized Sharpe (252 trading days) FROM ml_predictions WHERE outcome_recorded_at IS NOT NULL GROUP BY model_name; -- Index on materialized view CREATE UNIQUE INDEX IF NOT EXISTS idx_ml_model_performance_model ON ml_model_performance(model_name); -- Refresh function CREATE OR REPLACE FUNCTION refresh_ml_model_performance() RETURNS void AS $$ BEGIN REFRESH MATERIALIZED VIEW CONCURRENTLY ml_model_performance; END; $$ LANGUAGE plpgsql; -- Comment on table COMMENT ON TABLE ml_predictions IS 'ML model predictions and outcomes for performance tracking and analysis'; COMMENT ON COLUMN ml_predictions.features IS 'JSON array of feature values used for prediction'; COMMENT ON COLUMN ml_predictions.predicted_action IS '0=Buy, 1=Sell, 2=Hold'; COMMENT ON COLUMN ml_predictions.confidence IS 'Model confidence score (0.0-1.0)'; COMMENT ON COLUMN ml_predictions.actual_action IS 'Actual action taken (filled after outcome is known)'; COMMENT ON COLUMN ml_predictions.pnl IS 'Profit/Loss from this prediction'; COMMENT ON MATERIALIZED VIEW ml_model_performance IS 'Aggregated model performance metrics including accuracy and Sharpe ratio';