---
id: "US-ML-024"
title: "HISTORIA DE USUARIO"
type: "User Story"
status: "Done"
priority: "Media"
epic: "OQI-006"
project: "trading-platform"
story_points: 3
created_date: "2025-12-05"
updated_date: "2026-01-04"
---

# HISTORIA DE USUARIO

**Version:** 1.0.0
**Fecha:** 2025-12-05
**Uso:** Definicion de historia de usuario

---

## US-ML-024: Ver Score de Confluencia Multi-Factor

### Metadata

| Campo | Valor |
|-------|-------|
| **ID** | US-ML-024 |
| **Epica** | OQI-006A - Estrategia AMD y Modelos ML Avanzados |
| **Modulo** | ml-signals |
| **Prioridad** | P0 |
| **Story Points** | 8 |
| **Sprint** | Sprint 9 |
| **Estado** | Ready |
| **Asignado a** | ML-Engineer / Frontend-Developer |

---

### Historia de Usuario

**Como** trader que busca senales de alta probabilidad,
**quiero** ver un score de confluencia que combine multiples factores (AMD, liquidez, ICT, SMC, predicciones ML),
**para** evaluar rapidamente la calidad de una senal y tomar decisiones de trading con mayor confianza.

### Descripcion Detallada

El Score de Confluencia es un indicador compuesto que pondera multiples factores para determinar la calidad de una oportunidad de trading:

**Factores del Score:**
1. **AMD Phase (25%):** Acumulacion/Distribucion favorables, Manipulacion penaliza
2. **Range Prediction (20%):** Confianza en prediccion de delta_high/delta_low
3. **TPSL Probability (20%):** P(TP antes de SL)
4. **Liquidity (15%):** Proximidad a zonas de liquidez
5. **ICT/SMC (10%):** Killzone, OTE, estructura de mercado
6. **Momentum (10%):** RSI, MACD, tendencia

**Escala de Score:**
- 80-100: **Excelente** (A) - Alta probabilidad, operar con conviccion
- 60-79: **Bueno** (B) - Probabilidad media-alta, considerar operar
- 40-59: **Regular** (C) - Probabilidad media, precaucion
- 0-39: **Bajo** (D) - Probabilidad baja, evitar operar

### Mockups/Wireframes

```
+----------------------------------------------------------+
|                    CONFLUENCE SCORE                       |
+----------------------------------------------------------+
|                                                          |
|              [==========] 78/100                         |
|                   BUENO (B)                              |
|                                                          |
|  +----------------------------------------------------+  |
|  | Factor           | Score | Weight | Contrib |       |  |
|  |--------------------|-------|--------|---------|       |  |
|  | AMD Phase (ACC)    |  85   |  25%   |  21.3  |       |  |
|  | Range Prediction   |  72   |  20%   |  14.4  |       |  |
|  | TPSL Probability   |  81   |  20%   |  16.2  |       |  |
|  | Liquidity          |  65   |  15%   |   9.8  |       |  |
|  | ICT/SMC            |  78   |  10%   |   7.8  |       |  |
|  | Momentum           |  85   |  10%   |   8.5  |       |  |
|  |--------------------|-------|--------|---------|       |  |
|  | TOTAL              |  --   | 100%   |  78.0  |       |  |
|  +----------------------------------------------------+  |
|                                                          |
|  [?] What is this?     [Customize Weights]              |
|                                                          |
+----------------------------------------------------------+
```

**Vista Compacta:**
```
+------------------------+
| CONFLUENCE: 78/100 (B) |
| [=================   ] |
+------------------------+
```

---

### Criterios de Aceptacion

**Escenario 1: Visualizacion de score general**
```gherkin
DADO que hay una senal de trading activa
CUANDO veo el indicador de confluencia
ENTONCES veo el score numerico (0-100)
Y veo la categoria (A/B/C/D)
Y veo una barra de progreso visual con color (verde/amarillo/naranja/rojo)
```

**Escenario 2: Desglose de factores**
```gherkin
DADO que estoy viendo el score de confluencia
CUANDO expando el panel de detalles
ENTONCES veo cada factor con su score individual (0-100)
Y veo el peso de cada factor (porcentaje)
Y veo la contribucion al score total
```

**Escenario 3: Actualizacion en tiempo real**
```gherkin
DADO que estoy viendo el score de confluencia
CUANDO cambia algun factor (AMD, prediccion, etc.)
ENTONCES el score se actualiza en menos de 3 segundos
Y los factores que cambiaron se destacan brevemente
```

**Escenario 4: Personalizacion de pesos**
```gherkin
DADO que quiero personalizar los pesos
CUANDO accedo a "Customize Weights"
ENTONCES puedo ajustar el peso de cada factor (0-100%)
Y el sistema valida que sumen 100%
Y puedo guardar mi configuracion personalizada
Y puedo restaurar pesos por defecto
```

**Escenario 5: Tooltip explicativo**
```gherkin
DADO que no entiendo un factor
CUANDO hago hover sobre el nombre del factor
ENTONCES veo un tooltip con:
  - Descripcion del factor
  - Como se calcula
  - Que valores son ideales
```

**Escenario 6: Sin datos suficientes**
```gherkin
DADO que faltan datos para calcular el score
CUANDO algun factor no esta disponible
ENTONCES el factor muestra "N/A"
Y el score se calcula con los factores disponibles (reajustando pesos)
Y se muestra advertencia "Datos parciales"
```

### Criterios Adicionales

- [ ] Score visible en vista compacta y expandida
- [ ] Colores accesibles (WCAG AA)
- [ ] Animacion suave en cambios de score
- [ ] Historial de scores en sesion actual
- [ ] Export a CSV de desglose de factores

---

### Tareas Tecnicas

**Backend (FastAPI):**
- [ ] BE-ML-040: Endpoint GET /api/ml/confluence/current
- [ ] BE-ML-041: Endpoint GET /api/ml/confluence/history
- [ ] BE-ML-042: Endpoint PUT /api/ml/confluence/weights (personalizar)
- [ ] BE-ML-043: WebSocket para streaming de score

**ML Model (StrategyOrchestrator):**
- [ ] ML-040: Implementar ConfluenceScorer.calculate()
- [ ] ML-041: Normalizar scores de cada modelo (0-100)
- [ ] ML-042: Weighted average con pesos configurables
- [ ] ML-043: Cache de scores (TTL 30s)

**Frontend:**
- [ ] FE-ML-040: Componente ConfluenceScoreCard (expandible)
- [ ] FE-ML-041: Componente ConfluenceScoreCompact
- [ ] FE-ML-042: Componente ConfluenceFactorRow
- [ ] FE-ML-043: Modal WeightsCustomizer
- [ ] FE-ML-044: Store confluenceStore (Zustand)

**Tests:**
- [ ] TEST-ML-040: Unit tests ConfluenceScorer
- [ ] TEST-ML-041: Unit tests normalizacion
- [ ] TEST-ML-042: E2E tests visualizacion

---

### Dependencias

**Depende de:**
- [ ] US-ML-020: Ver fase AMD - Estado: Ready
- [ ] US-ML-022: Ver zonas liquidez - Estado: Ready
- [ ] RangePredictor, TPSLClassifier funcionando - Estado: Done

**Bloquea:**
- [ ] US-ML-023: Senales filtradas por confluencia

---

### Notas Tecnicas

**Endpoints involucrados:**
| Metodo | Endpoint | Descripcion |
|--------|----------|-------------|
| GET | /api/ml/confluence/current | Score actual |
| GET | /api/ml/confluence/history | Historial de scores |
| PUT | /api/ml/confluence/weights | Personalizar pesos |
| WS | /ws/ml/confluence | Stream de actualizaciones |

**Entidades/Tablas:**
- `ml.confluence_scores`: Historial de scores
- `user_preferences.confluence_weights`: Pesos personalizados

**Componentes UI:**
- `ConfluenceScoreCard`: Card principal expandible
- `ConfluenceScoreCompact`: Version mini para header
- `ConfluenceFactorRow`: Fila individual de factor
- `WeightsCustomizer`: Modal de configuracion

**Response Schema:**
```typescript
interface ConfluenceScore {
  score: number;              // 0-100
  category: 'A' | 'B' | 'C' | 'D';
  factors: ConfluenceFactor[];
  timestamp: string;          // ISO 8601
  partial_data: boolean;      // Si faltan factores
}

interface ConfluenceFactor {
  name: string;
  value: number;              // 0-100
  weight: number;             // 0-1
  contribution: number;       // value * weight
  available: boolean;
  description: string;
  details: Record<string, any>;
}

// Ejemplo de respuesta
{
  "score": 78,
  "category": "B",
  "factors": [
    {
      "name": "amd_phase",
      "value": 85,
      "weight": 0.25,
      "contribution": 21.25,
      "available": true,
      "description": "Fase AMD actual del mercado",
      "details": {
        "phase": "accumulation",
        "confidence": 0.85
      }
    },
    {
      "name": "range_prediction",
      "value": 72,
      "weight": 0.20,
      "contribution": 14.4,
      "available": true,
      "description": "Confianza en prediccion de rango",
      "details": {
        "delta_high_confidence": 0.75,
        "delta_low_confidence": 0.68
      }
    }
    // ... mas factores
  ],
  "timestamp": "2025-12-05T14:30:00Z",
  "partial_data": false
}
```

**Logica de Scoring:**
```python
class ConfluenceScorer:
    DEFAULT_WEIGHTS = {
        'amd_phase': 0.25,
        'range_prediction': 0.20,
        'tpsl_probability': 0.20,
        'liquidity': 0.15,
        'ict_smc': 0.10,
        'momentum': 0.10
    }

    def calculate(self, predictions: dict, weights: dict = None) -> ConfluenceScore:
        weights = weights or self.DEFAULT_WEIGHTS
        factors = []
        total_weight = 0
        weighted_sum = 0

        for name, weight in weights.items():
            if name in predictions and predictions[name] is not None:
                value = self._normalize_score(name, predictions[name])
                contribution = value * weight
                weighted_sum += contribution
                total_weight += weight
                factors.append(ConfluenceFactor(
                    name=name,
                    value=value,
                    weight=weight,
                    contribution=contribution,
                    available=True
                ))
            else:
                factors.append(ConfluenceFactor(
                    name=name,
                    value=0,
                    weight=weight,
                    contribution=0,
                    available=False
                ))

        # Reajustar si hay datos parciales
        if total_weight < 1.0 and total_weight > 0:
            score = weighted_sum / total_weight
        else:
            score = weighted_sum

        return ConfluenceScore(
            score=round(score, 1),
            category=self._get_category(score),
            factors=factors,
            partial_data=total_weight < 1.0
        )

    def _get_category(self, score: float) -> str:
        if score >= 80:
            return 'A'
        elif score >= 60:
            return 'B'
        elif score >= 40:
            return 'C'
        else:
            return 'D'
```

---

### Definition of Ready (DoR)

- [x] Historia claramente escrita (quien, que, por que)
- [x] Criterios de aceptacion definidos
- [x] Story points estimados
- [x] Dependencias identificadas
- [x] Diseno/mockup disponible
- [x] API spec disponible

### Definition of Done (DoD)

- [ ] Codigo implementado segun criterios
- [ ] Tests unitarios escritos y pasando
- [ ] Tests de integracion pasando
- [ ] Code review aprobado
- [ ] Documentacion actualizada
- [ ] Inventarios actualizados
- [ ] Traza registrada
- [ ] QA aprobado
- [ ] Desplegado en ambiente de pruebas

---

### Historial de Cambios

| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2025-12-05 | Creacion | Requirements-Analyst |

---

### Notas de Implementacion

_Pendiente de desarrollo_

### Notas de QA

_Pendiente de pruebas_

---

**Creada por:** Requirements-Analyst
**Fecha:** 2025-12-05
**Ultima actualizacion:** 2025-12-05
