trading-platform/docs/02-definicion-modulos/OQI-004-investment-accounts/requerimientos/RF-INV-004-retiros.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
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>
2026-01-07 05:33:35 -06:00

327 lines
10 KiB
Markdown

---
id: "RF-INV-004"
title: "Sistema de Retiros"
type: "Requirement"
status: "Done"
priority: "Alta"
epic: "OQI-004"
project: "trading-platform"
version: "1.0.0"
created_date: "2025-12-05"
updated_date: "2026-01-04"
---
# RF-INV-004: Sistema de Retiros
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | RF-INV-004 |
| **Épica** | OQI-004 - Cuentas de Inversión |
| **Tipo** | Requerimiento Funcional |
| **Prioridad** | P0 |
| **Story Points** | 10 |
| **Estado** | Aprobado |
| **Última actualización** | 2025-12-05 |
---
## Descripción
El sistema debe permitir a los usuarios retirar fondos de sus cuentas de inversión hacia su wallet interno o directamente a su cuenta bancaria/tarjeta, con validaciones de seguridad y procesamiento seguro.
---
## Destinos de Retiro
### 1. Wallet Interno
| Característica | Valor |
|----------------|-------|
| Mínimo | $10 USD |
| Máximo | Balance disponible |
| Comisión | Sin comisión |
| Tiempo procesamiento | Instantáneo |
| Disponibilidad | Inmediata para re-inversión o retiro externo |
### 2. Stripe (Payout a banco/tarjeta)
| Característica | Valor |
|----------------|-------|
| Mínimo | $50 USD |
| Máximo | $25,000 USD |
| Comisión | 0.25% (mín $0.25) |
| Tiempo procesamiento | 2-5 días hábiles |
| Requisito | Cuenta bancaria o tarjeta débito verificada |
---
## Balance Disponible vs Total
```
┌─────────────────────────────────────────────────────────────┐
│ BALANCE DE CUENTA │
├─────────────────────────────────────────────────────────────┤
│ │
│ Balance Total = Balance Disponible + Balance Bloqueado │
│ │
│ ┌──────────────────┐ ┌────────────────────────────┐ │
│ │ DISPONIBLE │ │ BLOQUEADO │ │
│ │ │ │ │ │
│ │ • Para retiro │ │ • Margin usado en trades │ │
│ │ • Para trading │ │ • Retiros pendientes │ │
│ │ │ │ • Reservas de seguridad │ │
│ └──────────────────┘ └────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
### Cálculo de Balance Disponible
```typescript
availableBalance = totalBalance
- unrealizedPnl // P&L no realizado de posiciones abiertas
- marginUsed // Margen usado en posiciones abiertas
- pendingWithdrawals // Retiros en proceso
- reserveAmount // Reserva mínima (5% del balance)
```
---
## Flujo de Retiro
### Diagrama de Flujo
```
┌─────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Request │────▶│ Validate │────▶│ Security │────▶│ Process │
│ Withdraw│ │ Amount │ │ Check │ │ Withdraw │
└─────────┘ └──────────┘ └──────────┘ └────┬─────┘
┌──────────────────────────────────┘
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Confirm │────▶│ Transfer │────▶│ Notify │
│ Email │ │ Funds │ │ User │
└──────────┘ └──────────┘ └──────────┘
```
### Estados de Retiro
| Estado | Descripción |
|--------|-------------|
| `pending_confirmation` | Esperando confirmación por email |
| `pending` | Confirmado, esperando procesamiento |
| `processing` | En proceso de transferencia |
| `completed` | Fondos transferidos |
| `failed` | Error en procesamiento |
| `cancelled` | Cancelado por usuario |
---
## Funcionalidades Requeridas
### RF-INV-004.1: Solicitar Retiro
El usuario debe poder:
- Ver balance disponible para retiro
- Seleccionar destino (wallet o payout)
- Ingresar monto a retirar
- Ver resumen con comisiones
- Confirmar solicitud
### RF-INV-004.2: Verificación de Seguridad
Para retiros, el sistema debe validar:
- Confirmación por email (link válido por 1 hora)
- 2FA si está habilitado
- Límites diarios no excedidos
- Cuenta no en proceso de cierre
### RF-INV-004.3: Retiro a Wallet
```typescript
interface WalletWithdrawalRequest {
accountId: string; // Cuenta de inversión origen
amount: number; // Monto en USD
}
interface WalletWithdrawalResponse {
withdrawalId: string;
status: 'completed';
amount: number;
fee: 0;
newAccountBalance: number;
newWalletBalance: number;
}
```
### RF-INV-004.4: Retiro Externo (Stripe Payout)
```typescript
interface ExternalWithdrawalRequest {
accountId: string;
amount: number;
payoutMethodId: string; // Stripe connected account o método guardado
}
interface ExternalWithdrawalResponse {
withdrawalId: string;
status: 'pending';
amount: number;
fee: number;
netAmount: number;
estimatedArrival: Date; // 2-5 días hábiles
}
```
### RF-INV-004.5: Límites y Validaciones
| Validación | Límite | Mensaje de Error |
|------------|--------|------------------|
| Mínimo wallet | $10 | "El monto mínimo para retiro a wallet es $10" |
| Mínimo externo | $50 | "El monto mínimo para retiro externo es $50" |
| Máximo diario | $25,000 | "Has alcanzado el límite diario de retiros" |
| Balance insuficiente | - | "Balance disponible insuficiente" |
| Posiciones abiertas | - | "Debes cerrar posiciones antes de retirar todo" |
---
## Modelo de Datos
### Entidad: WithdrawalTransaction
```typescript
interface WithdrawalTransaction {
id: string; // UUID
accountId: string; // FK a investment_accounts
userId: string; // FK a users
destination: 'wallet' | 'bank' | 'card';
status: WithdrawalStatus;
// Montos
amount: number; // Monto solicitado
fee: number; // Comisión
netAmount: number; // Monto a recibir
currency: 'USD';
// Stripe specific
stripePayoutId?: string;
stripeTransferId?: string;
// Wallet specific
walletTransactionId?: string;
// Seguridad
confirmationToken?: string;
confirmedAt?: Date;
confirmationIp?: string;
// Metadata
ipAddress: string;
userAgent: string;
// Timestamps
createdAt: Date;
processedAt?: Date;
completedAt?: Date;
failedAt?: Date;
cancelledAt?: Date;
// Error handling
failureReason?: string;
}
```
---
## Reglas de Negocio
1. **RN-030**: Los retiros requieren confirmación por email
2. **RN-031**: No se puede retirar más del balance disponible
3. **RN-032**: Retiro total requiere cerrar posiciones abiertas primero
4. **RN-033**: Límite diario de $25,000 USD en retiros
5. **RN-034**: Retiros a wallet son instantáneos
6. **RN-035**: Retiros externos tienen período de espera de 2-5 días
7. **RN-036**: Los retiros pueden cancelarse antes de ser procesados
8. **RN-037**: Cooldown de 24 horas para retiro después de agregar nuevo método de pago
---
## Criterios de Aceptación
```gherkin
Escenario: Retiro a wallet exitoso
DADO que el usuario tiene $1,000 disponibles en su cuenta Atlas
CUANDO solicita retirar $500 a su wallet
Y confirma por email
ENTONCES el balance de la cuenta disminuye en $500
Y el balance del wallet aumenta en $500
Y no se cobra comisión
Y recibe confirmación instantánea
Escenario: Retiro externo exitoso
DADO que el usuario tiene cuenta bancaria verificada
Y tiene $5,000 disponibles en su cuenta
CUANDO solicita retirar $1,000 a su banco
Y confirma por email
ENTONCES el retiro queda en estado "processing"
Y se muestra fecha estimada de llegada
Y recibe email cuando los fondos se envíen
Escenario: Retiro supera límite diario
DADO que el usuario ya retiró $20,000 hoy
CUANDO intenta retirar $10,000 adicionales
ENTONCES recibe error "Has alcanzado el límite diario de retiros"
Y se muestra cuándo se reinicia el límite
Escenario: Retiro con posiciones abiertas
DADO que el usuario tiene $1,000 disponibles
Y tiene $200 en margen usado por posiciones abiertas
CUANDO intenta retirar $900
ENTONCES recibe error "Balance disponible insuficiente"
Y ve que su balance disponible es $800
Y tiene opción de ver posiciones abiertas
```
---
## API Endpoints
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| GET | /investment/withdrawals/available | Ver balance disponible |
| POST | /investment/withdrawals/wallet | Retirar a wallet |
| POST | /investment/withdrawals/payout | Retirar externo |
| GET | /investment/withdrawals | Listar retiros |
| GET | /investment/withdrawals/:id | Detalle de retiro |
| POST | /investment/withdrawals/:id/confirm | Confirmar retiro |
| DELETE | /investment/withdrawals/:id | Cancelar retiro |
---
## Notificaciones
| Evento | Canal | Contenido |
|--------|-------|-----------|
| Retiro solicitado | Email | Link de confirmación |
| Retiro confirmado | Email + Push | Confirmación y ETA |
| Retiro procesado | Email + Push | Fondos en camino |
| Retiro completado | Email | Fondos recibidos |
| Retiro fallido | Email + Push | Razón + pasos a seguir |
---
## Referencias
- [US-INV-008: Retirar fondos](../historias-usuario/US-INV-008-retirar-fondos.md)
- [ET-INV-003: Stripe Integration](../especificaciones/ET-INV-003-stripe.md)
- [RF-PAY-003: Wallet](../../OQI-005-payments-stripe/requerimientos/RF-PAY-003-wallet.md)
---
**Autor:** Requirements-Analyst
**Fecha:** 2025-12-05