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

577 lines
20 KiB
Markdown

---
title: "Análisis de Modelos ML - Vuelta 2"
version: "1.0.0"
date: "2026-01-06"
status: "In Progress"
author: "ML-Specialist + Orquestador"
epic: "OQI-006"
tags: ["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`
```yaml
symbols:
primary: ["XAUUSD", "EURUSD", "GBPUSD", "BTCUSD"]
secondary: ["USDJPY", "GBPJPY", "AUDUSD", "NZDUSD"]
timeframes:
primary: 5
aggregations: [15, 30, 60, 240]
```
**Archivo**: `config/models.yaml`
```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`
```python
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`:
```python
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`:
```python
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**
```python
# 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**
```python
# 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**
```python
# 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
```yaml
# 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:
```yaml
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
```python
# 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**:
```python
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
```python
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**
```python
from ..models.range_predictor import RangePredictor # ← Legacy
self._range_predictor = RangePredictor() # ← No usa modelos entrenados
```
**Debería ser:**
```python
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:**
```python
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**
```python
# 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*