joellewis/factor-investing
Apply factor models to portfolio construction and fund evaluation, from CAPM through the Fama-French 3- and 5-factor models plus momentum. Use when the user asks about 'Fama-French', 'value factor', 'smart beta', 'factor tilt', 'momentum exposure', or the 'factor zoo', wants to run or interpret a factor regression (loadings, alpha after controlling for factors, R-squared, t-stats), decompose a manager's returns into factor exposures versus skill, or asks 'is my fund closet indexing'. Also trigger on SMB, HML, RMW, CMA, UMD, size/value/quality/profitability/low-vol premia, factor ETF or smart-beta product evaluation (factor purity, turnover, capacity, fees), factor cyclicality and the danger of factor timing, factor crowding, long-short academic factors versus long-only implementable tilts, and post-publication factor decay.
npx skills add https://github.com/JoelLewis/finance_skills --skill factor-investing
CAPM prices a single source of risk: E(R_i) - R_f = beta * (E(R_m) - R_f). Persistent anomalies — small caps, cheap (high book-to-market) stocks, and recent winners earning more than beta predicts — motivated adding factors. Fama-French (1993) added size and value to the market factor (3-factor model); Carhart (1997) added momentum; Fama-French (2015) added profitability and investment (5-factor model):
R_i - R_f = alpha + b_MKT*MKT + b_SMB*SMB + b_HML*HML [+ b_RMW*RMW + b_CMA*CMA] [+ b_UMD*UMD] + epsilon
The key reinterpretation: a manager's CAPM alpha may be nothing more than static factor exposure. Alpha only means skill *after* controlling for the factors an investor could buy cheaply. Single-factor OLS mechanics, t-statistics, and the CAPM regression itself live in the statistics-fundamentals skill; this skill generalizes to K regressors and interprets the output.
| Factor | Construction (long-short) | Rationale: risk-based | Rationale: behavioral | Approx. premium* |
|--------|---------------------------|----------------------|----------------------|------------------|
| MKT | Market minus risk-free | Non-diversifiable macro risk | — | 6-7%/yr |
| SMB (size) | Small caps minus big caps | Illiquidity, distress sensitivity | Neglect of small firms | 1.5-2%/yr |
| HML (value) | High book/market minus low | Distress risk, cyclical cash flows | Overextrapolation of growth | 2.5-3%/yr |
| RMW (profitability) | Robust minus weak operating profitability | Compensation for cash-flow risk | Underreaction to quality | ~3%/yr |
| CMA (investment) | Conservative minus aggressive asset growth | Q-theory: high investment implies low expected return | Empire-building overinvestment | ~3%/yr |
| UMD (momentum, Carhart) | Past 12-1 month winners minus losers | Crash risk (violent reversals) | Underreaction, herding | 6-7%/yr |
*Approximate annualized US long-short premia over the 1963-2024 sample, Ken French data library, as of 2026. Long-run averages, not forecasts; realized decade-long stretches deviate wildly (see cyclicality below).
The rationale matters for durability: risk-based premia should persist (someone must bear the risk); behavioral premia survive only while limits to arbitrage prevent them from being competed away — and are more vulnerable to crowding.
Run OLS of fund *excess* returns on the factor return series. Interpret:
Two complementary uses of the same regression:
E(R) = R_f + sum(b_k * lambda_k), where lambda_k are assumed factor premia. This tells you what the fund *should* earn from its exposures alone; realized excess return minus the factor-implied excess is the manager's implied alpha. If the implied alpha is near zero, the fund is a factor portfolio you could replicate with cheap factor ETFs.IR_breakeven = (fund fee - index fee) / tracking error. A closet indexer needs an implausibly high IR on a tiny active-risk budget just to earn back its fee gap (Information Ratio itself is covered in performance-metrics).Treat every smart-beta product as a factor portfolio (the equities skill's rule) and evaluate the implementation, not the marketing name:
Published premia are measured on long-short, often leverage- and shorting-unconstrained portfolios rebalanced without costs. A long-only implementable tilt:
Scale expectations accordingly: a long-only value tilt with b_HML = 0.4 against a 2.5-3% premium is worth roughly 1.0-1.35%/yr before costs, not the headline long-short number.
Every factor endures multi-year droughts: US value underperformed growth for roughly the 2017-2020 stretch, with a relative drawdown deep enough to end careers, before rebounding sharply in 2021-2022. Momentum crashes violently in sharp reversals (2009). Because droughts are long and turning points are unforecastable, factor *timing* — rotating into "cheap" factors — has a poor live record and adds turnover. The defensible uses of cyclicality are (a) diversifying across factors with low mutual correlation (value and momentum are natural complements) and (b) sizing tilts so the investor can survive a decade-long drought without capitulating at the bottom.
Hundreds of "significant" factors have been published — Cochrane's "factor zoo." Treat the zoo skeptically:
| Formula | Expression | Use Case |
|---------|-----------|----------|
| 3-factor model | R_i - R_f = alpha + b_MKT*MKT + b_SMB*SMB + b_HML*HML + eps | Baseline equity attribution |
| Carhart 4-factor | 3-factor + b_UMD*UMD | Add momentum control |
| 5-factor model | 3-factor + b_RMW*RMW + b_CMA*CMA | Profitability and investment control |
| Expected-return decomposition | E(R) = R_f + sum(b_k * lambda_k) | Factor-implied return from loadings and premia |
| Implied alpha | realized excess mean - sum(b_k * lambda_k) | Skill after factor exposure |
| Significance rule | t = coefficient / SE; skill requires \|t(alpha)\| > ~2 | Separate luck from skill |
| Residual (active) vol | sigma_resid = sigma_fund * sqrt(1 - R^2) | Tracking-error decomposition |
| Breakeven IR | (fund fee - index fee) / tracking error | Closet-index fee test |
Given: 60 monthly excess returns of a US large-cap value fund regressed on MKT, SMB, HML (all in % per month):
alpha = 0.037 (t = 0.60) -> 0.037 x 12 = 0.44% per year
b_MKT = 0.98 (t = 58.1)
b_SMB = 0.12 (t = 4.6)
b_HML = 0.45 (t = 23.1)
R^2 = 0.986 (residual vol 0.457% per month)
Analysis: The three factors explain 98.6% of the fund's return variance. The value loading of 0.45 is strong and highly significant (t = 23.1 >> 2) — this is a genuine, stable value tilt, typical of a long-only value fund (well below the 1.0 of the academic long-short HML portfolio). The market loading of 0.98 is ordinary full-invested equity exposure, and the small positive SMB loading shows a mild small-cap lean. Alpha is 0.44% per year with t = 0.60 < 2: statistically indistinguishable from zero.
Verdict: factor exposure, not skill. Everything this fund delivers could be replicated with a market fund plus a value-tilted index fund. Whether to own it now becomes a fee question (Example 3), not a skill question.
Given: The Example 1 loadings, assumed forward-looking premia of MKT 6.5%, SMB 2.0%, HML 3.0% per year, a risk-free rate of 4.0% (assumption as of mid-2026), and a realized fund excess return of 8.4% per year.
MKT contribution = 0.98 x 6.5% = 6.37%
SMB contribution = 0.12 x 2.0% = 0.24%
HML contribution = 0.45 x 3.0% = 1.35%
Factor-implied excess return = 6.37 + 0.24 + 1.35 = 7.96%
Total expected return = 4.0% + 7.96% = 11.96%
Implied alpha = 8.4% - 7.96% = 0.44% per year
Analysis: Of the fund's 8.4% realized excess return, 7.96 points came from factor exposures and only 0.44 from anything unexplained — consistent with Example 1's insignificant regression alpha. Note also the implementability haircut: the fund's value tilt is worth 1.35%/yr (0.45 x 3.0%), roughly half the headline long-short HML premium, exactly as the long-only discussion above predicts.
Given: A fund with monthly volatility 4.30%, R-squared of 0.99 against its benchmark, a 0.85% expense ratio, and a 0.05% comparable index fund.
Residual vol = 4.30% x sqrt(1 - 0.99) = 4.30% x 0.10 = 0.43% per month
Tracking error = 0.43% x sqrt(12) = 1.49% annualized
Fee gap = 0.85% - 0.05% = 0.80% per year
Breakeven IR = 0.80 / 1.49 = 0.54
Analysis: R-squared of 0.99 (>= 0.98) and tracking error of 1.49% (<= 2%) both trip the closet-index screen. Worse, on a 1.49% active-risk budget the manager must sustain an Information Ratio of 0.54 *just to break even on fees* — an IR that would rank among top-decile active managers, demanded here merely to match the index fund net of costs. Verdict: closet indexer; the rational holdings are the index fund, or a genuinely active fund whose tracking error is large enough to make its fee gap recoverable.
uv run scripts/factor_investing.py # run the demo (uses PEP 723 inline deps)
uv run scripts/factor_investing.py --verify # check outputs against the worked examples (exit 1 on mismatch)
python3 scripts/factor_investing.py # alternative (requires: pip install numpy scipy)
scripts/factor_investing.py provides a FactorInvesting class with static methods multifactor_regression (K-factor OLS via numpy least squares, returning alpha, loadings, t-stats, p-values, R-squared, and residual vol), expected_return_decomposition (loadings x premia, with implied alpha), and closet_index_diagnostics (residual vol, tracking error, breakeven IR, closet-index flag). A bare run (or --verify) prints the demo on a deterministic seeded dataset and asserts the worked-example values above (Example 1 loadings/t-stats/R-squared, Example 2 decomposition, Example 3 diagnostics), exiting nonzero on any mismatch. Run --help for the method list. For programmatic use, import rather than run: from factor_investing import FactorInvesting.
Take joellewis/factor-investing from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference pip.
Without those the skill loads but fails at the first command.