Spaces:
Sleeping
Sleeping
File size: 6,644 Bytes
bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa bf1c4f6 bb2b2aa |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
import pandas as pd
import numpy as np
import gradio as gr
# ========== Helpers ==========
try:
from numpy_financial import irr
except ImportError:
def irr(cashflows):
rate = 0.1
for _ in range(1000):
npv = sum(cf / (1 + rate) ** i for i, cf in enumerate(cashflows))
d_npv = sum(-i * cf / (1 + rate) ** (i + 1) for i, cf in enumerate(cashflows))
rate -= npv / d_npv if d_npv else 0
return rate
def format_huf(x):
return f"{x:,.0f} HUF".replace(",", " ")
def format_pct(x):
return f"{x*100:.2f}%"
# ========== Core Model ==========
def build_property_projection(purchase_price, equity, loan_years, annual_interest_rate,
monthly_payment, monthly_rent, vacancy_months,
annual_renovation, inflation_rate):
loan_balance = purchase_price - equity
monthly_interest = annual_interest_rate / 12
schedule = []
for year in range(1, loan_years + 1):
interest_paid_year = 0
principal_paid_year = 0
for _ in range(12):
interest = loan_balance * monthly_interest
principal = monthly_payment - interest
if principal > loan_balance:
principal = loan_balance
loan_balance -= principal
interest_paid_year += interest
principal_paid_year += principal
# Rent with inflation
effective_rent_months = 12 - vacancy_months
rent_income_year = monthly_rent * ((1 + inflation_rate) ** (year - 1)) * effective_rent_months
net_cash_flow = rent_income_year - (monthly_payment * 12) - annual_renovation
property_value = purchase_price * ((1 + inflation_rate) ** year)
net_worth = property_value - loan_balance
schedule.append({
"Year": year,
"InterestPaid": round(interest_paid_year),
"PrincipalPaid": round(principal_paid_year),
"LoanBalance": round(loan_balance),
"RentIncome": round(rent_income_year),
"NetCashFlow": round(net_cash_flow),
"PropertyValue": round(property_value),
"NetWorth": round(net_worth)
})
return pd.DataFrame(schedule)
def compute_property_irr(df, equity, sell_property_at_end=True):
cashflows = [-equity]
for i, row in df.iterrows():
cf = row["NetCashFlow"]
if i == len(df) - 1 and sell_property_at_end:
cf += row["PropertyValue"] - row["LoanBalance"]
cashflows.append(cf)
return irr(cashflows)
def build_etf_projection(principal, years, annual_return):
value = principal
projection = []
for year in range(1, years + 1):
value *= (1 + annual_return)
projection.append({"Year": year, "ETF_Value": round(value)})
return pd.DataFrame(projection)
def compute_etf_irr(principal, years, annual_return):
final_value = principal * ((1 + annual_return) ** years)
cashflows = [-principal] + [0] * (years - 1) + [round(final_value)]
return irr(cashflows)
# ========== Gradio App ==========
def simulate(
purchase_price, equity, loan_years, annual_interest_rate_pct,
monthly_payment, monthly_rent, vacancy_months, annual_renovation,
inflation_rate_pct, etf_annual_return_pct
):
# Convert % to decimals
annual_interest_rate = annual_interest_rate_pct / 100
inflation_rate = inflation_rate_pct / 100
etf_annual_return = etf_annual_return_pct / 100
# Property
df_property = build_property_projection(purchase_price, equity, loan_years,
annual_interest_rate, monthly_payment,
monthly_rent, vacancy_months,
annual_renovation, inflation_rate)
prop_irr = compute_property_irr(df_property, equity)
# ETF
df_etf = build_etf_projection(equity, loan_years, etf_annual_return)
etf_irr = compute_etf_irr(equity, loan_years, etf_annual_return)
# Results summary
summary = f"""
π **Results after {loan_years} years**:
- Property IRR: {format_pct(prop_irr)}
- ETF IRR: {format_pct(etf_irr)}
π° Final Values:
- Property Net Worth: {format_huf(df_property.iloc[-1]['NetWorth'])}
- ETF Value: {format_huf(df_etf.iloc[-1]['ETF_Value'])}
"""
# Format tables for readability
df_property_fmt = df_property.copy()
for col in ["InterestPaid", "PrincipalPaid", "LoanBalance",
"RentIncome", "NetCashFlow", "PropertyValue", "NetWorth"]:
df_property_fmt[col] = df_property_fmt[col].apply(lambda x: format_huf(x))
df_etf_fmt = df_etf.copy()
df_etf_fmt["ETF_Value"] = df_etf_fmt["ETF_Value"].apply(lambda x: format_huf(x))
return summary, df_property_fmt, df_etf_fmt
with gr.Blocks(title="Investment Simulator") as demo:
gr.Markdown("# π vs π Investment Simulator")
gr.Markdown("Compare buying a property with renting vs investing in ETFs.")
with gr.Row():
with gr.Column():
purchase_price = gr.Number(value=60_000_000, label="Purchase Price (HUF)", precision=0)
equity = gr.Number(value=20_000_000, label="Equity (HUF)", precision=0)
loan_years = gr.Number(value=20, label="Loan Term (years)", precision=0)
annual_interest_rate = gr.Number(value=3.0, label="Loan Interest (THM %)", precision=2)
monthly_payment = gr.Number(value=220_000, label="Monthly Loan Payment (HUF)", precision=0)
monthly_rent = gr.Number(value=170_000, label="Monthly Rent (HUF)", precision=0)
vacancy_months = gr.Number(value=1, label="Vacancy (months/year)", precision=0)
annual_renovation = gr.Number(value=100_000, label="Annual Renovation (HUF)", precision=0)
inflation_rate = gr.Number(value=4.5, label="Inflation Rate (%)", precision=2)
etf_annual_return = gr.Number(value=11.0, label="ETF Annual Return (%)", precision=2)
run_button = gr.Button("Run Simulation")
with gr.Column():
results = gr.Markdown()
df_property_out = gr.Dataframe(interactive=False, wrap=True)
df_etf_out = gr.Dataframe(interactive=False, wrap=True)
run_button.click(
simulate,
inputs=[
purchase_price, equity, loan_years, annual_interest_rate,
monthly_payment, monthly_rent, vacancy_months, annual_renovation,
inflation_rate, etf_annual_return
],
outputs=[results, df_property_out, df_etf_out]
)
if __name__ == "__main__":
demo.launch()
|