Unit Root Tests for Time Series with Non-Stationary Volatility
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file urvol-1.1.0.tar.gz.
File metadata
- Download URL: urvol-1.1.0.tar.gz
- Upload date:
- Size: 22.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e352e0d2e11161bd89aaa0e2bfd9e6855c0ec2110cfff659f1112d42da540cf
|
|
| MD5 |
e30264f9f5c4570b2eb38d56d6ab9929
|
|
| BLAKE2b-256 |
2ae58d407b9900b2f648947536b63d262cec1c0e7e988787643884269f82c325
|
File details
Details for the file urvol-1.1.0-py3-none-any.whl.
File metadata
- Download URL: urvol-1.1.0-py3-none-any.whl
- Upload date:
- Size: 22.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce45b023bcacf1d1154b66bf60c4aa65f92d5a1a1a52d81df03ffc223dc3f8cf
|
|
| MD5 |
0b5fcdd714df21299896348c41203c6d
|
|
| BLAKE2b-256 |
033fd2beb73fd279dc664d0b2c7accbace29a0fab7507ffe57733c2ed86dd2b1
|