---
id: "US-TRD-012"
title: "Configurar Take Profit y Stop Loss"
type: "User Story"
status: "Done"
priority: "Alta"
epic: "OQI-003"
story_points: 5
created_date: "2025-12-05"
updated_date: "2026-01-04"
---

# US-TRD-012: Configurar Take Profit y Stop Loss

## Metadata

| Campo | Valor |
|-------|-------|
| **ID** | US-TRD-012 |
| **Épica** | OQI-003 - Trading y Charts |
| **Módulo** | trading |
| **Prioridad** | P1 |
| **Story Points** | 3 |
| **Sprint** | Sprint 5 |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |

---

## Historia de Usuario

**Como** trader practicante,
**quiero** configurar niveles de Take Profit y Stop Loss en mis posiciones,
**para** automatizar la gestión de riesgo y asegurar ganancias sin monitoreo constante.

## Descripción Detallada

El usuario debe poder establecer niveles de Take Profit (TP) y Stop Loss (SL) en posiciones abiertas, tanto al crear una orden como después de que la posición esté abierta. El sistema debe monitorear estos niveles y ejecutar automáticamente el cierre cuando el precio los alcance.

## Mockups/Wireframes

```
┌─────────────────────────────────────────────────────────────────┐
│  CONFIGURE TP/SL - BTCUSDT LONG Position                       │
├─────────────────────────────────────────────────────────────────┤
│  Position Details:                                              │
│  Size: 0.1 BTC  |  Entry: $95,000  |  Current: $97,234.50      │
│  Current P&L: +$223.45 (+2.35%)                                 │
│                                                                  │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │ TAKE PROFIT                                       [✓ Enable]│ │
│  ├───────────────────────────────────────────────────────────┤ │
│  │ Price:                                                     │ │
│  │ ┌─────────────────────────────────────┐                   │ │
│  │ │ 100,000.00                          │                   │ │
│  │ └─────────────────────────────────────┘                   │ │
│  │ Distance: +2.84% (+$2,765.50)                             │ │
│  │ [Set 1%] [Set 2%] [Set 5%] [Set 10%]                      │ │
│  │                                                            │ │
│  │ Est. Profit if triggered: +$500.00 (+5.26%)               │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                  │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │ STOP LOSS                                         [✓ Enable]│ │
│  ├───────────────────────────────────────────────────────────┤ │
│  │ Price:                                                     │ │
│  │ ┌─────────────────────────────────────┐                   │ │
│  │ │ 93,000.00                           │                   │ │
│  │ └─────────────────────────────────────┘                   │ │
│  │ Distance: -4.35% (-$4,234.50)                             │ │
│  │ [Set 1%] [Set 2%] [Set 5%] [Set 10%]                      │ │
│  │                                                            │ │
│  │ Est. Loss if triggered: -$200.00 (-2.11%)                 │ │
│  │ ⚠ Warning: SL is below entry price                        │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                  │
│  Risk/Reward Ratio: 2.50 (Good)                                │
│                                                                  │
│  ┌───────────────────────────────────────────────────────────┐ │
│  │                                                            │ │
│  │  Chart Preview:                                            │ │
│  │    $100,000 ─────────────────── TP (Green line)           │ │
│  │     $97,234 ████ Current Price                            │ │
│  │     $95,000 ──── Entry (Blue line)                        │ │
│  │     $93,000 ─────────────────── SL (Red line)             │ │
│  │                                                            │ │
│  └───────────────────────────────────────────────────────────┘ │
│                                                                  │
│  [Cancel]  [Save TP/SL]                                         │
└─────────────────────────────────────────────────────────────────┘
```

---

## Criterios de Aceptación

**Escenario 1: Configurar TP y SL en posición existente**
```gherkin
DADO que el usuario tiene posición long BTCUSDT a $95,000
Y el precio actual es $97,234.50
CUANDO abre el diálogo de TP/SL
Y habilita Take Profit en $100,000
Y habilita Stop Loss en $93,000
Y hace click en "Save"
ENTONCES se guardan los niveles
Y aparecen en el panel de posiciones
Y se muestran líneas horizontales en el chart
Y el sistema comienza a monitorear estos niveles
```

**Escenario 2: Activación automática de Take Profit**
```gherkin
DADO que la posición tiene TP en $100,000
CUANDO el precio sube y alcanza $100,000
ENTONCES se ejecuta automáticamente orden market sell
Y la posición se cierra
Y el P&L realizado es +$500.00
Y el close_reason es "take_profit"
Y se envía notificación "Take Profit triggered at $100,000"
```

**Escenario 3: Activación automática de Stop Loss**
```gherkin
DADO que la posición tiene SL en $93,000
CUANDO el precio baja y alcanza $93,000
ENTONCES se ejecuta automáticamente orden market sell
Y la posición se cierra con pérdida
Y el P&L realizado es -$200.00
Y el close_reason es "stop_loss"
Y se envía notificación "Stop Loss triggered at $93,000"
```

**Escenario 4: Validación de niveles lógicos**
```gherkin
DADO que el usuario tiene posición LONG
CUANDO intenta configurar TP=$90,000 (menor al precio actual)
ENTONCES se muestra warning "TP should be above current price for LONG"
Y permite continuar (puede ser trailing stop futuro)

CUANDO intenta configurar SL=$105,000 (mayor al precio actual)
ENTONCES se muestra warning "SL should be below current price for LONG"
```

**Escenario 5: Modificar TP/SL existentes**
```gherkin
DADO que la posición tiene TP=$100,000 y SL=$93,000
CUANDO el usuario modifica TP a $105,000
Y guarda los cambios
ENTONCES el sistema actualiza solo el TP
Y mantiene el SL en $93,000
Y las líneas en el chart se actualizan
```

**Escenario 6: Deshabilitar TP o SL**
```gherkin
DADO que la posición tiene TP y SL configurados
CUANDO el usuario deshabilita el checkbox de TP
Y guarda
ENTONCES el TP se elimina
Y solo queda activo el SL
Y la línea verde desaparece del chart
```

**Escenario 7: Mostrar Risk/Reward Ratio**
```gherkin
DADO que el usuario configura TP=$100,000 y SL=$93,000
CUANDO el sistema calcula
ENTONCES muestra Risk/Reward = 2.50
  - Potencial ganancia: $500 (riesgo hacia arriba)
  - Potencial pérdida: $200 (riesgo hacia abajo)
  - Ratio: 500 / 200 = 2.50
Y muestra indicador "Good" si ratio > 2.0
```

## Criterios Adicionales

- [ ] Botones rápidos para configurar TP/SL en %
- [ ] Trailing Stop Loss (futuro enhancement)
- [ ] Notificación cuando el precio se acerca a TP/SL (±1%)
- [ ] Mostrar distancia a TP/SL en tiempo real
- [ ] Histórico de TP/SL activados

---

## Tareas Técnicas

**Database:**
- [ ] DB-TRD-019: Añadir campos take_profit, stop_loss a paper_positions
- [ ] DB-TRD-020: Añadir índice en (take_profit, stop_loss) para queries

**Backend:**
- [ ] BE-TRD-064: Crear endpoint PATCH /trading/paper/positions/:id/tp-sl
- [ ] BE-TRD-065: Implementar PositionService.updateTPSL()
- [ ] BE-TRD-066: Implementar TPSLMonitorService (background job)
- [ ] BE-TRD-067: Implementar lógica de activación de TP
- [ ] BE-TRD-068: Implementar lógica de activación de SL
- [ ] BE-TRD-069: Integrar con PositionService.closePosition()

**Frontend:**
- [ ] FE-TRD-064: Crear componente ConfigureTPSLDialog.tsx
- [ ] FE-TRD-065: Crear componente TPSLInput.tsx
- [ ] FE-TRD-066: Crear componente RiskRewardIndicator.tsx
- [ ] FE-TRD-067: Añadir líneas de TP/SL en TradingChart
- [ ] FE-TRD-068: Implementar hook useConfigureTPSL
- [ ] FE-TRD-069: Actualizar PositionRow con indicadores de TP/SL

**Tests:**
- [ ] TEST-TRD-031: Test unitario cálculo risk/reward
- [ ] TEST-TRD-032: Test integración activación TP/SL
- [ ] TEST-TRD-033: Test E2E flujo completo TP/SL

---

## Dependencias

**Depende de:**
- [ ] US-TRD-009: Ver posiciones - Estado: Pendiente
- [ ] US-TRD-008: Cerrar posición - Estado: Pendiente

**Bloquea:**
- Ninguna

---

## Notas Técnicas

**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| PATCH | /trading/paper/positions/:id/tp-sl | Configurar/actualizar TP/SL |
| DELETE | /trading/paper/positions/:id/tp-sl | Eliminar TP/SL |

**Entidades/Tablas:**
```sql
ALTER TABLE trading.paper_positions
ADD COLUMN take_profit DECIMAL(20, 8),
ADD COLUMN stop_loss DECIMAL(20, 8);

CREATE INDEX idx_positions_tp_sl
ON trading.paper_positions(take_profit, stop_loss)
WHERE take_profit IS NOT NULL OR stop_loss IS NOT NULL;
```

**Componentes UI:**
- `ConfigureTPSLDialog`: Modal de configuración
- `TPSLInput`: Input con validación
- `RiskRewardIndicator`: Indicador de ratio
- `TPSLLines`: Líneas horizontales en chart
- `QuickPercentButtons`: Botones de % rápidos

**Request Body:**
```typescript
{
  takeProfit: 100000.00,  // null para deshabilitar
  stopLoss: 93000.00      // null para deshabilitar
}
```

**Response:**
```typescript
{
  position: {
    id: "uuid",
    symbol: "BTCUSDT",
    side: "long",
    quantity: 0.1,
    entryPrice: 95000.00,
    currentPrice: 97234.50,
    takeProfit: 100000.00,
    stopLoss: 93000.00,
    riskRewardRatio: 2.50
  },
  preview: {
    distanceToTP: 2.84,
    distanceToSL: -4.35,
    potentialProfit: 500.00,
    potentialLoss: -200.00,
    riskRewardRatio: 2.50
  }
}
```

**TP/SL Monitor Logic (Background Job - cada segundo):**
```typescript
// Para posición LONG
const positions = await getPositionsWithTPSL();

for (const position of positions) {
  const currentPrice = await getCurrentPrice(position.symbol);

  // Check Take Profit
  if (position.takeProfit && currentPrice >= position.takeProfit) {
    await closePosition(position.id, 'take_profit');
    await sendNotification(`TP triggered at ${currentPrice}`);
  }

  // Check Stop Loss
  if (position.stopLoss && currentPrice <= position.stopLoss) {
    await closePosition(position.id, 'stop_loss');
    await sendNotification(`SL triggered at ${currentPrice}`);
  }
}

// Para posición SHORT (lógica inversa)
// TP se activa cuando currentPrice <= takeProfit
// SL se activa cuando currentPrice >= stopLoss
```

**Cálculos:**
```typescript
// Risk/Reward Ratio
const potentialProfit = Math.abs(takeProfit - entryPrice) * quantity;
const potentialLoss = Math.abs(entryPrice - stopLoss) * quantity;
const riskRewardRatio = potentialProfit / potentialLoss;

// Distance to TP/SL (%)
const distanceToTP = ((takeProfit - currentPrice) / currentPrice) * 100;
const distanceToSL = ((stopLoss - currentPrice) / currentPrice) * 100;

// Validaciones para LONG
const validTPForLong = takeProfit > currentPrice;
const validSLForLong = stopLoss < currentPrice;

// Validaciones para SHORT
const validTPForShort = takeProfit < currentPrice;
const validSLForShort = stopLoss > currentPrice;
```

**Quick Percentage Buttons:**
```typescript
// Para posición LONG, TP
const tp1Percent = currentPrice * 1.01;  // +1%
const tp2Percent = currentPrice * 1.02;  // +2%
const tp5Percent = currentPrice * 1.05;  // +5%
const tp10Percent = currentPrice * 1.10; // +10%

// Para posición LONG, SL
const sl1Percent = currentPrice * 0.99;  // -1%
const sl2Percent = currentPrice * 0.98;  // -2%
const sl5Percent = currentPrice * 0.95;  // -5%
const sl10Percent = currentPrice * 0.90; // -10%
```

---

## 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
