Compare four housing strategies over 30 years: aggressive 5-year payoff, standard 15-year mortgage, 30-year mortgage with early investing, and renting while investing the down payment.
The common advice is: take a 30-year mortgage at 7% because you can invest the payment difference and earn 10% in the market. But this ignores what happens after shorter mortgages are paid off. A 5-year payoff means 25 years of investing your entire former housing payment. Does that beat 30 years of investing a smaller amount?
This calculator runs the numbers.
pip install -r requirements.txt
streamlit run app.py
Requires Python 3.8+. Uses Streamlit, Plotly, and Pandas.
All scenarios use the same annual budget. The budget is whatever the aggressive 5-year payoff plan requires (about $110k/year by default).
15-year mortgage at 6.5%, paid off in exactly 5 years with large extra payments. For the first 5 years, all budget goes to housing. For the next 25 years, the entire budget (minus property tax, insurance, repairs) goes into stock investments.
Standard 15-year mortgage at 6.5%. Monthly payment is lower than the 5-year plan, so the difference goes into stocks immediately. After year 15, the full budget (minus ongoing home costs) goes into stocks.
Standard 30-year mortgage at 7.0%. Lowest monthly payment, so the most money goes into stocks from day one. Investing happens for all 30 years, but you're also paying mortgage interest for all 30 years.
Never buy. Invest the entire down payment and closing costs ($82k) on day one. Each month, pay rent and invest what's left from the budget. No equity is built, but the portfolio starts with a large lump sum.
Three options for how stock returns are calculated each year:
Flat Assumption - Every year gets the same return. Set it to 10% and every year the portfolio grows 10%.
Historical Mapping - Uses actual S&P 500 annual returns from 1995-2024, mapped to your simulation years 2026-2055. Year 2026 gets 1995's return (37.4%), year 2033 gets 2008's return (-36.6%), and so on. The slider shifts all years up or down to hit your target average.
Historical Random - Same historical returns, but shuffled randomly across years. Click the shuffle button to see different sequences. Shows how timing affects outcomes. Run 500 shuffles to see win percentages.
Range: -10% to 15%
For Flat mode, this exact rate applies every year.
For Historical modes, this sets the target average. The app adds or subtracts a constant from each historical year to make them average to your target. At -5% target (vs 10.4% historical average), every year is reduced by 15.4 percentage points.
Range: -5% to 6%
How much the home value grows each year. Default 3.8% is based on St. Louis metro historical data. At 0%, your $500k home is still worth $500k in 30 years. Negative values simulate a housing crash.
Range: $2,500 to $4,000
Starting rent for the Rent Only scenario. Based on comparable rental rates for a $500k property.
Range: 2% to 5%
How much rent grows each year. At 3.5%, a $3,200 rent becomes $8,700 after 30 years.
Range: ~$55k to $150k
Total money available for housing and investing each year. The minimum ($55k) covers the 15-year mortgage payment plus property tax, insurance, repairs, and HOA. The default ($110k) matches the aggressive 5-year payoff plan.
The budget can grow annually with the Budget Increase slider.
Separate budget for after the mortgage is paid off. Defaults to matching the main budget. Useful for modeling scenarios where you invest more aggressively once debt-free, or less aggressively (semi-retirement).
Filter which years appear in charts and calculations. The simulation always runs 30 years, but you can compare scenarios at year 10 or between years 5-15. Winner cards update based on selected range.
Home equity plus stock portfolio value. For renters, this is just stocks (no equity).
Current home value minus remaining mortgage balance. For renters, always zero.
Current value of the investment portfolio.
All money spent across the scenario: mortgage payments, down payment, closing costs, property tax, insurance, repairs, HOA, and stock contributions. When selected, rankings are by ROI (return on investment) rather than absolute value.
Four cards showing each scenario's performance at the selected year. Ranked by the selected metric.
Gold - Winner Silver - 2nd place, shows gap behind winner Bronze - 3rd place Red - 4th place
Each card shows:
- Metric value (Net Worth, Equity, Stocks, or Capital depending on selection)
- How far behind the winner
- Equity value
- Stock portfolio value
- Return percentage
In Historical Random mode, small text under each card shows win percentage across 500 simulations.
Line graph showing all four scenarios over time for the selected metric. Toggle between Total (cumulative) and Yearly (year-over-year change). Scroll to zoom, drag to pan, double-click to reset.
Bar chart comparing money put in versus what it became. Toggle between Net Worth (stocks + equity), Stocks Only, or Home Equity Only. The percentage label shows gain or loss.
Line graph showing how much goes into stocks each year per scenario. Useful for understanding cash flow patterns. The 5-year scenario shows zero investment for years 1-5, then spikes. The 30-year shows steady investment throughout.
Text analysis explaining why the current winner is winning given current slider settings. Considers market return level, appreciation rate, budget settings, and market mode. Updates dynamically as you adjust sliders.
The app runs month-by-month for 360 months (30 years). Each month:
- Home value grows by monthly appreciation rate
- Rent grows annually (applied in month 12, 24, etc.)
- Budget grows annually
- Mortgage payment made (principal + interest split calculated)
- Remaining budget after housing costs goes to investments
- Investment portfolio grows by monthly return rate
Standard amortization formula. Early payments are mostly interest; late payments are mostly principal. The 5-year scenario makes extra principal payments each month to hit the 60-month payoff target.
Annual returns converted to monthly using: monthly = (1 + annual)^(1/12) - 1
For historical modes, the simulation looks up which historical year maps to the current simulation year, applies the shift to hit the target average, and uses that adjusted return.
If the renter's budget can't cover rent (happens with high rent growth over time), they must sell stocks to cover the difference. This models the real constraint that rent must be paid.
├── app.py Entry point, page layout, section composition
├── config.py Constants: rates, defaults, colors, historical S&P data
├── requirements.txt Python dependencies
├── README.md This file
│
├── core/
│ ├── __init__.py
│ └── simulation.py Monthly simulation loop, scenario logic
│
├── ui/
│ ├── __init__.py
│ ├── sidebar.py All sidebar controls, returns UserInputs dataclass
│ ├── charts.py Plotly chart builders
│ └── components.py Winner cards, insights text, breakdown tables
│
├── docs/
│ └── assumptions.md Model assumptions and methodology notes
│
├── scripts/
│ ├── calculate_baseline.py Utility for calculating baseline payments
│ └── mortgage_comparison_engine.py
│
└── deprecated/
└── mortgage_app.py Original monolithic app (kept for reference)
All hardcoded values live here. Mortgage rates, default slider ranges, property costs, scenario colors, historical S&P 500 returns by year.
run_simulation() is the main function. Takes all user inputs, runs the 360-month loop, returns a DataFrame with monthly data and final scenario states.
get_annual_return() handles the three market modes and applies historical shifts.
render_sidebar() builds all controls and returns a UserInputs dataclass. Add new sliders here.
Each chart has its own builder function. Returns Plotly Figure objects. Modify chart appearance here.
render_winner_cards() builds the four ranking cards.
render_key_insights() generates the dynamic analysis text.
render_capital_breakdown_table() builds the data table.
These are hardcoded based on a sample $500k property:
| Parameter | Value |
|---|---|
| Home Price | $500,000 |
| Down Payment | 15% ($75,000) |
| Closing Costs | $7,000 |
| Loan Amount | $425,000 |
| 30-Year Rate | 7.0% |
| 15-Year Rate | 6.5% |
| Property Tax | $500/month |
| Insurance | $200/month |
| Repairs | $200/month |
| HOA | $29/month |
No inflation adjustment. All values are nominal dollars.
No tax modeling. Mortgage interest deduction, capital gains taxes, and property tax deductions are not factored in.
Single appreciation rate. Home values grow steadily; no housing market volatility.
Fixed rent growth rate. Real rent can spike or stay flat unpredictably.
No transaction costs on investments. Real brokerages charge fees and spreads.
No refinancing. Mortgage rates are locked for the life of the loan.
No dividend return rates are modeled.
S&P 500 historical returns: Annual total returns 1995-2024 from public market data.
St. Louis metro home appreciation: Based on regional housing price indices.
Rental rates: Estimated from comparable properties in the area.