SPB Git forge

spb/wp18_uqo

Public
6commits 1branches 0releases
5.4 MBsize
maindefault branch
yesterdaylast push
TeX 53.2% Python 46.6%
3.5 KB · 95 lines python
Raw Blame History
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