Skip to main content

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.

PyPI License Python


Author

Dr Merwan Roudane


Table of Contents

  1. Overview
  2. Installation
  3. Quick Start
  4. Tests Reference
  5. Models Reference
  6. Visualization
  7. Comparison Table
  8. Critical Values
  9. Core Utilities
  10. Academic References
  11. 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

  1. Balke, N.S. & Fomby, T.B. (1997). Threshold cointegration. International Economic Review, 38(3), 627-645.
  2. Enders, W. & Siklos, P.L. (2001). Cointegration and threshold adjustment. JBES, 19(2), 166-176.
  3. Lo, M.C. & Zivot, E. (2001). Threshold cointegration and nonlinear adjustment to the law of one price. Macroeconomic Dynamics, 5, 533-576.
  4. Hansen, B.E. & Seo, B. (2002). Testing for two-regime threshold cointegration in vector error-correction models. J. Econometrics, 110, 293-318.
  5. Bec, F., Ben Salem, M. & Carrasco, M. (2004). Tests for unit-root versus threshold specification. JBES, 22(4).
  6. Gonzalo, J. & Pitarakis, J.-Y. (2006). Threshold effects in cointegrating relationships. Oxford Bull. Econ. Stat., 68(s1), 813-833.
  7. Kapetanios, G., Shin, Y. & Snell, A. (2006). Testing for cointegration in nonlinear STAR ECM. Econometric Theory, 22(2), 279-303.
  8. Cook, S. (2007). A threshold cointegration test with increased power. Math. Comput. Simul., 73, 386-392.
  9. Li, J. & Lee, J. (2010). ADL tests for threshold cointegration. J. Time Ser. Anal., 31, 241-254.
  10. Krishnakumar, J. & Neto, D. (2015). Testing for the cointegration rank in threshold systems. Statistical Methodology, 26, 84-102.
  11. Li, J. (2016). System-equation ADL test for threshold cointegration. Oxford Bull. Econ. Stat.
  12. Wang, C., Chan, N. & Yau, C. (2016). Nonlinear error correction model and multiple-threshold cointegration. Statistica Sinica, 26, 1479-1498.
  13. Oh, D.-Y., Lee, H. & Meng, M. (2017). More powerful threshold cointegration tests. Empirical Economics.
  14. Schweikert, K. (2019). Testing for cointegration with threshold adjustment in the presence of structural breaks. SNDE.
  15. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

threshcoint-1.0.0.tar.gz (36.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

threshcoint-1.0.0-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

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

Hashes for threshcoint-1.0.0.tar.gz
Algorithm Hash digest
SHA256 def38220c4d619ab8162ca8a8f07e827ab7eefdef9e74fc909e634c17edd64e7
MD5 998219992d8e37ea67506c06cef60d06
BLAKE2b-256 ab6bb2b1df1cb5e4775c6e320d123bf3f6c6407969ae95e1bf454344a90952b6

See more details on using hashes here.

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

Hashes for threshcoint-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1c7878e55d55159a57b339bab8ed91ded39059a528fb5335ad5d7e4031f171a2
MD5 a7ac587d02c0e3cfcb8427e59fa848e4
BLAKE2b-256 6744dc3e008eec965c9f6ecd833ecc2c18b84bc0daa9cc5b242a4713e622f727

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page