Skip to main content

Cointegration analysis with I(1) and I(2) variables based on Haldrup (1994)

Project description

Haldrup: Cointegration Analysis with I(1) and I(2) Variables

PyPI version Python 3.8+ License: MIT

A Python implementation of the econometric methods from:

Haldrup, N. (1994). "The asymptotics of single-equation cointegration regressions with I(1) and I(2) variables." Journal of Econometrics, 63(1), 153-181.

Overview

This package provides tools for cointegration analysis when the underlying data-generating process contains both I(1) and I(2) variables. The key contributions include:

  • Critical values for residual-based cointegration tests (Table 1 from Haldrup 1994)
  • Cointegration regression with proper handling of mixed integration orders
  • Spurious regression diagnostics following Theorem 1
  • Unit root tests including tests for double unit roots (I(2))
  • Monte Carlo simulation for computing critical values

Installation

pip install haldrup

Or install from source:

git clone https://github.com/merwanroudane/haldrup.git
cd haldrup
pip install -e .

Quick Start

Basic Cointegration Test

import numpy as np
from haldrup import cointegration_regression, get_critical_value

# Generate example data
np.random.seed(42)
n = 100

# I(2) process
x2 = np.cumsum(np.cumsum(np.random.randn(n)))

# Cointegrated y (I(2) + I(0) error)
y = 2.0 * x2 + np.random.randn(n)

# Run cointegration regression
result = cointegration_regression(y, x2=x2)
print(result.summary())

Get Critical Values

from haldrup import get_critical_value, get_critical_values_table

# Get specific critical value
cv = get_critical_value(m1=1, m2=1, n=100, alpha=0.05)
print(f"5% critical value: {cv.critical_value}")

# Print full table
print(get_critical_values_table(m2=1))

Test for Cointegration

from haldrup import adf_test

# Compute residuals from your cointegration regression
residuals = result.residuals

# Perform ADF test with proper critical values
test_result = adf_test(residuals, m1=1, m2=1)
print(test_result.summary())

Determine Integration Order

from haldrup import determine_integration_order, generate_i2_process

# Generate an I(2) process
x = generate_i2_process(n=500, seed=42)

# Determine integration order
order = determine_integration_order(x)
print(f"Estimated integration order: {order}")

Theoretical Background

The Model (Haldrup 1994, Section 2)

The package handles the general regression model:

$$y_t = \hat{\beta}'_0 c_t + \hat{\beta}'1 x{1t} + \hat{\beta}'2 x{2t} + \hat{u}_t$$

where:

  • $c_t$ = deterministic components (constant, trend)
  • $x_{1t}$ = I(1) regressors (m₁ variables)
  • $x_{2t}$ = I(2) regressors (m₂ variables)

Key Results from Theorem 1 (pp. 159-161)

For the conditional model with integration order $d$:

Statistic d = 0 (full cointegration) d = 1 (partial) d = 2 (no cointegration)
$\hat{\beta}_1$ $O_p(n^{-1})$-consistent Nondegenerate Diverges $O_p(n)$
$\hat{\beta}_2$ $O_p(n^{-2})$-superconsistent $O_p(n^{-1})$-consistent Nondegenerate
F-test $\chi^2$ Diverges $O_p(n)$ Diverges $O_p(n)$
DW → 0 rate $O_p(n^{-3})$ → 0 rate $O_p(n^{-1})$ → 0 rate $O_p(n^{-1})$
→ 1 rate $O_p(n^{-3})$ → 1 rate $O_p(n^{-2})$ Nondegenerate

Critical Values (Table 1, p. 168)

The ADF test critical values depend on both m₁ (I(1) regressors) and m₂ (I(2) regressors). For large samples, critical values are similar for given m₁ + m₂, but for small samples, critical values become more negative as m₂ increases.

API Reference

Critical Values

from haldrup import get_critical_value, get_critical_values_table

# Get single critical value
cv = get_critical_value(m1, m2, n, alpha=0.05, deterministic="intercept")

# Get formatted table
table = get_critical_values_table(m2=1)

Cointegration Tests

from haldrup import adf_test, phillips_z_test, cointegration_test

# ADF test (Theorem 4)
result = adf_test(residuals, m1, m2, lags=None, deterministic="intercept")

# Phillips Z test
result = phillips_z_test(residuals, m1, m2, truncation=None)

# Unified interface
result = cointegration_test(residuals, m1, m2, method="adf")

Regression

from haldrup import cointegration_regression, polynomial_cointegration_regression

# Basic cointegration regression
result = cointegration_regression(y, x1=None, x2=x2, deterministic="c")

# Polynomial cointegration (with differences of I(2) variables)
result = polynomial_cointegration_regression(y, x2=x2, include_dx2=True)

Unit Root Tests

from haldrup import (
    adf_unit_root_test,
    hasza_fuller_test,
    double_unit_root_test,
    determine_integration_order
)

# Standard ADF test
result = adf_unit_root_test(y, deterministic="ct")

# Hasza-Fuller test for I(2)
result = hasza_fuller_test(y, deterministic="ct")

# Sequential testing for double unit root
test_i2, test_i1 = double_unit_root_test(y)

# Automatic integration order determination
order = determine_integration_order(y, max_order=2)

Diagnostics

from haldrup import durbin_watson, r_squared, spurious_regression_diagnostics

# Durbin-Watson statistic
dw = durbin_watson(residuals)

# R-squared
r2 = r_squared(y, y_fitted)

# Comprehensive spurious regression check
diagnostics = spurious_regression_diagnostics(y, y_fitted, k=2)
print(diagnostics.summary())

Simulation

from haldrup import (
    simulate_critical_values,
    generate_i1_process,
    generate_i2_process
)

# Generate processes
x1 = generate_i1_process(n=100, seed=42)
x2 = generate_i2_process(n=100, seed=42)

# Simulate critical values
result = simulate_critical_values(m1=1, m2=1, n=100, replications=10000)
print(result.summary())

Examples

Example 1: UK Money Demand (Section 5)

Replicating the empirical application from Haldrup (1994, pp. 169-173):

import numpy as np
from haldrup import (
    cointegration_regression,
    determine_integration_order,
    adf_test
)

# Load your data (m_t, p_t, y_t, R_t*)
# m_t and p_t are I(2), y_t and R_t* are I(1)

# Test integration orders
order_m = determine_integration_order(m)
order_p = determine_integration_order(p)
print(f"m_t integration order: {order_m}")
print(f"p_t integration order: {order_p}")

# Run cointegration regression
# y_t = m_t, x2 = p_t, x1 = [y_t, R_t*]
result = cointegration_regression(
    m,
    x1=np.column_stack([y, R]),
    x2=p.reshape(-1, 1),
    deterministic="ct"
)

print(result.summary())

Example 2: Detecting Spurious Regression

import numpy as np
from haldrup import (
    generate_i1_process,
    cointegration_regression,
    spurious_regression_diagnostics
)

np.random.seed(42)
n = 200

# Generate independent random walks
y = generate_i1_process(n)
x = generate_i1_process(n)

# Run regression (spurious!)
result = cointegration_regression(y, x1=x.reshape(-1, 1))

# Check for spurious regression
diag = spurious_regression_diagnostics(
    y, result.fitted_values, k=1
)
print(diag.summary())

# Note: Low DW + high R² = likely spurious!

Example 3: Monte Carlo Replication of Table 1

from haldrup import simulate_critical_values, get_critical_value

# Replicate Table 1 entry for m1=1, m2=1, n=100
simulated = simulate_critical_values(
    m1=1, m2=1, n=100,
    replications=10000,
    seed=42
)

# Compare with published values
table_cv = get_critical_value(m1=1, m2=1, n=100, alpha=0.05)

print(f"Table 1 (5%):   {table_cv.critical_value:.4f}")
print(f"Simulated (5%): {simulated.critical_values[0.05]:.4f}")

Citation

If you use this package in your research, please cite both the original paper and this implementation:

@article{haldrup1994asymptotics,
  title={The asymptotics of single-equation cointegration regressions with {I}(1) and {I}(2) variables},
  author={Haldrup, Niels},
  journal={Journal of Econometrics},
  volume={63},
  number={1},
  pages={153--181},
  year={1994},
  publisher={Elsevier}
}

@software{roudane2024haldrup,
  author = {Roudane, Merwan},
  title = {haldrup: Python Implementation of Haldrup (1994) Cointegration Methods},
  year = {2024},
  url = {https://github.com/merwanroudane/haldrup}
}

References

  • Haldrup, N. (1994). The asymptotics of single-equation cointegration regressions with I(1) and I(2) variables. Journal of Econometrics, 63(1), 153-181.

  • Phillips, P.C.B. and Ouliaris, S. (1990). Asymptotic properties of residual based tests for cointegration. Econometrica, 58(1), 165-193.

  • Engle, R.F. and Granger, C.W.J. (1987). Co-integration and error correction: Representation, estimation and testing. Econometrica, 55(2), 251-276.

  • Hasza, D.P. and Fuller, W.A. (1979). Estimation of autoregressive processes with unit roots. Annals of Statistics, 7(5), 1106-1120.

  • Dickey, D.A. and Pantula, S.G. (1987). Determining the order of differencing in autoregressive processes. Journal of Business and Economic Statistics, 5(4), 455-461.

License

MIT License - see LICENSE file.

Author

Dr Merwan Roudane

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Changelog

Version 0.0.1 (Initial Release)

  • Implementation of Table 1 critical values
  • ADF and Phillips Z cointegration tests
  • Cointegration regression with diagnostics
  • Unit root tests including Hasza-Fuller
  • Monte Carlo simulation for critical values
  • Comprehensive test suite

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

haldrup-0.0.1.tar.gz (41.4 kB view details)

Uploaded Source

Built Distribution

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

haldrup-0.0.1-py3-none-any.whl (42.6 kB view details)

Uploaded Python 3

File details

Details for the file haldrup-0.0.1.tar.gz.

File metadata

  • Download URL: haldrup-0.0.1.tar.gz
  • Upload date:
  • Size: 41.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for haldrup-0.0.1.tar.gz
Algorithm Hash digest
SHA256 d77052e6e7e19ad2366ca47e3d0007b6476627fdef8860ed895a54f95d894ac0
MD5 b67083099bfd7c493a35546f61195701
BLAKE2b-256 006337853e1fe227b8f3548a5258cbab8b385ee41174630b2e42bdd15715d017

See more details on using hashes here.

File details

Details for the file haldrup-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: haldrup-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 42.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for haldrup-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 92942aab6bd31feb1859978afbf9f46f154b4f178bec53402ab478220a3b6457
MD5 3d711f332c99df69ca64879a14e1db75
BLAKE2b-256 8e4ea6380b9a0079b41126fc461e395bc3e2554d3397e793e7ad880b8d4dcdc4

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