Jensen’s alpha#

Michael Jensen (1968) measured a mutual fund’s skill as the intercept of its excess return regressed on the market’s,

\[r_{pt} - r_{ft} = \alpha_p + \beta_p (r_{mt} - r_{ft}) + \varepsilon_{pt}.\]

A manager who takes more market risk earns more on average but no alpha; only returns beyond the security market line count. Over 1945-1964 Jensen found the average alpha of 115 funds to be negative after fees, and no more funds with significant positive alpha than chance allows.

import matplotlib.pyplot as plt
import numpy as np

from financialkit.asset_pricing import jensen_alpha, simulate_factor_model

rng = np.random.default_rng(1968)
n_funds, T = 115, 240
betas = rng.uniform(0.7, 1.3, n_funds)
# Fees of 1% a year and no skill, except five genuinely skilled funds.
true_alpha = np.full(n_funds, -0.01 / 12)
true_alpha[:5] = 0.04 / 12
panel = simulate_factor_model(T, betas, [0.006], [[0.0020]], idio_vol=0.02, alphas=true_alpha, rng=rng)
res = jensen_alpha(panel.excess_returns, panel.factors[:, 0])
print(f"mean annual alpha: {12 * res.alphas.mean():+.2%}")
print(f"funds with alpha t > 2: {(res.alpha_t > 2).sum()} (true skilled: 5)")
mean annual alpha: -0.70%
funds with alpha t > 2: 4 (true skilled: 5)
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].hist(res.alpha_t, bins=25, color="0.7")
axes[0].axvline(2, color="C3", ls="--")
axes[0].set_xlabel("t-statistic of alpha")
axes[0].set_title("most funds: no skill after fees")
axes[1].scatter(res.betas[:, 0], 12 * res.alphas, s=10)
axes[1].scatter(res.betas[:5, 0], 12 * res.alphas[:5], s=25, color="C3", label="skilled funds")
axes[1].axhline(0, color="k", lw=0.8)
axes[1].set_xlabel("estimated beta")
axes[1].set_ylabel("annual alpha")
axes[1].set_title("alpha is unrelated to beta")
axes[1].legend()
fig.tight_layout()

plt.show()
most funds: no skill after fees, alpha is unrelated to beta

Total running time of the script: (0 minutes 0.090 seconds)

Gallery generated by Sphinx-Gallery