A small-cap value fund may outperform the broad market because it has exposures the broad market comparison misses. The regression gives those exposures separate names and estimates how much each contributes to the fitted return. The factors are returns on specified portfolios or portfolio spreads, so a positive slope on the size factor indicates co-movement with periods when small stocks outperform big stocks after accounting for the other factors.
Align the factor and portfolio returns before estimating
Let . The three-factor regression is
The five-factor version includes . SMB is small minus big, HML is high minus low book-to-market, RMW is robust minus weak operating profitability, and CMA is conservative minus aggressive investment. In the French data library, SMB is constructed differently in the three-factor and five-factor datasets. Use the series from the specification you intend to fit. If you want a nested test of adding two columns to the same regressors, explicitly hold the common columns fixed on an identical date range.
Explain a month using the fitted exposures
In the arithmetic above, the value factor subtracts 0.20 percentage points because a positive exposure is multiplied by a negative factor return. If the realised excess return was 2%, the residual is percentage points. That is one month's unexplained return. Alpha is the intercept estimated across the whole sample and is a different number. Keeping those units straight helps prevent a large residual in one month from being mistaken for persistent abnormal performance.
OLS with dated joins and robust standard errors
monthly whose columns include the asset's total return asset_return and the chosen factor data, merged by month. Convert every return column to decimal units before fitting. Use a matching market, frequency, and currency, and select the corresponding three- or five-factor dataset before calling the function.import statsmodels.api as sm
def estimate_factors(monthly, factors):
data = monthly[["asset_return", "RF", *factors]].dropna().sort_index()
y = data["asset_return"] - data["RF"]
x = sm.add_constant(data[factors], has_constant="add")
return sm.OLS(y, x).fit(cov_type="HAC", cov_kwds={"maxlags": 3})
five = ["Mkt-RF", "SMB", "HML", "RMW", "CMA"]
fit = estimate_factors(monthly, five)
print(fit.params)
print(fit.conf_int())