Skip to content
Finance Lessons

Time-Series Finance

Stationarity & Returns

Why raw prices are non-stationary but returns are roughly stationary, what a unit root is, the intuition behind the augmented Dickey–Fuller test, and the transformations (logs, differencing) that make a series modelable.

11 min Updated Jun 7, 2026

Every model you will build in this topic — autocorrelations, AR and GARCH, EWMA — quietly assumes the series you feed it behaves consistently over time: that its mean and its spread don’t go wandering off as the calendar turns. That assumption has a name, stationarity, and it is the single gate every time-series technique has to pass through. The catch is that the most obvious financial series of all — a stock’s price — flunks it badly, while a tiny transformation — the return — sails through. Getting that distinction exactly right, and knowing how to test and fix it, is the foundation the rest of this topic stands on.

Before you read — take a guess

You download ten years of a stock's daily closing prices and want to model them. A colleague says 'just fit the model straight to the price levels.' What's the core problem?

What stationarity actually means

Analogy. Imagine two rivers. The first has a fixed water level and a steady ripple — scoop a bucket today or next month and it looks statistically the same. The second is a tide coming in: the level keeps rising and the waves keep growing. The first river is stationary; the second is non-stationary. A model trained on one bucket of the first river generalizes to any other bucket. A model trained on the rising tide will be wrong the moment the tide moves on.

Definition. A process is (weakly, or covariance) stationary if three things stay constant over time:

  • the mean E[Xt]=μE[X_t] = \mu does not depend on tt,
  • the variance Var(Xt)=σ2\mathrm{Var}(X_t) = \sigma^2 does not depend on tt,
  • the autocovariance Cov(Xt,Xt+k)\mathrm{Cov}(X_t, X_{t+k}) depends only on the lag kk, never on when you look.

In plain words: the statistical “shape” of the series is the same wherever you slide your window. That is exactly what lets you estimate one set of parameters from history and trust them tomorrow — without stationarity, “the past” and “the future” are drawn from different distributions, and estimation is built on sand.

Info:

Strict vs weak stationarity

Strict stationarity demands the entire joint distribution be shift-invariant; weak (covariance) stationarity only pins down the first two moments and the autocovariance. In finance we almost always work with weak stationarity — it’s what the standard estimators need, and it’s testable. When this topic says “stationary,” read “weakly stationary.”

Why prices fail and returns pass

Prices are non-stationary. A price level has no fixed mean to revert to — it drifts up over decades, and its variance grows the longer you watch (recall the t\sqrt{t} spreading of a random walk). Slide your window from 2005 to 2020 and the mean and spread are wildly different. That’s textbook non-stationarity.

Returns are (approximately) stationary. Define the simple return rt=PtPt1Pt1r_t = \frac{P_t - P_{t-1}}{P_{t-1}} or, more commonly, the log return rt=ln ⁣PtPt1=lnPtlnPt1r_t = \ln\!\frac{P_t}{P_{t-1}} = \ln P_t - \ln P_{t-1}. Returns hover around a small, roughly constant mean with a roughly constant spread. Their distribution from 2005 looks much like 2020’s (same ballpark mean near zero, comparable volatility). They aren’t perfectly stationary — volatility clusters, as we’ll see in a later lesson — but they are close enough that models built on returns work, while models built on prices do not.

This is why the entire quant toolkit is built on returns, not prices. The same series, transformed once, flips from un-modelable to modelable.

Same data, two faces: price vs returns
Price (random walk + drift)mean
-0010180

Toggle between the level and its first difference. The price wanders off and its spread keeps widening — non-stationary. The returns sit in a flat cloud around a fixed mean with stable spread — approximately stationary. Differencing once turned one into the other.

Tip:

Why logs, not just simple returns

Log returns have two handy properties: they add over time (lnPTP0=trt\ln\frac{P_T}{P_0} = \sum_t r_t, so multi-period returns are just sums), and they’re symmetric around zero in a way simple returns aren’t (a +50% then −50% leaves you at 75%, but in logs +0.405 then −0.405 cancels to 0). For modeling, additive and roughly symmetric is exactly what you want.

Unit roots: the precise reason a price won’t settle

We can say why a price wanders more sharply. Model it as an AR(1) process — today equals a coefficient ϕ\phi times yesterday plus a shock: Xt=ϕXt1+εt.X_t = \phi X_{t-1} + \varepsilon_t. The whole behavior hinges on ϕ\phi:

  • If ϕ<1|\phi| < 1, shocks decay — the series is pulled back toward its mean and is stationary.
  • If ϕ=1\phi = 1, you have Xt=Xt1+εtX_t = X_{t-1} + \varepsilon_t — a pure random walk. Shocks never decay; they accumulate forever. This is a unit root, and it is the defining fingerprint of a non-stationary series.
  • If ϕ>1|\phi| > 1, the series explodes away.

A unit root is exactly the ϕ=1\phi = 1 case: the characteristic root of the process sits on the unit circle, so a shock today is still fully present a thousand steps later. Prices behave like unit-root processes; that’s the formal reason their variance grows without bound and they refuse to revert.

Worked example — persistence of a shock. Suppose a one-time shock of +10+10 hits an AR(1).

  • With ϕ=0.5\phi = 0.5: after the shock the contribution is 1010, then 0.5×10=50.5 \times 10 = 5, then 2.52.5, then 1.251.25 — halving each step, gone within a handful of periods. Mean-reverting.
  • With ϕ=0.95\phi = 0.95: 10,9.5,9.025,10, 9.5, 9.025, \dots — it takes about ln(0.5)/ln(0.95)13.5\ln(0.5)/\ln(0.95) \approx 13.5 steps just to halve. Sticky, but eventually fades.
  • With ϕ=1\phi = 1: 10,10,10,10, 10, 10, \dots — the shock is permanent. The level has been moved forever. That is a unit root.

The lesson: as ϕ\phi climbs toward 1, shocks linger longer and longer; at exactly 1 they become permanent and stationarity breaks.

In an AR(1) process X_t = φ·X_{t−1} + ε_t, which value of φ corresponds to a unit root (a non-stationary random walk)?

The augmented Dickey–Fuller test (intuition)

How do you test whether a series has a unit root? The workhorse is the augmented Dickey–Fuller (ADF) test. You don’t need its full machinery, just the logic.

The trick. Rewrite the AR(1) by subtracting Xt1X_{t-1} from both sides: ΔXt=(ϕ1)Xt1+εt=γXt1+εt,\Delta X_t = (\phi - 1)X_{t-1} + \varepsilon_t = \gamma X_{t-1} + \varepsilon_t, where ΔXt=XtXt1\Delta X_t = X_t - X_{t-1} and γ=ϕ1\gamma = \phi - 1. Now the question “is there a unit root?” becomes “is γ=0\gamma = 0?” (because γ=0    ϕ=1\gamma = 0 \iff \phi = 1). The ADF test regresses the change ΔXt\Delta X_t on the lagged level Xt1X_{t-1} (the “augmented” part adds a few lagged differences to mop up extra autocorrelation) and checks whether the coefficient γ\gamma is significantly negative.

  • Null hypothesis H0H_0: γ=0\gamma = 0 — there is a unit root (non-stationary).
  • Alternative H1H_1: γ<0\gamma < 0 — no unit root, the series is stationary (a level above its mean pulls the next change down).

A very negative test statistic (more negative than the critical value) lets you reject the null and call the series stationary. A statistic near zero means you fail to reject — you can’t rule out a unit root, so treat it as non-stationary.

Warning:

The ADF null is 'non-stationary' — mind the direction

Failing to reject does not prove a unit root; it just means you lack evidence against one. And the test has low power: it often fails to reject for a series that is almost a unit root (φ = 0.98). Pair it with a plot, an ACF, and economic sense — never lean on one p-value. Some practitioners also run the KPSS test, which flips the null (stationary under H₀) as a cross-check.

The logic of the augmented Dickey–Fuller test.

Pick the right option for each blank, then check.

The ADF test rewrites the AR(1) so the unit-root question becomes whether γ = φ − 1 equals . Its null hypothesis is that the series , so a test statistic lets you reject the null and conclude the series is stationary.

Making a series stationary: logs and differencing

If a series is non-stationary, you transform it until it isn’t. Two tools do most of the work.

1. Log transform — tame growing variance. When a series grows multiplicatively (prices, GDP, anything that compounds), its variance grows with its level. Taking logs converts multiplicative growth into additive growth and stabilizes the variance. It doesn’t fix the trend, but it makes the next step well-behaved.

2. Differencing — kill the trend / unit root. Replace the level with its change: ΔXt=XtXt1\Delta X_t = X_t - X_{t-1}. A random walk differenced once becomes white noise — its first difference is just the shock εt\varepsilon_t, which is stationary. The number of differences you need to reach stationarity is the order of integration, written I(d)I(d):

  • I(0)I(0) = already stationary (returns are roughly I(0)I(0)).
  • I(1)I(1) = stationary after one difference (log prices are I(1)I(1) — difference them once and you get log returns).
  • I(2)I(2) = needs two differences (rare in finance).

Notice the chain: log price is I(1)I(1); difference it once and you get the log return, which is I(0)I(0) — exactly the stationary series every later model wants. That’s not a coincidence; it’s the whole reason “model returns, not prices” is gospel.

Worked example — from price to modelable input. A price path 100103101106100 \to 103 \to 101 \to 106:

  • Log prices: ln100=4.605\ln 100 = 4.605, ln103=4.635\ln 103 = 4.635, ln101=4.615\ln 101 = 4.615, ln106=4.663\ln 106 = 4.663 — still trending, non-stationary.
  • First differences (log returns): 4.6354.605=+0.0304.635 - 4.605 = +0.030, 4.6154.635=0.0204.615 - 4.635 = -0.020, 4.6634.615=+0.0484.663 - 4.615 = +0.048. These hover around a small mean with no trend — stationary, ready to model.
Warning:

Don't over-difference

Differencing a series that’s already stationary (over-differencing) injects artificial negative autocorrelation and inflates variance — you create problems you then have to model away. Difference only as much as the data demands: check with a plot and an ADF/KPSS test after each difference, and stop the moment the series looks stationary.

Match each term to its precise meaning.

Pick a term, then click its definition.

If two prices are each non-stationary, can a model of them ever be valid?

Yes — and this is the gem behind pairs trading. Two non-stationary I(1)I(1) prices can be cointegrated: although each wanders off on its own, a particular linear combination of them (say, price of A minus a hedge ratio times price of B) is stationary. The two prices are tied together by an economic tether — think of two refiners, or a stock and its ADR — so the spread between them mean-reverts even though neither price does. You’d never regress one raw price on another (that produces the classic spurious regression: two independent random walks can show a huge, totally fake R²), but you can model their stationary spread. Cointegration is exactly “the difference is I(0)I(0) even though the levels are I(1)I(1),” and it’s the statistical foundation of statistical-arbitrage spread trades.

Putting it together

Stationarity — constant mean, constant variance, lag-only autocovariance — is the gate every time-series model must pass: it’s what lets you learn parameters from the past and trust them in the future. Raw prices fail because they carry a unit root (ϕ=1\phi = 1 in an AR(1)): shocks never decay, the variance grows without bound, and the mean drifts. Returns pass because differencing the (log) price strips out the trend, leaving a roughly I(0)I(0) series. The augmented Dickey–Fuller test formalizes the check — its null is a unit root, and a strongly negative statistic rejects it in favor of stationarity (with the caveat of low power, so corroborate with plots and KPSS). The fixes are logs (stabilize growing variance) and differencing (remove the trend), applied just enough — a log price is I(1)I(1), and one difference turns it into the stationary log return that every later model in this topic is built on. And when two prices are individually non-stationary but tied together, cointegration lets a stationary spread between them be modeled even though neither level can.

Big picture

Stationarity & returns — the whole picture

  • Stationarity & returns
    • Stationarity
      • Constant mean and variance
      • Autocovariance depends only on lag k
      • Lets you trust past parameters in the future
      • Weak (covariance) stationarity is the working notion
    • Prices fail, returns pass
      • Prices: drifting mean, growing variance
      • Returns: roughly constant mean and spread
      • Log returns add over time and are symmetric
      • Quant toolkit is built on returns, not prices
    • Unit roots
      • AR(1): φ controls persistence
      • φ = 1 → unit root, shocks permanent
      • |φ| < 1 stationary, |φ| > 1 explosive
    • Testing & fixing
      • ADF null = unit root; very negative stat rejects it
      • Low power; corroborate with KPSS and a plot
      • Logs stabilize growing variance
      • Differencing removes trend; I(1) → I(0)
      • Cointegration: stationary spread of I(1) prices
Stationarity is the modeling gate; prices fail it via a unit root; returns pass after differencing; ADF tests it; logs and differencing fix it.

Recap: stationarity & returns

Question 1 of 40 correct

Which of these is a defining requirement for a (weakly) stationary process?

Check your answer to continue.

Next up — autocorrelation, the ACF and PACF — now that we have a stationary series to work with, we ask the obvious follow-up: does today’s return tell you anything about tomorrow’s? The autocorrelation function and its partner the PACF are the tools that answer that, and they’re how you’ll decide which model a series actually needs.

Mark lesson as complete