-- ===================================================== -- ML SCHEMA - LLM SIGNALS TABLE -- ===================================================== -- Description: Logs ML signals and LLM decisions for feedback and fine-tuning -- Schema: ml -- Author: ML-Specialist (NEXUS v4.0) -- Date: 2026-01-25 -- Module: OQI-007-llm-strategy-agent -- ===================================================== CREATE TABLE ml.llm_signals ( id SERIAL PRIMARY KEY, signal_id UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(), -- Symbol and timing symbol VARCHAR(20) NOT NULL, timestamp TIMESTAMPTZ NOT NULL, -- ML Predictions (from metamodel) ml_prediction JSONB, -- Expected structure: -- { -- "direction": "BULLISH"|"BEARISH"|"NEUTRAL", -- "magnitude": 0.5, -- "confidence": 0.75, -- "delta_high": 10.5, -- "delta_low": 8.2, -- "volatility_regime": "HIGH"|"MEDIUM"|"LOW", -- "market_phase": "accumulation"|"distribution"|"manipulation"|"trend" -- } -- Strategy predictions (individual strategies) strategy_predictions JSONB, -- Expected structure: -- [ -- {"name": "PVA", "direction": "BULLISH", "confidence": 0.8, "weight": 0.25}, -- {"name": "MRD", "direction": "NEUTRAL", "confidence": 0.5, "weight": 0.20}, -- ... -- ] -- LLM interaction llm_prompt TEXT, llm_response TEXT, -- Parsed decision from LLM decision JSONB, -- Expected structure: -- { -- "action": "TRADE"|"NO_TRADE"|"WAIT", -- "direction": "LONG"|"SHORT"|null, -- "entry": 2340.50, -- "stop_loss": 2335.00, -- "take_profit": [2350.00, 2360.00], -- "position_size": 1.0, -- "reasoning": "...", -- "is_valid": true -- } -- Trade result (updated after trade closes) trade_result JSONB, -- Expected structure: -- { -- "result": "WIN"|"LOSS"|"BREAKEVEN"|"PARTIAL", -- "pnl": 50.00, -- "pnl_pct": 5.0, -- "entry_price": 2340.50, -- "exit_price": 2350.00, -- "stop_loss_hit": false, -- "take_profit_hit": true, -- "duration_minutes": 45, -- "exit_reason": "TP1" -- } -- Timestamps created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Indices for common queries CREATE INDEX idx_llm_signals_symbol ON ml.llm_signals(symbol); CREATE INDEX idx_llm_signals_timestamp ON ml.llm_signals(timestamp DESC); CREATE INDEX idx_llm_signals_created_at ON ml.llm_signals(created_at DESC); -- Index for finding signals with results (for training data export) CREATE INDEX idx_llm_signals_with_results ON ml.llm_signals(timestamp DESC) WHERE trade_result IS NOT NULL; -- Index for decision types CREATE INDEX idx_llm_signals_decision_action ON ml.llm_signals((decision->>'action')); -- GIN index for JSONB queries CREATE INDEX idx_llm_signals_ml_prediction ON ml.llm_signals USING GIN (ml_prediction); CREATE INDEX idx_llm_signals_trade_result ON ml.llm_signals USING GIN (trade_result); -- Trigger to update updated_at CREATE OR REPLACE FUNCTION ml.update_llm_signals_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_llm_signals_updated_at BEFORE UPDATE ON ml.llm_signals FOR EACH ROW EXECUTE FUNCTION ml.update_llm_signals_updated_at(); -- Comments COMMENT ON TABLE ml.llm_signals IS 'Logs ML signals and LLM decisions for performance tracking and fine-tuning dataset generation'; COMMENT ON COLUMN ml.llm_signals.id IS 'Auto-incrementing primary key'; COMMENT ON COLUMN ml.llm_signals.signal_id IS 'Unique UUID for external reference'; COMMENT ON COLUMN ml.llm_signals.symbol IS 'Trading symbol (e.g., XAUUSD, EURUSD)'; COMMENT ON COLUMN ml.llm_signals.timestamp IS 'Timestamp of the signal generation'; COMMENT ON COLUMN ml.llm_signals.ml_prediction IS 'JSONB with metamodel prediction output'; COMMENT ON COLUMN ml.llm_signals.strategy_predictions IS 'JSONB array with individual strategy predictions'; COMMENT ON COLUMN ml.llm_signals.llm_prompt IS 'Full prompt sent to the LLM'; COMMENT ON COLUMN ml.llm_signals.llm_response IS 'Raw response from the LLM'; COMMENT ON COLUMN ml.llm_signals.decision IS 'JSONB with parsed trading decision'; COMMENT ON COLUMN ml.llm_signals.trade_result IS 'JSONB with trade outcome (null until trade closes)'; COMMENT ON COLUMN ml.llm_signals.created_at IS 'Record creation timestamp'; COMMENT ON COLUMN ml.llm_signals.updated_at IS 'Record last update timestamp';