1:30am and i’m staring at correlation matrices again.
everyone talks about diversification like it’s free lunch.
it’s not.
the diversification myth #
portfolios are “diversified” until they’re not.
2020 march - everything dropped together.
2022 crypto winter - BTC and ETH moved in lockstep.
late 2025 vol spike - correlations spiked across all my positions.
when you need diversification most, it disappears.
tracking correlations in real time #
built a system to track rolling correlations across my entire portfolio.
not just at month end.
every day.
current 30-day rolling correlation matrix. ES and NQ at 0.94 - basically same asset. BTC and ETH at 0.87 - also high. gold is the only real diversifier at -0.15 to equities.
what this tells me:
- my “diversified” portfolio is actually 3 bets: equities, crypto, gold
- ES and NQ positions are redundant from correlation perspective
- SPX options are 0.89 correlated to ES - makes sense, same underlying
- gold is the only true hedge but tiny allocation
correlations aren’t static #
this is the part most people miss.
correlations change based on market regime.
rolling 30-day correlations over the past 6 months. notice how ES-BTC correlation spiked during the october vol event. when shit hits the fan, everything correlates.
key observation:
during stress, ES-BTC correlation went from 0.35 to 0.55+
that’s a 60% increase in correlation when i needed diversification most.
meanwhile ES-NQ stayed glued at 0.92-0.95.
BTC-ETH stayed glued at 0.85-0.90.
the algo approach #
from dataclasses import dataclass
from typing import Dict, List, Tuple
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
@dataclass
class AssetReturns:
symbol: str
returns: pd.Series
class CorrelationTracker:
def __init__(self, lookback: int = 30):
self.lookback = lookback
self.assets: Dict[str, pd.Series] = {}
self.correlation_history: List[Dict] = []
def add_asset(self, symbol: str, returns: pd.Series):
"""Add asset return series"""
self.assets[symbol] = returns
def calculate_correlation_matrix(self, as_of: datetime = None) -> pd.DataFrame:
"""Calculate correlation matrix as of specific date"""
if as_of is None:
as_of = datetime.now()
# align all series to same date range
aligned = {}
for symbol, returns in self.assets.items():
mask = returns.index <= as_of
aligned[symbol] = returns[mask].tail(self.lookback)
df = pd.DataFrame(aligned)
return df.corr()
def get_rolling_correlation(self, asset1: str, asset2: str,
window: int = 30) -> pd.Series:
"""Calculate rolling correlation between two assets"""
r1 = self.assets[asset1]
r2 = self.assets[asset2]
# align dates
combined = pd.concat([r1, r2], axis=1)
combined.columns = [asset1, asset2]
combined = combined.dropna()
return combined[asset1].rolling(window).corr(combined[asset2])
def detect_correlation_regime(self) -> str:
"""Classify current correlation environment"""
matrix = self.calculate_correlation_matrix()
# average off-diagonal correlation
n = len(matrix)
off_diag = []
for i in range(n):
for j in range(i+1, n):
off_diag.append(matrix.iloc[i, j])
avg_corr = np.mean(off_diag)
if avg_corr > 0.7:
return "high_correlation" # risk-off, everything moving together
elif avg_corr > 0.4:
return "normal"
else:
return "low_correlation" # good for diversification
def calculate_effective_positions(self) -> float:
"""How many truly independent bets do I have?"""
matrix = self.calculate_correlation_matrix()
# eigenvalue decomposition
eigenvalues = np.linalg.eigvals(matrix.values)
eigenvalues = np.real(eigenvalues)
eigenvalues = eigenvalues[eigenvalues > 0]
# effective number of bets (Shannon entropy based)
eigenvalues = eigenvalues / eigenvalues.sum()
effective_n = np.exp(-np.sum(eigenvalues * np.log(eigenvalues + 1e-10)))
return effective_n
def get_diversification_score(self) -> float:
"""0-100 score of portfolio diversification"""
n_assets = len(self.assets)
effective_n = self.calculate_effective_positions()
# ratio of effective to actual positions
score = (effective_n / n_assets) * 100
return min(100, score)
def daily_snapshot(self) -> Dict:
"""Record daily correlation state"""
matrix = self.calculate_correlation_matrix()
snapshot = {
'timestamp': datetime.now().isoformat(),
'regime': self.detect_correlation_regime(),
'effective_positions': self.calculate_effective_positions(),
'diversification_score': self.get_diversification_score(),
'correlation_matrix': matrix.to_dict()
}
self.correlation_history.append(snapshot)
return snapshot
not rocket science.
tracks rolling correlations.
calculates “effective positions” - how many truly independent bets i have.
gives me a diversification score.
what the data says #
ran this across all of 2025.
findings:
- average effective positions: 2.4 (out of 6 assets)
- average diversification score: 40/100
- correlation regime breakdown:
- high correlation (>0.7 avg): 18% of days
- normal (0.4-0.7): 62% of days
- low correlation (<0.4): 20% of days
translation:
my “6 asset” portfolio is really 2.4 independent bets on average.
and during stress, that drops to like 1.5.
how i use this #
rule 1: reduce size when correlations spike
when regime = “high_correlation”, i cut position sizes by 30%.
everything is moving together. doubling down on any position doubles total portfolio risk.
rule 2: track effective positions, not actual positions
my dashboard shows effective positions, not asset count.
if effective positions < 2, i’m basically making one big bet.
rule 3: rebalance based on correlation changes
when ES-BTC correlation dropped back to 0.35 in december, i increased crypto allocation.
diversification value had returned.
current state #
as of today (jan 22):
- correlation regime: normal
- effective positions: 2.6
- diversification score: 43/100
- ES-NQ correlation: 0.94 (very high - expected)
- ES-BTC correlation: 0.42 (moderate)
- gold correlation to equities: -0.15 (negative - good hedge)
sitting in a reasonable spot.
not over-concentrated.
not perfectly diversified either.
been tracking correlation regimes with some traders on NexusFi who run similar multi-asset portfolios. the consensus is that correlation-based position sizing is one of the few edges that actually scales.
the takeaway #
diversification isn’t a set-it-and-forget-it thing.
correlations change.
your “diversified” portfolio can become a single bet overnight.
track it. adjust for it. don’t assume yesterday’s correlation matrix applies today.
1:30am wednesday. tracking cross-asset correlations. my “6 asset” portfolio is really 2.4 independent bets. ES-NQ at 0.94 is basically one position. BTC-ETH at 0.87 same thing. gold at -0.15 to equities is the only real diversifier. diversification score: 43/100. not great but not terrible. regime is normal. will reduce size if correlations spike again.
-AK