From 0d3e0dda5fba560fa454c9b1b6423ec48a26011a Mon Sep 17 00:00:00 2001 From: Eli Date: Tue, 11 Feb 2025 15:34:38 -0500 Subject: [PATCH] First commit --- own_vs_buy.py | 151 ++++++++++++++++++++++++++++++++ own_vs_buy2.py | 233 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 own_vs_buy.py create mode 100644 own_vs_buy2.py diff --git a/own_vs_buy.py b/own_vs_buy.py new file mode 100644 index 0000000..36a3f63 --- /dev/null +++ b/own_vs_buy.py @@ -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() + diff --git a/own_vs_buy2.py b/own_vs_buy2.py new file mode 100644 index 0000000..f1cb7ca --- /dev/null +++ b/own_vs_buy2.py @@ -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() +