TeX 53.2%
Python 46.6%
1"""Primitives: income process, mortgage arithmetic (Fisher, annuity-due), supply, utility."""2import numpy as np34from src import model as M567def test_rouwenhorst_moments():8 grid, Pi = M.rouwenhorst(5, 0.7, 0.3)9 pi = M.stationary_dist(Pi)10 assert np.allclose(Pi.sum(axis=1), 1.0)11 assert abs(pi @ grid) < 1e-1212 var = pi @ grid**213 assert abs(var - 0.3**2 / (1 - 0.7**2)) < 1e-814 # first-order autocorrelation equals rho15 acov = sum(pi[i] * grid[i] * sum(Pi[i, k] * grid[k] for k in range(5)) for i in range(5))16 assert abs(acov / var - 0.7) < 1e-8171819def test_period_conversions(P_small):20 P = P_small21 cfg = P.cfg22 assert abs(P.beta - cfg["preferences"]["beta_annual"] ** 5) < 1e-1223 assert abs(P.R - (1 + cfg["rates"]["r_annual"]) ** 5) < 1e-1224 assert abs(P.rho_z - cfg["income"]["rho_annual"] ** 5) < 1e-1225 # Fisher: 1 + i = R (1 + pibar)26 assert abs((1 + P.i_nom) - P.R * (1 + P.pibar)) < 1e-1227 assert abs(P.pi_z @ P.z_grid - 1.0) < 1e-10 # E[z] = 128 assert np.all(P.ybar[P.j_retire - 1:] == P.rr * P.ybar[P.j_retire - 2])293031def test_annuity_due_amortises_in_N_payments(P_small):32 P = P_small33 for i in (0.0, 0.1, P.i_nom):34 b = 1.035 pays = []36 for n in range(P.N, 0, -1):37 pays.append(M.payment(b, n, i))38 b = M.next_balance(b, n, i, 0.0) # nominal path (no deflation)39 assert abs(b) < 1e-1240 assert np.allclose(pays, pays[0]) # constant nominal payment41 # present value of the annuity-due at rate i equals the principal42 pv = sum(p / (1 + i) ** k for k, p in enumerate(pays))43 assert abs(pv - 1.0) < 1e-12444546def test_real_balance_erodes_with_inflation(P_small):47 P = P_small48 b0 = 1.049 b_nom = M.next_balance(b0, P.N, P.i_nom, 0.0)50 b_real = M.next_balance(b0, P.N, P.i_nom, P.pibar)51 assert abs(b_real * (1 + P.pibar) - b_nom) < 1e-1252 # a surprise pi_u on top of pibar erodes the real balance by 1/(1+pi_u)53 b_surprise = M.next_balance(b0, P.N, P.i_nom, (1 + P.pibar) * 1.1 - 1)54 assert abs(b_surprise * 1.1 - b_real) < 1e-12555657def test_borrowing_is_pv_neutral_against_deposits(P_small):58 """Borrow B, pay the first payment now, deposit the rest: next period the real position equals59 the one of not borrowing (annuity-due timing makes loans and deposits PV-consistent)."""60 P = P_small61 B = 0.862 pay = M.payment(B, P.N, P.i_nom)63 deposit_next = (B - pay) * P.R64 debt_next = M.next_balance(B, P.N, P.i_nom, P.pibar)65 assert abs(deposit_next - debt_next) < 1e-12666768def test_ltv_dsti_caps(P_small):69 P = P_small70 y = 1.071 cap = M.max_loan(P, 1.0, P.h_grid[0], y, P.i_q)72 assert cap <= (1 - P.theta) * P.h_grid[0] + 1e-1273 assert M.payment(cap, P.N, P.i_q) <= P.psi * y + 1e-1074 # the stress test tightens the cap75 assert M.max_loan(P, 1.0, P.h_grid[-1], y, P.i_q) <= M.max_loan(P, 1.0, P.h_grid[-1], y, P.i_nom) + 1e-12767778def test_supply_and_rent(P_small):79 P = P_small80 H = M.supply_stock(P, 1.0, 10.0, 1.0)81 assert abs(H - 10.0) < 1e-1282 assert abs(M.stock_next(P, H, 1.0, 10.0, 1.0) - H) < 1e-12 # stationary stock83 assert M.supply_stock(P, 1.1, 10.0, 2.0) > M.supply_stock(P, 1.1, 10.0, 0.5)84 rho = M.rent_from_price(P, 1.0, 1.0, P.R)85 assert abs(rho - (1 + P.m + P.phi - 1 / P.R)) < 1e-12868788def test_utility_homogeneity(P_small):89 P = P_small90 c, s = 1.3, 0.891 k = 1.792 expo = (1 - P.alpha) * (1 - P.gamma)93 assert abs(M.utility(P, k * c, s) - k**expo * M.utility(P, c, s)) < 1e-1294 assert M.warm_glow(P, 1.0) > M.warm_glow(P, 0.5)95