Asymmetric Causality Testing - Implementation of Hatemi-J (2012) test
Project description
asymcaus
Asymmetric Causality Testing in Python
A Python implementation of the asymmetric causality test developed by Hatemi-J (2012). This package allows testing for Granger-causal relationships between positive and negative components of time series variables separately.
📚 Background
Traditional Granger causality tests assume that the causal impact of positive shocks is the same as negative shocks in absolute terms. However, economic agents often react differently to positive versus negative news. The asymmetric causality test addresses this limitation by decomposing variables into cumulative positive and negative changes and testing causality between these components separately.
🎯 Features
- Asymmetric Causality Testing: Test causal relationships between positive and negative components
- Bootstrap Critical Values: Leverage-adjusted bootstrap for robust inference under non-normality and ARCH effects
- Multiple Information Criteria: AIC, AICC, BIC/SBC, HQC, and Hatemi-J Criterion (HJC)
- Toda-Yamamoto Procedure: Handle integrated variables without pre-testing for cointegration
- Comprehensive Diagnostics: Multivariate normality tests, ARCH tests, and autocorrelation tests
- Unit Root Tests: ADF, KPSS, and Phillips-Perron tests
📦 Installation
pip install asymcaus
For development installation with all dependencies:
pip install asymcaus[full]
🚀 Quick Start
Basic Usage
import numpy as np
from asymcaus import asymmetric_causality_test
# Generate sample data (two I(1) series)
np.random.seed(42)
T = 500
z = np.cumsum(np.random.randn(T)) # Cause variable
y = np.cumsum(np.random.randn(T)) # Effect variable
# Test if positive shocks in Z cause positive shocks in Y
result = asymmetric_causality_test(
y=y,
z=z,
component='positive',
n_bootstrap=1000
)
# View results
print(result.summary())
Full Analysis (All Components)
from asymcaus import full_asymmetric_causality_analysis, print_full_analysis
# Test all combinations
results = full_asymmetric_causality_analysis(
y=y,
z=z,
var_names=('Oil Price', 'Stock Index'),
n_bootstrap=1000
)
# Print comprehensive summary
print(print_full_analysis(results))
With Unit Root Pre-testing
from asymcaus import determine_integration_order, asymmetric_causality_test
# Determine integration order
int_order_y, _ = determine_integration_order(y)
int_order_z, _ = determine_integration_order(z)
int_order = max(int_order_y, int_order_z)
print(f"Integration order: {int_order}")
# Use Toda-Yamamoto procedure
result = asymmetric_causality_test(
y=y,
z=z,
component='positive',
integration_order=int_order, # Add extra lags
criterion='hjc'
)
Diagnostic Tests
from asymcaus import run_all_diagnostics, print_diagnostics_summary
# After running causality test, check residual diagnostics
# (Assumes you have residuals from VAR estimation)
residuals = np.random.randn(100, 2) # Example residuals
diagnostics = run_all_diagnostics(residuals)
print(print_diagnostics_summary(diagnostics))
📖 API Reference
Main Functions
asymmetric_causality_test(y, z, component='positive', ...)
Perform the Hatemi-J (2012) asymmetric causality test.
Parameters:
y(array): Dependent variable (effect)z(array): Independent variable (cause)component(str): Type of component to test'positive': Test Z+ → Y+'negative': Test Z- → Y-'positive_to_negative': Test Z+ → Y-'negative_to_positive': Test Z- → Y+'original': Test without decomposition
criterion(str): Information criterion ('aic', 'bic', 'hqc', 'hjc')max_lag(int): Maximum lag order (default: 8)integration_order(int): Order of integration for Toda-Yamamoto (default: 0)n_bootstrap(int): Number of bootstrap replications (default: 1000)log_transform(bool): Apply log transformation (default: False)var_names(tuple): Names for variablesrandom_state(int): Random seed for reproducibility
Returns: AsymmetricCausalityResult object
full_asymmetric_causality_analysis(y, z, ...)
Run asymmetric causality tests for all component combinations.
cumulative_components(y, log_transform=False)
Calculate cumulative positive and negative components.
Unit Root Tests
adf_test(y, trend='c')- Augmented Dickey-Fuller testkpss_test(y, trend='c')- KPSS stationarity testpp_test(y, trend='c')- Phillips-Perron testdetermine_integration_order(y)- Automatic integration order detection
Diagnostic Tests
doornik_hansen_test(residuals)- Multivariate normality testmultivariate_arch_test(residuals)- ARCH effects testljung_box_test(residuals)- Autocorrelation testrun_all_diagnostics(residuals)- Run all diagnostics
📊 Example: Oil Prices and Stock Markets
Replicating the UAE market analysis from Hatemi-J (2012):
import numpy as np
from asymcaus import (
asymmetric_causality_test,
full_asymmetric_causality_analysis,
print_full_analysis,
determine_integration_order
)
# Load your data (oil prices and stock index)
# oil_price = ...
# stock_index = ...
# Example with simulated data
np.random.seed(2012)
T = 488
# Simulated I(1) processes
oil_price = np.cumsum(np.random.randn(T) * 0.02) + 4.5
stock_index = np.cumsum(np.random.randn(T) * 0.015) + 5.0
# Determine integration order
int_order, _ = determine_integration_order(oil_price)
print(f"Oil price integration order: {int_order}")
# Full asymmetric causality analysis
results = full_asymmetric_causality_analysis(
y=stock_index,
z=oil_price,
var_names=('Oil', 'Stock'),
integration_order=1,
n_bootstrap=1000,
criterion='hjc'
)
print(print_full_analysis(results))
📝 Interpretation of Results
The test evaluates the null hypothesis:
H₀: Variable Z does not Granger-cause variable Y
For asymmetric components:
- Positive components (Z+ → Y+): Do positive shocks in Z cause positive shocks in Y?
- Negative components (Z- → Y-): Do negative shocks in Z cause negative shocks in Y?
- Cross effects (Z+ → Y-, Z- → Y+): Do shocks of one sign cause opposite effects?
Decision Rule:
- If Wald statistic > Bootstrap critical value → Reject H₀ (causality exists)
- Bootstrap critical values are preferred over χ² critical values when data exhibits non-normality or ARCH effects
🔬 Methodology
Cumulative Sum Decomposition
For a time series y_t, positive and negative shocks are defined as:
ε⁺_t = max(Δy_t, 0)
ε⁻_t = min(Δy_t, 0)
Cumulative sums:
y⁺_t = Σᵢ₌₁ᵗ ε⁺ᵢ
y⁻_t = Σᵢ₌₁ᵗ ε⁻ᵢ
Bootstrap with Leverage Adjustment
The bootstrap procedure:
- Estimate restricted VAR model (under H₀)
- Calculate leverage-adjusted residuals
- Generate bootstrap samples
- Compute bootstrap Wald statistics
- Derive critical values from bootstrap distribution
Information Criteria
The Hatemi-J Criterion (HJC) is the average of SBC and HQC:
HJC = (SBC + HQC) / 2
📚 References
- Hatemi-J, A. (2012). Asymmetric Causality Tests with an Application. Empirical Economics, 43(1), 447-456.
- Granger, C.W.J. & Yoon, G. (2002). Hidden Cointegration. Working Paper, UC San Diego.
- Toda, H.Y. & Yamamoto, T. (1995). Statistical Inference in Vector Autoregressions with Possibly Integrated Processes. Journal of Econometrics, 66, 225-250.
- Hacker, R.S. & Hatemi-J, A. (2006). Tests for Causality between Integrated Variables Using Asymptotic and Bootstrap Distributions. Applied Economics, 38(13), 1489-1500.
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
👤 Author
Dr. Merwan Roudane
- GitHub: @merwanroudane
- Email: merwanroudane920@gmail.com
🙏 Acknowledgments
- Original GAUSS code by Prof. Abdulnasser Hatemi-J and Prof. Scott Hacker
- Based on the methodology in Hatemi-J (2012), Empirical Economics
📈 Citation
If you use this package in your research, please cite:
@software{roudane2024asymcaus,
author = {Roudane, Merwan},
title = {asymcaus: Asymmetric Causality Testing in Python},
year = {2024},
url = {https://github.com/merwanroudane/asymcaus}
}
@article{hatemi2012asymmetric,
title={Asymmetric causality tests with an application},
author={Hatemi-J, Abdulnasser},
journal={Empirical Economics},
volume={43},
number={1},
pages={447--456},
year={2012},
publisher={Springer}
}
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 asymcaus-2.0.0.tar.gz.
File metadata
- Download URL: asymcaus-2.0.0.tar.gz
- Upload date:
- Size: 31.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2107d851de6d85f16fdb181bc629e517b971800277ec178c34e0eb85081a406a
|
|
| MD5 |
f8b94c7be3e3173407ef0f826b883073
|
|
| BLAKE2b-256 |
189175a85cdac6af5b2d1bb858b1a962301035ec7f506de016295103ef109719
|
File details
Details for the file asymcaus-2.0.0-py3-none-any.whl.
File metadata
- Download URL: asymcaus-2.0.0-py3-none-any.whl
- Upload date:
- Size: 23.5 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 |
d7b79dca29cb151b037b7abf293dceb2fbaef9930a2e78535afb6e80c3f8cd50
|
|
| MD5 |
5335bff6dcdc45ca3be6ae6dc8767497
|
|
| BLAKE2b-256 |
350292386288024bae44e45299a0a12f45d9dea7c7ca31bbad9c803a9e23b98b
|