spb/traite-evaluation-qc
Public
1import math, pytest2from traite import finance as f34def test_taux_mensuel_canadien_connu():5 # 6 % composé semestriellement → 0,49386 % par mois (valeur standard des tables canadiennes)6 assert f.taux_mensuel_canadien(0.06) == pytest.approx(0.0049386, abs=1e-7)7 assert f.taux_effectif_annuel(0.06, 2) == pytest.approx(0.0609, abs=1e-6)89def test_facteurs_identites():10 r, n = 0.05, 2511 assert f.facteur_va_annuite(r, n) * f.facteur_recouvrement(r, n) == pytest.approx(1.0)12 # recouvrement = SFF + r13 assert f.facteur_recouvrement(r, n) == pytest.approx(f.facteur_fonds_amortissement(r, n) + r)14 assert f.facteur_va(r, n) * f.facteur_vf(r, n) == pytest.approx(1.0)15 assert f.facteur_va_annuite(0.0, 10) == 101617def test_van_au_tri_est_nulle():18 flux = [-1_000_000, 65_000, 67_000, 69_000, 71_000, 1_250_000]19 r = f.tri(flux)20 assert f.van(flux, r) == pytest.approx(0.0, abs=1e-4)21 assert 0.09 < r < 0.122223def test_tri_sans_changement_de_signe():24 with pytest.raises(ValueError):25 f.tri([100, 10, 10])2627def test_mirr_bornes():28 flux = [-100, 30, 40, 50, 60]29 m = f.tri_modifie(flux, 0.05, 0.05)30 assert 0.0 < m < f.tri(flux) + 1e-9 # avec réinvestissement à 5 % < TRI, le MIRR est plus bas3132def test_hypotheque_paiement_canadien_connu():33 # 300 000 $ à 5 % composé semestriellement, 25 ans : paiement mensuel ≈ 1 744,81 $ (calculateurs canadiens)34 h = f.Hypotheque(300_000, 0.05, 300)35 assert h.paiement == pytest.approx(1744.81, abs=0.05)36 assert h.solde(300) == pytest.approx(0.0, abs=1e-6)37 tab = h.tableau()38 assert len(tab) == 300 and tab[-1]["solde"] == pytest.approx(0.0, abs=1e-6)39 assert sum(r["capital"] for r in tab) == pytest.approx(300_000, abs=1e-4)40 assert h.solde(60) == pytest.approx(tab[59]["solde"], abs=1e-4)41 assert h.interets_annee(1) + h.capital_annee(1) == pytest.approx(12 * h.paiement, abs=1e-6)4243def test_hypotheque_us_composition_mensuelle():44 h = f.Hypotheque(200_000, 0.06, 360, composition=12)45 assert h.paiement == pytest.approx(1199.10, abs=0.01)4647def test_pret_max_rcd_coherent():48 noi = 180_00049 pret = f.pret_max_par_rcd(noi, 1.25, 0.05, 300)50 h = f.Hypotheque(pret, 0.05, 300)51 assert f.rcd(noi, h.service_dette_annuel) == pytest.approx(1.25)5253def test_rbe_rne_identites():54 rbp = 240_00055 rbe = f.revenu_brut_effectif(rbp, 0.04, 6_000)56 assert rbe == pytest.approx(240_000 * 0.96 + 6_000)57 assert f.rne(rbe, 90_000, 6_000) == pytest.approx(rbe - 96_000)5859def test_capitalisation_directe_identite():60 v = f.capitalisation_directe(120_000, 0.05)61 assert v == 2_400_00062 assert f.taux_global_extrait(120_000, v) == pytest.approx(0.05)63 with pytest.raises(ValueError):64 f.capitalisation_directe(1, 0)6566def test_bande_investissement_et_rcd():67 h = f.Hypotheque(1.0, 0.05, 300)68 R = f.taux_bande_investissement(0.70, h.constante_hypothecaire, 0.09)69 assert R == pytest.approx(0.70 * h.constante_hypothecaire + 0.30 * 0.09)70 assert f.taux_par_rcd(1.25, 0.70, h.constante_hypothecaire) == pytest.approx(1.25 * 0.70 * h.constante_hypothecaire)7172def test_ellwood_egale_akerson_et_gordon():73 h = f.Hypotheque(1.0, 0.055, 300)74 fconst = h.constante_hypothecaire75 P = 1 - h.solde(120) # part remboursée après 10 ans76 a = f.taux_ellwood(0.10, 0.70, fconst, P, 10, 0.20)77 b = f.taux_akerson(0.10, 0.70, fconst, P, 10, 0.20)78 assert a == pytest.approx(b, abs=1e-12)79 # sans dette (M = 0) et sans variation de valeur : R = Y_E80 assert f.taux_ellwood(0.10, 0.0, fconst, P, 10, 0.0) == pytest.approx(0.10)81 assert f.taux_gordon(0.08, 0.02) == pytest.approx(0.06)82 with pytest.raises(ValueError):83 f.taux_gordon(0.02, 0.03)8485def test_dcf_croissance_constante_egale_gordon():86 # RNE croissant à g, actualisé à r, VT = RNE_{T+1}/(r−g) ⇒ V_0 = RNE_1/(r−g) exactement87 r, g, noi1, T = 0.08, 0.02, 100_000, 1088 noi = f.projeter_croissance(noi1, g, T + 1)89 res = f.dcf(noi[:T], r, noi_suivant=noi[T], taux_terminal=r - g)90 assert res.valeur == pytest.approx(noi1 / (r - g), rel=1e-12)91 # avec coûts de vente, la valeur baisse de c_v × VA(VT)92 res2 = f.dcf(noi[:T], r, noi_suivant=noi[T], taux_terminal=r - g, couts_vente=0.03)93 assert res.valeur - res2.valeur == pytest.approx(0.03 * res.va_terminale, rel=1e-12)9495def test_levier_tri_fonds_propres():96 prix = 2_400_000; noi = [120_000 * 1.02 ** k for k in range(10)]97 h = f.Hypotheque(0.65 * prix, 0.05, 300)98 out = f.rendement_fonds_propres_levier(noi, prix, h, 2_900_000 * 0.97)99 assert out["mise_de_fonds"] == pytest.approx(0.35 * prix)100 assert 0.05 < out["tri"] < 0.25101 assert f.van(out["flux"], out["tri"]) == pytest.approx(0, abs=1e-3)102103def test_taux_admissible_minimal():104 assert f.taux_admissible_minimal(0.045) == pytest.approx(0.065)105 assert f.taux_admissible_minimal(0.02) == pytest.approx(0.0525)106