SPB Git
10.8 KB · 197 lines python
1"""Tests du chapitre 29 — capitalisation directe (cas 3, données synthétiques).2Identités financières + valeurs citées dans manuscript/chapters/ch29.tex et solutions/ch29.tex (tolérances déclarées)."""3import sys, pathlib4sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))5sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1] / "cases"))6import pytest7from traite import cas3, finance as fin8from ch29_capitalisation import calculer, exercices, droits_mutation910ROOT = pathlib.Path(__file__).resolve().parents[3]111213@pytest.fixture(scope="module")14def res():15    return calculer()161718@pytest.fixture(scope="module")19def ex(res):20    return exercices(res)212223# ----------------------------------------------------------------------------- identités24def test_identite_capitalisation(res):25    assert res["V"] == pytest.approx(res["base"]["rne"] / res["R"], rel=1e-12)26    assert fin.taux_global_extrait(res["base"]["rne"], res["V"]) == pytest.approx(res["R"], rel=1e-12)272829def test_coherence_avec_cas3_partage(res):30    """Les chiffres du chapitre 29 coïncident avec ceux que les chapitres 30 et 47 tirent de traite.cas3.tout()."""31    t = cas3.tout()32    assert res["V"] == pytest.approx(t["valeur_capitalisation"], rel=1e-12)33    assert res["base"]["rne"] == pytest.approx(t["base"]["rne"], rel=1e-12)34    assert res["R"] == pytest.approx(t["taux"]["mediane"], rel=1e-12)353637def test_ellwood_egal_akerson(res):38    e = res["ellwood"]39    assert e["R_delta"] == pytest.approx(e["R_akerson"], abs=1e-12)40    # somme des composantes d'Akerson = taux41    assert sum(e["composantes"].values()) == pytest.approx(e["R_delta"], abs=1e-12)42    assert sum(e["composantes_marche"].values()) == pytest.approx(res["R"], abs=1e-9)43    # sans dette ni variation de valeur : R = Y44    assert e["R_sans_dette_delta0"] == pytest.approx(e["Y"], abs=1e-12)45    # Y implicite : réinjecté dans Ellwood, redonne le taux de marché46    h = fin.Hypotheque(1.0, res["hyp"]["financement"]["taux"], res["hyp"]["financement"]["amortissement_mois"])47    assert fin.taux_ellwood(e["Y_implicite"], e["M"], e["f"], 1 - h.solde(120), e["n"], e["delta"]) == pytest.approx(res["R"], abs=1e-8)484950def test_bande_et_rcd(res):51    assert fin.taux_bande_investissement(res["M"], res["f"], res["re_implicite"]) == pytest.approx(res["R"], abs=1e-12)52    assert res["R_rcd"] == pytest.approx(1.20 * 0.75 * res["f"], rel=1e-12)53    # constante hypothécaire : 4,12 % composé semestriellement, 480 mois54    i_m = (1 + 0.0412 / 2) ** (1 / 6) - 155    assert res["f"] == pytest.approx(12 * i_m / (1 - (1 + i_m) ** -480), rel=1e-12)565758def test_gordon(res):59    g = res["gordon"]60    assert g["R_g_terminal"] == pytest.approx(g["r"] - g["g_terminal"], abs=1e-12)61    assert g["R_g_terminal"] == pytest.approx(res["hyp"]["taux_terminal"], abs=1e-12)62    with pytest.raises(ValueError):63        fin.taux_gordon(0.05, 0.05)646566def test_derivee_sensibilite(res):67    d = res["derive"]; V, R = res["V"], res["R"]68    assert d["dV_dR"] == pytest.approx(-V / R, rel=1e-12)69    # approximation linéaire vs variation exacte pour +25 pb : la linéarisation surestime la baisse70    assert d["var_plus25_exacte"] > d["var_plus25_lineaire"]71    assert d["var_plus25_exacte"] == pytest.approx(-0.0025 / (R + 0.0025), rel=1e-12)72    s = res["sensibilite"]73    assert (s["rne_p5"] / s["rne"] - 1).round(10).eq(0.05).all()74    assert (s["rne_m5"] / s["rne"] - 1).round(10).eq(-0.05).all()757677def test_droits_mutation_bareme():78    assert droits_mutation(50_000) == pytest.approx(250.0)79    assert droits_mutation(62_900) == pytest.approx(314.5)80    assert droits_mutation(315_000) == pytest.approx(314.5 + 2521.0)81    assert droits_mutation(0) == 0.0828384# ----------------------------------------------------------------------------- valeurs citées dans le texte85def test_valeurs_citees_revenus(res):86    b = res["base"]87    assert b["rbp_contrat"] == pytest.approx(165_540, abs=0.5)88    assert b["rbp_marche"] == pytest.approx(186_036, abs=0.5)89    assert b["vacance_pertes"] == pytest.approx(6_456.06, abs=0.01)90    assert b["rbe"] == pytest.approx(168_443.94, abs=0.01)91    assert b["depenses_hors_reserve"] == pytest.approx(70_385.19, abs=0.01)92    assert b["reserve"] == pytest.approx(8_103, abs=0.01)93    assert b["rne"] == pytest.approx(89_955.75, abs=0.01)94    assert b["ratio_depenses"] == pytest.approx(0.4660, abs=5e-4)95    assert b["rne_par_logement"] == pytest.approx(7_496.31, abs=0.01)969798def test_valeurs_citees_taux(res):99    t = res["taux"]100    assert t["n"] == 40101    assert t["mediane"] == pytest.approx(0.04415, abs=1e-6)102    assert t["moyenne"] == pytest.approx(0.044038, abs=1e-6)103    assert t["ponderee_rne"] == pytest.approx(0.043319, abs=1e-6)104    assert (t["q1"], t["q3"], t["min"], t["max"]) == pytest.approx((0.041525, 0.046375, 0.0372, 0.0547), abs=1e-6)105    r = res["regression"]106    assert r["constante"] == pytest.approx(0.04567, abs=1e-5)107    assert r["etat"] == pytest.approx(-0.000441, abs=1e-6)108    assert r["taille"] == pytest.approx(-0.000227, abs=1e-6)109    assert r["r2"] == pytest.approx(0.156, abs=1e-3)110    assert r["sigma_resid"] == pytest.approx(0.003825, abs=1e-6)111    assert res["mediane_proches"] == pytest.approx(0.0452, abs=1e-6)112    assert len(res["proches"]) == 10 and res["proches"].iloc[0]["id_vente"] == "M040"113114115def test_valeurs_citees_valeur(res):116    assert res["V"] == pytest.approx(2_037_502.89, abs=0.01)117    assert res["V_arrondie"] == 2_040_000118    assert res["V_reg"] == pytest.approx(1_969_694, abs=1)119    assert res["V_proches"] == pytest.approx(1_990_172, abs=1)120    assert res["V_q1"] == pytest.approx(1_939_747, abs=1) and res["V_q3"] == pytest.approx(2_166_303, abs=1)121122123def test_valeurs_citees_construction(res):124    assert res["f"] == pytest.approx(0.050789, abs=1e-6)125    assert res["re_implicite"] == pytest.approx(0.02423, abs=1e-5)126    assert res["grille_re"][0.06] == pytest.approx(0.05309, abs=1e-5)127    assert res["R_rcd"] == pytest.approx(0.04571, abs=1e-5)128    assert res["V_rcd"] == pytest.approx(1_967_946, abs=1)129    g = res["gordon"]130    assert g["g_terminal"] == pytest.approx(0.0225, abs=1e-9) and g["R_g_tal"] == pytest.approx(0.0415, abs=1e-9)131    assert g["g_implicite_marche"] == pytest.approx(0.02835, abs=1e-6)132    e = res["ellwood"]133    assert e["P"] == pytest.approx(0.122504, abs=1e-6)134    assert e["SFF"] == pytest.approx(0.071527, abs=1e-6)135    assert e["delta"] == pytest.approx(0.249203, abs=1e-6)136    assert e["R_delta0"] == pytest.approx(0.049645, abs=1e-6)137    assert e["R_delta"] == pytest.approx(0.03182, abs=1e-5)138    assert e["R_sans_dette"] == pytest.approx(0.054675, abs=1e-6)139    assert e["delta_implicite"] == pytest.approx(0.076828, abs=1e-6)140    assert e["Y_implicite"] == pytest.approx(0.1070, abs=1e-4)141    assert e["V_delta"] == pytest.approx(2_826_982, abs=1)142143144def test_valeurs_citees_multiplicateurs_coherence(res):145    m = res["mrb"]146    assert m["mediane"] == pytest.approx(13.54, abs=1e-6) and m["moyenne"] == pytest.approx(13.372, abs=1e-3)147    assert m["V_contrat"] == pytest.approx(2_241_412, abs=1) and m["V_marche"] == pytest.approx(2_518_927, abs=1)148    assert m["mrn"] == pytest.approx(22.650, abs=1e-3) and m["mrb_sujet_implicite"] == pytest.approx(12.308, abs=1e-3)149    assert m["cv"] > m["cv_taux"]150    c = res["coherence"]151    assert c["taxes_role"] == pytest.approx(11_925.98, abs=0.01)152    assert c["ecart_taxes"] == pytest.approx(880.88, abs=0.01) and c["effet_valeur"] == pytest.approx(19_952, abs=1)153    assert c["R_avant_reserve_equiv"] == pytest.approx(0.0481, abs=1e-4)154    assert c["V_si_taux_avant_reserve_sur_rne_apres"] == pytest.approx(1_869_136, abs=1)155    assert c["rne_marche"] == pytest.approx(108_864.54, abs=0.01)156    assert c["V_marche"] == pytest.approx(2_465_788, abs=1) and c["surevaluation_marche"] == pytest.approx(0.2102, abs=1e-4)157    mu = res["mutations"]158    assert mu["base"] == 2_200_000 and mu["droits"] == pytest.approx(45_460.5, abs=0.01)159    assert mu["droits_sur_prix"] == pytest.approx(40_763.07, abs=0.01) and mu["pct_prix"] == pytest.approx(0.0223, abs=1e-4)160161162def test_valeurs_citees_sensibilite(res):163    s = res["sensibilite"].set_index("R")164    assert s.loc[0.0375, "rne"] == pytest.approx(2_398_820, abs=1)165    assert s.loc[0.0525, "rne"] == pytest.approx(1_713_443, abs=1)166    assert s.loc[0.045, "rne_p5"] == pytest.approx(2_098_968, abs=1)167    d = res["derive"]168    assert d["dV_25pb"] == pytest.approx(-115_374, abs=1)169    assert d["V_plus25"] == pytest.approx(1_928_312, abs=1) and d["V_moins25"] == pytest.approx(2_159_802, abs=1)170    assert d["var_plus25_exacte"] == pytest.approx(-0.0536, abs=1e-4) and d["var_plus25_lineaire"] == pytest.approx(-0.0566, abs=1e-4)171172173def test_exercices(ex):174    assert ex["1"]["V"] == pytest.approx(1_288_421.05, abs=0.01) and ex["1"]["V_plus25"] == pytest.approx(1_224_000, abs=0.01)175    assert ex["1"]["var"] == pytest.approx(-0.05, abs=1e-9)176    assert ex["2"]["mediane"] == pytest.approx(0.044519, abs=1e-6) and ex["2"]["moyenne"] == pytest.approx(0.045395, abs=1e-6)177    assert ex["2"]["ponderee"] == pytest.approx(0.045277, abs=1e-6) and ex["2"]["V_mediane"] == pytest.approx(2_020_629, abs=1)178    assert ex["3"]["R_apres"] == pytest.approx(0.044118, abs=1e-6) and ex["3"]["R_avant"] == pytest.approx(0.047691, abs=1e-6)179    assert ex["3"]["V_errone"] == pytest.approx(1_886_214, abs=1) and ex["3"]["erreur"] == pytest.approx(-0.0749, abs=1e-4)180    assert ex["3"]["V_coherent_avant"] == pytest.approx(2_056_119, abs=1)181    assert ex["4"]["R_bande"] == pytest.approx(0.053092, abs=1e-6) and ex["4"]["R_rcd"] == pytest.approx(0.047615, abs=1e-6)182    assert ex["4"]["V_bande"] == pytest.approx(1_694_335, abs=1) and ex["4"]["V_rcd"] == pytest.approx(1_889_228, abs=1)183    assert ex["5"]["V_225"] == pytest.approx(1_799_115, abs=1) and ex["5"]["V_310"] == pytest.approx(2_167_608, abs=1) and ex["5"]["V_g4"] == pytest.approx(2_767_869, abs=1)184    assert ex["6"]["R_ellwood"] == pytest.approx(ex["6"]["R_akerson"], abs=1e-12)185    assert ex["6"]["R_ellwood"] == pytest.approx(0.031763, abs=1e-6) and ex["6"]["R_sans_dette"] == pytest.approx(0.054618, abs=1e-6)186    assert ex["6"]["g_equiv"] == pytest.approx(0.022565, abs=1e-6) and ex["6"]["R_gordon_equiv"] == pytest.approx(0.049935, abs=1e-6)187    assert ex["6"]["V"] == pytest.approx(2_832_053, abs=1)188    assert ex["7"]["ecart_rne"] == pytest.approx(18_908.79, abs=0.01) and ex["7"]["V_mrb_vs_cap"] == pytest.approx(0.1001, abs=1e-4)189    assert ex["8"]["R_24_etat2"] == pytest.approx(0.043381, abs=1e-6) and ex["8"]["R_6_etat4"] == pytest.approx(0.046594, abs=1e-6)190    assert ex["8"]["V_pire"] == pytest.approx(1_831_896, abs=1) and ex["8"]["V_meilleur"] == pytest.approx(2_267_792, abs=1)191    assert ex["8"]["var_pire"] == pytest.approx(-0.1009, abs=1e-4) and ex["8"]["var_meilleur"] == pytest.approx(0.1130, abs=1e-4)192193194def test_figures_presentes():195    for slug in ("taux-extraits", "taux-etat-taille", "surface-v", "bande-investissement", "taux-gdc"):196        assert (ROOT / f"assets/figures/ch29/ch29-fig-{slug}.pdf").exists(), slug197
Files · 52713f1726a682cc02b48561b6b82a2be2ec84ba
Menu

Theme