- Add 5 frontend specification documents (ET-*-frontend.md): - ET-AUTH-006: Authentication module frontend spec - ET-ML-008: ML Signals module frontend spec - ET-LLM-007: LLM Agent module frontend spec - ET-PFM-008: Portfolio Manager frontend spec (design) - ET-MKT-003: Marketplace frontend spec (design) - Add 8 new user stories: - US-AUTH-013: Global logout - US-AUTH-014: Device management - US-ML-008: Ensemble signal view - US-ML-009: ICT analysis view - US-ML-010: Multi-symbol scan - US-LLM-011: Execute trade from chat - US-PFM-013: Rebalance alerts - US-PFM-014: PDF report generation - Update task index with completed analysis Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1038 lines
25 KiB
Markdown
1038 lines
25 KiB
Markdown
---
|
||
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*
|
||
|