--- id: "US-TRD-008" title: "Cerrar Posicion" 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-008: Cerrar Posición ## Metadata | Campo | Valor | |-------|-------| | **ID** | US-TRD-008 | | **É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** cerrar mis posiciones abiertas total o parcialmente, **para** realizar mis ganancias o limitar mis pérdidas en el momento que decida. ## Descripción Detallada El usuario debe poder cerrar posiciones long o short en cualquier momento, ya sea completamente o una porción específica. Al cerrar, se ejecuta una orden market en dirección opuesta y se calcula el P&L (profit and loss) realizado. ## Mockups/Wireframes ``` ┌─────────────────────────────────────────────────────────────────┐ │ OPEN POSITIONS │ ├─────────────────────────────────────────────────────────────────┤ │ Symbol Side Size Entry Current PnL Actions │ │ ────────────────────────────────────────────────────────────── │ │ BTCUSDT LONG 0.1 BTC $95,000 $97,234.50 +$223.45 [Close]│ │ (+2.35%) [ ▼ ] │ │ ────────────────────────────────────────────────────────────── │ │ │ │ ┌────────────────────────────────────┐ │ │ │ CLOSE POSITION │ │ │ ├────────────────────────────────────┤ │ │ │ Symbol: BTCUSDT │ │ │ │ Position: 0.1 BTC LONG │ │ │ │ │ │ │ │ Amount to close: │ │ │ │ ┌──────────────────────────────┐ │ │ │ │ │ 0.1 BTC │ │ │ │ │ └──────────────────────────────┘ │ │ │ │ [25%] [50%] [75%] [100%] │ │ │ │ │ │ │ │ Entry Price: $95,000.00 │ │ │ │ Current Price: $97,234.50 │ │ │ │ Est. P&L: +$223.45 (+2.35%) │ │ │ │ │ │ │ │ [Cancel] [Close Position] │ │ │ └────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Criterios de Aceptación **Escenario 1: Cerrar posición long completa** ```gherkin DADO que el usuario tiene posición long de 0.1 BTC en BTCUSDT Y el precio de entrada fue $95,000 Y el precio actual es $97,234.50 CUANDO hace click en "Close" en la posición Y selecciona cerrar 100% (0.1 BTC) Y confirma ENTONCES se ejecuta orden market SELL de 0.1 BTC Y la posición se cierra completamente Y se calcula P&L: +$223.45 (+2.35%) Y el balance se incrementa en $9,723.45 ($9,500 + $223.45) Y la posición desaparece de "Open Positions" Y se muestra notificación "Position closed. P&L: +$223.45" ``` **Escenario 2: Cerrar posición short con ganancia** ```gherkin DADO que el usuario tiene posición short de 0.05 BTC Y el precio de entrada fue $97,000 Y el precio actual es $96,000 CUANDO cierra la posición completa ENTONCES se ejecuta orden market BUY de 0.05 BTC Y se calcula P&L: +$50.00 (+1.03%) Y la posición se cierra ``` **Escenario 3: Cerrar posición parcial (50%)** ```gherkin DADO que el usuario tiene posición long de 0.1 BTC CUANDO hace click en "Close" Y selecciona 50% (0.05 BTC) Y confirma ENTONCES se cierra solo 0.05 BTC Y la posición restante es 0.05 BTC Y el P&L parcial se registra Y la posición sigue apareciendo con nuevo tamaño ``` **Escenario 4: Cerrar posición con pérdida** ```gherkin DADO que el usuario tiene posición long a $97,000 Y el precio actual es $95,000 CUANDO cierra la posición ENTONCES se calcula P&L: -$200.00 (-2.06%) Y el balance se reduce en $200 Y se registra la pérdida en el historial ``` **Escenario 5: Confirmación antes de cerrar** ```gherkin DADO que el usuario hace click en "Close" CUANDO se abre el diálogo de confirmación ENTONCES muestra: - Cantidad a cerrar - Precio de entrada vs actual - P&L estimado - Botón de confirmar Y debe confirmar antes de ejecutar ``` ## Criterios Adicionales - [ ] Slippage aplicado al cerrar (±0.1%) - [ ] Keyboard shortcut: Esc para cancelar - [ ] Color verde para P&L positivo, rojo para negativo - [ ] Mostrar ROI (Return on Investment) en % - [ ] Registro en trade history --- ## Tareas Técnicas **Database:** - [ ] DB-TRD-012: Crear tabla paper_trade_history - [ ] DB-TRD-013: Añadir campo closed_at a paper_positions **Backend:** - [ ] BE-TRD-038: Crear endpoint POST /trading/paper/positions/:id/close - [ ] BE-TRD-039: Implementar PositionService.closePosition() - [ ] BE-TRD-040: Implementar cálculo de P&L - [ ] BE-TRD-041: Implementar cierre parcial - [ ] BE-TRD-042: Actualizar BalanceService con P&L - [ ] BE-TRD-043: Crear registro en trade_history **Frontend:** - [ ] FE-TRD-038: Crear componente OpenPositionsPanel.tsx - [ ] FE-TRD-039: Crear componente ClosePositionDialog.tsx - [ ] FE-TRD-040: Crear componente PositionRow.tsx con P&L - [ ] FE-TRD-041: Implementar hook useClosePosition - [ ] FE-TRD-042: Actualizar positionStore con cierres - [ ] FE-TRD-043: Implementar animación al cerrar **Tests:** - [ ] TEST-TRD-019: Test unitario cálculo P&L - [ ] TEST-TRD-020: Test integración cerrar posición - [ ] TEST-TRD-021: Test E2E flujo completo cierre --- ## Dependencias **Depende de:** - [ ] US-TRD-006: Crear orden market - Estado: Pendiente (necesita posiciones abiertas) **Bloquea:** - [ ] US-TRD-010: Ver historial de trades --- ## Notas Técnicas **Endpoints involucrados:** | Método | Endpoint | Descripción | |--------|----------|-------------| | POST | /trading/paper/positions/:id/close | Cerrar posición | | GET | /trading/paper/positions | Listar posiciones abiertas | | GET | /trading/paper/positions/:id | Obtener detalles de posición | **Entidades/Tablas:** ```sql CREATE TABLE trading.paper_trade_history ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES auth.users(id), symbol VARCHAR(20) NOT NULL, side VARCHAR(10) NOT NULL, quantity DECIMAL(20, 8) NOT NULL, entry_price DECIMAL(20, 8) NOT NULL, exit_price DECIMAL(20, 8) NOT NULL, pnl DECIMAL(20, 8) NOT NULL, pnl_percentage DECIMAL(10, 4) NOT NULL, opened_at TIMESTAMP NOT NULL, closed_at TIMESTAMP DEFAULT NOW(), duration_seconds INTEGER ); ALTER TABLE trading.paper_positions ADD COLUMN closed_at TIMESTAMP; ALTER TABLE trading.paper_positions ADD COLUMN status VARCHAR(20) DEFAULT 'open'; ``` **Componentes UI:** - `OpenPositionsPanel`: Panel de posiciones abiertas - `ClosePositionDialog`: Modal de confirmación - `PositionRow`: Fila con datos de posición - `PnLBadge`: Badge con P&L coloreado **Request Body:** ```typescript { quantity: 0.05, // Cantidad a cerrar (o null para cerrar todo) percentage: 50 // O porcentaje (25, 50, 75, 100) } ``` **Response:** ```typescript { trade: { id: "uuid", symbol: "BTCUSDT", side: "long", quantity: 0.05, entryPrice: 95000.00, exitPrice: 97234.50, pnl: 111.73, pnlPercentage: 2.35, openedAt: "2025-12-05T09:00:00Z", closedAt: "2025-12-05T10:30:00Z", durationSeconds: 5400 }, position: { id: "uuid", remainingQuantity: 0.05, // Si cierre parcial status: "open" // o "closed" }, balance: { balance: 9611.73, equity: 9723.46, marginUsed: 4762.50 } } ``` **Cálculo de P&L:** ```typescript // Para posición LONG const pnl = (exitPrice - entryPrice) * quantity; const pnlPercentage = ((exitPrice - entryPrice) / entryPrice) * 100; // Para posición SHORT const pnl = (entryPrice - exitPrice) * quantity; const pnlPercentage = ((entryPrice - exitPrice) / entryPrice) * 100; // Aplicar slippage (simulación) const slippage = 0.001; // 0.1% const actualExitPrice = side === 'long' ? currentPrice * (1 - slippage) : currentPrice * (1 + slippage); ``` --- ## 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