trading-platform-database-v2/ddl/schemas/ml/005_market_analysis.sql
rckrdmrd 9f8bbb7494 [DDL] feat: Sprint 4 - Add data_sources and ml_predictions schemas
- data_sources schema:
  - api_providers: Proveedores de datos de mercado
  - ticker_mapping: Mapeo de simbolos entre proveedores
  - data_sync_status: Estado de sincronizacion de datos

- ml schema additions:
  - range_predictions: Predicciones de rango (particionada)
  - entry_signals: Señales de entrada con metodologias ICT/SMC/AMD
  - market_analysis: Analisis de mercado (sesgo, estructura, volatilidad)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 20:08:51 -06:00

407 lines
14 KiB
PL/PgSQL

-- ============================================================================
-- SCHEMA: ml
-- TABLE: market_analysis
-- DESCRIPTION: Analisis de mercado generado por ML (sesgo, volatilidad, estructura)
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 4 - DDL Implementation Roadmap Q1-2026
-- ============================================================================
-- Enum para tipo de analisis
DO $$ BEGIN
CREATE TYPE ml.analysis_type AS ENUM (
'daily_bias', -- Sesgo diario
'weekly_outlook', -- Perspectiva semanal
'session_analysis', -- Analisis de sesion
'structure_analysis', -- Analisis de estructura
'volatility_forecast', -- Pronostico de volatilidad
'correlation_report', -- Reporte de correlaciones
'sentiment_analysis', -- Analisis de sentimiento
'fundamental_impact', -- Impacto fundamental
'comprehensive' -- Analisis completo
);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Enum para sesgo de mercado
DO $$ BEGIN
CREATE TYPE ml.market_bias AS ENUM (
'strong_bullish', -- Fuertemente alcista
'bullish', -- Alcista
'slightly_bullish', -- Ligeramente alcista
'neutral', -- Neutral
'slightly_bearish', -- Ligeramente bajista
'bearish', -- Bajista
'strong_bearish' -- Fuertemente bajista
);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Enum para regimen de volatilidad
DO $$ BEGIN
CREATE TYPE ml.volatility_regime AS ENUM (
'extremely_low', -- Extremadamente baja
'low', -- Baja
'normal', -- Normal
'high', -- Alta
'extreme', -- Extrema
'transitioning' -- En transicion
);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Enum para estructura de mercado
DO $$ BEGIN
CREATE TYPE ml.market_structure AS ENUM (
'uptrend_strong', -- Tendencia alcista fuerte
'uptrend_weak', -- Tendencia alcista debil
'downtrend_strong', -- Tendencia bajista fuerte
'downtrend_weak', -- Tendencia bajista debil
'ranging_tight', -- Rango estrecho
'ranging_wide', -- Rango amplio
'consolidating', -- Consolidando
'breaking_out', -- Rompiendo
'reversing' -- Revirtiendo
);
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
-- Tabla de Analisis de Mercado
CREATE TABLE IF NOT EXISTS ml.market_analysis (
-- Identificadores
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL,
-- Simbolo y scope
symbol VARCHAR(20) NOT NULL,
asset_class ml.asset_class NOT NULL DEFAULT 'FOREX',
analysis_type ml.analysis_type NOT NULL,
timeframe VARCHAR(10) NOT NULL DEFAULT 'D1',
-- Periodo del analisis
analysis_date DATE NOT NULL,
valid_from TIMESTAMPTZ NOT NULL,
valid_until TIMESTAMPTZ NOT NULL,
-- Sesgo y direccion
bias ml.market_bias NOT NULL,
bias_confidence DECIMAL(5, 4) NOT NULL DEFAULT 0.5
CHECK (bias_confidence BETWEEN 0 AND 1),
bias_reasoning TEXT,
-- Estructura de mercado
structure ml.market_structure NOT NULL,
structure_timeframe VARCHAR(10), -- TF de la estructura dominante
trend_strength DECIMAL(5, 2), -- -100 a +100
-- Volatilidad
volatility_regime ml.volatility_regime NOT NULL,
current_atr DECIMAL(15, 8),
atr_percentile DECIMAL(5, 2), -- Percentil historico
expected_range_pips DECIMAL(10, 2),
volatility_forecast DECIMAL(10, 4), -- Volatilidad esperada
-- Niveles clave
key_resistance_1 DECIMAL(15, 8),
key_resistance_2 DECIMAL(15, 8),
key_resistance_3 DECIMAL(15, 8),
key_support_1 DECIMAL(15, 8),
key_support_2 DECIMAL(15, 8),
key_support_3 DECIMAL(15, 8),
pivot_point DECIMAL(15, 8),
-- Order blocks y FVGs
bullish_order_blocks JSONB DEFAULT '[]'::JSONB,
bearish_order_blocks JSONB DEFAULT '[]'::JSONB,
fair_value_gaps JSONB DEFAULT '[]'::JSONB,
liquidity_levels JSONB DEFAULT '[]'::JSONB,
-- Indicadores
indicators JSONB DEFAULT '{}'::JSONB, -- RSI, MACD, etc.
moving_averages JSONB DEFAULT '{}'::JSONB, -- SMAs, EMAs
-- Correlaciones
correlation_dxy DECIMAL(5, 4), -- Correlacion con DXY
correlation_gold DECIMAL(5, 4), -- Correlacion con oro
correlation_sp500 DECIMAL(5, 4), -- Correlacion con S&P500
correlated_pairs JSONB DEFAULT '[]'::JSONB, -- Pares correlacionados
-- Sentimiento
sentiment_score DECIMAL(5, 2), -- -100 a +100
sentiment_sources JSONB DEFAULT '{}'::JSONB, -- Fuentes de sentimiento
cot_report JSONB DEFAULT '{}'::JSONB, -- Datos COT
-- Eventos fundamentales
upcoming_events JSONB DEFAULT '[]'::JSONB, -- Eventos proximos
recent_events_impact JSONB DEFAULT '[]'::JSONB, -- Impacto de eventos recientes
high_impact_event_today BOOLEAN NOT NULL DEFAULT FALSE,
-- Escenarios
primary_scenario JSONB DEFAULT '{}'::JSONB, -- Escenario principal
secondary_scenario JSONB DEFAULT '{}'::JSONB, -- Escenario alternativo
risk_scenario JSONB DEFAULT '{}'::JSONB, -- Escenario de riesgo
-- Zonas de interes
buy_zones JSONB DEFAULT '[]'::JSONB, -- Zonas de compra
sell_zones JSONB DEFAULT '[]'::JSONB, -- Zonas de venta
avoid_zones JSONB DEFAULT '[]'::JSONB, -- Zonas a evitar
-- Modelo
model_id VARCHAR(100),
model_version VARCHAR(50) NOT NULL,
analysis_confidence DECIMAL(5, 4) NOT NULL DEFAULT 0.5
CHECK (analysis_confidence BETWEEN 0 AND 1),
-- Resumen
summary TEXT, -- Resumen ejecutivo
trading_plan TEXT, -- Plan de trading sugerido
key_insights JSONB DEFAULT '[]'::JSONB, -- Insights clave
-- Resultado (post-validacion)
actual_direction VARCHAR(20), -- Direccion real
actual_range_pips DECIMAL(10, 2),
accuracy_score DECIMAL(5, 2), -- Score de precision
validated_at TIMESTAMPTZ,
-- Metadata
tags VARCHAR(50)[],
notes TEXT,
metadata JSONB DEFAULT '{}'::JSONB,
-- Timestamps
generated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
-- Constraints
CONSTRAINT market_analysis_unique UNIQUE (tenant_id, symbol, analysis_type, analysis_date)
);
COMMENT ON TABLE ml.market_analysis IS
'Analisis de mercado generado por modelos ML: sesgo, estructura, volatilidad, niveles clave';
COMMENT ON COLUMN ml.market_analysis.bias IS
'Sesgo direccional del mercado para el periodo analizado';
COMMENT ON COLUMN ml.market_analysis.structure IS
'Estructura de mercado dominante (tendencia, rango, etc.)';
-- Indices
CREATE INDEX IF NOT EXISTS idx_market_analysis_tenant
ON ml.market_analysis(tenant_id);
CREATE INDEX IF NOT EXISTS idx_market_analysis_symbol
ON ml.market_analysis(symbol, analysis_date DESC);
CREATE INDEX IF NOT EXISTS idx_market_analysis_date
ON ml.market_analysis(analysis_date DESC);
CREATE INDEX IF NOT EXISTS idx_market_analysis_type
ON ml.market_analysis(analysis_type, analysis_date DESC);
CREATE INDEX IF NOT EXISTS idx_market_analysis_bias
ON ml.market_analysis(bias, analysis_date DESC);
CREATE INDEX IF NOT EXISTS idx_market_analysis_active
ON ml.market_analysis(valid_until)
WHERE valid_until > NOW();
CREATE INDEX IF NOT EXISTS idx_market_analysis_model
ON ml.market_analysis(model_version, analysis_date DESC);
CREATE INDEX IF NOT EXISTS idx_market_analysis_high_impact
ON ml.market_analysis(analysis_date, high_impact_event_today)
WHERE high_impact_event_today = TRUE;
-- GIN indices para JSONB
CREATE INDEX IF NOT EXISTS idx_market_analysis_events_gin
ON ml.market_analysis USING GIN (upcoming_events);
CREATE INDEX IF NOT EXISTS idx_market_analysis_insights_gin
ON ml.market_analysis USING GIN (key_insights);
-- Trigger para updated_at
DROP TRIGGER IF EXISTS market_analysis_updated_at ON ml.market_analysis;
CREATE TRIGGER market_analysis_updated_at
BEFORE UPDATE ON ml.market_analysis
FOR EACH ROW
EXECUTE FUNCTION ml.update_ml_timestamp();
-- Funcion para obtener analisis actual
CREATE OR REPLACE FUNCTION ml.get_current_analysis(
p_tenant_id UUID,
p_symbol VARCHAR,
p_analysis_type ml.analysis_type DEFAULT 'daily_bias'
)
RETURNS ml.market_analysis AS $$
DECLARE
v_analysis ml.market_analysis;
BEGIN
SELECT * INTO v_analysis
FROM ml.market_analysis
WHERE tenant_id = p_tenant_id
AND symbol = p_symbol
AND analysis_type = p_analysis_type
AND valid_until > NOW()
ORDER BY analysis_date DESC
LIMIT 1;
RETURN v_analysis;
END;
$$ LANGUAGE plpgsql;
-- Funcion para obtener sesgo agregado de multiples simbolos
CREATE OR REPLACE FUNCTION ml.get_market_overview(
p_tenant_id UUID,
p_symbols VARCHAR[] DEFAULT NULL
)
RETURNS TABLE (
symbol VARCHAR,
bias ml.market_bias,
bias_confidence DECIMAL,
structure ml.market_structure,
volatility_regime ml.volatility_regime,
analysis_date DATE
) AS $$
BEGIN
RETURN QUERY
SELECT DISTINCT ON (ma.symbol)
ma.symbol,
ma.bias,
ma.bias_confidence,
ma.structure,
ma.volatility_regime,
ma.analysis_date
FROM ml.market_analysis ma
WHERE ma.tenant_id = p_tenant_id
AND ma.analysis_type = 'daily_bias'
AND ma.valid_until > NOW()
AND (p_symbols IS NULL OR ma.symbol = ANY(p_symbols))
ORDER BY ma.symbol, ma.analysis_date DESC;
END;
$$ LANGUAGE plpgsql;
-- Funcion para validar analisis con datos reales
CREATE OR REPLACE FUNCTION ml.validate_market_analysis(
p_analysis_id UUID,
p_actual_high DECIMAL,
p_actual_low DECIMAL,
p_actual_close DECIMAL
)
RETURNS VOID AS $$
DECLARE
v_analysis ml.market_analysis;
v_direction VARCHAR;
v_accuracy DECIMAL;
BEGIN
SELECT * INTO v_analysis FROM ml.market_analysis WHERE id = p_analysis_id;
IF NOT FOUND THEN
RETURN;
END IF;
-- Determinar direccion real
IF p_actual_close > (p_actual_high + p_actual_low) / 2 THEN
v_direction := 'bullish';
ELSE
v_direction := 'bearish';
END IF;
-- Calcular accuracy basado en sesgo predicho vs real
v_accuracy := CASE
WHEN v_analysis.bias IN ('strong_bullish', 'bullish', 'slightly_bullish') AND v_direction = 'bullish' THEN 100
WHEN v_analysis.bias IN ('strong_bearish', 'bearish', 'slightly_bearish') AND v_direction = 'bearish' THEN 100
WHEN v_analysis.bias = 'neutral' THEN 50
ELSE 0
END;
UPDATE ml.market_analysis
SET actual_direction = v_direction,
actual_range_pips = (p_actual_high - p_actual_low) * 10000,
accuracy_score = v_accuracy,
validated_at = NOW()
WHERE id = p_analysis_id;
END;
$$ LANGUAGE plpgsql;
-- Vista de analisis activos
CREATE OR REPLACE VIEW ml.v_current_market_analysis AS
SELECT
id,
tenant_id,
symbol,
asset_class,
analysis_type,
analysis_date,
bias,
bias_confidence,
structure,
volatility_regime,
expected_range_pips,
key_resistance_1,
key_support_1,
pivot_point,
sentiment_score,
high_impact_event_today,
summary,
analysis_confidence,
valid_until
FROM ml.market_analysis
WHERE valid_until > NOW()
ORDER BY analysis_date DESC, symbol;
-- Vista de rendimiento de analisis
CREATE OR REPLACE VIEW ml.v_market_analysis_performance AS
SELECT
symbol,
analysis_type,
model_version,
COUNT(*) AS total_analyses,
ROUND(AVG(accuracy_score)::NUMERIC, 2) AS avg_accuracy,
ROUND(AVG(bias_confidence)::NUMERIC, 4) AS avg_confidence,
COUNT(*) FILTER (WHERE accuracy_score >= 70) AS accurate_count,
COUNT(*) FILTER (WHERE accuracy_score < 30) AS inaccurate_count,
ROUND((COUNT(*) FILTER (WHERE accuracy_score >= 70)::DECIMAL
/ NULLIF(COUNT(*) FILTER (WHERE validated_at IS NOT NULL), 0) * 100), 2) AS accuracy_rate
FROM ml.market_analysis
WHERE validated_at IS NOT NULL
GROUP BY symbol, analysis_type, model_version
ORDER BY accuracy_rate DESC NULLS LAST;
-- Vista de correlaciones actuales
CREATE OR REPLACE VIEW ml.v_market_correlations AS
SELECT
symbol,
analysis_date,
correlation_dxy,
correlation_gold,
correlation_sp500,
bias,
structure
FROM ml.market_analysis
WHERE analysis_type = 'daily_bias'
AND valid_until > NOW()
AND (correlation_dxy IS NOT NULL OR correlation_gold IS NOT NULL)
ORDER BY analysis_date DESC, symbol;
-- RLS Policies
ALTER TABLE ml.market_analysis ENABLE ROW LEVEL SECURITY;
CREATE POLICY market_analysis_tenant ON ml.market_analysis
FOR ALL
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
-- Grants
GRANT SELECT, INSERT, UPDATE ON ml.market_analysis TO trading_app;
GRANT SELECT ON ml.market_analysis TO trading_readonly;
GRANT SELECT ON ml.v_current_market_analysis TO trading_app;
GRANT SELECT ON ml.v_market_analysis_performance TO trading_app;
GRANT SELECT ON ml.v_market_correlations TO trading_app;
GRANT EXECUTE ON FUNCTION ml.get_current_analysis TO trading_app;
GRANT EXECUTE ON FUNCTION ml.get_market_overview TO trading_app;
GRANT EXECUTE ON FUNCTION ml.validate_market_analysis TO trading_app;