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
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})$ |
| R² | → 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
- Email: merwanroudane920@gmail.com
- GitHub: merwanroudane
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
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 haldrup-0.0.2.tar.gz.
File metadata
- Download URL: haldrup-0.0.2.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d58e609943ca2bd8097c8795717d834540f35803fa4d31a055020480e86ca57
|
|
| MD5 |
c48d896ccacc2ee7098e0e843bce9da7
|
|
| BLAKE2b-256 |
1cab3aae24dac18d386cbb5c5b5c2e14f5b372d8dd3e9fe6e13f0a5744bcafc5
|
File details
Details for the file haldrup-0.0.2-py3-none-any.whl.
File metadata
- Download URL: haldrup-0.0.2-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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89f050965b37b6972927b57ef80af38be585d342cddd5db3492bc9f05a4c320d
|
|
| MD5 |
a14ca8a49bfc302a8da5342869604bdf
|
|
| BLAKE2b-256 |
f4130a84f18313891a29a993535e6178151609ca46ad38d4f7f03f1dbfb5de89
|