Comprehensive threshold cointegration tests and models in Python — TAR, MTAR, TVECM, supF, Hansen-Seo, and 12+ methods from the literature.
Project description
threshcoint
Comprehensive Threshold Cointegration Tests & Models in Python
All major methods from 12+ academic papers, 3 R packages, and original R code — unified in one library.
Author
Dr Merwan Roudane
Table of Contents
- Overview
- Installation
- Quick Start
- Tests Reference
- Enders-Siklos TAR/MTAR
- GLS-MTAR (Cook 2007)
- Extended E-S (Osińska & Gałecki 2022)
- Covariates-Augmented (Oh et al. 2017)
- Balke-Fomby Sup-Wald
- ADL-BDM (Li & Lee 2010)
- ADL-BO (Li & Lee 2010)
- System ADL (Li 2016)
- supF* with Breaks (Schweikert 2019)
- Hansen-Seo supLM
- KSS Nonlinear Cointegration
- BBC Unit Root vs SETAR
- Models Reference
- Visualization
- Comparison Table
- Critical Values
- Core Utilities
- Academic References
- License
Overview
threshcoint is a pure-Python library that implements every major threshold cointegration test and model from the econometrics literature. It consolidates methods from:
| Source | Methods Included |
|---|---|
| Balke & Fomby (1997) | EQ-TAR, Band-TAR, RD-TAR, sup-Wald test |
| Enders & Siklos (2001) | TAR / MTAR cointegration tests (Φ, F_asy, t_max) |
| Lo & Zivot (2001) | Bivariate TVECM testing & estimation |
| Gonzalo & Pitarakis (2006) | Threshold effects in cointegrating regressions |
| Cook (2007) | GLS-MTAR test with increased power |
| Li & Lee (2010) | ADL-BDM and ADL-BO tests |
| Li (2016) | System-equation ADL test |
| Krishnakumar & Neto (2015) | Cointegration rank in TVECM |
| Wang, Chan & Yau (2016) | Multiple-threshold cointegration |
| Oh, Lee & Meng (2017) | Covariates-augmented TAR/MTAR |
| Schweikert (2019) | supF* with structural breaks (from ZIP archive) |
| Osińska & Gałecki (2022) | Extended Enders-Siklos test |
| tsDyn R package | Hansen-Seo supLM, Seo sup-Wald, BBC test, TVECM |
| NonlinearTSA R package | Enders-Granger 1998, KSS 2006, ESTAR ECM, MTAR ECM, SETAR |
Key Features
- ✅ 12+ threshold cointegration tests with tabulated critical values
- ✅ 7 model classes (TAR, MTAR, EQ-TAR, Band-TAR, RD-TAR, SETAR, TVECM)
- ✅ No bootstrap required for most tests (asymptotic critical values provided)
- ✅ Grid search for unknown thresholds with sup-type statistics
- ✅ Publication-quality dark-themed visualizations
- ✅ Comparison tables — run all tests on your data in one line
- ✅ Pure NumPy/SciPy — no R dependency
Installation
# From GitHub
pip install git+https://github.com/merwanroudane/threshcoint.git
# Local install (development)
cd thrshcoint
pip install -e ".[full]"
# Minimal (no plotting)
pip install -e .
Dependencies
| Package | Required | Purpose |
|---|---|---|
numpy>=1.20 |
✅ Yes | Core computation |
scipy>=1.7 |
✅ Yes | Statistical distributions |
matplotlib>=3.4 |
⬜ Optional | Visualization |
tabulate>=0.8 |
⬜ Optional | Pretty tables |
pandas>=1.3 |
⬜ Optional | Data handling |
Quick Start
import numpy as np
import threshcoint as tc
# Generate example cointegrated data with threshold adjustment
np.random.seed(42)
T = 500
e = np.zeros(T)
for t in range(1, T):
if e[t-1] > 0.5:
e[t] = -0.4 * e[t-1] + np.random.normal(0, 0.5)
elif e[t-1] < -0.5:
e[t] = -0.8 * e[t-1] + np.random.normal(0, 0.5)
else:
e[t] = e[t-1] + np.random.normal(0, 0.5)
x = np.cumsum(np.random.normal(0, 1, T))
y = x + e
# Run Enders-Siklos MTAR test
result = tc.enders_siklos_test(y, x, model="mtar")
result.summary()
# Run ALL tests at once and compare
results = tc.comparison_table(y, x)
# Visualize regimes
tc.plot_regime_diagram(result.regression["resid"], result.threshold, model="mtar")
Tests Reference
1. Enders & Siklos (2001) — TAR/MTAR Test
The foundational threshold cointegration test.
Equation (TAR):
Δê_t = ρ₁·I_t·ê_{t-1} + ρ₂·(1-I_t)·ê_{t-1} + Σγⱼ·Δê_{t-j} + ε_t
where I_t = 1{ê_{t-1} ≥ τ}
Equation (MTAR):
Same but M_t = 1{Δê_{t-1} ≥ τ}
Hypotheses:
- H₀: ρ₁ = ρ₂ = 0 (no cointegration)
- H₁: at least one ρ ≠ 0 (threshold cointegration)
- Symmetry test: H₀: ρ₁ = ρ₂
Syntax
result = tc.enders_siklos_test(
y, # array: dependent variable (I(1))
x, # array: independent variable(s) (I(1))
model="mtar", # str: "tar" or "mtar"
threshold=0.0, # float: threshold value τ
max_lag=8, # int: maximum augmentation lag
criterion="aic", # str: "aic" or "bic" for lag selection
case="c", # str: "nc", "c", or "ct"
)
Output
| Attribute | Description |
|---|---|
result.phi_stat |
Φ statistic = (t²_ρ₁ + t²_ρ₂) / 2 |
result.rho1 |
Adjustment coefficient ρ₁ (above threshold) |
result.rho2 |
Adjustment coefficient ρ₂ (below threshold) |
result.t_rho1 |
t-statistic for ρ₁ |
result.t_rho2 |
t-statistic for ρ₂ |
result.f_asymmetry |
F-statistic for H₀: ρ₁ = ρ₂ |
result.lags |
Selected lag order |
result.cv |
Critical values {0.01, 0.05, 0.10} |
result.conclusion |
Text: reject/fail-to-reject at 5% |
result.regime_obs |
(n₁, n₂) observations per regime |
Example
result = tc.enders_siklos_test(y, x, model="mtar", threshold=0.0)
print(f"Φ = {result.phi_stat}, ρ₁ = {result.rho1}, ρ₂ = {result.rho2}")
print(f"Asymmetry F = {result.f_asymmetry}")
print(result.conclusion)
2. GLS-MTAR (Cook 2007)
Higher power than standard MTAR via GLS local-to-unity detrending.
Syntax
result = tc.gls_mtar_test(
y, x,
threshold=0.0, # float: MTAR threshold
max_lag=8, # int: max lag
case="c", # str: "c" (c̄=-7) or "ct" (c̄=-13.5)
criterion="aic", # str: lag selection criterion
cbar=None, # float or None: custom c̄ value
)
Output
| Attribute | Description |
|---|---|
result.phi_gls_stat |
GLS-detrended Φ* statistic |
result.cv_5pct |
Interpolated 5% critical value for sample size T |
Example
result = tc.gls_mtar_test(y, x, case="c")
print(f"Φ*_GLS = {result.phi_gls_stat}, CV(5%) = {result.cv_5pct}")
3. Extended Enders-Siklos (Osińska & Gałecki 2022)
Uses individual variables (not ECM residual) as threshold variable. Splits both short-run and long-run.
Syntax
result = tc.extended_enders_siklos_test(
y, x,
threshold_var=None, # array or None (default: Δx)
model="mtar", # str: "tar" or "mtar"
max_lag=8,
criterion="aic",
trim=0.15, # float: trimming for grid search
)
Output
| Attribute | Description |
|---|---|
result.sup_phi_stat |
Supremum Φ over the grid |
result.estimated_threshold |
Optimal threshold from grid search |
4. Covariates-Augmented (Oh, Lee & Meng 2017)
Augments E-S testing equation with Δx (stationary covariates) for power gains.
Syntax
result = tc.covariates_augmented_test(
y, x,
model="mtar", # str: "tar" or "mtar"
threshold=0.0,
max_lag=8,
criterion="aic",
)
5. Balke & Fomby (1997) Sup-Wald
Two-step: (1) Engle-Granger, (2) sup-Wald for threshold behavior.
Syntax
result = tc.balke_fomby_supwald(
y, x,
max_lag=4,
trim=0.15,
n_grid=300, # int: grid search resolution
)
Output
| Attribute | Description |
|---|---|
result.sup_wald |
Sup-Wald statistic |
result.estimated_threshold |
Optimal threshold |
result.eg_stat |
Engle-Granger ADF statistic (step 1) |
result.grid_stats |
Array of Wald stats over grid |
result.grid_values |
Threshold grid values |
6. ADL-BDM (Li & Lee 2010)
Cointegrating vector NOT pre-specified. Uses percentile-based grid search.
Syntax
result = tc.adl_bdm_test(
y, x,
max_lag=4,
trim=0.15,
n_grid=200,
case="c", # str: "c" or "ct"
)
7. ADL-BO (Li & Lee 2010)
Boswijk variant: tests joint significance of lagged regressand AND lagged conditioning variables.
Syntax
result = tc.adl_bo_test(
y, x,
max_lag=4,
trim=0.15,
n_grid=200,
case="c",
)
8. System ADL (Li 2016)
System-equation test. No weak exogeneity required. Detects asymmetric speeds AND roles.
Syntax
result = tc.system_adl_test(
data, # (T, k) array: multivariate data
lag=1,
trim=0.15,
n_grid=200,
case="c",
)
9. supF* with Structural Breaks (Schweikert 2019)
Threshold cointegration robust to structural breaks. Python translation of supF.r from the ZIP archive.
Syntax
result = tc.supF_test(
y, x,
model="tar", # str: "tar" or "mtar"
breaktype=1, # int: 1=none, 2=intercept, 3=trend, 4=slope
max_lag=4,
threshold=0.0, # float: TAR threshold
u=None, # float: MTAR percentile (e.g. 0.5)
trim=0.15,
criterion="aic",
)
Break Types
| Value | Type | Model |
|---|---|---|
| 1 | No break | Standard E-S |
| 2 | C₀ (intercept shift) | y = μ + DU·δ + α'x + e |
| 3 | C/T (trend shift) | y = μ + DU·δ + trend + α'x + e |
| 4 | C/S (slope shift) | y = μ + DU·δ + DU·x·δ₂ + α'x + e |
Output
| Attribute | Description |
|---|---|
result.f_star |
supF* statistic |
result.breakpoint |
Estimated break date (index) |
result.rho1, result.rho2 |
Regime-specific adjustment coefficients |
10. Hansen & Seo (2002) supLM
Linear VECM vs. threshold VECM test. Python translation of TVECM.HStest from tsDyn.
Syntax
result = tc.hansen_seo_test(
data, # (T, 2) array
lag=1,
beta=None, # float or None: cointegrating coefficient
trim=0.05,
n_grid=300,
nboot=0, # int: bootstrap replications (0 = asymptotic)
)
Output
| Attribute | Description |
|---|---|
result.supLM_stat |
Sup-LM statistic |
result.estimated_threshold |
Optimal threshold for ECT |
result.grid_stats |
LM values over the grid |
11. KSS (2006) Nonlinear Cointegration
ESTAR-based cointegration test using cubic transformation. From NonlinearTSA package.
Syntax
result = tc.kss_cointegration_test(
y, x,
case=1, # int: 1=raw, 2=demeaned, 3=detrended
max_lag=8,
criterion="aic",
)
12. BBC (2004) Unit Root vs SETAR
Tests unit root null against stationary three-regime SETAR. From tsDyn package.
Syntax
result = tc.bbc_test(
y, # array: univariate series
m=1, # int: AR lag order
trim=0.10,
test_type="Wald", # str: "Wald", "LM", or "LR"
)
Models Reference
TARModel
model = tc.TARModel(threshold=0.0)
result = model.fit(residuals, max_lag=4, criterion="aic")
print(result.rho1, result.rho2, result.phi_stat)
MTARModel
model = tc.MTARModel(threshold=0.0)
result = model.fit(residuals, max_lag=4)
EQ_TAR
model = tc.EQ_TAR(threshold=None) # None = grid search
result = model.fit(residuals, max_lag=4, trim=0.15, n_grid=300)
print(result.rho_low, result.rho_mid, result.rho_high)
print(result.regime_obs) # [n_low, n_mid, n_high]
BandTAR
model = tc.BandTAR(threshold=0.5)
result = model.fit(residuals)
RD_TAR
model = tc.RD_TAR(threshold=None)
result = model.fit(residuals)
print(result.drift_low, result.drift_mid, result.drift_high)
SETAR
model = tc.SETAR(nthresh=1, delay=1, trim=0.15)
result = model.fit(y, lag=2, n_grid=300)
print(result.threshold, result.coefficients)
TVECM
model = tc.TVECM(nthresh=1, lag=1, trim=0.05, beta=None)
result = model.fit(data, n_grid=300) # data shape (T, 2)
print(result.threshold, result.beta)
print(result.regime_obs)
# Access equation-by-equation regressions:
print(result.regressions["eq1"]["coef"])
Visualization
Regime Diagram
import threshcoint as tc
result = tc.enders_siklos_test(y, x, model="mtar")
tc.plot_regime_diagram(
residuals=result.regression["resid"],
threshold=result.threshold,
model="mtar",
title="MTAR Regime Classification"
)
Grid Search Plot
result = tc.balke_fomby_supwald(y, x)
tc.plot_threshold_grid_search(
grid_values=result.grid_values,
grid_stats=result.grid_stats,
title="Sup-Wald Grid Search"
)
TVECM Regimes
model = tc.TVECM(lag=1)
result = model.fit(data)
tc.plot_tvecm_regimes(
ect=result.ect,
data=data,
threshold=result.threshold
)
Results Table
result = tc.gls_mtar_test(y, x)
tc.results_table(result)
Running All Tests at Once
import threshcoint as tc
# Run all tests and display comparison table
results = tc.comparison_table(y, x)
# Or manually select tests:
r1 = tc.enders_siklos_test(y, x, model="tar")
r2 = tc.enders_siklos_test(y, x, model="mtar")
r3 = tc.gls_mtar_test(y, x)
r4 = tc.covariates_augmented_test(y, x)
tc.summary_table({
"TAR": r1,
"MTAR": r2,
"GLS-MTAR": r3,
"Covariates-MTAR": r4,
})
Critical Values
All critical values are tabulated in threshcoint.critical_values:
from threshcoint.critical_values import (
ES_TAR_PHI, # Enders-Siklos TAR
ES_MTAR_PHI, # Enders-Siklos MTAR
GLS_MTAR_PHI, # Cook GLS-MTAR (by sample size)
ADL_BDM_CV, # Li & Lee ADL-BDM
ADL_BO_CV, # Li & Lee ADL-BO
SUPF_BREAK_CV, # Schweikert supF* with breaks
BBC_CV, # BBC unit root vs SETAR
KSS_COINT_CV, # KSS nonlinear cointegration
COVAUG_TAR_CV, # Oh et al. covariates-augmented TAR
COVAUG_MTAR_CV, # Oh et al. covariates-augmented MTAR
get_gls_mtar_cv, # Interpolation function
)
# Example: get 5% critical value for GLS-MTAR with T=200
cv = get_gls_mtar_cv(T=200, case="c", sig=0.05)
Core Utilities
from threshcoint import adf_test, pp_test, engle_granger_test
# ADF test
r = adf_test(y, max_lag=12, case="c", criterion="aic")
print(r["stat"], r["cv"])
# Phillips-Perron test
r = pp_test(y, case="c")
# Engle-Granger cointegration
r = engle_granger_test(y, x, case="c")
print(r["stat"], r["cv"], r["coint_vec"])
Utility Functions
from threshcoint.utils import (
ols, # OLS regression → dict with coef, resid, se, tstat, etc.
embed, # Time-delay embedding (like R's embed)
lag_matrix, # Build lag matrix
gls_detrend, # GLS local-to-unity detrending
heaviside_tar, # TAR indicator: I(z ≥ τ)
heaviside_mtar, # MTAR indicator: I(Δz ≥ τ)
heaviside_band, # Band-TAR: 3-regime indicator
)
Academic References
- Balke, N.S. & Fomby, T.B. (1997). Threshold cointegration. International Economic Review, 38(3), 627-645.
- Enders, W. & Siklos, P.L. (2001). Cointegration and threshold adjustment. JBES, 19(2), 166-176.
- Lo, M.C. & Zivot, E. (2001). Threshold cointegration and nonlinear adjustment to the law of one price. Macroeconomic Dynamics, 5, 533-576.
- Hansen, B.E. & Seo, B. (2002). Testing for two-regime threshold cointegration in vector error-correction models. J. Econometrics, 110, 293-318.
- Bec, F., Ben Salem, M. & Carrasco, M. (2004). Tests for unit-root versus threshold specification. JBES, 22(4).
- Gonzalo, J. & Pitarakis, J.-Y. (2006). Threshold effects in cointegrating relationships. Oxford Bull. Econ. Stat., 68(s1), 813-833.
- Kapetanios, G., Shin, Y. & Snell, A. (2006). Testing for cointegration in nonlinear STAR ECM. Econometric Theory, 22(2), 279-303.
- Cook, S. (2007). A threshold cointegration test with increased power. Math. Comput. Simul., 73, 386-392.
- Li, J. & Lee, J. (2010). ADL tests for threshold cointegration. J. Time Ser. Anal., 31, 241-254.
- Krishnakumar, J. & Neto, D. (2015). Testing for the cointegration rank in threshold systems. Statistical Methodology, 26, 84-102.
- Li, J. (2016). System-equation ADL test for threshold cointegration. Oxford Bull. Econ. Stat.
- Wang, C., Chan, N. & Yau, C. (2016). Nonlinear error correction model and multiple-threshold cointegration. Statistica Sinica, 26, 1479-1498.
- Oh, D.-Y., Lee, H. & Meng, M. (2017). More powerful threshold cointegration tests. Empirical Economics.
- Schweikert, K. (2019). Testing for cointegration with threshold adjustment in the presence of structural breaks. SNDE.
- Osińska, M. & Gałecki, J. (2022). Extended Enders and Siklos test for threshold cointegration. Statistical Review, 69(1), 1-20.
License
MIT License. Copyright (c) 2025 Dr Merwan Roudane.
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 threshcoint-1.0.0.tar.gz.
File metadata
- Download URL: threshcoint-1.0.0.tar.gz
- Upload date:
- Size: 36.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
def38220c4d619ab8162ca8a8f07e827ab7eefdef9e74fc909e634c17edd64e7
|
|
| MD5 |
998219992d8e37ea67506c06cef60d06
|
|
| BLAKE2b-256 |
ab6bb2b1df1cb5e4775c6e320d123bf3f6c6407969ae95e1bf454344a90952b6
|
File details
Details for the file threshcoint-1.0.0-py3-none-any.whl.
File metadata
- Download URL: threshcoint-1.0.0-py3-none-any.whl
- Upload date:
- Size: 32.6 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 |
1c7878e55d55159a57b339bab8ed91ded39059a528fb5335ad5d7e4031f171a2
|
|
| MD5 |
a7ac587d02c0e3cfcb8427e59fa848e4
|
|
| BLAKE2b-256 |
6744dc3e008eec965c9f6ecd833ecc2c18b84bc0daa9cc5b242a4713e622f727
|