Many traders think they're diversified because they trade multiple instruments. But if those instruments are correlated, you're really just taking one big position.
Measuring Correlation
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
def calculate_correlations(price_data, window=60):
"""
price_data: DataFrame with columns as instruments, rows as dates
"""
returns = price_data.pct_change().dropna()
correlation_matrix = returns.rolling(window).corr()
return returns.corr() # Static correlation
# Example
data = pd.DataFrame({
'ES': es_prices, # S&P 500 futures
'NQ': nq_prices, # Nasdaq futures
'YM': ym_prices, # Dow futures
'GC': gc_prices, # Gold
'CL': cl_prices, # Crude Oil
'EURUSD': eur_prices,
'GBPUSD': gbp_prices,
})
corr = calculate_correlations(data)
Visualizing Correlations
def plot_correlation_heatmap(corr_matrix):
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='RdBu_r',
center=0, vmin=-1, vmax=1, fmt='.2f')
plt.title('Instrument Correlations')
plt.tight_layout()
plt.savefig('correlations.png', dpi=150)
Common Correlation Traps
Trap 1: Index Futures
ES, NQ, YM, and RTY often have correlations above 0.85. Trading all four is essentially one position.
Trap 2: Currency Pairs
EUR/USD and GBP/USD typically correlate at 0.7-0.9. Going long both is amplifying risk, not diversifying.
Trap 3: Correlation Changes
Correlations spike during market stress. Assets that seem uncorrelated in calm markets suddenly move together during crashes.
def rolling_correlation(series1, series2, window=30):
returns1 = series1.pct_change()
returns2 = series2.pct_change()
rolling_corr = returns1.rolling(window).corr(returns2)
return rolling_corr
# Check if correlation spikes during high VIX
def correlation_by_regime(returns_df, vix_series, threshold=25):
calm = returns_df[vix_series < threshold]
stress = returns_df[vix_series >= threshold]
return {
'calm': calm.corr(),
'stress': stress.corr()
}
Building a Truly Diversified Portfolio
Step 1: Cluster Analysis
from scipy.cluster.hierarchy import linkage, dendrogram
def cluster_instruments(corr_matrix):
distance = 1 - corr_matrix.abs()
linkage_matrix = linkage(distance, method='ward')
plt.figure(figsize=(12, 6))
dendrogram(linkage_matrix, labels=corr_matrix.columns)
plt.title('Instrument Clusters')
plt.savefig('clusters.png')
Step 2: Select One Per Cluster
Pick the most liquid instrument from each cluster. This gives you genuine diversification.
Step 3: Dynamic Position Sizing
Adjust position sizes based on current correlations:
def correlation_adjusted_size(base_size, positions, corr_matrix):
adjusted_sizes = {}
for instrument in positions:
# Check correlation with existing positions
max_corr = 0
for existing in adjusted_sizes:
c = abs(corr_matrix.loc[instrument, existing])
max_corr = max(max_corr, c)
# Reduce size for correlated positions
reduction = max(0.3, 1 - max_corr)
adjusted_sizes[instrument] = base_size * reduction
return adjusted_sizes
Practical Application
If you trade 5 correlated instruments at 1% risk each, your effective risk is closer to 4-5% β not the 1% you planned. This is how accounts blow up.
True diversification means trading instruments from different asset classes: a stock index future, a commodity, a currency pair, and perhaps a bond future. Each should have a correlation below 0.5 with the others.
This matters significantly when you have daily drawdown limits. Understanding how correlation affects your aggregate risk is essential. propfirmkey.com details the specific risk limits for different firms.
How many instruments do you trade, and have you measured their correlations?
Top comments (0)