Kalman filters for dynamic factor loading estimation
Using Kalman filters to estimate time-varying factor loadings has been a game-changer for my models.
The key insight: factor betas are NOT constant. A stock's sensitivity to momentum or value changes over time as the company evolves.
import pykalman
kf = pykalman.KalmanFilter(
transition_matrices=np.eye(n_factors),
observation_matrices=factor_returns,
initial_state_mean=np.zeros(n_factors),
)
beta_estimates = kf.filter(asset_returns)[0]
This gives you smooth, time-varying betas that react to regime changes.
36 Replies
import numpy as np
from scipy import optimize
def max_sharpe_portfolio(returns, rf=0.0):
n = returns.shape[1]
init_w = np.ones(n) / n
bounds = [(0.0, 0.1)] * n
constraints = {'type': 'eq', 'fun': lambda w: np.sum(w) - 1.0}
result = optimize.minimize(
lambda w: -(np.mean(returns @ w) - rf) / np.std(returns @ w),
init_w, bounds=bounds, constraints=constraints
)
return result.x
Here's a simple max-Sharpe optimizer for reference.
The biggest mistake I see newcomers make: optimizing for the wrong metric. Sharpe != best trading strategy. Consider Calmar, Sortino, and max drawdown.
For time-series cross-validation, I've found that 5 expanding windows with a 21-day embargo works well for daily data.
For factor models, I'd strongly recommend the Fama-French 5-factor model as a starting point. It captures most systematic risk.
For factor models, I'd strongly recommend the Fama-French 5-factor model as a starting point. It captures most systematic risk.
I'd recommend reading "Quantitative Portfolio Management" by Michael Isichenko. It's the best practical guide I've found.
I'd recommend reading "Quantitative Portfolio Management" by Michael Isichenko. It's the best practical guide I've found.
One more thing: the scoring engine uses a held-out test period that you never see. So your validation score is the best you can do.
Be careful with the Kelly criterion for position sizing. Full Kelly is way too aggressive. I use quarter-Kelly in practice.
Turnover control is crucial. My best performing model has a turnover of only 8% daily. High turnover strategies rarely survive transaction costs.
I ran a quick backtest on this idea and got a Sharpe of about 1.2 before costs. Not bad for a simple strategy.
Anyone else noticing that momentum factors have been working particularly well in the last month of competition data?
For those new to the platform: start with the tutorial competition. It has a smaller dataset and more forgiving scoring.