Skip to content

How to Check Financial Returns for Dependence and Breaks

Original question

How do I test financial time series for autocorrelation, heteroskedasticity, and structural breaks before building forecasting models?
Inspect the time plot and rolling summaries, fit a simple baseline, and diagnose its residuals. Use the Ljung–Box test for serial correlation, the ARCH LM test for dependence in squared residuals, and a stability test such as CUSUM for changes in a regression's parameters. Run diagnostics within the training window and check the forecast impact on later data.

Separate dependence, changing variance and parameter breaks

For residuals ete_t, the Ljung–Box statistic over mm lags uses the estimated autocorrelations ρ^k\hat\rho_k:

Q=n(n+2)∑k=1mρ^k2n−k.Q=n(n+2)\sum_{k=1}^m\frac{\hat\rho_k^2}{n-k}.
Its large-sample reference distribution uses degrees of freedom adjusted for fitted ARMA orders when appropriate. The ARCH LM test regresses et2e_t^2 on a constant and its past mm squared values, then checks whether the lag coefficients are jointly zero. The common LM statistic is the auxiliary sample size times its R2R^2, with the usual asymptotic qualifications. ARCH LM targets conditional variance dependence. A Breusch–Pagan test answers a different question about variance explained by specified covariates.

An OLS-residual CUSUM standardises cumulative residuals and looks for excursions from the range expected under parameter stability. For a known break date, a regression with post-event indicators and interactions gives interpretable estimates of intercept and slope changes. Selecting a date after inspecting the same series changes the testing problem. An unknown-break test and error assumptions that match the data are important.

Suppose a training-window benchmark gives Ljung–Box p-values of 0.35 on residuals and 0.002 on squared residuals. Its ARCH LM p-value is 0.006, and the rolling mean is stable while the rolling variance rises sharply during several episodes. A conditional variance model is a reasonable candidate. If rolling volatility jumps once and stays high, compare it against a simpler variance-break specification. Those explanations imply different forecasts after another shock, so evaluate both over later windows.

A break can masquerade as persistent dependence. Suppose volatility is low for half the sample and high thereafter. The squared residuals are likely to cluster by regime even if they are independent within each regime. A significant ARCH test in that sample is a reason to investigate, not evidence that a single stationary recursion explains the whole period. Check whether the model fits both sides of a candidate break and whether the date was chosen on the training sample. If you look for the most dramatic date after seeing the data, account for that search in your interpretation.

Residual tests in Python

This synthetic series has a known change in mean and constant innovation variance. Try setting the shift to zero to compare the diagnostics.

import numpy as np import statsmodels.api as sm from statsmodels.stats.diagnostic import ( acorr_ljungbox, breaks_cusumolsresid, het_arch, ) rng = np.random.default_rng(18) returns = rng.normal(0, 1, 600) returns[300:] += 0.45 fit = sm.OLS(returns, np.ones((len(returns), 1))).fit() print(acorr_ljungbox(fit.resid, lags=[10, 20], model_df=0)) print("ARCH LM p-value:", het_arch(fit.resid, nlags=10)[1]) print("CUSUM p-value:", breaks_cusumolsresid(fit.resid, ddof=1)[1])

References and next steps