ogeth 0.1.0__tar.gz → 0.2.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.
Files changed (31) hide show
  1. {ogeth-0.1.0/ogeth.egg-info → ogeth-0.2.0}/PKG-INFO +88 -17
  2. {ogeth-0.1.0 → ogeth-0.2.0}/README.md +85 -13
  3. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/__init__.py +1 -1
  4. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/calibrate.py +4 -2
  5. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/income.py +2 -12
  6. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/macro_params.py +33 -134
  7. ogeth-0.2.0/ogeth/ogeth_default_parameters.json +874546 -0
  8. {ogeth-0.1.0 → ogeth-0.2.0/ogeth.egg-info}/PKG-INFO +88 -17
  9. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/requires.txt +1 -1
  10. {ogeth-0.1.0 → ogeth-0.2.0}/pyproject.toml +17 -5
  11. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_macro_params.py +4 -47
  12. ogeth-0.1.0/ogeth/ogeth_default_parameters.json +0 -103789
  13. {ogeth-0.1.0 → ogeth-0.2.0}/LICENSE +0 -0
  14. {ogeth-0.1.0 → ogeth-0.2.0}/MANIFEST.in +0 -0
  15. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/constants.py +0 -0
  16. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/data/IFPRI_SAM_ETH_2022_SAM.csv +0 -0
  17. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/input_output.py +0 -0
  18. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/labor.py +0 -0
  19. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/ogeth_multi_industry_parameters.json +0 -0
  20. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/test_est_chi_n.py +0 -0
  21. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/update_baseline.py +0 -0
  22. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth/utils.py +0 -0
  23. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/SOURCES.txt +0 -0
  24. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/dependency_links.txt +0 -0
  25. {ogeth-0.1.0 → ogeth-0.2.0}/ogeth.egg-info/top_level.txt +0 -0
  26. {ogeth-0.1.0 → ogeth-0.2.0}/setup.cfg +0 -0
  27. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_calibrate.py +0 -0
  28. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_import_smoke.py +0 -0
  29. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_input_output.py +0 -0
  30. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_run_example.py +0 -0
  31. {ogeth-0.1.0 → ogeth-0.2.0}/tests/test_update_baseline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ogeth
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Ethiopia Calibration for OG-Core
5
5
  Author: Marcelo LaFleur, Richard W. Evans, and Jason DeBacker
6
6
  License: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
@@ -14,12 +14,11 @@ Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.11
18
17
  Classifier: Programming Language :: Python :: 3.12
19
18
  Classifier: Programming Language :: Python :: 3.13
20
19
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
21
20
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
- Requires-Python: <3.14,>=3.11
21
+ Requires-Python: <3.14,>=3.12
23
22
  Description-Content-Type: text/markdown
24
23
  License-File: LICENSE
25
24
  Requires-Dist: numpy
@@ -47,7 +46,7 @@ Requires-Dist: ipython; extra == "dev"
47
46
  Requires-Dist: ipykernel; extra == "dev"
48
47
  Requires-Dist: jupyter; extra == "dev"
49
48
  Provides-Extra: docs
50
- Requires-Dist: jupyter-book<2.0.0; extra == "docs"
49
+ Requires-Dist: jupyter-book<2.0,>=1.0; extra == "docs"
51
50
  Requires-Dist: sphinx>=3.5.4; extra == "docs"
52
51
  Requires-Dist: sphinx-book-theme>=0.1.3; extra == "docs"
53
52
  Requires-Dist: sphinx-argparse; extra == "docs"
@@ -69,28 +68,100 @@ OG-ETH is an overlapping-generations (OG) model that allows for dynamic general
69
68
 
70
69
  ## Using and contributing to OG-ETH
71
70
 
72
- There are two primary methods for installing and running OG-ETH on your computer locally. The first and simplest method is to download the most recent `ogeth` Python package from the Python Package Index ([PyPI.org](https://pypi.org/project/ogeth/)). The second option is to fork and clone the most recent version of OG-ETH from its GitHub repository and install the `ogeth` package with its development dependencies using `uv`. Both methods are detailed below.
71
+ Install and run OG-ETH by cloning this GitHub repository and installing the `ogeth` package with its dependencies using [`uv`](https://docs.astral.sh/uv/), as detailed below. (Installing the `ogeth` package from [PyPI](https://pypi.org/project/ogeth/) with `pip` is no longer the recommended path: on the Python versions many machines ship, `pip` either refuses the current release outright — as on the Python 3.9 built into macOS — or silently pairs it with an older `ogcore` than the model is tested against, and even on a supported Python the PyPI route does not pin the `ogcore` version the repository is tested against. The `uv` workflow installs the exact tested versions of every dependency, including a compatible Python interpreter.)
73
72
 
74
- ### Installing and Running OG-ETH from PyPI
73
+ ### Installation
75
74
 
76
- * On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
77
- * Open your terminal and install the [`ogeth`](https://pypi.org/project/ogeth/) package from the Python Package Index by typing `pip install ogeth`.
78
- * Navigate to a folder `./YourFolderName/` where you want to save scripts to run OG-ETH and output from the simulations in those scripts.
79
- * Copy the python script [`run_og_eth.py`](https://github.com/EAPD-DRB/OG-ETH/blob/main/examples/run_og_eth.py) from the OG-ETH GitHub repository into your folder as `./YourFolderName/run_og_eth.py`.
80
- * Run the model with an example reform from terminal/command prompt by typing `python run_og_eth.py`.
75
+ There are two ways to install OG-ETH: the easy way, using the OG model family's universal installer, and a manual install that runs the same steps one command at a time. Both start from a terminal, put the model in a new OG-ETH folder inside your current directory (a freshly opened terminal starts in your home folder), and need git.
81
76
 
82
- ### Installing and Running OG-ETH from the GitHub repository
77
+ #### Before you start: git
78
+
79
+ On a Mac where you have never used git before, run this line first and accept the dialog that appears:
80
+
81
+ ```
82
+ xcode-select --install
83
+ ```
84
+
85
+ On Windows, install Git first (skip this if you already have it):
86
+
87
+ ```
88
+ winget install --id Git.Git -e --source winget
89
+ ```
90
+
91
+ #### The easy way: the universal installer
92
+
93
+ The OG model family has a [universal installer](https://github.com/PSLmodels/OG-Core/blob/master/scripts/QUICK_INSTALL.md) that installs the uv tool, downloads the model, builds its environment, and verifies it — for OG-ETH or any of its sibling country models.
94
+
95
+ On macOS and Linux, paste:
96
+
97
+ ```
98
+ curl -fsSL https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.sh -o og-install.sh
99
+ bash og-install.sh --repo og-eth --yes
100
+ ```
101
+
102
+ On Windows (PowerShell), paste:
103
+
104
+ ```
105
+ $f = "$env:TEMP\og-install.ps1"; irm https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.ps1 -OutFile $f; powershell -ExecutionPolicy Bypass -File $f -Repo og-eth -Yes
106
+ ```
107
+
108
+ When the installer finishes, run the example. On macOS and Linux, paste:
109
+
110
+ ```
111
+ source $HOME/.local/bin/env
112
+ cd OG-ETH
113
+ uv run python examples/run_og_eth.py
114
+ ```
115
+
116
+ On Windows, open a new PowerShell window (so the just-installed tools are found) and paste:
117
+
118
+ ```
119
+ cd OG-ETH
120
+ uv run python examples/run_og_eth.py
121
+ ```
122
+
123
+ #### Manual install
124
+
125
+ The same setup as individual commands. On macOS and Linux, paste:
126
+
127
+ ```
128
+ curl -LsSf https://astral.sh/uv/install.sh | sh
129
+ source $HOME/.local/bin/env
130
+ git clone https://github.com/EAPD-DRB/OG-ETH.git
131
+ cd OG-ETH
132
+ uv run python examples/run_og_eth.py
133
+ ```
134
+
135
+ The second line makes the just-installed uv available in the current terminal; from your next terminal session it is available automatically.
136
+
137
+ On Windows (PowerShell), install uv:
138
+
139
+ ```
140
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
141
+ ```
142
+
143
+ Then open a new PowerShell window (so the just-installed tools are found) and paste:
144
+
145
+ ```
146
+ git clone https://github.com/EAPD-DRB/OG-ETH.git
147
+ cd OG-ETH
148
+ uv run python examples/run_og_eth.py
149
+ ```
150
+
151
+ #### What happens
152
+
153
+ The first `uv run` creates the project environment if it does not exist yet — downloading a compatible Python interpreter if needed and installing the exact locked dependencies — and then runs the example. Early in the run you may be asked for a UN API token; just press return, and the model reads the same population data from a public mirror and continues. A full baseline-plus-reform run takes from 35 minutes to more than two hours; when it finishes, its plots and tables are saved under `./examples/OG-ETH-Example/` (see the list of outputs below).
154
+
155
+ ### Installing for development or contributing
83
156
 
84
- * On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
85
- * Install [`uv`](https://docs.astral.sh/uv/) by following the [installation instructions](https://docs.astral.sh/uv/getting-started/installation/) for your platform (or simply run `pip install uv`).
86
157
  * Fork this repository and clone your fork to a directory on your computer.
87
- * From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies. `uv` will also download a compatible Python interpreter if you don't already have one.
158
+ * From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies (`uv` downloads a compatible Python if you don't already have one).
88
159
  * For docs/Jupyter Book work, also run `uv sync --extra dev --extra docs`.
160
+ * Run commands in the environment with `uv run <command>`, or activate it first with `source .venv/bin/activate` (macOS/Linux) or `.\.venv\Scripts\Activate.ps1` (Windows).
89
161
 
90
162
  ### Run an example of the model
91
163
 
92
- * Navigate to `./examples`.
93
- * Run the model with an example reform: `uv run python run_og_eth.py` (or activate the venv first with `source .venv/bin/activate` on macOS/Linux or `.\.venv\Scripts\Activate.ps1` on Windows, then `python run_og_eth.py`).
164
+ * From the repository root, run the model with an example reform: `uv run python examples/run_og_eth.py`.
94
165
  * You can adjust the `./examples/run_og_eth.py` by modifying model parameters specified in the dictionary passed to the `p.update_specifications()` calls.
95
166
  * Model outputs will be saved in the following files:
96
167
  * `./examples/OG-ETH-Example/OG-ETH_example_plots`
@@ -11,28 +11,100 @@ OG-ETH is an overlapping-generations (OG) model that allows for dynamic general
11
11
 
12
12
  ## Using and contributing to OG-ETH
13
13
 
14
- There are two primary methods for installing and running OG-ETH on your computer locally. The first and simplest method is to download the most recent `ogeth` Python package from the Python Package Index ([PyPI.org](https://pypi.org/project/ogeth/)). The second option is to fork and clone the most recent version of OG-ETH from its GitHub repository and install the `ogeth` package with its development dependencies using `uv`. Both methods are detailed below.
14
+ Install and run OG-ETH by cloning this GitHub repository and installing the `ogeth` package with its dependencies using [`uv`](https://docs.astral.sh/uv/), as detailed below. (Installing the `ogeth` package from [PyPI](https://pypi.org/project/ogeth/) with `pip` is no longer the recommended path: on the Python versions many machines ship, `pip` either refuses the current release outright — as on the Python 3.9 built into macOS — or silently pairs it with an older `ogcore` than the model is tested against, and even on a supported Python the PyPI route does not pin the `ogcore` version the repository is tested against. The `uv` workflow installs the exact tested versions of every dependency, including a compatible Python interpreter.)
15
15
 
16
- ### Installing and Running OG-ETH from PyPI
16
+ ### Installation
17
17
 
18
- * On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
19
- * Open your terminal and install the [`ogeth`](https://pypi.org/project/ogeth/) package from the Python Package Index by typing `pip install ogeth`.
20
- * Navigate to a folder `./YourFolderName/` where you want to save scripts to run OG-ETH and output from the simulations in those scripts.
21
- * Copy the python script [`run_og_eth.py`](https://github.com/EAPD-DRB/OG-ETH/blob/main/examples/run_og_eth.py) from the OG-ETH GitHub repository into your folder as `./YourFolderName/run_og_eth.py`.
22
- * Run the model with an example reform from terminal/command prompt by typing `python run_og_eth.py`.
18
+ There are two ways to install OG-ETH: the easy way, using the OG model family's universal installer, and a manual install that runs the same steps one command at a time. Both start from a terminal, put the model in a new OG-ETH folder inside your current directory (a freshly opened terminal starts in your home folder), and need git.
23
19
 
24
- ### Installing and Running OG-ETH from the GitHub repository
20
+ #### Before you start: git
21
+
22
+ On a Mac where you have never used git before, run this line first and accept the dialog that appears:
23
+
24
+ ```
25
+ xcode-select --install
26
+ ```
27
+
28
+ On Windows, install Git first (skip this if you already have it):
29
+
30
+ ```
31
+ winget install --id Git.Git -e --source winget
32
+ ```
33
+
34
+ #### The easy way: the universal installer
35
+
36
+ The OG model family has a [universal installer](https://github.com/PSLmodels/OG-Core/blob/master/scripts/QUICK_INSTALL.md) that installs the uv tool, downloads the model, builds its environment, and verifies it — for OG-ETH or any of its sibling country models.
37
+
38
+ On macOS and Linux, paste:
39
+
40
+ ```
41
+ curl -fsSL https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.sh -o og-install.sh
42
+ bash og-install.sh --repo og-eth --yes
43
+ ```
44
+
45
+ On Windows (PowerShell), paste:
46
+
47
+ ```
48
+ $f = "$env:TEMP\og-install.ps1"; irm https://raw.githubusercontent.com/PSLmodels/OG-Core/master/scripts/install.ps1 -OutFile $f; powershell -ExecutionPolicy Bypass -File $f -Repo og-eth -Yes
49
+ ```
50
+
51
+ When the installer finishes, run the example. On macOS and Linux, paste:
52
+
53
+ ```
54
+ source $HOME/.local/bin/env
55
+ cd OG-ETH
56
+ uv run python examples/run_og_eth.py
57
+ ```
58
+
59
+ On Windows, open a new PowerShell window (so the just-installed tools are found) and paste:
60
+
61
+ ```
62
+ cd OG-ETH
63
+ uv run python examples/run_og_eth.py
64
+ ```
65
+
66
+ #### Manual install
67
+
68
+ The same setup as individual commands. On macOS and Linux, paste:
69
+
70
+ ```
71
+ curl -LsSf https://astral.sh/uv/install.sh | sh
72
+ source $HOME/.local/bin/env
73
+ git clone https://github.com/EAPD-DRB/OG-ETH.git
74
+ cd OG-ETH
75
+ uv run python examples/run_og_eth.py
76
+ ```
77
+
78
+ The second line makes the just-installed uv available in the current terminal; from your next terminal session it is available automatically.
79
+
80
+ On Windows (PowerShell), install uv:
81
+
82
+ ```
83
+ powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
84
+ ```
85
+
86
+ Then open a new PowerShell window (so the just-installed tools are found) and paste:
87
+
88
+ ```
89
+ git clone https://github.com/EAPD-DRB/OG-ETH.git
90
+ cd OG-ETH
91
+ uv run python examples/run_og_eth.py
92
+ ```
93
+
94
+ #### What happens
95
+
96
+ The first `uv run` creates the project environment if it does not exist yet — downloading a compatible Python interpreter if needed and installing the exact locked dependencies — and then runs the example. Early in the run you may be asked for a UN API token; just press return, and the model reads the same population data from a public mirror and continues. A full baseline-plus-reform run takes from 35 minutes to more than two hours; when it finishes, its plots and tables are saved under `./examples/OG-ETH-Example/` (see the list of outputs below).
97
+
98
+ ### Installing for development or contributing
25
99
 
26
- * On macOS, first install Xcode Command Line Tools (in Terminal: `xcode-select --install`).
27
- * Install [`uv`](https://docs.astral.sh/uv/) by following the [installation instructions](https://docs.astral.sh/uv/getting-started/installation/) for your platform (or simply run `pip install uv`).
28
100
  * Fork this repository and clone your fork to a directory on your computer.
29
- * From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies. `uv` will also download a compatible Python interpreter if you don't already have one.
101
+ * From the terminal, navigate to the cloned directory and run `uv sync --extra dev` to create a local `.venv` and install OG-ETH with its development dependencies (`uv` downloads a compatible Python if you don't already have one).
30
102
  * For docs/Jupyter Book work, also run `uv sync --extra dev --extra docs`.
103
+ * Run commands in the environment with `uv run <command>`, or activate it first with `source .venv/bin/activate` (macOS/Linux) or `.\.venv\Scripts\Activate.ps1` (Windows).
31
104
 
32
105
  ### Run an example of the model
33
106
 
34
- * Navigate to `./examples`.
35
- * Run the model with an example reform: `uv run python run_og_eth.py` (or activate the venv first with `source .venv/bin/activate` on macOS/Linux or `.\.venv\Scripts\Activate.ps1` on Windows, then `python run_og_eth.py`).
107
+ * From the repository root, run the model with an example reform: `uv run python examples/run_og_eth.py`.
36
108
  * You can adjust the `./examples/run_og_eth.py` by modifying model parameters specified in the dictionary passed to the `p.update_specifications()` calls.
37
109
  * Model outputs will be saved in the following files:
38
110
  * `./examples/OG-ETH-Example/OG-ETH_example_plots`
@@ -8,4 +8,4 @@ from ogeth.input_output import * # noqa: F403
8
8
  from ogeth.macro_params import * # noqa: F403
9
9
  from ogeth.utils import * # noqa: F403
10
10
 
11
- __version__ = "0.1.0"
11
+ __version__ = "0.2.0"
@@ -86,9 +86,10 @@ class Calibration:
86
86
  p.T,
87
87
  0,
88
88
  99,
89
- country_id="710",
89
+ country_id="231",
90
90
  initial_data_year=p.start_year - 1,
91
91
  final_data_year=p.start_year + 1,
92
+ income_percentiles=p.lambdas.flatten(),
92
93
  GraphDiag=False,
93
94
  download_path=demographic_data_path,
94
95
  )
@@ -100,9 +101,10 @@ class Calibration:
100
101
  p.T,
101
102
  0,
102
103
  99,
103
- country_id="710",
104
+ country_id="231",
104
105
  initial_data_year=p.start_year - 1,
105
106
  final_data_year=p.start_year + 1,
107
+ income_percentiles=p.lambdas.flatten(),
106
108
  GraphDiag=False,
107
109
  )
108
110
 
@@ -116,14 +116,7 @@ def get_e_interp(
116
116
  )
117
117
  a = x.root
118
118
  e_new = usa_params.e[0, :, :] * np.exp(a * usa_params.e[0, :, :])
119
- emat_new_scaled = (
120
- e_new
121
- / (
122
- e_new
123
- * usa_params.omega_SS.reshape(usa_params.S, 1)
124
- * usa_params.lambdas.reshape(1, usa_params.J)
125
- ).sum()
126
- )
119
+ emat_new_scaled = e_new / (e_new * usa_params.omega_SS).sum()
127
120
  # Now interpolate for the cases where S and/or J not the same in the
128
121
  # country parameterization as in the default USA parameterization
129
122
  if (
@@ -182,10 +175,7 @@ def get_e_interp(
182
175
  (new_s_mesh, new_j_mesh),
183
176
  method="linear",
184
177
  )
185
- emat_new_scaled = (
186
- emat_new
187
- / (emat_new * age_wgts.reshape(S, 1) * lambdas.reshape(1, J)).sum()
188
- )
178
+ emat_new_scaled = emat_new / (emat_new * age_wgts).sum()
189
179
 
190
180
  if plot_path is not None:
191
181
  kwargs = {"path": plot_path, "filesuffix": "_intrp_scaled"}
@@ -15,6 +15,11 @@ from pathlib import Path
15
15
  # Public capital elasticity; see firms.md.
16
16
  GAMMA_G_LIC = 0.1
17
17
 
18
+ # Start year for the g_y_annual average-growth calculation; matches the
19
+ # documented window in macro.md (average annual GDP-per-capita growth
20
+ # 2006-2024 = 6.0%).
21
+ G_Y_START_YEAR = 2006
22
+
18
23
 
19
24
  def _fetch_wb_data(indicators, country_iso, start_year, end_year, source):
20
25
  """
@@ -236,12 +241,6 @@ def get_macro_params(
236
241
  """
237
242
  # initialize a dictionary of parameters
238
243
  macro_parameters = {}
239
- # baseline date formatted for World Bank data
240
- baseline_YYYYQ = (
241
- str(data_end_date.year)
242
- + "Q"
243
- + str(pd.Timestamp(data_end_date).quarter)
244
- )
245
244
 
246
245
  """
247
246
  Retrieve data from the World Bank World Development Indicators.
@@ -256,12 +255,11 @@ def get_macro_params(
256
255
  "General government final consumption expenditure (current US$)"
257
256
  ): "NE.CON.GOVT.CD",
258
257
  }
259
- # Quarterly data
260
- wb_q_variable_dict = {
261
- "Gross PSD USD - domestic creditors": "DP.DOD.DECD.CR.PS.CD",
262
- "Gross PSD USD - external creditors": "DP.DOD.DECX.CR.PS.CD",
263
- "Gross PSD Gen Gov - percentage of GDP": "DP.DOD.DECT.CR.GG.Z1",
264
- }
258
+ # Quarterly public-sector-debt (QPSD) indicators are intentionally
259
+ # not fetched for OG-ETH: the World Bank QPSD database has no Ethiopia
260
+ # data. The debt parameters (initial_debt_ratio,
261
+ # initial_foreign_debt_ratio, zeta_D) are hand-calibrated from the
262
+ # Ethiopia MoF Public Sector Debt Bulletin No. 51 (see macro.md).
265
263
  if update_from_api:
266
264
  try:
267
265
  wb_data_a = _fetch_wb_data(
@@ -271,116 +269,32 @@ def get_macro_params(
271
269
  data_end_date.year,
272
270
  source=2,
273
271
  )
274
- wb_data_q = _fetch_wb_data(
275
- wb_q_variable_dict,
276
- country_iso,
277
- data_start_date.year,
278
- data_end_date.year,
279
- source=20,
280
- )
281
-
282
- # Get the latest valid data if baseline_YYYYQ is missing/NaN
283
- def get_valid_data(series, baseline_YYYYQ):
284
- value = series.get(baseline_YYYYQ, None)
285
-
286
- if pd.isna(value):
287
- latest_non_nan = series.dropna().last_valid_index()
288
-
289
- if latest_non_nan is not None:
290
- print(
291
- f"Warning: No data for {baseline_YYYYQ}. "
292
- f"Using last available quarter: "
293
- f"{latest_non_nan}"
294
- )
295
- value = series.get(latest_non_nan, None)
296
- else:
297
- print(
298
- "Warning: No historical data available. "
299
- "Skipping update."
300
- )
301
- value = None
302
-
303
- return value
304
-
305
- # Compute macro parameters from WB data
306
- macro_parameters["initial_debt_ratio"] = get_valid_data(
307
- pd.Series(wb_data_q["Gross PSD Gen Gov - percentage of GDP"])
308
- / 100,
309
- baseline_YYYYQ,
310
- )
311
- print(
312
- "initial_debt_ratio updated from World Bank API: "
313
- f"{macro_parameters['initial_debt_ratio']}"
314
- )
315
-
316
- # Compute initial_foreign_debt_ratio safely
317
- if (
318
- "Gross PSD USD - external creditors" in wb_data_q.columns
319
- and "Gross PSD USD - domestic creditors" in wb_data_q.columns
320
- ):
321
- total_debt = (
322
- wb_data_q["Gross PSD USD - domestic creditors"]
323
- + wb_data_q["Gross PSD USD - external creditors"]
324
- )
325
-
326
- # Avoid division by zero
327
- wb_data_q["foreign_debt_ratio"] = wb_data_q[
328
- "Gross PSD USD - external creditors"
329
- ] / total_debt.replace(0, np.nan)
330
-
331
- macro_parameters["initial_foreign_debt_ratio"] = (
332
- get_valid_data(
333
- wb_data_q["foreign_debt_ratio"], baseline_YYYYQ
334
- )
335
- )
336
- else:
337
- print(
338
- "Warning: Missing debt variables in World Bank "
339
- "data. Skipping update for "
340
- "initial_foreign_debt_ratio."
341
- )
342
-
343
- print(
344
- "initial_foreign_debt_ratio updated from World Bank "
345
- f"API: {macro_parameters['initial_foreign_debt_ratio']}"
346
- )
347
-
348
- # Compute zeta_D safely
349
- macro_parameters["zeta_D"] = [
350
- macro_parameters["initial_foreign_debt_ratio"]
351
- ] # Since it's the same formula, we use the same calculated value
352
-
353
- print(
354
- "zeta_D updated from World Bank API: "
355
- f"{macro_parameters['zeta_D']}"
356
- )
357
-
358
- # Compute annual GDP growth safely
272
+ # Compute annual GDP-per-capita growth (g_y_annual) from the
273
+ # World Bank WDI series, averaging pct_change from
274
+ # G_Y_START_YEAR onward to match the documented window (see
275
+ # macro.md). Debt parameters are not derived here (see note
276
+ # above).
359
277
  if "GDP per capita (constant 2015 US$)" in wb_data_a.columns:
360
- g_y_series = wb_data_a[
361
- "GDP per capita (constant 2015 US$)"
362
- ].pct_change(-1)
278
+ gdp_pc = wb_data_a["GDP per capita (constant 2015 US$)"]
279
+ gdp_pc = gdp_pc[gdp_pc.index.astype(int) >= G_Y_START_YEAR]
280
+ g_y_series = gdp_pc.pct_change(-1)
363
281
 
364
282
  # If all values are NaN, return None
365
283
  macro_parameters["g_y_annual"] = (
366
284
  g_y_series.mean() if not g_y_series.isna().all() else None
367
285
  )
286
+ print(
287
+ "g_y_annual updated from World Bank API: "
288
+ f"{macro_parameters['g_y_annual']}"
289
+ )
368
290
  else:
369
291
  print(
370
292
  "Warning: Missing GDP per capita data in World "
371
293
  "Bank data. Skipping update for g_y_annual."
372
294
  )
373
-
374
- print(
375
- "g_y_annual updated from World Bank API: "
376
- f"{macro_parameters['g_y_annual']}"
377
- )
378
295
  except Exception:
379
296
  print("Failed to retrieve data from World Bank")
380
- print("Will not update the following parameters:")
381
- print(
382
- "[initial_debt_ratio, initial_foreign_debt_ratio, zeta_D, g_y]"
383
- )
297
+ print("Will not update g_y_annual")
384
298
  else:
385
299
  print("Not updating from World Bank API")
386
300
 
@@ -443,31 +357,16 @@ def get_macro_params(
443
357
  print("Not updating from ILOSTAT API")
444
358
 
445
359
  """
446
- Calibrate parameters from IMF data
360
+ Estimate r_gov_shift and r_gov_scale (Li, Magud, Werner 2021 method).
447
361
  """
448
362
 
363
+ # alpha_T and alpha_G are NOT pulled from the IMF API for OG-ETH: the
364
+ # IMF SDMX endpoint returns only 2002-vintage data for Ethiopia, and
365
+ # the documented sources differ (alpha_G -> World Bank NE.CON.GOVT.ZS;
366
+ # alpha_T -> IMF GFS + IMF Country Report 25/188, hand-combined). Both
367
+ # stay at the committed values in macro.md. _get_imf_macro_params is
368
+ # retained (tested independently) for reuse if wired to the right data.
449
369
  if update_from_api:
450
- try:
451
- imf_year = (
452
- data_end_date.year if imf_data_year is None else imf_data_year
453
- )
454
- macro_parameters.update(
455
- _get_imf_macro_params(
456
- country_iso,
457
- imf_year,
458
- data_path=imf_data_path,
459
- )
460
- )
461
- print(
462
- f"alpha_T updated from IMF data: {macro_parameters['alpha_T']}"
463
- )
464
- print(
465
- f"alpha_G updated from IMF data: {macro_parameters['alpha_G']}"
466
- )
467
- except Exception:
468
- print("Failed to retrieve data from IMF")
469
- print("Will not update alpha_T, alpha_G")
470
-
471
370
  """"
472
371
  Estimate the discount on sovereign yields relative to private debt
473
372
  Follow the methodology in Li, Magud, Werner, Witte (2021)
@@ -497,17 +396,17 @@ def get_macro_params(
497
396
  macro_parameters["r_gov_shift"] = [-res.params[0] / 100]
498
397
  macro_parameters["r_gov_scale"] = [res.params[1]]
499
398
  print(
500
- "r_gov_shift updated from IMF data: "
399
+ "r_gov_shift computed (LMW 2021 method): "
501
400
  f"{macro_parameters['r_gov_shift']}"
502
401
  )
503
402
  print(
504
- "r_gov_scale updated from IMF data: "
403
+ "r_gov_scale computed (LMW 2021 method): "
505
404
  f"{macro_parameters['r_gov_scale']}"
506
405
  )
507
406
  except Exception:
508
407
  print("Failed to compute r_gov_shift, r_gov_scale")
509
408
  print("Will not update r_gov_shift, r_gov_scale")
510
409
  else:
511
- print("Not updating alpha_T, alpha_G, r_gov_shift, r_gov_scale")
410
+ print("Not computing r_gov_shift, r_gov_scale")
512
411
 
513
412
  return macro_parameters