# RF-ML-002: Generación de Señales de Trading

**Versión:** 1.0.0
**Fecha:** 2025-12-05
**Épica:** OQI-006 - Señales ML y Predicciones
**Prioridad:** P0
**Story Points:** 10

---

## Descripción

El sistema debe generar señales de trading (BUY/SELL/HOLD) basadas en las predicciones del modelo ML, combinando análisis de rango esperado, clasificación de TP/SL (Take Profit / Stop Loss) y gestión de riesgo. Las señales deben incluir niveles recomendados de entrada, objetivos y stops.

---

## Requisitos Funcionales

### RF-ML-002.1: Tipos de Señales

El sistema debe generar tres tipos de señales:

| Tipo | Condición | Acción Recomendada |
|------|-----------|-------------------|
| **BUY** | Predicción alcista con alta confianza | Abrir posición long |
| **SELL** | Predicción bajista con alta confianza | Abrir posición short o cerrar long |
| **HOLD** | Señal neutral o baja confianza | Mantener posición actual, no operar |

### RF-ML-002.2: Clasificador TP/SL

El sistema debe incluir un clasificador que determine:

**Take Profit (TP):**
- Nivel de precio objetivo para cerrar con ganancia
- Basado en `predicted_high` ajustado por confianza
- Múltiples niveles: TP1 (conservador), TP2 (moderado), TP3 (agresivo)

**Stop Loss (SL):**
- Nivel de precio máximo de pérdida aceptable
- Basado en `predicted_low` ajustado por confianza
- Ratio riesgo/recompensa mínimo: 1:2

### RF-ML-002.3: Cálculo de Señales

El sistema debe aplicar la siguiente lógica:

**Señal BUY:**
```
Condiciones:
- predicted_high > current_price * 1.005 (mín 0.5% de subida esperada)
- confidence >= 0.60
- rsi_14 < 70 (no sobrecompra)
- volume_ratio > 0.8 (volumen suficiente)

Niveles:
- entry_price = current_price
- tp1 = current_price + (predicted_high - current_price) * 0.5
- tp2 = current_price + (predicted_high - current_price) * 0.75
- tp3 = predicted_high
- stop_loss = current_price - (current_price - predicted_low) * 0.5
```

**Señal SELL:**
```
Condiciones:
- predicted_low < current_price * 0.995 (mín 0.5% de bajada esperada)
- confidence >= 0.60
- rsi_14 > 30 (no sobreventa)
- volume_ratio > 0.8

Niveles:
- entry_price = current_price
- tp1 = current_price - (current_price - predicted_low) * 0.5
- tp2 = current_price - (current_price - predicted_low) * 0.75
- tp3 = predicted_low
- stop_loss = current_price + (predicted_high - current_price) * 0.5
```

**Señal HOLD:**
```
Condiciones:
- No cumple criterios de BUY ni SELL
- O confidence < 0.60
- O rango esperado muy estrecho (< 0.5%)
```

### RF-ML-002.4: Gestión de Riesgo

El sistema debe calcular:

**Risk/Reward Ratio:**
```
rr_ratio = (tp_price - entry_price) / (entry_price - stop_loss)
```
- Mínimo aceptable: 1:2
- Óptimo: 1:3 o superior

**Position Size Recomendado:**
```
position_size = account_balance * risk_per_trade / (entry_price - stop_loss)

Donde:
- risk_per_trade: 1% - 2% del balance (configurable)
```

### RF-ML-002.5: Priorización de Señales

El sistema debe asignar prioridad a las señales:

| Prioridad | Score | Criterios |
|-----------|-------|-----------|
| **HIGH** | >= 8.0 | confidence > 0.70, RR > 1:3, volumen alto |
| **MEDIUM** | 6.0 - 7.9 | confidence > 0.60, RR > 1:2, volumen normal |
| **LOW** | 4.0 - 5.9 | confidence > 0.50, RR > 1:1.5 |

**Fórmula de Score:**
```
score = (confidence * 10) * 0.4
      + (rr_ratio / 3) * 10 * 0.4
      + (volume_ratio) * 10 * 0.2
```

### RF-ML-002.6: Histórico de Señales

El sistema debe:
- Guardar todas las señales generadas con timestamp
- Rastrear el outcome real vs predicción
- Calcular accuracy histórico de señales
- Permitir filtrado por símbolo, horizonte, tipo de señal

---

## Datos de Entrada

| Campo | Tipo | Descripción | Requerido |
|-------|------|-------------|-----------|
| symbol | string | Par de trading | Sí |
| horizon | enum | scalping, intraday, swing, position | No (default: scalping) |
| risk_per_trade | float | % de balance a arriesgar | No (default: 0.01) |

---

## Datos de Salida

```typescript
interface TradingSignal {
  signal_id: string;              // UUID único
  symbol: string;
  timestamp: string;              // ISO 8601
  horizon: string;

  // Señal principal
  action: 'BUY' | 'SELL' | 'HOLD';
  priority: 'HIGH' | 'MEDIUM' | 'LOW';
  score: number;                  // 0-10

  // Precios
  current_price: number;
  entry_price: number;

  // Niveles objetivo
  take_profit: {
    tp1: number;
    tp2: number;
    tp3: number;
  };
  stop_loss: number;

  // Métricas
  risk_reward_ratio: number;
  expected_gain_pct: number;
  max_risk_pct: number;
  confidence: number;             // 0-1

  // Posición recomendada
  recommended_position_size?: number;

  // Indicadores técnicos
  rsi: number;
  volume_ratio: number;

  // Razones
  reasons: string[];              // Por qué se generó la señal
}
```

**Ejemplo:**
```json
{
  "signal_id": "550e8400-e29b-41d4-a716-446655440000",
  "symbol": "BTCUSDT",
  "timestamp": "2025-12-05T18:30:00.000Z",
  "horizon": "scalping",
  "action": "BUY",
  "priority": "HIGH",
  "score": 8.5,
  "current_price": 89400.00,
  "entry_price": 89400.00,
  "take_profit": {
    "tp1": 89650.00,
    "tp2": 89775.00,
    "tp3": 89900.00
  },
  "stop_loss": 89150.00,
  "risk_reward_ratio": 2.0,
  "expected_gain_pct": 0.56,
  "max_risk_pct": 0.28,
  "confidence": 0.72,
  "recommended_position_size": 0.05,
  "rsi": 55.3,
  "volume_ratio": 1.2,
  "reasons": [
    "Strong upward prediction (0.72 confidence)",
    "Healthy RSI (55.3, not overbought)",
    "Above average volume (1.2x)",
    "Favorable risk/reward (1:2)"
  ]
}
```

---

## Reglas de Negocio

1. **Generación Continua:** Las señales se generan cada 5 minutos (cierre de vela)
2. **Expiración:** Una señal expira después de su horizonte temporal
3. **No Duplicados:** No generar señal BUY si ya existe una activa del mismo horizonte
4. **Señal Contradictoria:** Una SELL cancela una BUY anterior del mismo horizonte
5. **Límite Diario:** Máximo 50 señales HIGH por símbolo por día
6. **Validación de Precio:** El entry_price debe estar dentro del 0.1% del current_price

---

## Criterios de Aceptación

```gherkin
Escenario: Generar señal BUY con alta confianza
  DADO que BTCUSDT tiene predicción alcista
  Y confidence = 0.75
  Y predicted_high = current_price * 1.008
  Y RSI = 55
  CUANDO el sistema calcula la señal
  ENTONCES action = "BUY"
  Y priority = "HIGH"
  Y se generan 3 niveles de TP
  Y risk_reward_ratio >= 2.0

Escenario: Generar señal HOLD por baja confianza
  DADO que ETHUSDT tiene predicción neutral
  Y confidence = 0.45
  CUANDO el sistema calcula la señal
  ENTONCES action = "HOLD"
  Y priority = "LOW"
  Y reasons incluye "Low confidence"

Escenario: Señal SELL en mercado bajista
  DADO que BTCUSDT tiene predicción bajista
  Y confidence = 0.68
  Y predicted_low = current_price * 0.992
  CUANDO el sistema calcula la señal
  ENTONCES action = "SELL"
  Y priority = "MEDIUM" o "HIGH"
  Y stop_loss > entry_price

Escenario: Obtener señales vía API
  DADO que el usuario está autenticado
  CUANDO hace GET /api/signals/BTCUSDT?horizon=scalping
  ENTONCES recibe la señal más reciente
  Y la señal tiene menos de 5 minutos
  Y incluye todos los niveles de TP/SL
```

---

## Dependencias

### Técnicas:
- **RF-ML-001:** Predicciones de rangos de precio
- **RF-ML-003:** Indicadores técnicos (RSI, volumen)
- **PostgreSQL:** Almacenamiento de histórico de señales
- **Redis:** Caché de señales activas

### Funcionales:
- Sistema de notificaciones para alertas (RF-ML-005)
- Integración con charts para visualización (RF-TRD-001)

---

## Notas Técnicas

### Arquitectura del Generador de Señales

```python
# apps/ml-services/src/models/signal_generator.py

class SignalGenerator:
    """
    Genera señales de trading basadas en predicciones ML
    """

    def generate_signal(
        self,
        symbol: str,
        horizon: str,
        risk_per_trade: float = 0.01
    ) -> TradingSignal:
        # 1. Obtener predicción del ML
        prediction = predictor.predict(symbol, horizon)

        # 2. Obtener indicadores técnicos actuales
        indicators = get_current_indicators(symbol)

        # 3. Determinar acción (BUY/SELL/HOLD)
        action = classify_action(prediction, indicators)

        # 4. Calcular niveles de TP/SL
        levels = calculate_levels(action, prediction)

        # 5. Calcular métricas de riesgo
        metrics = calculate_risk_metrics(levels, risk_per_trade)

        # 6. Asignar prioridad y score
        priority, score = calculate_priority(prediction, metrics, indicators)

        # 7. Construir razones
        reasons = build_reasons(action, prediction, indicators, metrics)

        return TradingSignal(...)
```

### Base de Datos - Tabla `ml_signals`

```sql
CREATE TABLE ml_signals (
  signal_id UUID PRIMARY KEY,
  symbol VARCHAR(20) NOT NULL,
  horizon VARCHAR(20) NOT NULL,
  action VARCHAR(10) NOT NULL,
  priority VARCHAR(10) NOT NULL,
  score DECIMAL(4,2),

  current_price DECIMAL(20,8),
  entry_price DECIMAL(20,8),
  tp1 DECIMAL(20,8),
  tp2 DECIMAL(20,8),
  tp3 DECIMAL(20,8),
  stop_loss DECIMAL(20,8),

  confidence DECIMAL(4,3),
  risk_reward_ratio DECIMAL(5,2),

  created_at TIMESTAMP DEFAULT NOW(),
  expires_at TIMESTAMP,

  -- Tracking
  actual_outcome VARCHAR(20),  -- hit_tp1, hit_tp2, hit_sl, expired
  closed_at TIMESTAMP,
  actual_gain_pct DECIMAL(6,3),

  INDEX idx_symbol_horizon (symbol, horizon),
  INDEX idx_created_at (created_at),
  INDEX idx_priority (priority)
);
```

### Performance:
- Generación de señal: < 100ms
- Consulta de señales activas: < 50ms (con índices)
- Caché en Redis por 5 minutos

---

## Referencias

- [Risk Management in Trading](https://www.investopedia.com/articles/trading/09/risk-management.asp)
- [Take Profit and Stop Loss Strategies](https://www.babypips.com/learn/forex/take-profit-stop-loss)
- [Position Sizing Calculator](https://www.myfxbook.com/forex-calculators/position-size-calculator)

---

**Creado por:** Requirements-Analyst
**Fecha:** 2025-12-05
**Última actualización:** 2025-12-05
