Finance15 min read·

Autocorrelation: What It Is & How to Test for It 2026

A practical guide to autocorrelation - what it means in time series data, how to detect it using ACF plots and the Durbin-Watson test, and why it matters for financial modelling and trading.

What Is Autocorrelation?

Autocorrelation is the correlation of a time series with a lagged copy of itself. If today's value tells you something about tomorrow's value - beyond what the mean and trend already tell you - the series is autocorrelated. It's one of the most fundamental properties of time series data and the starting point for building any serious forecasting or trading model.

More precisely, autocorrelation at lag k measures the linear relationship between observations separated by k time steps. For a time series ( X_t ), the autocorrelation at lag k is:

[ \rho_k = \frac{\text{Cov}(X_t, X_{t-k})}{\text{Var}(X_t)} ]

This always lies between -1 and +1. At lag 0, the autocorrelation is 1 by definition (a series is perfectly correlated with itself). What matters is the autocorrelation at lags 1, 2, 3, and beyond.

Autocorrelation is also called serial correlation, particularly in econometrics. The two terms are interchangeable, though "autocorrelation" is more common in statistics and signal processing, while "serial correlation" tends to appear in regression diagnostics.

Positive autocorrelation means high values tend to follow high values, and low values tend to follow low values. Think of temperature readings throughout the year - a hot day is very likely followed by another hot day. The series has momentum, or persistence. Most economic and financial time series in levels (GDP, stock prices, interest rates) exhibit strong positive autocorrelation.

Negative autocorrelation means high values tend to be followed by low values, and vice versa. The series alternates. Picture a market maker's inventory that oscillates around zero - a large buy pushes inventory high, triggering sells that push it low. Negative autocorrelation is less common in raw financial data but appears in certain mean-reverting processes and in the residuals of over-differenced series.

Zero autocorrelation means knowing the current value gives you no information about the next value. White noise is the textbook example. Under the efficient market hypothesis, stock returns should be approximately uncorrelated - and in practice, daily returns of liquid stocks show very little autocorrelation, though not precisely zero.


Positive vs Negative Autocorrelation

Understanding the distinction between positive and negative autocorrelation is essential for choosing the right model and the right trading strategy.

Positive Autocorrelation

A positively autocorrelated series exhibits persistence. If it's above its mean today, it's more likely to be above its mean tomorrow. Plotting such a series, you'd see long, smooth runs above and below the average - the series meanders slowly rather than jumping around randomly.

Examples in finance:

  • Interest rates. The Bank of England base rate doesn't jump from 4% to 1% overnight. It moves in gradual trends, with each month's rate closely related to the previous month's. The autocorrelation at lag 1 is extremely high, often above 0.99.
  • Volatility. Realised volatility of equity indices shows strong positive autocorrelation. A week of high volatility is almost always followed by another week of high volatility. This is the volatility clustering that GARCH models are designed to capture.
  • Macroeconomic series. GDP growth, unemployment, and inflation all exhibit positive autocorrelation. The economy doesn't randomly reset each quarter.

In a scatter plot of ( X_t ) against ( X_{t-1} ) for a positively autocorrelated series, the points cluster along an upward-sloping line. The tighter the cluster, the stronger the autocorrelation.

Negative Autocorrelation

A negatively autocorrelated series oscillates. If it's above its mean today, it's more likely to be below its mean tomorrow. Plotting it, you'd see a jagged, zigzag pattern - the series bounces up and down more frequently than a random series would.

Examples in finance:

  • Bid-ask bounce. At tick level, trade prices alternate between the bid and ask prices, creating negative autocorrelation in observed returns. This is a microstructure artefact rather than a tradeable signal.
  • Over-differenced series. If you difference a stationary series, the result shows negative autocorrelation at lag 1. This is a common diagnostic clue that you've differenced too many times.
  • Mean-reverting spreads. The spread between cointegrated assets often shows negative autocorrelation at short lags - when the spread widens, it tends to narrow, and vice versa.

In a scatter plot of ( X_t ) against ( X_{t-1} ), negatively autocorrelated data clusters along a downward-sloping line.


The Autocorrelation Function (ACF)

The autocorrelation function gives you the complete picture of linear dependence in a time series. Rather than looking at a single lag, the ACF computes the autocorrelation at every lag from 1 up to some maximum, and displays the results in an ACF plot.

How to Read an ACF Plot

An ACF plot has lag on the x-axis and autocorrelation on the y-axis, ranging from -1 to +1. Each lag is shown as a vertical bar (or spike) extending from zero. A horizontal dashed line at zero marks the baseline, and two horizontal bands - typically at ( \pm 1.96 / \sqrt{n} ) where n is the number of observations - mark the 95% confidence interval under the null hypothesis of no autocorrelation.

Here's how to interpret it:

  • Bars inside the confidence bands are consistent with zero autocorrelation at that lag. They're statistically insignificant.
  • Bars outside the confidence bands indicate statistically significant autocorrelation at that lag.
  • Slowly decaying bars (all positive, gradually shrinking) suggest a persistent, trending process - likely non-stationary. This pattern screams "you need to difference before modelling."
  • A sharp cutoff after lag q (significant bars at lags 1 through q, then nothing) suggests a moving average process of order q, or MA(q).
  • An alternating pattern of positive and negative bars can indicate negative autocorrelation or seasonal effects.

For financial returns (which are roughly stationary), you'd expect most bars to be within the confidence bands, with perhaps a few small but significant values at specific lags. For raw prices, you'd see the slow-decay pattern because prices are non-stationary.

What the Confidence Bands Mean

The confidence bands represent the range within which autocorrelation values would fall about 95% of the time if the true data-generating process were white noise. Under the null of no serial correlation, the sample autocorrelation at each lag is approximately normally distributed with mean zero and variance 1/n. So the bands are at ( \pm 1.96 / \sqrt{n} ).

With 500 observations, the bands sit at roughly +/- 0.088. With 2,000 observations, they narrow to about +/- 0.044. More data gives you sharper tests. Note that even with white noise, you'd expect about 5% of lags to poke outside the bands by chance - so a single barely significant bar at lag 17 isn't worth worrying about.


Partial Autocorrelation (PACF)

The partial autocorrelation function measures the correlation between ( X_t ) and ( X_{t-k} ) after removing the linear effect of all intermediate lags ( X_{t-1}, X_{t-2}, \ldots, X_{t-k+1} ). It isolates the direct relationship at each lag.

How PACF Differs from ACF

The ACF at lag 2 measures the total correlation between ( X_t ) and ( X_{t-2} ) - which includes both the direct relationship and the indirect path through ( X_{t-1} ). If ( X_t ) is correlated with ( X_{t-1} ), and ( X_{t-1} ) is correlated with ( X_{t-2} ), then ( X_t ) will show correlation with ( X_{t-2} ) even if there's no direct link. The PACF strips out this indirect effect.

This distinction matters for model selection:

  • ACF cuts off sharply after lag q → MA(q) process. The ACF tells you the order of the moving average component.
  • PACF cuts off sharply after lag p → AR(p) process. The PACF tells you the order of the autoregressive component.

For an AR(1) process, the ACF decays exponentially (slowly) but the PACF has a single significant spike at lag 1 and nothing after. For an AR(2) process, the PACF has significant spikes at lags 1 and 2 and then cuts off. This makes the PACF the primary tool for determining how many lagged terms to include in an autoregressive model.

When to Use PACF

Use the PACF when you're trying to determine the order of an AR model. If you're debating between AR(1), AR(2), and AR(3), the PACF plot gives you a direct answer: count the number of significant spikes before the cutoff.

If both the ACF and PACF decay gradually without a clean cutoff, the data likely follows an ARMA process, and you'll need to use information criteria (AIC, BIC) to select the orders of both the AR and MA components.


How to Test for Autocorrelation

Beyond visual inspection of ACF and PACF plots, three formal statistical tests are widely used to detect autocorrelation.

The Durbin-Watson Test

The Durbin-Watson test is the classic check for first-order autocorrelation in regression residuals. The test statistic is:

[ DW = \frac{\sum_{t=2}^{n}(e_t - e_{t-1})^2}{\sum_{t=1}^{n} e_t^2} ]

where ( e_t ) are the regression residuals. The Durbin-Watson statistic ranges from 0 to 4:

  • DW ≈ 2 means no autocorrelation.
  • DW < 2 suggests positive autocorrelation (the closer to 0, the stronger).
  • DW > 2 suggests negative autocorrelation (the closer to 4, the stronger).

As a rough guide, values between 1.5 and 2.5 are generally acceptable. The Durbin-Watson test has formal critical values that depend on the sample size and number of regressors, but the "close to 2 is fine" rule covers most practical cases.

The test has one important limitation: it only detects first-order (lag-1) autocorrelation. If your residuals show autocorrelation at lag 3 but not lag 1, the Durbin-Watson test won't catch it. For higher-order serial correlation, you need the Ljung-Box or Breusch-Godfrey tests.

The Ljung-Box Test

The Ljung-Box test checks for autocorrelation at multiple lags simultaneously. Rather than testing one lag at a time, it tests the null hypothesis that the first m autocorrelations are all zero:

[ Q = n(n+2) \sum_{k=1}^{m} \frac{\hat{\rho}_k^2}{n-k} ]

Under the null of no autocorrelation, Q follows a chi-squared distribution with m degrees of freedom. A small p-value rejects the null, indicating that at least one of the first m autocorrelations is significantly different from zero.

The Ljung-Box test is more versatile than Durbin-Watson because it tests multiple lags and can be applied to any time series, not just regression residuals. The choice of m matters - too small and you might miss autocorrelation at higher lags, too large and you lose power. A common rule of thumb is ( m = \min(10, n/5) ), or ( m = 2s ) for seasonal data with period s.

The Breusch-Godfrey Test

The Breusch-Godfrey test is designed specifically for regression residuals and can detect autocorrelation at any specified lag. Unlike the Durbin-Watson test, it works even when lagged dependent variables appear as regressors.

The procedure:

  1. Fit the original regression and save the residuals ( e_t ).
  2. Regress ( e_t ) on the original regressors plus ( e_{t-1}, e_{t-2}, \ldots, e_{t-p} ).
  3. The test statistic is ( n \times R^2 ) from this auxiliary regression, distributed as chi-squared with p degrees of freedom.

The Breusch-Godfrey test is the most flexible of the three for regression diagnostics. It handles higher-order serial correlation, works with lagged dependent variables, and is straightforward to implement.


Detecting Autocorrelation in Python

Here's a complete workflow for detecting autocorrelation in a time series using Python. We'll generate a process with known autocorrelation, plot the ACF and PACF, and run formal statistical tests.

import numpy as np import pandas as pd import statsmodels.api as sm from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from statsmodels.stats.stattools import durbin_watson from statsmodels.stats.diagnostic import acorr_ljungbox import matplotlib.pyplot as plt np.random.seed(42) n = 500 # Generate an AR(2) process with known coefficients errors = np.random.normal(0, 1, n) y = np.zeros(n) phi_1, phi_2 = 0.6, -0.2 for t in range(2, n): y[t] = phi_1 * y[t - 1] + phi_2 * y[t - 2] + errors[t] series = pd.Series(y, name="y") # --- ACF and PACF plots --- fig, axes = plt.subplots(1, 2, figsize=(13, 4)) plot_acf(series, lags=30, ax=axes[0], alpha=0.05) axes[0].set_title("Autocorrelation Function (ACF)") axes[0].set_xlabel("Lag") axes[0].set_ylabel("Autocorrelation") plot_pacf(series, lags=30, ax=axes[1], alpha=0.05, method="ywm") axes[1].set_title("Partial Autocorrelation Function (PACF)") axes[1].set_xlabel("Lag") axes[1].set_ylabel("Partial Autocorrelation") plt.tight_layout() plt.savefig("acf_pacf_plot.png", dpi=150) plt.show()

In the ACF plot, you'll see the autocorrelation decaying gradually - positive at lag 1, smaller at lag 2, and oscillating slightly as it tails off. This slow, exponential decay is the signature of an autoregressive process. In the PACF plot, you'll see significant spikes at lags 1 and 2 and then an abrupt cutoff, with all subsequent lags falling within the confidence bands. This sharp cutoff at lag 2 tells you the process is AR(2) - exactly what we simulated.

Now run the formal tests:

# --- Durbin-Watson test --- # Fit a simple regression (intercept only) to get residuals X_const = sm.add_constant(np.arange(n)) model = sm.OLS(series, X_const).fit() dw_stat = durbin_watson(model.resid) print("=== Durbin-Watson Test ===") print(f"DW statistic: {dw_stat:.4f}") print(f"Interpretation: {'Positive autocorrelation' if dw_stat < 1.5 else 'No strong evidence' if dw_stat < 2.5 else 'Negative autocorrelation'}") print() # --- Ljung-Box test --- lb_results = acorr_ljungbox(series, lags=[5, 10, 20], return_df=True) print("=== Ljung-Box Test ===") print(lb_results.to_string()) print() # Interpret results for lag in lb_results.index: pval = lb_results.loc[lag, "lb_pvalue"] print(f"Lag {lag}: p-value = {pval:.6f} -> {'Autocorrelated' if pval < 0.05 else 'No autocorrelation detected'}")

The Durbin-Watson statistic should be well below 2 for this AR(2) process, indicating positive autocorrelation at lag 1. The Ljung-Box test should reject the null at all tested lags with very small p-values, confirming that significant autocorrelation is present.


Why Autocorrelation Matters in Finance

Autocorrelation has direct implications for regression inference, signal construction, and risk modelling. Ignoring it can lead to overconfident backtests, false trading signals, and mispriced risk.

It Violates OLS Assumptions

One of the Gauss-Markov assumptions underlying ordinary least squares is that the error terms are uncorrelated. When regression residuals are autocorrelated, OLS coefficient estimates remain unbiased, but the standard errors are wrong. Specifically, positive autocorrelation in residuals causes OLS to underestimate standard errors, which inflates t-statistics. You end up thinking your coefficients are more significant than they really are.

This is a critical problem in financial research. If you regress next-month stock returns on a factor (say, momentum) using monthly data and the residuals exhibit positive autocorrelation, your t-statistic might show 3.5 when the corrected value is only 1.8. That's the difference between a "highly significant" finding and a non-result. Many published anomalies in financial economics have been questioned precisely because the original studies failed to account for serial correlation in residuals.

Implications for Trading Signals

If returns show statistically significant autocorrelation, that autocorrelation is itself a potential trading signal:

  • Positive autocorrelation in returns suggests momentum - buying past winners and selling past losers might be profitable.
  • Negative autocorrelation in returns suggests mean reversion - contrarian strategies that buy losers and sell winners could work.

In practice, daily stock returns show very little autocorrelation. The efficient market hypothesis predicts this: if returns were predictable from their own past values, traders would exploit the pattern until it disappeared. However, at very short horizons (intraday, tick level) and at longer horizons (monthly, annual), small but economically significant autocorrelation patterns do appear. Momentum is one of the best-documented anomalies in finance, and it's fundamentally a claim about positive autocorrelation in returns over 3-to-12-month horizons.

Connection to GARCH

Here's a subtlety that matters enormously. While raw returns of liquid stocks show very little autocorrelation, squared returns and absolute returns show strong positive autocorrelation. A large return today - whether positive or negative - predicts another large return tomorrow. This is volatility clustering, and it means the conditional variance of returns is time-varying.

GARCH models are built directly on this observation. A GARCH(1,1) model specifies that today's variance depends on yesterday's squared return (capturing the autocorrelation in squared returns) and yesterday's variance (capturing persistence). Testing for autocorrelation in squared returns is equivalent to testing for ARCH effects - and it's one of the first diagnostics you should run on any financial return series.


How to Handle Autocorrelation

When you've detected autocorrelation, four approaches address it depending on your context and goals.

Newey-West Standard Errors

If your primary concern is correct inference in a regression, Newey-West (HAC - heteroscedasticity and autocorrelation consistent) standard errors are the most straightforward fix. They adjust the standard errors to account for both heteroscedasticity and autocorrelation in the residuals, without changing the coefficient estimates.

import statsmodels.api as sm import numpy as np np.random.seed(42) n = 300 # Generate autocorrelated data x = np.random.normal(0, 1, n) errors = np.zeros(n) for t in range(1, n): errors[t] = 0.7 * errors[t - 1] + np.random.normal(0, 1) y = 2.0 + 1.5 * x + errors X = sm.add_constant(x) # OLS with standard errors ols_model = sm.OLS(y, X).fit() # OLS with Newey-West standard errors nw_model = sm.OLS(y, X).fit(cov_type="HAC", cov_kwds={"maxlags": 5}) print("=== Standard Errors Comparison ===") print(f"OLS SE (slope): {ols_model.bse[1]:.4f}") print(f"Newey-West SE (slope): {nw_model.bse[1]:.4f}") print(f"Ratio: {nw_model.bse[1] / ols_model.bse[1]:.2f}x") print() print(f"OLS t-stat: {ols_model.tvalues[1]:.4f}") print(f"Newey-West t-stat: {nw_model.tvalues[1]:.4f}")

The Newey-West standard errors will typically be larger than the naive OLS standard errors when positive autocorrelation is present, leading to smaller t-statistics. The number of lags to include in the correction (the bandwidth) can be set manually or determined by automatic selection rules like the Newey-West (1994) plug-in estimator.

Adding Lagged Variables

If autocorrelation in the residuals comes from an omitted lagged dependent variable, adding it as a regressor can eliminate the problem. This is essentially fitting an autoregressive distributed lag model:

[ Y_t = \alpha + \beta X_t + \gamma Y_{t-1} + \epsilon_t ]

If the residuals from the original regression ( Y_t = \alpha + \beta X_t + \epsilon_t ) were autocorrelated because ( Y_t ) depends on its own past, including ( Y_{t-1} ) absorbs this dependence and the new residuals should be approximately white noise. Check the ACF of the new residuals to confirm.

Differencing

For non-stationary series with strong positive autocorrelation (the slow-decay ACF pattern), differencing is often the right remedy. First differencing transforms ( X_t ) into ( \Delta X_t = X_t - X_{t-1} ), which is stationary for many economic and financial series. Stock prices are non-stationary but returns (the first difference of log prices) are stationary. GDP in levels is non-stationary but GDP growth (the first difference) is stationary.

Don't over-difference. If the series is already stationary, differencing introduces artificial negative autocorrelation at lag 1. Check stationarity with the augmented Dickey-Fuller test before differencing.

ARIMA Models

When autocorrelation is a feature of the data rather than a nuisance, ARIMA (AutoRegressive Integrated Moving Average) models capture it explicitly. An ARIMA(p, d, q) model combines p autoregressive terms, d orders of differencing, and q moving average terms.

from statsmodels.tsa.arima.model import ARIMA np.random.seed(42) n = 500 # Generate an AR(2) process errors = np.random.normal(0, 1, n) y = np.zeros(n) for t in range(2, n): y[t] = 0.6 * y[t - 1] - 0.2 * y[t - 2] + errors[t] series = pd.Series(y) # Fit ARIMA(2,0,0) which is equivalent to AR(2) arima_model = ARIMA(series, order=(2, 0, 0)).fit() print("=== ARIMA(2,0,0) Results ===") print(f"AR(1) coefficient: {arima_model.params['ar.L1']:.4f} (true: 0.6)") print(f"AR(2) coefficient: {arima_model.params['ar.L2']:.4f} (true: -0.2)") print(f"AIC: {arima_model.aic:.2f}") print(f"BIC: {arima_model.bic:.2f}") print() # Check residuals for remaining autocorrelation lb_resid = acorr_ljungbox(arima_model.resid, lags=[10], return_df=True) print("=== Ljung-Box Test on Residuals ===") print(f"p-value at lag 10: {lb_resid['lb_pvalue'].values[0]:.4f}") print(f"Conclusion: {'Residuals still autocorrelated' if lb_resid['lb_pvalue'].values[0] < 0.05 else 'Residuals appear white noise'}")

The estimated AR coefficients should be close to the true values (0.6 and -0.2). The Ljung-Box test on the model residuals should show a large p-value, confirming that the ARIMA model has captured the autocorrelation structure and the residuals are approximately white noise.

Use the ACF and PACF plots from earlier to guide your choice of p and q. Alternatively, fit several candidate models and compare them using AIC or BIC - lower values indicate a better balance between fit and complexity.


Autocorrelation in Financial Returns

This section covers one of the most important empirical facts in quantitative finance: returns themselves show very little autocorrelation, but transformations of returns - particularly squared returns - show a great deal.

Raw Returns Are Nearly Uncorrelated

For liquid stocks and indices at daily frequency, the autocorrelation of returns is very close to zero. This is consistent with weak-form market efficiency: if past returns reliably predicted future returns, traders would act on the pattern until it vanished. Studies consistently find that the first-order autocorrelation of daily returns for major indices is typically between -0.05 and +0.05 - statistically insignificant or economically tiny.

There are exceptions. Illiquid assets (small caps, emerging market stocks, certain fixed-income instruments) can show meaningful positive autocorrelation because slow information diffusion and thin trading cause prices to adjust gradually. At very high frequencies, microstructure effects like the bid-ask bounce create negative autocorrelation. And at monthly horizons, the momentum effect represents small but persistent positive autocorrelation.

Squared Returns Show Strong Autocorrelation

Here's where it gets interesting. While ( r_t ) shows almost no autocorrelation, ( r_t^2 ) and ( |r_t| ) show strong, slowly decaying positive autocorrelation. A large squared return today predicts a large squared return tomorrow. This is volatility clustering - the empirical observation that volatile periods and calm periods tend to persist.

import numpy as np import pandas as pd import matplotlib.pyplot as plt from statsmodels.graphics.tsaplots import plot_acf np.random.seed(42) n = 2000 # Simulate returns with GARCH(1,1) volatility clustering returns = np.zeros(n) sigma2 = np.zeros(n) sigma2[0] = 0.0001 omega, alpha, beta = 0.000002, 0.08, 0.90 for t in range(1, n): sigma2[t] = omega + alpha * returns[t - 1] ** 2 + beta * sigma2[t - 1] returns[t] = np.sqrt(sigma2[t]) * np.random.normal() returns_series = pd.Series(returns * 100) squared_returns = returns_series ** 2 fig, axes = plt.subplots(1, 2, figsize=(13, 4)) plot_acf(returns_series.dropna(), lags=30, ax=axes[0], alpha=0.05) axes[0].set_title("ACF of Returns") axes[0].set_xlabel("Lag") axes[0].set_ylabel("Autocorrelation") plot_acf(squared_returns.dropna(), lags=30, ax=axes[1], alpha=0.05) axes[1].set_title("ACF of Squared Returns") axes[1].set_xlabel("Lag") axes[1].set_ylabel("Autocorrelation") plt.tight_layout() plt.savefig("returns_autocorrelation.png", dpi=150) plt.show()

The left panel will show the ACF of raw returns - nearly all bars within the confidence bands, confirming that returns themselves are approximately uncorrelated. The right panel tells a completely different story: the ACF of squared returns shows large, slowly decaying positive autocorrelation extending out to 20+ lags. Large absolute returns are followed by more large absolute returns.

This pattern is one of the "stylised facts" of financial returns documented across virtually every asset class, market, and time period. It's the reason GARCH models exist - they capture this autocorrelation in the conditional variance.

Implications for Quant Strategies

The near-zero autocorrelation of raw returns means simple linear forecasting models (predicting tomorrow's return from today's return) won't work well for liquid assets. The returns themselves are close to unpredictable from their own history.

But the strong autocorrelation of squared returns creates opportunities:

  • Volatility forecasting. Because squared returns are autocorrelated, you can forecast future volatility from past volatility. This feeds into option pricing, risk management, and position sizing.
  • Volatility trading. If you can forecast volatility better than the market's implied volatility, you can trade variance swaps, straddles, or VIX futures profitably.
  • Dynamic position sizing. In a momentum strategy, adjusting position size inversely with forecasted volatility (volatility scaling) improves risk-adjusted returns precisely because volatility is predictable.

Frequently Asked Questions

What is autocorrelation in simple terms?

Autocorrelation measures how much a value in a time series is related to its own past values. If today's observation helps you predict tomorrow's, the series has autocorrelation. Positive autocorrelation means the series tends to continue in the same direction - highs follow highs, lows follow lows. Negative autocorrelation means the series tends to reverse - a high value is likely followed by a low one. A series with no autocorrelation is unpredictable from its own history. In everyday terms, think of the weather: today's temperature is a strong predictor of tomorrow's temperature. That predictability is autocorrelation.

What is the difference between ACF and PACF?

The autocorrelation function (ACF) measures the total correlation between a time series and its lagged values, including indirect effects through intermediate lags. The partial autocorrelation function (PACF) measures only the direct correlation at each lag, stripping out the contribution of all intermediate lags. For example, if ( X_t ) depends on ( X_{t-1} ) which depends on ( X_{t-2} ), the ACF at lag 2 captures both the direct and indirect links, while the PACF at lag 2 captures only the direct link. In practice, the ACF is used to identify MA model orders (it cuts off sharply after lag q for an MA(q) process), while the PACF is used to identify AR model orders (it cuts off after lag p for an AR(p) process). You typically examine both plots together when selecting time series models.

What does the Durbin-Watson test tell you?

The Durbin-Watson test detects first-order autocorrelation in regression residuals. It produces a statistic between 0 and 4. A value of 2 means no autocorrelation. Values below 2 indicate positive autocorrelation (residuals tend to have the same sign as the previous residual), and values above 2 indicate negative autocorrelation (residuals tend to flip sign). As a practical rule, values between 1.5 and 2.5 are usually acceptable. The main limitation is that it only tests for lag-1 autocorrelation. If you suspect higher-order serial correlation, use the Ljung-Box or Breusch-Godfrey tests instead.

Can a series have both autocorrelation and heteroscedasticity?

Yes, and in finance this is the norm rather than the exception. Stock returns show very little autocorrelation in the returns themselves, but strong autocorrelation in squared returns - which is exactly what heteroscedasticity (specifically, conditional heteroscedasticity) looks like. Volatility clustering means that periods of high variance follow periods of high variance. GARCH models address both features simultaneously: they model the conditional variance as a function of past squared returns and past variances. If you detect autocorrelation in squared residuals but not in raw residuals, that's a classic sign of ARCH effects and a signal to consider a GARCH specification.

How do you choose the number of lags to test?

For the ACF and PACF plots, displaying 20 to 40 lags is standard for most time series. For daily financial data, 20 lags (about one trading month) is a reasonable starting point. For monthly data, you might extend to 24 or 36 lags to capture annual seasonal patterns. For the Ljung-Box test, common choices are ( m = 10 ) or ( m = 20 ) for non-seasonal data, and ( m = 2s ) (where s is the seasonal period) for seasonal data. More lags give you a broader test but reduce statistical power for any single lag. There's no single correct answer - the choice depends on your data frequency, sample size, and what kind of dependence structure you're looking for.

Does autocorrelation mean a series is non-stationary?

Not necessarily. A stationary AR(1) process has strong autocorrelation at lag 1, but it's perfectly stationary as long as the coefficient is between -1 and 1. What autocorrelation patterns can signal, however, is non-stationarity. If the ACF shows very slow decay - bars that remain large even at lags 10, 15, 20 - that's a strong indication of a unit root, meaning the series is non-stationary and needs to be differenced. A stationary series has an ACF that decays to zero relatively quickly (exponentially for AR processes). So while autocorrelation is consistent with stationarity, the pattern of autocorrelation in the ACF plot helps you diagnose whether the series is stationary or not. Always confirm with a formal unit root test like the augmented Dickey-Fuller test if you're uncertain.

Want to go deeper on Autocorrelation: What It Is & How to Test for It 2026?

This article covers the essentials, but there's a lot more to learn. Inside Quantt, you'll find hands-on coding exercises, interactive quizzes, and structured lessons that take you from fundamentals to production-ready skills — across 50+ courses in technology, finance, and mathematics.

Free to get started · No credit card required