Jorge Jesus Alonso Ortiz

Jorge Jesus Alonso Ortiz

Research, teaching, coding… and dogs

puremacro

VERSION 4.3 · OPEN SOURCE · MIT LICENSE · PYTHON 3.11+

Empirical macroeconomics in pure Python.

From SVARs and local projections to Bayesian DSGE, continuous-time heterogeneous agents and audited quantitative trade policy: one toolbox that runs on your laptop, in your browser and on an iPad.

pip install puremacro

PyPI version Supported Python versions MIT license

16,200+

automated tests in the suite

90

example scripts and real-data replications

68

notebooks that run in your browser, in English and Spanish

0

compiled extensions of its own: pure Python on NumPy and SciPy

New in 4.3 · Gallery · From Stata & Dynare · Run it anywhere · Documentation · Changelog

NEW IN 4.3 · SEPTEMBER 2026

Three new trade-policy tools, each with a notebook

Tariff games scored by consumption equivalent variation, solvers that recover from hard equilibria without relaxing the tolerance, and welfare that comes from an expenditure function instead of GDP. The figures come from notebooks 63–65, re-run for this page. The economies are small synthetic teaching tables, not forecasts. Click any figure to enlarge it.

TARIFF POLICY WITH HICKSIAN WELFARE · NOTEBOOK 63

Tariff games that separate a candidate from a verified best response

Unilateral optimal tariffs, fixed-action payoff matrices and multilateral Nash searches can now score outcomes by consumption equivalent variation against one fixed zero-tariff baseline. Every equilibrium in the search is audited. A candidate counts as converged only if the final simultaneous best-response gap and the regret relative to baseline consumption both pass. In the notebook’s economy both unilateral optima sit on the 30% ceiling, so they depend on that constraint, and the 0/10% payoff matrix is not a Prisoner’s Dilemma.

trade.compute_unilateral_optimal_tariff, trade.compute_welfare_payoff_matrix, trade.solve_multilateral_nash_tariffs
Open notebook 63 in your browser →

ROBUST EQUILIBRIUM SOLVING · NOTEBOOK 64

Keller continuation for equilibria that Newton cannot reach

Keller pseudo-arclength continuation lets the state and the continuation parameter move together, solving a bordered system that stays well conditioned through a turning point. solve_policy_equilibrium tries Newton, then a hybrid method, then Keller continuation, all at the requested tolerance. If all three fail it raises an error, so a failed deviation never yields a payoff. The notebook illustrates the numerics on a scalar fold; it does not claim an economic fold.

trade.solve_policy_equilibrium, trade.PolicyEquilibriumError, trade.solver.solve_keller_pac
Open notebook 64 in your browser →

CONSISTENT TRADE ACCOUNTING · NOTEBOOK 65

Welfare from an expenditure function, not from GDP

With accounting="consistent", trade equilibria keep producer and purchaser ledgers, complete duty schedules and independent physical and accounting checks. compute_hicksian_welfare computes EV and CV from a declared consumption expenditure function, excluding investment, and attributes EV exactly to purchaser prices, factor income and fiscal transfers, with the rebated duties counted once. In the notebook, a 10% duty raises the imposer’s nominal GDP by 3.6% while its consumption welfare barely moves. The attribution is endpoint accounting, not a causal terms-of-trade decomposition.

trade.compute_hicksian_welfare, trade.HicksianWelfareResult, trade.solve_trade_equilibrium(accounting="consistent")
Open notebook 65 in your browser →

Also in 4.3: native ingestion of the OECD 2023 regular ICIO tables with provenance and a frozen three-region fixture; corrected third-order DSGE risk-slope timing, with Dynare parity now checking steady states and every requested tensor; failed Markov-switching solves that no longer return finite certificates; and stricter convergence checks in VFI projection, collocation and Deep Macro. Full changelog.

UPGRADING FROM 4.2

  • Historical trade accounting and welfare stay the defaults. To use the new model and objective, pass accounting="consistent" and metric="hicksian_ev" explicitly.
  • The historical TOT/Alloc/TariffRec welfare decomposition and the theorem-certification endpoints now raise NotImplementedError, as do the unimplemented heterogeneous-agent IFT distribution and GE sensitivities.
  • Generated MRIO inputs require an explicit opt-in (fallback_to_synthetic=True); real-data loaders expect a source file.
  • solve_policy_equilibrium raises PolicyEquilibriumError when Newton, hybrid and Keller recovery are exhausted, instead of returning an unconverged result.
  • Known issues targeted for 4.3.1 are listed in the changelog; the release baseline records 11 affected tests with workarounds.

LATEST RELEASES · UPDATED AUTOMATICALLY

  • puremacro 4.3.0 adds audited structural solvers, consistent trade accounting and Hicksian tariff-policy analysis. Corrected VFI convergence and third-order DSGE risk terms, with ten frozen Dynare model/order comparisons. Opt-in accounting="consistent", expenditure-function EV/CV, and […]
  • puremacro 4.2.0 — bilingual notebook polish, dual-mode b&w card styli…
  • chore(release): bump version to 4.1.1

From the GitHub release feed. All releases · Changelog · PyPI history

Why puremacro

Built at ITAM–CIE for research and teaching, and engineered like production software.

PURE PYTHON

No compiler, no licence

The estimator core imports only NumPy, SciPy, pandas and Matplotlib. Nothing to compile, no MATLAB or Stata licence, and every documented result reproduces with Python alone.

RUNS ANYWHERE

Laptop, browser, iPad

The same code runs locally, in JupyterLite and under Pyodide. Heavy jobs offload to Google Colab; long bootstraps resume after the app is suspended.

SPEAKS DYNARE

Bring your .mod files

Load native Dynare models, solve to second order with pruning, handle the ZLB with OccBin and get oo_.dr-compatible decision rules.

PUBLICATION-READY

From estimate to LaTeX

Estimators return result objects with .summary(), .plot() and .to_latex(), so the last step to a paper table is one line.

What it can do

The empirical and structural toolkit of modern macroeconomics, in one library.

VARs & identification

Cholesky, long-run, sign and zero, narrative, proxy-IV, heteroskedasticity and non-Gaussian identification, with bootstrap and Bayesian bands.

Open the notebook →

Local projections & inference

LP-HAC, LP-IV, lag-augmented, panel, state-dependent, smooth and quantile LPs, with HAC, fixed-b and weak-IV-robust inference.

Open the notebook →

DSGE & Bayesian estimation

Native .mod files, second-order pruning, OccBin, perfect foresight, and NUTS sampling with exact likelihood gradients.

Open the notebook →

Heterogeneous agents

Sequence-space HANK with the Fake News algorithm, Aiyagari, Krusell–Smith, life-cycle and firm dynamics, continuous-time HJB–KFE, continuous-state and neural-network solvers.

Open the notebook →

Trade, space & climate

Caliendo–Parro trade, Allen–Arkolakis spatial equilibrium, spatial econometrics and a DICE climate–macro simulator.

Open the notebook →

Data, nowcasting & forecasting

FRED, OECD, IMF, ECB, Banxico and INEGI fetchers, real-time vintages, dynamic-factor nowcasts, text-based uncertainty indices, growth-at-risk and BVAR fan charts.

Open the notebook →

See every figure in the gallery →

Classic results, reproduced

Real-data replications ship with the package on frozen data snapshots and run fully offline. A built-in scorecard checks puremacro against each paper’s published numbers.

from puremacro.replication import scorecard

df = scorecard()   # vs each paper's published number
df["passed"].all()

Every case compares puremacro’s estimate with the number printed in the paper, so a regression shows up as a failed row, not a silently different figure.

Coming from Stata, MATLAB or Dynare?

The commands you know, and their puremacro equivalents.

TaskStata / MATLAB / Dynarepuremacro
Cholesky SVARvar y1 y2, lags(1/4) + irf createvar.identify.cholesky_svar(Y, p=4, horizon=20)
Local Projections (HAC)jorda / manual OLSlp.lp_hac(df, y="y", x="shock", horizon=20, lags=4)
Staggered DiDcsdid y, ivar(id) time(t) gvar(g)did.callaway_santanna(df, unit="id", time="t", outcome="y", treat_time="g")
DSGE from equations / .modDynare .mod filedsge.load_mod("rbc.mod") / dsge.build_dynare(eqs)
Bayesian DSGE (MCMC)Dynare estimation(...) (Metropolis-Hastings)dsge.estimate_dsge_bayesian(m, data, priors, n_draws=10000)
Trade Exact Hat AlgebraCostinot-Rodríguez-Clare codetrade.CaliendoParroModel(...) / cp.solve_counterfactual(...)

ON YOUR IPAD

Macroeconomics on an iPad, with Juno

Juno runs Python 3.13 natively on the iPad, offline, with NumPy, SciPy, pandas and Matplotlib preinstalled. puremacro is pure Python built on exactly those libraries, so it installs with Juno’s package manager and runs on the tablet itself.

  • Knows where it is. puremacro recognises Juno, both its built-in Python and its in-browser Pyodide kernel, and works inside the iPad’s sandboxed file system.
  • Brings its data. Pocket cartridges carry panels built on your workstation to the iPad, checked on arrival, even in airplane mode.
  • Survives interruptions. Long bootstraps and MCMC chains resume after iPadOS suspends the app, with bit-identical results.
  • Knows its limits. runtime.fit sizes bootstraps to the device, and heavy jobs offload to Google Colab as a single notebook.
# In Juno, with puremacro installed
from puremacro import runtime

# What can this iPad do?
print(runtime.report())

# Size the bootstrap to the device
print(runtime.fit(n_boot=2000))

Detection and budgets are opt-in: the same script gives the same numbers on your laptop.

ENGINEERED FOR CORRECTNESS

Numbers you can defend

Research code has to be right before it is fast. puremacro treats correctness as a feature.

  • Every push runs the test suite, about 16,200 tests, on three operating systems and three Python versions, plus mypy and a Pyodide-compatibility contract.
  • A validation gallery cross-checks estimators against statsmodels, linearmodels and arch.
  • A replication scorecard compares results with each paper’s published numbers.
  • Clear diagnostic errors instead of silent garbage: singular matrices, non-positive-definite covariances and Blanchard–Kahn violations say what went wrong and where.
  • Any released version that returned a wrong number is listed in a public correctness advisory.