# 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<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:**
```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<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)
