mirror of
https://github.com/elisspace/own_vs_buy.git
synced 2026-08-29 15:44:04 +00:00
First commit
This commit is contained in:
151
own_vs_buy.py
Normal file
151
own_vs_buy.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Compare lifetime cost of home ownership vs. renting+investing.
|
||||||
|
Incorporates:
|
||||||
|
- House appreciation/depreciation
|
||||||
|
- Down payment and closing costs
|
||||||
|
- Monthly leftover investment if renting is cheaper
|
||||||
|
- Monthly compounding for investment returns
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 1. Define Constants
|
||||||
|
CURRENT_AGE = 35
|
||||||
|
AGE_AT_DEATH = 90
|
||||||
|
|
||||||
|
# Mortgage details
|
||||||
|
MORTGAGE_RATE = 0.04 # 4% annual
|
||||||
|
MORTGAGE_TERM_YEARS = 30
|
||||||
|
HOME_COST = 350_000
|
||||||
|
DOWN_PAYMENT = 50_000
|
||||||
|
BUYER_CLOSING_COSTS = 10_000 # e.g., typical closing fees
|
||||||
|
|
||||||
|
# Home-related costs
|
||||||
|
PROPERTY_TAX_RATE = 0.083 # 1% per year
|
||||||
|
HOME_INSURANCE_PER_YEAR = 1200
|
||||||
|
AVERAGE_YEARLY_MAINTENANCE = 5000
|
||||||
|
|
||||||
|
# House appreciation/depreciation
|
||||||
|
# e.g. 0.02 => +2% per year, -0.02 => -2% per year
|
||||||
|
HOME_APPRECIATION_PERCENT = 0.05
|
||||||
|
|
||||||
|
# Rent details
|
||||||
|
RENT_PER_MONTH = 1500
|
||||||
|
RENT_ANNUAL_GROWTH_RATE = 0.10 # 2.5% per year
|
||||||
|
|
||||||
|
# Investment details
|
||||||
|
INVESTMENT_RETURN_PERCENT = 0.07 # 10% annual
|
||||||
|
|
||||||
|
# 2. Calculate total months for the simulation
|
||||||
|
total_years = AGE_AT_DEATH - CURRENT_AGE
|
||||||
|
total_months = total_years * 12
|
||||||
|
|
||||||
|
# 3. Mortgage Payment Calculation (Monthly)
|
||||||
|
# Formula: M = P * (r(1+r)^n) / ((1+r)^n - 1)
|
||||||
|
# where:
|
||||||
|
# P = (HOME_COST - DOWN_PAYMENT)
|
||||||
|
# r = MORTGAGE_RATE / 12
|
||||||
|
# n = MORTGAGE_TERM_YEARS * 12
|
||||||
|
principal = HOME_COST - DOWN_PAYMENT
|
||||||
|
monthly_interest_rate = MORTGAGE_RATE / 12
|
||||||
|
number_of_payments = MORTGAGE_TERM_YEARS * 12
|
||||||
|
|
||||||
|
if principal > 0:
|
||||||
|
monthly_mortgage_payment = (
|
||||||
|
principal *
|
||||||
|
(monthly_interest_rate * (1 + monthly_interest_rate) ** number_of_payments) /
|
||||||
|
((1 + monthly_interest_rate) ** number_of_payments - 1)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# If DOWN_PAYMENT >= HOME_COST, no mortgage needed
|
||||||
|
monthly_mortgage_payment = 0
|
||||||
|
|
||||||
|
# 4. Break down monthly home costs
|
||||||
|
monthly_property_tax = (HOME_COST * PROPERTY_TAX_RATE) / 12
|
||||||
|
monthly_insurance = HOME_INSURANCE_PER_YEAR / 12
|
||||||
|
monthly_maintenance = AVERAGE_YEARLY_MAINTENANCE / 12
|
||||||
|
|
||||||
|
# 5. Initialize tracking variables
|
||||||
|
|
||||||
|
# For the homeowner:
|
||||||
|
# Start with the home’s initial value; it will appreciate monthly
|
||||||
|
house_value = HOME_COST
|
||||||
|
total_ownership_cost = DOWN_PAYMENT + BUYER_CLOSING_COSTS # upfront out-of-pocket
|
||||||
|
|
||||||
|
# For the renter:
|
||||||
|
# Lump sum investment is the down payment + closing costs that aren't spent on buying.
|
||||||
|
investment_balance = DOWN_PAYMENT + BUYER_CLOSING_COSTS
|
||||||
|
total_renting_cost = 0.0
|
||||||
|
|
||||||
|
# Convert annual appreciation to a monthly factor
|
||||||
|
monthly_appreciation_rate = (1 + HOME_APPRECIATION_PERCENT) ** (1/12) - 1
|
||||||
|
|
||||||
|
# Convert annual investment return to monthly
|
||||||
|
monthly_investment_return_rate = INVESTMENT_RETURN_PERCENT / 12
|
||||||
|
|
||||||
|
current_rent = RENT_PER_MONTH
|
||||||
|
|
||||||
|
# 6. Iterate month by month
|
||||||
|
for month in range(1, total_months + 1):
|
||||||
|
# House appreciates each month (can be negative if it's depreciation)
|
||||||
|
house_value *= (1 + monthly_appreciation_rate)
|
||||||
|
|
||||||
|
# Calculate monthly ownership cost
|
||||||
|
if month <= number_of_payments:
|
||||||
|
# Mortgage not fully paid yet
|
||||||
|
monthly_owner_cost = (monthly_mortgage_payment +
|
||||||
|
monthly_property_tax +
|
||||||
|
monthly_insurance +
|
||||||
|
monthly_maintenance)
|
||||||
|
else:
|
||||||
|
# After the mortgage is paid off, only taxes, insurance, and maintenance remain
|
||||||
|
monthly_owner_cost = (monthly_property_tax +
|
||||||
|
monthly_insurance +
|
||||||
|
monthly_maintenance)
|
||||||
|
|
||||||
|
# Add to total ownership cost
|
||||||
|
total_ownership_cost += monthly_owner_cost
|
||||||
|
|
||||||
|
# Renter pays this month’s rent
|
||||||
|
total_renting_cost += current_rent
|
||||||
|
|
||||||
|
# Determine leftover that the renter invests if renting is cheaper
|
||||||
|
# difference > 0 => owning is more expensive => that difference can be invested by the renter
|
||||||
|
difference = monthly_owner_cost - current_rent
|
||||||
|
|
||||||
|
if difference > 0:
|
||||||
|
# This means renting is cheaper by 'difference'
|
||||||
|
investment_balance += difference # invest that difference immediately
|
||||||
|
|
||||||
|
# Grow the investment balance by the monthly return
|
||||||
|
investment_balance *= (1 + monthly_investment_return_rate)
|
||||||
|
|
||||||
|
# Increase rent once a year
|
||||||
|
if month % 12 == 0:
|
||||||
|
current_rent *= (1 + RENT_ANNUAL_GROWTH_RATE)
|
||||||
|
|
||||||
|
# 7. Final net worth calculations
|
||||||
|
# Homeowner's final net worth (simplified):
|
||||||
|
# They own the house, which is now worth house_value.
|
||||||
|
# total_ownership_cost is how much cash was spent over the period (plus the upfront).
|
||||||
|
# You can show them both or compute net_worth as (house_value - total_ownership_cost)
|
||||||
|
net_worth_owning = house_value - total_ownership_cost
|
||||||
|
|
||||||
|
# Renter's final net worth is simply the investment balance
|
||||||
|
net_worth_renting = investment_balance
|
||||||
|
|
||||||
|
# 8. Results
|
||||||
|
print("----- Results -----")
|
||||||
|
print(f"Total Ownership Cost (cash outlay): ${total_ownership_cost:,.2f}")
|
||||||
|
print(f"Final House Value: ${house_value:,.2f}")
|
||||||
|
print(f"Net Worth (Owning) = House Value - Outlays = ${net_worth_owning:,.2f}")
|
||||||
|
print()
|
||||||
|
print(f"Total Rent Paid Over {total_years} Years: ${total_renting_cost:,.2f}")
|
||||||
|
print(f"Final Investment Balance (Renting): ${investment_balance:,.2f}")
|
||||||
|
print(f"Net Worth (Renting) = ${net_worth_renting:,.2f}")
|
||||||
|
print()
|
||||||
|
difference = net_worth_renting - net_worth_owning
|
||||||
|
print(f"Difference (Renting Net Worth - Owning Net Worth): ${difference:,.2f}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
233
own_vs_buy2.py
Normal file
233
own_vs_buy2.py
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
def main():
|
||||||
|
"""
|
||||||
|
1. Prints assumption values.
|
||||||
|
2. Calculates monthly living expenses (inflation-adjusted) for groceries, travel, schooling, healthcare, incidentals.
|
||||||
|
3. Calculates renting vs buying costs each month (both in terms of cash flow and net worth).
|
||||||
|
4. Compares the final net worth of renting vs buying, color-codes the final statement to indicate which is better.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ANSI color codes for terminal output
|
||||||
|
COLOR_GREEN = "\033[92m"
|
||||||
|
COLOR_RED = "\033[91m"
|
||||||
|
COLOR_RESET = "\033[0m"
|
||||||
|
COLOR_YELLOW = "\033[93m" # optional for neutral or headings
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Part 1: Constants
|
||||||
|
# ================
|
||||||
|
|
||||||
|
# Time horizon
|
||||||
|
CURRENT_AGE = 35
|
||||||
|
AGE_AT_DEATH = 90
|
||||||
|
total_years = AGE_AT_DEATH - CURRENT_AGE
|
||||||
|
total_months = total_years * 12
|
||||||
|
|
||||||
|
# --- Income & Growth ---
|
||||||
|
MONTHLY_SALARY = 5000.0 # Initial monthly salary
|
||||||
|
ANNUAL_SALARY_GROWTH = 0.02 # 2% annual salary increase
|
||||||
|
|
||||||
|
# --- Inflation for Monthly Expenses ---
|
||||||
|
ANNUAL_INFLATION = 0.03 # 3% annual
|
||||||
|
|
||||||
|
# --- Base Monthly Expenses (excluding accommodation) ---
|
||||||
|
BASE_GROCERIES = 500.0
|
||||||
|
BASE_TRAVEL = 200.0
|
||||||
|
BASE_SCHOOLING = 300.0
|
||||||
|
BASE_HEALTHCARE = 400.0
|
||||||
|
BASE_INCIDENTALS = 2500 # "catch-all" category
|
||||||
|
|
||||||
|
# --- Investment Growth ---
|
||||||
|
ANNUAL_INVESTMENT_RETURN = 0.06 # 6% annual
|
||||||
|
|
||||||
|
# --- Renting Details ---
|
||||||
|
RENT_PER_MONTH = 1500.0
|
||||||
|
ANNUAL_RENT_GROWTH = 0.025 # 2.5% annual
|
||||||
|
|
||||||
|
# --- Buying Details ---
|
||||||
|
HOME_COST = 350_000.0
|
||||||
|
DOWN_PAYMENT = 80_000.0
|
||||||
|
BUYER_CLOSING_COSTS = 5_000.0
|
||||||
|
|
||||||
|
MORTGAGE_RATE = 0.04 # 4% annual
|
||||||
|
MORTGAGE_TERM_YEARS = 30
|
||||||
|
PROPERTY_TAX_RATE = 0.01 # 1% of home value per year
|
||||||
|
HOME_INSURANCE_PER_YEAR = 1200.0
|
||||||
|
AVERAGE_YEARLY_MAINTENANCE = 5000.0
|
||||||
|
|
||||||
|
# Home appreciation (positive or negative)
|
||||||
|
ANNUAL_HOME_APPRECIATION = 0.02 # 2% per year
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Display Assumptions
|
||||||
|
# ================
|
||||||
|
print(f"{COLOR_YELLOW}----- Assumptions -----{COLOR_RESET}")
|
||||||
|
print(f"Time Span: {CURRENT_AGE} to {AGE_AT_DEATH} (Total {total_years} years)")
|
||||||
|
print(f"Initial Monthly Salary: ${MONTHLY_SALARY:,.2f}")
|
||||||
|
print(f"Annual Salary Growth: {ANNUAL_SALARY_GROWTH*100:.2f}%")
|
||||||
|
print(f"Annual Inflation (non-housing expenses): {ANNUAL_INFLATION*100:.2f}%")
|
||||||
|
print(f"Base Monthly Expenses (Groceries + Travel + Schooling + Healthcare + Incidentals): "
|
||||||
|
f"${(BASE_GROCERIES + BASE_TRAVEL + BASE_SCHOOLING + BASE_HEALTHCARE + BASE_INCIDENTALS):,.2f}")
|
||||||
|
print(f"Annual Investment Return: {ANNUAL_INVESTMENT_RETURN*100:.2f}%\n")
|
||||||
|
|
||||||
|
print("Renting Assumptions:")
|
||||||
|
print(f" - Initial Monthly Rent: ${RENT_PER_MONTH:,.2f}")
|
||||||
|
print(f" - Annual Rent Growth: {ANNUAL_RENT_GROWTH*100:.2f}%\n")
|
||||||
|
|
||||||
|
print("Buying Assumptions:")
|
||||||
|
print(f" - Home Cost: ${HOME_COST:,.2f}")
|
||||||
|
print(f" - Down Payment: ${DOWN_PAYMENT:,.2f}")
|
||||||
|
print(f" - Buyer Closing Costs: ${BUYER_CLOSING_COSTS:,.2f}")
|
||||||
|
print(f" - Mortgage Rate (Annual): {MORTGAGE_RATE*100:.2f}%")
|
||||||
|
print(f" - Mortgage Term: {MORTGAGE_TERM_YEARS} years")
|
||||||
|
print(f" - Property Tax Rate: {PROPERTY_TAX_RATE*100:.2f}% of home value/year")
|
||||||
|
print(f" - Home Insurance/Year: ${HOME_INSURANCE_PER_YEAR:,.2f}")
|
||||||
|
print(f" - Avg Yearly Maintenance: ${AVERAGE_YEARLY_MAINTENANCE:,.2f}")
|
||||||
|
print(f" - Annual Home Appreciation: {ANNUAL_HOME_APPRECIATION*100:.2f}%")
|
||||||
|
print(f"{'-'*50}\n")
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Part 2: Derive Monthly Rates and Setup
|
||||||
|
# ================
|
||||||
|
monthly_salary_growth = (1 + ANNUAL_SALARY_GROWTH) ** (1/12) - 1
|
||||||
|
monthly_inflation = (1 + ANNUAL_INFLATION) ** (1/12) - 1
|
||||||
|
monthly_investment_growth = ANNUAL_INVESTMENT_RETURN / 12
|
||||||
|
monthly_rent_growth = (1 + ANNUAL_RENT_GROWTH) ** (1/12) - 1
|
||||||
|
monthly_home_appreciation = (1 + ANNUAL_HOME_APPRECIATION) ** (1/12) - 1
|
||||||
|
|
||||||
|
# Base standard expenses total
|
||||||
|
base_standard_expenses = (
|
||||||
|
BASE_GROCERIES +
|
||||||
|
BASE_TRAVEL +
|
||||||
|
BASE_SCHOOLING +
|
||||||
|
BASE_HEALTHCARE +
|
||||||
|
BASE_INCIDENTALS
|
||||||
|
)
|
||||||
|
current_standard_expenses = base_standard_expenses
|
||||||
|
|
||||||
|
# Mortgage payment
|
||||||
|
principal = HOME_COST - DOWN_PAYMENT
|
||||||
|
monthly_mortgage_rate = MORTGAGE_RATE / 12
|
||||||
|
number_of_payments = MORTGAGE_TERM_YEARS * 12
|
||||||
|
|
||||||
|
if principal > 0:
|
||||||
|
monthly_mortgage_payment = (
|
||||||
|
principal *
|
||||||
|
(monthly_mortgage_rate * (1 + monthly_mortgage_rate) ** number_of_payments) /
|
||||||
|
((1 + monthly_mortgage_rate) ** number_of_payments - 1)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
monthly_mortgage_payment = 0.0
|
||||||
|
|
||||||
|
monthly_property_tax = (HOME_COST * PROPERTY_TAX_RATE) / 12
|
||||||
|
monthly_insurance = HOME_INSURANCE_PER_YEAR / 12
|
||||||
|
monthly_maintenance = AVERAGE_YEARLY_MAINTENANCE / 12
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Part 3: Tracking & Simulation
|
||||||
|
# ================
|
||||||
|
total_income = 0.0
|
||||||
|
total_standard_expenses_accum = 0.0
|
||||||
|
|
||||||
|
# Renting scenario
|
||||||
|
total_rent_cost = 0.0
|
||||||
|
rent_investment_balance = DOWN_PAYMENT + BUYER_CLOSING_COSTS # Freed up capital if you don't buy
|
||||||
|
current_rent = RENT_PER_MONTH
|
||||||
|
|
||||||
|
# Buying scenario
|
||||||
|
total_buy_cost = DOWN_PAYMENT + BUYER_CLOSING_COSTS # upfront cost
|
||||||
|
buy_investment_balance = 0.0
|
||||||
|
house_value = HOME_COST
|
||||||
|
|
||||||
|
# Starting salary
|
||||||
|
current_monthly_salary = MONTHLY_SALARY
|
||||||
|
|
||||||
|
for month in range(1, total_months + 1):
|
||||||
|
# --- Income
|
||||||
|
total_income += current_monthly_salary
|
||||||
|
|
||||||
|
# --- Standard Expenses (inflation-adjusted)
|
||||||
|
total_standard_expenses_accum += current_standard_expenses
|
||||||
|
|
||||||
|
# --- Renting: Pay Rent, Invest Leftover
|
||||||
|
total_rent_cost += current_rent
|
||||||
|
leftover_rent = current_monthly_salary - current_standard_expenses - current_rent
|
||||||
|
if leftover_rent > 0:
|
||||||
|
rent_investment_balance += leftover_rent
|
||||||
|
rent_investment_balance *= (1 + monthly_investment_growth)
|
||||||
|
|
||||||
|
# --- Buying: Pay Mortgage/Costs, Invest Leftover
|
||||||
|
if month <= number_of_payments:
|
||||||
|
monthly_ownership_cost = (
|
||||||
|
monthly_mortgage_payment +
|
||||||
|
monthly_property_tax +
|
||||||
|
monthly_insurance +
|
||||||
|
monthly_maintenance
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
monthly_ownership_cost = (
|
||||||
|
monthly_property_tax +
|
||||||
|
monthly_insurance +
|
||||||
|
monthly_maintenance
|
||||||
|
)
|
||||||
|
|
||||||
|
total_buy_cost += monthly_ownership_cost
|
||||||
|
leftover_buy = current_monthly_salary - current_standard_expenses - monthly_ownership_cost
|
||||||
|
if leftover_buy > 0:
|
||||||
|
buy_investment_balance += leftover_buy
|
||||||
|
buy_investment_balance *= (1 + monthly_investment_growth)
|
||||||
|
|
||||||
|
# House Appreciation
|
||||||
|
house_value *= (1 + monthly_home_appreciation)
|
||||||
|
|
||||||
|
# Increase Salary, Rent, Standard Expenses (monthly growth)
|
||||||
|
current_monthly_salary *= (1 + monthly_salary_growth)
|
||||||
|
current_rent *= (1 + monthly_rent_growth)
|
||||||
|
current_standard_expenses *= (1 + monthly_inflation)
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Part 4: Final Output & Comparison
|
||||||
|
# ================
|
||||||
|
print(f"{COLOR_YELLOW}----- Final Results -----{COLOR_RESET}")
|
||||||
|
print(f"Total Income (All Sources): ${total_income:,.2f}")
|
||||||
|
print(f"Total Standard Expenses (Excl. Accommodation): ${total_standard_expenses_accum:,.2f}")
|
||||||
|
|
||||||
|
# Costs including renting
|
||||||
|
total_rent_incl_expenses = total_standard_expenses_accum + total_rent_cost
|
||||||
|
print(f"Total Costs (Incl. Rent): ${total_rent_incl_expenses:,.2f}")
|
||||||
|
|
||||||
|
# Costs including buying
|
||||||
|
total_buy_incl_expenses = total_standard_expenses_accum + total_buy_cost
|
||||||
|
print(f"Total Costs (Incl. Buy): ${total_buy_incl_expenses:,.2f}\n")
|
||||||
|
|
||||||
|
# Compute a simplified 'final net worth' approach
|
||||||
|
# - Renter's net worth: final investment balance
|
||||||
|
# - Owner's net worth: final investment balance + house value
|
||||||
|
rent_net_worth = rent_investment_balance
|
||||||
|
buy_net_worth = buy_investment_balance + house_value
|
||||||
|
|
||||||
|
print(f"Renter's Final Investment Balance: ${rent_net_worth:,.2f}")
|
||||||
|
print(f"Homeowner's Investment Balance: ${buy_investment_balance:,.2f}")
|
||||||
|
print(f"Final House Value: ${house_value:,.2f}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
difference = buy_net_worth - rent_net_worth
|
||||||
|
if difference > 0:
|
||||||
|
# Buying scenario is ahead
|
||||||
|
print(
|
||||||
|
f"{COLOR_GREEN}Buying is ahead by ${difference:,.2f} "
|
||||||
|
f"({buy_net_worth:,.2f} vs. {rent_net_worth:,.2f}){COLOR_RESET}"
|
||||||
|
)
|
||||||
|
elif difference < 0:
|
||||||
|
# Renting scenario is ahead
|
||||||
|
print(
|
||||||
|
f"{COLOR_GREEN}Renting is ahead by ${abs(difference):,.2f} "
|
||||||
|
f"({rent_net_worth:,.2f} vs. {buy_net_worth:,.2f}){COLOR_RESET}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Exactly the same (unlikely in real life)
|
||||||
|
print(f"{COLOR_YELLOW}Both scenarios come out exactly the same!{COLOR_RESET}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user