- 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>
25 KiB
| id | title | type | status | priority | epic | project | version | created_date | updated_date |
|---|---|---|---|---|---|---|---|---|---|
| ET-ML-008 | Especificación Frontend del Módulo ML Signals | Technical Specification | Implementado | Alta | OQI-006 | trading-platform | 1.0.0 | 2025-12-15 | 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:
interface MLDashboardProps {
userId: string;
selectedSymbol?: string;
autoRefresh?: boolean;
}
Estado Inicial:
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:
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:
<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:
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:
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:
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:
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:
- Order Blocks: Mostrar niveles de orden bloqueados
- Fair Value Gaps: Visualizar gaps de precio
- Liquidity Levels: Mostrar zonas de liquidez
- Swing Structure: Estructura de oscilaciones
- 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:
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:
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:
- Confirmación de Señal: Mostrar detalles de la señal
- Parámetros de Orden: Cantidad, SL, TP
- Risk Management: Cálculo de riesgo/recompensa
- Revisión: Confirmar todos los parámetros
- 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:
<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:
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
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
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
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
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
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:
mlService.connectWebSocket({
symbols: ['BTCUSDT', 'ETHUSDT'],
channels: ['signals', 'predictions', 'indicators'],
onMessage: handleMessage,
onError: handleError,
onClose: handleClose
});
Eventos:
// 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
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
// 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
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
// 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
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
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
// Lazy load ML components
const MLDashboard = lazy(() => import('./pages/MLDashboard'));
const TradeExecutionModal = lazy(() =>
import('./components/ml/TradeExecutionModal')
);
Memoization
// Memoizar componentes costosos
export const AMDPhaseIndicator = React.memo(
AMDPhaseIndicatorComponent,
(prevProps, nextProps) => {
return prevProps.phase === nextProps.phase &&
prevProps.confidence === nextProps.confidence;
}
);
Virtual Scrolling
// Para listas grandes de señales
<VirtualList
data={signals}
height={600}
itemHeight={100}
renderItem={(signal) => <SignalRow signal={signal} />}
/>
Testing Strategy
Unit Tests
// 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
// 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
// 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
<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
- Injection: Validación de todas las entradas con Zod
- Authentication: JWT tokens en headers
- XSS: Sanitización de datos dinámicos con DOMPurify
- CSRF: Tokens CSRF en forms
- Rate Limiting: Cliente + Servidor
Ejemplo
import DOMPurify from 'dompurify';
const sanitizedContent = DOMPurify.sanitize(userContent);
Deployment
Build Process
# 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
- Dark Mode: Tema oscuro completo
- Custom Indicators: Permitir usuarios agregar indicadores personalizados
- Backtesting UI: Interfaz para backtesting de estrategias
- Mobile App: React Native para iOS/Android
- Voice Commands: Ejecución de trades por voz
- ML Model Marketplace: Mercado de modelos ML
Referencias
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