trading-platform/docs/02-definicion-modulos/OQI-003-trading-charts/historias-usuario/US-TRD-018-comparar-simbolos.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
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>
2026-01-07 05:33:35 -06:00

16 KiB

id title type status priority epic story_points created_date updated_date
US-TRD-018 Comparar Multiples Simbolos en el Chart User Story Done Media OQI-003 5 2025-12-05 2026-01-04

US-TRD-018: Comparar Múltiples Símbolos en el Chart

Metadata

Campo Valor
ID US-TRD-018
Épica OQI-003 - Trading y Charts
Módulo trading
Prioridad P2
Story Points 5
Sprint Sprint 7
Estado Pendiente
Asignado a Por asignar

Historia de Usuario

Como trader avanzado, quiero comparar múltiples símbolos en el mismo chart, para analizar correlaciones, divergencias y movimientos relativos entre diferentes activos.

Descripción Detallada

El usuario debe poder superponer múltiples símbolos en el mismo chart para comparación visual. Los precios se normalizan a un índice base (100) para permitir comparación de activos con diferentes escalas de precio. Cada símbolo tiene un color distintivo y se puede mostrar/ocultar individualmente.

Mockups/Wireframes

┌─────────────────────────────────────────────────────────────────┐
│  COMPARE MODE                                         [Exit]    │
├─────────────────────────────────────────────────────────────────┤
│  [+ Add Symbol to Compare]                                      │
│                                                                  │
│  Active Comparisons:                                            │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │ ● BTCUSDT   $97,234.50  +2.34%  [────] [x]             │  │
│  │ ● ETHUSDT   $3,845.20   -0.45%  [────] [x]             │  │
│  │ ● SOLUSDT   $142.73     +1.56%  [────] [x]             │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
│  View Mode: [Normalized ▼]                                      │
│  Options: Normalized (Index), Absolute Price, % Change          │
│                                                                  │
│  Base Date: [2025-12-01] (Index = 100 at this date)            │
│                                                                  │
├─────────────────────────────────────────────────────────────────┤
│  NORMALIZED VIEW (Index Base = 100)                            │
│                                                                  │
│  120 ┤                                    ──── BTC (Blue)       │
│  115 ┤                           ────────                       │
│  110 ┤                  ────────                                │
│  105 ┤         ════════                    ════ ETH (Orange)    │
│  100 ┤────────                                                  │
│   95 ┤    ····························     ···· SOL (Green)     │
│   90 ┤                                                          │
│                                                                  │
│  Legend:                                                        │
│  ──── BTCUSDT (+15.2% from base)                               │
│  ════ ETHUSDT (+8.7% from base)                                │
│  ···· SOLUSDT (-3.4% from base)                                │
│                                                                  │
│  Correlation Matrix:                                            │
│  ┌─────────────────────────────────────┐                       │
│  │        BTC    ETH    SOL            │                       │
│  │ BTC    1.00   0.87   0.65           │                       │
│  │ ETH    0.87   1.00   0.72           │                       │
│  │ SOL    0.65   0.72   1.00           │                       │
│  └─────────────────────────────────────┘                       │
└─────────────────────────────────────────────────────────────────┘

ABSOLUTE PRICE VIEW:
┌─────────────────────────────────────────┐
│  Dual Y-Axis Mode                       │
├─────────────────────────────────────────┤
│  $100K ┤                    ──── BTC    │
│  $95K  ┤            ────────            │
│  $90K  ┤  ──────────                    │
│        │                                 │
│  $4K   ┤            ════════ ETH         │
│  $3.8K ┤  ════════                       │
│  $3.6K ┤                                 │
│        │                                 │
│  $150  ┤  ····························  │
│  $140  ┤            ····· SOL            │
│  $130  ┤  ·····                          │
└─────────────────────────────────────────┘

Criterios de Aceptación

Escenario 1: Activar modo comparación

DADO que el usuario está viendo chart de BTCUSDT
CUANDO hace click en botón "Compare"
ENTONCES el chart entra en modo comparación
Y BTCUSDT se convierte en el símbolo base
Y se muestra botón "+ Add Symbol to Compare"
Y se muestra la lista de símbolos activos

Escenario 2: Agregar símbolo a comparación

DADO que el usuario está en modo comparación con BTCUSDT
CUANDO hace click en "+ Add Symbol to Compare"
Y busca "ETH"
Y selecciona "ETHUSDT"
ENTONCES ETHUSDT se agrega al chart
Y se muestra con línea de color diferente (naranja)
Y aparece en la lista de símbolos activos
Y ambos símbolos están visibles simultáneamente

Escenario 3: Ver modo normalizado (índice base 100)

DADO que hay 3 símbolos en comparación
Y el modo es "Normalized"
Y la fecha base es 2025-12-01
ENTONCES todos los símbolos comienzan en índice 100 en la fecha base
Y los valores subsecuentes muestran cambio relativo al base
Ejemplo:
  - BTC: $90K → $100K = Índice 100111.1 (+11.1%)
  - ETH: $3.6K → $3.9K = Índice 100108.3 (+8.3%)
Y se pueden comparar visualmente los rendimientos

Escenario 4: Ver modo precio absoluto

DADO que el usuario selecciona "Absolute Price"
ENTONCES cada símbolo muestra su precio real
Y se usan ejes Y múltiples (uno por símbolo)
Y los ejes Y están a la derecha con colores matching
Y el chart permite ver movimientos absolutos

Escenario 5: Ver modo % de cambio

DADO que el usuario selecciona "% Change"
Y la fecha base es 2025-12-01
ENTONCES todos los símbolos muestran % de cambio desde el base
Y el eje Y muestra -10%, 0%, +10%, +20%, etc.
Y las líneas cruzan en 0% en la fecha base

Escenario 6: Ocultar/mostrar símbolo

DADO que hay 3 símbolos en comparación
CUANDO el usuario hace click en el color de ETHUSDT
ENTONCES la línea de ETHUSDT se oculta
Y sigue en la lista pero con opacidad reducida
Y puede volver a hacer click para mostrarla

Escenario 7: Eliminar símbolo de comparación

DADO que SOLUSDT está en comparación
CUANDO el usuario hace click en [x] junto a SOLUSDT
ENTONCES SOLUSDT se elimina del chart
Y desaparece de la lista
Y su línea desaparece del gráfico

Escenario 8: Ver matriz de correlación

DADO que hay múltiples símbolos en comparación
CUANDO se calcula la correlación
ENTONCES se muestra matriz con coeficientes de correlación
Y valores van de -1.0 (correlación negativa) a +1.0 (positiva)
Y diagonal siempre es 1.00 (símbolo consigo mismo)
Ejemplo: BTC vs ETH = 0.87 (alta correlación positiva)

Escenario 9: Cambiar fecha base

DADO que el usuario está en modo normalizado
CUANDO cambia la fecha base a 2025-11-15
ENTONCES todos los índices se recalculan
Y el índice 100 ahora está en 2025-11-15
Y los cambios relativos se ajustan

Escenario 10: Límite de símbolos

DADO que el usuario tiene 5 símbolos en comparación (límite)
CUANDO intenta agregar un sexto
ENTONCES se muestra mensaje "Maximum 5 symbols for comparison"
Y debe eliminar uno para agregar otro

Criterios Adicionales

  • Colores distintivos automáticos para cada símbolo
  • Tooltip sincronizado mostrando todos los valores
  • Exportar comparación como imagen
  • Guardar configuración de comparación
  • Templates de comparación (ej: "Major Crypto", "DeFi Tokens")

Tareas Técnicas

Database:

  • DB-TRD-026: Crear tabla trading.comparison_presets
    • Campos: id, user_id, name, symbols, view_mode, base_date

Backend:

  • BE-TRD-096: Crear endpoint GET /trading/candles/multi
  • BE-TRD-097: Implementar normalización de precios
  • BE-TRD-098: Implementar cálculo de correlación
  • BE-TRD-099: Optimizar queries para múltiples símbolos
  • BE-TRD-100: Crear endpoint para guardar comparación

Frontend:

  • FE-TRD-102: Crear componente CompareMode.tsx
  • FE-TRD-103: Crear componente SymbolSelector.tsx
  • FE-TRD-104: Crear componente SymbolsList.tsx
  • FE-TRD-105: Crear componente CorrelationMatrix.tsx
  • FE-TRD-106: Implementar normalización en frontend
  • FE-TRD-107: Implementar múltiples series en Lightweight Charts
  • FE-TRD-108: Implementar tooltip sincronizado
  • FE-TRD-109: Implementar hook useCompare

Tests:

  • TEST-TRD-049: Test unitario normalización
  • TEST-TRD-050: Test unitario correlación
  • TEST-TRD-051: Test integración múltiples símbolos
  • TEST-TRD-052: Test E2E modo comparación completo

Dependencias

Depende de:

  • US-TRD-001: Ver chart - Estado: Pendiente

Bloquea:

  • Ninguna

Notas Técnicas

Endpoints involucrados:

Método Endpoint Descripción
GET /trading/candles/multi Obtener velas de múltiples símbolos
POST /trading/compare/correlation Calcular correlación
POST /trading/compare/presets Guardar preset de comparación

Componentes UI:

  • CompareMode: Modo de comparación principal
  • SymbolSelector: Selector de símbolos
  • SymbolsList: Lista de símbolos activos
  • CorrelationMatrix: Matriz de correlaciones
  • ViewModeSelector: Selector de modo de vista

Query Parameters (Multi Candles):

{
  symbols: ["BTCUSDT", "ETHUSDT", "SOLUSDT"],
  interval: "1h",
  from: "2025-11-01",
  to: "2025-12-05"
}

Response (Multi Candles):

{
  data: {
    "BTCUSDT": [
      { time: 1699027200, open: 90000, high: 91000, low: 89500, close: 90500, volume: 1234 },
      // ... más velas
    ],
    "ETHUSDT": [
      { time: 1699027200, open: 3600, high: 3650, low: 3580, close: 3620, volume: 5678 },
      // ... más velas
    ],
    "SOLUSDT": [
      { time: 1699027200, open: 140, high: 145, low: 138, close: 142, volume: 9012 },
      // ... más velas
    ]
  }
}

Normalization Logic:

function normalizeToIndex(candles: Candle[], baseDate: Date) {
  const baseCandle = candles.find(c => c.time === baseDate.getTime() / 1000);
  if (!baseCandle) return candles;

  const basePrice = baseCandle.close;

  return candles.map(candle => ({
    ...candle,
    indexValue: (candle.close / basePrice) * 100,
    percentChange: ((candle.close - basePrice) / basePrice) * 100
  }));
}

Correlation Calculation:

function calculateCorrelation(series1: number[], series2: number[]): number {
  const n = Math.min(series1.length, series2.length);

  // Calculate means
  const mean1 = series1.reduce((a, b) => a + b, 0) / n;
  const mean2 = series2.reduce((a, b) => a + b, 0) / n;

  // Calculate correlation coefficient
  let numerator = 0;
  let sum1Sq = 0;
  let sum2Sq = 0;

  for (let i = 0; i < n; i++) {
    const diff1 = series1[i] - mean1;
    const diff2 = series2[i] - mean2;

    numerator += diff1 * diff2;
    sum1Sq += diff1 * diff1;
    sum2Sq += diff2 * diff2;
  }

  const denominator = Math.sqrt(sum1Sq * sum2Sq);

  return denominator === 0 ? 0 : numerator / denominator;
}

function calculateCorrelationMatrix(symbols: string[], data: CandleData) {
  const matrix: { [key: string]: { [key: string]: number } } = {};

  symbols.forEach(symbol1 => {
    matrix[symbol1] = {};
    symbols.forEach(symbol2 => {
      if (symbol1 === symbol2) {
        matrix[symbol1][symbol2] = 1.0;
      } else {
        const series1 = data[symbol1].map(c => c.close);
        const series2 = data[symbol2].map(c => c.close);
        matrix[symbol1][symbol2] = calculateCorrelation(series1, series2);
      }
    });
  });

  return matrix;
}

Chart Implementation (Lightweight Charts):

// Add multiple series
const colors = ['#2962FF', '#FF6D00', '#26A69A', '#9C27B0', '#F44336'];

symbols.forEach((symbol, index) => {
  const series = chart.addLineSeries({
    color: colors[index],
    lineWidth: 2,
    title: symbol,
    priceScaleId: viewMode === 'absolute' ? `scale-${index}` : 'right',
  });

  const normalizedData = normalizeToIndex(data[symbol], baseDate);
  series.setData(normalizedData.map(candle => ({
    time: candle.time,
    value: viewMode === 'normalized' ? candle.indexValue : candle.close
  })));

  symbolSeries[symbol] = series;
});

// Configure price scales for absolute mode
if (viewMode === 'absolute') {
  symbols.forEach((symbol, index) => {
    chart.priceScale(`scale-${index}`).applyOptions({
      scaleMargins: {
        top: 0.1 + (index * 0.3),
        bottom: 0.7 - (index * 0.3),
      },
      borderColor: colors[index],
    });
  });
}

Synchronized Crosshair:

function setupSyncedCrosshair(chart, symbols, data) {
  chart.subscribeCrosshairMove((param) => {
    if (!param.time) {
      tooltip.style.display = 'none';
      return;
    }

    const tooltipContent = symbols.map(symbol => {
      const price = param.seriesPrices.get(symbolSeries[symbol]);
      return `${symbol}: ${price?.toFixed(2) || 'N/A'}`;
    }).join('\n');

    tooltip.textContent = tooltipContent;
    tooltip.style.display = 'block';
  });
}

Color Palette:

const SYMBOL_COLORS = [
  '#2962FF', // Blue
  '#FF6D00', // Orange
  '#26A69A', // Teal
  '#9C27B0', // Purple
  '#F44336'  // Red
];

Definition of Ready (DoR)

  • Historia claramente escrita
  • Criterios de aceptación definidos
  • Story points estimados
  • Dependencias identificadas
  • Sin bloqueadores
  • Diseño/mockup disponible
  • API spec disponible

Definition of Done (DoD)

  • Código implementado según criterios
  • Tests unitarios escritos y pasando
  • Tests de integración pasando
  • Code review aprobado
  • Documentación actualizada
  • QA aprobado
  • Desplegado en ambiente de pruebas

Historial de Cambios

Fecha Cambio Autor
2025-12-05 Creación Requirements-Analyst

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