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>
318 lines
11 KiB
Markdown
318 lines
11 KiB
Markdown
---
|
|
id: "US-TRD-009"
|
|
title: "Ver Panel de Posiciones Abiertas"
|
|
type: "User Story"
|
|
status: "Done"
|
|
priority: "Alta"
|
|
epic: "OQI-003"
|
|
story_points: 3
|
|
created_date: "2025-12-05"
|
|
updated_date: "2026-01-04"
|
|
---
|
|
|
|
# US-TRD-009: Ver Panel de Posiciones Abiertas
|
|
|
|
## Metadata
|
|
|
|
| Campo | Valor |
|
|
|-------|-------|
|
|
| **ID** | US-TRD-009 |
|
|
| **Épica** | OQI-003 - Trading y Charts |
|
|
| **Módulo** | trading |
|
|
| **Prioridad** | P0 |
|
|
| **Story Points** | 3 |
|
|
| **Sprint** | Sprint 4 |
|
|
| **Estado** | Pendiente |
|
|
| **Asignado a** | Por asignar |
|
|
|
|
---
|
|
|
|
## Historia de Usuario
|
|
|
|
**Como** trader practicante,
|
|
**quiero** ver un panel con todas mis posiciones abiertas y su P&L en tiempo real,
|
|
**para** monitorear el rendimiento actual de mis trades y tomar decisiones informadas.
|
|
|
|
## Descripción Detallada
|
|
|
|
El usuario debe tener acceso a un panel dedicado que muestre todas las posiciones abiertas con información crítica: símbolo, dirección (long/short), tamaño, precio de entrada, precio actual, P&L no realizado en dólares y porcentaje, y acciones rápidas (cerrar, modificar TP/SL).
|
|
|
|
## Mockups/Wireframes
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ OPEN POSITIONS Total P&L: +$345.67 │
|
|
├─────────────────────────────────────────────────────────────────────────┤
|
|
│ Symbol Side Size Entry Current PnL Actions │
|
|
│ ───────────────────────────────────────────────────────────────────── │
|
|
│ BTCUSDT LONG 0.10 BTC $95,000.00 $97,234.50 +$223.45 [...] │
|
|
│ (+2.35%) ▲ │
|
|
│ TP: $100,000 | SL: $93,000 │
|
|
│ ───────────────────────────────────────────────────────────────────── │
|
|
│ ETHUSDT LONG 2.5 ETH $3,800.00 $3,850.20 +$125.50 [...] │
|
|
│ (+1.32%) ▲ │
|
|
│ TP: $4,000 | SL: $3,700 │
|
|
│ ───────────────────────────────────────────────────────────────────── │
|
|
│ SOLUSDT SHORT 10 SOL $145.00 $142.73 +$22.70 [...] │
|
|
│ (+1.56%) ▲ │
|
|
│ TP: $140.00 | SL: $148.00 │
|
|
│ ───────────────────────────────────────────────────────────────────── │
|
|
│ │
|
|
│ Summary: │
|
|
│ Total Margin Used: $7,450.00 | Free Balance: $2,550.00 │
|
|
│ Total Equity: $10,345.67 | Margin Level: 138.9% │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
|
|
┌─────────────────────────┐
|
|
│ POSITION ACTIONS │
|
|
├─────────────────────────┤
|
|
│ > Close Position │
|
|
│ > Modify TP/SL │
|
|
│ > Add to Position │
|
|
│ > View on Chart │
|
|
└─────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Criterios de Aceptación
|
|
|
|
**Escenario 1: Ver panel con múltiples posiciones**
|
|
```gherkin
|
|
DADO que el usuario tiene 3 posiciones abiertas
|
|
CUANDO navega al panel de posiciones
|
|
ENTONCES se muestran las 3 posiciones en una tabla
|
|
Y cada fila muestra: símbolo, side, size, entry, current, P&L
|
|
Y el P&L total aparece en el header
|
|
Y los valores se actualizan cada segundo
|
|
```
|
|
|
|
**Escenario 2: Actualización de P&L en tiempo real**
|
|
```gherkin
|
|
DADO que el usuario tiene posición long BTCUSDT
|
|
Y el precio actual es $97,234.50
|
|
CUANDO el precio sube a $97,500.00
|
|
ENTONCES el P&L se actualiza automáticamente
|
|
Y muestra +$250.00 (+2.63%)
|
|
Y el color cambia según el valor (verde positivo, rojo negativo)
|
|
```
|
|
|
|
**Escenario 3: Mostrar TP y SL configurados**
|
|
```gherkin
|
|
DADO que la posición tiene TP=$100,000 y SL=$93,000
|
|
CUANDO el usuario ve la posición
|
|
ENTONCES se muestran ambos valores debajo de la fila principal
|
|
Y se indica la distancia en % al TP y SL
|
|
Ejemplo: "TP: $100,000 (+2.84%) | SL: $93,000 (-4.35%)"
|
|
```
|
|
|
|
**Escenario 4: Panel vacío**
|
|
```gherkin
|
|
DADO que el usuario no tiene posiciones abiertas
|
|
CUANDO accede al panel de posiciones
|
|
ENTONCES se muestra mensaje "No open positions"
|
|
Y se muestra botón "Start Trading"
|
|
Y el total P&L es $0.00
|
|
```
|
|
|
|
**Escenario 5: Ordenar por P&L**
|
|
```gherkin
|
|
DADO que el usuario tiene múltiples posiciones
|
|
CUANDO hace click en el header "PnL"
|
|
ENTONCES las posiciones se ordenan por P&L descendente
|
|
Y un segundo click ordena ascendente
|
|
```
|
|
|
|
**Escenario 6: Filtrar por símbolo**
|
|
```gherkin
|
|
DADO que el usuario tiene posiciones en BTC, ETH, SOL
|
|
CUANDO escribe "BTC" en el filtro
|
|
ENTONCES solo se muestran posiciones de BTCUSDT
|
|
```
|
|
|
|
## Criterios Adicionales
|
|
|
|
- [ ] Resaltar posiciones con P&L > ±5% en color intenso
|
|
- [ ] Sonido de alerta cuando P&L alcanza ±10%
|
|
- [ ] Mostrar duración de la posición (ej: "2h 35m")
|
|
- [ ] Indicador visual cuando el precio se acerca al TP o SL (±2%)
|
|
- [ ] Exportar posiciones a CSV
|
|
|
|
---
|
|
|
|
## Tareas Técnicas
|
|
|
|
**Database:**
|
|
- [ ] DB-TRD-014: Crear vista positions_with_pnl con cálculos
|
|
|
|
**Backend:**
|
|
- [ ] BE-TRD-044: Crear endpoint GET /trading/paper/positions
|
|
- [ ] BE-TRD-045: Implementar PositionService.listPositions()
|
|
- [ ] BE-TRD-046: Implementar cálculo de P&L no realizado
|
|
- [ ] BE-TRD-047: Implementar WebSocket para actualizaciones de P&L
|
|
- [ ] BE-TRD-048: Añadir filtros y ordenamiento
|
|
|
|
**Frontend:**
|
|
- [ ] FE-TRD-044: Crear componente PositionsPanel.tsx
|
|
- [ ] FE-TRD-045: Crear componente PositionRow.tsx
|
|
- [ ] FE-TRD-046: Crear componente PositionSummary.tsx
|
|
- [ ] FE-TRD-047: Crear componente PositionActions.tsx
|
|
- [ ] FE-TRD-048: Implementar hook usePositions con WebSocket
|
|
- [ ] FE-TRD-049: Implementar animación de cambios de P&L
|
|
|
|
**Tests:**
|
|
- [ ] TEST-TRD-022: Test unitario cálculo P&L no realizado
|
|
- [ ] TEST-TRD-023: Test integración listar posiciones
|
|
- [ ] TEST-TRD-024: Test E2E actualización en tiempo real
|
|
|
|
---
|
|
|
|
## Dependencias
|
|
|
|
**Depende de:**
|
|
- [ ] US-TRD-006: Crear orden market - Estado: Pendiente (necesita posiciones)
|
|
- [ ] US-TRD-001: Ver chart - Estado: Pendiente (para precios)
|
|
|
|
**Bloquea:**
|
|
- [ ] US-TRD-008: Cerrar posición
|
|
- [ ] US-TRD-012: Configurar TP/SL
|
|
|
|
---
|
|
|
|
## Notas Técnicas
|
|
|
|
**Endpoints involucrados:**
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | /trading/paper/positions | Listar posiciones abiertas |
|
|
| GET | /trading/paper/positions/summary | Resumen de posiciones |
|
|
| WS | /trading/positions/stream | Stream de actualizaciones P&L |
|
|
|
|
**Entidades/Tablas:**
|
|
```sql
|
|
CREATE VIEW trading.positions_with_pnl AS
|
|
SELECT
|
|
p.*,
|
|
t.price as current_price,
|
|
CASE
|
|
WHEN p.side = 'long' THEN (t.price - p.entry_price) * p.quantity
|
|
WHEN p.side = 'short' THEN (p.entry_price - t.price) * p.quantity
|
|
END as unrealized_pnl,
|
|
CASE
|
|
WHEN p.side = 'long' THEN ((t.price - p.entry_price) / p.entry_price) * 100
|
|
WHEN p.side = 'short' THEN ((p.entry_price - t.price) / p.entry_price) * 100
|
|
END as unrealized_pnl_percentage,
|
|
EXTRACT(EPOCH FROM (NOW() - p.created_at)) as duration_seconds
|
|
FROM trading.paper_positions p
|
|
LEFT JOIN trading.current_prices t ON p.symbol = t.symbol
|
|
WHERE p.status = 'open';
|
|
```
|
|
|
|
**Componentes UI:**
|
|
- `PositionsPanel`: Panel principal
|
|
- `PositionRow`: Fila de posición con datos
|
|
- `PositionSummary`: Resumen total
|
|
- `PositionActions`: Menú de acciones
|
|
- `PnLCell`: Celda con P&L coloreado y animado
|
|
|
|
**Response (List Positions):**
|
|
```typescript
|
|
{
|
|
positions: [
|
|
{
|
|
id: "uuid-1",
|
|
symbol: "BTCUSDT",
|
|
side: "long",
|
|
quantity: 0.1,
|
|
entryPrice: 95000.00,
|
|
currentPrice: 97234.50,
|
|
unrealizedPnl: 223.45,
|
|
unrealizedPnlPercentage: 2.35,
|
|
marginUsed: 9500.00,
|
|
takeProfit: 100000.00,
|
|
stopLoss: 93000.00,
|
|
durationSeconds: 8640,
|
|
createdAt: "2025-12-05T08:00:00Z"
|
|
},
|
|
// ... más posiciones
|
|
],
|
|
summary: {
|
|
totalPositions: 3,
|
|
totalMarginUsed: 7450.00,
|
|
totalUnrealizedPnl: 345.67,
|
|
totalUnrealizedPnlPercentage: 4.64,
|
|
freeBalance: 2550.00,
|
|
totalEquity: 10345.67,
|
|
marginLevel: 138.9
|
|
}
|
|
}
|
|
```
|
|
|
|
**WebSocket Update:**
|
|
```typescript
|
|
{
|
|
type: "position_update",
|
|
data: {
|
|
positionId: "uuid-1",
|
|
currentPrice: 97500.00,
|
|
unrealizedPnl: 250.00,
|
|
unrealizedPnlPercentage: 2.63,
|
|
timestamp: 1733414400
|
|
}
|
|
}
|
|
```
|
|
|
|
**Cálculos importantes:**
|
|
```typescript
|
|
// P&L no realizado (unrealized)
|
|
const unrealizedPnl = side === 'long'
|
|
? (currentPrice - entryPrice) * quantity
|
|
: (entryPrice - currentPrice) * quantity;
|
|
|
|
// Equity
|
|
const equity = balance + totalUnrealizedPnl;
|
|
|
|
// Margin Level
|
|
const marginLevel = (equity / totalMarginUsed) * 100;
|
|
|
|
// Distancia a TP/SL
|
|
const distanceToTP = ((takeProfit - currentPrice) / currentPrice) * 100;
|
|
const distanceToSL = ((stopLoss - currentPrice) / currentPrice) * 100;
|
|
```
|
|
|
|
---
|
|
|
|
## Definition of Ready (DoR)
|
|
|
|
- [x] Historia claramente escrita
|
|
- [x] Criterios de aceptación definidos
|
|
- [x] Story points estimados
|
|
- [x] Dependencias identificadas
|
|
- [x] Sin bloqueadores
|
|
- [ ] Diseño/mockup disponible
|
|
- [ ] API spec disponible
|
|
|
|
## Definition of Done (DoD)
|
|
|
|
- [ ] Código implementado según criterios
|
|
- [ ] Tests unitarios escritos y pasando
|
|
- [ ] Tests de integración pasando
|
|
- [ ] Code review aprobado
|
|
- [ ] Documentación actualizada
|
|
- [ ] QA aprobado
|
|
- [ ] Desplegado en ambiente de pruebas
|
|
|
|
---
|
|
|
|
## Historial de Cambios
|
|
|
|
| Fecha | Cambio | Autor |
|
|
|-------|--------|-------|
|
|
| 2025-12-05 | Creación | Requirements-Analyst |
|
|
|
|
---
|
|
|
|
**Creada por:** Requirements-Analyst
|
|
**Fecha:** 2025-12-05
|
|
**Última actualización:** 2025-12-05
|