SPB Git
23.1 KB · 298 lines python
1#!/usr/bin/env python32"""Chapitre 30 — Flux actualisés et valeur terminale : exemple intégral du cas 3 (12 logements, Montréal,3DONNÉES SYNTHÉTIQUES). Tous les chiffres cités dans manuscript/chapters/ch30.tex et solutions/ch30.tex4proviennent de ce script, qui n'appelle que la bibliothèque commune (traite.cas3, traite.finance).5Usage (racine du dépôt) : PYTHONPATH=analysis/python python3 analysis/python/cases/ch30_dcf.py6Les fonctions sont importées par les scripts de figures (analysis/python/figures/ch30_*.py) et par7analysis/python/tests/test_ch30.py."""8from __future__ import annotations9import sys, copy, pathlib10import numpy as np, pandas as pd11sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))12from traite import cas3, finance as fin1314ROOT = pathlib.Path(__file__).resolve().parents[3]1516# ----------------------------------------------------------------------------- cœur du cas 31718def base() -> dict:19    """Tout le cas 3 (RNE normalisé, taux extraits, projection 11 ans, DCF, capitalisation directe, financement)."""20    return cas3.tout()2122def tableau_dcf(r: dict) -> pd.DataFrame:23    """Tableau DCF complet : projection + facteur d'actualisation + valeur actuelle + VA cumulée (années 1..T, puis T+1)."""24    h = r["hyp"]; T = h["horizon_ans"]; taux = h["taux_actualisation"]25    p = r["projection"].copy()26    p["facteur"] = [fin.facteur_va(taux, int(t)) if t <= T else np.nan for t in p["annee"]]27    p["va"] = p["flux_avant_dette"] * p["facteur"]28    p["va_cumulee"] = p["va"].cumsum()29    return p3031def dcf_sans_levier(r: dict) -> dict:32    """Flux de l'investisseur non endetté qui paie V_0 : TRI, VAN au taux d'actualisation, délai de récupération, MIRR."""33    d = r["dcf"]; h = r["hyp"]34    flux = [-d["valeur"]] + list(d["flux"]); flux[-1] += d["vt_nette"]35    taux_r = h["taux_actualisation"]36    return {"flux": flux, "tri": fin.tri(flux), "van_au_taux": fin.van(flux, taux_r),37            "delai_recuperation": fin.delai_recuperation(flux),38            "mirr": fin.tri_modifie(flux, taux_r, taux_r)}3940def taux_implicites(r: dict) -> dict:41    """Lecture croisée DCF / capitalisation directe : taux implicite du DCF, croissance implicite, TRI si l'on paie la42    valeur par capitalisation directe, croissance annualisée du RNE sur l'horizon."""43    d = r["dcf"]; h = r["hyp"]; p = r["projection"]; T = h["horizon_ans"]44    rne1 = float(p.loc[p["annee"] == 1, "rne"].iloc[0]); rneT1 = float(p.loc[p["annee"] == T + 1, "rne"].iloc[0])45    R_med = r["taux"]["mediane"]; taux_r = h["taux_actualisation"]; Rt = h["taux_terminal"]46    V_cap = r["valeur_capitalisation"]47    flux_cap = [-V_cap] + list(d["flux"]); flux_cap[-1] += d["vt_nette"]48    return {"R_implicite_dcf": rne1 / d["valeur"], "g_implicite_gordon_R_med": taux_r - R_med, "g_implicite_terminal": taux_r - Rt,49            "croissance_rne_annualisee": (rneT1 / rne1) ** (1 / T) - 1, "croissance_rbp_annualisee": (float(p.loc[p["annee"] == T + 1, "rbp"].iloc[0]) / float(p.loc[p["annee"] == 1, "rbp"].iloc[0])) ** (1 / T) - 1,50            "tri_si_paye_V_cap": fin.tri(flux_cap), "ecart_dcf_cap": d["valeur"] - V_cap, "ecart_dcf_cap_pct": d["valeur"] / V_cap - 1,51            "V_gordon_g_marche": fin.capitalisation_directe(rne1, fin.taux_gordon(taux_r, h["croissance_loyers_marche"])),52            "V_cap_au_taux_terminal": fin.capitalisation_directe(rne1, Rt)}5354def flux_levier(r: dict) -> dict:55    """Flux après service de la dette (financement de traite.cas3.financement) et TRI des fonds propres avec levier.56    Les CAPEX sont supportés par les fonds propres : la série passée à rendement_fonds_propres_levier est le flux avant dette (RNE − CAPEX)."""57    d = r["dcf"]; f = r["financement"]; h = r["hyp"]; T = h["horizon_ans"]58    hyp = f["hypotheque"]59    res = fin.rendement_fonds_propres_levier(d["flux"], d["valeur"], hyp, d["vt_nette"])60    apres_dette = fin.flux_apres_financement(d["flux"], hyp)61    rne = r["projection"].loc[r["projection"]["annee"] <= T, "rne"].tolist()62    tab = pd.DataFrame({"annee": range(1, T + 1), "rne": rne, "capex": [c for c in (r["projection"].loc[r["projection"]["annee"] <= T, "capex"])],63                        "flux_avant_dette": d["flux"], "service_dette": [hyp.service_dette_annuel] * T, "flux_apres_dette": apres_dette,64                        "rcd": [x / hyp.service_dette_annuel for x in rne]})65    tab["flux_fonds_propres"] = res["flux"][1:]66    signes = int(sum(1 for a, b in zip(res["flux"][:-1], res["flux"][1:]) if a * b < 0))67    mirr = fin.tri_modifie(res["flux"], h["financement"]["taux"], h["taux_actualisation"])68    return {**res, "tableau": tab, "service_dette": hyp.service_dette_annuel, "changements_signe": signes, "mirr": mirr,69            "produit_net_revente": d["vt_nette"] - res["solde_final"], "cash_on_cash_1": fin.rendement_cash_on_cash(apres_dette[0], res["mise_de_fonds"]),70            "rcd_1": fin.rcd(rne[0], hyp.service_dette_annuel), "rcd_min_horizon": min(tab["rcd"]), "taux_effectif_annuel_hyp": fin.taux_effectif_annuel(h["financement"]["taux"], 2),71            "taux_mensuel": hyp.taux_periodique, "taux_mensuel_si_composition_mensuelle": h["financement"]["taux"] / 12,72            "levier": "positif" if res["tri"] > r["hyp"]["taux_actualisation"] else "négatif"}7374# ----------------------------------------------------------------------------- sensibilité7576def valeur_avec(hyp_mod: dict, r: dict) -> dict:77    """Recalcule projection + DCF avec un dictionnaire d'hypothèses modifié (les données d'état locatif/dépenses sont inchangées)."""78    proj = cas3.projection_dcf(r["etat"], r["dep"], hyp_mod)79    return cas3.valeur_dcf(proj, hyp_mod) | {"projection": proj}8081def modifier(hyp: dict, **kw) -> dict:82    h = copy.deepcopy(hyp)83    for k, v in kw.items():84        if k == "capex_facteur":85            h["capex"] = {a: m * v for a, m in h["capex"].items()}86        else:87            h[k] = v88    return h8990def sensibilite_taux_terminal(r: dict, grille=(0.0425, 0.045, 0.0475, 0.05, 0.0525, 0.055, 0.0575)) -> pd.DataFrame:91    rows = []92    for Rt in grille:93        v = valeur_avec(modifier(r["hyp"], taux_terminal=Rt), r)94        rows.append({"taux_terminal": Rt, "vt_brute": v["vt_brute"], "vt_nette": v["vt_nette"], "va_terminale": v["va_terminale"], "valeur": v["valeur"],95                     "part_terminale": v["part_terminale"], "ecart_pct_base": v["valeur"] / r["dcf"]["valeur"] - 1})96    return pd.DataFrame(rows)9798def surface_r_Rt(r: dict, taux=(0.0625, 0.065, 0.0675, 0.07, 0.0725, 0.075, 0.0775, 0.08, 0.0825), Rt=(0.0425, 0.045, 0.0475, 0.05, 0.0525, 0.055, 0.0575)) -> pd.DataFrame:99    """Surface V(r, R_T) ; lignes = r, colonnes = R_T."""100    M = np.zeros((len(taux), len(Rt)))101    for i, ri in enumerate(taux):102        for j, Rj in enumerate(Rt):103            M[i, j] = valeur_avec(modifier(r["hyp"], taux_actualisation=ri, taux_terminal=Rj), r)["valeur"]104    return pd.DataFrame(M, index=list(taux), columns=list(Rt))105106def surface_r_g(r: dict, taux=(0.0625, 0.065, 0.0675, 0.07, 0.0725, 0.075, 0.0775, 0.08, 0.0825), g=(0.02, 0.025, 0.03, 0.035, 0.04, 0.045, 0.05)) -> pd.DataFrame:107    """Surface V(r, g) où g est la croissance des loyers de marché (R_T inchangé)."""108    M = np.zeros((len(taux), len(g)))109    for i, ri in enumerate(taux):110        for j, gj in enumerate(g):111            M[i, j] = valeur_avec(modifier(r["hyp"], taux_actualisation=ri, croissance_loyers_marche=gj), r)["valeur"]112    return pd.DataFrame(M, index=list(taux), columns=list(g))113114def tornade(r: dict) -> pd.DataFrame:115    """Variation de la valeur pour un choc bas/haut de chaque intrant, les autres étant à leur valeur de base."""116    h = r["hyp"]; V0 = r["dcf"]["valeur"]117    chocs = [118        ("Taux d'actualisation r (−50 / +50 pb)", {"taux_actualisation": h["taux_actualisation"] - 0.005}, {"taux_actualisation": h["taux_actualisation"] + 0.005}),119        ("Taux terminal R_T (−25 / +25 pb)", {"taux_terminal": h["taux_terminal"] - 0.0025}, {"taux_terminal": h["taux_terminal"] + 0.0025}),120        ("Croissance des loyers de marché (2,5 / 4,5 %)", {"croissance_loyers_marche": 0.025}, {"croissance_loyers_marche": 0.045}),121        ("Croissance des loyers contractuels (2,0 / 4,0 %)", {"croissance_loyers_contrat": 0.020}, {"croissance_loyers_contrat": 0.040}),122        ("Rotation annuelle (5 / 25 %)", {"rotation_annuelle": 0.05}, {"rotation_annuelle": 0.25}),123        ("Inoccupation et pertes (2,9 / 4,9 %)", {"taux_inoccupation_pertes": 0.029}, {"taux_inoccupation_pertes": 0.049}),124        ("CAPEX (−25 / +25 %)", {"capex_facteur": 0.75}, {"capex_facteur": 1.25}),125        ("Croissance des dépenses (2,0 / 4,0 %)", {"croissance_depenses": 0.020}, {"croissance_depenses": 0.040}),126        ("Coûts de vente (1,5 / 3,5 %)", {"couts_vente": 0.015}, {"couts_vente": 0.035}),127    ]128    rows = []129    for nom, bas, haut in chocs:130        vb = valeur_avec(modifier(h, **bas), r)["valeur"]; vh = valeur_avec(modifier(h, **haut), r)["valeur"]131        rows.append({"intrant": nom, "valeur_bas": vb, "valeur_haut": vh, "delta_bas": vb - V0, "delta_haut": vh - V0, "amplitude": abs(vh - vb)})132    return pd.DataFrame(rows).sort_values("amplitude", ascending=False).reset_index(drop=True)133134def scenarios(r: dict) -> pd.DataFrame:135    """Trois scénarios narratifs : base ; encadrement serré des loyers ; hausse des taux.136    Deux lectures : (i) la valeur que conclurait l'évaluateur sous le scénario ; (ii) le sort de l'investisseur qui a payé la137    valeur de base et financé avec le prêt de base (TRI sans levier et TRI des fonds propres réalisés si le scénario se matérialise).138    Dans « Hausse des taux », le prêt de base est supposé renouvelé au taux initial + 100 pb dès l'origine (approximation du renouvellement, cf. ch. 31)."""139    h = r["hyp"]; V_base = r["dcf"]["valeur"]; f_base = r["financement"]140    defs = {141        "Base": ({}, 0.0),142        "Encadrement serré": ({"croissance_loyers_contrat": 0.020, "rotation_annuelle": 0.08, "croissance_loyers_marche": 0.030}, 0.0),143        "Hausse des taux": ({"taux_actualisation": h["taux_actualisation"] + 0.0075, "taux_terminal": h["taux_terminal"] + 0.005}, 0.01),144    }145    rows = []146    for nom, (kw, choc_taux_hyp) in defs.items():147        hm = modifier(h, **kw); v = valeur_avec(hm, r); p = v["projection"]148        hyp_pret = fin.Hypotheque(f_base["pret"], h["financement"]["taux"] + choc_taux_hyp, h["financement"]["amortissement_mois"])149        flux_sl = [-V_base] + list(v["flux"]); flux_sl[-1] += v["vt_nette"]150        lev = fin.rendement_fonds_propres_levier(v["flux"], V_base, hyp_pret, v["vt_nette"])151        rows.append({"scenario": nom, "r": hm["taux_actualisation"], "R_T": hm["taux_terminal"], "g_contrat": hm["croissance_loyers_contrat"], "g_marche": hm["croissance_loyers_marche"],152                     "rotation": hm["rotation_annuelle"], "taux_hyp": hyp_pret.taux_nominal, "rne_1": float(p.loc[p["annee"] == 1, "rne"].iloc[0]),153                     "rne_T1": v["rne_T1"], "vt_nette": v["vt_nette"], "valeur": v["valeur"], "part_terminale": v["part_terminale"],154                     "ecart_pct_base": v["valeur"] / V_base - 1, "service_dette": hyp_pret.service_dette_annuel, "rcd_min": min(x / hyp_pret.service_dette_annuel for x in p.loc[p["annee"] <= hm["horizon_ans"], "rne"]),155                     "tri_sans_levier_prix_base": fin.tri(flux_sl), "tri_fonds_propres_prix_base": lev["tri"], "flux_fp_min": min(lev["flux"][1:-1])})156    return pd.DataFrame(rows)157158# ----------------------------------------------------------------------------- vérification de la proposition DCF = capitalisation directe (Gordon)159160def verification_gordon(noi1: float = 100_000.0, r: float = 0.0725, g: float = 0.035, T: int = 10, couts_vente: float = 0.0) -> dict:161    """Sous croissance constante g et R_T = r − g, le DCF à horizon T redonne exactement NOI_1/(r − g), quel que soit T."""162    noi = fin.projeter_croissance(noi1, g, T + 1)163    res = fin.dcf(noi[:T], r, noi_suivant=noi[T], taux_terminal=fin.taux_gordon(r, g), couts_vente=couts_vente)164    return {"V_dcf": res.valeur, "V_gordon": fin.capitalisation_directe(noi1, fin.taux_gordon(r, g)), "part_terminale": res.va_terminale / res.valeur, "T": T}165166# ----------------------------------------------------------------------------- exercices (solutions/ch30.tex)167168def exercices() -> dict:169    out = {}170    # 30.1 Gordon171    out["ex1"] = {"R": fin.taux_gordon(0.0725, 0.035), "V": fin.capitalisation_directe(100_000, fin.taux_gordon(0.0725, 0.035)), "g_implicite": 0.0725 - 0.04415, "r_implicite": 0.04415 + 0.035}172    # 30.2 valeur terminale173    vtb, vtn = fin.valeur_terminale(159_658.38, 0.05, 0.025)174    out["ex2"] = {"vt_brute": vtb, "vt_nette": vtn, "va_10": vtn * fin.facteur_va(0.0725, 10), "va_11_erronee": vtn * fin.facteur_va(0.0725, 11), "ecart": vtn * fin.facteur_va(0.0725, 10) - vtn * fin.facteur_va(0.0725, 11),175                  "vt_nette_55": fin.valeur_terminale(159_658.38, 0.055, 0.025)[1]}176    # 30.3 DCF 5 ans177    flux5 = [62_000, 64_000, 20_000, 68_000, 70_000]; noi6 = 72_000178    res5 = fin.dcf(flux5, 0.07, noi_suivant=noi6, taux_terminal=0.05, couts_vente=0.03)179    prix = 1_300_000180    f5 = [-prix] + flux5; f5[-1] += res5.valeur_terminale_nette181    out["ex3"] = {"va_flux": res5.va_flux, "vt_brute": res5.valeur_terminale_brute, "vt_nette": res5.valeur_terminale_nette, "va_vt": res5.va_terminale, "valeur": res5.valeur,182                  "van_prix": fin.van(f5, 0.07), "tri_prix": fin.tri(f5), "part_terminale": res5.va_terminale / res5.valeur}183    # 30.4 taux hypothécaire canadien184    i = 0.0412185    out["ex4"] = {"i_m_can": fin.taux_mensuel_canadien(i), "i_m_us": i / 12, "eff_can": fin.taux_effectif_annuel(i, 2), "eff_us": fin.taux_effectif_annuel(i, 12),186                  "paiement_can": fin.Hypotheque(1_000_000, i, 300).paiement, "paiement_us": fin.Hypotheque(1_000_000, i, 300, composition=12).paiement}187    out["ex4"]["ecart_annuel"] = (out["ex4"]["paiement_us"] - out["ex4"]["paiement_can"]) * 12188    # 30.5 cohérence Gordon189    out["ex5"] = {T: verification_gordon(90_000, 0.0725, 0.035, T) for T in (5, 10, 20)}190    out["ex5_cv"] = verification_gordon(90_000, 0.0725, 0.035, 10, couts_vente=0.025)191    # 30.6 variante du cas 3192    r = base()193    v6 = valeur_avec(modifier(r["hyp"], taux_actualisation=0.0775, taux_terminal=0.055), r)194    out["ex6"] = {"valeur": v6["valeur"], "va_flux": v6["va_flux"], "va_terminale": v6["va_terminale"], "vt_nette": v6["vt_nette"], "part_terminale": v6["part_terminale"], "ecart_pct": v6["valeur"] / r["dcf"]["valeur"] - 1,195                  "R_implicite": float(v6["projection"].loc[0, "rne"]) / v6["valeur"]}196    # 30.7 TRI avec levier (données du cas 3)197    lev = flux_levier(r)198    out["ex7"] = {"flux": lev["flux"], "tri": lev["tri"], "mirr": lev["mirr"], "changements_signe": lev["changements_signe"], "mise": lev["mise_de_fonds"], "solde_final": lev["solde_final"],199                  "van_8": fin.van(lev["flux"], 0.08), "van_12": fin.van(lev["flux"], 0.12)}200    # 30.8 écart DCF / capitalisation directe201    out["ex8"] = taux_implicites(r)202    return out203204205# ----------------------------------------------------------------------------- corps de tableaux LaTeX (collés dans ch30.tex)206207def _n(x, dec=0):208    """Nombre brut pour une colonne S de siunitx (point décimal, pas de séparateur)."""209    return f"{x:.{dec}f}"210211def latex_tables():212    r = base(); h = r["hyp"]; T = h["horizon_ans"]; t = tableau_dcf(r); d = r["dcf"]213    print("% --- tab:30:projection (revenus et dépenses, années 1-11)")214    for _, x in t.iterrows():215        print(f"{int(x.annee)} & {int(x.exercice)} & {_n(x.rbp)} & {_n(x.rbp_marche)} & {_n(x.rbe)} & {_n(x.depenses)} & {_n(x.reserve)} & {_n(x.rne)} \\\\")216    print("% --- tab:30:dcf (flux, facteur, VA)")217    for _, x in t[t.annee <= T].iterrows():218        print(f"{int(x.annee)} & {_n(x.rne)} & {_n(x.capex)} & {_n(x.flux_avant_dette)} & {_n(x.facteur, 6)} & {_n(x.va)} & {_n(x.va_cumulee)} \\\\")219    print("% --- tab:30:levier")220    lv = flux_levier(r)221    for _, x in lv["tableau"].iterrows():222        print(f"{int(x.annee)} & {_n(x.rne)} & {_n(x.flux_avant_dette)} & {_n(x.service_dette)} & {_n(x.flux_apres_dette)} & {_n(x.rcd, 2)} & {_n(x.flux_fonds_propres)} \\\\")223    print("% --- tab:30:sens-rt")224    for _, x in sensibilite_taux_terminal(r).iterrows():225        print(f"{_n(x.taux_terminal*100, 2)} & {_n(x.vt_brute)} & {_n(x.vt_nette)} & {_n(x.va_terminale)} & {_n(x.valeur)} & {_n(x.part_terminale*100, 1)} & {_n(x.ecart_pct_base*100, 1)} \\\\")226    print("% --- tab:30:tornade")227    for _, x in tornade(r).iterrows():228        print(f"{x.intrant} & {_n(x.valeur_bas)} & {_n(x.valeur_haut)} & {_n(x.delta_bas)} & {_n(x.delta_haut)} & {_n(x.amplitude)} \\\\")229    print("% --- tab:30:scenarios (colonnes = scénarios)")230    s = scenarios(r).set_index("scenario")231    lignes = [("Taux d'actualisation $r$ (\\%)", "r", 2, 100), ("Taux terminal $R_T$ (\\%)", "R_T", 2, 100), ("Croissance des loyers contractuels (\\%)", "g_contrat", 1, 100),232              ("Croissance des loyers de marché (\\%)", "g_marche", 1, 100), ("Rotation annuelle (\\%)", "rotation", 0, 100), ("Taux hypothécaire (\\%)", "taux_hyp", 2, 100),233              ("$\\NOI_{11}$ (\\$)", "rne_T1", 0, 1), ("Valeur terminale nette (\\$)", "vt_nette", 0, 1), ("Valeur $V_0$ (\\$)", "valeur", 0, 1), ("Écart à la base (\\%)", "ecart_pct_base", 1, 100),234              ("Part de la valeur terminale (\\%)", "part_terminale", 1, 100), ("Service de la dette (\\$)", "service_dette", 0, 1), ("RCD minimal sur l'horizon", "rcd_min", 2, 1),235              ("TRI sans levier si payé \\dollars{2208566} (\\%)", "tri_sans_levier_prix_base", 2, 100), ("TRI des fonds propres si payé \\dollars{2208566} (\\%)", "tri_fonds_propres_prix_base", 2, 100), ("Flux des fonds propres le plus bas (\\$)", "flux_fp_min", 0, 1)]236    for lab, col, dec, mult in lignes:237        print(lab + " & " + " & ".join(_n(s.loc[sc, col] * mult, dec) for sc in ["Base", "Encadrement serré", "Hausse des taux"]) + " \\\\")238    print("% --- surface V(r,R_T) en milliers")239    S = surface_r_Rt(r)240    for ri, row in S.iterrows():241        print(_n(ri*100, 2) + " & " + " & ".join(_n(v/1000, 0) for v in row.values) + " \\\\")242243# ----------------------------------------------------------------------------- impression244245def _d(x): return f"{x:,.0f}".replace(",", " ") + " $"246def _p(x, d=2): return f"{x*100:.{d}f}".replace(".", ",") + " %"247248def main():249    pd.set_option("display.width", 250); pd.set_option("display.max_columns", 40); pd.set_option("display.float_format", lambda x: f"{x:,.4f}")250    r = base(); h = r["hyp"]; b = r["base"]; tx = r["taux"]; d = r["dcf"]251    print("=" * 100); print("CHAPITRE 30 — CAS 3 (DONNÉES SYNTHÉTIQUES) : FLUX ACTUALISÉS"); print("=" * 100)252    print("\n== Hypothèses (data/synthetic/cas3_montreal_hypotheses_dcf.json)")253    for k in ["date_evaluation", "horizon_ans", "taux_inoccupation_pertes", "croissance_loyers_contrat", "croissance_loyers_marche", "rotation_annuelle", "croissance_depenses", "taux_actualisation", "taux_terminal", "couts_vente", "capex", "autres_revenus_annuels"]:254        print(f"  {k:32s} {h[k]}")255    print(f"  financement : {h['financement']}")256    print("\n== Année 1 (RNE normalisé, cf. ch. 27-28)")257    print(f"  RBP contractuel {_d(b['rbp_contrat'])} ; RBP marché {_d(b['rbp_marche'])} ; écart {_d(b['ecart_marche'])} ({_p(b['ecart_marche']/b['rbp_marche'],1)} sous le marché)")258    print(f"  Inoccupation et pertes {_p(b['taux_vacance_pertes'],1)} = {_d(b['vacance_pertes'])} ; autres revenus {_d(b['autres_revenus'])} ; RBE {_d(b['rbe'])}")259    print(f"  Dépenses hors réserve {_d(b['depenses_hors_reserve'])} ; réserve {_d(b['reserve'])} ; RNE {_d(b['rne'])} ({_d(b['rne_par_logement'])}/log.) ; ratio dépenses {_p(b['ratio_depenses'],1)}")260    print("\n== Taux extraits des 40 comparables (ch. 29)")261    print(f"  n={tx['n']} ; médiane {_p(tx['mediane'],3)} ; moyenne {_p(tx['moyenne'],3)} ; pondérée RNE {_p(tx['ponderee_rne'],3)} ; Q1 {_p(tx['q1'],3)} ; Q3 {_p(tx['q3'],3)} ; min {_p(tx['min'],2)} ; max {_p(tx['max'],2)}")262    print(f"  Valeur par capitalisation directe au taux médian : {_d(r['valeur_capitalisation'])}")263    print("\n== Tableau DCF complet (années 1-10 + année 11 pour la VT)")264    t = tableau_dcf(r)265    print(t[["annee", "exercice", "rbp", "rbp_marche", "rbe", "depenses", "reserve", "rne", "capex", "flux_avant_dette", "facteur", "va", "va_cumulee"]].to_string(index=False))266    print("\n== Valeur terminale et valeur")267    print(f"  RNE_11 {_d(d['rne_T1'])} ; R_T {_p(h['taux_terminal'])} ; VT brute {_d(d['vt_brute'])} ; coûts de vente {_p(h['couts_vente'],1)} = {_d(d['vt_brute']-d['vt_nette'])} ; VT nette {_d(d['vt_nette'])}")268    print(f"  Facteur (1+r)^-10 = {fin.facteur_va(h['taux_actualisation'], 10):.6f} ; VA de la VT {_d(d['va_terminale'])} ; VA des flux {_d(d['va_flux'])}")269    print(f"  VALEUR DCF = {_d(d['valeur'])} ; part de la VT {_p(d['part_terminale'],1)} ; par logement {_d(d['valeur']/12)}")270    ti = taux_implicites(r)271    print("\n== Lecture croisée DCF / capitalisation directe")272    for k, v in ti.items(): print(f"  {k:32s} {(_p(v,3) if abs(v) < 1 else _d(v))}")273    sl = dcf_sans_levier(r)274    print("\n== Investisseur non endetté payant V_0")275    print(f"  TRI {_p(sl['tri'],4)} (= r par construction) ; VAN(r) {sl['van_au_taux']:.6f} $ ; délai de récupération {sl['delai_recuperation']:.2f} ans ; MIRR(r,r) {_p(sl['mirr'],4)}")276    lv = flux_levier(r); f = r["financement"]277    print("\n== Financement (traite.cas3.financement) et flux après dette")278    print(f"  Prêt max RPV 75 % {_d(f['pret_rpv'])} ; prêt max RCD 1,20 {_d(f['pret_rcd'])} ; prêt retenu {_d(f['pret'])} (contrainte {f['contrainte']}) ; RPV effectif {_p(f['rpv'])}")279    print(f"  Taux nominal {_p(h['financement']['taux'])} comp. semestrielle → mensuel {_p(lv['taux_mensuel'],5)} (vs {_p(lv['taux_mensuel_si_composition_mensuelle'],5)} si mensuelle) ; effectif annuel {_p(lv['taux_effectif_annuel_hyp'],4)}")280    print(f"  Paiement mensuel {_d(f['hypotheque'].paiement)} ; service de la dette {_d(lv['service_dette'])} ; constante {_p(f['constante'],3)} ; RCD année 1 {lv['rcd_1']:.3f} ; RCD min sur l'horizon {lv['rcd_min_horizon']:.3f}")281    print(f"  Mise de fonds {_d(lv['mise_de_fonds'])} ; solde après 120 paiements {_d(lv['solde_final'])} ; produit net de revente {_d(lv['produit_net_revente'])}")282    print(lv["tableau"].to_string(index=False))283    print(f"  Flux des fonds propres : {[round(x) for x in lv['flux']]}")284    print(f"  Changements de signe {lv['changements_signe']} ; TRI fonds propres {_p(lv['tri'],3)} ; MIRR (fin. {_p(h['financement']['taux'])}, réinv. {_p(h['taux_actualisation'])}) {_p(lv['mirr'],3)} ; cash-on-cash an 1 {_p(lv['cash_on_cash_1'],2)} ; levier {lv['levier']}")285    print("\n== Sensibilité au taux terminal")286    print(sensibilite_taux_terminal(r).to_string(index=False))287    print("\n== Surface V(r, R_T)"); print(surface_r_Rt(r).round(0).to_string())288    print("\n== Surface V(r, g_marché)"); print(surface_r_g(r).round(0).to_string())289    print("\n== Tornade"); print(tornade(r).to_string(index=False))290    print("\n== Scénarios"); print(scenarios(r).to_string(index=False))291    print("\n== Vérification de la proposition (croissance constante, R_T = r − g)")292    for T in (5, 10, 30): print(f"  T={T:2d} : {verification_gordon(T=T)}")293    print("\n== Exercices")294    for k, v in exercices().items(): print(f"  {k}: {v}")295296if __name__ == "__main__":297    latex_tables() if "--latex" in sys.argv else main()298
Files · 2fa255cfbe38460cb046bb32c81cf4f586081ba2
Menu

Theme