BoundedTest: GLS-based Unit Root Tests for Bounded Processes
A Python implementation of unit root tests for bounded time series based on Carrion-i-Silvestre and Gadea (2013).
Overview
boundedtest provides comprehensive tools for testing unit roots in time series that are constrained within bounds. The package implements:
- GLS-detrending with bound-specific non-centrality parameter κ̅(c,c̄)
- OLS-detrending for comparison
- M-type test statistics: MZα, MSB, and MZt
- Parametric and non-parametric long-run variance estimation
- Critical values tailored to different bound configurations
Reference
This package implements the methodology from:
Carrion-i-Silvestre, J.L. and Gadea, M.D. (2013). "GLS-based unit root tests for bounded processes." Economics Letters, 120(2), 184-187.
Installation
pip install boundedtest
Or install from source:
git clone https://github.com/merwanroudane/boundedtest.git
cd boundedtest
pip install -e .
Quick Start
import numpy as np
from boundedtest import bounded_unit_root_test
# Generate bounded data
np.random.seed(42)
data = np.cumsum(np.random.randn(200))
data = np.clip(data, -10, 10) # Apply bounds
# Test for unit root with GLS-BOUNDS method (recommended)
result = bounded_unit_root_test(
data=data,
bounds=(-10, 10),
statistic='mz_alpha',
detrending='gls_bounds',
lrv_method='np'
)
print(result)
Main Features
1. Detrending Methods
'ols': Standard OLS detrending'gls_ers': GLS detrending with standard κ = -7 (Elliott et al., 1996)'gls_bounds': GLS detrending with bound-specific κ̅(c,c̄) (recommended)
2. Test Statistics
- MZα: Modified Phillips-Perron statistic
- MSB: Modified Sargan-Bhargava statistic
- MZt: Modified t-statistic
3. LRV Estimation
- Non-parametric (
'np'): Newey-West with automatic bandwidth selection - Parametric (
'ar'): AR-based with MAIC lag selection (Ng & Perron, 2001)
Examples
Example 1: Basic Usage
import numpy as np
from boundedtest import bounded_unit_root_test
# Generate data
np.random.seed(123)
T = 200
data = np.cumsum(np.random.randn(T))
bounds = (-5, 5)
data = np.clip(data, bounds[0], bounds[1])
# Run test
result = bounded_unit_root_test(
data=data,
bounds=bounds,
detrending='gls_bounds'
)
print(result)
print(f"\nReject H0 at 5%: {result.reject_5pct}")
Example 2: Compare All Test Statistics
results = bounded_unit_root_test(
data=data,
bounds=bounds,
statistic='all', # Compute all statistics
detrending='gls_bounds'
)
# Results is a dictionary
for stat_name, result in results.items():
print(f"\n{stat_name}:")
print(f" Statistic: {result.statistic:.4f}")
print(f" Critical (5%): {result.critical_values['5%']:.4f}")
print(f" Reject H0: {result.reject_5pct}")
Example 3: Compare Detrending Methods
methods = ['ols', 'gls_ers', 'gls_bounds']
for method in methods:
result = bounded_unit_root_test(
data=data,
bounds=bounds,
statistic='mz_alpha',
detrending=method
)
print(f"\n{method.upper()}:")
print(f" MZα = {result.statistic:.4f}")
print(f" Reject H0 = {result.reject_5pct}")
Example 4: With Pandas DataFrame
import pandas as pd
# Create DataFrame
df = pd.DataFrame({
'date': pd.date_range('2020-01-01', periods=200, freq='D'),
'series': data
})
# Test using the series
result = bounded_unit_root_test(
data=df['series'],
bounds=bounds,
detrending='gls_bounds'
)
Example 5: Unemployment Rate (0-100% bounded)
# Unemployment rate bounded between 0 and 100
unemployment = np.random.uniform(3, 10, size=100) # Example data
unemployment += np.cumsum(np.random.randn(100)) * 0.2
result = bounded_unit_root_test(
data=unemployment,
bounds=(0, 100),
detrending='gls_bounds'
)
Understanding Results
The output includes:
- Test Statistic Value: The computed test statistic
- Critical Values: At 1%, 5%, and 10% significance levels
- Rejection Decision: Whether to reject the unit root null hypothesis
- Bounds Information: Original bounds and estimated c-parameters
- Non-centrality Parameter (κ̅): Used in GLS detrending
- LRV Estimate: Estimated long-run variance
Interpretation
- MZα and MZt: Left-tail tests. Reject H₀ if statistic < critical value.
- MSB: Right-tail test. Reject H₀ if statistic > critical value.
- H₀: Series has a unit root (is I(1))
- H₁: Series is stationary (is I(0))
Advanced Usage
Generating Bounded Processes
from boundedtest.regulated_ou import generate_bounded_ar1
# Generate bounded AR(1) process
data = generate_bounded_ar1(
T=200,
bounds=(-5, 5),
rho=1.0, # Unit root
sigma=1.0,
burnin=100,
seed=42
)
Custom Critical Values via Simulation
from boundedtest.regulated_ou import compute_critical_values
# Compute critical values for specific bounds
cv = compute_critical_values(
c_lower=-0.5,
c_upper=0.5,
kappa=0,
n_sim=10000,
alpha=0.05
)
print(cv)
Accessing Individual Components
from boundedtest import (
ols_detrend,
gls_detrend,
compute_mz_alpha,
estimate_lrv_np,
get_kappa
)
# Manual detrending
y_tilde, _, _ = ols_detrend(data)
# Compute LRV
from boundedtest.statistics import compute_ar1_residuals
residuals = compute_ar1_residuals(y_tilde)
s2 = estimate_lrv_np(residuals)
# Compute statistic
mz_alpha = compute_mz_alpha(y_tilde, s2)
API Reference
Main Function
bounded_unit_root_test(
data, # array-like: Time series data
bounds, # tuple: (lower_bound, upper_bound)
statistic='mz_alpha', # str: Test statistic to compute
detrending='gls_bounds', # str: Detrending method
lrv_method='np', # str: LRV estimation method
deterministics='constant' # str: Deterministic components
) -> BoundedTestResult
Monte Carlo Simulations
The package includes utilities for Monte Carlo experiments:
from boundedtest.regulated_ou import simulate_bounded_process
# Simulate under H0
data_h0 = simulate_bounded_process(
T=200,
b_lower=-5,
b_upper=5,
alpha=1.0, # Unit root
sigma=1.0
)
# Simulate under H1
data_h1 = simulate_bounded_process(
T=200,
b_lower=-5,
b_upper=5,
alpha=0.95, # Stationary
sigma=1.0
)
Requirements
- Python >= 3.8
- NumPy >= 1.20.0
- SciPy >= 1.7.0
- Pandas >= 1.3.0
- Statsmodels >= 0.13.0
Citation
If you use this package in your research, please cite:
@article{carrion2013gls,
title={GLS-based unit root tests for bounded processes},
author={Carrion-i-Silvestre, Josep Llu{\'\i}s and Gadea, Mar{\'\i}a Dolores},
journal={Economics Letters},
volume={120},
number={2},
pages={184--187},
year={2013},
publisher={Elsevier}
}
License
This project is licensed under the MIT License - see the LICENSE file for details.
Author
Merwan Roudane
Email: merwanroudane920@gmail.com
GitHub: @merwanroudane
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Acknowledgments
This implementation is based on the methodology developed by Josep Lluís Carrion-i-Silvestre and María Dolores Gadea. The original MATLAB code and methodological guidance were instrumental in developing this Python package.
See Also
- Original paper: Economics Letters (2013)
- Elliott, Rothenberg & Stock (1996): "Efficient Tests for an Autoregressive Unit Root"
- Ng & Perron (2001): "Lag Length Selection and the Construction of Unit Root Tests"
- Cavaliere (2005): "Limited Time Series with a Unit Root"
Metadata
Release files for boundedtest 1.0.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 | |
|---|---|---|---|---|
| boundedtest-1.0.0.tar.gz | 28.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| boundedtest-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.6 kB
Release files / boundedtest-1.0.0.tar.gz
| Download URL | boundedtest-1.0.0.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
89d74cb4bd95057f2cc84ca8b6006b5d884f144f2afab546fbcd80b45297d770
|
|
BLAKE2b-256 checksum How to use checksums |
45851b7d5f71069eda9a965a25cb19d893ea77645f758730c636d50dd6749728
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / boundedtest-1.0.0-py3-none-any.whl
| Download URL | boundedtest-1.0.0-py3-none-any.whl |
|---|---|
| Size | 24.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2110ac6292ca630cd3d89d01b99c6f4e961c4c8a9defd61ff0f47f8b856a3ce4
|
|
BLAKE2b-256 checksum How to use checksums |
0cfb3beb07103633711fb7feb575d4297717d41061772e65d73d4ba2d90684ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Security for boundedtest 1.0.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.