macroshock 0.1.2__tar.gz → 0.2.2__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.
- macroshock-0.2.2/PKG-INFO +206 -0
- macroshock-0.2.2/README.md +169 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/pyproject.toml +4 -1
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/bootstrap.py +33 -16
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/data.py +3 -3
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/fc.py +1 -1
- macroshock-0.2.2/src/macroshock/fevd.py +63 -0
- macroshock-0.2.2/src/macroshock/identification.py +531 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/irf.py +5 -5
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/macroshock.py +207 -297
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/plotting.py +61 -39
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/var.py +5 -6
- macroshock-0.2.2/src/macroshock.egg-info/PKG-INFO +206 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock.egg-info/SOURCES.txt +1 -0
- macroshock-0.1.2/PKG-INFO +0 -216
- macroshock-0.1.2/README.md +0 -180
- macroshock-0.1.2/src/macroshock/identification.py +0 -315
- macroshock-0.1.2/src/macroshock.egg-info/PKG-INFO +0 -216
- {macroshock-0.1.2 → macroshock-0.2.2}/LICENSE +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/setup.cfg +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/__init__.py +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock/stats.py +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock.egg-info/dependency_links.txt +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock.egg-info/requires.txt +0 -0
- {macroshock-0.1.2 → macroshock-0.2.2}/src/macroshock.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: macroshock
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Powerful time series econometrics for Structural Vector Autoregressions (SVAR)
|
|
5
|
+
Author-email: Patricio Arias <patoariaslopez2@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Patricio
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: GitHub repository, https://github.com/patricioariaslpz/macroshock.git
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: numpy>=1.24.0
|
|
33
|
+
Requires-Dist: pandas>=2.0.0
|
|
34
|
+
Requires-Dist: scipy>=1.10.0
|
|
35
|
+
Requires-Dist: matplotlib>=3.7.0
|
|
36
|
+
Dynamic: license-file
|
|
37
|
+
|
|
38
|
+
# macroshock
|
|
39
|
+
|
|
40
|
+
**macroshock** is a Python library for the estimation and analysis of **SVAR** (Structural Vector Autoregression) models aimed at applied macroeconometrics. It allows you to estimate restricted VARs, identify the structural system using four different methodologies, compute impulse-response functions (IRF), forecast error variance decomposition (FEVD), and forecasts, all with bootstrap confidence intervals and ready-to-use plotting.
|
|
41
|
+
|
|
42
|
+
## Main Features
|
|
43
|
+
|
|
44
|
+
* - **Restricted VAR estimation** (Lütkepohl-style GLS), with support for:
|
|
45
|
+
|
|
46
|
+
- Constant, trend and quadratic trend.
|
|
47
|
+
- Exogenous variables.
|
|
48
|
+
- Seasonal dummies (quarterly or monthly).
|
|
49
|
+
- Linear restrictions on the coefficients (`restrictions='zeros'` or `'custom zeros'`).
|
|
50
|
+
* - **Four structural identification methods**:
|
|
51
|
+
|
|
52
|
+
|Method|Description|
|
|
53
|
+
|-|-|
|
|
54
|
+
|`short`|Short-run restrictions (Cholesky or custom restrictions via optimization)|
|
|
55
|
+
|`long`|Long-run restrictions (Cholesky or custom restrictions via optimization)|
|
|
56
|
+
|`signs`|Sign restrictions (orthogonal rotation sampling with acceptance/rejection)|
|
|
57
|
+
|`IV`|Instrumental variable identification (proxy-SVAR)|
|
|
58
|
+
|
|
59
|
+
* - **Impulse-response functions (IRF)** with confidence bands.
|
|
60
|
+
* - **Forecast error variance decomposition (FEVD)**.
|
|
61
|
+
* - **Conditional forecasts** with confidence bands.
|
|
62
|
+
* - **Bootstrap** (normal or *wild* resampling) for inference.
|
|
63
|
+
* - **Built-in plots** for IRF, forecasts and FEVD, publication-ready.
|
|
64
|
+
* - **Stability test** of the system (characteristic polynomial roots).
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install macroshock
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Requirements
|
|
73
|
+
|
|
74
|
+
* Python >= 3.9
|
|
75
|
+
* `numpy >= 1.24.0`
|
|
76
|
+
* `pandas >= 2.0.0`
|
|
77
|
+
* `scipy`
|
|
78
|
+
* `matplotlib >= 3.7.0`
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import pandas as pd
|
|
84
|
+
from macroshock import SVAR
|
|
85
|
+
|
|
86
|
+
# df is a DataFrame with your series in columns
|
|
87
|
+
df = pd.read\_csv("my\_dataset.csv")
|
|
88
|
+
|
|
89
|
+
model = SVAR(
|
|
90
|
+
data=df,
|
|
91
|
+
variables=\["gdp", "inflation", "interest\_rate"],
|
|
92
|
+
lags=4,
|
|
93
|
+
const=1, # 0: no constant, 1: constant, 2: +trend, 3: +quadratic trend
|
|
94
|
+
method="short", # 'short', 'long', 'signs' or 'IV'
|
|
95
|
+
steps=24, # horizon for IRF/FEVD
|
|
96
|
+
horizon=8, # forecast horizon
|
|
97
|
+
past=12, # past periods to show in the forecast
|
|
98
|
+
alpha=32, # confidence interval level (32 -> 68% central band)
|
|
99
|
+
reps=1000, # bootstrap replications
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Runs the complete pipeline: Y/X construction, VAR estimation,
|
|
103
|
+
# structural identification and results summary
|
|
104
|
+
model.run(showIR=True, showFC=True, showVD=True)
|
|
105
|
+
|
|
106
|
+
# System stability check
|
|
107
|
+
model.stability(show=True)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Step-by-step Usage
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
model.YX() # builds Y, X and the restriction matrix R
|
|
114
|
+
model.VAR() # estimates the reduced-form VAR and the companion matrix F
|
|
115
|
+
model.S() # identifies the structural system (matrix B)
|
|
116
|
+
model.summary() # prints the estimation summary
|
|
117
|
+
|
|
118
|
+
# Impulse response to shock 1, with "pair" bands (low/high percentile)
|
|
119
|
+
ir = model.ImpulseResponse(1, show=True, bands="pair")
|
|
120
|
+
|
|
121
|
+
# Forecast with "many" bands (multiple stacked confidence levels)
|
|
122
|
+
fc = model.Forecast(show=True, bands="many")
|
|
123
|
+
|
|
124
|
+
# Forecast error variance decomposition for variable 1
|
|
125
|
+
vd = model.VarianceDecomp(1, show=True)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Each of these methods returns a dictionary with the point estimate and confidence bands at different levels (`'point'`, `'low'`, `'high'`, `2.5`, `5`, `95`, `97.5`, `0.5`, `99.5`), indexed by variable name.
|
|
129
|
+
|
|
130
|
+
## Structural Identification
|
|
131
|
+
|
|
132
|
+
### 1\. Short-run (Cholesky / custom restrictions)
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
model = SVAR(data=df, variables=variables, lags=4, method="short")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
By default it uses the Cholesky decomposition. If `matrix\_short` is passed (a binary matrix of 1s and 0s), the `B` matrix satisfying the indicated zero restrictions is solved numerically.
|
|
139
|
+
|
|
140
|
+
### 2\. Long-run (Blanchard-Quah)
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
model = SVAR(data=df, variables=variables, lags=4, method="long")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
By default it uses the Cholesky decomposition. If `matrix\_long` is passed (a binary matrix of 1s and 0s), the `B` matrix satisfying the indicated zero restrictions is solved numerically.
|
|
147
|
+
|
|
148
|
+
### 3\. Sign restrictions
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
matrix\_signs = \[\[1, -1, 0],
|
|
152
|
+
\[1, 1, 0],
|
|
153
|
+
\[0, 0, 1]]
|
|
154
|
+
|
|
155
|
+
model = SVAR(
|
|
156
|
+
data=df, variables=variables, lags=4,
|
|
157
|
+
method="signs",
|
|
158
|
+
matrix\_signs=matrix\_signs,
|
|
159
|
+
steps\_signs=4, # horizons over which signs are checked
|
|
160
|
+
reps=1000, # number of accepted B matrices
|
|
161
|
+
)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 4\. Instrumental variables (Proxy-SVAR)
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
model = SVAR(
|
|
168
|
+
data=df, variables=variables, lags=4,
|
|
169
|
+
method="IV",
|
|
170
|
+
iv=\["instrument\_1"], # DataFrame column(s) with the instrument(s)
|
|
171
|
+
)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Package Structure
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
macroshock/
|
|
179
|
+
├── data.py # construction of Y, X and restriction matrix R
|
|
180
|
+
├── var.py # reduced-form VAR estimation (restricted GLS, IC, t-stats)
|
|
181
|
+
├── stats.py # statistical utilities (Student's t CDF and p-values)
|
|
182
|
+
├── identification.py # the 4 structural identification methods
|
|
183
|
+
├── irf.py # impulse-response functions and bands from bootstrap
|
|
184
|
+
├── fevd.py # forecast error variance decomposition
|
|
185
|
+
├── fc.py # forecast computation
|
|
186
|
+
├── bootstrap.py # bootstrap (normal / wild) for IR, FC and FEVD
|
|
187
|
+
├── plotting.py # IRF, forecast and FEVD plots
|
|
188
|
+
└── macroshock.py # main SVAR class (and SVEC, LP scaffolds for future development)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Roadmap
|
|
192
|
+
|
|
193
|
+
* Full documentation (Sphinx / ReadTheDocs)
|
|
194
|
+
* SVEC model (structural Vector Error Correction)
|
|
195
|
+
* Local Projections (LP)
|
|
196
|
+
* Historical decomposition (`HistoricalDecomp`)
|
|
197
|
+
* Unit tests and CI
|
|
198
|
+
|
|
199
|
+
## Contributing
|
|
200
|
+
|
|
201
|
+
Issues and pull requests are welcome. If you find a bug or have an improvement proposal, open an issue in the project's repository.
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
This project is distributed under the MIT license. See the `LICENSE` file for more details.
|
|
206
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# macroshock
|
|
2
|
+
|
|
3
|
+
**macroshock** is a Python library for the estimation and analysis of **SVAR** (Structural Vector Autoregression) models aimed at applied macroeconometrics. It allows you to estimate restricted VARs, identify the structural system using four different methodologies, compute impulse-response functions (IRF), forecast error variance decomposition (FEVD), and forecasts, all with bootstrap confidence intervals and ready-to-use plotting.
|
|
4
|
+
|
|
5
|
+
## Main Features
|
|
6
|
+
|
|
7
|
+
* - **Restricted VAR estimation** (Lütkepohl-style GLS), with support for:
|
|
8
|
+
|
|
9
|
+
- Constant, trend and quadratic trend.
|
|
10
|
+
- Exogenous variables.
|
|
11
|
+
- Seasonal dummies (quarterly or monthly).
|
|
12
|
+
- Linear restrictions on the coefficients (`restrictions='zeros'` or `'custom zeros'`).
|
|
13
|
+
* - **Four structural identification methods**:
|
|
14
|
+
|
|
15
|
+
|Method|Description|
|
|
16
|
+
|-|-|
|
|
17
|
+
|`short`|Short-run restrictions (Cholesky or custom restrictions via optimization)|
|
|
18
|
+
|`long`|Long-run restrictions (Cholesky or custom restrictions via optimization)|
|
|
19
|
+
|`signs`|Sign restrictions (orthogonal rotation sampling with acceptance/rejection)|
|
|
20
|
+
|`IV`|Instrumental variable identification (proxy-SVAR)|
|
|
21
|
+
|
|
22
|
+
* - **Impulse-response functions (IRF)** with confidence bands.
|
|
23
|
+
* - **Forecast error variance decomposition (FEVD)**.
|
|
24
|
+
* - **Conditional forecasts** with confidence bands.
|
|
25
|
+
* - **Bootstrap** (normal or *wild* resampling) for inference.
|
|
26
|
+
* - **Built-in plots** for IRF, forecasts and FEVD, publication-ready.
|
|
27
|
+
* - **Stability test** of the system (characteristic polynomial roots).
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install macroshock
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Requirements
|
|
36
|
+
|
|
37
|
+
* Python >= 3.9
|
|
38
|
+
* `numpy >= 1.24.0`
|
|
39
|
+
* `pandas >= 2.0.0`
|
|
40
|
+
* `scipy`
|
|
41
|
+
* `matplotlib >= 3.7.0`
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import pandas as pd
|
|
47
|
+
from macroshock import SVAR
|
|
48
|
+
|
|
49
|
+
# df is a DataFrame with your series in columns
|
|
50
|
+
df = pd.read\_csv("my\_dataset.csv")
|
|
51
|
+
|
|
52
|
+
model = SVAR(
|
|
53
|
+
data=df,
|
|
54
|
+
variables=\["gdp", "inflation", "interest\_rate"],
|
|
55
|
+
lags=4,
|
|
56
|
+
const=1, # 0: no constant, 1: constant, 2: +trend, 3: +quadratic trend
|
|
57
|
+
method="short", # 'short', 'long', 'signs' or 'IV'
|
|
58
|
+
steps=24, # horizon for IRF/FEVD
|
|
59
|
+
horizon=8, # forecast horizon
|
|
60
|
+
past=12, # past periods to show in the forecast
|
|
61
|
+
alpha=32, # confidence interval level (32 -> 68% central band)
|
|
62
|
+
reps=1000, # bootstrap replications
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Runs the complete pipeline: Y/X construction, VAR estimation,
|
|
66
|
+
# structural identification and results summary
|
|
67
|
+
model.run(showIR=True, showFC=True, showVD=True)
|
|
68
|
+
|
|
69
|
+
# System stability check
|
|
70
|
+
model.stability(show=True)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Step-by-step Usage
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
model.YX() # builds Y, X and the restriction matrix R
|
|
77
|
+
model.VAR() # estimates the reduced-form VAR and the companion matrix F
|
|
78
|
+
model.S() # identifies the structural system (matrix B)
|
|
79
|
+
model.summary() # prints the estimation summary
|
|
80
|
+
|
|
81
|
+
# Impulse response to shock 1, with "pair" bands (low/high percentile)
|
|
82
|
+
ir = model.ImpulseResponse(1, show=True, bands="pair")
|
|
83
|
+
|
|
84
|
+
# Forecast with "many" bands (multiple stacked confidence levels)
|
|
85
|
+
fc = model.Forecast(show=True, bands="many")
|
|
86
|
+
|
|
87
|
+
# Forecast error variance decomposition for variable 1
|
|
88
|
+
vd = model.VarianceDecomp(1, show=True)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Each of these methods returns a dictionary with the point estimate and confidence bands at different levels (`'point'`, `'low'`, `'high'`, `2.5`, `5`, `95`, `97.5`, `0.5`, `99.5`), indexed by variable name.
|
|
92
|
+
|
|
93
|
+
## Structural Identification
|
|
94
|
+
|
|
95
|
+
### 1\. Short-run (Cholesky / custom restrictions)
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
model = SVAR(data=df, variables=variables, lags=4, method="short")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
By default it uses the Cholesky decomposition. If `matrix\_short` is passed (a binary matrix of 1s and 0s), the `B` matrix satisfying the indicated zero restrictions is solved numerically.
|
|
102
|
+
|
|
103
|
+
### 2\. Long-run (Blanchard-Quah)
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
model = SVAR(data=df, variables=variables, lags=4, method="long")
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
By default it uses the Cholesky decomposition. If `matrix\_long` is passed (a binary matrix of 1s and 0s), the `B` matrix satisfying the indicated zero restrictions is solved numerically.
|
|
110
|
+
|
|
111
|
+
### 3\. Sign restrictions
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
matrix\_signs = \[\[1, -1, 0],
|
|
115
|
+
\[1, 1, 0],
|
|
116
|
+
\[0, 0, 1]]
|
|
117
|
+
|
|
118
|
+
model = SVAR(
|
|
119
|
+
data=df, variables=variables, lags=4,
|
|
120
|
+
method="signs",
|
|
121
|
+
matrix\_signs=matrix\_signs,
|
|
122
|
+
steps\_signs=4, # horizons over which signs are checked
|
|
123
|
+
reps=1000, # number of accepted B matrices
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4\. Instrumental variables (Proxy-SVAR)
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
model = SVAR(
|
|
131
|
+
data=df, variables=variables, lags=4,
|
|
132
|
+
method="IV",
|
|
133
|
+
iv=\["instrument\_1"], # DataFrame column(s) with the instrument(s)
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Package Structure
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
macroshock/
|
|
142
|
+
├── data.py # construction of Y, X and restriction matrix R
|
|
143
|
+
├── var.py # reduced-form VAR estimation (restricted GLS, IC, t-stats)
|
|
144
|
+
├── stats.py # statistical utilities (Student's t CDF and p-values)
|
|
145
|
+
├── identification.py # the 4 structural identification methods
|
|
146
|
+
├── irf.py # impulse-response functions and bands from bootstrap
|
|
147
|
+
├── fevd.py # forecast error variance decomposition
|
|
148
|
+
├── fc.py # forecast computation
|
|
149
|
+
├── bootstrap.py # bootstrap (normal / wild) for IR, FC and FEVD
|
|
150
|
+
├── plotting.py # IRF, forecast and FEVD plots
|
|
151
|
+
└── macroshock.py # main SVAR class (and SVEC, LP scaffolds for future development)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Roadmap
|
|
155
|
+
|
|
156
|
+
* Full documentation (Sphinx / ReadTheDocs)
|
|
157
|
+
* SVEC model (structural Vector Error Correction)
|
|
158
|
+
* Local Projections (LP)
|
|
159
|
+
* Historical decomposition (`HistoricalDecomp`)
|
|
160
|
+
* Unit tests and CI
|
|
161
|
+
|
|
162
|
+
## Contributing
|
|
163
|
+
|
|
164
|
+
Issues and pull requests are welcome. If you find a bug or have an improvement proposal, open an issue in the project's repository.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
This project is distributed under the MIT license. See the `LICENSE` file for more details.
|
|
169
|
+
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "macroshock"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
dependencies = [
|
|
10
10
|
"numpy>=1.24.0",
|
|
@@ -18,3 +18,6 @@ authors = [
|
|
|
18
18
|
description = "Powerful time series econometrics for Structural Vector Autoregressions (SVAR)"
|
|
19
19
|
readme = {file = "README.md", content-type = "text/markdown"}
|
|
20
20
|
license = { file = "LICENSE"}
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
"GitHub repository" = "https://github.com/patricioariaslpz/macroshock.git"
|
|
@@ -5,10 +5,12 @@ import numpy as np
|
|
|
5
5
|
import pandas as pd
|
|
6
6
|
from scipy.linalg import solve_triangular
|
|
7
7
|
from .var import estimate_var
|
|
8
|
+
from .irf import impulse_response
|
|
8
9
|
from .fc import compute_forecast
|
|
10
|
+
from .fevd import forecast_error_variance_decomposition
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
def bootstrap_svar(model, typ: str, shock: int = 1):
|
|
13
|
+
def bootstrap_svar(model, typ: str, shock: int = 1, reps: int = 100, impact: float = 1.0, steps: int = 30, horizon: int = 5, past: int = 24):
|
|
12
14
|
"""
|
|
13
15
|
Replica la lógica original de SVAR.Bootstrap, pero fuera de la clase.
|
|
14
16
|
|
|
@@ -28,25 +30,28 @@ def bootstrap_svar(model, typ: str, shock: int = 1):
|
|
|
28
30
|
- IR: (reps, steps)
|
|
29
31
|
- FC: (reps, past + horizon)
|
|
30
32
|
"""
|
|
33
|
+
if model.method == 'signs':
|
|
34
|
+
raise ValueError("No bootstrap in sign restriction SVAR")
|
|
35
|
+
|
|
36
|
+
|
|
31
37
|
# BEGIN BOOTSTRAP
|
|
32
38
|
b = 0
|
|
33
39
|
|
|
34
40
|
if typ == "IR":
|
|
35
|
-
draws = {var: np.zeros((
|
|
41
|
+
draws = {var: np.zeros((reps, steps)) for var in model.variables}
|
|
36
42
|
elif typ == "FC":
|
|
37
|
-
draws = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
43
|
+
draws = {var: np.zeros((reps, past + horizon)) for var in model.variables}
|
|
44
|
+
elif typ == "VD":
|
|
45
|
+
draws = {var: np.zeros((reps, steps)) for var in model.variables}
|
|
41
46
|
else:
|
|
42
|
-
raise ValueError("typ must be 'IR' or '
|
|
47
|
+
raise ValueError("typ must be 'IR', 'FC' or 'VD'.")
|
|
43
48
|
|
|
44
49
|
while True:
|
|
45
50
|
# progreso
|
|
46
51
|
if b in list(
|
|
47
|
-
range(int(
|
|
52
|
+
range(int(reps / 10) - 1, reps, int(reps / 10))
|
|
48
53
|
):
|
|
49
|
-
print(str(b + 1) + "/" + str(
|
|
54
|
+
print(str(b + 1) + "/" + str(reps))
|
|
50
55
|
|
|
51
56
|
# ---------- tipo de remuestreo ----------
|
|
52
57
|
if model.resampling == 1: # normal
|
|
@@ -152,11 +157,11 @@ def bootstrap_svar(model, typ: str, shock: int = 1):
|
|
|
152
157
|
[np.ones((model.n_obs, 1)), trend, trend**2, Xsim]
|
|
153
158
|
)
|
|
154
159
|
|
|
155
|
-
if model.
|
|
156
|
-
if len(model.
|
|
157
|
-
Xsim_exog = model.
|
|
160
|
+
if model.data_exogenous is not None:
|
|
161
|
+
if len(model.variables_exogenous) == model.n_obs:
|
|
162
|
+
Xsim_exog = model.data_exogenous
|
|
158
163
|
else:
|
|
159
|
-
Xsim_exog = model.
|
|
164
|
+
Xsim_exog = model.data_exogenous[-model.n_obs :]
|
|
160
165
|
if len(Xsim_exog) != model.n_obs:
|
|
161
166
|
print("Exogenous variables in different domain")
|
|
162
167
|
Xsim = np.hstack([Xsim, Xsim_exog])
|
|
@@ -237,8 +242,8 @@ def bootstrap_svar(model, typ: str, shock: int = 1):
|
|
|
237
242
|
|
|
238
243
|
# ---------- almacenar draws ----------
|
|
239
244
|
if typ == "IR":
|
|
240
|
-
ir_b =
|
|
241
|
-
|
|
245
|
+
ir_b = impulse_response(Bsim, Fsim, shock, steps=steps, impact=impact)
|
|
246
|
+
|
|
242
247
|
if np.any(Bsim != 0):
|
|
243
248
|
if model.method in ("short", "long", "IV"):
|
|
244
249
|
for k in range(model.n_vars):
|
|
@@ -252,8 +257,20 @@ def bootstrap_svar(model, typ: str, shock: int = 1):
|
|
|
252
257
|
for k in range(model.n_vars):
|
|
253
258
|
draws[model.variables[k]][b, :] = fc_b[:, k]
|
|
254
259
|
b += 1
|
|
260
|
+
|
|
261
|
+
if typ == "VD":
|
|
262
|
+
vd_dict = forecast_error_variance_decomposition(
|
|
263
|
+
Bsim, Fsim, steps=steps
|
|
264
|
+
)
|
|
265
|
+
if np.any(Bsim != 0):
|
|
266
|
+
if model.method in ("short", "long", "IV"):
|
|
267
|
+
for k in range(model.n_vars):
|
|
268
|
+
# vd_dict[k + 1] gets the (steps, n_vars) FEVD matrix for variable k+1.
|
|
269
|
+
# [:, shock - 1] isolates the proportion of variance explained by 'shock'.
|
|
270
|
+
draws[model.variables[k]][b, :] = vd_dict[k + 1][:, shock - 1]
|
|
271
|
+
b += 1
|
|
255
272
|
|
|
256
|
-
if b >=
|
|
273
|
+
if b >= reps:
|
|
257
274
|
break
|
|
258
275
|
|
|
259
276
|
return draws
|
|
@@ -32,11 +32,11 @@ def YX(model) -> YXR:
|
|
|
32
32
|
|
|
33
33
|
model.n_obs, _ = X.shape
|
|
34
34
|
|
|
35
|
-
if model.
|
|
35
|
+
if model.data_exogenous is not None:
|
|
36
36
|
if model.n_obsex==model.n_obs:
|
|
37
|
-
X_exog=model.
|
|
37
|
+
X_exog=model.data_exogenous
|
|
38
38
|
else:
|
|
39
|
-
X_exog=model.
|
|
39
|
+
X_exog=model.data_exogenous[-model.n_obs:]
|
|
40
40
|
if len(X_exog)!=model.n_obs:
|
|
41
41
|
print('Exogenous variables in different domain')
|
|
42
42
|
X=np.hstack([X,X_exog])
|
|
@@ -38,7 +38,7 @@ def compute_forecast(modelo, F):
|
|
|
38
38
|
if modelo.const == 1:
|
|
39
39
|
FYs += beta_const
|
|
40
40
|
elif modelo.const == 2:
|
|
41
|
-
FYs += beta_const + (
|
|
41
|
+
FYs += beta_const + (i * beta_trend)
|
|
42
42
|
elif modelo.const == 3:
|
|
43
43
|
FYs += beta_const + (i * beta_trend) + ((i**2) * beta_sqrd)
|
|
44
44
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# fevd.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def forecast_error_variance_decomposition(
|
|
8
|
+
B: np.ndarray,
|
|
9
|
+
F: np.ndarray,
|
|
10
|
+
steps: int = 10,
|
|
11
|
+
) -> dict[int, np.ndarray]:
|
|
12
|
+
"""Compute Forecast Error Variance Decomposition (FEVD) for a given structural matrix B
|
|
13
|
+
|
|
14
|
+
and companion matrix F.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
B : np.ndarray
|
|
19
|
+
Impact matrix of shape (n_vars, n_vars).
|
|
20
|
+
F : np.ndarray
|
|
21
|
+
Companion matrix of shape (n_vars * lags, n_vars * lags).
|
|
22
|
+
steps : int, optional
|
|
23
|
+
Forecast horizon steps (default is 10).
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
dict[int, np.ndarray]
|
|
28
|
+
Dictionary keyed by 1-based variable index (1, 2, ..., n_vars).
|
|
29
|
+
Each value is an array of shape (steps, n_vars) containing the share
|
|
30
|
+
of variance contributed by each shock j to variable i over horizon h.
|
|
31
|
+
"""
|
|
32
|
+
B = np.asarray(B, dtype=float)
|
|
33
|
+
F = np.asarray(F, dtype=float)
|
|
34
|
+
|
|
35
|
+
n_vars = B.shape[0]
|
|
36
|
+
|
|
37
|
+
# 1. Pre-calculate Orthogonalized Impulse Responses for all horizons.
|
|
38
|
+
# Accumulate F^h incrementally (F^h = F^(h-1) @ F) instead of calling
|
|
39
|
+
# np.linalg.matrix_power(F, h) from scratch at every horizon.
|
|
40
|
+
theta = np.zeros((steps, n_vars, n_vars))
|
|
41
|
+
F_power = np.eye(F.shape[0]) # F^0
|
|
42
|
+
for h in range(steps):
|
|
43
|
+
Psi_h = F_power[:n_vars, :n_vars]
|
|
44
|
+
theta[h] = Psi_h @ B
|
|
45
|
+
F_power = F_power @ F # advance to F^(h+1) for the next iteration
|
|
46
|
+
|
|
47
|
+
# 2. Calculate Variance Decomposition per variable
|
|
48
|
+
VD = {}
|
|
49
|
+
for i in range(n_vars):
|
|
50
|
+
vardec = np.zeros((steps, n_vars))
|
|
51
|
+
for k in range(steps):
|
|
52
|
+
# Squared responses of variable i to all shocks j up to step k
|
|
53
|
+
squared_responses = theta[: k + 1, i, :] ** 2
|
|
54
|
+
mse_ij = np.sum(squared_responses, axis=0)
|
|
55
|
+
|
|
56
|
+
total_mse_i = np.sum(mse_ij)
|
|
57
|
+
if total_mse_i > 0:
|
|
58
|
+
vardec[k, :] = mse_ij / total_mse_i
|
|
59
|
+
|
|
60
|
+
# Store using 1-based variable index
|
|
61
|
+
VD[i + 1] = vardec
|
|
62
|
+
|
|
63
|
+
return VD
|