# Crisis Resilience Scoring

**Shipped**: 2026-05-17

## Overview

Crisis Resilience Scoring provides quantitative analysis of how stocks perform during market crises. The system computes scores based on historical crisis performance (2008, 2020, 2022), market beta, downside capture ratios, and VIX correlation to identify defensive and "fortress" stocks.

## Architecture

### Database Schema (`db/migrations/243_stock_resilience_scores.sql`)

**Tables:**

1. `predict.stock_resilience_scores` — Per-symbol resilience metrics
   - Composite score (0-100)
   - Tier classification (fortress/defensive/moderate/aggressive/speculative)
   - Grade (A+ to F)
   - Sub-scores: volatility, drawdown, crisis, income, correlation
   - Core metrics: beta, upside/downside capture, VIX correlation, dividend yield

2. `predict.resilience_watchlists` — User watchlists for defensive screening

3. `predict.crisis_periods` — Historical crisis data (10 crises seeded)
   - 2008 Financial Crisis, COVID-19 2020, 2022 Bear Market
   - 2011 Debt Ceiling, 2015 China Devaluation, 2018 Q4 Correction
   - Flash Crash 2010, Euro Crisis 2011, Taper Tantrum 2013, Brexit 2016

4. `predict.resilience_sync_status` — Job tracking

### Module Structure (`packages/be/src/resilience/`)

| File | Purpose |
|------|---------|
| `types.ts` | TypeScript interfaces for scores, responses, DSL data |
| `repository.ts` | Database CRUD operations |
| `service.ts` | Score computation, refresh, sync functions |
| `dsl-wrappers.ts` | DSL primitive implementations with 6-hour cache |
| `index.ts` | Module exports |

### Score Computation

**5 Sub-Scores (Weighted Composite):**

| Sub-Score | Weight | Calculation |
|-----------|--------|-------------|
| Volatility | 15% | Based on annualized volatility vs SPY |
| Drawdown | 25% | Max drawdown severity and duration |
| Crisis Performance | 30% | Average return during historical crises |
| Income Stability | 15% | Dividend yield and consistency |
| Correlation | 15% | VIX correlation (positive = hedge) |

**Tier Assignment:**

| Tier | Score Range | Description |
|------|-------------|-------------|
| Fortress | 90-100 | Elite defensive stocks that thrive in crises |
| Defensive | 75-89 | Strong downside protection |
| Moderate | 50-74 | Balanced risk/reward |
| Aggressive | 25-49 | Higher volatility, growth-focused |
| Speculative | 0-24 | Maximum risk |

## DSL Primitives

10 primitives available for algorithmic trading strategies:

| Primitive | Returns | Description |
|-----------|---------|-------------|
| `resilience_score(symbol)` | number | Composite score 0-100 |
| `resilience_tier(symbol)` | string | fortress/defensive/moderate/aggressive/speculative |
| `is_defensive_stock(symbol)` | boolean | True if score >= 75 |
| `is_fortress_stock(symbol)` | boolean | True if score >= 90 |
| `crisis_beta(symbol)` | number | Market beta (< 1 = less volatile) |
| `downside_capture(symbol)` | number | Downside capture ratio (< 1 = defensive) |
| `avg_crisis_return(symbol)` | number | Average return during crises (decimal) |
| `is_crisis_outperformer(symbol)` | boolean | True if crisis return > -10% |
| `vix_correlation(symbol)` | number | Correlation to VIX (-1 to +1) |
| `is_crisis_hedge(symbol)` | boolean | True if VIX correlation >= 0.3 |

**Example DSL Usage:**

```
// Buy defensive stocks when VIX spikes
entry when vix() > 25 and is_defensive_stock('JNJ') and resilience_score('JNJ') > 80

// Exit speculative positions during crisis
exit when resilience_tier(symbol) == 'speculative' and vix() > 30

// Portfolio allocation based on crisis protection
size = resilience_score(symbol) / 100 * base_position
```

## API Endpoints

### Public Endpoints

| Method | Path | Description |
|--------|------|-------------|
| GET | `/api/predict/v1/resilience/scores` | List scores with filtering |
| GET | `/api/predict/v1/resilience/stats` | Aggregate statistics |
| GET | `/api/predict/v1/resilience/crisis-periods` | Historical crisis data |
| GET | `/api/predict/v1/resilience/defensive` | Defensive stocks (score >= 75) |
| GET | `/api/predict/v1/resilience/fortress` | Fortress stocks (score >= 90) |
| GET | `/api/predict/v1/resilience/[symbol]` | Symbol detail |

### Admin Endpoints

| Method | Path | Description |
|--------|------|-------------|
| POST | `/api/predict/v1/resilience/[symbol]` | Refresh single symbol |
| GET | `/api/predict/v1/admin/resilience/sync` | Get sync status |
| POST | `/api/predict/v1/admin/resilience/sync` | Trigger full sync |

## Scheduler Job

**`sync-resilience-scores`** — Weekly job
- Computes scores for tracked symbols + core defensive stocks
- ~50 core symbols (indices, defensive stocks, utilities, consumer staples, REITs)
- Rate-limited to avoid overwhelming price APIs (200ms delay between symbols)

## Integration Points

### Tick Context (`algorithms/paper/tick-context.ts`)

Resilience data is prefetched per tick for the primary symbol:
- Scores cached for 6 hours (data updates weekly)
- Sync access during tick evaluation

### Executor (`algorithms/paper/executor.ts`)

All 10 primitives bound to EvalContext:
- Symbol matching validates against primary symbol
- Fallback defaults for missing data (score=50, tier='moderate', beta=1)

## Use Cases

1. **Defensive Portfolio Construction**: Filter for fortress/defensive stocks
2. **Crisis Hedging**: Identify stocks with positive VIX correlation
3. **Risk Management**: Reduce position size for high-beta stocks
4. **Market Regime Adaptation**: Shift to defensive holdings when VIX elevates
5. **Dividend Stability**: Screen for consistent income generators

## Cost & Performance

- **Price Data**: Yahoo Finance (free) for historical prices
- **Computation**: ~200ms per symbol (rate-limited)
- **Storage**: ~1KB per symbol
- **Cache**: 6-hour TTL on DSL primitives
- **Sync Frequency**: Weekly scheduler job

## Example Defensive Stocks

**Fortress Tier (score >= 90):**
- Consumer staples: PG, JNJ, KO, PEP
- Utilities: NEE, DUK, SO
- Healthcare: UNH, JNJ
- Low-vol ETFs: USMV, SPLV

**Crisis Hedges (positive VIX correlation):**
- GLD, IAU (gold)
- TLT, IEF (bonds)
- VXX, VIXY (volatility)
