trading-platform/docs/02-definicion-modulos/OQI-003-trading-charts/requerimientos/RF-TRD-006-gestion-posiciones.md

469 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
```typescript
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
```typescript
interface ClosePositionDto {
positionId: string;
percentage: number; // 1-100, default 100
type: 'market' | 'limit';
limitPrice?: number;
}
```
---
## Datos de Salida
### Posición
```typescript
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
```typescript
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
1. **Posiciones simultáneas:**
- MVP: 1 posición por símbolo
- Futuro: Múltiples posiciones (avg down/up)
2. **Cierre de posiciones:**
- Cierre parcial mínimo: 10%
- Siempre ejecutar a precio market
- Actualizar entrada promedio en parciales
3. **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
4. **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
5. **Liquidación:**
- Ocurre si pérdida > 80% del margen
- Notificar cuando margen < 20%
- Liquidar todo, no parcial
6. **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
```gherkin
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