What is stationarity in a time series, and how do you test for it?
A stationary series has a constant mean, constant variance, and autocovariance that depends only on lag — not on when you look. Most classical models (ARIMA, VAR) require it. The Augmented Dickey-Fuller (ADF) test is the standard check; a p-value below 0.05 lets you reject the unit-root null and conclude the series is stationary.
How to think about it
Lead with the definition, then the ADF mechanics, then how you fix non-stationarity. Interviewers at quant firms expect you to know the null hypothesis precisely.
Formal definition
A weakly (covariance) stationary series satisfies three conditions:
- Constant mean: E[Yt] = μ for all t
- Constant variance: Var(Yt) = σ² for all t
- Autocovariance depends only on lag: Cov(Yt, Yt+k) = γ(k), not on t
A trending or seasonal series violates the first condition. A series whose volatility grows over time violates the second.
The ADF test
The Augmented Dickey-Fuller test checks whether a unit root is present. The null hypothesis is that the series has a unit root (is non-stationary). A small p-value is evidence against that null — meaning the series is stationary.
from statsmodels.tsa.stattools import adfuller
import pandas as pd
series = pd.read_csv("prices.csv", index_col=0, parse_dates=True).squeeze()
result = adfuller(series, autolag="AIC")
print(f"ADF statistic : {result[0]:.4f}")
print(f"p-value : {result[1]:.4f}")
# p < 0.05 → reject unit root → series is stationary
Making a series stationary
| Problem | Fix |
|---|---|
| Linear trend | First-order differencing: Yt - Yt-1 |
| Quadratic trend | Second-order differencing |
| Exponential growth | Log transform, then difference |
| Seasonality | Seasonal differencing: Yt - Yt-s |
After each transformation, re-run ADF to confirm.