--- id: "ET-PFM-004" title: "Motor de Rebalanceo" type: "Technical Specification" status: "Done" priority: "Alta" epic: "OQI-008" project: "trading-platform" version: "1.0.0" created_date: "2025-12-05" updated_date: "2026-01-04" --- # ET-PFM-004: Motor de Rebalanceo **Épica:** OQI-008 - Portfolio Manager **Versión:** 1.0 **Fecha:** 2025-12-05 **Estado:** Planificado --- ## Arquitectura ``` ┌─────────────────────────────────────────────────────────────┐ │ REBALANCING ENGINE │ ├─────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Allocation │ │ Deviation │ │ Plan │ │ │ │ Manager │──▶│ Calculator │──▶│ Generator │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────┐ │ │ │ Order │ │ │ │ Executor │ │ │ └──────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Algoritmo de Rebalanceo ```typescript @Injectable() export class RebalanceService { async generatePlan( portfolioId: string, targetAllocation: Allocation[] ): Promise { const positions = await this.portfolioService.getPositions(portfolioId); const totalValue = this.calculateTotalValue(positions); const orders: RebalanceOrder[] = []; // Calcular diferencias for (const target of targetAllocation) { const current = positions.find(p => p.symbol === target.symbol); const currentValue = current?.marketValue || 0; const targetValue = totalValue * (target.percent / 100); const difference = targetValue - currentValue; if (Math.abs(difference) > 100) { // Min $100 para operar orders.push({ symbol: target.symbol, action: difference > 0 ? 'BUY' : 'SELL', amount: Math.abs(difference), currentAllocation: (currentValue / totalValue) * 100, targetAllocation: target.percent, }); } } // Ordenar: ventas primero orders.sort((a, b) => { if (a.action === 'SELL' && b.action === 'BUY') return -1; if (a.action === 'BUY' && b.action === 'SELL') return 1; return b.amount - a.amount; }); return { portfolioId, orders, estimatedCost: this.estimateCosts(orders), timestamp: new Date().toISOString(), }; } async executePlan(planId: string): Promise { const plan = await this.getPlan(planId); const results = []; for (const order of plan.orders) { const result = await this.orderService.createOrder({ symbol: order.symbol, side: order.action.toLowerCase(), amount: order.amount, type: 'market', }); results.push(result); } return { planId, executed: results.filter(r => r.success).length, failed: results.filter(r => !r.success).length, results, }; } } ``` --- ## Referencias - [RF-PFM-003: Rebalanceo](../requerimientos/RF-PFM-003-rebalanceo.md) --- *Especificación técnica - Sistema NEXUS*