Quant Memo
Advanced

Fama-MacBeth Regression

A two-pass method for testing whether a stock characteristic earns a return premium: run one cross-sectional regression per month, then treat the sequence of monthly slopes as an ordinary time series and t-test its average. It exists because pooling every stock-month into one regression produces standard errors that are far too small.

Prerequisites: Ordinary Least Squares (OLS), Cross-Sectional vs. Time-Series Strategies

You have twenty years of monthly returns for two thousand stocks, and one number attached to each stock in each month — say its book-to-market ratio. The question is plain: do cheap stocks earn more than expensive ones, and is the gap real or is it luck? The obvious move is to stack all 480,000 rows into a single regression of return on book-to-market and read off the t-statistic. Do that and you will declare victory, because the t-statistic will be enormous. It will also be badly wrong. In any given month every stock in the market is shoved around by the same handful of shocks, so those 480,000 rows are nowhere near 480,000 independent pieces of evidence.

An analogy: 240 polls, not 480,000 voters

Suppose you want to know whether a political slogan moves opinion. You run a poll every month for twenty years, two thousand people per poll. If a national news story swings everyone in a given month, then within that month the two thousand answers are close to one answer repeated two thousand times. You do not have 480,000 independent observations. You have something much nearer to 240 — one per poll.

The honest way to summarise that evidence is not to pool the people. It is to compute one number per poll, then look at how those 240 numbers behave over time. If the slogan's effect averages plus two points across the polls and swings by five points from poll to poll, you can say exactly how sure you are — and the shared national shocks are already accounted for, because they are precisely what makes the poll-to-poll number bounce.

Fama-MacBeth is that procedure applied to stocks. One regression per month gives one estimate of the premium per month. Then you run the simplest test there is on that little sequence of numbers.

slope +2.4 slope −1.2 slope +3.6 pass 1: one month each monthly slope pass 2: t-test these
Pass 1 fits a line across stocks inside each month and keeps only the slope. Pass 2 forgets the stocks entirely and asks whether that little series of slopes has a mean different from zero. The shaded band is one standard error either side of the average.

The two passes, one symbol at a time

Let Ri,tR_{i,t} be the return on stock ii in month tt. Let Xi,t1X_{i,t-1} be the characteristic you are testing, measured before the return so there is no look-ahead. Let γ1,t\gamma_{1,t} ("gamma-one at time t") be the reward per unit of that characteristic in month tt, and γ0,t\gamma_{0,t} the common intercept for that month.

Pass 1 — one cross-section at a time. For each month tt separately, run

Ri,t=γ0,t+γ1,tXi,t1+εi,t.R_{i,t} = \gamma_{0,t} + \gamma_{1,t}\,X_{i,t-1} + \varepsilon_{i,t}.

In plain English: inside a single month, line the stocks up by their characteristic and fit a line through them; the slope is what one extra unit of the characteristic paid that month. Repeat TT times and you hold a time series of slopes, γ^1,1,,γ^1,T\hat\gamma_{1,1},\dots,\hat\gamma_{1,T}.

Pass 2 — a t-test on those slopes. The estimated premium is their average, and its uncertainty is their scatter:

γ^1=1Tt=1Tγ^1,t,sγ2=1T1t=1T(γ^1,tγ^1)2,t=γ^1sγ/T.\hat\gamma_1 = \frac{1}{T}\sum_{t=1}^{T}\hat\gamma_{1,t}, \qquad s_\gamma^2 = \frac{1}{T-1}\sum_{t=1}^{T}\big(\hat\gamma_{1,t}-\hat\gamma_1\big)^2, \qquad t = \frac{\hat\gamma_1}{s_\gamma/\sqrt{T}} .

In plain English: the premium is the average monthly slope, and how confident you are depends on how much that slope wobbles month to month — not on how many stocks you had. Here sγs_\gamma is the standard deviation of the slopes and TT is the number of months.

Notice what pass 2 never does: it never looks inside a month. Whatever correlation existed among stocks in March 2016 has already been compressed into a single number, and its damage surfaces honestly as month-to-month volatility of that number.

The explorer below is pass 1 in miniature. Drag the points and watch the fitted line and its residuals — every month of your sample produces one of these, and only the slope survives to pass 2.

Regression explorer
amber = residuals
fitted slope 1.133true slope 1.00 0.642SSres 42.0

Fit the regression once per period, then t-test the sequence of slopes. Your effective sample size is the number of periods, not the number of stock-months.

Worked example 1: five months, done by hand

Start with a single month. Four stocks, XX is book-to-market, RR is that month's return in percent.

StockXXRR
A0.51.0
B1.02.0
C1.52.0
D2.05.0

Step 1 — centre both columns. The means are Xˉ=1.25\bar X = 1.25 and Rˉ=2.5\bar R = 2.5. The XX deviations are 0.75,0.25,0.25,0.75-0.75,\,-0.25,\,0.25,\,0.75; the RR deviations are 1.5,0.5,0.5,2.5-1.5,\,-0.5,\,-0.5,\,2.5.

Step 2 — the two sums. Sum of squared XX deviations: 0.5625+0.0625+0.0625+0.5625=1.250.5625+0.0625+0.0625+0.5625 = 1.25. Sum of cross-products: 1.125+0.1250.125+1.875=3.01.125+0.125-0.125+1.875 = 3.0.

Step 3 — the slope. γ^1=3.0/1.25=2.4\hat\gamma_{1} = 3.0/1.25 = 2.4, and the intercept is 2.52.4(1.25)=0.52.5 - 2.4(1.25) = -0.5. That month, a stock one full unit higher in book-to-market earned 2.4 percentage points more. That is one observation about the premium, not four.

Step 4 — repeat and test. Say five months give slopes 2.4, 1.2, 3.6, 0.8, 0.62.4,\ -1.2,\ 3.6,\ 0.8,\ -0.6. Their sum is 5.05.0, so γ^1=1.0\hat\gamma_1 = 1.0. The deviations are 1.4,2.2,2.6,0.2,1.61.4,\,-2.2,\,2.6,\,-0.2,\,-1.6, whose squares sum to 16.1616.16; dividing by T1=4T-1 = 4 gives sγ2=4.04s_\gamma^2 = 4.04 and sγ=2.01s_\gamma = 2.01. Then

SE=2.015=2.012.236=0.899,t=1.00.899=1.11.\text{SE} = \frac{2.01}{\sqrt{5}} = \frac{2.01}{2.236} = 0.899, \qquad t = \frac{1.0}{0.899} = 1.11 .

An average premium of 1.0 with a t of 1.11 is not distinguishable from zero, and it should not be: five slopes that swing from 1.2-1.2 to +3.6+3.6 cannot pin down an average of 1.0. The method is being honest with you.

Worked example 2: twenty years, and what pooling would have claimed

Now the realistic version. T=240T = 240 months, mean slope γ^1=0.32\hat\gamma_1 = 0.32 percent per month, standard deviation of the slopes sγ=1.55s_\gamma = 1.55 percent.

SE=1.55240=1.5515.49=0.100,t=0.320.100=3.20.\text{SE} = \frac{1.55}{\sqrt{240}} = \frac{1.55}{15.49} = 0.100, \qquad t = \frac{0.32}{0.100} = 3.20 .

Annualised, the premium is 0.32×12=3.840.32 \times 12 = 3.84 percent per year per unit of the characteristic. A 95% interval runs 0.32±1.96(0.100)0.32 \pm 1.96(0.100), i.e. 0.124 to 0.516 percent monthly, or roughly 1.5 to 6.2 percent a year. Wide, and genuinely so.

Now the pooled alternative. A single regression on all 2000×240=480,0002000 \times 240 = 480{,}000 rows treats every row as independent. Under equicorrelated residuals — every stock in a month sharing one shock with correlation ρ\rho — the variance of a within-month average is inflated by 1+(N1)ρ1 + (N-1)\rho. With N=2000N = 2000 and a modest ρ=0.10\rho = 0.10:

1+(20001)(0.10)=200.9,200.9=14.2.1 + (2000-1)(0.10) = 200.9, \qquad \sqrt{200.9} = 14.2 .

In plain English: the pooled standard error is about 14 times smaller than the truth, so the pooled t-statistic would print near 3.20×14.2453.20 \times 14.2 \approx 45. The effective sample is 480,000/200.92,390480{,}000/200.9 \approx 2{,}390 observations, not half a million. A t of 45 on a 3.8 percent annual premium is not a discovery; it is a diagnostic that your standard errors are broken.

one column = one month shared shock inside each column, none across them
Every dot in a column is hit by the same monthly shock, so a column carries roughly one column's worth of information, not five stocks' worth. Pooled OLS counts all 35 dots; Fama-MacBeth counts 7.

What this means in practice

  • It is the default test for a new signal. Nearly every "we found an anomaly" table in asset pricing is a column of Fama-MacBeth t-statistics. If you want a research claim taken seriously, this is the format it is expected in.
  • The slope series is a portfolio return. γ^1,t\hat\gamma_{1,t} is, up to scaling, the monthly return on a zero-cost book long high-XX and short low-XX. That makes pass 2 identical to a Sharpe-ratio test: t=T×(γ^1/sγ)t = \sqrt{T}\times(\hat\gamma_1/s_\gamma). In example 2, 0.32/1.55=0.2070.32/1.55 = 0.207 monthly, an annualised Sharpe of 0.20712=0.720.207\sqrt{12} = 0.72, and 0.7220=3.20.72\sqrt{20} = 3.2 — the same t-statistic, arrived at from the trading side.
  • Watch the weighting. An equal-weighted cross-sectional regression hands enormous influence to microcaps. Use weighted least squares, or trim the universe, or you are measuring a premium you cannot trade.
  • Many characteristics at once. Add columns to pass 1 and you get one slope series per characteristic, each with its own second-pass t-test — this is how you check whether a new signal survives controls for size and momentum.

A quick sanity check: tannualised Sharpe×years of datat \approx \text{annualised Sharpe} \times \sqrt{\text{years of data}}. Twenty years and a t of 3.2 means a Sharpe near 0.7 — if someone shows you a t of 12 from ten years, the implied Sharpe is about 3.8, and you should ask what went wrong.

Two confusions, both common. First, Fama-MacBeth fixes cross-sectional correlation, not time-series correlation. The second pass assumes the monthly slopes are independent of each other. If the premium is persistent, or your signal overlaps across months, that assumption fails and the standard error is still too small — apply Newey-West to the slope series. Second, it is not the same thing as a time-series factor regression. Regressing one portfolio's returns on market, size and value over time asks "is this portfolio's alpha zero?"; Fama-MacBeth asks "does this characteristic get paid across stocks?" People quote one result and describe it as the other. A third, quieter trap: when XX is an estimated beta rather than an observed characteristic, measurement error drags the slope toward zero — which is exactly why Fama and MacBeth ran their original test on portfolios instead of single stocks.

Related concepts

Practice in interviews

Further reading

  • Fama & MacBeth (1973), Risk, Return, and Equilibrium: Empirical Tests
  • Cochrane, Asset Pricing (ch. 12)
  • Petersen (2009), Estimating Standard Errors in Finance Panel Data Sets
ShareTwitterLinkedIn