QFADF - Quantile Fourier ADF Unit Root Test
A Python implementation of the Quantile Fourier ADF unit root test proposed by Li & Zheng (2018), which is robust to both non-Gaussian conditions and smooth structural changes.
Reference
Li, H., & Zheng, C. (2018). Unit root quantile autoregression testing with smooth structural changes. Finance Research Letters, 25, 83-89.
DOI: 10.1016/j.frl.2017.10.008
Features
- Quantile Fourier ADF Test (
qr_fourier_adf): Unit root test at a specified quantile with Fourier approximation for structural changes - Bootstrap Critical Values (
qr_fourier_adf_bootstrap): Bootstrap procedure for finite-sample critical values - QKS and QCM Statistics (
qks_qcm_statistics): Quantile Kolmogorov-Smirnov and Cramér-von Mises tests over a range of quantiles - Optimal Frequency Selection (
estimate_optimal_k): Data-driven selection of Fourier frequency - Pre-computed Critical Values: Based on extensive Monte Carlo simulations
- Publication-ready Output: LaTeX tables and formatted results
Installation
From PyPI (when available)
pip install qfadf
From Source
git clone https://github.com/merwanroudane/quantilefourierunitroot.git
cd quantilefourierunitroot
pip install -e .
Dependencies
- Python >= 3.8
- NumPy >= 1.20.0
- Pandas >= 1.3.0
- SciPy >= 1.7.0
- Matplotlib >= 3.4.0 (optional, for plotting)
Quick Start
Basic Unit Root Test
import numpy as np
from qfadf import qr_fourier_adf
# Generate a random walk (unit root process)
np.random.seed(42)
y = np.cumsum(np.random.randn(200))
# Perform test at median (tau=0.5)
results = qr_fourier_adf(y, model=1, tau=0.5, k=3, pmax=8)
# Output:
# ======================================================================
# QUANTILE FOURIER ADF UNIT ROOT TEST
# Li & Zheng (2018, Finance Research Letters)
# ======================================================================
# Model: Constant
# Fourier frequency k: 3
# Lags (pmax): 8
# Sample size: 191
# ----------------------------------------------------------------------
# Test Results:
# ----------------------------------------------------------------------
# Quantile (τ): 0.500
# ρ(τ): 0.998xxx
# t_f(τ) statistic: -1.xxxx
# ----------------------------------------------------------------------
Bootstrap Critical Values
from qfadf import qr_fourier_adf_bootstrap
# Bootstrap for critical values (recommended for inference)
boot_results = qr_fourier_adf_bootstrap(
y,
model=1,
tau=0.5,
n_boot=1000,
random_state=42
)
# Access results
print(f"Test statistic: {boot_results['tn']:.4f}")
print(f"Bootstrap p-value: {boot_results['p_value']:.4f}")
print(f"Critical values (1%, 5%, 10%): {boot_results['cv']}")
print(f"Reject H0 at 5%: {boot_results['reject_5pct']}")
Multiple Quantiles Analysis
from qfadf import qr_fourier_adf, qks_qcm_statistics, multiple_quantile_results_table
# Test at multiple quantiles
tau_values = [0.1, 0.25, 0.5, 0.75, 0.9]
results_list = []
for tau in tau_values:
result = qr_fourier_adf(y, model=1, tau=tau, print_results=False)
results_list.append(result)
# Create comparison table
comparison_df = multiple_quantile_results_table(results_list)
print(comparison_df)
# QKS and QCM statistics
qks_qcm = qks_qcm_statistics(y, model=1, tau_range=(0.1, 0.9))
print(f"QKS_f: {qks_qcm['QKS_f']:.4f}")
print(f"QCM_f: {qks_qcm['QCM_f']:.4f}")
Optimal Fourier Frequency
from qfadf import estimate_optimal_k
# Estimate optimal k using residual sum of squares criterion
k_opt = estimate_optimal_k(y, model=1, tau=0.5, k_max=5)
print(f"Optimal Fourier frequency: k = {k_opt}")
Model Specifications
Model 1: Constant Only
$$y_t = \phi \tilde{y}_{t-1} + \alpha_0 + \alpha_k \sin(2\pi kt/T) + \beta_k \cos(2\pi kt/T) + \mu_t$$
Model 2: Constant and Trend
$$y_t = \phi \tilde{y}_{t-1} + \alpha_0 + \alpha_k \sin(2\pi kt/T) + \beta_k \cos(2\pi kt/T) + \gamma t + \mu_t$$
Test Statistics
t_f(τ) Statistic
The quantile t-ratio test statistic at quantile τ:
$$t_f(\tau) = \frac{\hat{f}(F^{-1}(\tau))}{\sqrt{\tau(1-\tau)}} (Y'{-1} M_x Y{-1})^{1/2} (\hat{\phi} - 1)$$
QKS_f Statistic
$$QKS_f = \sup_{\tau \in \mathcal{T}} |t_f(\tau)|$$
QCM_f Statistic
$$QCM_f = \int_{\tau \in \mathcal{T}} t_f(\tau)^2 d\tau$$
API Reference
Main Functions
| Function | Description |
|---|---|
qr_fourier_adf() |
Main test function for single quantile |
qr_fourier_adf_bootstrap() |
Bootstrap procedure for critical values |
qks_qcm_statistics() |
QKS and QCM tests over quantile range |
estimate_optimal_k() |
Optimal Fourier frequency selection |
Critical Values
| Function | Description |
|---|---|
get_critical_values() |
Get pre-computed critical values |
simulate_critical_values() |
Monte Carlo simulation for critical values |
print_critical_value_table() |
Print formatted critical value table |
Utilities
| Function | Description |
|---|---|
prepare_data() |
Data preprocessing |
adf_lag_selection() |
Automatic lag selection |
format_results_latex() |
Export results as LaTeX table |
plot_quantile_results() |
Visualization of results |
Parameters
| Parameter | Default | Description |
|---|---|---|
y |
- | Time series data (1D array) |
model |
1 | 1: constant, 2: constant + trend |
tau |
0.5 | Quantile level (0 < τ < 1) |
pmax |
8 | Maximum lag order for Δy |
k |
3 | Fourier frequency (1 ≤ k ≤ 5) |
n_boot |
1000 | Number of bootstrap replications |
Output
The test returns a dictionary with:
tn: Test statistic t_f(τ)rho_tau: Estimated AR coefficient ρ(τ)tau: Quantile levelmodel: Model specificationk: Fourier frequencyn: Effective sample sizecv: Critical values (if bootstrap)p_value: Bootstrap p-value (if bootstrap)reject_*pct: Decision at various significance levels
Citation
If you use this package in your research, please cite:
@article{li2018unit,
title={Unit root quantile autoregression testing with smooth structural changes},
author={Li, Haiqi and Zheng, Chaowen},
journal={Finance Research Letters},
volume={25},
pages={83--89},
year={2018},
publisher={Elsevier},
doi={10.1016/j.frl.2017.10.008}
}
Author
Dr Merwan Roudane
License
This project is licensed under the MIT License - see the LICENSE file for details.
Related Packages
- Original GAUSS code by Saban Nazlioglu (TSPDLIB)
- statsmodels - Standard ADF tests
- arch - Unit root tests with various specifications
Changelog
Version 1.0.0 (2025)
- Initial release
- Implementation of QR-Fourier-ADF test
- Bootstrap critical values
- QKS and QCM statistics
- Pre-computed critical value tables
- Comprehensive documentation
Metadata
Release files for qfadf 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 | |
|---|---|---|---|---|
| qfadf-1.0.0.tar.gz | 28.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qfadf-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.2 kB
Release files / qfadf-1.0.0.tar.gz
| Download URL | qfadf-1.0.0.tar.gz |
|---|---|
| Size | 28.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9905f70b67890179a6bbcf45a166d5e7af517df1bbb47e67a913a82f712717dd
|
|
BLAKE2b-256 checksum How to use checksums |
0b100b84ab92cb5c547fc9e38f08654830c65df8207cd3d93b60a0525f238f29
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / qfadf-1.0.0-py3-none-any.whl
| Download URL | qfadf-1.0.0-py3-none-any.whl |
|---|---|
| Size | 25.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4429a1cd9a6adc3bb9a3cfbcc79b979b5eb9e0eef0bf65741cf2801febb6787e
|
|
BLAKE2b-256 checksum How to use checksums |
f324e8bf2771d7dec4cc74bedb0019d1a5d48055b09ad608b23f9ccb6ee086b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Security for qfadf 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.