# VS-05: Risk Metrics — Vertical Slice Specification

**Domain:** Risk & Portfolio Management  
**Capability:** Calculate VAR, Sharpe, Sortino, concentration metrics; publish to dashboard  
**User Goal:** "I need real-time risk metrics to monitor portfolio health and trigger alerts"

---

## Non-Goals

- Stress testing scenarios (VS-06)
- Risk alerts & notifications (VS-07)
- Factor decomposition (future)
- Machine-learning risk modeling (future)

---

## Requirements

### Functional

| Req ID | Description | RBAC | SLA | Evidence |
|--------|-------------|------|-----|----------|
| **RISK-001** | GET /api/portfolio/{id}/risk | DataReader | <200ms | JSON w/ VAR/Sharpe/Sortino |
| **RISK-002** | Calculate VAR (95% confidence, 1-day horizon) | System | <5s | Daily batch job |
| **RISK-003** | Calculate Sharpe ratio (252-day rolling) | System | <5s | Daily batch job |
| **RISK-004** | Concentration metrics (top-N holdings %) | System | <1s | Cache-friendly calculation |
| **RISK-005** | Publish metrics to outbox for downstream | System | <100ms | PortfolioMetricsCalculated event |

### Non-Functional

- **Accuracy:** VAR model validated against historical data
- **Latency:** Batch calculations <5min, GET response <200ms
- **Caching:** Results cached <1hr (metrics refresh daily)
- **Audit:** All metric changes traced via CorrelationId

---

## State Transitions

```
Portfolio (Current) — from VS-04
  ↓ DailyRiskCalculationJob (9:30 KST, after market open)
Risk Metrics Calculated (VAR, Sharpe, Sortino, concentration)
  ↓ event
PortfolioMetricsCalculated event published to outbox
  ↓ inbox consumer
Risk dashboard updated, alerts evaluated (VS-07)
```

**Frequency:** Daily after market open (9:30 KST)  
**Idempotency:** Same `{portfolio_id, calculation_date, correlation_id}` → no re-run

---

## Data & API Contracts

### GET /api/portfolio/{portfolioId}/risk

**Response (200 OK):**
```json
{
  "portfolioId": "550e8400-e29b-41d4-a716-446655440001",
  "calculationDate": "2026-08-05",
  "metrics": {
    "valueAtRisk95": {
      "amount": 15250.00,
      "percent": 5.2,
      "horizon": "1-day",
      "confidence": 0.95
    },
    "sharpeRatio": {
      "ratio": 1.85,
      "riskFreeRate": 0.045,
      "rollingDays": 252
    },
    "sortinoRatio": {
      "ratio": 2.45,
      "downsideDeviation": 0.082
    },
    "concentration": {
      "topFivePercent": 52.3,
      "hirschman": 0.18,
      "maxSinglePosition": 40.0
    },
    "volatility": {
      "annualized": 0.185,
      "rollingDays": 30
    }
  },
  "lastUpdate": "2026-08-05T09:30:00Z",
  "dataQuality": "Complete"
}
```

### Events

**PortfolioMetricsCalculated:**
```json
{
  "eventId": "550e8400-e29b-41d4-a716-446655440004",
  "eventType": "PortfolioMetricsCalculated",
  "portfolioId": "550e8400-e29b-41d4-a716-446655440001",
  "calculatedAt": "2026-08-05T09:30:00Z",
  "metrics": {
    "var95": 15250.00,
    "sharpe": 1.85,
    "sortino": 2.45,
    "concentration": 52.3
  },
  "correlationId": "risk-2026-08-05-001"
}
```

---

## RBAC & Authorization

| Operation | Role | Condition |
|-----------|------|-----------|
| VIEW metrics | DataReader | Own portfolio only |
| TRIGGER calculation | RiskAnalyst | Manual override (unusual) |
| APPROVE metrics | RiskCommittee | For reporting purposes |

---

## Testing Strategy

1. **Unit:** Metric calculations (15 tests)
   - VAR computation (95% confidence)
   - Sharpe ratio (rolling 252-day)
   - Sortino ratio (downside deviation)
   - Concentration detection

2. **Integration:** DB persistence (4 tests)
   - Insert risk metrics snapshot
   - Historical metric queries
   - Event published to outbox
   - Idempotency check

3. **E2E:** API flow (2 tests)
   - GET /risk returns current metrics
   - Daily job execution completes

4. **Golden:** Metric accuracy (3 tests)
   - Known portfolio → expected VAR/Sharpe
   - High concentration → concentration flag
   - Low volatility → low Sharpe

---

## Assumptions

- Historical price data available (from VS-03)
- Risk-free rate 4.5% (configurable)
- 252 trading days per year
- No intraday rebalancing (EOD snapshot only)
- VAR model: Parametric (assumes normal distribution)

---

## Vertical Slice Boundary

✅ **In Scope:** Metric calculations + API endpoint + daily batch job + event publishing  
❌ **Out of Scope:** Stress testing (VS-06), alerts (VS-07), risk approval workflows

**Rationale:** Metrics feed downstream systems (dashboard, alerts); published asynchronously via events
