asycaus 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
asycaus-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dr Merwan Roudane
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ include docs/SYNTAX.md
5
+ recursive-include examples *.py
6
+ recursive-include tests *.py
asycaus-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,305 @@
1
+ Metadata-Version: 2.2
2
+ Name: asycaus
3
+ Version: 1.0.0
4
+ Summary: Asymmetric Granger-causality suite for Python (Hatemi-J, Bahmani-Oskooee, Fang et al., Nazlioglu et al.)
5
+ Author-email: Dr Merwan Roudane <merwanroudane920@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/merwanroudane/asycaus
8
+ Project-URL: Source, https://github.com/merwanroudane/asycaus
9
+ Project-URL: Issues, https://github.com/merwanroudane/asycaus/issues
10
+ Keywords: granger causality,asymmetric causality,Hatemi-J,Toda-Yamamoto,Breitung-Candelon,spectral causality,quantile causality,Fourier causality,leverage bootstrap,time-varying causality,econometrics,time series
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
21
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
22
+ Requires-Python: >=3.9
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.22
26
+ Requires-Dist: scipy>=1.8
27
+ Requires-Dist: pandas>=1.4
28
+ Requires-Dist: matplotlib>=3.5
29
+ Requires-Dist: rich>=12.0
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=7; extra == "dev"
32
+ Requires-Dist: black; extra == "dev"
33
+ Requires-Dist: ruff; extra == "dev"
34
+
35
+ # asycaus — Asymmetric Granger-Causality Suite for Python
36
+
37
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
38
+ [![Python ≥3.9](https://img.shields.io/badge/python-%E2%89%A53.9-blue.svg)]()
39
+ [![GitHub](https://img.shields.io/badge/GitHub-merwanroudane%2Fasycaus-181717?logo=github)](https://github.com/merwanroudane/asycaus)
40
+
41
+ **Repository:** <https://github.com/merwanroudane/asycaus>
42
+
43
+ A complete Python implementation of asymmetric Granger-causality tests for
44
+ bivariate time series. The package is a faithful mirror of the companion
45
+ **Stata `asycaus`** library by the same author, with publication-quality
46
+ tables (powered by [`rich`](https://github.com/Textualize/rich)) and plots
47
+ (`matplotlib`).
48
+
49
+ > **Author:** Dr Merwan Roudane &nbsp;·&nbsp; <merwanroudane920@gmail.com>
50
+ > &nbsp;·&nbsp; [GitHub](https://github.com/merwanroudane/asycaus)
51
+
52
+ ---
53
+
54
+ ## Methods implemented
55
+
56
+ | Function | Test | Reference |
57
+ |---|---|---|
58
+ | `asycaus.static` | Static asymmetric causality with leverage bootstrap | Hatemi-J (2012); Hacker & Hatemi-J (2006, 2012) |
59
+ | `asycaus.dynamic` | Rolling / recursive time-varying asymmetric causality | Hatemi-J (2021) |
60
+ | `asycaus.fourier` | Fourier-augmented asymmetric Toda-Yamamoto | Nazlioglu, Gormus & Soytas (2016); Pata (2020) |
61
+ | `asycaus.spectral` | Frequency-domain BC test on Pos / Neg components | Bahmani-Oskooee, Chang & Ranjbar (2016); Breitung & Candelon (2006) |
62
+ | `asycaus.quantile` | Quantile asymmetric causality (+ optional Fourier detrending) | Fang, Wang, Shieh & Chung (2026) |
63
+ | `asycaus.efficient` | SUR-based joint Pos / Neg / Joint / Pos=Neg test | Hatemi-J (2024) |
64
+ | `asycaus.all_tests` | Full battery with unified summary table | this package |
65
+ | `asycaus.pos_neg_components` | Utility: build cumulative shock components | Granger & Yoon (2002) |
66
+
67
+ The default lag-selection criterion across the library is the
68
+ **Hatemi-J information criterion** (HJC; Hatemi-J 2003), with AIC, AICC,
69
+ SBC, HQC also available.
70
+
71
+ ---
72
+
73
+ ## Installation
74
+
75
+ ```bash
76
+ # Once published to PyPI:
77
+ pip install asycaus
78
+
79
+ # Directly from GitHub:
80
+ pip install git+https://github.com/merwanroudane/asycaus.git
81
+
82
+ # Or from a local clone:
83
+ git clone https://github.com/merwanroudane/asycaus.git
84
+ pip install -e asycaus
85
+ ```
86
+
87
+ **Dependencies** (installed automatically):
88
+ `numpy`, `scipy`, `pandas`, `matplotlib`, `rich`.
89
+
90
+ Python **≥ 3.9** is required.
91
+
92
+ ---
93
+
94
+ ## Quick start
95
+
96
+ ```python
97
+ import numpy as np
98
+ import asycaus
99
+
100
+ # An asymmetric DGP: positive shocks in x cause y, negative do not.
101
+ rng = np.random.default_rng(30540)
102
+ ex = rng.standard_normal(300)
103
+ ey = rng.standard_normal(300)
104
+ x = np.cumsum(ex)
105
+ y = np.zeros(300)
106
+ for t in range(1, 300):
107
+ y[t] = 0.5 * y[t - 1] + 0.7 * max(ex[t - 1], 0) + ey[t]
108
+
109
+ # --- 1. Static Hatemi-J (2012) ----------------------------------------
110
+ asycaus.static(y, x, shock="both", boot=300)
111
+
112
+ # --- 2. Dynamic Hatemi-J (2021) rolling window ------------------------
113
+ asycaus.dynamic(y, x, shock="pos", mode="rolling", boot=150)
114
+
115
+ # --- 3. Fourier (Nazlioglu et al. 2016) -------------------------------
116
+ asycaus.fourier(y, x, kmax=3, form="single")
117
+
118
+ # --- 4. Spectral (Bahmani-Oskooee et al. 2016) ------------------------
119
+ asycaus.spectral(y, x, nfreq=50)
120
+
121
+ # --- 5. Quantile (Fang et al. 2026), with Fourier detrending ----------
122
+ asycaus.quantile(y, x, quantiles=(0.1, 0.25, 0.5, 0.75, 0.9),
123
+ fourier=True, kmax=2)
124
+
125
+ # --- 6. Efficient SUR (Hatemi-J 2024) ---------------------------------
126
+ asycaus.efficient(y, x, max_lag=4)
127
+
128
+ # --- Everything in one call -------------------------------------------
129
+ asycaus.all_tests(y, x, max_lag=4, boot=300, skip_dynamic=True)
130
+ ```
131
+
132
+ Every test prints a coloured, boxed table (via `rich`) and renders a
133
+ publication-quality plot (set `plot=False` to suppress; `show=False` to
134
+ suppress the table; both return a `Result` dataclass).
135
+
136
+ ---
137
+
138
+ ## Detailed function reference
139
+
140
+ ### `asycaus.static(y, x, *, shock='both', max_lag=8, ic='hjc', intorder=1, boot=1000, seed=12345, lnform=False, show=True, plot=True)`
141
+
142
+ **Hatemi-J (2012) static asymmetric causality with leverage-adjusted bootstrap.**
143
+
144
+ - `y`, `x`: 1-D arrays of equal length (length T). H₀: *x* does **not** Granger-cause *y*.
145
+ - `shock`: `'pos'` | `'neg'` | `'both'`. The cumulative components to test.
146
+ - `max_lag`: integer, max VAR lag for the IC search.
147
+ - `ic`: `'aic'` | `'aicc'` | `'sbc'` | `'hqc'` | `'hjc'` (default).
148
+ - `intorder`: integer ≥ 0, Toda-Yamamoto augmentation lags (max integration order).
149
+ - `boot`: bootstrap replications.
150
+ - `seed`: RNG seed (`None` for non-reproducible).
151
+ - `lnform`: take `np.log()` of inputs before the decomposition.
152
+ - `show` / `plot`: print the table / render the bar plot.
153
+
154
+ Returns `StaticResult`:
155
+ - `.table` — `pandas.DataFrame` indexed by shock, columns `Wald`, `lag`, `dof`, `asy_p`, `cv10`, `cv5`, `cv1`, `decision_5pct`.
156
+ - `.depvar`, `.causvar`, `.ic`, `.boot`, `.sample_size`, `.intorder`.
157
+
158
+ ---
159
+
160
+ ### `asycaus.dynamic(y, x, *, shock='pos', mode='rolling', window=None, max_lag=4, ic='hjc', intorder=1, boot=200, seed=12345, lnform=False, show=True, plot=True, progress=True)`
161
+
162
+ **Hatemi-J (2021) time-varying asymmetric causality.**
163
+
164
+ - `mode`: `'rolling'` (fixed window, slides by 1) or `'recursive'` (anchored at observation 1, expanding).
165
+ - `window`: window size *S*; defaults to the Phillips-Shi-Yu (2015) lower bound
166
+ *S = ceil(T (0.01 + 1.8/√T))*.
167
+ - `progress`: print `subsample k/N` every 10 windows.
168
+
169
+ Returns `DynamicResult`:
170
+ - `.table` — DataFrame columns `sub_start`, `sub_end`, `lag`, `Wald`, `cv10`, `cv5`, `cv1`, `ratio_5pct`.
171
+ - `.mode`, `.window`, `.smin`, `.nsub`, `.shock`, `.ic`, `.boot`, `.intorder`.
172
+
173
+ ---
174
+
175
+ ### `asycaus.fourier(y, x, *, shock='both', kmax=5, form='single', max_lag=8, ic='hjc', intorder=1, lnform=False, show=True, plot=True)`
176
+
177
+ **Fourier-augmented asymmetric Toda-Yamamoto (Nazlioglu et al. 2016; Pata 2020).**
178
+
179
+ - `kmax`: maximum Fourier frequency. The function searches `k = 1..kmax` and selects the most informative *k*\*.
180
+ - `form`: `'single'` (sin/cos at frequency *k*) or `'cumulative'` (basis `k = 1..k_max`).
181
+
182
+ Returns `FourierResult` with `.table` indexed by shock, columns
183
+ `Wald`, `lag`, `k_opt`, `asy_p`, `sample`, `decision_5pct`.
184
+
185
+ ---
186
+
187
+ ### `asycaus.spectral(y, x, *, shock='both', nfreq=50, max_lag=8, ic='hjc', lnform=False, show=True, plot=True)`
188
+
189
+ **Asymmetric frequency-domain causality (Bahmani-Oskooee et al. 2016 — BC 2006 applied to Pos/Neg components).**
190
+
191
+ - `nfreq`: number of grid points in `ω ∈ (0, π]`.
192
+
193
+ Returns `SpectralResult` with:
194
+ - `.table` — full grid (`shock_id`, `shock`, `omega`, `Wald`, `cv10`, `cv5`, `cv1`, `lag`)
195
+ - `.summary` — per-shock count of rejections at 1%, 5%, 10%
196
+
197
+ ---
198
+
199
+ ### `asycaus.quantile(y, x, *, shock='both', quantiles=(0.1,0.25,0.5,0.75,0.9), max_lag=4, ic='hjc', intorder=1, fourier=False, kmax=3, lnform=False, show=True, plot=True)`
200
+
201
+ **Quantile asymmetric causality (Fang, Wang, Shieh & Chung 2026).**
202
+
203
+ - `quantiles`: iterable of quantile probabilities in (0, 1).
204
+ - `fourier=True`: project out a cumulative Fourier basis (sin/cos with *k = 1..kmax*) before estimating the quantile causality.
205
+
206
+ Returns `QuantileResult` with `.table` columns
207
+ `shock_id`, `shock`, `tau`, `Wald`, `lag`, `asy_p`, `decision_5pct`.
208
+
209
+ ---
210
+
211
+ ### `asycaus.efficient(y, x, *, max_lag=8, ic='hjc', intorder=1, lnform=False, show=True, plot=True)`
212
+
213
+ **Hatemi-J (2024) efficient asymmetric causality via SUR.**
214
+
215
+ Reports four hypotheses jointly:
216
+
217
+ 1. No causality through **Pos** shocks
218
+ 2. No causality through **Neg** shocks
219
+ 3. **Joint** no causality
220
+ 4. **Pos = Neg** causal coefficients — the formal asymmetry test
221
+
222
+ Returns `EfficientResult` with:
223
+ - `.table` indexed by hypothesis: `Wald`, `df`, `asy_p`, `decision_5pct`
224
+ - `.raw` dict with `W_pos`, `p_pos`, `W_neg`, `p_neg`, `W_joint`, `p_joint`, `W_diff`, `p_diff`, `dof`
225
+
226
+ ---
227
+
228
+ ### `asycaus.all_tests(y, x, *, max_lag=4, ic='hjc', intorder=1, boot=500, seed=12345, kmax=5, nfreq=50, quantiles=(0.1,0.25,0.5,0.75,0.9), window=None, lnform=False, skip_dynamic=False, skip_spectral=False, skip_quantile=False, show=True, plot=False)`
229
+
230
+ **Run the full battery and print a unified summary.**
231
+
232
+ Returns `AllResult` containing every individual result plus:
233
+ - `.summary` — DataFrame with rows of the form (Test, Shock, Statistic, p-value, Decision).
234
+ - `.plot()` — assembles a 6-panel dashboard.
235
+
236
+ `skip_dynamic`, `skip_spectral`, `skip_quantile` let you turn off the slowest tests.
237
+
238
+ ---
239
+
240
+ ### `asycaus.pos_neg_components(Y, positive=True)`
241
+
242
+ Utility: cumulative sum of positive (or negative) first differences of `Y` (T × K).
243
+ Returns a (T-1) × K matrix.
244
+
245
+ ---
246
+
247
+ ## Output styling
248
+
249
+ Tables use `rich` for colour output if available, falling back to a clean
250
+ ASCII boxed format otherwise. Plots use matplotlib with a consistent
251
+ publication-quality theme (navy / orange / green / red).
252
+
253
+ Each `Result` dataclass exposes `.print()` and `.plot()` so you can re-render
254
+ without re-running the test:
255
+
256
+ ```python
257
+ r = asycaus.static(y, x, show=False, plot=False) # silent
258
+ r.print() # boxed table
259
+ fig = r.plot(save="static.png") # save the figure
260
+ ```
261
+
262
+ ---
263
+
264
+ ## References
265
+
266
+ - Bahmani-Oskooee, M., Chang, T., & Ranjbar, O. (2016). Asymmetric causality using frequency-domain and time-frequency-domain (wavelet) approaches. *Economic Modelling*, 56, 66–78.
267
+ - Breitung, J., & Candelon, B. (2006). Testing for short- and long-run causality: a frequency-domain approach. *Journal of Econometrics*, 132, 363–378.
268
+ - Enders, W., & Lee, J. (2012). The flexible Fourier form and Dickey-Fuller type unit root tests. *Economics Letters*, 117(1), 196–199.
269
+ - Fang, H., Wang, C.-H., Shieh, J. C. P., & Chung, C.-P. (2026). The asymmetric Granger causality between banking-sector and stock-market development and economic growth in quantiles considering Fourier. *Applied Economics*, 58(20), 3822–3838.
270
+ - Granger, C. W. J., & Yoon, G. (2002). Hidden cointegration. *UCSD Discussion Paper* 2002-02.
271
+ - Hacker, R. S., & Hatemi-J, A. (2006). Tests for causality between integrated variables using asymptotic and bootstrap distributions: theory and application. *Applied Economics*, 38(13), 1489–1500.
272
+ - Hacker, R. S., & Hatemi-J, A. (2012). A bootstrap test for causality with endogenous lag length choice: theory and application in finance. *Journal of Economic Studies*, 39(2), 144–160.
273
+ - Hatemi-J, A. (2003). A new method to choose optimal lag order in stable and unstable VAR models. *Applied Economics Letters*, 10(3), 135–137.
274
+ - Hatemi-J, A. (2012). Asymmetric causality tests with an application. *Empirical Economics*, 43, 447–456.
275
+ - Hatemi-J, A. (2021). Dynamic Asymmetric Causality Tests with an Application. *arXiv* 2106.07612.
276
+ - Hatemi-J, A. (2024). Efficient Asymmetric Causality Tests. *arXiv* 2408.03137.
277
+ - Koenker, R. (2005). *Quantile Regression*. Cambridge University Press.
278
+ - Nazlioglu, S., Gormus, N. A., & Soytas, U. (2016). Oil prices and real estate investment trusts (REITs): gradual-shift causality and volatility transmission analysis. *Energy Economics*, 60, 168–175.
279
+ - Pata, U. K. (2020). How is COVID-19 affecting environmental pollution in US cities? Evidence from asymmetric Fourier causality test. *Air Quality, Atmosphere & Health*, 13, 1149–1155.
280
+ - Phillips, P. C. B., Shi, S., & Yu, J. (2015). Testing for multiple bubbles: limit theory of real-time detectors. *International Economic Review*, 56(4), 1043–1078.
281
+ - Toda, H. Y., & Yamamoto, T. (1995). Statistical inference in vector autoregressions with possibly integrated processes. *Journal of Econometrics*, 66, 225–250.
282
+
283
+ ---
284
+
285
+ ## Citation
286
+
287
+ ```
288
+ Roudane, M. (2026). asycaus: Asymmetric Granger-causality suite for Python.
289
+ Version 1.0.0. https://github.com/merwanroudane/asycaus
290
+ ```
291
+
292
+ ---
293
+
294
+ ## License
295
+
296
+ MIT — see [LICENSE](LICENSE).
297
+
298
+ ## Companion package (Stata)
299
+
300
+ The Stata twin of this library, also by the same author, is available on SSC:
301
+
302
+ ```stata
303
+ ssc install asycaus
304
+ help asycaus
305
+ ```
@@ -0,0 +1,271 @@
1
+ # asycaus — Asymmetric Granger-Causality Suite for Python
2
+
3
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
4
+ [![Python ≥3.9](https://img.shields.io/badge/python-%E2%89%A53.9-blue.svg)]()
5
+ [![GitHub](https://img.shields.io/badge/GitHub-merwanroudane%2Fasycaus-181717?logo=github)](https://github.com/merwanroudane/asycaus)
6
+
7
+ **Repository:** <https://github.com/merwanroudane/asycaus>
8
+
9
+ A complete Python implementation of asymmetric Granger-causality tests for
10
+ bivariate time series. The package is a faithful mirror of the companion
11
+ **Stata `asycaus`** library by the same author, with publication-quality
12
+ tables (powered by [`rich`](https://github.com/Textualize/rich)) and plots
13
+ (`matplotlib`).
14
+
15
+ > **Author:** Dr Merwan Roudane &nbsp;·&nbsp; <merwanroudane920@gmail.com>
16
+ > &nbsp;·&nbsp; [GitHub](https://github.com/merwanroudane/asycaus)
17
+
18
+ ---
19
+
20
+ ## Methods implemented
21
+
22
+ | Function | Test | Reference |
23
+ |---|---|---|
24
+ | `asycaus.static` | Static asymmetric causality with leverage bootstrap | Hatemi-J (2012); Hacker & Hatemi-J (2006, 2012) |
25
+ | `asycaus.dynamic` | Rolling / recursive time-varying asymmetric causality | Hatemi-J (2021) |
26
+ | `asycaus.fourier` | Fourier-augmented asymmetric Toda-Yamamoto | Nazlioglu, Gormus & Soytas (2016); Pata (2020) |
27
+ | `asycaus.spectral` | Frequency-domain BC test on Pos / Neg components | Bahmani-Oskooee, Chang & Ranjbar (2016); Breitung & Candelon (2006) |
28
+ | `asycaus.quantile` | Quantile asymmetric causality (+ optional Fourier detrending) | Fang, Wang, Shieh & Chung (2026) |
29
+ | `asycaus.efficient` | SUR-based joint Pos / Neg / Joint / Pos=Neg test | Hatemi-J (2024) |
30
+ | `asycaus.all_tests` | Full battery with unified summary table | this package |
31
+ | `asycaus.pos_neg_components` | Utility: build cumulative shock components | Granger & Yoon (2002) |
32
+
33
+ The default lag-selection criterion across the library is the
34
+ **Hatemi-J information criterion** (HJC; Hatemi-J 2003), with AIC, AICC,
35
+ SBC, HQC also available.
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ # Once published to PyPI:
43
+ pip install asycaus
44
+
45
+ # Directly from GitHub:
46
+ pip install git+https://github.com/merwanroudane/asycaus.git
47
+
48
+ # Or from a local clone:
49
+ git clone https://github.com/merwanroudane/asycaus.git
50
+ pip install -e asycaus
51
+ ```
52
+
53
+ **Dependencies** (installed automatically):
54
+ `numpy`, `scipy`, `pandas`, `matplotlib`, `rich`.
55
+
56
+ Python **≥ 3.9** is required.
57
+
58
+ ---
59
+
60
+ ## Quick start
61
+
62
+ ```python
63
+ import numpy as np
64
+ import asycaus
65
+
66
+ # An asymmetric DGP: positive shocks in x cause y, negative do not.
67
+ rng = np.random.default_rng(30540)
68
+ ex = rng.standard_normal(300)
69
+ ey = rng.standard_normal(300)
70
+ x = np.cumsum(ex)
71
+ y = np.zeros(300)
72
+ for t in range(1, 300):
73
+ y[t] = 0.5 * y[t - 1] + 0.7 * max(ex[t - 1], 0) + ey[t]
74
+
75
+ # --- 1. Static Hatemi-J (2012) ----------------------------------------
76
+ asycaus.static(y, x, shock="both", boot=300)
77
+
78
+ # --- 2. Dynamic Hatemi-J (2021) rolling window ------------------------
79
+ asycaus.dynamic(y, x, shock="pos", mode="rolling", boot=150)
80
+
81
+ # --- 3. Fourier (Nazlioglu et al. 2016) -------------------------------
82
+ asycaus.fourier(y, x, kmax=3, form="single")
83
+
84
+ # --- 4. Spectral (Bahmani-Oskooee et al. 2016) ------------------------
85
+ asycaus.spectral(y, x, nfreq=50)
86
+
87
+ # --- 5. Quantile (Fang et al. 2026), with Fourier detrending ----------
88
+ asycaus.quantile(y, x, quantiles=(0.1, 0.25, 0.5, 0.75, 0.9),
89
+ fourier=True, kmax=2)
90
+
91
+ # --- 6. Efficient SUR (Hatemi-J 2024) ---------------------------------
92
+ asycaus.efficient(y, x, max_lag=4)
93
+
94
+ # --- Everything in one call -------------------------------------------
95
+ asycaus.all_tests(y, x, max_lag=4, boot=300, skip_dynamic=True)
96
+ ```
97
+
98
+ Every test prints a coloured, boxed table (via `rich`) and renders a
99
+ publication-quality plot (set `plot=False` to suppress; `show=False` to
100
+ suppress the table; both return a `Result` dataclass).
101
+
102
+ ---
103
+
104
+ ## Detailed function reference
105
+
106
+ ### `asycaus.static(y, x, *, shock='both', max_lag=8, ic='hjc', intorder=1, boot=1000, seed=12345, lnform=False, show=True, plot=True)`
107
+
108
+ **Hatemi-J (2012) static asymmetric causality with leverage-adjusted bootstrap.**
109
+
110
+ - `y`, `x`: 1-D arrays of equal length (length T). H₀: *x* does **not** Granger-cause *y*.
111
+ - `shock`: `'pos'` | `'neg'` | `'both'`. The cumulative components to test.
112
+ - `max_lag`: integer, max VAR lag for the IC search.
113
+ - `ic`: `'aic'` | `'aicc'` | `'sbc'` | `'hqc'` | `'hjc'` (default).
114
+ - `intorder`: integer ≥ 0, Toda-Yamamoto augmentation lags (max integration order).
115
+ - `boot`: bootstrap replications.
116
+ - `seed`: RNG seed (`None` for non-reproducible).
117
+ - `lnform`: take `np.log()` of inputs before the decomposition.
118
+ - `show` / `plot`: print the table / render the bar plot.
119
+
120
+ Returns `StaticResult`:
121
+ - `.table` — `pandas.DataFrame` indexed by shock, columns `Wald`, `lag`, `dof`, `asy_p`, `cv10`, `cv5`, `cv1`, `decision_5pct`.
122
+ - `.depvar`, `.causvar`, `.ic`, `.boot`, `.sample_size`, `.intorder`.
123
+
124
+ ---
125
+
126
+ ### `asycaus.dynamic(y, x, *, shock='pos', mode='rolling', window=None, max_lag=4, ic='hjc', intorder=1, boot=200, seed=12345, lnform=False, show=True, plot=True, progress=True)`
127
+
128
+ **Hatemi-J (2021) time-varying asymmetric causality.**
129
+
130
+ - `mode`: `'rolling'` (fixed window, slides by 1) or `'recursive'` (anchored at observation 1, expanding).
131
+ - `window`: window size *S*; defaults to the Phillips-Shi-Yu (2015) lower bound
132
+ *S = ceil(T (0.01 + 1.8/√T))*.
133
+ - `progress`: print `subsample k/N` every 10 windows.
134
+
135
+ Returns `DynamicResult`:
136
+ - `.table` — DataFrame columns `sub_start`, `sub_end`, `lag`, `Wald`, `cv10`, `cv5`, `cv1`, `ratio_5pct`.
137
+ - `.mode`, `.window`, `.smin`, `.nsub`, `.shock`, `.ic`, `.boot`, `.intorder`.
138
+
139
+ ---
140
+
141
+ ### `asycaus.fourier(y, x, *, shock='both', kmax=5, form='single', max_lag=8, ic='hjc', intorder=1, lnform=False, show=True, plot=True)`
142
+
143
+ **Fourier-augmented asymmetric Toda-Yamamoto (Nazlioglu et al. 2016; Pata 2020).**
144
+
145
+ - `kmax`: maximum Fourier frequency. The function searches `k = 1..kmax` and selects the most informative *k*\*.
146
+ - `form`: `'single'` (sin/cos at frequency *k*) or `'cumulative'` (basis `k = 1..k_max`).
147
+
148
+ Returns `FourierResult` with `.table` indexed by shock, columns
149
+ `Wald`, `lag`, `k_opt`, `asy_p`, `sample`, `decision_5pct`.
150
+
151
+ ---
152
+
153
+ ### `asycaus.spectral(y, x, *, shock='both', nfreq=50, max_lag=8, ic='hjc', lnform=False, show=True, plot=True)`
154
+
155
+ **Asymmetric frequency-domain causality (Bahmani-Oskooee et al. 2016 — BC 2006 applied to Pos/Neg components).**
156
+
157
+ - `nfreq`: number of grid points in `ω ∈ (0, π]`.
158
+
159
+ Returns `SpectralResult` with:
160
+ - `.table` — full grid (`shock_id`, `shock`, `omega`, `Wald`, `cv10`, `cv5`, `cv1`, `lag`)
161
+ - `.summary` — per-shock count of rejections at 1%, 5%, 10%
162
+
163
+ ---
164
+
165
+ ### `asycaus.quantile(y, x, *, shock='both', quantiles=(0.1,0.25,0.5,0.75,0.9), max_lag=4, ic='hjc', intorder=1, fourier=False, kmax=3, lnform=False, show=True, plot=True)`
166
+
167
+ **Quantile asymmetric causality (Fang, Wang, Shieh & Chung 2026).**
168
+
169
+ - `quantiles`: iterable of quantile probabilities in (0, 1).
170
+ - `fourier=True`: project out a cumulative Fourier basis (sin/cos with *k = 1..kmax*) before estimating the quantile causality.
171
+
172
+ Returns `QuantileResult` with `.table` columns
173
+ `shock_id`, `shock`, `tau`, `Wald`, `lag`, `asy_p`, `decision_5pct`.
174
+
175
+ ---
176
+
177
+ ### `asycaus.efficient(y, x, *, max_lag=8, ic='hjc', intorder=1, lnform=False, show=True, plot=True)`
178
+
179
+ **Hatemi-J (2024) efficient asymmetric causality via SUR.**
180
+
181
+ Reports four hypotheses jointly:
182
+
183
+ 1. No causality through **Pos** shocks
184
+ 2. No causality through **Neg** shocks
185
+ 3. **Joint** no causality
186
+ 4. **Pos = Neg** causal coefficients — the formal asymmetry test
187
+
188
+ Returns `EfficientResult` with:
189
+ - `.table` indexed by hypothesis: `Wald`, `df`, `asy_p`, `decision_5pct`
190
+ - `.raw` dict with `W_pos`, `p_pos`, `W_neg`, `p_neg`, `W_joint`, `p_joint`, `W_diff`, `p_diff`, `dof`
191
+
192
+ ---
193
+
194
+ ### `asycaus.all_tests(y, x, *, max_lag=4, ic='hjc', intorder=1, boot=500, seed=12345, kmax=5, nfreq=50, quantiles=(0.1,0.25,0.5,0.75,0.9), window=None, lnform=False, skip_dynamic=False, skip_spectral=False, skip_quantile=False, show=True, plot=False)`
195
+
196
+ **Run the full battery and print a unified summary.**
197
+
198
+ Returns `AllResult` containing every individual result plus:
199
+ - `.summary` — DataFrame with rows of the form (Test, Shock, Statistic, p-value, Decision).
200
+ - `.plot()` — assembles a 6-panel dashboard.
201
+
202
+ `skip_dynamic`, `skip_spectral`, `skip_quantile` let you turn off the slowest tests.
203
+
204
+ ---
205
+
206
+ ### `asycaus.pos_neg_components(Y, positive=True)`
207
+
208
+ Utility: cumulative sum of positive (or negative) first differences of `Y` (T × K).
209
+ Returns a (T-1) × K matrix.
210
+
211
+ ---
212
+
213
+ ## Output styling
214
+
215
+ Tables use `rich` for colour output if available, falling back to a clean
216
+ ASCII boxed format otherwise. Plots use matplotlib with a consistent
217
+ publication-quality theme (navy / orange / green / red).
218
+
219
+ Each `Result` dataclass exposes `.print()` and `.plot()` so you can re-render
220
+ without re-running the test:
221
+
222
+ ```python
223
+ r = asycaus.static(y, x, show=False, plot=False) # silent
224
+ r.print() # boxed table
225
+ fig = r.plot(save="static.png") # save the figure
226
+ ```
227
+
228
+ ---
229
+
230
+ ## References
231
+
232
+ - Bahmani-Oskooee, M., Chang, T., & Ranjbar, O. (2016). Asymmetric causality using frequency-domain and time-frequency-domain (wavelet) approaches. *Economic Modelling*, 56, 66–78.
233
+ - Breitung, J., & Candelon, B. (2006). Testing for short- and long-run causality: a frequency-domain approach. *Journal of Econometrics*, 132, 363–378.
234
+ - Enders, W., & Lee, J. (2012). The flexible Fourier form and Dickey-Fuller type unit root tests. *Economics Letters*, 117(1), 196–199.
235
+ - Fang, H., Wang, C.-H., Shieh, J. C. P., & Chung, C.-P. (2026). The asymmetric Granger causality between banking-sector and stock-market development and economic growth in quantiles considering Fourier. *Applied Economics*, 58(20), 3822–3838.
236
+ - Granger, C. W. J., & Yoon, G. (2002). Hidden cointegration. *UCSD Discussion Paper* 2002-02.
237
+ - Hacker, R. S., & Hatemi-J, A. (2006). Tests for causality between integrated variables using asymptotic and bootstrap distributions: theory and application. *Applied Economics*, 38(13), 1489–1500.
238
+ - Hacker, R. S., & Hatemi-J, A. (2012). A bootstrap test for causality with endogenous lag length choice: theory and application in finance. *Journal of Economic Studies*, 39(2), 144–160.
239
+ - Hatemi-J, A. (2003). A new method to choose optimal lag order in stable and unstable VAR models. *Applied Economics Letters*, 10(3), 135–137.
240
+ - Hatemi-J, A. (2012). Asymmetric causality tests with an application. *Empirical Economics*, 43, 447–456.
241
+ - Hatemi-J, A. (2021). Dynamic Asymmetric Causality Tests with an Application. *arXiv* 2106.07612.
242
+ - Hatemi-J, A. (2024). Efficient Asymmetric Causality Tests. *arXiv* 2408.03137.
243
+ - Koenker, R. (2005). *Quantile Regression*. Cambridge University Press.
244
+ - Nazlioglu, S., Gormus, N. A., & Soytas, U. (2016). Oil prices and real estate investment trusts (REITs): gradual-shift causality and volatility transmission analysis. *Energy Economics*, 60, 168–175.
245
+ - Pata, U. K. (2020). How is COVID-19 affecting environmental pollution in US cities? Evidence from asymmetric Fourier causality test. *Air Quality, Atmosphere & Health*, 13, 1149–1155.
246
+ - Phillips, P. C. B., Shi, S., & Yu, J. (2015). Testing for multiple bubbles: limit theory of real-time detectors. *International Economic Review*, 56(4), 1043–1078.
247
+ - Toda, H. Y., & Yamamoto, T. (1995). Statistical inference in vector autoregressions with possibly integrated processes. *Journal of Econometrics*, 66, 225–250.
248
+
249
+ ---
250
+
251
+ ## Citation
252
+
253
+ ```
254
+ Roudane, M. (2026). asycaus: Asymmetric Granger-causality suite for Python.
255
+ Version 1.0.0. https://github.com/merwanroudane/asycaus
256
+ ```
257
+
258
+ ---
259
+
260
+ ## License
261
+
262
+ MIT — see [LICENSE](LICENSE).
263
+
264
+ ## Companion package (Stata)
265
+
266
+ The Stata twin of this library, also by the same author, is available on SSC:
267
+
268
+ ```stata
269
+ ssc install asycaus
270
+ help asycaus
271
+ ```
@@ -0,0 +1,64 @@
1
+ """
2
+ asycaus
3
+ =======
4
+
5
+ Asymmetric Granger-causality suite for Python. Python mirror of the Stata
6
+ package `asycaus` by the same author.
7
+
8
+ Quick start
9
+ -----------
10
+
11
+ >>> import numpy as np, asycaus
12
+ >>> rng = np.random.default_rng(0)
13
+ >>> x = np.cumsum(rng.standard_normal(300))
14
+ >>> y = np.r_[0, 0.5*x[:-1] + rng.standard_normal(299)]
15
+ >>> r = asycaus.static(y, x, shock="both", boot=200, plot=False)
16
+
17
+ Available tests
18
+ ---------------
19
+
20
+ asycaus.static Hatemi-J (2012) static asymmetric (leverage bootstrap)
21
+ asycaus.dynamic Hatemi-J (2021) rolling / recursive
22
+ asycaus.fourier Nazlioglu et al. (2016) Fourier-augmented TY
23
+ asycaus.spectral Bahmani-Oskooee et al. (2016) BC frequency-domain
24
+ asycaus.quantile Fang et al. (2026) quantile asymmetric
25
+ asycaus.efficient Hatemi-J (2024) SUR (Pos / Neg / Joint / Pos=Neg)
26
+ asycaus.all_tests Run every test, return unified summary
27
+
28
+ Author : Dr Merwan Roudane <merwanroudane920@gmail.com>
29
+ GitHub : https://github.com/merwanroudane/asycaus
30
+ License: MIT
31
+ """
32
+
33
+ from importlib.metadata import version, PackageNotFoundError
34
+
35
+ try:
36
+ __version__ = version("asycaus")
37
+ except PackageNotFoundError:
38
+ __version__ = "1.0.0"
39
+
40
+ __author__ = "Dr Merwan Roudane"
41
+ __email__ = "merwanroudane920@gmail.com"
42
+ __license__ = "MIT"
43
+ __url__ = "https://github.com/merwanroudane/asycaus"
44
+
45
+ from . import engine
46
+ from . import tables
47
+ from . import plots
48
+ from .static import static, StaticResult
49
+ from .dynamic import dynamic, DynamicResult
50
+ from .fourier import fourier, FourierResult
51
+ from .spectral import spectral, SpectralResult
52
+ from .quantile import quantile, QuantileResult
53
+ from .efficient import efficient, EfficientResult
54
+ from .all_tests import all_tests, AllResult
55
+ from .engine import pos_neg_components
56
+
57
+ __all__ = [
58
+ "static", "dynamic", "fourier", "spectral", "quantile",
59
+ "efficient", "all_tests", "pos_neg_components",
60
+ "StaticResult", "DynamicResult", "FourierResult", "SpectralResult",
61
+ "QuantileResult", "EfficientResult", "AllResult",
62
+ "engine", "tables", "plots",
63
+ "__version__", "__author__", "__email__", "__license__", "__url__",
64
+ ]