urvol: Unit Root Tests for Time Series with Non-Stationary Volatility
A comprehensive Python library implementing unit root tests robust to non-stationary volatility, based on the seminal papers:
-
Cavaliere & Taylor (2008): "Bootstrap Unit Root Tests for Time Series with Nonstationary Volatility", Econometric Theory, 24, 43-71.
-
Cavaliere & Taylor (2007): "Testing for unit roots in time series models with non-stationary volatility", Journal of Econometrics, 140, 919-947.
Features
- Wild Bootstrap Tests: Robust to heteroskedasticity via wild bootstrap methodology
- Simulation-Based Tests: Uses estimated variance profiles for critical value simulation
- M Statistics: MZa, MZt, and MSB unit root tests with local GLS detrending
- Volatility Models: Built-in models for single/multiple breaks, trending, smooth transitions
- Critical Values: Automated generation for any variance profile
- Publication-Ready: Designed for academic research with full documentation
Installation
pip install urvol
Or install from source:
git clone https://github.com/merwanroudane/urvol.git
cd urvol
pip install -e .
Quick Start
Wild Bootstrap Test
import numpy as np
from urvol import wild_bootstrap_test
# Generate data with volatility break
T = 200
np.random.seed(42)
sigma = np.where(np.arange(T+1) < 100, 1.0, 0.5)
errors = np.random.normal(0, sigma[:-1])
X = np.concatenate([[0], np.cumsum(errors)])
# Perform wild bootstrap test
results = wild_bootstrap_test(X, statistic="MZa", N=999)
print(f"Statistic: {results['statistic']:.3f}")
print(f"p-value: {results['p_value']:.3f}")
print(f"Reject at 5%: {results['reject_05']}")
Simulation-Based Test
from urvol import simulation_based_test
# Perform simulation-based test
results = simulation_based_test(X, statistic="MZa", N=10000)
print(f"Statistic: {results['statistic']:.3f}")
print(f"Critical value (5%): {results['critical_value']:.3f}")
print(f"Reject: {results['reject']}")
Variance Profile Estimation
from urvol import estimate_variance_profile
import matplotlib.pyplot as plt
# Estimate variance profile
eta_hat = estimate_variance_profile(X)
# Plot estimated profile
s_grid = np.linspace(0, 1, 100)
plt.plot(s_grid, eta_hat(s_grid), label='Estimated η(s)')
plt.plot(s_grid, s_grid, '--', label='Homoskedastic')
plt.xlabel('s')
plt.ylabel('η(s)')
plt.legend()
plt.show()
Methodological Background
The Problem
Standard unit root tests (ADF, PP, etc.) assume homoskedastic errors. However, many economic and financial time series exhibit:
- Volatility breaks (e.g., Great Moderation, COVID-19)
- Trending volatility (changing uncertainty over time)
- Smooth volatility transitions
Under non-stationary volatility, standard tests can be severely size-distorted, leading to unreliable inference.
The Solution
This library implements two complementary approaches:
1. Wild Bootstrap (Cavaliere & Taylor 2008)
The wild bootstrap preserves heteroskedasticity in resampled data:
u*_t = û_t × w_t, w_t ~ iid N(0,1)
This yields asymptotically valid tests for a wide class of volatility processes without requiring a parametric specification.
2. Simulation-Based Tests (Cavaliere & Taylor 2007)
Estimates the variance profile η(s) and simulates critical values from the appropriate limiting distribution:
η(s) = (ω²)^{-1} ∫₀ˢ ω(r)² dr
Provides asymptotically similar tests for any bounded volatility process.
API Reference
Main Functions
wild_bootstrap_test(X, statistic="MZa", trend="c", N=999, ...)
Wild bootstrap unit root test robust to non-stationary volatility.
Parameters:
X: Time series data (T+1,) arraystatistic: "MZa", "MZt", or "MSB"trend: "c" (constant) or "ct" (constant + trend)N: Number of bootstrap replications
Returns: Dictionary with statistic, p-value, critical values, rejection decisions
simulation_based_test(X, statistic="MZa", trend="c", N=10000, ...)
Simulation-based test using estimated variance profile.
Parameters:
X: Time series dataN: Number of simulations for critical valuesT_sim: Grid size for Brownian motion simulation
Returns: Dictionary with results and estimated variance profile
estimate_variance_profile(X, trend="c", method="diff")
Estimate the variance profile η(s).
Returns: Callable function η̂(s) on [0,1]
Volatility Models
from urvol.volatility_models import (
single_break,
double_break,
trending_volatility,
smooth_transition,
)
# Single break at τ=0.3 with δ=3
omega = single_break(tau=0.3, delta=3.0)
# Evaluate volatility at specific points
s = np.linspace(0, 1, 100)
sigma = omega(s)
Critical Values
from urvol import get_critical_value, generate_critical_value_table
# Get homoskedastic critical value
cv = get_critical_value("MZa", trend="c", alpha=0.05)
# Generate table for specific variance profile
omega = single_break(tau=0.5, delta=3.0)
eta = lambda s: np.where(s < 0.5, s/0.55, (s-0.45)/0.55)
cv_table = generate_critical_value_table(eta, N=50000)
Examples
Example 1: Producer Price Inflation
Replicating the empirical application from Cavaliere & Taylor (2007):
import pandas as pd
from urvol import wild_bootstrap_test, estimate_variance_profile
# Load data (Stock-Watson database)
data = pd.read_csv("PWFSA.csv")
X = data['inflation'].values
# Estimate variance profile
eta_hat = estimate_variance_profile(X, trend="c")
# Perform tests
boot_results = wild_bootstrap_test(X, statistic="MSB", N=999)
print(f"MSB Bootstrap p-value: {boot_results['p_value']:.3f}")
Example 2: Monte Carlo Simulation
Evaluating test size and power:
from urvol import wild_bootstrap_test
from urvol.volatility_models import single_break
import numpy as np
def monte_carlo_size(T=200, tau=0.8, delta=3.0, N_mc=1000, N_boot=499):
"""Compute empirical size under H0: α=1."""
rejections = 0
omega = single_break(tau=tau, delta=delta)
for _ in range(N_mc):
# Generate data under unit root with volatility break
sigma = omega(np.linspace(0, 1, T+1))
errors = np.random.normal(0, sigma[:-1])
X = np.concatenate([[0], np.cumsum(errors)])
# Test
results = wild_bootstrap_test(X, N=N_boot)
rejections += results['reject_05']
return rejections / N_mc
size = monte_carlo_size()
print(f"Empirical size: {size:.3f}")
Theory and Asymptotic Results
Theorem 1 (Limiting Distributions under Heteroskedasticity)
Under non-stationary volatility ω(s), the M statistics converge to:
MZa → 0.5(B̃²_η(1) - B̃²_η(0) - 1) / ∫₀¹ B̃²_η(s)ds
where B̃_η|Z is the projection of the variance-transformed Brownian motion.
Theorem 2 (Consistency of Variance Profile Estimator)
sup_{s∈[0,1]} |η̂(s) - η(s)| →_p 0
Theorem 3 (Bootstrap Validity)
The wild bootstrap statistics satisfy:
MZa* →_p MZa^{c,p,η} (in probability)
ensuring asymptotically correct inference.
Testing
Run the test suite:
pytest tests/
With coverage:
pytest --cov=urvol tests/
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Citation
If you use this library in your research, please cite:
@article{cavaliere2008bootstrap,
title={Bootstrap unit root tests for time series with nonstationary volatility},
author={Cavaliere, Giuseppe and Taylor, A.M. Robert},
journal={Econometric Theory},
volume={24},
number={1},
pages={43--71},
year={2008},
publisher={Cambridge University Press}
}
@article{cavaliere2007testing,
title={Testing for unit roots in time series models with non-stationary volatility},
author={Cavaliere, Giuseppe and Taylor, A.M. Robert},
journal={Journal of Econometrics},
volume={140},
number={2},
pages={919--947},
year={2007},
publisher={Elsevier}
}
@software{urvol2024,
author = {Roudane, Merwan},
title = {urvol: Unit Root Tests for Non-Stationary Volatility},
year = {2024},
url = {https://github.com/merwanroudane/urvol}
}
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Dr Merwan Roudane
- Email: merwanroudane920@gmail.com
- GitHub: @merwanroudane
Acknowledgments
This library implements the methodology developed by Giuseppe Cavaliere and A.M. Robert Taylor. All credit for the theoretical contributions goes to the original authors.
References
Cavaliere, G., Taylor, A.M.R. (2008). "Bootstrap Unit Root Tests for Time Series with Nonstationary Volatility". Econometric Theory 24, 43-71.
Cavaliere, G., Taylor, A.M.R. (2007). "Testing for unit roots in time series models with non-stationary volatility". Journal of Econometrics 140, 919-947.
Elliott, G., Rothenberg, T.J., Stock, J.H. (1996). "Efficient Tests for an Autoregressive Unit Root". Econometrica 64, 813-836.
Ng, S., Perron, P. (2001). "Lag Length Selection and the Construction of Unit Root Tests with Good Size and Power". Econometrica 69, 1519-1554.
Metadata
Release files for urvol 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| urvol-1.1.0.tar.gz | 22.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| urvol-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.5 kB
Release files / urvol-1.1.0.tar.gz
| Download URL | urvol-1.1.0.tar.gz |
|---|---|
| Size | 22.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6e352e0d2e11161bd89aaa0e2bfd9e6855c0ec2110cfff659f1112d42da540cf
|
|
BLAKE2b-256 checksum How to use checksums |
2ae58d407b9900b2f648947536b63d262cec1c0e7e988787643884269f82c325
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Release files / urvol-1.1.0-py3-none-any.whl
| Download URL | urvol-1.1.0-py3-none-any.whl |
|---|---|
| Size | 22.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ce45b023bcacf1d1154b66bf60c4aa65f92d5a1a1a52d81df03ffc223dc3f8cf
|
|
BLAKE2b-256 checksum How to use checksums |
033fd2beb73fd279dc664d0b2c7accbace29a0fab7507ffe57733c2ed86dd2b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Security for urvol 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.