-- 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';
