# ET-PFM-008: Especificación Frontend - Módulo Portfolio Manager **Módulo:** OQI-008 Portfolio Manager **Documento:** ET-PFM-008 **Estado:** A IMPLEMENTAR **Versión:** 1.0.0 **Fecha de Creación:** 2026-01-25 **Última Actualización:** 2026-01-25 --- ## 📋 Resumen Ejecutivo Este documento especifica la arquitectura, estructura de componentes y flujos de interfaz de usuario para el módulo Portfolio Manager en la plataforma de trading. **Este es un diseño a implementar que no cuenta actualmente con código base.** El módulo proporciona funcionalidades de visualización, análisis y gestión de portafolios de inversión, incluyendo posiciones, métricas de riesgo, pruebas de estrés y generación de reportes. --- ## 🎯 Objetivos del Frontend 1. Proporcionar visualización clara y en tiempo real del estado del portafolio 2. Facilitar análisis de riesgo mediante métricas consolidadas 3. Permitir simulaciones de rebalanceo de posiciones 4. Generar reportes analíticos exportables 5. Integrar datos de múltiples fuentes de mercado --- ## 📄 Páginas Propuestas ### 1. PortfolioPage **Ruta:** `/portfolio` **Descripción:** Página principal de gestión del portafolio **Responsabilidades:** - Mostrar resumen ejecutivo del portafolio - Listar posiciones activas - Mostrar indicadores clave de desempeño (KPIs) - Permitir filtrado y búsqueda de posiciones - Facilitar acceso a rebalanceo **Estructura:** ``` PortfolioPage ├── PortfolioSummaryCard ├── PerformanceChart ├── PositionsTable │ ├── Filtros │ └── Paginación └── Acciones (Rebalancear, Exportar) ``` **Datos Requeridos:** - Valor total del portafolio - Rentabilidad YTD - Rentabilidad acumulada - Composición por activo - Posiciones individuales con métricas --- ### 2. StressTestPage **Ruta:** `/portfolio/stress-tests` **Descripción:** Página para ejecución y análisis de pruebas de estrés **Responsabilidades:** - Crear nuevas pruebas de estrés - Ejecutar escenarios predefinidos - Visualizar resultados de stress tests - Comparar múltiples escenarios - Exportar análisis de sensibilidad **Estructura:** ``` StressTestPage ├── ScenarioSelector ├── SimulationControls ├── RiskMetricsPanel ├── ResultsVisualization │ ├── ImpactChart │ └── SensitivityTable └── ExportOptions ``` **Datos Requeridos:** - Escenarios disponibles - Parámetros de simulación - Resultados de ejecución - Metricas de sensibilidad --- ### 3. ReportsPage **Ruta:** `/portfolio/reports` **Descripción:** Página de generación y consulta de reportes analíticos **Responsabilidades:** - Listar reportes generados - Crear nuevos reportes personalizados - Visualizar reportes en tiempo real - Descargar reportes en múltiples formatos - Programar generación automática de reportes **Estructura:** ``` ReportsPage ├── ReportsList │ └── ReportFilters ├── ReportGenerator │ ├── ParameterSelector │ └── FormatSelector ├── ReportViewer │ ├── PaginationControls │ └── ExportOptions └── ScheduleManager ``` **Datos Requeridos:** - Lista de reportes disponibles - Historico de reportes generados - Parámetros configurables - Formato de salida (PDF, Excel, CSV) --- ## 🧩 Componentes Propuestos ### 1. PortfolioSummaryCard **Tipo:** Componente Presentacional **Ubicación:** `src/components/portfolio/PortfolioSummaryCard.vue` **Props:** ```typescript interface PortfolioSummaryProps { totalValue: number; ytdReturn: number; cumulativeReturn: number; currency: string; lastUpdated: Date; isLoading?: boolean; } ``` **Funcionalidades:** - Mostrar valor total del portafolio - Indicadores de rentabilidad (YTD, acumulada) - Tendencia visual (arriba/abajo) - Moneda de referencia - Timestamp de actualización - Estado de carga **Emits:** - `refresh`: Solicitar actualización de datos --- ### 2. PositionsTable **Tipo:** Componente Presentacional **Ubicación:** `src/components/portfolio/PositionsTable.vue` **Props:** ```typescript interface PositionsTableProps { positions: Position[]; loading?: boolean; sortBy?: string; sortOrder?: 'asc' | 'desc'; pageSize?: number; currentPage?: number; } interface Position { id: string; symbol: string; name: string; quantity: number; entryPrice: number; currentPrice: number; currentValue: number; percentageChange: number; percentageOfPortfolio: number; sector?: string; lastUpdated: Date; } ``` **Funcionalidades:** - Visualización de tabla de posiciones - Ordenamiento por columnas - Paginación configurable - Filtrado por sector/tipo - Búsqueda por símbolo o nombre - Indicadores visuales de desempeño - Acciones por fila (detalles, vender, rebalancear) **Emits:** - `sort`: Cambio de ordenamiento - `page-change`: Cambio de página - `position-selected`: Selección de posición - `position-action`: Acción sobre posición --- ### 3. PerformanceChart **Tipo:** Componente Presentacional **Ubicación:** `src/components/portfolio/PerformanceChart.vue` **Props:** ```typescript interface PerformanceChartProps { data: PerformanceData[]; timeframe?: 'D' | 'W' | 'M' | 'Y' | 'ALL'; currency?: string; showComparison?: boolean; isLoading?: boolean; } interface PerformanceData { date: Date; value: number; return: number; benchmark?: number; } ``` **Funcionalidades:** - Gráfico de línea del desempeño del portafolio - Múltiples plazos (Día, Semana, Mes, Año, Todo) - Comparación con benchmark - Visualización de retorno absoluto y porcentual - Interactividad con tooltips - Exportación como imagen **Emits:** - `timeframe-change`: Cambio de período - `range-select`: Selección de rango personalizado --- ### 4. RiskMetricsPanel **Tipo:** Componente Presentacional **Ubicación:** `src/components/portfolio/RiskMetricsPanel.vue` **Props:** ```typescript interface RiskMetricsPanelProps { metrics: RiskMetrics; isLoading?: boolean; } interface RiskMetrics { volatility: number; // Volatilidad anualizada sharpeRatio: number; // Ratio de Sharpe sortinoRatio: number; // Ratio de Sortino valueAtRisk: number; // VaR 95% expectedShortfall: number; // CVaR (Expected Shortfall) beta: number; // Beta respecto a benchmark correlation: number; // Correlación con benchmark maxDrawdown: number; // Máxima caída histórica diversificationRatio: number; // Ratio de diversificación } ``` **Funcionalidades:** - Visualización de métricas de riesgo clave - Indicadores de riesgo (bajo/medio/alto) - Comparación con benchmarks - Explicación de métricas (tooltips) - Gráficos de sensibilidad - Histórico de evolución de métricas **Emits:** - `metric-selected`: Selección de métrica para análisis profundo - `learn-more`: Solicitud de explicación de métrica --- ### 5. RebalanceModal **Tipo:** Componente Modal **Ubicación:** `src/components/portfolio/RebalanceModal.vue` **Props:** ```typescript interface RebalanceModalProps { visible: boolean; portfolio: Portfolio; targetAllocation: AllocationTarget[]; currentAllocation: AllocationCurrent[]; constraints?: RebalanceConstraints; } interface AllocationTarget { assetType: string; targetPercentage: number; minPercentage?: number; maxPercentage?: number; } interface RebalanceConstraints { maxTransactionCost?: number; minTradeSize?: number; excludeAssets?: string[]; allowNewPositions?: boolean; } ``` **Funcionalidades:** - Mostrar asignación actual vs. objetivo - Calcular transacciones necesarias - Permitir selección de restricciones - Vista previa de cambios - Estimación de costos de transacción - Confirmación antes de ejecutar - Historial de rebalanceos **Emits:** - `close`: Cierre del modal - `confirm`: Confirmación de rebalanceo - `cancel`: Cancelación de operación - `preview`: Solicitud de vista previa --- ## 🗂️ Estructura de Store ### portfolioStore **Ubicación:** `src/stores/portfolioStore.ts` **Estado:** ```typescript interface PortfolioState { portfolio: Portfolio | null; positions: Position[]; selectedPosition: Position | null; performanceData: PerformanceData[]; riskMetrics: RiskMetrics | null; stressTestResults: StressTestResult[] | null; reports: Report[]; loading: { portfolio: boolean; positions: boolean; riskMetrics: boolean; stressTest: boolean; reports: boolean; }; filters: { sector?: string; minValue?: number; maxValue?: number; searchTerm?: string; }; error: string | null; } interface Portfolio { id: string; name: string; totalValue: number; ytdReturn: number; cumulativeReturn: number; currency: string; positions: Position[]; lastUpdated: Date; } ``` **Acciones Principales:** ```typescript // Portafolio fetchPortfolio(portfolioId: string): Promise updatePortfolio(portfolioId: string, data: Partial): Promise selectPosition(position: Position): void clearSelection(): void // Posiciones fetchPositions(portfolioId: string): Promise updatePosition(positionId: string, data: Partial): Promise deletePosition(positionId: string): Promise addPosition(position: Position): Promise // Desempeño fetchPerformanceData(portfolioId: string, timeframe: string): Promise // Métricas de Riesgo fetchRiskMetrics(portfolioId: string): Promise // Pruebas de Estrés executeStressTest(portfolioId: string, scenario: StressScenario): Promise fetchStressTestResults(portfolioId: string): Promise // Rebalanceo calculateRebalance(portfolioId: string, targets: AllocationTarget[]): Promise executeRebalance(portfolioId: string, plan: RebalancePlan): Promise // Reportes fetchReports(portfolioId: string): Promise generateReport(portfolioId: string, config: ReportConfig): Promise exportReport(reportId: string, format: 'pdf' | 'excel' | 'csv'): Promise // Filtros setFilter(filterName: string, value: any): void clearFilters(): void ``` **Getters:** ```typescript getPortfolioValue(): number getTotalReturn(): number getPositionCount(): number getFilteredPositions(): Position[] getTopPerformer(): Position | null getTopLoser(): Position | null getRiskLevel(): 'low' | 'medium' | 'high' ``` --- ## 🔄 Flujos de Datos ### Flujo 1: Carga Inicial de Portafolio ``` PortfolioPage Montada ↓ [Dispatch] fetchPortfolio() ↓ API Backend (GET /api/portfolio/{id}) ↓ [Commit] setPortfolio() ↓ PortfolioSummaryCard actualizado PositionsTable actualizado ``` ### Flujo 2: Búsqueda y Filtrado ``` Usuario escribe en SearchInput ↓ [Dispatch] setFilter('searchTerm', value) ↓ Computed getFilteredPositions() ↓ PositionsTable re-renderiza ``` ### Flujo 3: Ejecución de Stress Test ``` Usuario selecciona escenario ↓ [Dispatch] executeStressTest(scenario) ↓ API Backend (POST /api/portfolio/stress-test) ↓ [Commit] setStressTestResults() ↓ RiskMetricsPanel actualizado ResultsVisualization mostrada ``` ### Flujo 4: Rebalanceo ``` Usuario abre RebalanceModal ↓ [Dispatch] calculateRebalance(targets) ↓ API Backend (POST /api/portfolio/calculate-rebalance) ↓ Modal muestra vista previa ↓ Usuario confirma ↓ [Dispatch] executeRebalance(plan) ↓ API Backend (POST /api/portfolio/execute-rebalance) ↓ [Dispatch] fetchPortfolio() para refrescar ``` --- ## 🎨 Estilos y Temas ### Principios de Diseño - **Diseño Responsivo:** Compatible con desktop, tablet y mobile - **Accesibilidad:** WCAG 2.1 AA como mínimo - **Consistencia:** Uso de design system corporativo - **Rendimiento:** Carga y animaciones fluidas ### Componentes de UI Requeridos - Cards para resumen de métricas - Tablas con ordenamiento y paginación - Gráficos interactivos (Chart.js o Echarts) - Modals para acciones confirmables - Alerts y notificaciones Toast - Loaders y spinners - Iconografía consistente --- ## 📊 Integraciones Externas ### APIs Backend Requeridas | Endpoint | Método | Descripción | |----------|--------|-------------| | `/api/portfolio/{id}` | GET | Obtener datos del portafolio | | `/api/portfolio/{id}` | PUT | Actualizar portafolio | | `/api/portfolio/{id}/positions` | GET | Listar posiciones | | `/api/portfolio/{id}/positions` | POST | Crear posición | | `/api/portfolio/position/{id}` | PUT | Actualizar posición | | `/api/portfolio/position/{id}` | DELETE | Eliminar posición | | `/api/portfolio/{id}/performance` | GET | Obtener datos de desempeño | | `/api/portfolio/{id}/risk-metrics` | GET | Calcular métricas de riesgo | | `/api/portfolio/stress-test` | POST | Ejecutar prueba de estrés | | `/api/portfolio/{id}/rebalance/calculate` | POST | Calcular plan de rebalanceo | | `/api/portfolio/{id}/rebalance/execute` | POST | Ejecutar rebalanceo | | `/api/portfolio/{id}/reports` | GET | Listar reportes | | `/api/portfolio/report/generate` | POST | Generar reporte | | `/api/portfolio/report/{id}/export` | GET | Exportar reporte | ### Servicios Externos - **Market Data Provider:** Para precios en tiempo real - **Benchmark Data:** Índices de referencia (S&P 500, etc.) - **Reporting Engine:** Generación de reportes complejos --- ## ⚙️ Configuración y Constantes ### Variables de Entorno ```env VITE_PORTFOLIO_API_BASE_URL=http://localhost:3000/api VITE_CHART_LIBRARY=echarts|chart.js VITE_REPORT_FORMAT_DEFAULT=pdf VITE_AUTO_REFRESH_INTERVAL=30000 VITE_MAX_POSITIONS_DISPLAY=50 ``` ### Constantes de Aplicación ```typescript const CURRENCY_SYMBOLS: Record = { USD: '$', EUR: '€', COP: '$', }; const TIMEFRAMES = ['D', 'W', 'M', 'Y', 'ALL'] as const; const RISK_LEVELS = { low: { min: 0, max: 0.08 }, medium: { min: 0.08, max: 0.15 }, high: { min: 0.15, max: Infinity }, }; const STRESS_SCENARIOS = [ { id: 'market-crash', label: 'Caída de Mercado (-10%)', intensity: -0.1 }, { id: 'rate-shock', label: 'Choque de Tasas (+2%)', intensity: 0.02 }, { id: 'geopolitical', label: 'Evento Geopolítico', intensity: -0.05 }, ]; ``` --- ## 📱 Responsive Design ### Breakpoints - **Mobile:** < 640px - **Tablet:** 640px - 1024px - **Desktop:** > 1024px ### Ajustes por Pantalla | Elemento | Mobile | Tablet | Desktop | |----------|--------|--------|---------| | PortfolioSummaryCard | Apilado | 2 columnas | 4 columnas | | PositionsTable | Horizontal scroll | Scroll limitado | Completo | | PerformanceChart | Altura reducida | Altura media | Altura completa | | RiskMetricsPanel | 1 columna | 2 columnas | 3 columnas | --- ## 🔒 Seguridad - **Autenticación:** Bearer token en headers - **Validación Frontend:** Validación de input antes de envío - **HTTPS Obligatorio:** En producción - **CORS:** Configuración restrictiva - **Rate Limiting:** Control de llamadas a API --- ## 📝 Notas de Implementación ### Estado Actual **Este documento describe un diseño que aún no ha sido implementado.** No existe código base en el repositorio para estos componentes. ### Próximos Pasos 1. Crear estructura de directorios de componentes 2. Implementar store de Pinia con acciones básicas 3. Desarrollar componentes en orden de dependencia 4. Integrar con APIs backend 5. Implementar pruebas unitarias 6. Realizar pruebas de integración 7. Optimizar rendimiento ### Consideraciones Técnicas - **Framework:** Vue 3 (Composition API recomendada) - **State Management:** Pinia - **Gráficos:** Echarts o Chart.js según disponibilidad - **Validación:** Vee-validate - **Estilos:** TailwindCSS o SCSS - **Pruebas:** Vitest + Vue Test Utils --- ## 📚 Referencias Relacionadas - OQI-008 Portfolio Manager - Especificación General - ET-PFM-001-backend.md - Especificación Backend - ET-PFM-002-database.md - Especificación Base de Datos - Arquitectura Trading Platform --- ## ✅ Control de Cambios | Versión | Fecha | Autor | Cambios | |---------|-------|-------|---------| | 1.0.0 | 2026-01-25 | Sistema | Especificación inicial | --- **Estado:** A IMPLEMENTAR | **Prioridad:** Alta | **Dependencias:** Backend Portfolio Manager (OQI-008)