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>
9.8 KiB
| id | title | type | status | priority | epic | project | version | created_date | updated_date |
|---|---|---|---|---|---|---|---|---|---|
| RF-ML-003 | Indicadores Tecnicos del ML | Requirement | Done | Alta | OQI-006 | trading-platform | 1.0.0 | 2025-12-05 | 2026-01-04 |
RF-ML-003: Indicadores Técnicos del ML
Versión: 1.0.0 Fecha: 2025-12-05 Épica: OQI-006 - Señales ML y Predicciones Prioridad: P1 Story Points: 5
Descripción
El sistema debe calcular y proporcionar indicadores técnicos avanzados utilizados como features del modelo ML. Estos indicadores deben estar disponibles tanto para el entrenamiento del modelo como para visualización en la interfaz de usuario.
Requisitos Funcionales
RF-ML-003.1: Indicadores de Volatilidad
El sistema debe calcular:
Volatilidad Estándar:
volatility_N = std(returns[-N:])
Períodos: 5, 10, 20, 50
Average True Range (ATR):
true_range = max(
high - low,
abs(high - close_prev),
abs(low - close_prev)
)
atr_N = sma(true_range, N)
Períodos: 5, 10, 20, 50
Bollinger Bands Position:
bb_middle = sma(close, 20)
bb_std = std(close, 20)
bb_upper = bb_middle + (2 * bb_std)
bb_lower = bb_middle - (2 * bb_std)
bb_position = (close - bb_lower) / (bb_upper - bb_lower)
// Rango: 0 (en banda inferior) a 1 (en banda superior)
RF-ML-003.2: Indicadores de Momentum
El sistema debe calcular:
Momentum Simple:
momentum_N = (close / close[-N]) - 1
Períodos: 5, 10, 20
Rate of Change (ROC):
roc_N = ((close - close[-N]) / close[-N]) * 100
Períodos: 5, 10, 20
Relative Strength Index (RSI):
# RSI de 14 períodos
gains = max(0, close - close_prev)
losses = max(0, close_prev - close)
avg_gain = ema(gains, 14)
avg_loss = ema(losses, 14)
rs = avg_gain / avg_loss
rsi_14 = 100 - (100 / (1 + rs))
// Rango: 0 (sobreventa extrema) a 100 (sobrecompra extrema)
// Zonas: < 30 sobreventa, > 70 sobrecompra
RF-ML-003.3: Medias Móviles
El sistema debe calcular:
Simple Moving Average (SMA):
sma_N = mean(close[-N:])
Períodos: 5, 10, 20, 50
Exponential Moving Average (EMA):
multiplier = 2 / (N + 1)
ema_N = (close * multiplier) + (ema_prev * (1 - multiplier))
Períodos: 5, 10, 20, 50
SMA Ratios:
sma_ratio_N = close / sma_N - 1
// Indica distancia del precio actual respecto a la SMA
// Positivo: precio sobre SMA (alcista)
// Negativo: precio bajo SMA (bajista)
Períodos: 5, 10, 20, 50
RF-ML-003.4: MACD (Moving Average Convergence Divergence)
El sistema debe calcular:
# MACD estándar (12, 26, 9)
ema_12 = ema(close, 12)
ema_26 = ema(close, 26)
macd_line = ema_12 - ema_26
macd_signal = ema(macd_line, 9)
macd_histogram = macd_line - macd_signal
// Interpretación:
// macd > signal: momento alcista
// macd < signal: momento bajista
// histogram > 0: aceleración alcista
// histogram < 0: aceleración bajista
RF-ML-003.5: Indicadores de Volumen
El sistema debe calcular:
Volume Ratio:
volume_sma = sma(volume, 20)
volume_ratio = volume / volume_sma
// Rango típico: 0.5 - 2.0
// > 1.5: volumen alto (confirmación de movimiento)
// < 0.7: volumen bajo (falta de interés)
RF-ML-003.6: Indicadores de High/Low
El sistema debe calcular:
High-Low Range Percentage:
hl_range_pct = (high - low) / close * 100
// Mide la volatilidad intravela
Distance to High/Low:
high_distance = (high - close) / high
low_distance = (close - low) / low
// Indica posición del cierre dentro de la vela
Historical Max/Min Ratios:
hist_max_N = max(high[-N:])
hist_min_N = min(low[-N:])
hist_max_ratio_N = close / hist_max_N - 1
hist_min_ratio_N = close / hist_min_N - 1
Períodos: 10, 20, 50, 100
Datos de Entrada
| Campo | Tipo | Descripción | Requerido |
|---|---|---|---|
| symbol | string | Par de trading | Sí |
| limit | number | Número de velas históricas | No (default: 100) |
Datos de Salida
interface TechnicalIndicators {
symbol: string;
timestamp: string;
price: number;
// Volatilidad (9 indicators)
volatility: {
vol_5: number;
vol_10: number;
vol_20: number;
vol_50: number;
atr_5: number;
atr_10: number;
atr_20: number;
atr_50: number;
bb_position: number; // 0-1
};
// Momentum (7 indicators)
momentum: {
mom_5: number;
mom_10: number;
mom_20: number;
roc_5: number;
roc_10: number;
roc_20: number;
rsi_14: number; // 0-100
};
// Medias Móviles (12 indicators)
moving_averages: {
sma_5: number;
sma_10: number;
sma_20: number;
sma_50: number;
ema_5: number;
ema_10: number;
ema_20: number;
ema_50: number;
sma_ratio_5: number;
sma_ratio_10: number;
sma_ratio_20: number;
sma_ratio_50: number;
};
// MACD (3 indicators)
macd: {
macd_line: number;
macd_signal: number;
macd_histogram: number;
};
// Volumen (1 indicator)
volume: {
volume_ratio: number;
};
// High/Low (7 indicators)
high_low: {
hl_range_pct: number;
high_distance: number;
low_distance: number;
hist_max_ratio_10: number;
hist_max_ratio_20: number;
hist_min_ratio_10: number;
hist_min_ratio_20: number;
};
}
Ejemplo:
{
"symbol": "BTCUSDT",
"timestamp": "2025-12-05T18:35:00.000Z",
"price": 89450.00,
"volatility": {
"vol_5": 0.0012,
"vol_10": 0.0015,
"vol_20": 0.0018,
"vol_50": 0.0022,
"atr_5": 250.5,
"atr_10": 280.3,
"atr_20": 310.8,
"atr_50": 345.2,
"bb_position": 0.65
},
"momentum": {
"mom_5": 0.0025,
"mom_10": 0.0045,
"mom_20": 0.0082,
"roc_5": 0.25,
"roc_10": 0.45,
"roc_20": 0.82,
"rsi_14": 58.3
},
"moving_averages": {
"sma_5": 89380.5,
"sma_10": 89320.2,
"sma_20": 89250.8,
"sma_50": 89100.4,
"ema_5": 89400.1,
"ema_10": 89350.6,
"ema_20": 89280.3,
"ema_50": 89150.7,
"sma_ratio_5": 0.0008,
"sma_ratio_10": 0.0014,
"sma_ratio_20": 0.0022,
"sma_ratio_50": 0.0039
},
"macd": {
"macd_line": 45.2,
"macd_signal": 38.7,
"macd_histogram": 6.5
},
"volume": {
"volume_ratio": 1.25
},
"high_low": {
"hl_range_pct": 0.35,
"high_distance": 0.0002,
"low_distance": 0.0032,
"hist_max_ratio_10": -0.0015,
"hist_max_ratio_20": -0.0028,
"hist_min_ratio_10": 0.0042,
"hist_min_ratio_20": 0.0078
}
}
Reglas de Negocio
- Datos Mínimos: Requiere al menos 100 velas para indicadores de período 50
- Actualización: Los indicadores se recalculan cada 5 minutos (nueva vela)
- Caché: Resultados se cachean por 1 minuto
- Precisión: Cálculos con precisión de 8 decimales
- NaN Handling: Valores NaN/Inf se reemplazan con 0 o último valor válido
Criterios de Aceptación
Escenario: Calcular indicadores para BTCUSDT
DADO que existen al menos 100 velas históricas
CUANDO hace GET /api/indicators/BTCUSDT
ENTONCES recibe 39 indicadores técnicos
Y todos los valores son números válidos (no NaN)
Y rsi_14 está entre 0 y 100
Y bb_position está entre 0 y 1
Escenario: Indicadores en tiempo real vía WebSocket
DADO que el usuario está conectado a /ws/BTCUSDT
CUANDO se cierra una nueva vela de 5 minutos
ENTONCES recibe indicadores actualizados
Y el timestamp coincide con el cierre de la vela
Escenario: Datos insuficientes
DADO que solo existen 30 velas históricas
CUANDO solicita indicadores
ENTONCES recibe error 400 Bad Request
Y el mensaje indica "Insufficient data: need 100+ candles"
Dependencias
Técnicas:
- NumPy: Cálculos vectorizados
- Pandas: Series de tiempo
- TA-Lib (opcional): Librería de indicadores técnicos
- Binance API: Datos OHLCV
Funcionales:
- Usado por RF-ML-001 (como features del modelo)
- Usado por RF-ML-002 (para generar señales)
- Usado por RF-TRD-002 (visualización en charts)
Notas Técnicas
Implementación - Feature Calculator
# apps/ml-services/src/models/indicators.py
import numpy as np
import pandas as pd
class TechnicalIndicators:
"""
Calcula indicadores técnicos para ML features
"""
@staticmethod
def calculate_all(ohlcv: pd.DataFrame) -> dict:
"""
Calcula todos los indicadores
Args:
ohlcv: DataFrame con columnas [timestamp, open, high, low, close, volume]
Returns:
dict con 39 indicadores
"""
close = ohlcv['close'].values
high = ohlcv['high'].values
low = ohlcv['low'].values
volume = ohlcv['volume'].values
indicators = {}
# Volatilidad (9)
indicators.update(calculate_volatility(close, high, low))
# Momentum (7)
indicators.update(calculate_momentum(close))
# Medias Móviles (12)
indicators.update(calculate_moving_averages(close))
# MACD (3)
indicators.update(calculate_macd(close))
# Volumen (1)
indicators.update(calculate_volume(volume))
# High/Low (7)
indicators.update(calculate_high_low(close, high, low))
return indicators
Optimizaciones:
- Uso de NumPy vectorizado (100x más rápido que loops)
- Cálculo incremental para nuevas velas
- Caché de medias móviles intermedias
Performance:
- Cálculo de 39 indicadores: < 10ms para 500 velas
- Memoria: ~50KB por símbolo en caché
Referencias
Creado por: Requirements-Analyst Fecha: 2025-12-05 Última actualización: 2025-12-05