Time-Varying Cointegration Test based on Bierens and Martins (2010) with Bootstrap Tests from Martins (2016)
Project description
tvcoint: Time-Varying Cointegration Analysis in Python
A comprehensive Python library implementing the time-varying cointegration framework of Bierens and Martins (2010) from Econometric Theory.
Overview
The tvcoint package provides tools for testing whether cointegrating relationships in multivariate time series are time-invariant (standard Johansen cointegration) or time-varying. The methodology allows cointegrating vectors to change smoothly over time using Chebyshev polynomial approximations.
Key Features
- Time-Varying VECM Estimation: Estimate vector error correction models where cointegrating vectors evolve over time via Chebyshev time polynomials
- Likelihood Ratio Test: Test H₀ (time-invariant cointegration) vs. H₁ (time-varying cointegration)
- Bootstrap Tests (NEW): Wild and i.i.d. bootstrap tests from Martins (2016) with better finite-sample properties
- Asymptotic Chi-Square Distribution: Under H₀, the test statistic follows χ²(mkr)
- Standard Johansen Analysis: Full implementation of Johansen (1988, 1991) as a special case
- Critical Values: Asymptotic and Monte Carlo simulated critical values
- PPP Application: Specialized functions for Purchasing Power Parity testing
Installation
From PyPI (recommended)
pip install tvcoint
From Source
git clone https://github.com/merwanroudane/tvcoint.git
cd tvcoint
pip install -e .
Dependencies
- Python ≥ 3.8
- NumPy ≥ 1.20
- SciPy ≥ 1.7
- pandas ≥ 1.3
- statsmodels ≥ 0.13
- matplotlib ≥ 3.4
- tabulate ≥ 0.8
Quick Start
Basic Time-Varying Cointegration Test
import numpy as np
import tvcoint
# Simulate cointegrated data
Y = tvcoint.simulate_cointegrated_system(T=200, k=2, r=1, seed=42)
# Test for time-varying cointegration
# H0: Time-invariant cointegration (m=0)
# H1: Time-varying cointegration (m>0)
result = tvcoint.lr_test_tv_cointegration(
Y,
p=2, # VAR lag order
r=1, # Cointegration rank
m=2, # Chebyshev polynomial order
include_intercept=True
)
# Print formatted results
print(result)
Output
======================================================================
Time-Varying Cointegration Test
Bierens and Martins (2010)
======================================================================
Test Configuration:
Sample size (T) : 200
Number of variables (k) : 2
Cointegration rank (r) : 1
Chebyshev order (m) : 2
VAR lag order (p) : 2
Test Results:
LR Test Statistic : 3.4521
Degrees of Freedom : 4
P-value : 0.4853
Critical Values:
10% level : 7.7794
5% level : 9.4877
1% level : 13.2767
Conclusion:
Fail to reject H0 at 5% level
Evidence supports TIME-INVARIANT cointegration
======================================================================
Detailed Usage
1. Chebyshev Time Polynomials
The cointegrating vectors are modeled as:
βₜ = Σᵢ₌₀ᵐ ξᵢ Pᵢ,ₜ(t)
where Pᵢ,ₜ(t) are Chebyshev time polynomials defined as:
- P₀,ₜ(t) = 1
- Pᵢ,ₜ(t) = √2 cos(iπ(t - 0.5)/T), for i ≥ 1
import tvcoint
import numpy as np
# Generate Chebyshev polynomial matrix
T = 100
m = 3 # Order
P = tvcoint.chebyshev_polynomial_matrix(T, m)
# Verify orthonormality: (1/T) Σₜ Pᵢ(t)Pⱼ(t) = δᵢⱼ
is_orthonormal = tvcoint.verify_orthonormality(P)
print(f"Orthonormality verified: {is_orthonormal}")
2. Standard Johansen VECM (m = 0)
import tvcoint
# Load or simulate data
Y = tvcoint.simulate_cointegrated_system(T=200, k=3, r=1)
# Select lag order using information criteria
best_lag = tvcoint.select_lag_order(Y, max_lag=8, criterion='bic')
print(f"Selected lag order: {best_lag}")
# Estimate standard VECM
vecm = tvcoint.JohansenVECM(Y, p=best_lag, r=1)
vecm.fit()
# Get estimated parameters
print("Eigenvalues:", vecm.eigenvalues)
print("Alpha (adjustment):\n", vecm.alpha)
print("Beta (cointegrating vectors):\n", vecm.beta)
# Trace test for cointegration rank
test_results = tvcoint.johansen_trace_test(Y, p=best_lag)
print(test_results)
3. Time-Varying VECM (m > 0)
import tvcoint
# Simulate time-varying cointegrated data
Y_tv = tvcoint.simulate_tv_cointegrated_system(
T=300, k=2, r=1, m=2, seed=42
)
# Estimate time-varying VECM
tv_vecm = tvcoint.TimeVaryingVECM(Y_tv, p=2, r=1, m=2)
tv_vecm.fit()
# Get time-varying cointegrating vectors
beta_t = tv_vecm.get_time_varying_beta() # Shape: (T, k, r)
# Plot evolution of cointegrating coefficients
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
for i in range(tv_vecm.k):
plt.plot(beta_t[:, i, 0], label=f'β_{i+1}(t)')
plt.xlabel('Time')
plt.ylabel('Coefficient Value')
plt.title('Time-Varying Cointegrating Vector')
plt.legend()
plt.show()
# Test for time-invariance
variation = tv_vecm.test_time_invariance()
print(f"Variation ratio: {variation['variation_ratio']:.4f}")
4. LR Test with Multiple m Values
import tvcoint
# Test across multiple Chebyshev orders
results = tvcoint.multiple_m_test(
Y, p=2, r=1,
m_values=[1, 2, 3, 4, 5],
alpha=0.05,
correction='bonferroni'
)
for m, res in results.items():
print(f"m={m}: LR={res.test_statistic:.3f}, p={res.p_value:.4f}")
5. Sequential Testing
# Sequential test (stops at first non-rejection)
result, m_selected = tvcoint.sequential_test(
Y, p=2, r=1,
m_max=5,
alpha=0.05
)
print(f"Selected m: {m_selected}")
6. PPP Application
Testing Purchasing Power Parity with time-varying cointegration:
import pandas as pd
import tvcoint
# Load PPP data: [ln(S), ln(P_domestic), ln(P_foreign)]
# S = nominal exchange rate, P = price indices
data = pd.read_csv('ppp_data.csv')
Y = data[['log_exchange', 'log_price_us', 'log_price_uk']].values
# Test PPP with time-varying cointegration
result = tvcoint.test_ppp_application(
Y,
p=2,
m=3,
domestic_col=1,
foreign_col=2
)
print(result)
7. Simulation Studies
import tvcoint
import numpy as np
# Size simulation under H0
def simulate_size(T, k, r, m, n_rep=1000, alpha=0.05):
rejections = 0
for i in range(n_rep):
# Simulate under H0 (time-invariant)
Y = tvcoint.simulate_cointegrated_system(T=T, k=k, r=r, seed=i)
result = tvcoint.lr_test_tv_cointegration(Y, p=2, r=r, m=m)
if result.p_value < alpha:
rejections += 1
return rejections / n_rep
# Run simulation
empirical_size = simulate_size(T=200, k=2, r=1, m=2)
print(f"Empirical size (nominal 5%): {empirical_size:.3f}")
# Power simulation under H1
def simulate_power(T, k, r, m, omega=0.5, n_rep=1000, alpha=0.05):
rejections = 0
for i in range(n_rep):
# Simulate under H1 (time-varying)
Y = tvcoint.simulate_tv_cointegrated_system(
T=T, k=k, r=r, m=m, omega=omega, seed=i
)
result = tvcoint.lr_test_tv_cointegration(Y, p=2, r=r, m=m)
if result.p_value < alpha:
rejections += 1
return rejections / n_rep
power = simulate_power(T=200, k=2, r=1, m=2, omega=0.5)
print(f"Empirical power: {power:.3f}")
8. Critical Values
import tvcoint
# Asymptotic critical values (χ² distribution)
cv_5pct = tvcoint.asymptotic_critical_value(m=2, k=2, r=1, alpha=0.05)
print(f"5% asymptotic CV: {cv_5pct:.4f}")
# Monte Carlo simulated critical values (for small samples)
simulated_cvs = tvcoint.simulate_null_distribution(
T=100, k=2, r=1, m=2,
n_simulations=10000,
alpha_levels=[0.10, 0.05, 0.01]
)
print(f"Simulated CVs: {simulated_cvs}")
# Size-adjusted critical values
cv_adjusted = tvcoint.get_size_adjusted_critical_value(
T=100, k=2, r=1, m=2, alpha=0.05
)
print(f"Size-adjusted CV: {cv_adjusted:.4f}")
# Bootstrap p-value
p_bootstrap = tvcoint.bootstrap_p_value(
Y, p=2, r=1, m=2,
observed_statistic=5.5,
n_bootstrap=1000
)
print(f"Bootstrap p-value: {p_bootstrap:.4f}")
9. Bootstrap Tests for TVC (Martins, 2016)
The bootstrap tests provide better finite-sample size properties compared to the asymptotic chi-square test, especially when sample size is small or when there is conditional heteroskedasticity.
import numpy as np
import tvcoint
# Generate data
Y, _ = tvcoint.simulate_cointegrated_system(T=200, k=2, r=1, seed=42)
# Wild Bootstrap Test (recommended under conditional heteroskedasticity)
result_wild = tvcoint.wild_bootstrap_tvc_test(
Y,
r=1, # Cointegration rank
m=2, # Chebyshev order
p=2, # Lag order
n_bootstrap=399, # Number of bootstrap replications
seed=123
)
print(result_wild)
# i.i.d. Bootstrap Test (Swensen, 2006)
result_iid = tvcoint.iid_bootstrap_tvc_test(
Y, r=1, m=2, p=2,
n_bootstrap=399,
seed=123
)
# Compare asymptotic and bootstrap results
comparison = tvcoint.compare_asymptotic_bootstrap(
Y, r=1, m=2, p=2,
n_bootstrap=399,
seed=456
)
print(f"Asymptotic p-value: {comparison['asymptotic']['p_value']:.4f}")
print(f"Wild bootstrap p-value: {comparison['wild_bootstrap']['p_value']:.4f}")
print(f"i.i.d. bootstrap p-value: {comparison['iid_bootstrap']['p_value']:.4f}")
# Bootstrap test for multiple m values
results = tvcoint.bootstrap_multiple_m_test(
Y, r=1, m_values=[1, 2, 3, 4, 5], p=2,
bootstrap_method='wild',
n_bootstrap=199,
bonferroni_correction=True
)
print(f"Minimum p-value: {results['min_p_value']:.4f} at m={results['min_p_value_m']}")
print(f"Bonferroni-corrected p-value: {results['bonferroni_p_value']:.4f}")
Bootstrap Methods
| Method | Description | When to Use |
|---|---|---|
| Wild Bootstrap | wild_bootstrap_tvc_test() |
Default choice; robust to conditional heteroskedasticity |
| i.i.d. Bootstrap | iid_bootstrap_tvc_test() |
Standard parametric bootstrap |
Residual Types
Both unrestricted (from TV-VECM) and restricted (from standard VECM) residuals can be used:
# Unrestricted residuals (default, recommended)
result_ur = tvcoint.wild_bootstrap_tvc_test(
Y, r=1, m=2, p=2,
residual_type='unrestricted'
)
# Restricted residuals (Cavaliere et al., 2012)
result_r = tvcoint.wild_bootstrap_tvc_test(
Y, r=1, m=2, p=2,
residual_type='restricted'
)
Reference: Martins, L.F. (2016). "Bootstrap tests for time varying cointegration." Econometric Reviews, DOI: 10.1080/07474938.2015.1092830
Mathematical Framework
Model Specification
The time-varying VECM(p) model is:
ΔYₜ = αβₜ'Yₜ₋₁ + Σⱼ₌₁ᵖ⁻¹ Γⱼ ΔYₜ₋ⱼ + εₜ, t = 1, ..., T
where:
Yₜ ∈ ℝᵏis a k-dimensional I(1) processαis the k×r matrix of adjustment coefficients (time-invariant)βₜis the k×r matrix of time-varying cointegrating vectorsΓⱼare k×k short-run coefficient matricesεₜ ~ i.i.d. Nₖ(0, Ω)
Chebyshev Approximation
The time-varying cointegrating vectors are modeled as:
βₜ = Σᵢ₌₀ᵐ ξᵢ Pᵢ,ₜ(t)
Orthonormality property: For all integers i, j:
(1/T) Σₜ₌₁ᵀ Pᵢ,ₜ(t) Pⱼ,ₜ(t) = δᵢⱼ
LR Test Statistic
The likelihood ratio test statistic (equation 6) is:
LR^{tvc} = T Σⱼ₌₁ʳ ln[(1 - λ̂₀,ⱼ) / (1 - λ̂ₘ,ⱼ)]
where:
λ̂₀,ⱼare eigenvalues from standard Johansen estimation (m=0)λ̂ₘ,ⱼare eigenvalues from TV-VECM estimation (m>0)
Asymptotic Distribution (Theorem 1)
Under H₀ (time-invariant cointegration):
LR^{tvc} →ᵈ χ²(mkr)
API Reference
Main Functions
| Function | Description |
|---|---|
lr_test_tv_cointegration(Y, p, r, m, ...) |
Perform LR test for time-varying cointegration |
bootstrap_tvc_test(Y, r, m, p, ...) |
Bootstrap test for TVC (Martins, 2016) |
wild_bootstrap_tvc_test(Y, r, m, p, ...) |
Wild bootstrap test for TVC |
iid_bootstrap_tvc_test(Y, r, m, p, ...) |
i.i.d. bootstrap test for TVC |
bootstrap_multiple_m_test(Y, r, m_values, ...) |
Bootstrap test for multiple m values |
compare_asymptotic_bootstrap(Y, r, m, p, ...) |
Compare asymptotic and bootstrap tests |
multiple_m_test(Y, p, r, m_values, ...) |
Test across multiple Chebyshev orders |
sequential_test(Y, p, r, m_max, ...) |
Sequential testing procedure |
test_ppp_application(Y, p, m, ...) |
PPP-specific test |
Classes
| Class | Description |
|---|---|
JohansenVECM |
Standard Johansen VECM estimation |
TimeVaryingVECM |
Time-varying VECM estimation |
TVCointegrationTestResult |
Asymptotic test results container |
BootstrapTVCTestResult |
Bootstrap test results container |
CriticalValueCache |
Cache for critical values |
Utility Functions
| Function | Description |
|---|---|
chebyshev_polynomial_matrix(T, m) |
Generate Chebyshev polynomial matrix |
construct_extended_y(Y, m) |
Build extended regressor Y^(m) |
simulate_cointegrated_system(...) |
Simulate TI cointegrated data |
simulate_tv_cointegrated_system(...) |
Simulate TV cointegrated data |
select_lag_order(Y, max_lag, criterion) |
VAR lag selection |
select_chebyshev_order(Y, p, r, m_max, ...) |
Chebyshev order selection |
Replication of Paper Results
Table 1: Power of the LR Test
import tvcoint
import numpy as np
# Replicate Table 1 from Bierens and Martins (2010)
def replicate_table1(T, m, n_rep=10000):
omega_values = [0, 0.01, 0.05, 0.1, 0.2, 0.5, 1.0]
results = {}
for omega in omega_values:
rejections = 0
for rep in range(n_rep):
# DGP from paper (Section 4.3)
Y = tvcoint.simulate_tv_cointegrated_system(
T=T, k=2, r=1, m=m, omega=omega, seed=rep
)
result = tvcoint.lr_test_tv_cointegration(Y, p=1, r=1, m=m)
if result.p_value < 0.05:
rejections += 1
results[omega] = rejections / n_rep
return results
# Run for T=100, m=1
results_100_m1 = replicate_table1(T=100, m=1)
print("T=100, m=1:", results_100_m1)
Citation
If you use this library in your research, please cite:
@article{bierens2010time,
title={Time-varying cointegration},
author={Bierens, Herman J and Martins, Luis F},
journal={Econometric Theory},
volume={26},
number={5},
pages={1453--1490},
year={2010},
publisher={Cambridge University Press},
doi={10.1017/S0266466609990648}
}
@article{martins2016bootstrap,
title={Bootstrap tests for time varying cointegration},
author={Martins, Luis F},
journal={Econometric Reviews},
year={2016},
doi={10.1080/07474938.2015.1092830}
}
@software{tvcoint,
author = {Roudane, Merwan},
title = {tvcoint: Time-Varying Cointegration Analysis in Python},
year = {2025},
url = {https://github.com/merwanroudane/tvcoint}
}
License
MIT License - see LICENSE file.
Author
Dr. Merwan Roudane
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Changelog
v1.1.0 (2025)
- NEW: Bootstrap tests for time-varying cointegration (Martins, 2016)
- Wild bootstrap test (
wild_bootstrap_tvc_test) - i.i.d. bootstrap test (
iid_bootstrap_tvc_test) - Support for unrestricted and restricted residuals
bootstrap_multiple_m_testfor testing multiple m valuescompare_asymptotic_bootstrapfor comparing methods
- Wild bootstrap test (
- Added
BootstrapTVCTestResultclass for bootstrap test results - Improved finite-sample size properties
v1.0.0 (2025)
- Initial release
- Full implementation of Bierens and Martins (2010)
- Chebyshev polynomial-based time-varying VECM
- LR test for time-varying cointegration
- Asymptotic and simulated critical values
- PPP application support
- Comprehensive documentation and examples
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 tvcoint-1.1.0.tar.gz.
File metadata
- Download URL: tvcoint-1.1.0.tar.gz
- Upload date:
- Size: 52.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb410b0146600684efc25cd2870e5f223fadc2e2dff7ed31a2ff6508139fcc01
|
|
| MD5 |
dd9654b87071cd9a6a431863c17f7425
|
|
| BLAKE2b-256 |
068b773d33ecbf313ac0c05a3c86c0abd23b7ecfb7e12a0c82df9fe614e30122
|
File details
Details for the file tvcoint-1.1.0-py3-none-any.whl.
File metadata
- Download URL: tvcoint-1.1.0-py3-none-any.whl
- Upload date:
- Size: 49.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2291fe4de95916c042e6c8719de0eabb40d8865c15f0e09b370c454b792f5ceb
|
|
| MD5 |
ccc3d4526d206739a41275be4666c4a0
|
|
| BLAKE2b-256 |
7ed0951f550fafd029b8e37b8020f1e5a57fe07fca879c68b2b39b1897074334
|