---
id: "ET-ML-008"
title: "Especificación Frontend del Módulo ML Signals"
type: "Technical Specification"
status: "Implementado"
priority: "Alta"
epic: "OQI-006"
project: "trading-platform"
version: "1.0.0"
created_date: "2025-12-15"
updated_date: "2026-01-25"
---

# ET-ML-008: Especificación Frontend del Módulo ML Signals

## Metadata

| Campo | Valor |
|-------|-------|
| **ID** | ET-ML-008 |
| **Épica** | OQI-006 - Señales ML |
| **Tipo** | Especificación Técnica |
| **Versión** | 1.0.0 |
| **Estado** | Implementado |
| **Última actualización** | 2026-01-25 |
| **Responsable** | Trading Platform Frontend Team |

---

## Propósito

Definir la arquitectura, componentes y servicios del frontend para el módulo de Señales ML (OQI-006). Este documento especifica la interfaz de usuario, estructura de componentes React, integración con el backend ML (puerto 3083) y los flujos de usuario para visualización y análisis de señales de trading.

---

## Visión General

### Objetivo Principal

Proporcionar una interfaz intuitiva y responsive que permita a los usuarios:
- Visualizar señales ML en tiempo real
- Analizar predicciones de rangos de precios
- Monitorear indicadores técnicos avanzados
- Ejecutar operaciones basadas en señales

### Arquitectura de Frontend

```
┌─────────────────────────────────────────────────────────────────┐
│                    ML DASHBOARD (REACT)                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │               MLDashboard Container                       │  │
│  │   - State Management (Zustand)                            │  │
│  │   - WebSocket Subscriptions (Real-time)                   │  │
│  │   - Query Management (TanStack Query)                     │  │
│  └──────────────────────────────────────────────────────────┘  │
│    │                    │                      │                │
│    ▼                    ▼                      ▼                │
│  ┌──────────┐  ┌──────────────┐  ┌──────────────────┐         │
│  │ Signals  │  │ ICT Analysis │  │ Ensemble Signals │         │
│  │   Tab    │  │     Tab      │  │      Tab         │         │
│  └──────────┘  └──────────────┘  └──────────────────┘         │
│                                                                  │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │              ML Service Integration                       │  │
│  │   - Base URL: http://localhost:3083                       │  │
│  │   - WebSocket: ws://localhost:3083/ws                     │  │
│  │   - Rate Limiting per User                                │  │
│  │   - Error Handling & Retry Logic                          │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
```

---

## Componentes Frontend

### 1. MLDashboard (Container Principal)

**Ruta:** `apps/frontend/src/pages/MLDashboard.tsx`

**Responsabilidades:**
- Gestionar estado global de señales ML
- Coordinar múltiples tabs (Signals, ICT Analysis, Ensemble)
- Manejar conexiones WebSocket
- Controlar ciclo de vida de datos

**Props:**
```typescript
interface MLDashboardProps {
  userId: string;
  selectedSymbol?: string;
  autoRefresh?: boolean;
}
```

**Estado Inicial:**
```typescript
interface MLDashboardState {
  activeTab: 'signals' | 'ict-analysis' | 'ensemble';
  selectedSymbol: string; // BTCUSDT, ETHUSDT, etc.
  timeframe: '1h' | '4h' | '1d';
  isConnected: boolean;
  signals: Signal[];
  predictions: Prediction[];
  indicators: Indicator[];
  lastUpdate: Date;
  loading: boolean;
  error?: string;
}
```

**Features:**
- Real-time WebSocket connection
- Automatic reconnection with exponential backoff
- TanStack Query for data caching
- Zustand for state management
- Error boundaries

---

### 2. AMDPhaseIndicator (Componente de Fase AMD)

**Ruta:** `apps/frontend/src/components/ml/AMDPhaseIndicator.tsx`

**Propósito:** Visualizar la fase actual AMD (Accumulation, Manipulation, Distribution)

**Props:**
```typescript
interface AMDPhaseIndicatorProps {
  phase: 'accumulation' | 'manipulation' | 'distribution' | 'unknown';
  confidence: number; // 0-100
  priceLevel: number;
  volume: number;
  duration: number; // minutos
  history?: PhaseTransition[];
}
```

**Estilos y Visualización:**
- **Accumulation:** Verde (#10b981)
- **Manipulation:** Amarillo (#f59e0b)
- **Distribution:** Rojo (#ef4444)
- **Unknown:** Gris (#6b7280)

**Elementos:**
```jsx
<div className="amd-phase-indicator">
  <PhaseCircle phase={phase} confidence={confidence} />
  <PhaseLabel phase={phase} duration={duration} />
  <ConfidenceBar confidence={confidence} />
  <VolumeProfile volume={volume} />
  <PhaseHistory history={history} />
</div>
```

---

### 3. PredictionCard (Tarjeta de Predicción)

**Ruta:** `apps/frontend/src/components/ml/PredictionCard.tsx`

**Propósito:** Mostrar predicciones de rangos de precios y objetivos

**Props:**
```typescript
interface PredictionCardProps {
  prediction: {
    symbol: string;
    timeframe: string;
    predictedLow: number;
    predictedHigh: number;
    currentPrice: number;
    confidence: number;
    targetPrice: number;
    stopLoss: number;
    takeProfit: number[];
    direction: 'BULLISH' | 'BEARISH' | 'NEUTRAL';
    timestamp: Date;
  };
  onTrade?: (action: TradeAction) => void;
}
```

**Componentes Internos:**
```
PredictionCard
├── Header (Symbol, Timeframe)
├── RangeDisplay (Low-High)
├── ConfidenceGauge
├── PriceLevels (SL, TP1, TP2, TP3)
├── DirectionBadge
└── ActionButtons (Buy/Sell/Close)
```

**Estilos:**
- Card con sombra y border-radius
- Gradientes según dirección (BULLISH: verde, BEARISH: rojo)
- Animaciones en cambios de precio
- Responsive: 1 col mobile, 2 cols tablet, 3 cols desktop

---

### 4. SignalsTimeline (Línea de Tiempo de Señales)

**Ruta:** `apps/frontend/src/components/ml/SignalsTimeline.tsx`

**Propósito:** Visualizar historial de señales en formato timeline

**Props:**
```typescript
interface SignalsTimelineProps {
  signals: Signal[];
  symbol: string;
  timeRange: {
    from: Date;
    to: Date;
  };
  onSignalClick?: (signal: Signal) => void;
}

interface Signal {
  id: string;
  timestamp: Date;
  type: 'BUY' | 'SELL' | 'CLOSE_LONG' | 'CLOSE_SHORT';
  price: number;
  strength: number; // 0-100
  reason: string;
  profitLoss?: number;
  status: 'PENDING' | 'EXECUTED' | 'CLOSED';
}
```

**Visualización:**
```
2026-01-25 14:30 ▼ BUY @ 45,230  |████████░░| 85% Strength
2026-01-25 13:15 ─ WAIT          |██░░░░░░░░| 25% Confidence
2026-01-25 12:00 ▲ SELL @ 45,100 |██████░░░░| 70% Strength
2026-01-25 10:45 ─ NEUTRAL       |████░░░░░░| 45% Confidence
```

**Filtros:**
- Por tipo de señal (BUY, SELL, CLOSE)
- Por rango temporal
- Por fuerza de señal (mínimo %)
- Por estado (PENDING, EXECUTED, CLOSED)

---

### 5. AccuracyMetrics (Métricas de Precisión)

**Ruta:** `apps/frontend/src/components/ml/AccuracyMetrics.tsx`

**Propósito:** Mostrar KPIs de desempeño del modelo ML

**Props:**
```typescript
interface AccuracyMetricsProps {
  metrics: {
    totalSignals: number;
    successfulTrades: number;
    failedTrades: number;
    winRate: number; // %
    profitFactor: number;
    sharpeRatio: number;
    maxDrawdown: number; // %
    totalProfit: number;
    periods: {
      period: 'TODAY' | 'WEEK' | 'MONTH' | '3M' | 'YTD' | 'ALL_TIME';
      value: number;
    }[];
  };
  period?: 'TODAY' | 'WEEK' | 'MONTH' | '3M' | 'YTD' | 'ALL_TIME';
}
```

**Layout de Métricas:**
```
┌────────────────────────────────────────────┐
│         ACCURACY METRICS (YTD)              │
├────────────────────────────────────────────┤
│  Win Rate: 68.5%  │  Profit Factor: 2.3   │
│  Total Trades: 47 │  Sharpe Ratio: 1.85   │
│  Success: 32/47   │  Max Drawdown: 12.3%  │
│  Total Profit: +8,450 USDT                 │
└────────────────────────────────────────────┘
```

**Gráficos:**
- Equity Curve (línea)
- Win/Loss distribution (pie)
- Drawdown (area)
- Monthly returns (bar)

---

### 6. ICTAnalysisCard (Tarjeta de Análisis ICT)

**Ruta:** `apps/frontend/src/components/ml/ICTAnalysisCard.tsx`

**Propósito:** Visualizar análisis de Institucionales Context Theory (ICT)

**Props:**
```typescript
interface ICTAnalysisCardProps {
  analysis: {
    symbol: string;
    timestamp: Date;
    orderBlock: OrderBlock;
    fairValueGap: FairValueGap[];
    liquidityLevels: LiquidityLevel[];
    swingStructure: SwingStructure;
    breaker: Breaker;
    disorderedMarket: boolean;
  };
}

interface OrderBlock {
  level: number;
  strength: 'weak' | 'moderate' | 'strong';
  timeframe: string;
  confirmed: boolean;
}

interface FairValueGap {
  high: number;
  low: number;
  timestamp: Date;
  mitigated: boolean;
}
```

**Secciones:**
1. **Order Blocks:** Mostrar niveles de orden bloqueados
2. **Fair Value Gaps:** Visualizar gaps de precio
3. **Liquidity Levels:** Mostrar zonas de liquidez
4. **Swing Structure:** Estructura de oscilaciones
5. **Market State:** Ordenado vs Desordenado

**Visualización:**
```
ORDER BLOCKS
├─ Level 45,200 [STRONG] ████████ Confirmed
├─ Level 44,950 [MODERATE] ████░░░░ Pending
└─ Level 44,700 [WEAK] ██░░░░░░ Watching

FAIR VALUE GAPS
├─ 45,100 - 45,200 [MITIGATED] ✓
└─ 44,900 - 45,000 [ACTIVE] ◆

LIQUIDITY LEVELS
├─ 45,500 [BUY] ▲ High
├─ 44,500 [SELL] ▼ High
└─ 43,000 [SUPPORT] ═══ Key Level
```

---

### 7. EnsembleSignalCard (Tarjeta de Señal de Ensemble)

**Ruta:** `apps/frontend/src/components/ml/EnsembleSignalCard.tsx`

**Propósito:** Mostrar consenso de múltiples modelos ML

**Props:**
```typescript
interface EnsembleSignalCardProps {
  symbol: string;
  models: ModelSignal[];
  ensemble: {
    direction: 'BULLISH' | 'BEARISH' | 'NEUTRAL';
    confidence: number; // 0-100
    agreementLevel: number; // % de modelos que concuerdan
    optimalEntry: number;
    optimalExit: number;
    riskRewardRatio: number;
  };
}

interface ModelSignal {
  name: string; // 'AMD Model', 'ICT Model', 'Neural Network', etc.
  direction: 'BULLISH' | 'BEARISH' | 'NEUTRAL';
  confidence: number;
  weight: number; // % en ensemble
  lastUpdate: Date;
}
```

**Visualización (Radar Chart):**
```
          BULLISH
           ╱╲
          ╱  ╲
    40°  ╱    ╲  40°
       ╱╱      ╲╲
      ╱ ┏━━━━┓ ╲
     ╱  ┃ MLP ┃  ╲
    ╱   ┗━━━━┛   ╲
   ╱    ┏━━━━┓    ╲
  ╱     ┃AMD ┃     ╲
 ╱      ┗━━━━┛      ╲
BEARISH     ICT     NEUTRAL
```

**Tabla de Modelos:**
| Modelo | Dirección | Confianza | Peso |
|--------|-----------|-----------|------|
| AMD Model | BULLISH | 85% | 30% |
| ICT Model | BULLISH | 78% | 30% |
| Neural Net | BEARISH | 45% | 20% |
| LSTM | BULLISH | 82% | 20% |
| **ENSEMBLE** | **BULLISH** | **81%** | **100%** |

---

### 8. TradeExecutionModal (Modal de Ejecución de Trades)

**Ruta:** `apps/frontend/src/components/ml/TradeExecutionModal.tsx`

**Propósito:** Interfaz para ejecutar trades basados en señales ML

**Props:**
```typescript
interface TradeExecutionModalProps {
  isOpen: boolean;
  signal: Signal;
  prediction: Prediction;
  onExecute: (trade: TradeOrder) => Promise<void>;
  onCancel: () => void;
}

interface TradeOrder {
  symbol: string;
  side: 'BUY' | 'SELL';
  quantity: number;
  entryPrice: number;
  stopLoss: number;
  takeProfit: number[];
  leverage?: number;
  orderType: 'MARKET' | 'LIMIT';
  timeInForce: 'GTC' | 'IOC' | 'FOK';
}
```

**Pasos del Formulario:**
1. **Confirmación de Señal:** Mostrar detalles de la señal
2. **Parámetros de Orden:** Cantidad, SL, TP
3. **Risk Management:** Cálculo de riesgo/recompensa
4. **Revisión:** Confirmar todos los parámetros
5. **Ejecución:** Enviar orden

**Validaciones:**
- Verificar saldo disponible
- Validar niveles SL/TP
- Confirmar riesgo máximo por operación
- Verificar límites de exposición

**Forma HTML:**
```jsx
<form className="trade-execution-form">
  <section className="signal-review">
    <SignalSummary signal={signal} />
  </section>

  <section className="order-parameters">
    <QuantityInput value={quantity} onChange={setQuantity} />
    <PriceInputs entry={entry} sl={stopLoss} tp={takeProfit} />
    <LeverageSlider value={leverage} max={20} />
  </section>

  <section className="risk-analysis">
    <RiskDisplay riskReward={riskReward} />
    <LimitValidator order={order} />
  </section>

  <footer className="actions">
    <button onClick={onCancel}>Cancel</button>
    <button onClick={onExecute} disabled={!isValid}>Execute Trade</button>
  </footer>
</form>
```

---

## ML Service Integration

### Arquitectura del Servicio

**Ruta:** `apps/frontend/src/services/ml/mlService.ts`

**Configuración Base:**
```typescript
const ML_SERVICE_CONFIG = {
  baseURL: 'http://localhost:3083',
  wsURL: 'ws://localhost:3083/ws',
  timeout: 10000,
  retryAttempts: 3,
  retryDelay: 1000,
  rateLimitPerUser: {
    requestsPerMinute: 60,
    concurrent: 5
  }
};
```

### Endpoints Principales

#### 1. Obtener Señales

**GET** `/api/signals`

```typescript
interface SignalsRequest {
  symbol: string;
  timeframe?: '1h' | '4h' | '1d';
  limit?: number;
  offset?: number;
}

interface SignalsResponse {
  data: Signal[];
  total: number;
  timestamp: Date;
}

// Uso
const signals = await mlService.getSignals({
  symbol: 'BTCUSDT',
  timeframe: '1h',
  limit: 50
});
```

---

#### 2. Obtener Predicciones

**GET** `/api/predictions`

```typescript
interface PredictionsRequest {
  symbol: string;
  timeframe?: '1h' | '4h' | '1d';
}

interface PredictionsResponse {
  data: Prediction[];
  confidence: number;
  timestamp: Date;
}

// Uso
const predictions = await mlService.getPredictions({
  symbol: 'ETHUSDT',
  timeframe: '4h'
});
```

---

#### 3. Análisis ICT

**GET** `/api/ict-analysis`

```typescript
interface ICTAnalysisRequest {
  symbol: string;
  timeframe: string;
}

interface ICTAnalysisResponse {
  orderBlocks: OrderBlock[];
  fairValueGaps: FairValueGap[];
  liquidityLevels: LiquidityLevel[];
  swingStructure: SwingStructure;
  timestamp: Date;
}

// Uso
const ictAnalysis = await mlService.getICTAnalysis({
  symbol: 'BTCUSDT',
  timeframe: '1h'
});
```

---

#### 4. Señal de Ensemble

**GET** `/api/ensemble-signal`

```typescript
interface EnsembleRequest {
  symbol: string;
  models?: string[];
}

interface EnsembleResponse {
  direction: 'BULLISH' | 'BEARISH' | 'NEUTRAL';
  confidence: number;
  modelSignals: ModelSignal[];
  agreementLevel: number;
  timestamp: Date;
}

// Uso
const ensemble = await mlService.getEnsembleSignal({
  symbol: 'BTCUSDT'
});
```

---

#### 5. Métricas de Precisión

**GET** `/api/accuracy-metrics`

```typescript
interface MetricsRequest {
  period?: 'TODAY' | 'WEEK' | 'MONTH' | '3M' | 'YTD' | 'ALL_TIME';
}

interface MetricsResponse {
  winRate: number;
  profitFactor: number;
  sharpeRatio: number;
  totalSignals: number;
  successfulTrades: number;
  timestamp: Date;
}

// Uso
const metrics = await mlService.getMetrics({
  period: 'MONTH'
});
```

---

### WebSocket Real-time

**Conexión:**
```typescript
mlService.connectWebSocket({
  symbols: ['BTCUSDT', 'ETHUSDT'],
  channels: ['signals', 'predictions', 'indicators'],
  onMessage: handleMessage,
  onError: handleError,
  onClose: handleClose
});
```

**Eventos:**
```typescript
// Signal Update
{
  type: 'signal',
  symbol: 'BTCUSDT',
  data: { ... }
}

// Prediction Update
{
  type: 'prediction',
  symbol: 'ETHUSDT',
  data: { ... }
}

// Indicator Update
{
  type: 'indicator',
  symbol: 'BTCUSDT',
  indicator: 'rsi',
  value: 65.5
}
```

---

## Estado Global (Zustand)

### Store Principal

**Ruta:** `apps/frontend/src/stores/mlSignalsStore.ts`

```typescript
interface MLSignalsStore {
  // Estado
  activeTab: 'signals' | 'ict-analysis' | 'ensemble';
  selectedSymbol: string;
  signals: Signal[];
  predictions: Prediction[];
  indicators: Indicator[];
  metrics: Metrics;
  isConnected: boolean;
  loading: boolean;
  error?: string;

  // Acciones
  setActiveTab: (tab: string) => void;
  setSymbol: (symbol: string) => void;
  updateSignals: (signals: Signal[]) => void;
  updatePredictions: (predictions: Prediction[]) => void;
  setConnected: (connected: boolean) => void;
  setError: (error: string | undefined) => void;
  reset: () => void;
}

export const useMlSignalsStore = create<MLSignalsStore>((set) => ({
  // Implementación
}));
```

---

## Queries de TanStack Query

### Query Configuration

```typescript
// Queries
export const mlQueries = {
  all: () => ['ml'],
  signals: (symbol: string) => [...mlQueries.all(), 'signals', symbol],
  predictions: (symbol: string) => [...mlQueries.all(), 'predictions', symbol],
  metrics: (period?: string) => [...mlQueries.all(), 'metrics', period],
  ictAnalysis: (symbol: string) => [...mlQueries.all(), 'ict', symbol],
  ensemble: (symbol: string) => [...mlQueries.all(), 'ensemble', symbol],
};

// Hook para obtener señales
export const useSignals = (symbol: string, options?: UseQueryOptions) => {
  return useQuery({
    queryKey: mlQueries.signals(symbol),
    queryFn: () => mlService.getSignals({ symbol }),
    staleTime: 30000, // 30s
    refetchInterval: 60000, // 60s
    ...options
  });
};
```

---

## Gestión de Errores y Estado

### Error Boundary

```typescript
interface MLErrorBoundaryProps {
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

export const MLErrorBoundary: React.FC<MLErrorBoundaryProps> = ({
  children,
  fallback
}) => {
  // Implementación
  return <ErrorFallback error={error} reset={reset} />;
};
```

### Error Handling

```typescript
// Tipos de errores
type MLError =
  | ConnectionError
  | DataValidationError
  | RateLimitError
  | InvalidSignalError
  | ExecutionError;

// Handler global
const handleMLError = (error: MLError) => {
  switch (error.type) {
    case 'ConnectionError':
      // Reintentar conexión con backoff exponencial
      break;
    case 'RateLimitError':
      // Mostrar advertencia, esperar cooldown
      break;
    case 'ExecutionError':
      // Mostrar error al usuario, registrar
      break;
  }
};
```

---

## Validaciones de Datos

### Schemas Zod

```typescript
import { z } from 'zod';

const SignalSchema = z.object({
  id: z.string().uuid(),
  timestamp: z.date(),
  type: z.enum(['BUY', 'SELL', 'CLOSE_LONG', 'CLOSE_SHORT']),
  price: z.number().positive(),
  strength: z.number().min(0).max(100),
  status: z.enum(['PENDING', 'EXECUTED', 'CLOSED'])
});

const PredictionSchema = z.object({
  symbol: z.string().regex(/^[A-Z]{1,10}USDT$/),
  predictedLow: z.number().positive(),
  predictedHigh: z.number().positive(),
  confidence: z.number().min(0).max(100),
  direction: z.enum(['BULLISH', 'BEARISH', 'NEUTRAL'])
});
```

---

## Responsive Design

### Breakpoints

```typescript
const breakpoints = {
  mobile: '320px',
  tablet: '768px',
  desktop: '1024px',
  wide: '1440px'
};
```

### Layout Mobile

- **Dashboard:** Stack vertical de tabs
- **Signals:** Cards en single column
- **Charts:** Fullscreen optimizado
- **Modals:** Fullscreen en mobile, centered en desktop

---

## Performance Optimization

### Code Splitting

```typescript
// Lazy load ML components
const MLDashboard = lazy(() => import('./pages/MLDashboard'));
const TradeExecutionModal = lazy(() =>
  import('./components/ml/TradeExecutionModal')
);
```

### Memoization

```typescript
// Memoizar componentes costosos
export const AMDPhaseIndicator = React.memo(
  AMDPhaseIndicatorComponent,
  (prevProps, nextProps) => {
    return prevProps.phase === nextProps.phase &&
           prevProps.confidence === nextProps.confidence;
  }
);
```

### Virtual Scrolling

```typescript
// Para listas grandes de señales
<VirtualList
  data={signals}
  height={600}
  itemHeight={100}
  renderItem={(signal) => <SignalRow signal={signal} />}
/>
```

---

## Testing Strategy

### Unit Tests

```typescript
// tests/components/ml/AMDPhaseIndicator.test.tsx
describe('AMDPhaseIndicator', () => {
  it('should render accumulation phase', () => {
    const { getByText } = render(
      <AMDPhaseIndicator phase="accumulation" confidence={85} />
    );
    expect(getByText(/Accumulation/i)).toBeInTheDocument();
  });
});
```

### Integration Tests

```typescript
// tests/integration/mlDashboard.test.tsx
describe('ML Dashboard Integration', () => {
  it('should load signals and display them', async () => {
    const { getByText } = render(<MLDashboard />);
    await waitFor(() => {
      expect(getByText(/BUY Signal/)).toBeInTheDocument();
    });
  });
});
```

### E2E Tests

```typescript
// tests/e2e/ml-signals.spec.ts
describe('ML Signals E2E', () => {
  it('should execute trade from signal', () => {
    cy.visit('/dashboard/ml');
    cy.contains('BUY Signal').click();
    cy.get('[data-testid="execute-btn"]').click();
    cy.contains('Trade Executed').should('be.visible');
  });
});
```

---

## Accesibilidad (WCAG 2.1)

### Requirements

- ARIA labels en todos los componentes interactivos
- Contraste mínimo 4.5:1 en textos
- Navegación por teclado completa
- Descripciones de imágenes y gráficos
- Announces de cambios dinámicos con aria-live

### Ejemplo

```jsx
<div role="region" aria-live="polite" aria-label="ML Signals">
  <button
    aria-label="Execute BUY signal at 45,230 USDT"
    onClick={handleExecute}
  >
    Execute
  </button>
</div>
```

---

## Seguridad

### OWASP Top 10

1. **Injection:** Validación de todas las entradas con Zod
2. **Authentication:** JWT tokens en headers
3. **XSS:** Sanitización de datos dinámicos con DOMPurify
4. **CSRF:** Tokens CSRF en forms
5. **Rate Limiting:** Cliente + Servidor

### Ejemplo

```typescript
import DOMPurify from 'dompurify';

const sanitizedContent = DOMPurify.sanitize(userContent);
```

---

## Deployment

### Build Process

```bash
# Frontend build
cd apps/frontend
npm run build  # Vite production build
npm run lint   # ESLint checks
npm run typecheck  # TypeScript validation

# Output
dist/
├── index.html
├── assets/
│   ├── js/
│   ├── css/
│   └── images/
```

### Environment Variables

```
VITE_API_BASE_URL=http://localhost:3080
VITE_ML_ENGINE_URL=http://localhost:3083
VITE_WS_URL=ws://localhost:3083/ws
VITE_APP_ENV=development
```

---

## Roadmap Futuro

1. **Dark Mode:** Tema oscuro completo
2. **Custom Indicators:** Permitir usuarios agregar indicadores personalizados
3. **Backtesting UI:** Interfaz para backtesting de estrategias
4. **Mobile App:** React Native para iOS/Android
5. **Voice Commands:** Ejecución de trades por voz
6. **ML Model Marketplace:** Mercado de modelos ML

---

## Referencias

- [React Documentation](https://react.dev)
- [Zustand Store](https://github.com/pmndrs/zustand)
- [TanStack Query](https://tanstack.com/query)
- [Vite Guide](https://vitejs.dev)
- [TypeScript Handbook](https://www.typescriptlang.org/docs)

---

## Changelog

| Versión | Fecha | Cambios |
|---------|-------|---------|
| 1.0.0 | 2026-01-25 | Especificación inicial completa |
| 0.9.0 | 2025-12-15 | Borrador de componentes |

---

*ET-ML-008 | ML Signals Frontend Specification v1.0.0 | Trading Platform*

