Alpha vs beta
The most common false positive in this whole discipline is a strategy that is really just the market wearing a costume. Making money in a bull run is not skill if you give it all back in the bear — that is leverage, not alpha. This chapter separates the two with a regression, shows why "regime modelling" is so often beta in disguise, and closes with the honest haircut you apply before trusting any forward number.
The plain question is embarrassingly simple: if I had just bought and held, would I have done about as well? If yes, whatever cleverness sits on top is decoration — you were paid for taking market risk, which anyone can do with a single click and no strategy at all. Beta is that borrowed return; alpha is the part left over that the market cannot explain. A regression separates them in one line, and the rest of this chapter is about why the separation matters more than any headline CAGR.
The decomposition#
Regress the strategy's returns on a benchmark's returns (buy-and-hold of the same instrument, say). The single-factor market model splits every period's return into three parts:
- — the part explained by riding the market. is your effective exposure: is fully long the benchmark, is 2× leveraged, is market-neutral.
- — the intercept: return not explained by the benchmark. This is the skill component, the thing you actually want.
- — idiosyncratic noise, mean zero by construction.
The slope and intercept are the ordinary-least-squares estimates:
You want near zero and positive: return that does not depend on the market going up. A high beta with near-zero alpha is the giveaway — you have leverage, not skill.
is_it_beta#
is_it_beta runs exactly this regression and returns the two numbers that matter — the slope and the annualised intercept residual.
import edgekit as ek
out = ek.validation.is_it_beta(strat_daily_ret, buy_and_hold_daily_ret, periods_per_year=365)
print(out["beta"], out["alpha"])
# high beta + ~0 alpha -> leveraged market exposure, not an edge
# ~0 beta + positive alpha -> return independent of the market (what you want)beta = 0.92, alpha ≈ +1%/yr. Almost the entire 40% is of borrowed market return — it is buy-and-hold with extra steps and worse fees, and it will hand the gains back in the next bear it has not seen. Strategy B is a market-neutral pairs trade: beta = 0.05, alpha ≈ +38%/yr. Its return barely moves with BTC, so the 40% is skill the market cannot explain. Same headline number, but you would size B as a real edge and treat A as leverage. The regression is what tells them apart — the CAGR never could.Regime modelling is often just beta#
A tempting story: "my regime overlay turns the strategy on in good markets and offin bad ones." If that overlay is really just detecting when the market is rising and going long, it has not added alpha — it has added timing beta. The equity curve improves, but only because you increased market exposure during the periods the market went up, which you can only know with hindsight in a backtest.
Two tests catch this. First, is_it_beta: a genuine regime edge keeps beta low even as it improves returns; a beta overlay just raises the slope. Second — and this is the harder gate — the permutation test. Drift-beta survives a reshuffle, because shuffling the bar order preserves the return marginal the long bias feeds on; genuine serial-correlation structure does not. If your "regime alpha" keeps its p-value after permutation, it is structural; if it evaporates, it was riding drift.
The honest forward haircut#
Even after a strategy survives the whole gauntlet with real alpha, the backtest number is a ceiling, not an expectation. The drawdown-matched size reproduces the historical worst case exactly, and history was one lucky draw. edgekit never hides the two haircuts you apply before believing a forward number:
- Edge decay ≈ ×0.85 — if the edge is permutation-validated (worse if it is not). The future regime is assumed less favourable than the past; edges erode as they are discovered and crowded.
- Size-down ≈ ×0.75 — because live drawdowns run deeper than the single lucky historical one. Size against the block-bootstrap dd95 (a bad-but-not-tail drawdown), not the realised max.
import edgekit as ek
# size against a realistic worst case, not the one lucky historical drawdown
dd = ek.validation.dd95(daily_r, block=5, horizon=252, n=15000) # 95th-pct max DD
sized = ek.sizing.size_to_dd(daily_r, dd_budget=0.095, account=100_000, daily_cap=0.045)
honest = backtest_annual * 0.85 * 0.75 # edge-decay x size-down -> plan around THISWhere this leads#
Separating alpha from beta is the last conceptual gate in the testing part of the course. The natural next question is how to generate the alternative worlds these tests rely on from first principles — the stochastic processes behind the bootstrap and the permutation. That is where Part V begins.
Next: Simulating markets — geometric Brownian motion, fat tails, and regime-switching, and how simulated markets let you stress a strategy against worlds that never happened.