6.1 KiB
6.1 KiB
RF-TRD-004: Paper Trading
Versión: 1.0.0 Fecha: 2025-12-05 Épica: OQI-003 - Trading y Charts Prioridad: P0 Story Points: 13
Descripción
El sistema debe proporcionar un entorno de paper trading (simulación) que permita a los usuarios practicar estrategias de trading sin arriesgar dinero real, utilizando un balance virtual.
Requisitos Funcionales
RF-TRD-004.1: Balance Virtual
El sistema debe:
- Asignar $10,000 USD virtuales a cada usuario nuevo
- Mostrar balance disponible en tiempo real
- Mostrar equity (balance + PnL no realizado)
- Calcular margen usado por posiciones abiertas
- Permitir reset del balance a $10,000 (máximo 1 vez por semana)
RF-TRD-004.2: Tipos de Órdenes
El sistema debe soportar:
| Tipo | Descripción | Ejecución |
|---|---|---|
| Market | Al precio actual | Inmediata |
| Limit | A precio específico | Cuando se alcanza |
| Stop-Limit | Stop + limit price | Cuando stop se activa |
RF-TRD-004.3: Ejecución de Órdenes
El sistema debe:
- Ejecutar órdenes market inmediatamente al precio actual
- Monitorear órdenes limit y ejecutar cuando precio alcanza
- Validar balance suficiente antes de crear orden
- Aplicar slippage simulado (0.1% para market orders)
- No cobrar comisiones (simplificación MVP)
RF-TRD-004.4: Gestión de Posiciones
El sistema debe:
- Permitir una posición por símbolo (long o short)
- Calcular PnL no realizado en tiempo real
- Permitir cerrar posición parcial o total
- Soportar Take Profit automático
- Soportar Stop Loss automático
RF-TRD-004.5: Liquidación
El sistema debe:
- Liquidar posición si pérdida > 80% del margen
- Notificar al usuario antes de liquidación
- Registrar liquidación en historial
Datos de Entrada
Crear Orden
interface CreateOrderDto {
symbol: string; // BTCUSDT
side: 'buy' | 'sell';
type: 'market' | 'limit' | 'stop_limit';
quantity: number; // Cantidad del activo
price?: number; // Solo para limit
stopPrice?: number; // Solo para stop_limit
takeProfit?: number; // Opcional
stopLoss?: number; // Opcional
}
Datos de Salida
Orden Ejecutada
interface Order {
id: string;
userId: string;
symbol: string;
side: 'buy' | 'sell';
type: 'market' | 'limit' | 'stop_limit';
status: 'pending' | 'filled' | 'cancelled' | 'rejected';
quantity: number;
price: number | null;
filledQuantity: number;
filledPrice: number | null;
takeProfit: number | null;
stopLoss: number | null;
createdAt: string;
filledAt: string | null;
}
Posición
interface Position {
id: string;
symbol: string;
side: 'long' | 'short';
quantity: number;
entryPrice: number;
currentPrice: number;
unrealizedPnl: number;
unrealizedPnlPercent: number;
takeProfit: number | null;
stopLoss: number | null;
openedAt: string;
}
Balance
interface PaperBalance {
balance: number; // Disponible
equity: number; // Balance + unrealized PnL
marginUsed: number; // En posiciones
marginAvailable: number; // Para nuevas posiciones
unrealizedPnl: number; // Total de posiciones
}
Reglas de Negocio
- Balance inicial: $10,000 USD para todos los usuarios
- Posiciones: Máximo 1 posición por símbolo
- Tamaño mínimo: $10 USD equivalente
- Tamaño máximo: 100% del balance disponible
- Apalancamiento: 1x (sin apalancamiento en MVP)
- Slippage: 0.1% en órdenes market
- Reset: Máximo 1 vez cada 7 días
Criterios de Aceptación
Escenario: Usuario crea orden market de compra
DADO que el usuario tiene balance de $10,000
Y el precio de BTCUSDT es $50,000
CUANDO crea una orden market BUY de 0.1 BTC
ENTONCES la orden se ejecuta inmediatamente
Y se crea una posición long de 0.1 BTC
Y el balance se reduce en ~$5,005 (precio + slippage)
Escenario: Usuario cierra posición con ganancia
DADO que el usuario tiene posición long BTCUSDT
Y el entry price fue $50,000
Y el precio actual es $52,000
CUANDO cierra la posición
ENTONCES el PnL realizado es +$200 (4%)
Y el balance aumenta correspondientemente
Y se registra el trade en historial
Escenario: Stop Loss se activa
DADO que el usuario tiene posición long BTCUSDT
Y el entry price fue $50,000
Y el Stop Loss está en $48,000
CUANDO el precio baja a $48,000
ENTONCES la posición se cierra automáticamente
Y se registra pérdida de ~$200 (4%)
Escenario: Usuario intenta orden sin balance
DADO que el usuario tiene balance de $100
CUANDO intenta crear orden de $1,000
ENTONCES la orden es rechazada
Y se muestra mensaje "Balance insuficiente"
Estados de Orden
┌─────────────┐
│ PENDING │
└──────┬──────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ FILLED │ │CANCELLED│ │REJECTED │
└─────────┘ └─────────┘ └─────────┘
Dependencias
- RF-TRD-001: Charts (precio actual)
- WebSocket para monitoreo de precios
- Cron job para verificar órdenes limit
Notas Técnicas
- Ejecutar verificación de órdenes limit cada 1 segundo
- Usar transacciones para operaciones de balance
- Implementar locks para evitar race conditions
- Guardar snapshots de precio para auditoría
Métricas a Trackear
- Órdenes creadas por día
- Win rate por usuario
- Volumen total operado
- Tiempo promedio de posición