dsgelab 0.5.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.
- dsgelab-0.5.0/CHANGELOG.md +235 -0
- dsgelab-0.5.0/CITATION.cff +23 -0
- dsgelab-0.5.0/LICENSE +21 -0
- dsgelab-0.5.0/MANIFEST.in +5 -0
- dsgelab-0.5.0/PKG-INFO +332 -0
- dsgelab-0.5.0/README.md +298 -0
- dsgelab-0.5.0/pyproject.toml +58 -0
- dsgelab-0.5.0/setup.cfg +4 -0
- dsgelab-0.5.0/src/dsgelab/__init__.py +129 -0
- dsgelab-0.5.0/src/dsgelab/bgp.py +141 -0
- dsgelab-0.5.0/src/dsgelab/blocks.py +304 -0
- dsgelab-0.5.0/src/dsgelab/calibration.py +208 -0
- dsgelab-0.5.0/src/dsgelab/cli.py +44 -0
- dsgelab-0.5.0/src/dsgelab/diagnostics.py +279 -0
- dsgelab-0.5.0/src/dsgelab/dynare.py +1541 -0
- dsgelab-0.5.0/src/dsgelab/estimate.py +276 -0
- dsgelab-0.5.0/src/dsgelab/estimation.py +719 -0
- dsgelab-0.5.0/src/dsgelab/examples/__init__.py +5 -0
- dsgelab-0.5.0/src/dsgelab/examples/_heutel_source.py +209 -0
- dsgelab-0.5.0/src/dsgelab/examples/heutel.py +210 -0
- dsgelab-0.5.0/src/dsgelab/examples/nk.py +55 -0
- dsgelab-0.5.0/src/dsgelab/examples/rbc.py +92 -0
- dsgelab-0.5.0/src/dsgelab/export.py +276 -0
- dsgelab-0.5.0/src/dsgelab/extended_path.py +355 -0
- dsgelab-0.5.0/src/dsgelab/foresight.py +443 -0
- dsgelab-0.5.0/src/dsgelab/kalman.py +609 -0
- dsgelab-0.5.0/src/dsgelab/klein.py +252 -0
- dsgelab-0.5.0/src/dsgelab/linearize.py +252 -0
- dsgelab-0.5.0/src/dsgelab/model.py +285 -0
- dsgelab-0.5.0/src/dsgelab/occbin.py +363 -0
- dsgelab-0.5.0/src/dsgelab/optimal.py +866 -0
- dsgelab-0.5.0/src/dsgelab/priors.py +168 -0
- dsgelab-0.5.0/src/dsgelab/projection.py +237 -0
- dsgelab-0.5.0/src/dsgelab/py.typed +0 -0
- dsgelab-0.5.0/src/dsgelab/secondorder.py +402 -0
- dsgelab-0.5.0/src/dsgelab/solution.py +491 -0
- dsgelab-0.5.0/src/dsgelab/solve.py +52 -0
- dsgelab-0.5.0/src/dsgelab/steady.py +366 -0
- dsgelab-0.5.0/src/dsgelab/symbolic.py +396 -0
- dsgelab-0.5.0/src/dsgelab/thirdorder.py +370 -0
- dsgelab-0.5.0/src/dsgelab/welfare.py +226 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/PKG-INFO +332 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/SOURCES.txt +71 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/dependency_links.txt +1 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/entry_points.txt +2 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/requires.txt +8 -0
- dsgelab-0.5.0/src/dsgelab.egg-info/top_level.txt +1 -0
- dsgelab-0.5.0/tests/conftest.py +19 -0
- dsgelab-0.5.0/tests/test_assemble.py +61 -0
- dsgelab-0.5.0/tests/test_bgp.py +104 -0
- dsgelab-0.5.0/tests/test_blocks.py +76 -0
- dsgelab-0.5.0/tests/test_calibration.py +66 -0
- dsgelab-0.5.0/tests/test_diagnose.py +84 -0
- dsgelab-0.5.0/tests/test_dynare_import.py +151 -0
- dsgelab-0.5.0/tests/test_estimate.py +57 -0
- dsgelab-0.5.0/tests/test_estimation.py +206 -0
- dsgelab-0.5.0/tests/test_expectation_errors.py +130 -0
- dsgelab-0.5.0/tests/test_export.py +65 -0
- dsgelab-0.5.0/tests/test_extended_path.py +91 -0
- dsgelab-0.5.0/tests/test_first_order.py +85 -0
- dsgelab-0.5.0/tests/test_foresight.py +64 -0
- dsgelab-0.5.0/tests/test_heutel.py +115 -0
- dsgelab-0.5.0/tests/test_klein.py +88 -0
- dsgelab-0.5.0/tests/test_model_checks.py +59 -0
- dsgelab-0.5.0/tests/test_occbin.py +104 -0
- dsgelab-0.5.0/tests/test_optimal.py +153 -0
- dsgelab-0.5.0/tests/test_policy.py +161 -0
- dsgelab-0.5.0/tests/test_projection.py +30 -0
- dsgelab-0.5.0/tests/test_secondorder.py +82 -0
- dsgelab-0.5.0/tests/test_steady_tools.py +50 -0
- dsgelab-0.5.0/tests/test_symbolic.py +74 -0
- dsgelab-0.5.0/tests/test_thirdorder.py +105 -0
- dsgelab-0.5.0/validation/heutel/reference.json +7514 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `dsgelab`. Versions follow [semantic versioning](https://semver.org/);
|
|
4
|
+
before 1.0, a minor version may add to the API and a patch version only fixes bugs.
|
|
5
|
+
|
|
6
|
+
## 0.5.0 — 2026-10-18
|
|
7
|
+
|
|
8
|
+
The roadmap's milestone 0.5, the public release. No new solver features.
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `py.typed`: the package declares its type annotations (PEP 561).
|
|
13
|
+
- CI tests the built wheel on Linux, macOS and Windows with Python 3.11 to 3.14, and
|
|
14
|
+
installs the sdist and tests it from its own tree. The site examples run in CI, and
|
|
15
|
+
`twine check --strict` passes on both artefacts. `DSGELAB_TEST_INSTALLED=1` makes the
|
|
16
|
+
suite import the installed package instead of `src/`.
|
|
17
|
+
- `validation/run_all.sh` runs the whole external validation and summarises which
|
|
18
|
+
comparisons passed. `validation/setup_octave_packages.sh` installs the Octave packages
|
|
19
|
+
at the versions the comparison used, checked by sha256, and `validation/macromodelling/`
|
|
20
|
+
is a Julia project with MacroModelling.jl pinned. A weekly CI job runs all three.
|
|
21
|
+
- A release workflow that publishes by trusted publishing, to TestPyPI first, tests what
|
|
22
|
+
TestPyPI serves, and only then publishes to PyPI.
|
|
23
|
+
- `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, and issue and pull-request templates. The
|
|
24
|
+
README has a section of known limitations.
|
|
25
|
+
- `.github/workflows/pages.yml` publishes the site to GitHub Pages, pointing the links to
|
|
26
|
+
`docs/` at the files on GitHub. It is skipped while the repository is private.
|
|
27
|
+
- The site in English, with the Portuguese version under `site/pt-br/`. The examples of
|
|
28
|
+
both versions run.
|
|
29
|
+
- `validation/heutel/fetch.sh` downloads Heutel's MATLAB files from the public copy at
|
|
30
|
+
Georgia State University's repository and checks them; the six `.m` files are
|
|
31
|
+
byte-identical to the ones the port was validated on.
|
|
32
|
+
- `dsgelab.examples.heutel.fetch()` downloads the same public copy, checks every file
|
|
33
|
+
by SHA-256, and writes the translated algebra of the port to a cache directory
|
|
34
|
+
(`~/.cache/dsgelab/heutel`, or `DSGELAB_HEUTEL_DIR`). Without it, `heutel.solve`
|
|
35
|
+
raises `HeutelSourceMissing` naming the call to make, and the Heutel tests are
|
|
36
|
+
skipped.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- The validation scripts print their reports in English (`s.s.` for steady state,
|
|
41
|
+
`moments`, `max relative deviation`, ...), with the same columns and numbers.
|
|
42
|
+
`compare_estimation.py --no-mh` and `compare_policy.py --no-dynare` are the new flag
|
|
43
|
+
names, and `--sem-mh` and `--sem-dynare` still work.
|
|
44
|
+
- The roadmap is in English (`ROADMAP.md`) and in Portuguese (`ROADMAP.pt-BR.md`).
|
|
45
|
+
- Examples, documentation, tests and validation scripts import the package as
|
|
46
|
+
`import dsgelab as dsg`. The former alias `dk` came from the old name, dsgekit.
|
|
47
|
+
- The site links to cgelab, whose `cgelab.bridge` uses dsgelab for the intertemporal part of
|
|
48
|
+
a model.
|
|
49
|
+
- The one comparison made on a model that is not public (the applied DSGE of an unpublished
|
|
50
|
+
paper) is marked on the site as not reproducible from the repository.
|
|
51
|
+
- The translated algebra of the Heutel port (`dsgelab/examples/_heutel_algebra.py`) is
|
|
52
|
+
no longer distributed, because it is a translation of Heutel's MATLAB files, which
|
|
53
|
+
carry no licence. `heutel.fetch()` generates it on the user's machine, and
|
|
54
|
+
`validation/heutel/translate.py` is gone.
|
|
55
|
+
- The calibration example on the site and in the user guide is replaced by one whose
|
|
56
|
+
targets identify the free parameters (`target_jacobian` reports `identified=True`). The
|
|
57
|
+
former example had a target that held identically, and `calibrate` returned different
|
|
58
|
+
answers from different starting points.
|
|
59
|
+
- The validation figures quoted on the site match the current run of
|
|
60
|
+
`validation/run_all.sh`. The README, `CONTRIBUTING.md`, the roadmap and the API
|
|
61
|
+
reference are corrected where they described the checks, the validation layers or the
|
|
62
|
+
API inaccurately.
|
|
63
|
+
- Python 3.11 or later is required. Python 3.10 is dropped, because SciPy 1.15.3, the
|
|
64
|
+
last release for it, does not load on macOS 27.
|
|
65
|
+
- Error messages, the labels of derived first-order conditions ("FOC for control c",
|
|
66
|
+
"Euler equation for state k", "constraint i: ...") and the header comments of files
|
|
67
|
+
written by `to_dynare` and `to_macromodelling` are in English. The exported model text
|
|
68
|
+
is unchanged.
|
|
69
|
+
- The external validation runs on Dynare 7.2, with Octave 11.3.0 and the Octave packages
|
|
70
|
+
statistics 2.0.0 and datatypes 1.5.0. Every comparison prints the same numbers as on
|
|
71
|
+
Dynare 7.1, and the Heutel errors move in their last digit.
|
|
72
|
+
|
|
73
|
+
### Fixed
|
|
74
|
+
|
|
75
|
+
- `SecondOrderSolution.simulate`, `mean_correction` and `ergodic_mean`, `ThirdOrderSolution.simulate`
|
|
76
|
+
and `solve_third_order`, when given a covariance other than the one the solution was computed at,
|
|
77
|
+
combined risk terms (`g_ss`, `h_ss`) of the old covariance with shocks or a state covariance of the
|
|
78
|
+
new one. On the RBC with the standard deviation doubled, the mean correction of capital came out
|
|
79
|
+
5.8e-05 instead of 2.4e-03. They now solve again at the covariance asked for, through the new
|
|
80
|
+
`SecondOrderSolution.at_covariance`.
|
|
81
|
+
- The sdist now carries `validation/heutel/reference.json`, which its own test suite
|
|
82
|
+
reads.
|
|
83
|
+
- `validation/compare_diagnostics.py` honours `OCTAVE` and `DYNARE_MATLAB` and looks in
|
|
84
|
+
the same places as the other scripts, instead of only in Homebrew's.
|
|
85
|
+
- `modelo.mod` and `modelo.jl`, written by a site example, had been committed at the
|
|
86
|
+
repository root; they are gone, and `tools/check_site_examples.py` now runs the
|
|
87
|
+
examples in a temporary directory.
|
|
88
|
+
- Package metadata uses the SPDX license expression (`license = "MIT"`), which
|
|
89
|
+
setuptools will require from 2027.
|
|
90
|
+
|
|
91
|
+
## 0.4.0 — 2026-10-11
|
|
92
|
+
|
|
93
|
+
The roadmap's milestone 0.4: nonlinearities and the declaration of the model. Each item is
|
|
94
|
+
validated against Dynare 7.1 on Dynare's own test files, against MacroModelling.jl, or
|
|
95
|
+
against a closed form.
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
|
|
99
|
+
- `OccbinModel`, `occbin_simulate`, `OccbinResult`: occasionally binding constraints by
|
|
100
|
+
the piecewise-linear method of Guerrieri and Iacoviello (2015), as in Dynare's
|
|
101
|
+
`+occbin`, with any number of constraints, time-varying rules found backwards, Dynare's
|
|
102
|
+
regime update with `curb_retrench`, surprise shocks with re-planning, and the horizon
|
|
103
|
+
extended while a constraint binds at its end. `from_mod` reads `bind=`/`relax=` equation tags,
|
|
104
|
+
`occbin_constraints`, `shocks(surprise)` and the `occbin_setup`/`occbin_solver`
|
|
105
|
+
options; `ModFile.occbin_simulate` runs them. Against Dynare's `borrcon.mod` (one
|
|
106
|
+
constraint) and `dynrbc.mod` (two) to 2e-15, with identical regime histories.
|
|
107
|
+
- `extended_path`, `quadrature_nodes`, `ExtendedPath`: the extended path (Fair and
|
|
108
|
+
Taylor, 1983) and the stochastic extended path (Adjemian and Juillard) of any order,
|
|
109
|
+
on Dynare's sparse or full tree of Gauss–Hermite nodes, with the hybrid second-order
|
|
110
|
+
risk correction, and `ModFile.extended_path`. Against Dynare's `burnside.mod` in seven
|
|
111
|
+
variants to 1.1e-11, and `linearmodel0.mod` to 2e-15.
|
|
112
|
+
- Declared trends in `from_mod`: `trend_var`, `log_trend_var`, `var(deflator=)` and
|
|
113
|
+
`var(log_deflator=)` are detrended as Dynare does, and an equation that still depends
|
|
114
|
+
on the level of a trend is refused (Dynare's balanced-growth test, checked at several
|
|
115
|
+
points). `fs2000_nonstationary.mod` from Dynare's tests joins `compare_import`.
|
|
116
|
+
- `balanced_growth`, `BalancedGrowth`, `ModFile.balanced_growth`: Dynare's `bgp.write`
|
|
117
|
+
problem, solved by Levenberg–Marquardt with restarts away from degenerate paths. The
|
|
118
|
+
residual matches Dynare's generated `bgpfun` to 2.2e-16 on its three tests.
|
|
119
|
+
- `diagnose`, Dynare's `model_diagnostics`. It reports variables absent at the current
|
|
120
|
+
date, collinear relations of the static Jacobian with their variables and equations,
|
|
121
|
+
redundant equations of the dynamic Jacobian, and unit roots, and gives the same report
|
|
122
|
+
as Dynare on a model broken on purpose.
|
|
123
|
+
- `analytic_steady_state`, `SteadyStateError`, `from_equations(steady_state_model=)` and
|
|
124
|
+
`ModFile.steady_state(analytic=True)`. A closed-form steady state is used only after it
|
|
125
|
+
zeroes the model's residuals, and refused otherwise, as Dynare refuses it.
|
|
126
|
+
- Calibration equations inside the model, MacroModelling's `k[ss]/q[ss] = 2.5 | β`:
|
|
127
|
+
`from_equations(calibration_equations=)` and `steady_state(calibrate=)`. Against
|
|
128
|
+
MacroModelling.jl to 4e-15.
|
|
129
|
+
- `steady_state(homotopy=)` and `homotopy_setup` in `from_mod`: continuation from a
|
|
130
|
+
parameter value where the model is easy, with adaptive steps.
|
|
131
|
+
- `assemble`: several agents' optimisation problems and the closing equations in one
|
|
132
|
+
`Model`, refusing a variable chosen twice and renaming clashing multipliers.
|
|
133
|
+
- `from_equations` accepts lags and leads of any order, each carried by an auxiliary
|
|
134
|
+
listed in `model.auxiliary`; a guess without the auxiliaries gets them from their
|
|
135
|
+
variables.
|
|
136
|
+
|
|
137
|
+
### Changed
|
|
138
|
+
|
|
139
|
+
- `perfect_foresight(jacobian="auto")` is the default: the stacked Jacobian is assembled
|
|
140
|
+
sparse from the model's exact derivatives when it has them (forward differences
|
|
141
|
+
otherwise); ex-post states use them too.
|
|
142
|
+
- `klein` uses the real ordered QZ by default, the complex one as a fallback: SciPy 1.18's
|
|
143
|
+
complex reordering loses up to 1e-8 on a pencil with a zero root and refuses one with
|
|
144
|
+
several infinite roots.
|
|
145
|
+
- Moments and variance decompositions of a model with a unit root mask the
|
|
146
|
+
nonstationary entries (`nan`) instead of failing; the Lyapunov equation is solved on
|
|
147
|
+
the stationary block of an ordered Schur form.
|
|
148
|
+
- `from_mod` refuses a name declared twice.
|
|
149
|
+
|
|
150
|
+
## 0.3.0 — 2026-10-11
|
|
151
|
+
|
|
152
|
+
The first version that carries the roadmap's milestones 0.2 (optimal policy, welfare,
|
|
153
|
+
perfect foresight with news) and 0.3 (estimation, smoothing, decomposition,
|
|
154
|
+
forecasting), each item validated against Dynare 7.1 on Dynare's own files.
|
|
155
|
+
|
|
156
|
+
### Changed
|
|
157
|
+
|
|
158
|
+
- Renamed from `dsgekit` to `dsgelab`: `dsgekit` is taken on PyPI by an unrelated
|
|
159
|
+
project. The import name, distribution name, CLI entry point and URLs move together.
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
|
|
163
|
+
- `state_space`, `kalman_filter`, `kalman_smoother`: the state space of a first-order
|
|
164
|
+
solution, with observables in levels or logs (Dynare's `loglinear` with `logdata`),
|
|
165
|
+
measurement errors and missing data; the filter starts stationary roots at their
|
|
166
|
+
unconditional law and unit roots with the exact diffuse initialisation (Koopman and Durbin, 2000, unit
|
|
167
|
+
roots first in the Schur form, as Dynare does). The likelihood matches Dynare's on
|
|
168
|
+
`fs2000.mod` to 6e-12 and its `diffuse_filter` to 2.5e-12, and the smoother matches to
|
|
169
|
+
1e-14.
|
|
170
|
+
- `EstimationProblem`, `posterior_mode`, `maximum_likelihood`, `metropolis_hastings`,
|
|
171
|
+
`smc`, `prior_predictive`, `model_probabilities`, `posterior_forecast`, `rhat`,
|
|
172
|
+
`effective_sample_size`: estimation, with Dynare's priors by mean and standard
|
|
173
|
+
deviation (`prior`), the Laplace and modified-harmonic-mean marginal likelihoods,
|
|
174
|
+
and `ModFile.estimation_problem` reading `estimated_params`, `varobs` and the options
|
|
175
|
+
of `estimation(...)`. Validated on Dynare's `fs2000.mod`: prior density to 4e-13, a
|
|
176
|
+
mode at least as high as Dynare's, Laplace by the same formula to 2e-13, and posterior
|
|
177
|
+
means within 3 Monte Carlo standard errors of Dynare's (largest 2.9).
|
|
178
|
+
- `shock_decomposition`, `realtime_shock_decomposition`, `forecast`: against Dynare's
|
|
179
|
+
commands of the same names to 5e-15 (forecast bands to 6e-9).
|
|
180
|
+
- `FirstOrderSolution.conditional_forecast(..., controlled=, levels=)`: Dynare's
|
|
181
|
+
`conditional_forecast` with `controlled_varexo`, to 1.6e-13 on its own test file.
|
|
182
|
+
- `perfect_foresight_with_expectation_errors` and `News`: agents re-plan at each date of
|
|
183
|
+
news from the states they have reached; constant or shrinking horizon. Validated
|
|
184
|
+
against Dynare's `pfwee.mod` and `pfwee_constant_sim_length.mod` to 3e-12.
|
|
185
|
+
- `perfect_foresight(..., shocks=)` validated against Dynare's `rbc_det1`–`3`
|
|
186
|
+
(anticipated shocks, initial conditions) to 1e-13.
|
|
187
|
+
- `from_mod`: exogenous variables carry their level (`EXO_SS_e`, from `initval`), may
|
|
188
|
+
appear one period ahead, and the deterministic `shocks` block and `histval` are read;
|
|
189
|
+
`ModFile.deterministic`, `ModFile.news`, `ModFile.initial_states` and
|
|
190
|
+
`read_expectation_errors_csv` turn them into arguments for the solvers.
|
|
191
|
+
- `osr(..., objective=, discount=)`: an optimal simple rule on welfare (minus
|
|
192
|
+
unconditional welfare at second order), Dynare's `osr` with `planner_objective`.
|
|
193
|
+
- `discretionary_policy` and `DiscretionSolution`: optimal policy under discretion
|
|
194
|
+
(Dennis, 2007, as Dynare implements it), with IRFs, moments and welfare. Validated
|
|
195
|
+
against Galí's closed form and Dynare's `tests/discretionary_policy/dennis_1.mod`.
|
|
196
|
+
- `osr` and `OSRResult`: optimal simple rules on a quadratic loss in unconditional
|
|
197
|
+
moments, Dynare's `optim_weights` convention. On Dynare's `osr_example.mod` the loss
|
|
198
|
+
matches Dynare's at its optimum to 2.6e-16, and the optimiser finds a lower one, which
|
|
199
|
+
Dynare's own objective confirms.
|
|
200
|
+
- `welfare`, `welfare_model`, `consumption_equivalent`: second-order welfare,
|
|
201
|
+
conditional and unconditional, and for Ramsey models with the lagged multipliers at
|
|
202
|
+
zero. Matches Dynare's `evaluate_planner_objective` to 1.4e-12 for Ramsey and to
|
|
203
|
+
6.1e-10 under discretion.
|
|
204
|
+
- `from_mod` reads `planner_objective`, `ramsey_model`, `discretionary_policy`,
|
|
205
|
+
`osr_params`, `optim_weights` and `osr_params_bounds`; `ramsey_model` and
|
|
206
|
+
`discretionary_policy` accept the resulting `ModFile`. `PrivateBlock` holds a
|
|
207
|
+
private sector with instruments left open.
|
|
208
|
+
- `ramsey_model`, `ramsey_steady_state`, `ramsey_multipliers`: the Ramsey planner under
|
|
209
|
+
commitment, timeless perspective, derived symbolically from the private-sector
|
|
210
|
+
equations and a period objective. Validated against Galí's targeting rule and closed
|
|
211
|
+
form, and against Dynare's `ramsey_model` on three models
|
|
212
|
+
(`validation/compare_ramsey.py`).
|
|
213
|
+
- `from_mod`, `ModFile`: read a Dynare `.mod` file, with macros, model-local variables,
|
|
214
|
+
`steady_state()`, and leads and lags of any order. Validated on eight `.mod` files read
|
|
215
|
+
unchanged, five of them from Dynare's `examples/` (`validation/compare_import.py`).
|
|
216
|
+
- `solve(..., qz_criterium=)` and `klein(..., qz_criterium=)`: Dynare's convention that
|
|
217
|
+
admits a unit root.
|
|
218
|
+
- `perfect_foresight(..., shocks=)`: a path of innovations, anticipated from the start.
|
|
219
|
+
- `SecondOrderSolution.irf`: the generalised impulse response of the pruned rule.
|
|
220
|
+
- `FirstOrderSolution.historical_decomposition` and `conditional_forecast`.
|
|
221
|
+
- `symbolic.parse_system` and `symbolic.model_from_expressions`: the symbolic front end
|
|
222
|
+
split in two, so that derived equations reach the model builder without being printed
|
|
223
|
+
and re-parsed.
|
|
224
|
+
|
|
225
|
+
## 0.2.0
|
|
226
|
+
|
|
227
|
+
- Third-order risk slopes, linear estimation (Kalman filter, posterior mode,
|
|
228
|
+
random-walk Metropolis) and Chebyshev projection.
|
|
229
|
+
- Standalone package, separate from the research repository.
|
|
230
|
+
|
|
231
|
+
## 0.1.0
|
|
232
|
+
|
|
233
|
+
- Steady state, first-order (Klein/QZ) and second-order perturbation, perfect foresight,
|
|
234
|
+
calibration on targets, symbolic front end, first-order-condition derivation,
|
|
235
|
+
exporters to Dynare and MacroModelling.jl.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software in a publication, please cite it as below."
|
|
3
|
+
type: software
|
|
4
|
+
title: "dsgelab: a general toolkit for solving DSGE models in Python"
|
|
5
|
+
abstract: >-
|
|
6
|
+
Steady state, Klein/QZ first-order solution, second-order perturbation and a partial third order (the cubic block and the risk slope), Chebyshev projection, perfect foresight with expectation errors, optimal policy (Ramsey, discretion, optimal simple rules) and welfare, Kalman filtering and smoothing, Bayesian estimation, shock decompositions and forecasts, reading Dynare .mod files, and export to Dynare and MacroModelling.jl. Validated against Dynare, MacroModelling.jl and closed-form solutions.
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: "Moreira"
|
|
9
|
+
given-names: "Gustavo Hoffmann"
|
|
10
|
+
email: "gustavo@gakusai.net"
|
|
11
|
+
orcid: "https://orcid.org/0000-0003-0827-2521"
|
|
12
|
+
version: "0.5.0"
|
|
13
|
+
date-released: "2026-10-18"
|
|
14
|
+
license: MIT
|
|
15
|
+
# The DOI is filled in with the first release archived on Zenodo, which makes the citation stable,
|
|
16
|
+
# since a repository URL is not an archivable reference.
|
|
17
|
+
repository-code: "https://github.com/GustavoHM/dsgelab"
|
|
18
|
+
# doi: "10.5281/zenodo.XXXXXXX"
|
|
19
|
+
keywords:
|
|
20
|
+
- "DSGE"
|
|
21
|
+
- "perturbation"
|
|
22
|
+
- "rational expectations"
|
|
23
|
+
- "Python"
|
dsgelab-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gustavo Hoffmann Moreira
|
|
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,5 @@
|
|
|
1
|
+
# The sdist carries the test suite, and test_heutel.py reads its reference
|
|
2
|
+
# values from validation/. Nothing else under validation/ is needed to test.
|
|
3
|
+
include CHANGELOG.md CITATION.cff LICENSE README.md
|
|
4
|
+
recursive-include tests *.py
|
|
5
|
+
include validation/heutel/reference.json
|
dsgelab-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dsgelab
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Solve, simulate and estimate DSGE models in Python: perturbation to second order (and a partial third order), perfect foresight, OccBin, optimal policy, Bayesian estimation and Dynare .mod import, validated against Dynare.
|
|
5
|
+
Author-email: Gustavo Hoffmann Moreira <gustavo@gakusai.net>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/GustavoHM/dsgelab
|
|
8
|
+
Project-URL: Documentation, https://github.com/GustavoHM/dsgelab/tree/main/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/GustavoHM/dsgelab
|
|
10
|
+
Project-URL: Issues, https://github.com/GustavoHM/dsgelab/issues
|
|
11
|
+
Keywords: dsge,perturbation,rational expectations,klein,macroeconomics
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
22
|
+
Classifier: Intended Audience :: Science/Research
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: numpy>=1.24
|
|
28
|
+
Requires-Dist: scipy>=1.10
|
|
29
|
+
Provides-Extra: symbolic
|
|
30
|
+
Requires-Dist: sympy>=1.12; extra == "symbolic"
|
|
31
|
+
Provides-Extra: test
|
|
32
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# dsgelab
|
|
36
|
+
|
|
37
|
+
[](https://github.com/GustavoHM/dsgelab/actions/workflows/tests.yml)
|
|
38
|
+
[](https://github.com/GustavoHM/dsgelab/blob/main/LICENSE)
|
|
39
|
+
|
|
40
|
+
A general toolkit for solving DSGE models in Python. A model is declared once, as lists of
|
|
41
|
+
state, jump and shock names and one function that returns the equilibrium residuals. The
|
|
42
|
+
package computes the steady state, the first-order solution, impulse responses, moments,
|
|
43
|
+
second-order risk corrections, nonlinear perfect-foresight transitions and calibration on
|
|
44
|
+
targets from that declaration.
|
|
45
|
+
|
|
46
|
+
The package is built so that the stochastic block and the deterministic transition are the
|
|
47
|
+
*same model*. One way applied work fails is a perturbation solution built on one set of
|
|
48
|
+
equations beside a transition path solved by a hand-written fixed point on another set, similar
|
|
49
|
+
to the first but not identical. Here both call the same residual function, so the equations
|
|
50
|
+
behind them cannot differ.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
pip install dsgelab
|
|
54
|
+
pip install "dsgelab[symbolic]" # adds text equations with exact derivatives (sympy)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Requires Python 3.11 or later, numpy and scipy. Pandas is not needed.
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
import dsgelab as dsg
|
|
63
|
+
from dsgelab.examples import rbc
|
|
64
|
+
|
|
65
|
+
model, params, guess = rbc.build()
|
|
66
|
+
sol = dsg.solve(model, params, guess=guess)
|
|
67
|
+
|
|
68
|
+
print(sol.summary())
|
|
69
|
+
irf = sol.irf("eps_a", size=0.01, periods=40) # per cent deviations
|
|
70
|
+
mom = sol.moments(cov={"eps_a": 0.007}) # std, corr, autocorr
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
A model of your own takes three lists and a function. The parameters can be any object with
|
|
74
|
+
attributes, here a dataclass.
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import numpy as np
|
|
78
|
+
from dataclasses import dataclass
|
|
79
|
+
from dsgelab import Model, solve
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class P:
|
|
83
|
+
alpha: float = 0.36
|
|
84
|
+
beta: float = 0.99
|
|
85
|
+
delta: float = 1.0
|
|
86
|
+
gamma: float = 1.0
|
|
87
|
+
rho: float = 0.95
|
|
88
|
+
|
|
89
|
+
def equations(nxt, cur, eps, p):
|
|
90
|
+
y = cur.a * cur.k ** p.alpha
|
|
91
|
+
y1 = nxt.a * nxt.k ** p.alpha
|
|
92
|
+
return [
|
|
93
|
+
nxt.k - ((1 - p.delta) * cur.k + y - cur.c), # resource
|
|
94
|
+
cur.c ** -p.gamma - p.beta * nxt.c ** -p.gamma # Euler
|
|
95
|
+
* (p.alpha * y1 / nxt.k + 1 - p.delta),
|
|
96
|
+
np.log(nxt.a) - p.rho * np.log(cur.a) - eps.eps_a, # technology
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
model = Model(states=["k", "a"], jumps=["c"], shocks=["eps_a"], equations=equations)
|
|
100
|
+
sol = solve(model, P(), guess={"k": 0.2, "a": 1.0, "c": 0.36})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Variables are addressed by *name*, in `cur` for period `t` and `nxt` for `t+1`. When
|
|
104
|
+
variables are read from a vector by position, swapping one index for another raises no error,
|
|
105
|
+
and the program solves a different model from the one intended. Reading each variable by name
|
|
106
|
+
rules that mistake out.
|
|
107
|
+
|
|
108
|
+
The [user guide](https://github.com/GustavoHM/dsgelab/blob/main/docs/guide.md) goes from the
|
|
109
|
+
declaration to second order, and the [site](https://gustavohm.github.io/dsgelab/) has runnable
|
|
110
|
+
examples in English and Portuguese.
|
|
111
|
+
|
|
112
|
+
## Terms
|
|
113
|
+
|
|
114
|
+
- A *state* (predetermined variable) has its value for period `t` fixed before the innovation
|
|
115
|
+
of period `t` arrives, as capital and the technology level do. A *jump* (non-predetermined
|
|
116
|
+
variable), such as consumption, moves within the period in response to that innovation.
|
|
117
|
+
- *Klein/QZ* is Klein's method for the linearised model, which orders the generalised Schur
|
|
118
|
+
(QZ) decomposition of the matrix pair `(B, A)` of the canonical form below.
|
|
119
|
+
- The *risk correction* is the second-order term that shifts the decision rules in proportion
|
|
120
|
+
to the variance of future shocks. At first order it is zero.
|
|
121
|
+
- *Pruning* drops, when the second-order rule is simulated, the terms of order higher than two
|
|
122
|
+
that the recursion would otherwise accumulate, so that simulated paths do not diverge.
|
|
123
|
+
|
|
124
|
+
## What is in the box
|
|
125
|
+
|
|
126
|
+
| Capability | Entry point |
|
|
127
|
+
|---|---|
|
|
128
|
+
| Steady state, with positivity and outer anchors | `steady_state` |
|
|
129
|
+
| First-order solution (Klein/QZ, Blanchard–Kahn enforced) | `solve` |
|
|
130
|
+
| Impulse responses, simulation, moments, variance decomposition | `FirstOrderSolution` |
|
|
131
|
+
| Second-order perturbation and risk corrections | `solve_second_order` |
|
|
132
|
+
| Third-order perturbation, partial (the cubic block and the risk slope) | `solve_third_order` |
|
|
133
|
+
| Global solution by Chebyshev collocation, up to three states | `solve_projection` |
|
|
134
|
+
| Nonlinear perfect-foresight transitions, announced policy and shock paths | `perfect_foresight` |
|
|
135
|
+
| Perfect foresight with expectation errors (news, surprises) | `perfect_foresight_with_expectation_errors` |
|
|
136
|
+
| Ramsey optimal policy under commitment (timeless), validated against Dynare | `ramsey_model` |
|
|
137
|
+
| Optimal policy under discretion; optimal simple rules, on moments or on welfare | `discretionary_policy`, `osr` |
|
|
138
|
+
| Kalman filter (exact diffuse start) and smoother; measurement error; missing data | `state_space`, `kalman_filter`, `kalman_smoother` |
|
|
139
|
+
| Bayesian estimation: mode, Laplace, Metropolis-Hastings, SMC, R-hat, ESS, marginal likelihood; maximum likelihood | `EstimationProblem`, `posterior_mode`, `metropolis_hastings`, `smc` |
|
|
140
|
+
| Shock decomposition (also real-time), forecasts with bands, conditional forecasts | `shock_decomposition`, `forecast`, the method `FirstOrderSolution.conditional_forecast` |
|
|
141
|
+
| Welfare at second order, conditional and unconditional; consumption equivalent | `welfare`, `consumption_equivalent` |
|
|
142
|
+
| Occasionally binding constraints (OccBin), any number of them, surprise shocks | `OccbinModel`, `occbin_simulate` |
|
|
143
|
+
| Extended path, deterministic and stochastic (sparse or full tree, hybrid correction) | `extended_path` |
|
|
144
|
+
| Models in levels: declared trends with Dynare's balanced-growth check; the growth path | `from_mod`, `balanced_growth` |
|
|
145
|
+
| Read a Dynare `.mod` file, macros and leads/lags included | `from_mod` |
|
|
146
|
+
| Export a model to Dynare and to MacroModelling.jl | `to_dynare`, `to_macromodelling` |
|
|
147
|
+
| Calibration on targets, with an identification diagnostic; calibration equations inside the model | `calibrate`, `target_jacobian`, `from_equations(calibration_equations=)` |
|
|
148
|
+
| Closed-form steady states, checked before use; homotopy for hard steady states | `analytic_steady_state`, `steady_state(homotopy=)` |
|
|
149
|
+
| Model diagnostics (Dynare's `model_diagnostics`) and independent checks | `diagnose`, `dsgelab.diagnostics` |
|
|
150
|
+
| Text equations with exact analytic derivatives, lags and leads of any order | `dsgelab.symbolic` |
|
|
151
|
+
| Several agents' optimisation problems in one equilibrium | `assemble` |
|
|
152
|
+
|
|
153
|
+
## Timing convention
|
|
154
|
+
|
|
155
|
+
`eps` is the innovation dated `t+1`, unknown at `t`, with `E_t eps_{t+1} = 0`. An AR(1) is
|
|
156
|
+
written as the residual
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
def equations(nxt, cur, eps, p):
|
|
160
|
+
return [nxt.a - p.rho * cur.a - eps.eps_a]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
and the resulting law of motion is `k_{t+1} = P k_t + Q eps_{t+1}`. Treating the innovation as
|
|
164
|
+
known at `t` instead makes the model deterministic within the period, and every second-order
|
|
165
|
+
risk correction then comes out zero without a warning. Of the package's conventions, this is
|
|
166
|
+
the only one it cannot check in a user's model.
|
|
167
|
+
|
|
168
|
+
Two checks run on every model without being requested. `solve` raises `BlanchardKahnError`
|
|
169
|
+
when the Blanchard–Kahn condition fails, and the steady state is accepted only when it zeroes
|
|
170
|
+
the residuals. Three others take one call each by the user. `check_identity` tests an
|
|
171
|
+
identity such as Walras's law, `sol.accuracy()` reports the order of accuracy of a solution,
|
|
172
|
+
and `target_jacobian` checks whether calibration targets identify the free parameters, which
|
|
173
|
+
`calibrate` does not check by itself.
|
|
174
|
+
|
|
175
|
+
## Canonical form
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
A E_t x_{t+1} = B x_t + C eps_{t+1}, x_t = [k_t ; u_t]
|
|
179
|
+
u_t = F k_t
|
|
180
|
+
k_{t+1} = P k_t + Q eps_{t+1}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
with `k` the predetermined variables (states) and `u` the non-predetermined ones (jumps). The
|
|
184
|
+
Blanchard–Kahn condition requires the number of stable generalised eigenvalues of the matrix
|
|
185
|
+
pair `(B, A)` to equal the number of states. When it fails, the equilibrium is indeterminate
|
|
186
|
+
or does not exist, and `solve` raises `BlanchardKahnError` instead of returning `F` and `P`.
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
- [`docs/whitepaper.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/whitepaper.md), the mathematics the solvers implement
|
|
191
|
+
- [`docs/guide.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/guide.md), the user guide, from the declaration to second order
|
|
192
|
+
- [`docs/api.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/api.md), the API reference
|
|
193
|
+
- [`docs/design-notes.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/design-notes.md), the numerical decisions and the errors each one avoids
|
|
194
|
+
- [`docs/from-scripts.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/from-scripts.md), porting an existing research script
|
|
195
|
+
- [`docs/comparison.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/comparison.md), how this package compares with the existing ones, and what it lacks
|
|
196
|
+
- [`ROADMAP.md`](https://github.com/GustavoHM/dsgelab/blob/main/ROADMAP.md), what is still missing, and when it is planned
|
|
197
|
+
- [`CONTRIBUTING.md`](https://github.com/GustavoHM/dsgelab/blob/main/CONTRIBUTING.md), how to report a problem and what a contribution needs
|
|
198
|
+
- [The site](https://gustavohm.github.io/dsgelab/), with runnable examples in English and Portuguese (source in [`site/`](https://github.com/GustavoHM/dsgelab/tree/main/site))
|
|
199
|
+
|
|
200
|
+
Questions and bug reports go to the [issue tracker](https://github.com/GustavoHM/dsgelab/issues).
|
|
201
|
+
|
|
202
|
+
## Heutel environmental-policy example
|
|
203
|
+
|
|
204
|
+
[`docs/heutel.md`](https://github.com/GustavoHM/dsgelab/blob/main/docs/heutel.md) documents the
|
|
205
|
+
first-order port of Heutel's (2012) MATLAB replication scripts, including the optimal tax and
|
|
206
|
+
the tax and quota rules with lagged information. The port is checked against the original
|
|
207
|
+
algebra, run in Octave, and against impulse responses and moments solved independently in
|
|
208
|
+
Dynare.
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
from dsgelab.examples import heutel
|
|
212
|
+
heutel.fetch() # once per machine; needs an internet connection
|
|
213
|
+
sol = heutel.solve("tax")
|
|
214
|
+
irf = sol.irf("eps_a", size=0.01, periods=100)
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The planner script's sensitivity calibration fails the admissible steady-state check, so the
|
|
218
|
+
Table 2 baseline has to be requested explicitly, with `heutel.solve("planner", heutel.Params())`.
|
|
219
|
+
Without it, `heutel.solve("planner")` raises `heutel.SteadyStateError`. The documentation lists
|
|
220
|
+
the differences between the supplied code and the published paper.
|
|
221
|
+
|
|
222
|
+
The port's scalar algebra is translated from Heutel's MATLAB files, which carry no licence, so
|
|
223
|
+
it is not distributed with the package. `heutel.fetch()` downloads the public copy from Georgia
|
|
224
|
+
State University's repository, checks each file against the SHA-256 of the files the port was
|
|
225
|
+
validated on, and writes the translation to `~/.cache/dsgelab/heutel` (or to
|
|
226
|
+
`DSGELAB_HEUTEL_DIR`).
|
|
227
|
+
|
|
228
|
+
## Verification
|
|
229
|
+
|
|
230
|
+
Each feature is validated against an independent reference where one exists, which may be
|
|
231
|
+
another implementation, a closed form or a published result. A few rest on internal tests
|
|
232
|
+
only, namely autocorrelations, variance decomposition, pruning, the second-order generalised
|
|
233
|
+
impulse response, announced parameter paths and the Blanchard–Kahn check, and the export to
|
|
234
|
+
MacroModelling.jl has no round trip. The checks come in three layers.
|
|
235
|
+
|
|
236
|
+
The first layer is the test suite (`pytest`), which compares the output with answers known
|
|
237
|
+
analytically. It has 148 tests. Of these, 65 need the `symbolic` extra (sympy) and 15 the
|
|
238
|
+
Heutel files from `heutel.fetch()`, and without those files a run gives 137 passed and 11
|
|
239
|
+
skipped. Among the closed forms it checks are the following.
|
|
240
|
+
|
|
241
|
+
- The RBC with log utility and full depreciation has the solution `P = [[α, 1], [0, ρ]]` and
|
|
242
|
+
`F = [α, 1]`.
|
|
243
|
+
- The New Keynesian example is determinate under a Taylor rule with `φπ = 1.5` and
|
|
244
|
+
indeterminate with `φπ = 0.8`, where `solve` raises `BlanchardKahnError`.
|
|
245
|
+
- On a lognormal AR(1), the second-order coefficient `h_ss` equals `σ²`, so the risk
|
|
246
|
+
correction in the decision rule, `½·h_ss = σ²/2`, is the Jensen term.
|
|
247
|
+
- The perfect-foresight transition reproduces the closed-form path `k_{t+1} = αβ k_t^α`.
|
|
248
|
+
- On two independent AR(1) processes and one forward-looking equation, the shock loading is
|
|
249
|
+
the identity. The textbook formula read off the QZ treats every equation as holding ex post
|
|
250
|
+
and gives a dense loading here, which is why `klein` solves for the loading on the rows that
|
|
251
|
+
hold ex post
|
|
252
|
+
([design notes](https://github.com/GustavoHM/dsgelab/blob/main/docs/design-notes.md#the-shock-loading-is-not-read-off-the-qz)).
|
|
253
|
+
- Halving the displacement in `accuracy()` divides the first-order residual by about four and
|
|
254
|
+
the second-order residual by about eight.
|
|
255
|
+
|
|
256
|
+
The suite runs from a clone of the repository.
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
git clone https://github.com/GustavoHM/dsgelab && cd dsgelab
|
|
260
|
+
pip install -e ".[symbolic,test]" && pytest
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
The second layer, in [`validation/`](https://github.com/GustavoHM/dsgelab/blob/main/validation/README.md),
|
|
264
|
+
runs Dynare's own example and test `.mod` files in Octave with Dynare, and one calibration in
|
|
265
|
+
MacroModelling.jl. Each result is compared with `dsgelab`'s, for steady states, impulse
|
|
266
|
+
responses, moments, optimal policy, perfect foresight, estimation, OccBin, the extended path,
|
|
267
|
+
balanced growth and diagnostics. The same folder checks the port of Heutel (2012) against
|
|
268
|
+
Heutel's own code. `bash validation/run_all.sh` runs all of it, and CI runs it weekly.
|
|
269
|
+
|
|
270
|
+
The third layer is one comparison on an applied model from an unpublished paper by the author.
|
|
271
|
+
That model is not public, so the comparison cannot be rerun from the repository. Of the three
|
|
272
|
+
layers, the second is the one in which both the models and the reference software come from
|
|
273
|
+
other authors.
|
|
274
|
+
|
|
275
|
+
## Known limitations
|
|
276
|
+
|
|
277
|
+
This section lists what the package does not do yet. The
|
|
278
|
+
[roadmap](https://github.com/GustavoHM/dsgelab/blob/main/ROADMAP.md) says when each item is
|
|
279
|
+
planned.
|
|
280
|
+
|
|
281
|
+
- **Third order is partial.** The cubic block and the risk slope (`g_ssk` and `h_ssk`) are
|
|
282
|
+
implemented. Dynare's full decision-rule tensor, with the innovation in every monomial, and
|
|
283
|
+
the stochastic steady state are planned for 0.7. The tensors are dense, so their size grows
|
|
284
|
+
with the cube of the number of variables and shocks, and sparse tensors for large models are
|
|
285
|
+
planned for the same version.
|
|
286
|
+
- **Estimation is linear.** The likelihood comes from the Kalman filter on the first-order
|
|
287
|
+
solution. There is no particle or inversion filter, so no estimation at second or third
|
|
288
|
+
order, and no gradient-based samplers (HMC/NUTS).
|
|
289
|
+
- **No identification analysis, global sensitivity, or method of moments** (Dynare's
|
|
290
|
+
`+identification`, `+gsa`, `+mom`), and no HP- or band-pass-filtered theoretical moments.
|
|
291
|
+
- **Global methods are limited** to Chebyshev collocation with up to three states. There is no
|
|
292
|
+
value or time iteration, endogenous grid, sparse grid, or Tauchen/Rouwenhorst discretisation.
|
|
293
|
+
- **No Markov regime switching, heterogeneous agents, BVAR or DSGE-VAR.**
|
|
294
|
+
- **No plotting.** Results are arrays and dictionaries, and plotting is left to the user.
|
|
295
|
+
- **The extended path's hybrid correction stops at second order.**
|
|
296
|
+
- **Trends can be declared only in a `.mod` file.** `from_equations` does not accept them yet.
|
|
297
|
+
- **`from_mod` reads the model and ignores the script.** Commands such as `stoch_simul`,
|
|
298
|
+
`estimation` or `identification` are skipped, and their options are not applied. In the
|
|
299
|
+
model block, the constructs the reader cannot translate (`@#include`, `@#for`, `varexo_det`,
|
|
300
|
+
leads of a shock, `expectation`, `diff`, `adl`, external functions) are refused with an
|
|
301
|
+
error that quotes the line containing them. Coverage is validated on the Dynare examples and
|
|
302
|
+
tests listed in `validation/`.
|
|
303
|
+
|
|
304
|
+
## Related package
|
|
305
|
+
|
|
306
|
+
[cgelab](https://github.com/GustavoHM/cgelab), by the same author, solves computable general
|
|
307
|
+
equilibrium models. Its module `cgelab.bridge` uses dsgelab for the intertemporal part of a
|
|
308
|
+
model.
|
|
309
|
+
|
|
310
|
+
## Citing
|
|
311
|
+
|
|
312
|
+
If the package contributed to a published result, cite it as any other methodological input,
|
|
313
|
+
with the version, because a number that reproduces only under one version cannot be reproduced
|
|
314
|
+
without knowing which. [`CITATION.cff`](https://github.com/GustavoHM/dsgelab/blob/main/CITATION.cff)
|
|
315
|
+
holds the same metadata in the format GitHub reads.
|
|
316
|
+
|
|
317
|
+
Moreira, G. H. (2026). dsgelab: A general toolkit for solving DSGE models in Python (Version
|
|
318
|
+
0.5.0) [Computer software]. https://github.com/GustavoHM/dsgelab
|
|
319
|
+
|
|
320
|
+
```bibtex
|
|
321
|
+
@software{dsgelab_2026,
|
|
322
|
+
author = {Moreira, Gustavo Hoffmann},
|
|
323
|
+
title = {{dsgelab}: a general toolkit for solving DSGE models in Python},
|
|
324
|
+
year = {2026},
|
|
325
|
+
version = {0.5.0},
|
|
326
|
+
license = {MIT},
|
|
327
|
+
url = {https://github.com/GustavoHM/dsgelab},
|
|
328
|
+
note = {Python package}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
A DOI will be added with the first release archived on Zenodo.
|