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>
518 lines
14 KiB
Markdown
518 lines
14 KiB
Markdown
---
|
|
title: "Especificación Técnica: Sistema de Atención con Factores Dinámicos"
|
|
version: "1.0.0"
|
|
date: "2026-01-06"
|
|
status: "Draft"
|
|
author: "ML-Specialist + Orquestador"
|
|
epic: "OQI-006"
|
|
tags: ["ml", "attention", "factors", "dynamic", "specification"]
|
|
priority: "HIGH"
|
|
---
|
|
|
|
# ET-ML-FACTORES-ATENCION: Sistema de Atención con Factores Dinámicos
|
|
|
|
## 1. RESUMEN
|
|
|
|
Este documento especifica la implementación de un sistema de atención basado en factores dinámicos calculados con ATR/mediana rolling, eliminando los factores hardcodeados actuales y permitiendo escalabilidad a 100+ activos.
|
|
|
|
---
|
|
|
|
## 2. PROBLEMA ACTUAL
|
|
|
|
### 2.1 Factores Hardcodeados
|
|
|
|
**Ubicación actual**: `range_predictor_factor.py:598-601`
|
|
|
|
```python
|
|
# PROBLEMA: Solo 2 activos, valores estáticos
|
|
SYMBOLS = {
|
|
'XAUUSD': {'base': 2650.0, 'volatility': 0.0012, 'factor': 2.5},
|
|
'EURUSD': {'base': 1.0420, 'volatility': 0.0004, 'factor': 0.0003},
|
|
}
|
|
```
|
|
|
|
### 2.2 Impactos
|
|
|
|
| Impacto | Descripción | Severidad |
|
|
|---------|-------------|-----------|
|
|
| Escalabilidad | No escala a 100+ activos | CRÍTICO |
|
|
| Adaptabilidad | No se adapta a cambios de volatilidad | ALTO |
|
|
| Mantenimiento | Requiere código nuevo por cada activo | MEDIO |
|
|
| Precisión | Factores desactualizados degradan predicciones | ALTO |
|
|
|
|
---
|
|
|
|
## 3. SOLUCIÓN PROPUESTA
|
|
|
|
### 3.1 Cálculo Dinámico del Factor
|
|
|
|
```python
|
|
def compute_factor_median_range(
|
|
df: pd.DataFrame,
|
|
window: int = 200,
|
|
min_periods: int = 100
|
|
) -> pd.Series:
|
|
"""
|
|
Factor dinámico = mediana rolling del rango de velas con shift(1).
|
|
|
|
El shift(1) evita data leakage - solo usa información pasada.
|
|
|
|
Args:
|
|
df: DataFrame con High/Low
|
|
window: Ventana rolling (default: 200 velas)
|
|
min_periods: Períodos mínimos para calcular
|
|
|
|
Returns:
|
|
Serie con factor dinámico por timestamp
|
|
"""
|
|
range_col = df['High'] - df['Low']
|
|
factor = range_col.rolling(window=window, min_periods=min_periods).median().shift(1)
|
|
return factor
|
|
```
|
|
|
|
### 3.2 Mapeo de Pesos de Atención
|
|
|
|
**Función smooth (softplus)**:
|
|
```python
|
|
def weight_smooth(m: np.ndarray, w_max: float = 3.0, beta: float = 4.0) -> np.ndarray:
|
|
"""
|
|
Mapeo suave de multiplicador a peso de atención.
|
|
|
|
Formula: w = log1p(exp(beta * (m - 1))) / beta
|
|
|
|
Interpretación:
|
|
- m < 1 → w ≈ 0 (ruido, ignorar)
|
|
- m = 1 → w ≈ 0 (movimiento típico)
|
|
- m = 2 → w ≈ 1 (2x normal, atención media)
|
|
- m = 3 → w ≈ 2 (3x normal, atención alta)
|
|
"""
|
|
x = beta * (m - 1.0)
|
|
w = np.where(x > 20, x / beta, np.log1p(np.exp(x)) / beta)
|
|
return np.clip(w, 0.0, w_max)
|
|
```
|
|
|
|
### 3.3 Ejemplo para XAUUSD
|
|
|
|
| Variación Real | Factor Dinámico | Multiplicador | Peso de Atención |
|
|
|----------------|-----------------|---------------|------------------|
|
|
| 3.5 USD | 5.0 USD | 0.70 | **0.0** (ruido) |
|
|
| 5.0 USD | 5.0 USD | 1.00 | **0.0** (normal) |
|
|
| 7.5 USD | 5.0 USD | 1.50 | **~0.4** (interés) |
|
|
| 10.0 USD | 5.0 USD | 2.00 | **~1.0** (atención) |
|
|
| 15.0 USD | 5.0 USD | 3.00 | **~2.0** (alta atención) |
|
|
| 20.0 USD | 5.0 USD | 4.00 | **3.0** (máximo) |
|
|
|
|
---
|
|
|
|
## 4. ARQUITECTURA DE IMPLEMENTACIÓN
|
|
|
|
### 4.1 Estructura de Archivos Propuesta
|
|
|
|
```
|
|
ml-engine/src/
|
|
├── config/
|
|
│ ├── symbols_config.yaml # Configuración de símbolos (NEW)
|
|
│ └── attention_config.yaml # Configuración de atención (NEW)
|
|
├── models/
|
|
│ ├── base/
|
|
│ │ └── attention_weighted_model.py # Base class (NEW)
|
|
│ ├── trained/
|
|
│ │ ├── XAUUSD/
|
|
│ │ │ ├── 5m/
|
|
│ │ │ │ ├── range_predictor.joblib
|
|
│ │ │ │ ├── movement_predictor.joblib
|
|
│ │ │ │ └── config.yaml
|
|
│ │ │ └── 15m/
|
|
│ │ │ └── ...
|
|
│ │ ├── EURUSD/
|
|
│ │ │ └── ...
|
|
│ │ └── BTCUSDT/
|
|
│ │ └── ...
|
|
│ └── (existing models)
|
|
└── training/
|
|
└── dynamic_factor_calculator.py # (NEW)
|
|
```
|
|
|
|
### 4.2 symbols_config.yaml
|
|
|
|
```yaml
|
|
# Configuración centralizada de símbolos
|
|
# Factores iniciales para warm-start (se actualizan automáticamente)
|
|
|
|
symbols:
|
|
XAUUSD:
|
|
category: "commodity"
|
|
decimal_places: 2
|
|
pip_size: 0.01
|
|
initial_factor: 5.0 # Solo para warmup
|
|
factor_window: 200
|
|
min_periods: 100
|
|
|
|
EURUSD:
|
|
category: "forex"
|
|
decimal_places: 5
|
|
pip_size: 0.0001
|
|
initial_factor: 0.0003
|
|
factor_window: 200
|
|
min_periods: 100
|
|
|
|
BTCUSDT:
|
|
category: "crypto"
|
|
decimal_places: 2
|
|
pip_size: 0.01
|
|
initial_factor: 200.0
|
|
factor_window: 200
|
|
min_periods: 100
|
|
|
|
# ... más símbolos
|
|
```
|
|
|
|
### 4.3 DynamicFactorCalculator Class
|
|
|
|
```python
|
|
class DynamicFactorCalculator:
|
|
"""
|
|
Calcula y mantiene factores dinámicos para todos los símbolos.
|
|
|
|
Features:
|
|
- Rolling median con shift(1) para evitar leakage
|
|
- Cache de factores por símbolo
|
|
- Actualización incremental (EMA)
|
|
- Persistencia opcional en Redis/archivo
|
|
"""
|
|
|
|
def __init__(self, config_path: str = "config/symbols_config.yaml"):
|
|
self.config = self._load_config(config_path)
|
|
self._factors: Dict[str, float] = {} # Cache
|
|
self._factor_history: Dict[str, List[float]] = {}
|
|
|
|
def get_factor(self, symbol: str, df: pd.DataFrame = None) -> float:
|
|
"""Obtiene factor actual para un símbolo."""
|
|
if df is not None:
|
|
return self._compute_factor(symbol, df)
|
|
return self._factors.get(symbol, self.config['symbols'][symbol]['initial_factor'])
|
|
|
|
def _compute_factor(self, symbol: str, df: pd.DataFrame) -> float:
|
|
"""Calcula factor dinámico basado en mediana rolling."""
|
|
cfg = self.config['symbols'].get(symbol, {})
|
|
window = cfg.get('factor_window', 200)
|
|
min_periods = cfg.get('min_periods', 100)
|
|
|
|
range_col = df['High'] - df['Low']
|
|
factor = range_col.rolling(window=window, min_periods=min_periods).median().iloc[-1]
|
|
|
|
# Cache
|
|
self._factors[symbol] = factor
|
|
|
|
return factor
|
|
|
|
def update_factor_incremental(self, symbol: str, new_range: float, alpha: float = 0.02):
|
|
"""Actualización incremental usando EMA."""
|
|
current = self._factors.get(symbol)
|
|
if current is None:
|
|
self._factors[symbol] = new_range
|
|
else:
|
|
self._factors[symbol] = alpha * new_range + (1 - alpha) * current
|
|
```
|
|
|
|
---
|
|
|
|
## 5. INTEGRACIÓN CON MODELOS EXISTENTES
|
|
|
|
### 5.1 AttentionWeightedModel (Base Class)
|
|
|
|
```python
|
|
class AttentionWeightedModel(ABC):
|
|
"""
|
|
Clase base para modelos con pesos de atención dinámicos.
|
|
|
|
Subclases:
|
|
- AttentionWeightedXGBoost
|
|
- AttentionWeightedTransformer
|
|
"""
|
|
|
|
def __init__(self, symbol: str, timeframe: str):
|
|
self.symbol = symbol
|
|
self.timeframe = timeframe
|
|
self.factor_calculator = DynamicFactorCalculator()
|
|
self.attention_config = VolatilityAttentionConfig()
|
|
|
|
@abstractmethod
|
|
def train(self, X, y, df_ohlcv: pd.DataFrame):
|
|
"""Entrena modelo con pesos de atención."""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def predict(self, X, df_ohlcv: pd.DataFrame):
|
|
"""Predice con factor dinámico actual."""
|
|
pass
|
|
|
|
def compute_sample_weights(self, df: pd.DataFrame) -> np.ndarray:
|
|
"""Calcula pesos de muestra basados en volatilidad."""
|
|
factor = self.factor_calculator.get_factor(self.symbol, df)
|
|
multiplier = compute_move_multiplier(df, factor)
|
|
weights = weight_smooth(multiplier, w_max=3.0, beta=4.0)
|
|
|
|
# Normalizar a mean=1
|
|
valid_mask = ~np.isnan(weights)
|
|
if weights[valid_mask].mean() > 0:
|
|
weights[valid_mask] /= weights[valid_mask].mean()
|
|
|
|
return weights
|
|
```
|
|
|
|
### 5.2 Modificación de RangePredictor
|
|
|
|
```python
|
|
# En range_predictor.py - train()
|
|
|
|
class RangePredictor(AttentionWeightedModel):
|
|
|
|
def train(self, X, y_high, y_low, df_ohlcv: pd.DataFrame):
|
|
# Calcular pesos de atención
|
|
sample_weights = self.compute_sample_weights(df_ohlcv)
|
|
|
|
# Entrenar modelo HIGH con pesos
|
|
self.model_high = XGBRegressor(**self.config)
|
|
self.model_high.fit(X, y_high, sample_weight=sample_weights)
|
|
|
|
# Entrenar modelo LOW con pesos
|
|
self.model_low = XGBRegressor(**self.config)
|
|
self.model_low.fit(X, y_low, sample_weight=sample_weights)
|
|
```
|
|
|
|
---
|
|
|
|
## 6. SEPARACIÓN POR ACTIVO Y TEMPORALIDAD
|
|
|
|
### 6.1 Estructura de Modelos Entrenados
|
|
|
|
```
|
|
trained/
|
|
├── XAUUSD/
|
|
│ ├── 5m/
|
|
│ │ ├── config.yaml # Hyperparámetros específicos
|
|
│ │ ├── factor_stats.json # Estadísticas del factor
|
|
│ │ ├── range_predictor.joblib
|
|
│ │ ├── movement_predictor.joblib
|
|
│ │ └── attention_weights.npz
|
|
│ └── 15m/
|
|
│ └── ...
|
|
├── EURUSD/
|
|
│ ├── 5m/
|
|
│ └── 15m/
|
|
└── BTCUSDT/
|
|
├── 5m/
|
|
└── 15m/
|
|
```
|
|
|
|
### 6.2 Config.yaml por Modelo
|
|
|
|
```yaml
|
|
# trained/XAUUSD/5m/config.yaml
|
|
symbol: XAUUSD
|
|
timeframe: 5m
|
|
prediction_horizon: 15m # 3 velas de 5m
|
|
|
|
factor:
|
|
computed_at: "2026-01-06T10:00:00Z"
|
|
value: 4.85
|
|
window: 200
|
|
method: "rolling_median_shift1"
|
|
|
|
attention:
|
|
w_max: 3.0
|
|
beta: 4.0
|
|
use_smooth: true
|
|
|
|
xgboost:
|
|
n_estimators: 300
|
|
max_depth: 6
|
|
learning_rate: 0.03
|
|
|
|
training:
|
|
samples: 50000
|
|
train_period: "2021-01-01 to 2025-12-31"
|
|
validation_split: 0.2
|
|
|
|
metrics:
|
|
mae_high: 2.15
|
|
mae_low: 1.98
|
|
r2_high: 0.72
|
|
r2_low: 0.75
|
|
```
|
|
|
|
---
|
|
|
|
## 7. API PARA MODELOS
|
|
|
|
### 7.1 Endpoint Unificado (Recomendado)
|
|
|
|
```
|
|
GET /api/ml/predictions/{symbol}
|
|
?timeframe=15m
|
|
&include_models=range,movement,amd,attention
|
|
|
|
Response:
|
|
{
|
|
"symbol": "XAUUSD",
|
|
"timeframe": "15m",
|
|
"timestamp": "2026-01-06T10:30:00Z",
|
|
"current_price": 2655.50,
|
|
"dynamic_factor": 4.85,
|
|
"attention_weight": 1.8,
|
|
|
|
"models": {
|
|
"range_predictor": {
|
|
"pred_high": 2658.5,
|
|
"pred_low": 2652.0,
|
|
"confidence": 0.72,
|
|
"multiplier_high": 0.62,
|
|
"multiplier_low": 0.72
|
|
},
|
|
"movement_predictor": {
|
|
"high_usd": 8.5,
|
|
"low_usd": 3.0,
|
|
"asymmetry_ratio": 2.83,
|
|
"direction": "LONG"
|
|
},
|
|
"amd_detector": {
|
|
"phase": "ACCUMULATION",
|
|
"confidence": 0.68,
|
|
"next_phase_prob": {"manipulation": 0.25, "distribution": 0.07}
|
|
},
|
|
"attention_model": {
|
|
"pred_high": 2659.0,
|
|
"pred_low": 2651.5,
|
|
"attention_score": 1.8
|
|
}
|
|
},
|
|
|
|
"metamodel": {
|
|
"direction": "LONG",
|
|
"confidence": 0.75,
|
|
"entry": 2655.50,
|
|
"tp": 2658.7,
|
|
"sl": 2651.8,
|
|
"rr_ratio": 2.83,
|
|
"reasoning": ["High asymmetry", "Accumulation phase", "Attention > 1.5"]
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7.2 Endpoint por Modelo Individual
|
|
|
|
```
|
|
GET /api/ml/models/{model_type}/{symbol}
|
|
?timeframe=15m
|
|
|
|
# model_type: range | movement | amd | attention | ensemble
|
|
```
|
|
|
|
---
|
|
|
|
## 8. FRONTEND: 2 PÁGINAS REQUERIDAS
|
|
|
|
### 8.1 Página "ML Realtime" (`/ml/realtime`)
|
|
|
|
**Propósito**: Visualización en tiempo real de predicciones ML
|
|
|
|
**Componentes**:
|
|
1. **Cards por Activo** (grid responsive)
|
|
- Símbolo + precio actual
|
|
- Factor dinámico actual
|
|
- Attention weight visual (barra de color)
|
|
- Dirección predicha (LONG/SHORT/NEUTRAL)
|
|
- Niveles TP/SL
|
|
- Confianza
|
|
|
|
2. **Filtros**:
|
|
- Por símbolo (multi-select)
|
|
- Por confianza mínima
|
|
- Por attention weight mínimo
|
|
- Solo señales activas
|
|
|
|
3. **Auto-refresh**: 30 segundos
|
|
|
|
### 8.2 Página "ML Historical" (`/ml/historical`)
|
|
|
|
**Propósito**: Análisis de predicciones pasadas sin refresh constante
|
|
|
|
**Componentes**:
|
|
1. **Date Range Picker** (inicio - fin)
|
|
2. **Selector de Símbolo**
|
|
3. **Selector de Modelo** (o todos)
|
|
|
|
4. **Tabla de Predicciones**:
|
|
- Timestamp
|
|
- Símbolo
|
|
- Modelo
|
|
- Predicción (High/Low)
|
|
- Actual (High/Low)
|
|
- Error (MAE)
|
|
- Acierto (TP hit / SL hit / Neutral)
|
|
|
|
5. **Gráfico de Equity Curve** (basado en predicciones)
|
|
|
|
6. **Métricas Agregadas**:
|
|
- Win Rate por modelo
|
|
- MAE promedio
|
|
- R² por período
|
|
- Factor promedio usado
|
|
|
|
---
|
|
|
|
## 9. PLAN DE IMPLEMENTACIÓN
|
|
|
|
### Fase 1: Infraestructura (Prioridad ALTA)
|
|
- [ ] Crear `symbols_config.yaml`
|
|
- [ ] Implementar `DynamicFactorCalculator`
|
|
- [ ] Crear `AttentionWeightedModel` base class
|
|
- [ ] Tests unitarios
|
|
|
|
### Fase 2: Migración de Modelos
|
|
- [ ] Refactorizar `RangePredictor` para usar factores dinámicos
|
|
- [ ] Refactorizar `MovementMagnitudePredictor`
|
|
- [ ] Refactorizar `EnhancedRangePredictor`
|
|
- [ ] Tests de regresión
|
|
|
|
### Fase 3: Separación por Activo/Timeframe
|
|
- [ ] Crear estructura de directorios
|
|
- [ ] Script de migración de modelos existentes
|
|
- [ ] Pipeline de entrenamiento por activo
|
|
- [ ] Documentación
|
|
|
|
### Fase 4: API y Frontend
|
|
- [ ] Endpoint `/api/ml/predictions/{symbol}`
|
|
- [ ] Página MLRealtime
|
|
- [ ] Página MLHistorical
|
|
- [ ] Tests de integración
|
|
|
|
---
|
|
|
|
## 10. MÉTRICAS DE ÉXITO
|
|
|
|
| Métrica | Objetivo | Cómo medir |
|
|
|---------|----------|------------|
|
|
| Win Rate (movimientos fuertes) | ≥ 80% | Backtesting con attention > 1.5 |
|
|
| R:R Ratio promedio | ≥ 2:1 | Promedio de trades ejecutados |
|
|
| Tiempo de adaptación del factor | < 24h | Correlación factor vs volatilidad real |
|
|
| Latencia de predicción | < 100ms | API response time |
|
|
| Cobertura de activos | 100% de activos configurados | Símbolos con modelo entrenado |
|
|
|
|
---
|
|
|
|
## 11. RIESGOS Y MITIGACIONES
|
|
|
|
| Riesgo | Probabilidad | Impacto | Mitigación |
|
|
|--------|--------------|---------|------------|
|
|
| Factor dinámico lag | Media | Alto | Usar EMA para actualización incremental |
|
|
| Overfitting por activo | Media | Medio | Cross-validation + walk-forward |
|
|
| Pérdida de modelos | Baja | Alto | Versionado + backups |
|
|
| Incompatibilidad APIs | Baja | Medio | Tests de contrato |
|
|
|
|
---
|
|
|
|
*Documento generado: 2026-01-06*
|
|
*Pendiente de revisión: Vuelta 2*
|