Variance Ratio Test
Calculate the Lo-MacKinlay Variance Ratio test for the random walk hypothesis.
The test compares the Variance of q-period (overlapping) returns, the sum of q consecutive returns, to q times the Variance of single-period returns. Under the random walk hypothesis these should be equal, giving a Variance Ratio of 1. A Variance Ratio above 1 with a significant (low) p-value indicates positive autocorrelation (momentum/trending behavior), while a Variance Ratio below 1 with a significant p-value indicates negative autocorrelation (mean-reversion).
The result holds two statistics. The homoskedastic z(q) assumes a constant volatility; daily returns cluster in volatility, and under such heteroskedasticity z(q) rejects the random walk too often. The heteroskedasticity-robust z*(q) of Lo and MacKinlay stays valid when volatility clusters and is the safer reading for returns. get_arch_lm_test shows whether a series has that volatility clustering.
The formula is as follows:
\[\operatorname{VR}(q) = \sigma ^{2} (q) / \sigma ^{2} (1),\;\; \text{with}\; \sigma ^{2} (1) = \operatorname{Σ}(\text{rₜ} - \mu) ^{2} / (n - 1) \text{and}\; \sigma ^{2} (q) = \operatorname{Σ}(\text{rₜ} + ... + \text{rₜ₋q₊₁} - q \cdot \mu) ^{2} / m \;\text{over the overlapping q-period sums},\;\; m = q \cdot (n - q + 1) \cdot (1 - q / n) \text{and}\; \mu \;\text{the mean return} (\text{the unbiased estimators of Lo}\; \text{\&} \;\text{MacKinlay}),\;\; q = 2 \;\text{by default}\] \[z(q) = (\operatorname{VR}(q) - 1) / \operatorname{√φ}(q),\;\; \text{with}\; \text{φ} (q) = 2 \cdot (2q - 1) \cdot (q - 1) / (3q \cdot n)\] \[z \cdot (q) = \sqrt{n} \cdot (\operatorname{VR}(q) - 1) / \sqrt{\theta} (q),\;\; \text{with}\; \theta (q) = \operatorname{Σ}(k = \text{1..q-1}) 4 \cdot (1 - k / q) ^{2} \cdot \operatorname{δ}(k) \text{and}\; \text{δ} (k) = n \cdot \operatorname{Σ}(t = k + 1..n) (\text{rₜ} - \mu) ^{2} \cdot (\text{rₜ₋ₖ} - \mu) ^{2} / (\operatorname{Σ}(t = 1..n) (\text{rₜ} - \mu) ^{2}) ^{2}\] \[\text{P-Value} = 2 \cdot (1 - \Phi(| z |)) \text{for both statistics},\;\; \text{with Phi the standard normal CDF}\]For more information about the method, see the following paper:
- Lo, A.W., & MacKinlay, A.C. (1988). “Stock Market Prices Do Not Follow Random Walks: Evidence from a Simple Specification Test.” Review of Financial Studies, 1(1), 41-66.
Also known as: Lo-MacKinlay test, VR test.
Variance Ratio Test in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_variance_ratio_test as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["XLE", "XLF", "XLK"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2021-01-01",
end_date="2025-12-31",
)
toolkit.econometrics.get_variance_ratio_test()
Or, after setting up the Finance Toolkit MCP, ask:
Did the energy, financials and technology sector ETFs (XLE, XLF and XLK) follow a random walk from 2021 to 2025, according to the variance ratio test on their daily returns?
Which returns:
| XLE | XLF | XLK | |
|---|---|---|---|
| Variance Ratio | 1.0249 | 1.0249 | 0.9611 |
| Variance Ratio Statistic | 0.8815 | 0.8805 | -1.3774 |
| P-Value | 0.3781 | 0.3786 | 0.1684 |
| Robust Variance Ratio Statistic | 0.6193 | 0.6256 | -0.9679 |
| Robust P-Value | 0.5358 | 0.5316 | 0.3331 |
Using Your Own Data
get_variance_ratio_test runs on any data, not only prices: ratios, economic indicators, yield curves or your own dataset. Pass a DataFrame, a Series or a dictionary of them to Econometrics as data, with the dates in the rows or the columns, and set changes to how its changes are calculated: "percentage", "log", "difference" for rates and ratios, or None when the data are changes already. For example, for the monthly unemployment rates of the United States and Germany:
from financetoolkit import Economics, Econometrics
economics = Economics(start_date="2000-01-01")
unemployment = economics.get_unemployment_rate(
countries=["United States", "Germany"], period="monthly"
)
econometrics = Econometrics(data=unemployment, changes="difference")
econometrics.get_variance_ratio_test()
Parameters
get_variance_ratio_test accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
period | str | The data frequency for returns (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”. | "weekly" |
within_period | bool | Whether to calculate the test within the specified period or for the entire period. Thus whether to look at the test within a specific year (if period = ‘yearly’) or look at the entirety of all years. Defaults to False. Note that this requires intraday data when period = ‘daily’, since a single day only nests observations when intraday data was fetched. | True |
q | int | The number of periods to sum returns over. Defaults to 2. | 4 |
include_benchmark | bool | Whether to include “Benchmark” among the assets tested. Defaults to False. | True |
rounding | int | None | The number of decimals to round the results to. Defaults to None. | 2 |