--- id: "ET-ML-014" title: "MTS (Multi-Timeframe Synthesis) Strategy" type: "Technical Specification" status: "Approved" priority: "Alta" epic: "OQI-006" project: "trading-platform" version: "1.0.0" created_date: "2026-01-25" updated_date: "2026-01-25" task_reference: "TASK-2026-01-25-ML-TRAINING-ENHANCEMENT" --- # ET-ML-014: MTS (Multi-Timeframe Synthesis) Strategy ## Metadata | Campo | Valor | |-------|-------| | **ID** | ET-ML-014 | | **Epica** | OQI-006 - Senales ML | | **Tipo** | Especificacion Tecnica | | **Version** | 1.0.0 | | **Estado** | Aprobado | | **Ultima actualizacion** | 2026-01-25 | | **Tarea Referencia** | TASK-2026-01-25-ML-TRAINING-ENHANCEMENT | --- ## Resumen La estrategia MTS (Multi-Timeframe Synthesis) sintetiza informacion de multiples timeframes usando una **Hierarchical Attention Network** para generar una representacion unificada y **XGBoost** para predicciones finales. El modelo calcula **alineamiento entre timeframes** y **scores de conflicto**. ### Caracteristicas Clave - **4 Timeframes**: 5m, 15m, 1h, 4h agregados desde datos base - **Hierarchical Attention**: Aprende pesos dinamicos por timeframe - **Alignment Score**: Mide coherencia entre timeframes - **Conflict Score**: Identifica divergencias entre timeframes --- ## Arquitectura ### Diagrama de Alto Nivel ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ MTS MODEL │ ├─────────────────────────────────────────────────────────────────────────┤ │ │ │ Input: 5m OHLCV Data (base timeframe) │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ TIMEFRAME AGGREGATION │ │ │ │ │ │ │ │ 5m Data ─┬──▶ 5m Features ───────────────────────┐ │ │ │ │ │ │ │ │ │ │ ├──▶ 15m Aggregation ──▶ 15m Features ───┤ │ │ │ │ │ │ │ │ │ │ ├──▶ 1h Aggregation ──▶ 1h Features ───┤ │ │ │ │ │ │ │ │ │ │ └──▶ 4h Aggregation ──▶ 4h Features ───┘ │ │ │ │ │ │ │ │ └─────────────────────────────────────────│──────────────────────────┘ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ HIERARCHICAL ATTENTION NETWORK │ │ │ │ │ │ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ │ │ Per-Timeframe Encoders │ │ │ │ │ │ │ │ │ │ │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │ │ │ │ │ 5m │ │ 15m │ │ 1h │ │ 4h │ │ │ │ │ │ │ │Enc. │ │Enc. │ │Enc. │ │Enc. │ │ │ │ │ │ │ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └─────│──────────│──────────│──────────│────────────────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ └──────────┼──────────┼──────────┘ │ │ │ │ ▼ ▼ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ │ Cross-Timeframe Attention │ │ │ │ │ │ (learns TF relationships) │ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ │ Timeframe Fusion Layer │ │ │ │ │ │ (learnable TF weights) │ │ │ │ │ └─────────────────────────────────┘ │ │ │ │ │ │ │ │ │ ▼ │ │ │ │ ┌─────────────────────────────────┐ │ │ │ │ │ Unified Representation │ │ │ │ │ │ (d_model = 128) │ │ │ │ │ └─────────────────────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ ┌───────────────────────────────────────────────────────────────────┐ │ │ │ XGBOOST HEADS │ │ │ │ │ │ │ │ ┌────────────────┐ ┌────────────────┐ ┌────────────────┐ │ │ │ │ │ Direction │ │ Confidence │ │ Optimal Entry │ │ │ │ │ │ Classifier │ │ Regressor │ │ TF Classifier │ │ │ │ │ │ (3 classes) │ │ (0 to 1) │ │ (4 classes) │ │ │ │ │ └────────────────┘ └────────────────┘ └────────────────┘ │ │ │ └───────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ Output: MTSPrediction │ │ - unified_direction: -1 to 1 │ │ - confidence_by_alignment: 0 to 1 │ │ - optimal_entry_tf: '5m' | '15m' | '1h' | '4h' │ │ - tf_contributions: Dict[str, float] │ └─────────────────────────────────────────────────────────────────────────┘ ``` ### Hierarchical Attention Config ```python HierarchicalAttentionConfig: d_model: 128 n_heads: 4 d_ff: 256 n_layers: 2 dropout: 0.1 max_seq_len: 256 timeframes: ('5m', '15m', '1h', '4h') use_cross_tf_attention: True use_learnable_tf_weights: True ``` --- ## Timeframe Aggregation ### Proceso de Agregacion El modelo recibe datos en 5m y agrega a timeframes superiores: ```python class MTSFeatureEngineer: def aggregate_to_timeframe( self, df_5m: pd.DataFrame, target_tf: str ) -> pd.DataFrame: """Agregar datos de 5m al timeframe objetivo""" # Mapeo de periodos periods = { '5m': 1, '15m': 3, '1h': 12, '4h': 48 } n_periods = periods[target_tf] # Agregar OHLCV resampled = df_5m.resample(target_tf).agg({ 'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum' }) return resampled ``` ### Features por Timeframe Cada timeframe tiene su propio conjunto de features: ```python Per-Timeframe Features: # Price-based returns_1: 1-period return returns_5: 5-period return returns_10: 10-period return # Volatility atr_14: ATR(14) volatility: rolling std of returns # Momentum rsi_14: RSI(14) macd: MACD line macd_signal: Signal line # Trend ema_8: EMA(8) ema_21: EMA(21) ema_55: EMA(55) trend_strength: EMA crossover metrics ``` --- ## Alignment y Conflict Scores ### Alignment Score Mide la coherencia direccional entre timeframes: ```python def compute_alignment_score( tf_features: Dict[str, np.ndarray] ) -> float: """Calcular alineamiento entre timeframes""" # Extraer direccion de cada timeframe directions = {} for tf, features in tf_features.items(): # Direction basada en trend indicators trend = np.sign(features['ema_8'] - features['ema_21']) momentum = np.sign(features['rsi_14'] - 50) macd_dir = np.sign(features['macd']) directions[tf] = np.mean([trend, momentum, macd_dir]) # Calcular coherencia all_directions = list(directions.values()) # Alignment = 1 si todos tienen misma direccion # Alignment = 0 si direcciones contradictorias alignment = 1 - np.std(all_directions) return np.clip(alignment, 0, 1) ``` ### Conflict Score Identifica divergencias significativas: ```python def compute_conflict_score( tf_features: Dict[str, np.ndarray], hierarchy: List[str] = ['4h', '1h', '15m', '5m'] ) -> float: """Calcular conflicto entre timeframes""" conflicts = [] for i, higher_tf in enumerate(hierarchy[:-1]): for lower_tf in hierarchy[i+1:]: higher_dir = get_direction(tf_features[higher_tf]) lower_dir = get_direction(tf_features[lower_tf]) # Conflicto si direcciones opuestas if higher_dir * lower_dir < 0: # Mas peso si el conflicto es con TF mayor weight = 1.0 / (i + 1) conflicts.append(weight) conflict_score = sum(conflicts) / len(hierarchy) if conflicts else 0 return np.clip(conflict_score, 0, 1) ``` ### Interpretacion | Alignment | Conflict | Interpretacion | Accion | |-----------|----------|----------------|--------| | > 0.8 | < 0.2 | Fuerte consenso | Trade con confianza | | 0.5-0.8 | 0.2-0.5 | Consenso parcial | Trade con precaucion | | < 0.5 | > 0.5 | Mercado mixto | Esperar o reducir size | | < 0.3 | > 0.7 | Conflicto severo | No operar | --- ## Hierarchical Attention Network ### Per-Timeframe Encoder Cada timeframe tiene su propio encoder: ```python class TimeframeEncoder(nn.Module): def __init__(self, input_dim: int, d_model: int): super().__init__() self.input_proj = nn.Linear(input_dim, d_model) self.encoder = nn.TransformerEncoder( nn.TransformerEncoderLayer( d_model=d_model, nhead=4, dim_feedforward=d_model * 2, dropout=0.1 ), num_layers=2 ) def forward(self, x: torch.Tensor) -> torch.Tensor: x = self.input_proj(x) return self.encoder(x) ``` ### Cross-Timeframe Attention Modela relaciones entre timeframes: ```python class CrossTimeframeAttention(nn.Module): def __init__(self, d_model: int, n_heads: int, n_timeframes: int): super().__init__() self.attention = nn.MultiheadAttention(d_model, n_heads) # Embeddings para cada timeframe self.tf_embeddings = nn.Embedding(n_timeframes, d_model) def forward( self, tf_features: Dict[str, torch.Tensor] ) -> torch.Tensor: # Concatenar features de todos los TFs tf_list = list(tf_features.keys()) features = torch.stack([tf_features[tf] for tf in tf_list]) # Agregar TF embeddings tf_ids = torch.arange(len(tf_list)) tf_embs = self.tf_embeddings(tf_ids) features = features + tf_embs.unsqueeze(1) # Cross-attention attended, weights = self.attention(features, features, features) return attended, weights ``` ### Learnable Timeframe Weights ```python class TimeframeFusion(nn.Module): def __init__(self, n_timeframes: int, d_model: int): super().__init__() # Pesos aprendibles por timeframe self.tf_weights = nn.Parameter(torch.ones(n_timeframes)) # Fusion layer self.fusion = nn.Sequential( nn.Linear(d_model * n_timeframes, d_model * 2), nn.GELU(), nn.Dropout(0.1), nn.Linear(d_model * 2, d_model) ) def forward( self, tf_features: List[torch.Tensor], alignment: torch.Tensor, conflict: torch.Tensor ) -> torch.Tensor: # Normalizar pesos weights = F.softmax(self.tf_weights, dim=0) # Ponderar features weighted_features = [] for i, feat in enumerate(tf_features): weighted_features.append(feat * weights[i]) # Ajustar por alignment (mas peso si hay consenso) alignment_factor = 0.5 + alignment * 0.5 # Concatenar y fusionar concat = torch.cat(weighted_features, dim=-1) unified = self.fusion(concat) * alignment_factor return unified, weights ``` --- ## Training Pipeline ### Fase 1: Feature Preparation ```python model = MTSModel(config) # Preparar datos multi-TF desde 5m base tf_features, alignment, conflict = model._prepare_features(df_5m) # Shape: {tf: (n_samples, seq_len, n_features)} print(f"5m features: {tf_features['5m'].shape}") print(f"1h features: {tf_features['1h'].shape}") print(f"Alignment: {alignment.shape}") print(f"Conflict: {conflict.shape}") ``` ### Fase 2: Attention Training ```python # Entrenar hierarchical attention model.train_attention( train_data=train_dfs, # List of 5m DataFrames val_data=val_dfs, epochs=50, batch_size=32, lr=0.001 ) ``` ### Fase 3: XGBoost Training ```python # Extraer representaciones unificadas unified_rep = model._extract_unified_representation(tf_features, alignment, conflict) # Generar labels y_direction = generate_direction_labels(df, forward_bars=12) y_confidence = generate_confidence_targets(alignment, conflict) y_entry_tf = determine_optimal_entry_tf(df, tf_features) # Entrenar XGBoost model.train_xgboost( X_train=unified_rep, y_direction=y_direction, y_confidence=y_confidence, y_entry_tf=y_entry_tf ) ``` ### XGBoost Configuration ```python MTSConfig: xgb_n_estimators: 200 xgb_max_depth: 6 xgb_learning_rate: 0.05 xgb_subsample: 0.8 xgb_colsample_bytree: 0.8 xgb_min_child_weight: 5 xgb_reg_alpha: 0.1 xgb_reg_lambda: 1.0 ``` --- ## Metricas de Evaluacion ### Metricas de Direccion | Metrica | Descripcion | Target | |---------|-------------|--------| | **Direction Accuracy** | Precision direccional | >= 55% | | **Direction F1** | F1 por clase | >= 0.50 | | **Alignment-Weighted Accuracy** | Accuracy ponderada por alignment | >= 60% | ### Metricas de Confianza | Metrica | Descripcion | Target | |---------|-------------|--------| | **Confidence MSE** | Error en prediccion de confianza | < 0.1 | | **Calibration Score** | Alineacion confianza-accuracy | > 0.8 | ### Metricas Multi-TF | Metrica | Descripcion | Target | |---------|-------------|--------| | **TF Contribution Stability** | Estabilidad de pesos TF | std < 0.1 | | **Optimal TF Accuracy** | Precision en TF de entrada optimo | >= 50% | | **Alignment Prediction** | Correlacion alignment predicho vs real | > 0.7 | --- ## API y Uso ### Clase Principal: MTSModel ```python from models.strategies.mts import MTSModel, MTSConfig, MTSPrediction # Configuracion config = MTSConfig( timeframes=('5m', '15m', '1h', '4h'), d_model=128, n_heads=4, n_layers=2, use_cross_tf_attention=True, use_learnable_tf_weights=True ) # Inicializar modelo model = MTSModel(config, use_xgboost=True) # Entrenar model.train_attention(train_dfs, val_dfs, epochs=50) model.train_xgboost(X_train, y_direction, y_confidence, y_entry_tf) # Prediccion desde datos 5m prediction = model.predict(df_5m) print(f"Direction: {prediction.direction_class} ({prediction.unified_direction:.2f})") print(f"Confidence: {prediction.confidence:.2f}") print(f"Optimal Entry TF: {prediction.optimal_entry_tf}") print(f"TF Contributions: {prediction.tf_contributions}") ``` ### Clase MTSPrediction ```python @dataclass class MTSPrediction: unified_direction: float # -1 to 1 direction_class: str # 'bullish', 'bearish', 'neutral' confidence: float # 0 to 1 confidence_by_alignment: float # Based on TF alignment optimal_entry_tf: str # '5m', '15m', '1h', '4h' tf_contributions: Dict[str, float] # Weight per TF signal_strength: float # 0 to 1 recommended_action: str # 'buy', 'sell', 'hold' def to_dict(self) -> Dict[str, Any]: return { 'unified_direction': float(self.unified_direction), 'direction_class': self.direction_class, 'confidence': float(self.confidence), 'confidence_by_alignment': float(self.confidence_by_alignment), 'optimal_entry_tf': self.optimal_entry_tf, 'tf_contributions': self.tf_contributions, 'signal_strength': float(self.signal_strength), 'recommended_action': self.recommended_action } ``` ### Timeframe Contributions ```python # Obtener contribucion de cada timeframe contributions = model.get_tf_contributions() # Ejemplo output: # { # '5m': 0.15, # Short-term noise # '15m': 0.25, # Entry timing # '1h': 0.35, # Main trend # '4h': 0.25 # Higher TF context # } # Interpretar: 1h es el TF mas importante para esta prediccion ``` --- ## Estructura de Archivos ``` apps/ml-engine/src/models/strategies/mts/ ├── __init__.py ├── model.py # MTSModel, MTSConfig, MTSPrediction ├── feature_engineering.py # MTSFeatureEngineer (aggregation + features) ├── hierarchical_attention.py # HierarchicalAttention, CrossTFAttention ├── timeframe_fusion.py # TimeframeFusion layer └── trainer.py # MTSTrainer ``` --- ## Estrategias de Trading ### Entry Based on Alignment ```python def generate_entry_signal(pred: MTSPrediction) -> Optional[Dict]: """Generar senal basada en MTS""" # Solo operar con alto alineamiento if pred.confidence_by_alignment < 0.6: return None # Direccion clara if abs(pred.unified_direction) < 0.3: return None direction = 'LONG' if pred.unified_direction > 0 else 'SHORT' return { 'direction': direction, 'entry_tf': pred.optimal_entry_tf, 'confidence': pred.signal_strength, 'tf_weights': pred.tf_contributions } ``` ### Multi-TF Confirmation ```python def check_tf_confirmation(pred: MTSPrediction) -> Dict: """Verificar confirmacion multi-TF""" contributions = pred.tf_contributions # Verificar que TFs mayores esten alineados higher_tf_weight = contributions['4h'] + contributions['1h'] lower_tf_weight = contributions['15m'] + contributions['5m'] # Preferir cuando TFs mayores tienen mas peso if higher_tf_weight > lower_tf_weight: quality = 'HIGH' else: quality = 'MEDIUM' return { 'quality': quality, 'higher_tf_weight': higher_tf_weight, 'lower_tf_weight': lower_tf_weight, 'dominant_tf': max(contributions, key=contributions.get) } ``` --- ## Consideraciones de Produccion ### Real-Time Multi-TF Updates ```python class MTSRealtime: def __init__(self, model_path: str): self.model = MTSModel.load(model_path) self.buffers = { '5m': deque(maxlen=500), '15m': deque(maxlen=200), '1h': deque(maxlen=100), '4h': deque(maxlen=50) } def on_candle_5m(self, candle: Dict) -> Optional[MTSPrediction]: self.buffers['5m'].append(candle) # Agregar a TFs superiores si es momento if self._is_15m_close(): self._aggregate_to_tf('15m') if self._is_1h_close(): self._aggregate_to_tf('1h') if self._is_4h_close(): self._aggregate_to_tf('4h') # Predecir si tenemos suficientes datos if len(self.buffers['5m']) >= 100: df_5m = pd.DataFrame(list(self.buffers['5m'])) return self.model.predict(df_5m) return None ``` ### Caching de Aggregations ```python # Cache TFs superiores (cambian menos frecuentemente) @cached(ttl=60) # Cache por 1 minuto def get_cached_1h_features(symbol: str) -> np.ndarray: df = get_1h_data(symbol, bars=100) return compute_features(df) @cached(ttl=240) # Cache por 4 minutos def get_cached_4h_features(symbol: str) -> np.ndarray: df = get_4h_data(symbol, bars=50) return compute_features(df) ``` ### Performance | Operacion | Tiempo | Notas | |-----------|--------|-------| | TF Aggregation | 10ms | 4 timeframes | | Feature computation | 20ms | Per TF | | Attention inference | 30ms | Hierarchical | | XGBoost prediction | 5ms | 3 heads | | **Total** | ~100ms | Full prediction | --- ## Referencias - [ET-ML-001: Arquitectura ML Engine](./ET-ML-001-arquitectura.md) - [ET-ML-010: PVA Strategy](./ET-ML-010-pva-strategy.md) - [Hierarchical Attention Networks (Yang et al.)](https://www.cs.cmu.edu/~./hovy/papers/16HLT-hierarchical-attention-networks.pdf) - [Multi-Scale Temporal Fusion](https://arxiv.org/abs/1912.09363) --- **Autor:** ML-Specialist (NEXUS v4.0) **Fecha:** 2026-01-25