189 lines
6.5 KiB
PL/PgSQL
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';
|