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>
14 KiB
| id | title | type | status | priority | module | epic | version | created_date | updated_date |
|---|---|---|---|---|---|---|---|---|---|
| RF-TRD-006 | Gestion de Posiciones | Requirement | Done | Alta | trading | OQI-003 | 1.0 | 2025-12-05 | 2026-01-04 |
RF-TRD-006: Gestión de Posiciones
Versión: 1.0.0 Fecha: 2025-12-05 Épica: OQI-003 - Trading y Charts Prioridad: P0 Story Points: 8
Descripción
El sistema debe proporcionar una gestión completa de posiciones abiertas, permitiendo a los usuarios monitorear su exposición al mercado, PnL en tiempo real, y ejecutar acciones sobre sus posiciones de manera eficiente y segura.
Requisitos Funcionales
RF-TRD-006.1: Apertura de Posiciones
El sistema debe:
- Crear posición automáticamente al ejecutar orden buy/sell
- Soportar posiciones long (compra) y short (venta, futuro)
- Permitir una posición por símbolo en paper trading MVP
- Calcular precio promedio de entrada
- Registrar timestamp de apertura
- Aplicar stop loss y take profit si fueron configurados
RF-TRD-006.2: Información de Posición
El sistema debe mostrar para cada posición:
| Campo | Descripción | Cálculo |
|---|---|---|
| Symbol | Par de trading | - |
| Side | Long/Short | - |
| Entry Price | Precio promedio de entrada | Weighted average |
| Current Price | Precio actual del mercado | Real-time |
| Quantity | Cantidad del activo | - |
| Position Value | Valor actual de la posición | quantity × currentPrice |
| Unrealized PnL | Ganancia/pérdida no realizada | (currentPrice - entryPrice) × quantity |
| Unrealized PnL % | Porcentaje de ganancia/pérdida | ((currentPrice - entryPrice) / entryPrice) × 100 |
| Margin Used | Margen ocupado | positionValue / leverage |
| Liquidation Price | Precio de liquidación | Calculado según leverage |
| Duration | Tiempo abierta | now - openedAt |
RF-TRD-006.3: Actualización en Tiempo Real
El sistema debe:
- Actualizar precios actuales cada 1 segundo vía WebSocket
- Recalcular PnL automáticamente con cada update
- Mostrar animación visual en cambios de precio
- Destacar posiciones en riesgo (pérdida > 50%)
- Actualizar métricas agregadas (total PnL, total margin)
RF-TRD-006.4: Panel de Posiciones
El sistema debe proporcionar tabla con:
- Lista de todas las posiciones abiertas
- Resumen agregado en header
- Filtros por símbolo, side, PnL
- Ordenamiento por cualquier columna
- Indicadores visuales de estado
- Acciones rápidas por posición
Resumen agregado:
Total Positions: 5
Total Margin Used: $15,234.56
Total Unrealized PnL: +$1,234.56 (+8.1%)
RF-TRD-006.5: Cerrar Posiciones
El sistema debe permitir:
Cierre total:
- Cerrar 100% de la posición
- Ejecutar orden market al precio actual
- Calcular PnL realizado
- Actualizar balance
- Registrar trade en historial
Cierre parcial:
- Cerrar porcentaje específico (25%, 50%, 75%)
- Mantener resto de posición abierta
- Recalcular precio promedio
- Registrar trade parcial
Confirmación:
- Modal con previsualización del cierre
- Mostrar PnL estimado
- Mostrar balance después del cierre
- Requiere confirmación del usuario
RF-TRD-006.6: Stop Loss y Take Profit
El sistema debe:
Configuración:
- Añadir SL/TP a posición existente
- Modificar SL/TP existentes
- Eliminar SL/TP
- Validar precios lógicos según side
Monitoreo automático:
- Verificar precios cada 1 segundo
- Ejecutar cierre automático al alcanzar nivel
- Notificar al usuario
- Registrar motivo de cierre
Trailing Stop Loss:
- Actualizar SL automáticamente según ganancia
- Configurar trailing distance (% o USD)
- Activar solo cuando posición es ganadora
RF-TRD-006.7: Alertas y Notificaciones
El sistema debe notificar cuando:
- Posición alcanza +X% de ganancia
- Posición alcanza -X% de pérdida
- Stop Loss está cerca de activarse (5%)
- Take Profit está cerca de activarse (5%)
- Posición está en riesgo de liquidación
- Posición ha estado abierta > 24h
RF-TRD-006.8: Gestión de Riesgo
El sistema debe:
Validaciones:
- Impedir apertura si margin used > 80% del balance
- Advertir si posición representa > 50% del portfolio
- Bloquear si existe ya posición del mismo símbolo
- Validar que stop loss sea lógico
Liquidación:
- Calcular precio de liquidación
- Liquidar automáticamente al alcanzarlo
- Notificar antes de liquidación (margen < 20%)
- Registrar liquidación en historial
Métricas de riesgo:
- Exposure por símbolo
- Exposure total
- Ratio de margen (margin used / balance)
- Win rate actual
- Average holding time
Datos de Entrada
Modificar Posición
interface UpdatePositionDto {
positionId: string;
stopLoss?: {
type: 'price' | 'percent';
value: number;
trailing?: {
enabled: boolean;
distance: number; // % o USD
};
};
takeProfit?: {
type: 'price' | 'percent';
value: number;
};
}
Cerrar Posición
interface ClosePositionDto {
positionId: string;
percentage: number; // 1-100, default 100
type: 'market' | 'limit';
limitPrice?: number;
}
Datos de Salida
Posición
interface Position {
id: string;
userId: string;
symbol: string;
side: 'long' | 'short';
// Cantidades
quantity: number;
entryPrice: number;
currentPrice: number;
// PnL
unrealizedPnl: number;
unrealizedPnlPercent: number;
realizedPnl: number; // De cierres parciales
// Valores
positionValue: number;
marginUsed: number;
// Stop Loss / Take Profit
stopLoss: PositionStopLoss | null;
takeProfit: PositionTakeProfit | null;
// Liquidación
liquidationPrice: number | null;
liquidationRisk: 'low' | 'medium' | 'high';
// Timestamps
openedAt: string;
lastUpdatedAt: string;
duration: number; // Segundos
// Estado
status: 'open' | 'closing' | 'closed';
isInProfit: boolean;
}
interface PositionStopLoss {
price: number;
type: 'price' | 'percent';
isTrailing: boolean;
trailingDistance?: number;
originalPrice?: number; // Para trailing
}
interface PositionTakeProfit {
price: number;
type: 'price' | 'percent';
}
Resumen de Posiciones
interface PositionsSummary {
totalPositions: number;
totalMarginUsed: number;
totalUnrealizedPnl: number;
totalUnrealizedPnlPercent: number;
marginRatio: number; // marginUsed / balance
byStatus: {
profitable: number;
unprofitable: number;
};
bySide: {
long: number;
short: number;
};
topGainer: Position | null;
topLoser: Position | null;
}
Reglas de Negocio
-
Posiciones simultáneas:
- MVP: 1 posición por símbolo
- Futuro: Múltiples posiciones (avg down/up)
-
Cierre de posiciones:
- Cierre parcial mínimo: 10%
- Siempre ejecutar a precio market
- Actualizar entrada promedio en parciales
-
Stop Loss:
- Debe estar por debajo del entry (long) o por encima (short)
- Mínimo 0.5% del entry price
- Máximo 50% del entry price
-
Take Profit:
- Debe estar por encima del entry (long) o por debajo (short)
- Mínimo 0.5% del entry price
- Sin límite máximo
-
Liquidación:
- Ocurre si pérdida > 80% del margen
- Notificar cuando margen < 20%
- Liquidar todo, no parcial
-
Trailing Stop:
- Solo se activa si posición en ganancia
- Se mueve solo hacia ganancia, nunca retrocede
- Mínima distancia: 0.5%
Criterios de Aceptación
Escenario: Posición se crea al ejecutar orden
DADO que el usuario creó orden buy de 0.5 BTC a $50,000
CUANDO la orden se ejecuta
ENTONCES se crea posición long
Y entry price es $50,000
Y quantity es 0.5 BTC
Y aparece en panel de posiciones
Escenario: PnL se actualiza en tiempo real
DADO que el usuario tiene posición long con entry $50,000
Y quantity es 0.5 BTC
CUANDO el precio sube a $51,000
ENTONCES unrealized PnL muestra +$500 (+2%)
Y el valor se actualiza cada segundo
Y se muestra en color verde
Escenario: Usuario cierra posición parcialmente
DADO que el usuario tiene posición de 1 BTC
CUANDO cierra 50% de la posición
ENTONCES se ejecuta orden sell de 0.5 BTC
Y la posición se reduce a 0.5 BTC
Y se calcula PnL realizado de la mitad cerrada
Y se registra trade en historial
Escenario: Stop Loss se activa
DADO que el usuario tiene posición long entry $50,000
Y stop loss configurado en $48,000
CUANDO el precio baja a $48,000
ENTONCES se ejecuta orden market sell automática
Y la posición se cierra completamente
Y se registra PnL realizado de -4%
Y aparece notificación "Stop Loss activado"
Escenario: Trailing Stop se ajusta
DADO que el usuario tiene trailing stop con 5% de distancia
Y posición long entry $50,000
Y stop loss inicial $47,500
CUANDO el precio sube a $55,000
ENTONCES stop loss se actualiza a $52,250 (5% debajo)
Y se muestra en panel de posiciones
Y se preserva ganancia de +4.5%
Escenario: Advertencia de riesgo de liquidación
DADO que el usuario tiene posición con 80% de pérdida
CUANDO se actualiza el precio
ENTONCES aparece alerta "Riesgo de liquidación"
Y se destaca la posición en rojo
Y se sugiere añadir margen o cerrar
Escenario: Usuario modifica Stop Loss
DADO que el usuario tiene posición con SL en $48,000
CUANDO modifica SL a $49,000
ENTONCES el nuevo SL se guarda
Y se monitorea el nuevo nivel
Y aparece confirmación
Interfaz de Usuario
┌────────────────────────────────────────────────────────────────┐
│ OPEN POSITIONS │
├────────────────────────────────────────────────────────────────┤
│ Total: 3 │ Margin: $15,234 │ PnL: +$1,234 (+8.1%) │
├────────────────────────────────────────────────────────────────┤
│ │
│ Symbol │ Side │ Entry │ Current │ Qty │ PnL │ │
│──────────┼──────┼────────┼─────────┼────────┼──────────┼─────│
│ BTCUSDT │ LONG │ 50,000 │ 51,500 │ 0.5 │ +$750 │ ... │
│ │ │ │ │ │ (+3.0%) │ │
│ │ │ SL: $48,000 TP: $55,000 │ Close│
│──────────┼──────┼────────┼─────────┼────────┼──────────┼─────│
│ ETHUSDT │ LONG │ 3,200 │ 3,350 │ 2.0 │ +$300 │ ... │
│ │ │ │ │ │ (+4.7%) │ │
│ │ │ SL: None TP: $3,500 │ Close│
│──────────┼──────┼────────┼─────────┼────────┼──────────┼─────│
│ BNBUSDT │ LONG │ 450 │ 425 │ 10 │ -$250 │ ... │
│ │ │ │ │ │ (-5.6%) │ │
│ │ │ SL: $400 TP: None │ Close│
└────────────────────────────────────────────────────────────────┘
Estados de Posición
┌──────────┐
│ OPEN │ ← Estado normal
└────┬─────┘
│
├─→ Profitable (PnL > 0)
├─→ Unprofitable (PnL < 0)
├─→ At Risk (loss > 50%)
│
├─→ [SL triggered] → CLOSING → CLOSED
├─→ [TP triggered] → CLOSING → CLOSED
├─→ [User closes] → CLOSING → CLOSED
└─→ [Liquidated] → LIQUIDATED
Dependencias
- RF-TRD-005: Sistema de Órdenes (crear órdenes de cierre)
- RF-TRD-004: Paper Trading (balance y ejecución)
- RF-TRD-007: Historial (registrar trades cerrados)
- WebSocket para precios en tiempo real
Notas Técnicas
- Actualizar PnL con debounce de 1 segundo
- Usar transacciones para cierres de posición
- Implementar locks para evitar double-close
- Cachear cálculos pesados (liquidation price)
- Guardar snapshots de precio cada minuto
- Implementar circuit breaker para liquidaciones masivas
- Usar Redis para monitoreo eficiente de SL/TP
- Indexar por userId y status para queries rápidas
Cálculos Importantes
PnL para Long Position
Unrealized PnL = (currentPrice - entryPrice) × quantity
Unrealized PnL % = ((currentPrice - entryPrice) / entryPrice) × 100
PnL para Short Position (futuro)
Unrealized PnL = (entryPrice - currentPrice) × quantity
Unrealized PnL % = ((entryPrice - currentPrice) / entryPrice) × 100
Liquidation Price (sin apalancamiento)
Liquidation Price = entryPrice × 0.2 (pérdida del 80%)
Trailing Stop Loss Update
New SL = currentPrice × (1 - trailingDistance) // Para long
Métricas a Trackear
- Posiciones abiertas concurrentes
- Tiempo promedio de holding
- Win rate (profitable / total)
- Profit factor (gross profit / gross loss)
- Activaciones de SL vs TP
- Liquidaciones (debería ser 0 idealmente)
- Máximo drawdown por posición