Portfolio Risk Management
Institutional-Grade Risk Control | Protect Your Capital
Learning Objectives
After this module, you will:
- Calculate and interpret Value at Risk (VaR) using multiple methods
- Implement stress testing and scenario analysis
- Design position sizing frameworks for options portfolios
- Manage Greeks across multi-position portfolios
- Identify and mitigate concentration and correlation risks
- Build risk monitoring dashboards
- Apply capital allocation strategies
- Measure risk-adjusted performance properly
- Learn from catastrophic risk failures
Prerequisites:
- The Greeks - Portfolio Greeks critical
- Delta Hedging - Risk management basics
- Volatility Trading - Vol portfolio risks
- Monte Carlo Simulation - Risk modeling
Time to Master: 10-15 hours | Difficulty: Expert
Why Risk Management Matters
The Harsh Reality
Trading Without Risk Management:
Month 1-11: +5%, +7%, +3%, +8%, +6%, +4%, +9%, +5%, +7%, +6%, +8%
Cumulative: +88% (Amazing!)
Month 12: -95% (One bad trade)
Final Result: -60% (Account devastated)
Trading With Risk Management:
Month 1-11: +4%, +5%, +2%, +6%, +4%, +3%, +7%, +4%, +5%, +4%, +6%
Cumulative: +59% (Good, not amazing)
Month 12: -8% (Controlled risk, stopped out)
Final Result: +46% (Survived and profitable)
The Difference: Risk management keeps you in the game
The Iron Law of Risk Management
“Rule #1: Don’t lose money. Rule #2: Never forget Rule #1.” - Warren Buffett
For Options Traders:
- You WILL be wrong
- You WILL face tail events
- Survival > Performance
- Compound gains require surviving losses
- One blow-up erases years of gains
The Goal: Maximize risk-adjusted returns, not absolute returns
Value at Risk (VaR)
What Is VaR?
Definition: Maximum expected loss over a time horizon at a given confidence level
English Translation: “I’m 95% confident I won’t lose more than $10,000 tomorrow”
Components:
- Confidence Level: 95%, 99% (how sure?)
- Time Horizon: 1 day, 10 days, 1 month
- Loss Amount: Dollar value
Method 1: Parametric VaR
Assumption: Returns are normally distributed
Formula:
VaR = Portfolio Value × σ × Z
Where:
- σ = Portfolio standard deviation (daily)
- Z = Z-score for confidence level
- 95% confidence: Z = 1.65
- 99% confidence: Z = 2.33
Example:
Portfolio: $100,000
Daily volatility: 3%
Confidence: 95%
VaR(95%, 1-day) = $100,000 × 3% × 1.65
= $4,950
Interpretation: 95% confident we won't lose more than $4,950 tomorrow
Or: Expect to lose more than $4,950 once every 20 days
Python Implementation:
import numpy as np
from scipy import stats
def parametric_var(portfolio_value, daily_volatility, confidence=0.95, horizon=1):
"""
Calculate parametric VaR
"""
z_score = stats.norm.ppf(1 - confidence) # Negative for losses
var = portfolio_value * daily_volatility * abs(z_score) * np.sqrt(horizon)
return var
# Usage
port_value = 100000
daily_vol = 0.03 # 3%
var_95 = parametric_var(port_value, daily_vol, 0.95, 1)
var_99 = parametric_var(port_value, daily_vol, 0.99, 1)
print(f"1-Day VaR (95%): ${var_95:,.0f}")
print(f"1-Day VaR (99%): ${var_99:,.0f}")
# Output:
# 1-Day VaR (95%): $4,950
# 1-Day VaR (99%): $6,990
Limitations:
- Assumes normal distribution (crypto/options are NOT normal!)
- Underestimates tail risk
- Ignores skewness and kurtosis
- Dangerous for options (non-linear payoffs)
Method 2: Historical VaR
Concept: Use actual historical returns
Steps:
- Collect historical portfolio returns (e.g., 250 days)
- Sort from worst to best
- Find the loss at the desired percentile
Example:
Historical returns (250 days sorted):
Day 1 (worst): -8.2%
Day 2: -6.5%
Day 3: -5.8%
...
Day 13: -2.1% ← 5th percentile (95% VaR)
...
Day 250 (best): +9.1%
For $100,000 portfolio:
VaR(95%) = $100,000 × 2.1% = $2,100
Interpretation: In the past year, 95% of days had losses smaller than $2,100
Python Implementation:
import numpy as np
import pandas as pd
def historical_var(returns, portfolio_value, confidence=0.95):
"""
Calculate historical VaR from returns series
"""
# Sort returns (worst to best)
sorted_returns = np.sort(returns)
# Find percentile
index = int((1 - confidence) * len(sorted_returns))
var_return = abs(sorted_returns[index])
var = portfolio_value * var_return
return var
# Usage
# Assume daily_returns is a pandas Series of historical returns
daily_returns = pd.Series([...]) # Your historical data
var_95_hist = historical_var(daily_returns, 100000, 0.95)
var_99_hist = historical_var(daily_returns, 100000, 0.99)
print(f"Historical VaR (95%): ${var_95_hist:,.0f}")
print(f"Historical VaR (99%): ${var_99_hist:,.0f}")
Advantages:
- No distribution assumptions
- Captures actual tail behavior
- Simple to understand
Limitations:
- Assumes future like past (rarely true)
- Limited by sample size
- Doesn’t capture unprecedented events
Method 3: Monte Carlo VaR
Concept: Simulate thousands of possible futures
Steps:
- Model asset price process (GBM, etc.)
- Generate 10,000 scenarios for tomorrow
- Calculate portfolio value in each scenario
- Sort outcomes, find 5th percentile
Example:
Simulate 10,000 possible tomorrows:
- Scenario 1: BTC +5%, ETH +3% → Portfolio +$4,200
- Scenario 2: BTC -2%, ETH +1% → Portfolio -$800
- ...
- Scenario 500 (5th percentile): Portfolio -$6,300 ← VaR(95%)
- ...
- Scenario 10,000: BTC +8%, ETH +7% → Portfolio +$7,500
VaR(95%) = $6,300
Python Implementation:
import numpy as np
def monte_carlo_var(portfolio_positions, n_simulations=10000, confidence=0.95):
"""
Monte Carlo VaR for multi-asset portfolio
portfolio_positions = {
'BTC': {'quantity': 2, 'price': 50000, 'volatility': 0.80},
'ETH': {'quantity': 10, 'price': 3000, 'volatility': 0.85}
}
"""
# Calculate initial portfolio value
initial_value = sum(p['quantity'] * p['price'] for p in portfolio_positions.values())
# Simulate scenarios
portfolio_values = []
for _ in range(n_simulations):
simulated_value = 0
for asset, position in portfolio_positions.items():
# Generate random return
daily_vol = position['volatility'] / np.sqrt(365)
random_return = np.random.normal(0, daily_vol)
# Calculate new price
new_price = position['price'] * (1 + random_return)
simulated_value += position['quantity'] * new_price
portfolio_values.append(simulated_value)
# Calculate VaR
portfolio_values = np.array(portfolio_values)
losses = initial_value - portfolio_values
var = np.percentile(losses, confidence * 100)
return var, portfolio_values
# Usage
positions = {
'BTC': {'quantity': 2, 'price': 50000, 'volatility': 0.80},
'ETH': {'quantity': 10, 'price': 3000, 'volatility': 0.85}
}
var_mc, simulated_values = monte_carlo_var(positions, 10000, 0.95)
print(f"Monte Carlo VaR (95%): ${var_mc:,.0f}")
# Analyze distribution
print(f"Expected Portfolio Value: ${np.mean(simulated_values):,.0f}")
print(f"Worst 1% outcome: ${np.percentile(simulated_values, 1):,.0f}")
Advantages:
- Handles complex portfolios (options, multi-asset)
- Captures non-linear payoffs
- Can model correlations
- Most flexible method
Limitations:
- Computationally intensive
- Model assumptions matter (garbage in, garbage out)
- Requires good volatility/correlation estimates
Conditional VaR (CVaR) / Expected Shortfall
Problem with VaR: Doesn’t tell you HOW BAD it gets beyond VaR
CVaR: Average loss in the worst X% of cases
Example:
VaR(95%) = $5,000 (5% of days exceed this)
But what's the average loss on those bad days?
CVaR(95%) = Average of worst 5% losses
= ($8,000 + $7,500 + $12,000 + ...) / N
= $9,200
Interpretation: When things go bad (5% of the time), expect to lose $9,200 on average
Why CVaR is Better:
- Captures tail risk severity
- More conservative
- Preferred by regulators
- Actually measures “how bad is bad”
Python Implementation:
def cvar(returns, portfolio_value, confidence=0.95):
"""
Calculate CVaR (Expected Shortfall)
"""
sorted_returns = np.sort(returns)
cutoff_index = int((1 - confidence) * len(sorted_returns))
# Average of worst cases
worst_returns = sorted_returns[:cutoff_index]
cvar_return = abs(np.mean(worst_returns))
cvar = portfolio_value * cvar_return
return cvar
# Usage
cvar_95 = cvar(daily_returns, 100000, 0.95)
print(f"CVaR (95%): ${cvar_95:,.0f}")
Stress Testing
What Is Stress Testing?
Definition: “What if the worst happens?”
vs VaR:
- VaR: “What’s normal bad?”
- Stress Test: “What’s catastrophic?”
Historical Scenario Analysis
Replay Historical Crises:
Scenario 1: COVID Crash (Feb-Mar 2020)
- BTC: -50% in 2 weeks
- Vol spike: 60% → 150%
- Correlations → 1.0
Apply to current portfolio:
- Long 2 BTC at $50k
- Short 5 BTC puts at $45k
Result:
BTC drops to $25k:
- Long BTC: -$50,000
- Short puts: -$100,000 (deep ITM)
- Total loss: -$150,000
Stress test reveals: Position is massively exposed to crash
Key Historical Scenarios:
- 2020 COVID Crash: -35% in 3 weeks, vol explosion
- 2021 Crypto Crash: -50% from peak
- 2018 Crypto Winter: -80% over 12 months
- 2008 Financial Crisis: Liquidity freeze
- Flash Crash: -10% in minutes, instant recovery
Custom Scenario Design
Build Your Own Nightmare Scenarios:
Scenario Design Template:
Scenario Name: "Bitcoin Regulation Ban"
Probability: Low (5% chance)
Impact: Catastrophic
Parameters:
- BTC: -60% overnight
- Volatility: +200%
- Liquidity: Dries up (can't exit)
- Correlations: ETH follows (0.95 correlation)
Portfolio Impact: [Calculate]
Python Implementation:
def stress_test_portfolio(portfolio, scenarios):
"""
Apply stress scenarios to portfolio
scenarios = {
'COVID Crash': {'BTC': -0.50, 'ETH': -0.45, 'vol_spike': 2.5},
'Flash Crash': {'BTC': -0.15, 'ETH': -0.18, 'vol_spike': 1.8},
'Regulation Ban': {'BTC': -0.60, 'ETH': -0.55, 'vol_spike': 3.0}
}
"""
initial_value = calculate_portfolio_value(portfolio)
results = {}
for scenario_name, shocks in scenarios.items():
# Apply shocks to portfolio
stressed_portfolio = apply_shocks(portfolio, shocks)
stressed_value = calculate_portfolio_value(stressed_portfolio)
loss = initial_value - stressed_value
loss_pct = (loss / initial_value) * 100
results[scenario_name] = {
'loss': loss,
'loss_pct': loss_pct,
'surviving': loss < initial_value * 0.5 # Can survive 50% loss
}
return results
# Usage
portfolio = {
'BTC_long': {'quantity': 2, 'price': 50000},
'BTC_put_short': {'quantity': -5, 'strike': 45000, 'price': 2000}
}
scenarios = {
'COVID Crash': {'BTC': -0.50, 'vol_spike': 2.5},
'Flash Crash': {'BTC': -0.15, 'vol_spike': 1.8},
}
stress_results = stress_test_portfolio(portfolio, scenarios)
for scenario, result in stress_results.items():
print(f"{scenario}:")
print(f" Loss: ${result['loss']:,.0f} ({result['loss_pct']:.1f}%)")
print(f" Survivable: {result['surviving']}")
Reverse Stress Testing
Concept: “What would it take to blow me up?”
Process:
- Define unacceptable loss (e.g., -80% of capital)
- Work backwards to find scenarios that cause it
- Assess probability of those scenarios
- Adjust position if probability too high
Example:
Portfolio: $100,000
Unacceptable Loss: -$80,000 (80%)
Positions:
- Long 2 BTC at $50k
- Short 10 ATM straddles
Reverse engineer:
What price movement causes -$80k loss?
Analysis:
- If BTC stays flat: Straddles expire worthless (+$20k profit) ✓
- If BTC moves 20%: Straddles lose $60k, BTC gains $20k = -$40k ✗
- If BTC moves 40%: Straddles lose $150k, BTC gains $40k = -$110k ✗✗
Conclusion: Any move >25% causes unacceptable loss
Recent history: BTC moves >25% about 4x per year
Action: Position is too risky, reduce short straddles!
Position Sizing Frameworks
Fixed Fractional Position Sizing
Concept: Risk fixed % of capital per trade
Formula:
Position Size = (Account Size × Risk %) / Risk per Unit
Example:
Account: $100,000
Risk per trade: 2%
Risk per unit: $1,000 (stop loss)
Position Size = ($100,000 × 2%) / $1,000
= $2,000 / $1,000
= 2 units
For Options:
Example: Buying straddles
Account: $100,000
Risk per trade: 5% = $5,000
Straddle cost: $3,000 (max risk)
Position Size = $5,000 / $3,000 = 1.67 straddles
Round down to 1 straddle
Kelly Criterion
Concept: Optimal position size for maximum long-term growth
Formula:
Kelly % = (Win Rate × Avg Win - Loss Rate × Avg Loss) / Avg Win
Example:
Win Rate: 40%
Avg Win: $2,000
Loss Rate: 60%
Avg Loss: $800
Kelly % = (0.40 × $2,000 - 0.60 × $800) / $2,000
= ($800 - $480) / $2,000
= 0.16 or 16%
Size next trade at 16% of capital
Practical Adjustment: Use Half-Kelly or Quarter-Kelly
Full Kelly: 16% (very aggressive)
Half Kelly: 8% (reasonable)
Quarter Kelly: 4% (conservative)
Python Implementation:
def kelly_criterion(win_rate, avg_win, avg_loss):
"""
Calculate Kelly optimal position size
"""
loss_rate = 1 - win_rate
kelly = (win_rate * avg_win - loss_rate * avg_loss) / avg_win
# Also calculate fractional Kelly
half_kelly = kelly * 0.5
quarter_kelly = kelly * 0.25
return {
'full_kelly': kelly,
'half_kelly': half_kelly,
'quarter_kelly': quarter_kelly
}
# Usage
kelly = kelly_criterion(win_rate=0.40, avg_win=2000, avg_loss=800)
print(f"Full Kelly: {kelly['full_kelly']:.1%}")
print(f"Half Kelly: {kelly['half_kelly']:.1%}")
print(f"Quarter Kelly: {kelly['quarter_kelly']:.1%}")
# Output:
# Full Kelly: 16.0%
# Half Kelly: 8.0%
# Quarter Kelly: 4.0%
Warning: Kelly assumes you know win rate and avg win/loss accurately. Overestimating leads to ruin!
Risk Parity Position Sizing
Concept: Size positions so each contributes equal risk
Formula:
Position Weight = 1 / Volatility
Example:
Asset A: 20% vol → Weight = 1/20 = 0.05 (5%)
Asset B: 40% vol → Weight = 1/40 = 0.025 (2.5%)
Asset C: 60% vol → Weight = 1/60 = 0.017 (1.7%)
Normalize to 100%:
Total = 0.05 + 0.025 + 0.017 = 0.092
Asset A: 54.3% of portfolio
Asset B: 27.2%
Asset C: 18.5%
Result: Each asset contributes ~equal risk despite different volatilities
Python Implementation:
def risk_parity_weights(assets_volatility):
"""
Calculate risk parity weights
assets_volatility = {
'BTC': 0.80, # 80% annual vol
'ETH': 0.90,
'Stocks': 0.20
}
"""
# Inverse volatility weights
inv_vol = {asset: 1/vol for asset, vol in assets_volatility.items()}
# Normalize to 100%
total_inv_vol = sum(inv_vol.values())
weights = {asset: inv/total_inv_vol for asset, inv in inv_vol.items()}
return weights
# Usage
vols = {'BTC': 0.80, 'ETH': 0.90, 'Stocks': 0.20}
weights = risk_parity_weights(vols)
for asset, weight in weights.items():
print(f"{asset}: {weight:.1%}")
# Output:
# BTC: 28.6%
# ETH: 25.4%
# Stocks: 46.0%
Greeks-Based Portfolio Risk
Portfolio Greeks Aggregation
Concept: Sum Greeks across all positions
Example Portfolio:
Position 1: Long 10 BTC calls ($50k strike)
- Delta: +400
- Gamma: +50
- Theta: -$500
- Vega: +$8,000
Position 2: Short 5 BTC puts ($45k strike)
- Delta: +250
- Gamma: -30
- Theta: +$300
- Vega: -$5,000
Position 3: Long 2 BTC (spot)
- Delta: +200
- Gamma: 0
- Theta: 0
- Vega: 0
Portfolio Totals:
- Net Delta: +850 (bullish)
- Net Gamma: +20 (slightly long vol)
- Net Theta: -$200 (bleeding daily)
- Net Vega: +$3,000 (long vol)
Interpretation:
- Directionally bullish (net delta +850)
- Slightly long volatility (gamma +20, vega +$3k)
- Small theta bleed (-$200/day)
- Needs BTC to rise or vol to increase
Greeks Risk Limits
Set Portfolio Limits:
Delta Limits: -500 to +500 (nearly market-neutral)
Gamma Limits:
- Long vol: 0 to +100
- Short vol: -100 to 0
Theta Limits: -$1,000 to +$1,000 per day
Vega Limits: -$10,000 to +$10,000 per vol point
Monitoring:
def check_greeks_limits(portfolio_greeks, limits):
"""
Check if portfolio Greeks exceed limits
"""
violations = []
for greek, value in portfolio_greeks.items():
if greek in limits:
min_limit, max_limit = limits[greek]
if value < min_limit or value > max_limit:
violations.append({
'greek': greek,
'value': value,
'limit': (min_limit, max_limit),
'breach_amount': max(0, value - max_limit, min_limit - value)
})
return violations
# Usage
portfolio_greeks = {
'delta': 850, # Exceeds limit!
'gamma': 20,
'theta': -200,
'vega': 3000
}
limits = {
'delta': (-500, 500),
'gamma': (-100, 100),
'theta': (-1000, 1000),
'vega': (-10000, 10000)
}
violations = check_greeks_limits(portfolio_greeks, limits)
if violations:
print("Greek violations detected:")
for v in violations:
print(f" {v['greek']}: {v['value']} (limit: {v['limit']})")
print(f" Breach: {v['breach_amount']}")
Delta-Gamma-Vega Hedging
Multi-Dimensional Hedging:
Scenario: Portfolio with complex Greeks
Current Greeks:
- Delta: +300 (too bullish)
- Gamma: +80 (want to keep)
- Vega: +$5,000 (want to keep)
Goal: Neutralize delta, keep gamma/vega
Solution: Use underlying (delta-only instrument)
Hedge: Short 300 delta of underlying
After hedge:
- Delta: 0 ✓
- Gamma: +80 ✓ (unchanged, underlying has no gamma)
- Vega: +$5,000 ✓ (unchanged)
Result: Pure volatility exposure, no directional risk
Correlation and Concentration Risk
Correlation Risk
Problem: Assets move together, less diversification than expected
Example:
Portfolio:
- 50% Bitcoin
- 50% Ethereum
Expected: 50% diversification benefit
Reality: BTC-ETH correlation = 0.85 (move together!)
Actual diversification: Much less than 50%
Measuring Correlation Risk:
import numpy as np
def portfolio_correlation_risk(positions, correlation_matrix):
"""
Calculate portfolio variance accounting for correlations
positions = {'BTC': 0.5, 'ETH': 0.5} # Weights
correlation_matrix = [[1.0, 0.85], [0.85, 1.0]]
volatilities = [0.80, 0.90]
"""
weights = np.array(list(positions.values()))
vols = np.array([0.80, 0.90]) # BTC, ETH vols
# Covariance matrix
cov_matrix = correlation_matrix * np.outer(vols, vols)
# Portfolio variance
portfolio_var = np.dot(weights, np.dot(cov_matrix, weights))
portfolio_vol = np.sqrt(portfolio_var)
return portfolio_vol
# Usage
positions = {'BTC': 0.5, 'ETH': 0.5}
corr_matrix = np.array([[1.0, 0.85], [0.85, 1.0]])
portfolio_vol = portfolio_correlation_risk(positions, corr_matrix)
print(f"Portfolio Volatility: {portfolio_vol:.1%}")
# Compare to average:
avg_vol = (0.80 + 0.90) / 2
print(f"Average Vol (no correlation): {avg_vol:.1%}")
print(f"Diversification benefit: {(avg_vol - portfolio_vol)/avg_vol:.1%}")
Concentration Risk
Problem: Too much in one position
Herfindahl Index (Concentration Measure):
HHI = Σ (weight_i)²
Example 1: Diversified
- 10 positions, each 10%
- HHI = 10 × (0.10)² = 0.10 (low concentration)
Example 2: Concentrated
- 1 position 60%, 4 positions 10%
- HHI = (0.60)² + 4×(0.10)² = 0.36 + 0.04 = 0.40 (high!)
Threshold: HHI > 0.25 = Too concentrated
Risk Limits:
Single Position Limits:
- Max 20% in any single asset
- Max 30% in any single strategy
- Max 40% in any single asset class
Monitoring:
- Daily concentration checks
- Rebalance if limits breached
- Force diversification
Liquidity Risk
What Is Liquidity Risk?
Definition: Risk you can’t exit when needed
Manifestations:
- Bid-ask spreads widen: Lose 5-10% on execution
- No buyers: Can’t sell at any price
- Slippage: Moving the market against yourself
Measuring Liquidity
Metrics:
- Bid-Ask Spread:
Bid: $49,500
Ask: $50,500
Spread: $1,000 (2%)
Cost to round-trip: 2% (ouch!)
- Volume:
Daily volume: $10M
Your position: $2M (20% of volume)
Risk: Liquidating would move market significantly
- Market Depth:
Order Book:
$50,000: 5 BTC available
$49,500: 3 BTC
$49,000: 2 BTC
$48,500: 1 BTC
To sell 10 BTC, average price: ~$49,300 (1.4% slippage)
Liquidity-Adjusted VaR
Concept: Account for liquidity constraints in VaR
Formula:
Liquidity-Adjusted VaR = VaR + Liquidity Cost
Liquidity Cost = Position Size × (Spread/2 + Slippage %)
Example:
VaR (95%): $5,000
Position: $100,000
Spread: 2%
Slippage: 1%
Liquidity Cost = $100,000 × (2%/2 + 1%) = $2,000
Liquidity-Adjusted VaR = $5,000 + $2,000 = $7,000
Lesson: Illiquid positions have higher effective risk
Risk-Adjusted Performance
Sharpe Ratio
Formula:
Sharpe = (Return - Risk-Free Rate) / Volatility
Example:
Annual Return: 25%
Risk-Free Rate: 3%
Volatility: 30%
Sharpe = (25% - 3%) / 30% = 0.73
Interpretation:
- Sharpe < 0.5: Poor
- Sharpe 0.5-1.0: Okay
- Sharpe 1.0-2.0: Good
- Sharpe > 2.0: Excellent
Sortino Ratio
Improvement on Sharpe: Only penalize downside volatility
Formula:
Sortino = (Return - Risk-Free Rate) / Downside Deviation
Downside Deviation = Std Dev of negative returns only
Example:
Annual Return: 25%
Risk-Free Rate: 3%
Downside Deviation: 18% (vs 30% total vol)
Sortino = (25% - 3%) / 18% = 1.22 (better than Sharpe!)
Why Better: Upside volatility is good! Don’t penalize it.
Calmar Ratio
Focus on Max Drawdown:
Formula:
Calmar = Annual Return / Max Drawdown
Example:
Annual Return: 40%
Max Drawdown: -25%
Calmar = 40% / 25% = 1.6
Interpretation:
- Calmar < 1.0: Return doesn't justify risk
- Calmar 1.0-3.0: Reasonable
- Calmar > 3.0: Excellent risk-adjusted returns
Python Risk Metrics Suite
import numpy as np
import pandas as pd
class RiskMetrics:
def __init__(self, returns, risk_free_rate=0.03):
self.returns = returns
self.rf = risk_free_rate
def sharpe_ratio(self):
excess_return = np.mean(self.returns) - self.rf / 252
volatility = np.std(self.returns)
return (excess_return * 252) / (volatility * np.sqrt(252))
def sortino_ratio(self):
excess_return = np.mean(self.returns) - self.rf / 252
downside_returns = self.returns[self.returns < 0]
downside_std = np.std(downside_returns)
return (excess_return * 252) / (downside_std * np.sqrt(252))
def max_drawdown(self):
cumulative = (1 + self.returns).cumprod()
running_max = cumulative.expanding().max()
drawdown = (cumulative - running_max) / running_max
return drawdown.min()
def calmar_ratio(self):
annual_return = np.mean(self.returns) * 252
max_dd = abs(self.max_drawdown())
return annual_return / max_dd
def generate_report(self):
return {
'Sharpe Ratio': self.sharpe_ratio(),
'Sortino Ratio': self.sortino_ratio(),
'Max Drawdown': self.max_drawdown(),
'Calmar Ratio': self.calmar_ratio(),
'Annual Return': np.mean(self.returns) * 252,
'Annual Volatility': np.std(self.returns) * np.sqrt(252)
}
# Usage
daily_returns = pd.Series([...]) # Your returns
metrics = RiskMetrics(daily_returns)
report = metrics.generate_report()
for metric, value in report.items():
print(f"{metric}: {value:.2f}")
Real-World Risk Failures
Case Study 1: Long-Term Capital Management (LTCM, 1998)
Background:
- Nobel Prize-winning team
- Sophisticated arbitrage strategies
- $1.25B capital, $125B balance sheet (100x leverage!)
The Strategy:
- Convergence trades (bond spreads)
- High Sharpe ratio (2.0+)
- Worked for years
What Went Wrong:
Russian Default (Aug 1998):
- Bonds crashed globally
- Spreads widened (opposite of expected)
- Liquidity disappeared
- Forced liquidations accelerated losses
Timeline:
Week 1: -$500M
Week 2: -$1.5B
Week 3: -$3B
Fed intervenes to prevent systemic collapse
Lessons:
- Leverage kills: 100x leverage = no room for error
- Liquidity risk: Can’t exit when everyone exits
- Tail risk: “6-sigma event” (but they happen!)
- Model risk: Assumed correlations → 1.0 in crisis
- Overconfidence: “Our models are perfect”
For Us:
- Never use extreme leverage
- Stress test for liquidity crises
- Assume correlations go to 1.0 in crashes
- Stay humble
Case Study 2: Archegos Capital (2021)
Background:
- Family office (less regulated)
- Equity swaps (synthetic leverage)
- ~5-6x leverage hidden via swaps
The Positions:
Concentrated bets on:
- ViacomCBS
- Discovery
- Chinese tech stocks
Total exposure: ~$100B on $10B capital (10x leverage!)
What Went Wrong:
ViacomCBS announces stock offering (dilutive)
↓
Stock drops 10%
↓
Margin call from broker
↓
Can't meet margin (overleveraged)
↓
Forced liquidation (massive size)
↓
Stock drops another 40%
↓
Other positions cascade
↓
Total loss: $20B in 2 days
Lessons:
- Concentration risk: Too much in few stocks
- Leverage risk: 10x leverage = instant death
- Correlation risk: All positions fell together
- Liquidity risk: Couldn’t exit without destroying prices
- Transparency: Swaps hid true exposure
For Us:
- Diversify (max 20% per position)
- Limit leverage (2-3x max)
- Maintain liquidity buffers
- Track total exposure honestly
Case Study 3: Amaranth Advisors (2006)
Background:
- Natural gas trader
- Exploited seasonal spreads
- Made billions in 2005
The Trade:
Strategy: Calendar spreads in nat gas futures
- Long winter delivery
- Short summer delivery
- Bet on seasonal spread widening
Position size: $9B exposure on $4B capital
Leverage: ~2x (reasonable!)
What Went Wrong:
September 2006:
- Mild hurricane season (less supply disruption)
- Spread collapsed (opposite of expected)
- Massive positions couldn't be exited
- Week 1: -$1B
- Week 2: -$3B
- Week 3: -$6B
- Total: Lost $6B in 2 weeks (fund collapsed)
Lessons:
- Liquidity: Big positions can’t exit in small markets
- Concentration: 90% of capital in one strategy
- Timing: Seasonal trades require patience
- Market depth: Position size exceeded market capacity
- No diversification: All eggs in one basket
For Us:
- Check market depth vs position size
- Diversify strategies
- Never put >50% in one trade
- Maintain exit plans
Building a Risk Dashboard
Daily Risk Report Template
=== DAILY RISK REPORT ===
Date: 2024-03-15
Portfolio Value: $487,200
POSITION SUMMARY:
- Long BTC: 5 units @ $50,000
- Short BTC Puts: 10 contracts @ $45k strike
- Long ETH: 20 units @ $3,000
GREEKS:
- Net Delta: +720 (BULLISH - Above limit!)
- Net Gamma: -45 (Short vol)
- Net Theta: +$450/day
- Net Vega: -$12,000 per vol point (SHORT VOL)
RISK METRICS:
- VaR (95%, 1-day): $18,400 (3.8% of portfolio)
- CVaR (95%): $29,200 (6.0%)
- Max Drawdown (30d): -12.3%
- Current Drawdown: -3.2%
STRESS TESTS:
- COVID Crash (-50%): -$198,000 (-41%) ⚠️
- Flash Crash (-15%): -$42,000 (-9%) ✓
- Regulation Ban (-60%): -$285,000 (-58%) ⚠️⚠️
CONCENTRATION:
- BTC exposure: 68% (OVER LIMIT!) ⚠️
- ETH exposure: 32%
- HHI: 0.57 (HIGH CONCENTRATION) ⚠️
VIOLATIONS:
1. Net delta exceeds limit (+720 vs +500 max)
2. BTC concentration exceeds 60% limit
3. Stress test losses exceed 50% in 2 scenarios
RECOMMENDED ACTIONS:
1. Sell 200 delta of BTC to neutralize
2. Add uncorrelated positions (reduce HHI)
3. Buy OTM puts for tail protection
Automated Risk Monitoring
class RiskMonitor:
def __init__(self, portfolio, limits):
self.portfolio = portfolio
self.limits = limits
self.alerts = []
def check_all_risks(self):
"""Run all risk checks"""
self.check_greeks()
self.check_concentration()
self.check_var()
self.run_stress_tests()
return self.generate_report()
def check_greeks(self):
"""Check Greeks against limits"""
greeks = self.portfolio.calculate_greeks()
for greek, value in greeks.items():
if greek in self.limits['greeks']:
min_val, max_val = self.limits['greeks'][greek]
if value < min_val or value > max_val:
self.alerts.append({
'type': 'GREEK_VIOLATION',
'severity': 'HIGH',
'greek': greek,
'value': value,
'limit': (min_val, max_val)
})
def check_concentration(self):
"""Check position concentration"""
weights = self.portfolio.get_weights()
hhi = sum(w**2 for w in weights.values())
if hhi > self.limits['max_hhi']:
self.alerts.append({
'type': 'CONCENTRATION',
'severity': 'MEDIUM',
'hhi': hhi,
'limit': self.limits['max_hhi']
})
def check_var(self):
"""Check VaR against limits"""
var = self.portfolio.calculate_var()
var_pct = var / self.portfolio.value
if var_pct > self.limits['max_var_pct']:
self.alerts.append({
'type': 'VAR_BREACH',
'severity': 'HIGH',
'var': var,
'var_pct': var_pct
})
def run_stress_tests(self):
"""Run stress scenarios"""
scenarios = self.limits['stress_scenarios']
results = self.portfolio.stress_test(scenarios)
for scenario, loss in results.items():
if loss > self.limits['max_stress_loss']:
self.alerts.append({
'type': 'STRESS_TEST_FAIL',
'severity': 'CRITICAL',
'scenario': scenario,
'loss': loss
})
def generate_report(self):
"""Generate formatted report"""
report = {
'timestamp': datetime.now(),
'portfolio_value': self.portfolio.value,
'alerts': self.alerts,
'risk_metrics': self.portfolio.calculate_all_metrics()
}
return report
# Usage
limits = {
'greeks': {'delta': (-500, 500), 'gamma': (-100, 100)},
'max_hhi': 0.30,
'max_var_pct': 0.05,
'max_stress_loss': 50000
}
monitor = RiskMonitor(portfolio, limits)
daily_report = monitor.check_all_risks()
if daily_report['alerts']:
print("⚠️ RISK ALERTS:")
for alert in daily_report['alerts']:
print(f" [{alert['severity']}] {alert['type']}: {alert}")
Practice Exercises
Exercise 1: VaR Calculation
Scenario: Your portfolio is worth $250,000 with daily volatility of 4%.
Questions:
- Calculate 95% VaR (1-day)
- Calculate 99% VaR (1-day)
- Calculate 95% VaR (10-day)
- Interpret each result
Solution
1. VaR (95%, 1-day):
VaR = Portfolio × σ × Z
= $250,000 × 4% × 1.65
= $16,500
Interpretation: 95% confident we won't lose more than $16,500 tomorrow2. VaR (99%, 1-day):
VaR = $250,000 × 4% × 2.33
= $23,300
Interpretation: 99% confident we won't lose more than $23,300 tomorrow
(But 1% of the time—about 2.5 trading days/year—we'll lose more)3. VaR (95%, 10-day):
VaR = $250,000 × 4% × 1.65 × √10
= $16,500 × 3.16
= $52,140
Interpretation: Over a 2-week period, 95% confident loss won't exceed $52,1404. Key Insights:
- VaR scales with √time (10-day VaR ≠ 10× 1-day VaR)
- Higher confidence = higher VaR
- These are parametric VaR (assume normal distribution—crypto is NOT normal!)
- Real tail risk likely higher than calculated
Exercise 2: Position Sizing
Scenario:
- Account size: $100,000
- Risk tolerance: 3% per trade
- You want to buy ATM straddles on Bitcoin
- Each straddle costs $5,000
Questions:
- How many straddles should you buy?
- What if you use 2x leverage?
- What’s your max loss?
Solution
1. Position Size (No Leverage):
Risk per trade = $100,000 × 3% = $3,000
Max risk per straddle = $5,000 (paid premium)
Position size = $3,000 / $5,000 = 0.6 straddles
Round down to 0 straddles
Alternative: Increase risk tolerance to 5%
$5,000 / $5,000 = 1 straddle ✓2. With 2x Leverage:
Effective capital = $100,000 × 2 = $200,000
Risk per trade = $200,000 × 3% = $6,000
Position size = $6,000 / $5,000 = 1.2 straddles
Round to 1 straddle
But remember: Leverage amplifies losses!3. Max Loss:
Without leverage: $5,000 (premium paid)
With leverage: $5,000 + interest costs
Since long options have defined risk (premium), max loss is known
This is why long options are safer than short options for leverageExercise 3: Stress Test Analysis
Scenario: Portfolio:
- Long 3 BTC at $50,000 = $150,000
- Short 5 BTC puts ($45k strike) collected $2,000 each = $10,000 credit
Questions:
- What’s your max profit potential?
- Calculate P&L if BTC drops to $40,000
- At what price do you lose 50% of initial capital?
- Should you hedge?
Solution
1. Max Profit:
Unlimited upside from long BTC
Best case for puts: Expire worthless (keep $10k credit)
Max profit: Unlimited (as BTC rises)
Collected income: $10,0002. BTC at $40,000 P&L:
Long BTC: 3 × ($40k - $50k) = -$30,000
Short puts: 5 × ($45k - $40k) = -$25,000 (in-the-money)
Less premium: +$10,000
Total P&L = -$30,000 - $25,000 + $10,000 = -$45,000
Loss: $45,000 on $160,000 initial = -28% 😬3. 50% Loss Point:
Initial capital: $160,000
50% loss: $80,000
Need: -$80,000 = 3×(P - 50k) - 5×max(0, 45k - P) + 10k
Solving:
If P < $45k:
-80k = 3×(P - 50k) - 5×(45k - P) + 10k
-80k = 3P - 150k - 225k + 5P + 10k
-80k = 8P - 365k
8P = 285k
P = $35,625
At $35,625, you've lost 50% of capital (DANGER ZONE!)4. Should You Hedge?:
YES! Here's why:
- Exposed to 20% drop before 50% loss
- Bitcoin commonly moves 20-40%
- Short puts without protection = disaster potential
Recommended hedges:
1. Buy OTM puts at $40k (tail protection)
2. Reduce short put position (cut exposure)
3. Sell some long BTC (reduce concentration)
Cost: $2,000-$3,000 for $40k puts
Benefit: Caps max loss at ~25% instead of potential wipeoutKey Takeaways
-
Survival > Performance
- Staying in the game is #1 priority
- One catastrophic loss can erase years of gains
- Risk management is not optional
-
Know Your Risk
- VaR quantifies normal risk
- Stress tests quantify catastrophic risk
- Both are necessary
-
Position Sizing is Everything
- Never risk more than 2-5% per trade
- Size by max loss, not credit received
- Kelly Criterion provides mathematical framework
-
Greeks Tell You Everything
- Portfolio delta: Directional exposure
- Portfolio gamma: Convexity risk
- Portfolio theta: Time decay impact
- Portfolio vega: Volatility exposure
- Monitor and set limits for each
-
Diversification is Real
- Don’t put >20% in any single position
- Low correlation assets provide true diversification
- But correlations → 1.0 in crises!
-
Liquidity Matters
- Can’t profit if you can’t exit
- Check bid-ask spreads and market depth
- Size positions relative to liquidity
-
Leverage Kills
- LTCM: 100x leverage → bankruptcy
- Archegos: 10x leverage → $20B loss
- Keep leverage <2-3x maximum
-
Stress Test Everything
- Historical scenarios (COVID, 2008)
- Custom scenarios (regulation, black swans)
- Reverse stress test: “What blows me up?”
-
Risk-Adjusted Returns > Absolute Returns
- Sharpe ratio: Risk per unit return
- Sortino: Penalize only downside
- Calmar: Return vs max drawdown
- Optimize for risk-adjusted, not absolute
-
Automate Monitoring
- Daily risk reports
- Automated limit checks
- Alert systems for violations
- Discipline beats discretion
Final Thoughts
Risk Management Hierarchy:
Level 1 (Beginner): Don't blow up
- Use stop losses
- Never risk >5% per trade
- Understand max loss
Level 2 (Intermediate): Quantify risk
- Calculate VaR
- Monitor Greeks
- Track correlations
Level 3 (Advanced): Optimize risk
- Risk parity allocation
- Dynamic hedging
- Tail risk management
- Kelly sizing
Level 4 (Professional): Portfolio construction
- Multi-dimensional risk budgeting
- Stress testing infrastructure
- Real-time risk monitoring
- Automated compliance
Start Simple:
- Set position size limits (start with 2% per trade)
- Calculate portfolio Greeks daily
- Run weekly stress tests
- Measure Sharpe ratio monthly
- Increase sophistication gradually
Remember: The goal isn’t to eliminate risk—it’s to take calculated risks that you can survive and profit from over the long term. Master risk management, and you’ll outlast 95% of traders who eventually blow up.
Next Steps
Master Prerequisites:
- ✓ The Greeks - Risk metrics
- ✓ Delta Hedging - Risk control
- ✓ Monte Carlo - Risk modeling
Related Advanced Topics:
- Volatility Trading - Vol portfolio risks
- Multi-Asset Structures - Correlation risk
- Autocallables - Structured product risks
Practical Application:
- Risk Calculators - VaR, Greeks, position sizing
- Stress Test Simulator - Practice scenarios
- Portfolio Greeks Manager - Greeks practice
Real-World Learning:
- Case Studies - Learn from failures
- Study historical crises (2008, 2020, LTCM, Archegos)
- Paper trade with strict risk limits
- Build your own risk dashboard
You’ve completed the Advanced Level! You now have institutional-grade knowledge of structured products, volatility trading, exotic options, and professional risk management. The next step is practice: apply these frameworks to real markets, make mistakes with small size, and build the discipline that separates professionals from gamblers.
Welcome to the top 1% of derivatives traders. 🎓