trading-platform/docs/99-analisis/ML-MODELOS-VUELTA2-ANALISIS.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

20 KiB

title version date status author epic tags
Análisis de Modelos ML - Vuelta 2 1.0.0 2026-01-06 In Progress ML-Specialist + Orquestador OQI-006
ml
analysis
architecture
integration
refactoring

ANÁLISIS DE MODELOS ML - VUELTA 2

1. RESUMEN DE HALLAZGOS VUELTA 1

1.1 Brechas Críticas Identificadas

Brecha Severidad Estado Real
Factores hardcodeados CRÍTICA PARCIALMENTE RESUELTO - SYMBOL_CONFIGS existe
Sin separación activo/timeframe ALTA RESUELTO - SymbolTimeframeTrainer existe
Atención no integrada ALTA RESUELTO - use_dynamic_factor_weighting=True
Win rate bajo CRÍTICA Pendiente optimización
R:R insuficiente ALTA Pendiente ajuste filtros

1.2 Cambio de Diagnóstico

Vuelta 1: Creíamos que faltaba infraestructura Vuelta 2: El problema es integración y uso de infraestructura existente


2. INFRAESTRUCTURA EXISTENTE DESCUBIERTA

2.1 Sistema de Configuración

Archivo: config/trading.yaml

symbols:
  primary: ["XAUUSD", "EURUSD", "GBPUSD", "BTCUSD"]
  secondary: ["USDJPY", "GBPJPY", "AUDUSD", "NZDUSD"]

timeframes:
  primary: 5
  aggregations: [15, 30, 60, 240]

Archivo: config/models.yaml

xgboost:
  base:
    n_estimators: 200
    max_depth: 5
    learning_rate: 0.05
    # ... configuración completa

meta_model:
  type: "xgboost"
  # Soporte para metamodelo ya existe

2.2 Trainer por Símbolo/Timeframe

Archivo: training/symbol_timeframe_trainer.py

SYMBOL_CONFIGS = {
    'XAUUSD': SymbolConfig(symbol='XAUUSD', base_factor=5.0, pip_value=0.01),
    'BTCUSD': SymbolConfig(symbol='BTCUSD', base_factor=100.0, pip_value=0.01),
    'EURUSD': SymbolConfig(symbol='EURUSD', base_factor=0.0005, pip_value=0.0001),
    'GBPUSD': SymbolConfig(symbol='GBPUSD', base_factor=0.0006, pip_value=0.0001),
    'USDJPY': SymbolConfig(symbol='USDJPY', base_factor=0.05, pip_value=0.01),
}

@dataclass
class TrainerConfig:
    timeframes: List[str] = ['5m', '15m']
    symbols: List[str] = ['XAUUSD', 'BTCUSD', 'EURUSD']
    use_dynamic_factor_weighting: bool = True  # ✅ Ya habilitado
    use_atr_weighting: bool = True             # ✅ Ya habilitado
    factor_window: int = 200
    softplus_beta: float = 4.0
    softplus_w_max: float = 3.0

2.3 Modelos Ya Entrenados Separados

Ubicación: models/ml_first/

ml_first/
└── XAUUSD/
    └── movement_predictor/
        ├── 5m_15min/
        │   └── metadata.yaml
        └── 15m_60min/
            └── metadata.yaml

3. ANÁLISIS DE BRECHAS REAL

3.1 El Problema: Fragmentación de Código

Código Nuevo (Correcto) - symbol_timeframe_trainer.py:

SYMBOL_CONFIGS = {
    'XAUUSD': SymbolConfig(symbol='XAUUSD', base_factor=5.0, ...),
    # Factores dinámicos por símbolo
}

Código Legacy (Incorrecto) - range_predictor_factor.py:598-601:

SYMBOLS = {
    'XAUUSD': {'base': 2650.0, 'volatility': 0.0012, 'factor': 2.5},
    'EURUSD': {'base': 1.0420, 'volatility': 0.0004, 'factor': 0.0003},
}
# Hardcoded, solo 2 símbolos, valores estáticos

3.2 Dependencias No Conectadas

symbol_timeframe_trainer.py ──✅─→ DynamicFactorWeighter
       │
       └── ❌ NO es usado por →  range_predictor_factor.py
                                  enhanced_range_predictor.py
                                  prediction_service.py

3.3 APIs No Usan Trainer Correcto

prediction_service.py usa modelos legacy:

  • RangePredictorFactor (hardcoded)
  • EnhancedRangePredictor (parcialmente dinámico)

Debería usar:

  • SymbolTimeframeTrainer.predict()
  • O modelos cargados desde models/ml_first/{symbol}/{timeframe}/

4. ARQUITECTURA PROPUESTA DE INTEGRACIÓN

4.1 Nuevo Flujo de Predicción

┌─────────────────────────────────────────────────────────────────┐
│                    PREDICTION SERVICE (Unificado)               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Request: { symbol: "XAUUSD", timeframe: "15m" }               │
│                                                                 │
│  1. Load Config: SYMBOL_CONFIGS['XAUUSD']                      │
│     → base_factor: 5.0, pip_value: 0.01                        │
│                                                                 │
│  2. Load Model: models/XAUUSD/15m/range_xgb.joblib             │
│                                                                 │
│  3. Apply Attention: DynamicFactorWeighter                     │
│     → compute_factor_median_range(df, window=200)              │
│     → weight_smooth(m, w_max=3.0, beta=4.0)                    │
│                                                                 │
│  4. Predict: model.predict(features, attention_weight)         │
│                                                                 │
│  5. Post-process: scale by base_factor                         │
│                                                                 │
│  Response: { delta_high, delta_low, confidence, attention }    │
└─────────────────────────────────────────────────────────────────┘

4.2 Refactoring Requerido

Paso 1: Eliminar Factores Hardcodeados

# ANTES (range_predictor_factor.py)
class PriceDataGenerator:
    SYMBOLS = {...}  # Hardcoded

# DESPUÉS
from training.symbol_timeframe_trainer import SYMBOL_CONFIGS

class PriceDataGenerator:
    def __init__(self, symbol: str):
        self.config = SYMBOL_CONFIGS.get(symbol, self._default_config(symbol))

Paso 2: Unificar Carga de Modelos

# prediction_service.py
class UnifiedPredictionService:
    def __init__(self):
        self.trainer = SymbolTimeframeTrainer()
        self.trainer.load('models/ml_first/')  # Cargar modelos entrenados

    def predict(self, symbol: str, timeframe: str, df: pd.DataFrame):
        return self.trainer.predict(df, symbol, timeframe)

Paso 3: Integrar en API

# api/main.py
@app.post("/predict/range/{symbol}")
async def predict_range(symbol: str, timeframe: str = "15m"):
    predictions = prediction_service.predict(symbol, timeframe, data)
    return predictions

5. ANÁLISIS DE HYPERPARÁMETROS

5.1 XGBoost - Comparación de Configs

Parámetro config/models.yaml symbol_timeframe_trainer.py Recomendación
n_estimators 200 300 300 (más estable)
max_depth 5 6 5 (evitar overfitting)
learning_rate 0.05 0.03 0.03 (más lento, mejor)
subsample 0.8 0.8 0.8
min_child_weight 3 10 10 (más conservador)

5.2 Attention Weighting - Config Óptima

Parámetro Valor Actual Propuesto Razón
factor_window 200 200 Suficiente contexto
softplus_beta 4.0 4.0 Transición suave
softplus_w_max 3.0 3.0 Cap razonable

5.3 Configuración Óptima Propuesta

# config/unified_model.yaml
training:
  use_dynamic_factor_weighting: true
  use_atr_weighting: true
  use_session_weighting: false  # Deshabilitar, no aporta en backtests

  factor:
    window: 200
    min_periods: 100

  softplus:
    beta: 4.0
    w_max: 3.0

  xgboost:
    n_estimators: 300
    max_depth: 5
    learning_rate: 0.03
    subsample: 0.8
    colsample_bytree: 0.8
    min_child_weight: 10
    gamma: 0.1
    reg_alpha: 0.1
    reg_lambda: 1.0

6. ANÁLISIS DE MODELOS POR TIPO

6.1 XGBoost vs GRU vs Transformer

Criterio XGBoost GRU Transformer
Velocidad inferencia Rápido 🔸 Medio 🔸 Medio
Memoria Bajo 🔸 Medio 🔴 Alto
Interpretabilidad Alta 🔴 Baja 🔴 Baja
Dependencias temporales 🔴 Limitado Excelente Excelente
Volatility Attention 🔸 Via sample_weight Nativo Nativo
Backtests actuales 80% WR (scalping) No probado Implementado

Recomendación:

  1. Corto plazo: XGBoost con attention via sample_weight (ya funciona)
  2. Mediano plazo: Agregar GRU como modelo secundario
  3. Largo plazo: Transformer con VolatilityBiasedSelfAttention

6.2 Arquitectura Híbrida Propuesta

┌─────────────────────────────────────────────────────────────┐
│                    HYBRID ENSEMBLE                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Level 1: Base Models                                       │
│  ├── XGBoost (Range): 35% weight                           │
│  │   └── Sample weight: DynamicFactorWeighter              │
│  │                                                          │
│  ├── Transformer (Attention): 30% weight                   │
│  │   └── VolatilityBiasedSelfAttention                     │
│  │                                                          │
│  ├── AMD Detector: 20% weight                              │
│  │   └── Phase-aware filtering                             │
│  │                                                          │
│  └── ICT/SMC: 15% weight                                   │
│      └── Order Blocks + FVG                                │
│                                                             │
│  Level 2: Meta-Model                                        │
│  └── XGBoost (stacking)                                    │
│      └── Features: predictions + volatility + session      │
│                                                             │
│  Output: Unified Signal + Confidence                        │
└─────────────────────────────────────────────────────────────┘

7. FEATURES ÓPTIMOS POR MODELO

7.1 Features Críticos (de trading.yaml)

Set Mínimo (14 features) - Mejor performance:

momentum: [macd_signal, macd_histogram, rsi]
trend: [sma_10, sma_20, sar]
volatility: [atr]
volume: [obv, ad, cmf, mfi]
patterns: [fractals_high, fractals_low, volume_zscore]

7.2 Features por Modelo

Modelo Features Prioritarios Razón
RangePredictor atr, bollinger_width, volume_zscore Volatilidad determina rango
AMDDetector volume, obv, cmf, rsi Detección de fases
ICT/SMC support_levels, resistance_levels, sar Estructura de mercado
TPSLClassifier atr, direction, momentum Probabilidad de hit

7.3 Feature Engineering Adicional

# Nuevos features propuestos
new_features = {
    'range_factor': (High - Low) / rolling_median(High - Low, 200).shift(1),
    'atr_ratio': ATR / ATR.rolling(20).mean(),
    'volume_momentum': Volume.pct_change(3),
    'session_code': encode_session(timestamp),  # 0=Asian, 1=London, 2=NY
    'hour_sin': np.sin(2 * np.pi * hour / 24),
    'hour_cos': np.cos(2 * np.pi * hour / 24),
}

8. OPTIMIZACIÓN DE FILTROS DIRECCIONALES

8.1 Hallazgo de Backtests

"100% de trades ganadores fueron SHORT en XAUUSD 5m"

Filtros que funcionaron:

SHORT_FILTERS = {
    'rsi': '> 55',      # Sobreextensión alcista
    'sar': 'above_price',  # SAR bajista
    'cmf': '< 0',       # Flujo vendedor
    'mfi': '> 55',      # Money flow alto (distribución)
}

8.2 Filtros Propuestos por Dirección

class DirectionalFilters:
    """Filtros mejorados basados en backtests"""

    @staticmethod
    def short_signal_valid(indicators: dict) -> bool:
        """SHORT: 2+ confirmaciones requeridas"""
        confirmations = 0
        if indicators['rsi'] > 55: confirmations += 1
        if indicators['sar_above_price']: confirmations += 1
        if indicators['cmf'] < 0: confirmations += 1
        if indicators['mfi'] > 55: confirmations += 1
        return confirmations >= 2

    @staticmethod
    def long_signal_valid(indicators: dict) -> bool:
        """LONG: 3+ confirmaciones requeridas (más estricto)"""
        confirmations = 0
        if indicators['rsi'] < 35: confirmations += 1
        if not indicators['sar_above_price']: confirmations += 1
        if indicators['cmf'] > 0.1: confirmations += 1
        if indicators['mfi'] < 35: confirmations += 1
        return confirmations >= 3

9. PLAN DE IMPLEMENTACIÓN VUELTA 2

Fase 2.1: Consolidación de Configuración

  • Migrar SYMBOLS de range_predictor_factor.py a SYMBOL_CONFIGS
  • Crear config/symbols.yaml centralizado
  • Actualizar todos los modelos para usar config unificada

Fase 2.2: Integración de Trainer

  • Modificar prediction_service.py para usar SymbolTimeframeTrainer
  • Cargar modelos desde models/ml_first/{symbol}/{timeframe}/
  • Agregar fallback a legacy models durante transición

Fase 2.3: Optimización de Filtros

  • Implementar DirectionalFilters en signal_generator.py
  • Ajustar thresholds según backtests
  • Agregar SHORT bias para XAUUSD

Fase 2.4: Ensemble Mejorado

  • Actualizar pesos de StrategyEnsemble basado en performance
  • Agregar adaptive weighting basado en volatility regime
  • Integrar XGBoost meta-model

10. MÉTRICAS OBJETIVO ACTUALIZADAS

10.1 Con Infraestructura Existente

Métrica Actual Objetivo Vuelta 2 Objetivo Final
Win Rate (fuertes) 33-44% 60% 80%
R:R Ratio 1.2:1 1.8:1 2.5:1
Profit Factor 1.07 1.3 1.8
Max Drawdown 15% 12% 10%

10.2 Quick Wins Identificados

  1. Usar filtros SHORT en XAUUSD: +10% win rate estimado
  2. Integrar DynamicFactorWeighter: Mejor selección de señales
  3. Cargar modelos separados: Predicciones más precisas por símbolo
  4. Ajustar confidence threshold a 0.7: Menos trades, mejor calidad

11. PRÓXIMOS PASOS

Vuelta 2 - FASE 2: Análisis Profundo de Arquitectura

  1. Revisar implementación de VolatilityBiasedSelfAttention
  2. Analizar métricas de modelos entrenados existentes
  3. Benchmark XGBoost vs Transformer en datos reales

Vuelta 2 - FASE 3: Retroalimentación

  1. Documentar decisiones arquitectónicas
  2. Proponer refactoring mínimo viable
  3. Definir tests de regresión

12. ANÁLISIS PROFUNDO DE ARQUITECTURA (FASE 2)

12.1 Métricas de Modelos Entrenados

XAUUSD Movement Predictor - Modelos Existentes:

Modelo Horizonte R² High R² Low MAE High MAE Low Muestras
5m→15min 15 min 38.85% 40.24% 0.76 USD 0.78 USD 135,199
15m→60min 60 min 48.32% 55.55% 1.42 USD 1.37 USD 45,500

Observaciones:

  • El modelo 15m→60min tiene mejor R² (48-56% vs 39-40%)
  • Más muestras no implica mejor modelo (5m tiene 3x muestras pero peor R²)
  • Horizonte más largo = más predecible (menos ruido)

Baseline Stats (5m→15min):

mean_high: 1.52 USD
mean_low: 1.64 USD
total_range: 3.16 USD

12.2 Features Usados por Modelos Entrenados

110 Features en MovementPredictor:

Categorías:
├── Range Features (20): bar_range_usd, avg_range_usd_*, range_zscore_*, range_pctl_*
├── Momentum (16): momentum_*, momentum_abs_*, range_roc_*
├── ATR/Volatility (12): atr_*, atr_pct_*, vol_clustering_*
├── Price Position (12): price_position_*, dist_from_high_*, dist_from_low_*
├── Volume (12): volume_ma_*, volume_ratio_*, vol_range_*
├── High/Low Body (16): high_body, low_body, avg_high_move_*, high_low_ratio_*
├── Session (5): hour, day_of_week, is_london, is_ny, is_overlap
└── Candlestick (17): body_size, upper_wick, lower_wick, body_to_range, avg_body_size_*, bullish_candles_*

Feature Redundancy Identificada:

  • 4 versiones de cada métrica (6, 12, 24, 48 períodos) = posible overfitting
  • Recomendación: Reducir a 2-3 períodos clave (6, 24)

12.3 Punto de Desconexión Identificado

prediction_service.py:157

from ..models.range_predictor import RangePredictor  # ← Legacy
self._range_predictor = RangePredictor()  # ← No usa modelos entrenados

Debería ser:

from ..training.symbol_timeframe_trainer import SymbolTimeframeTrainer
self._trainer = SymbolTimeframeTrainer()
self._trainer.load('models/ml_first/')  # ← Cargar modelos separados

12.4 Arquitectura de VolatilityBiasedSelfAttention

Componentes PyTorch implementados:

VolatilityBiasedSelfAttention
├── Multi-head attention con bias de volatilidad
├── attn_weight: (B, T) aplicado a Q·K^T
└── Softplus mapping para pesos suaves

VolatilityAttentionBlock
├── LayerNorm + Attention + Residual
└── LayerNorm + FeedForward + Residual

VolatilityTransformerEncoder
├── Input projection + Positional encoding
├── N capas de VolatilityAttentionBlock
└── Final LayerNorm

VolatilityRangePredictor  # ← Modelo completo
├── VolatilityTransformerEncoder
└── Output heads para delta_high, delta_low

Estado: Implementado pero NO usado en producción (solo XGBoost activo)

12.5 Comparación de Pipelines

Aspecto Pipeline Legacy Pipeline Propuesto
Modelos RangePredictor genérico models/ml_first/{symbol}/{tf}/
Factores Hardcoded en código SYMBOL_CONFIGS + dinámico
Atención No usa DynamicFactorWeighter
Símbolo Mezcla todos Separado por símbolo
Timeframe Fijo Separado por timeframe
Entrenamiento Manual SymbolTimeframeTrainer

13. QUICK WINS IDENTIFICADOS

13.1 Cambio de Bajo Riesgo - Alto Impacto

1. Cargar modelos entrenados en prediction_service.py

# Línea ~157: Cambiar de
from ..models.range_predictor import RangePredictor
# A
from ..models.movement_magnitude_predictor import MovementMagnitudePredictor
# Y cargar modelo específico por símbolo

2. Usar SYMBOL_CONFIGS en signal_generator.py

  • Eliminar factores hardcodeados
  • Usar base_factor de configuración centralizada

3. Activar filtros direccionales en XAUUSD

  • SHORT bias demostrado en backtests (+28 puntos porcentuales)
  • Implementar en generate_signal()

13.2 Impacto Estimado

Cambio Esfuerzo Impacto Win Rate Riesgo
Cargar modelos separados Bajo +5-10% Bajo
Filtros direccionales Bajo +10-15% Bajo
Integrar DynamicFactorWeighter Medio +5-10% Medio
Cambiar a Transformer Alto +10-20% Alto

Documento generado: 2026-01-06 Estado: FASE 2 Vuelta 2 completada