trading-platform/docs/02-definicion-modulos/OQI-008-portfolio-manager/especificaciones/ET-PFM-008-frontend.md
Adrian Flores Cortes cdec253b02 [TASK-2026-01-25-FRONTEND-ANALYSIS] docs: Add frontend specifications and user stories
- Add 5 frontend specification documents (ET-*-frontend.md):
  - ET-AUTH-006: Authentication module frontend spec
  - ET-ML-008: ML Signals module frontend spec
  - ET-LLM-007: LLM Agent module frontend spec
  - ET-PFM-008: Portfolio Manager frontend spec (design)
  - ET-MKT-003: Marketplace frontend spec (design)

- Add 8 new user stories:
  - US-AUTH-013: Global logout
  - US-AUTH-014: Device management
  - US-ML-008: Ensemble signal view
  - US-ML-009: ICT analysis view
  - US-ML-010: Multi-symbol scan
  - US-LLM-011: Execute trade from chat
  - US-PFM-013: Rebalance alerts
  - US-PFM-014: PDF report generation

- Update task index with completed analysis

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 01:47:27 -06:00

16 KiB

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:

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:

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:

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:

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:

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:

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:

// Portafolio
fetchPortfolio(portfolioId: string): Promise<Portfolio>
updatePortfolio(portfolioId: string, data: Partial<Portfolio>): Promise<Portfolio>
selectPosition(position: Position): void
clearSelection(): void

// Posiciones
fetchPositions(portfolioId: string): Promise<Position[]>
updatePosition(positionId: string, data: Partial<Position>): Promise<Position>
deletePosition(positionId: string): Promise<void>
addPosition(position: Position): Promise<Position>

// Desempeño
fetchPerformanceData(portfolioId: string, timeframe: string): Promise<PerformanceData[]>

// Métricas de Riesgo
fetchRiskMetrics(portfolioId: string): Promise<RiskMetrics>

// Pruebas de Estrés
executeStressTest(portfolioId: string, scenario: StressScenario): Promise<StressTestResult>
fetchStressTestResults(portfolioId: string): Promise<StressTestResult[]>

// Rebalanceo
calculateRebalance(portfolioId: string, targets: AllocationTarget[]): Promise<RebalancePlan>
executeRebalance(portfolioId: string, plan: RebalancePlan): Promise<RebalanceResult>

// Reportes
fetchReports(portfolioId: string): Promise<Report[]>
generateReport(portfolioId: string, config: ReportConfig): Promise<Report>
exportReport(reportId: string, format: 'pdf' | 'excel' | 'csv'): Promise<Blob>

// Filtros
setFilter(filterName: string, value: any): void
clearFilters(): void

Getters:

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

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

const CURRENCY_SYMBOLS: Record<string, string> = {
  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)