lost $1,400 yesterday because i didn’t track correlation between my positions. dumb mistake.
what happened #
may 10, 2pm:
- had 3 open credit spreads
- all “independent” strategies
- all on tech stocks
market dumped 2%. all 3 positions hit stops at same time.
total loss: $1,400
should’ve been $400-500 max (one position losing).
the problem #
my 3 “independent” positions:
- QQQ put spread (tech ETF)
- AAPL put spread (tech stock)
- MSFT put spread (tech stock)
thought i was diversified. i wasn’t.
QQQ is 40% AAPL + MSFT. when tech dumps, all 3 move together.
correlation = 0.92 between these positions. might as well have been the same trade 3 times.
what i should’ve tracked #
import pandas as pd
import numpy as np
# Get position correlations
positions = ['QQQ', 'AAPL', 'MSFT']
returns = get_historical_returns(positions, days=30)
correlation_matrix = returns.corr()
print(correlation_matrix)
# QQQ AAPL MSFT
# QQQ 1.00 0.89 0.91
# AAPL 0.89 1.00 0.93
# MSFT 0.91 0.93 1.00
# All highly correlated = not diversified
correlation > 0.7 = basically same position
i had 0.92. stupid.
position limits i should’ve had #
by sector:
- max 2 positions in same sector
- max 40% of capital in correlated positions (>0.7)
by underlying:
- max 1 position per stock
- ETFs count as multiple stocks (check holdings)
by strategy:
- even “different” strategies can correlate
- premium selling on correlated underlyings = same risk
how to actually diversify #
good diversification:
- SPX put spread (broad market)
- TLT call spread (bonds - negative correlation to stocks)
- GLD put spread (gold - low correlation)
correlation matrix:
SPX TLT GLD
SPX 1.00 -0.45 0.12
TLT -0.45 1.00 -0.18
GLD 0.12 -0.18 1.00
negative correlation to TLT = when stocks dump, bonds rally, TLT position makes money.
code i added #
class PositionManager:
def __init__(self):
self.positions = []
self.max_correlation = 0.70
self.max_sector_exposure = 0.40
def check_correlation(self, new_position):
"""Check if new position is too correlated with existing"""
if len(self.positions) == 0:
return True
# Get symbols of current positions
current_symbols = [p.underlying for p in self.positions]
# Calculate correlation with new position
all_symbols = current_symbols + [new_position.underlying]
returns = self.get_returns(all_symbols, days=30)
corr_matrix = returns.corr()
# Check correlation with each existing position
for symbol in current_symbols:
correlation = corr_matrix.loc[symbol, new_position.underlying]
if abs(correlation) > self.max_correlation:
print(f"REJECTED: {new_position.underlying} correlation {correlation:.2f} with {symbol}")
return False
return True
def check_sector_exposure(self, new_position):
"""Check if adding position exceeds sector limits"""
sector = self.get_sector(new_position.underlying)
# Calculate current sector exposure
sector_capital = sum(p.capital_at_risk for p in self.positions
if self.get_sector(p.underlying) == sector)
total_capital = self.account_value
new_exposure = (sector_capital + new_position.capital_at_risk) / total_capital
if new_exposure > self.max_sector_exposure:
print(f"REJECTED: {sector} exposure {new_exposure:.1%} exceeds {self.max_sector_exposure:.1%}")
return False
return True
def add_position(self, position):
"""Add position after checking correlation and sector limits"""
if not self.check_correlation(position):
return False
if not self.check_sector_exposure(position):
return False
self.positions.append(position)
return True
what this would’ve prevented #
may 10 scenario with correlation checking:
- add QQQ put spread ✅ (no existing positions)
- add AAPL put spread ❌ (correlation 0.89 with QQQ, rejected)
- add MSFT put spread ❌ (correlation 0.91 with QQQ, rejected)
would’ve only had 1 position in tech. loss: $400 instead of $1,400.
saved $1,000.
other correlation mistakes #
strategies that correlate more than you think:
- short volatility strategies (all lose when VIX spikes)
- premium selling (all lose in crashes)
- mean reversion (all lose in trends)
- momentum (all lose in reversals)
even “different” strategies can correlate during market stress.
may performance so far #
week 1: +$520 week 2 (so far): -$1,400
net may: -$880
back below break-even. frustrated but it’s a good lesson.
better to lose $1,400 learning about correlation now than $10k later when account is bigger.
what i’m changing #
- added correlation checking to position manager (code above)
- max 2 positions per sector
- target negative correlation between positions
- checking correlation weekly, not just at entry
- if correlation > 0.7 develops during hold, close one position
sectors i’m using for limits #
- technology (QQQ, AAPL, MSFT, GOOGL, etc)
- financials (JPM, BAC, XLF, etc)
- healthcare (JNJ, UNH, XLV, etc)
- energy (XLE, CVX, XOM, etc)
- bonds (TLT, IEF, AGG)
- commodities (GLD, SLV, USO)
testing the new system #
backtesting last 30 days with correlation limits:
- original: 14 trades, -$880 net
- with limits: 9 trades (5 rejected), +$340 net
correlation checking would’ve prevented all my correlated losses.
the math #
without correlation limits:
- 3 positions @ $400 risk each = $1,200 total risk
- correlation 0.92 means effective risk = $1,100 (not $400)
- actual loss: $1,400 (worse than expected)
with correlation limits:
- 3 positions with correlation < 0.3
- effective risk = $650 (true diversification benefit)
- expected max loss = $700 (much better)
lesson #
diversification isn’t about number of positions. it’s about correlation between positions.
10 positions in tech = 1 position 3 positions across uncorrelated sectors = actual diversification
3:15am. expensive lesson but necessary. correlation checking goes live tomorrow.
-AK