Time Series, lesson 3
Autocorrelation
Whether today's move says anything about tomorrow's.
If yesterday's move told you something about today's, you could trade on it. Autocorrelation measures how much a series remembers, and most of what follows in Time Series builds on it. You need returns, volatility and what a correlation is.
By the end, you can:
Part 1. Memory from one day to the next
Measure how much of yesterday carries into today.
Put each day's value next to the day before's. If high days tend to follow high days, the pairs move together and their correlation is positive. If high days tend to follow low ones, it's negative. If yesterday says nothing, it's near zero.
Example 1.1
Five days, one day apart
A series reads 1, 2, 4, 5, 3. How strongly is each value tied to the one before?
- Find each distance from the average−2, −1, +1, +2, 0
The average is 3.
- Add up the squared distances4 + 1 + 1 + 4 + 0 = 10
This sets the scale, as in any correlation.
- Multiply each distance by the one before(−1)(−2) + (1)(−1) + (2)(1) + (0)(2) = 3
Each product is positive when two days in a row sit on the same side of the average.
- Divide by the sum of squares3 / 10 = 0.3
It lands between −1 and 1, like any correlation.
Answer0.3: each day leans a little toward the one before.
Each product asks whether two days in a row sat on the same side of the average. Adding them gives a net vote, and dividing by the sum of squares puts it on a correlation's scale. Draw the pairs as dots and the vote shows as a tilt.
Autocorrelation
The autocorrelation is the correlation of a series with itself some days earlier. The gap is the lag. ρ̂(k), read "rho hat of k", is the autocorrelation at lag k measured from data. The hat marks it as an estimate.
ρ̂(k) = Σ (xₜ − x̄)(xₜ₋ₖ − x̄) / Σ (xₜ − x̄)²
What does it say about tomorrow? If the spread stays steady, the best straight-line guess for tomorrow's distance from the average is the lag-1 autocorrelation times today's. With 0.1 and a rise of 3% today, that's +0.3%. Even real memory in returns gives small forecasts.
Your turn
A series reads 4, 2, 6, 3, 5. What's its lag-1 autocorrelation?
Part 2. The correlogram
Read a correlogram of returns, their sizes and prices.
Lag 1 compares each day with the day before. Lag 2 compares it with two days before, and lag 5 with a week before. The working is the same. Only the pairs change.
Example 2.1
Five days, two days apart
For 1, 2, 4, 5, 3, what's the autocorrelation at lag 2?
- Multiply each distance by the one two days back(1)(−2) + (2)(−1) + (0)(1) = −4
The distances are −2, −1, +1, +2, 0, as before. Only three pairs are two days apart.
- Divide by the same sum of squares−4 / 10 = −0.4
Days two apart tend to sit on opposite sides of the average.
Answerρ̂(2) = −0.4.
Work out ρ̂(1), ρ̂(2), ρ̂(3) and on, and draw them as bars, one per lag. That chart shows a series' memory at a glance. Here are three, from a thousand days of a practice stock: its returns, their sizes and its prices.
Correlogram
A correlogram is a bar chart of the autocorrelation at lags 1, 2, 3 and on. Desks draw one for returns, for their sizes, and for whatever a model leaves unexplained.
Returns show next to no memory, so yesterday's direction says almost nothing about today's. Sizes show a long memory: that's volatility clustering, from the last lesson. Prices sit near 1 because each price is yesterday's plus a move. That's no help in predicting the move, so quants test returns.
Your turn
The series 4, 2, 6, 3, 5 has distances 0, −2, +2, −1, +1 from its average. What's its lag-2 autocorrelation?
Part 3. Memory or luck
Tell real memory from luck with the ±1.96 / √n band.
A series with no memory at all still gives bars that aren't exactly zero. Over a few hundred days, luck alone pushes them around. The question is how far.
Example 3.1
Is 0.05 real?
Over one year, 252 trading days, a stock's returns have a lag-1 autocorrelation of 0.05. Is that more than luck? What if the same 0.05 came from ten years?
- Size up luck's wobble1 / √252 = 0.063
With no memory, a bar from n days wobbles around zero with a standard deviation of about 1 / √n.
- Set the 95% band1.96 × 0.063 = ±0.123
Luck keeps 95% of bars within 1.96 standard deviations.
- Compare0.05 < 0.123
Inside the band. One year can't tell it from luck.
- Redo it for ten years1.96 / √2,520 = ±0.039
Now 0.05 sits outside. Small effects need a lot of data.
AnswerLuck, as far as one year can tell. The same 0.05 over ten years is evidence.
The band narrows with the square root of the data: four times the days halve it. That's why one year rarely settles anything about returns, and why the thousand-day correlogram in part 2 has a band of ±0.062.
The no-memory band
With n days of a series that has no memory, the autocorrelation at any lag lands inside this band 95% of the time. A bar outside it is evidence of memory.
±1.96 / √n
Check many lags and some land outside by luck. At 5% each, 20 lags give about 1. Tests such as Ljung-Box roll many lags into one number to guard against that.
And memory can be real yet small. At 0.05, with 1% daily volatility, a rule that follows yesterday's direction earns about 0.04% a day before costs, and it switches sides about every other day. Trading costs can eat all of that.
Your turn
Over 400 days, a series' lag-1 autocorrelation is −0.08. Is it outside the 95% no-memory band?
Where you'll meet it
Expect to read a correlogram, quote the band (often rounded to ±2 / √n) and say why one bar outside it isn't evidence. Common follow-ups: why the autocorrelation of prices tells you nothing, returns against their sizes, and what a small autocorrelation is worth once you pay to trade it.
Rama Cont's 2001 survey finds the autocorrelations of liquid asset returns usually insignificant, except over very short intraday horizons, while the autocorrelation of absolute returns decays slowly over many lags. Greta Ljung and George Box published their many-lag test in 1978. Desks also run it on a model's leftover errors.
import numpy as np
def acf(x, k): # autocorrelation at lag k
x = np.asarray(x, dtype=float) - np.mean(x)
return np.sum(x[k:] * x[:-k]) / np.sum(x * x)
print(f"lag 1 {acf([1, 2, 4, 5, 3], 1):.1f}, lag 2 {acf([1, 2, 4, 5, 3], 2):.1f}")
rng = np.random.default_rng(19)
r, var = np.zeros(1000), 0.0001
for t in range(1000): # a practice stock whose volatility clusters
r[t] = np.sqrt(var) * rng.standard_normal()
var = 0.000002 + 0.10 * r[t] ** 2 + 0.88 * var
for name, x in [("returns", r), ("sizes", np.abs(r)), ("prices", 100 * np.cumprod(1 + r))]:
print(f"{name:8s}", " ".join(f"{acf(x, k):+.2f}" for k in (1, 2, 5, 10)))
print(f"band +/-{1.96 / np.sqrt(1000):.3f}")
# Output:
# lag 1 0.3, lag 2 -0.4
# returns +0.01 +0.03 +0.06 +0.01
# sizes +0.21 +0.26 +0.21 +0.11
# prices +1.00 +0.99 +0.98 +0.96
# band +/-0.062Check yourself
Three questions from across the lesson. Try each one before you look back.
1
A stock's daily returns have a lag-1 autocorrelation of −0.1, and its volatility is steady. It rose 2% today. Ignoring the average, what's the best guess for tomorrow?
2
A correlogram of a stock's daily returns has every bar inside the band. The correlogram of their sizes has every bar above it. What does that tell you?
3
You check 20 lags of a series that truly has no memory, using a 95% band. How many bars do you expect outside the band?
What to remember
1Memory from one day to the next
Autocorrelation at lag k is the correlation of a series with itself k days earlier: 1, 2, 4, 5, 3 has ρ̂(1) = 3 / 10 = 0.3.
2The correlogram
A correlogram draws ρ̂(k) lag by lag: daily returns show almost no memory, their sizes a long one, and prices bars near 1 that say nothing about the next move.
3Memory or luck
With no memory, a bar from n days lands inside ±1.96 / √n 95% of the time: ±0.123 for one year of daily data, ±0.039 for ten.
3Memory or luck
Check 20 lags and about 1 bar lands outside the band by luck alone.
Time Series overviewSpotted a mistake? Tell us.