🇬🇧 English · 🇪🇸 Español
Gertler-Karadi (2011) DSGE with Financial Frictions
puremacro.dsge.gertler_karadi implements the canonical macro-finance DSGE model of banking frictions, balance-sheet amplification, and unconventional credit policy developed by Gertler and Karadi (2011, Journal of Monetary Economics), with support for occasionally binding regimes via OccBin (Guerrieri and Iacoviello 2015).
Following the 2007–2008 Global Financial Crisis, macroeconomic modeling recognized that disruptions in financial intermediation are not merely passive reflections of real downturns, but powerful primary sources of macroeconomic amplification. The Gertler-Karadi (GK 2011) framework models financial intermediaries (banks) that fund productive capital investments by issuing household deposits subject to an endogenous agency problem.
1. Theoretical Framework
1.1 Balance Sheets and the Agency Friction
Banks intermediate funds between household savers and non-financial firms. The aggregate bank balance sheet equates total asset holdings \(S_t = Q_t K_t\) to bank net worth \(N_t\) plus household deposits \(B_t\):
Bankers maximize their expected terminal equity transferred to households upon retirement. To introduce financial frictions, GK (2011) introduce a moral hazard agency problem: - At the end of each period, a banker can divert a fraction \(\lambda_b \in (0, 1)\) of bank assets \(Q_t K_t\) back to their household. - If a banker diverts assets, the bank defaults, depositors seize the remaining fraction \((1 - \lambda_b)\), and the bank is closed.
For depositors to voluntarily provide funds, the bank's continuation value \(V_t\) must satisfy the incentive compatibility constraint:
The continuation value can be decomposed as:
where \(\nu_t\) represents the marginal value of expanding assets (holding net worth fixed) and \(\eta_t\) represents the marginal value of expanding net worth (holding assets fixed).
When the incentive constraint binds, it establishes an endogenous bank leverage ratio \(\phi_t\):
This constraint endogenously pins down the credit spread (or external finance premium):
1.2 Macroeconomic Amplification & Capital Quality Shocks
The primary driving experiment in Gertler and Karadi (2011) is a capital quality shock \(\xi_t\).
The effective capital stock evolves according to \(K_{t+1} = \xi_{t+1} [(1 - \delta) K_t + I_t]\). A negative innovation \(\varepsilon_\xi < 0\): 1. Directly reduces the productive capability of physical capital. 2. Depresses the asset price \(Q_t\). 3. Induces massive capital losses on intermediary balance sheets. Because banks are leveraged at \(\phi \approx 4\), a 1% decline in asset value contracts bank net worth by approximately 4%: $\(\frac{d N_t}{N_{ss}} \approx \phi \cdot \frac{d Q_t}{Q_{ss}}\)$ 4. Forces banks to shed assets or spike credit spreads \(\mathbb{E}_t[R_{k,t+1} - R_{t+1}]\) by hundreds of basis points to satisfy depositor incentive compatibility. 5. Induces a severe, persistent collapse in private investment and aggregate GDP.
2. Dual Solution Solvers
puremacro.dsge.gertler_karadi provides dual solution engines:
- Klein (1998) Generalized Schur (QZ) Linear Solver (
method='klein'):
Computes exact first-order rational expectations perturbations around the deterministic steady state usingpuremacro.dsge.klein. Fast and ideal for standard linear impulse response analysis. - OccBin Piecewise-Linear Backward Recursion (
method='occbin'):
Solves dynamic models with occasionally binding regime switches per Guerrieri and Iacoviello (2015): - Unconventional Credit Policy (
constraint_type='credit_policy'): The central bank directly intermediates credit when private credit spreads spike above a target threshold (e.g., 100 bps): $\(\psi_t = \nu_g \cdot \max \left( 0, \, \text{Spread}_t - \text{threshold} \right)\)$ - Macroprudential Leverage Caps (
constraint_type='leverage_cap'): Imposes a regulatory ceiling on bank leverage, \(\phi_t \le \phi_{max}\), with a public backstop. While the cap binds, the constrained regime pegs \(\phi_t = \phi_{max}\) and frees the public credit share, so the balance sheet \((1 - \psi_t) Q_t K_t = \phi_t N_t\) determines how much intermediation the public sector absorbs, under complementary slackness: $\(\phi_t \le \phi_{max}, \qquad \psi_t \ge 0, \qquad \psi_t = 0 \ \text{where the cap is slack}.\)$ The moral-hazard incentive constraint is kept, so a binding cap compresses intermediation rents rather than rationing private credit. Enforcing the cap by deleting the incentive constraint instead — the pre-2.5.0 formulation — makes the constrained regime violate Blanchard-Kahn and admits a continuum of spurious solutions; see thesolve_gertler_karadidocstring.
3. Canonical Calibration (GK 2011 Table 1)
| Parameter | Value | Economic Description |
|---|---|---|
beta |
\(0.99\) | Quarterly subjective discount factor (\(R_{ss} \approx 4.0\%\) annualized) |
sigma |
\(1.0\) | Intertemporal elasticity of substitution (log utility) |
h |
\(0.815\) | Consumption habit persistence |
varphi |
\(0.276\) | Inverse Frisch labor supply elasticity |
alpha |
\(0.33\) | Capital share in production |
delta |
\(0.025\) | Physical quarterly depreciation rate (10% annualized) |
eta_i |
\(1.728\) | Investment adjustment cost curvature |
theta_b |
\(0.972\) | Banker survival probability (average tenure \(\approx 9\) years) |
lambda_b |
\(0.381\) | Divertable fraction of assets (moral hazard intensity) |
omega_b |
\(0.002\) | Start-up wealth endowment for entering bankers |
gamma |
\(0.779\) | Calvo price stickiness probability |
rho_xi |
\(0.66\) | Capital quality shock autoregressive persistence |
4. Basic & Advanced Usage
Simulating a Capital Quality Shock under Klein and OccBin
import numpy as np
from puremacro.dsge.gertler_karadi import (
solve_gertler_karadi,
solve_steady_state,
)
# 1. Inspect Deterministic Steady State
ss = solve_steady_state()
print(f"Steady-state bank leverage phi : {ss['phi']:.2f}x")
print(f"Annualized credit spread (bps) : {ss['spread_ann']:.1f}")
# 2. Simulate Capital Quality Shock (-5% shock to xi) under Klein linear solver
res_klein = solve_gertler_karadi(
shock_type="capital_quality",
shock_size=-0.05,
horizon=40,
method="klein",
)
# 3. Simulate under OccBin with Central Bank Credit Policy Intervention
res_occbin = solve_gertler_karadi(
shock_type="capital_quality",
shock_size=-0.05,
horizon=40,
method="occbin",
constraint_type="credit_policy",
threshold=0.0025, # Intervene if spread exceeds 100 bps
)
# 4. Compare Responses. to_frame() holds level deviations x_t - x_ss (the model
# is linearised in levels); to_frame(units="pct") gives 100 * (x_t - x_ss) / x_ss.
df_klein = res_klein.to_frame()
df_occbin = res_occbin.to_frame()
pct_klein = res_klein.to_frame(units="pct")
pct_occbin = res_occbin.to_frame(units="pct")
print("Peak Net Worth Contraction (Klein, %) :", pct_klein["N"].min())
print("Peak Net Worth Contraction (OccBin, %):", pct_occbin["N"].min())
print("Peak Spread Surge (Klein, bps) :", df_klein["prem"].max() * 40000)
print("Peak Spread Surge (OccBin, bps) :", df_occbin["prem"].max() * 40000)
# 5. Diagnostic Summary & Visualizations
print(res_occbin.summary())
fig = res_occbin.plot(units="pct")
Bank net worth falls 61.7% on impact under Klein and 49.2% under OccBin, where the credit policy absorbs part of the loss; the annualised spread rises by up to about 604 bps and 256 bps above its steady state of 100 bps. Read the percentages from to_frame(units="pct"): in levels net worth falls by 0.852 and 0.679 against \(N_{ss} = 1.381\), and multiplying a level deviation by 100 gives a percentage only for variables whose steady state is 1.
5. Full API Specification
solve_gertler_karadi
solve_gertler_karadi(
params: Mapping[str, float] | None = None,
shock_type: str = "capital_quality",
shock_size: float = -0.05,
horizon: int = 40,
method: str = "occbin",
constraint_type: str = "credit_policy",
threshold: float | None = None,
max_iter: int = 50,
) -> GertlerKaradiResult
Parameters:
params: Optional overrides for canonical calibrationGK2011_PARAMS.shock_type: Innovated shock:'capital_quality'(\(\varepsilon_\xi\)),'tfp'(\(\varepsilon_a\)), or'monetary'(\(\varepsilon_r\)).shock_size: Initial innovation magnitude at \(t=0\) (default-0.05for -5% capital quality shock).horizon: Simulation horizon in quarters (default40).method: Solution engine:'occbin'(piecewise-linear) or'klein'(linear QZ).constraint_type: For OccBin:'credit_policy'or'leverage_cap'.threshold: Activation threshold for the regime switch, as a deviation from steady state. Default0.0025(100 bps spread) forcredit_policy;0.20 * phi_ss(=0.8197at this calibration) forleverage_cap. A tighter leverage cap binds for longer and needs a longerhorizon(10% above \(\phi_{ss}\) needshorizon >= 80, 5% needs>= 200); the solver reportsconverged=Falserather than guessing.max_iter: Maximum backward iterations for OccBin convergence.
6. Result Interface
GertlerKaradiResult provides structured model simulations and outputs:
- Attributes:
irf:pandas.DataFrameof impulse responses, one column per model variable and one row per quarter (row 0 is the impact quarter). The entries are level deviations from the steady state, \(x_t - x_{ss}\), in model units: the equilibrium conditions are linearised in levels, so they are neither percent nor log deviations.res["N"]returns one column.variables: List of the model's variable names, the columns ofirf:['Y', 'C', 'I', 'K', 'L', 'w', 'rho_c', 'Q', 'R', 'Rk', 'prem', 'N', 'Ne', 'Nn', 'phi', 'nu', 'eta', 'Omega', 'Pm', 'Z', 'U', 'Pi', 'Rn', 'xi', 'a', 'psi'].steady_state: Dictionary of calculated steady-state values, keyed by the same names (plus calibration targets such asspread_ann).regimes: for OccBin, the regime indicator per quarter (0= reference,1= constrained);binding_periodscounts the constrained quarters.converged:Falsewhen the OccBin regime iteration hitmax_iter(aRuntimeWarningis emitted andsummary()flags it).- Units of a level deviation:
Y,C,I,K,N,Ne,Nn,L,w: model units (\(L_{ss} = 1/3\)).R,Rk,Rn: gross quarterly returns, so the deviation is the change in the net quarterly rate as a fraction (0.0025 = 25 bps per quarter, 100 bps annualised).Piis gross quarterly inflation.prem: the expected quarterly spread \(\mathbb{E}_t[R_{k,t+1} - R_{t+1}]\) as a fraction;40000 * premis annualised basis points.phi: private bank leverage \((1 - \psi_t) Q_t K_t / N_t\), a ratio;psi: the public share of intermediated assets, whose steady state is 0.100 * (x_t - x_ss)is a percentage only for variables whose steady state is 1 (Q,U,xi,a,Pi). At the default solve capital falls by 0.2866 in level on impact against \(K_{ss} = 5.6601\): that is −5.06%, not −28.66%.- Methods:
to_frame(units="level"): Returns apandas.DataFrameindexed by simulation quarters \(t = 0, \dots, T-1\).units="level"(the default) returnsirfunchanged;units="pct"returns percent deviations \(100\,(x_t - x_{ss})/x_{ss}\).psi, whose steady state is 0, has no percent deviation: it is NaN and listed indf.attrs["pct_undefined"].df.attrs["units"]records the choice..plot(variables=None, style="publication", figsize=None, units="level"): Matplotlib multi-panel figure; by default Output, Investment, Bank Net Worth, Credit Spread, Policy RateRnand Leverage \(\phi\), with the constrained OccBin quarters shaded.unitsis passed toto_frame, and the y-axis label states it..summary(): Plain-text report of the steady state, the shock and the impact, minimum, maximum, mean and final values of the key variables, in level deviations (the header says so and points tounits="pct")..to_markdown(units="level"),.to_latex(units="level"),.to_typst(units="level"): Formatted tables for academic manuscripts;unitsis passed toto_frame.