trading-platform-database-v2/ddl/schemas/ml/002_predictions.sql
rckrdmrd e520268348 Migración desde trading-platform/apps/database - Estándar multi-repo v2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 08:32:52 -06:00

189 lines
6.5 KiB
PL/PgSQL

-- ============================================================================
-- SCHEMA: ml
-- TABLE: predictions
-- DESCRIPTION: Tabla de predicciones individuales generadas
-- VERSION: 1.0.0
-- CREATED: 2026-01-10
-- DEPENDS: ml.prediction_purchases
-- ============================================================================
-- Enum para tipo de prediccion
DO $$ BEGIN
CREATE TYPE ml.prediction_type AS ENUM (
'AMD', -- Accumulation, Manipulation, Distribution
'RANGE', -- Range prediction
'TPSL', -- Take Profit / Stop Loss
'ICT_SMC', -- ICT Smart Money Concepts
'STRATEGY_ENSEMBLE' -- Combined strategies
);
EXCEPTION WHEN duplicate_object THEN null; END $$;
-- Enum para clase de activo
DO $$ BEGIN
CREATE TYPE ml.asset_class AS ENUM (
'FOREX',
'CRYPTO',
'INDICES',
'COMMODITIES'
);
EXCEPTION WHEN duplicate_object THEN null; END $$;
-- Enum para estado de prediccion
DO $$ BEGIN
CREATE TYPE ml.prediction_status AS ENUM (
'pending', -- Generada, esperando entrega
'delivered', -- Entregada al usuario
'expired', -- Expirada sin validar
'validated', -- Validada con resultado
'invalidated' -- Invalidada por error
);
EXCEPTION WHEN duplicate_object THEN null; END $$;
-- Tabla de predicciones individuales
CREATE TABLE IF NOT EXISTS ml.predictions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
user_id UUID NOT NULL,
-- Referencia a la compra
purchase_id UUID NOT NULL REFERENCES ml.prediction_purchases(id),
-- Tipo y activo
prediction_type ml.prediction_type NOT NULL,
asset VARCHAR(20) NOT NULL,
asset_class ml.asset_class NOT NULL,
timeframe VARCHAR(10) NOT NULL,
-- Predicción
direction VARCHAR(10) NOT NULL CHECK (direction IN ('LONG', 'SHORT', 'NEUTRAL')),
entry_price DECIMAL(20, 8),
target_price DECIMAL(20, 8),
stop_loss DECIMAL(20, 8),
confidence DECIMAL(5, 4) CHECK (confidence >= 0 AND confidence <= 1),
-- Estado
status ml.prediction_status NOT NULL DEFAULT 'pending',
expires_at TIMESTAMPTZ NOT NULL,
delivered_at TIMESTAMPTZ,
-- Datos adicionales
prediction_data JSONB DEFAULT '{}',
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
COMMENT ON TABLE ml.predictions IS
'Predicciones individuales generadas por modelos ML';
COMMENT ON COLUMN ml.predictions.prediction_type IS 'Tipo de modelo usado para la prediccion';
COMMENT ON COLUMN ml.predictions.asset_class IS 'Clase de activo (FOREX, CRYPTO, etc.)';
COMMENT ON COLUMN ml.predictions.status IS 'Estado actual de la prediccion';
COMMENT ON COLUMN ml.predictions.confidence IS 'Nivel de confianza del modelo (0-1)';
-- Indices
CREATE INDEX IF NOT EXISTS idx_pred_tenant ON ml.predictions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_pred_user ON ml.predictions(user_id);
CREATE INDEX IF NOT EXISTS idx_pred_purchase ON ml.predictions(purchase_id);
CREATE INDEX IF NOT EXISTS idx_pred_status ON ml.predictions(status);
CREATE INDEX IF NOT EXISTS idx_pred_type ON ml.predictions(prediction_type);
CREATE INDEX IF NOT EXISTS idx_pred_asset ON ml.predictions(asset);
CREATE INDEX IF NOT EXISTS idx_pred_asset_class ON ml.predictions(asset_class);
CREATE INDEX IF NOT EXISTS idx_pred_created ON ml.predictions(created_at DESC);
CREATE INDEX IF NOT EXISTS idx_pred_expires ON ml.predictions(expires_at)
WHERE status = 'pending';
-- Indice compuesto para busquedas comunes
CREATE INDEX IF NOT EXISTS idx_pred_user_status ON ml.predictions(user_id, status, created_at DESC);
-- RLS
ALTER TABLE ml.predictions ENABLE ROW LEVEL SECURITY;
CREATE POLICY pred_tenant ON ml.predictions
FOR ALL
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
-- Grants
GRANT SELECT, INSERT, UPDATE ON ml.predictions TO trading_app;
GRANT SELECT ON ml.predictions TO trading_readonly;
-- Actualizar FK en prediction_outcomes para referenciar predictions
DO $$
BEGIN
ALTER TABLE ml.prediction_outcomes
DROP CONSTRAINT IF EXISTS prediction_outcomes_prediction_id_fkey;
EXCEPTION WHEN undefined_object THEN null;
END $$;
ALTER TABLE ml.prediction_outcomes
ADD CONSTRAINT prediction_outcomes_prediction_id_fkey
FOREIGN KEY (prediction_id) REFERENCES ml.predictions(id)
ON DELETE SET NULL;
-- Funcion para generar prediccion desde un purchase
CREATE OR REPLACE FUNCTION ml.generate_prediction(
p_purchase_id UUID,
p_prediction_type ml.prediction_type,
p_asset VARCHAR(20),
p_asset_class ml.asset_class,
p_timeframe VARCHAR(10),
p_direction VARCHAR(10),
p_entry DECIMAL(20, 8) DEFAULT NULL,
p_target DECIMAL(20, 8) DEFAULT NULL,
p_sl DECIMAL(20, 8) DEFAULT NULL,
p_confidence DECIMAL(5, 4) DEFAULT 0.5,
p_expires_hours INT DEFAULT 24,
p_prediction_data JSONB DEFAULT '{}'
)
RETURNS UUID AS $$
DECLARE
v_purchase ml.prediction_purchases%ROWTYPE;
v_prediction_id UUID;
BEGIN
-- Validar purchase
SELECT * INTO v_purchase
FROM ml.prediction_purchases
WHERE id = p_purchase_id
FOR UPDATE;
IF NOT FOUND THEN
RAISE EXCEPTION 'Purchase not found: %', p_purchase_id;
END IF;
IF NOT v_purchase.is_active THEN
RAISE EXCEPTION 'Purchase is not active';
END IF;
IF v_purchase.valid_until IS NOT NULL AND v_purchase.valid_until < NOW() THEN
RAISE EXCEPTION 'Purchase has expired';
END IF;
IF v_purchase.predictions_used >= v_purchase.predictions_total THEN
RAISE EXCEPTION 'No predictions remaining';
END IF;
-- Crear prediccion
INSERT INTO ml.predictions (
tenant_id, user_id, purchase_id,
prediction_type, asset, asset_class, timeframe,
direction, entry_price, target_price, stop_loss, confidence,
expires_at, prediction_data
) VALUES (
v_purchase.tenant_id, v_purchase.user_id, p_purchase_id,
p_prediction_type, p_asset, p_asset_class, p_timeframe,
p_direction, p_entry, p_target, p_sl, p_confidence,
NOW() + (p_expires_hours || ' hours')::INTERVAL,
p_prediction_data
) RETURNING id INTO v_prediction_id;
-- Incrementar contador
UPDATE ml.prediction_purchases
SET predictions_used = predictions_used + 1
WHERE id = p_purchase_id;
RETURN v_prediction_id;
END;
$$ LANGUAGE plpgsql;
COMMENT ON FUNCTION ml.generate_prediction IS
'Genera una nueva prediccion desde un purchase, validando limites y estado';