# VS-06: Stress Testing — Vertical Slice Specification **Domain:** Risk & Portfolio Management **Capability:** Run scenario analysis (bull/bear/rate-shock/vol-spike); measure portfolio impact **User Goal:** "I need to understand how my portfolio performs under stressed market conditions" --- ## Non-Goals - Reverse stress testing (maximum loss scenario) - Monte Carlo simulations (future) - Correlation structure changes (simplified model) - Tail risk modeling (future) --- ## Requirements ### Functional | Req ID | Description | RBAC | SLA | Evidence | |--------|-------------|------|-----|----------| | **STRESS-001** | POST /api/portfolio/{id}/stress | RiskAnalyst | 202 Accepted | Job queued + scenarioId | | **STRESS-002** | Define 4 scenarios: Bull/Bear/RateShock/VolSpike | System | N/A | Hardcoded scenario library | | **STRESS-003** | Calculate portfolio loss under each scenario | System | <30s | Batch processing | | **STRESS-004** | Return scenario results with worst-case loss | System | <200ms (GET) | Sorted by impact | | **STRESS-005** | Support custom scenario definition | RiskAnalyst | N/A | User-provided shocks | ### Non-Functional - **Accuracy:** Scenario shocks calibrated to historical crises (2008, 2020) - **Latency:** Batch calculations <30s, GET response <200ms - **Audit:** Full scenario audit trail (inputs → outputs) - **Reproducibility:** Same scenario + portfolio = deterministic results --- ## State Transitions ``` Portfolio (Current) + Risk Metrics (from VS-05) ↓ POST /stress (trigger scenario) Stress Test Job (Queued via Hangfire) ↓ execution Apply scenario shocks to prices → calculate new VAR/Sharpe ↓ results Portfolio Stress Test Results (stored) ↓ event PortfolioStressTestCompleted event published ↓ inbox consumer Risk dashboard updated, alerts evaluated ``` **Frequency:** On-demand + daily overnight (pre-market analysis) **Idempotency:** Same `{portfolio_id, scenario_id, run_date, correlation_id}` → no re-run --- ## Scenario Library | Scenario | Shock Applied | Use Case | |----------|---------------|----------| | **Bull** | +15% equity, -50 bps bond yields | Upside capture | | **Bear** | -20% equity, +150 bps bond yields | Downside protection | | **Rate Shock** | +200 bps rates (duration impact) | Rising rate risk | | **Vol Spike** | +5x implied volatility | Derivatives exposure | **Custom Scenarios:** User provides `{shock_type, magnitude, asset_class}` --- ## Data & API Contracts ### POST /api/portfolio/{portfolioId}/stress **Request:** ```json { "scenarioId": "bear", "parameters": { "equityShock": -0.20, "bondYieldShock": 0.015, "volatilityMultiplier": 1.5 } } ``` **Response (202 Accepted):** ```json { "stressTestId": "550e8400-e29b-41d4-a716-446655440006", "portfolioId": "550e8400-e29b-41d4-a716-446655440001", "scenarioId": "bear", "status": "Queued", "correlationId": "stress-2026-08-05-001", "queuedAt": "2026-08-05T10:00:00Z" } ``` ### GET /api/portfolio/{portfolioId}/stress/{scenarioId} **Response (200 OK):** ```json { "stressTestId": "550e8400-e29b-41d4-a716-446655440006", "portfolioId": "550e8400-e29b-41d4-a716-446655440001", "scenarioId": "bear", "runDate": "2026-08-05", "results": { "baselineVAR95": 15250.00, "stressedVAR95": 42800.00, "varChange": { "amount": 27550.00, "percent": 180.7 }, "baslinePortfolioValue": 292500.00, "stressedPortfolioValue": 234000.00, "portfolioLoss": { "amount": 58500.00, "percent": -20.0 }, "exposureByAssetClass": [ { "assetClass": "Equities", "baselineValue": 150000.00, "stressedValue": 120000.00, "loss": -30000.00 }, { "assetClass": "Bonds", "baselineValue": 142500.00, "stressedValue": 114000.00, "loss": -28500.00 } ], "worstPosition": { "symbol": "AAPL", "loss": -15000.00 } }, "completedAt": "2026-08-05T10:05:00Z" } ``` ### Events **PortfolioStressTestCompleted:** ```json { "eventId": "550e8400-e29b-41d4-a716-446655440007", "eventType": "PortfolioStressTestCompleted", "portfolioId": "550e8400-e29b-41d4-a716-446655440001", "scenarioId": "bear", "stressedVAR95": 42800.00, "portfolioLossPercent": -20.0, "completedAt": "2026-08-05T10:05:00Z", "correlationId": "stress-2026-08-05-001" } ``` --- ## RBAC & Authorization | Operation | Role | Condition | |-----------|------|-----------| | VIEW results | DataReader | Own portfolio only | | TRIGGER test | RiskAnalyst | Own portfolio + standard scenarios | | DEFINE scenario | RiskHead | Organization-wide scenarios | --- ## Testing Strategy 1. **Unit:** Scenario application (10 tests) - Apply equity shock to prices - Calculate new VAR under stressed prices - Measure portfolio loss 2. **Integration:** DB persistence (3 tests) - Insert stress test result - Query by scenario_id - Event published to outbox 3. **E2E:** API flow (2 tests) - POST /stress queues job - GET /stress returns results 4. **Golden:** Scenario accuracy (3 tests) - Known portfolio + known scenario = expected loss - Worst-case position identified - VAR increase reasonable --- ## Assumptions - Scenarios are applied uniformly (no correlation changes) - Bond prices use simple duration approximation (not full curve) - Derivatives marked to market under new assumptions - Scenario shocks are immediate (no gradual transition) --- ## Vertical Slice Boundary ✅ **In Scope:** Scenario definition + price shock application + loss calculation + event publishing ❌ **Out of Scope:** Reverse stress testing (inverse scenario), correlation structure modeling **Rationale:** Supports risk monitoring; results feed dashboard (VS-08) and alerts (VS-07)