Running Cost Simulations
Buying a home was hard and easy in ways I didn’t expect at all. Now that I’ve closed and moving in soon, it’s a good time to write up some of the most interesting parts of home-buying. The parts you can’t find in any other online guide!
The logistics of it – setting priorities, excluding options, finding homes matching the criteria, setting up showings, filling out offers, completing inspections / financing / etc., and so on, were all easier than expected. (Yes, there was an annoyance when the final wire took 48 hours to go through after the first two wires for testing and earnest took 1 hour, but that’s not the worst of it.) Those execution skills came in handy, I suppose!
What was hard was determining what’s “affordable”. (And playing the dual games of “what will this house appraise for” and “what will everyone else offer”, sure.) There are good rules, such as:
- Loan value no more than 3x your annual income.
- Sale value no more than 4x your annual income.
- No more than 30% of your pre-tax income on housing.
- How much the bank will approve a loan for.
- Variations on the above for people with higher debt and/or lower income.
- Variations on the above for people who expected income growth or not.
These are great estimates for someone in a large labor market with largely salary income. They’re not terrifically useful for people in tech – like me – for whom >60% of their annual income is stock units whose value can fluctuate (as we all learned this past month) down 25%+ at the drop of a hat and stay there for 2-5 years. My real question was what can I afford given unstable income?
For obvious reasons, I didn’t trust the bank to make this determination for me …
I wanted to set a price such that I could achieve these goals:
- In case of a worst-case job and market downturn, I must be at no risk of losing the house.
- In case of an expected-case market downturn, I must be at no risk of reducing my standard of living.
- I must not be “house-poor”, essentially I must be able to make the 1-2 big purchases I plan in the next 18 months: a new luxury car and a 2-week tropical vacation.
- I must be able to pay all appropriate income and other taxes.
- I must be able to maintain >=20% savings rate (on pre-tax income) across principal, retirement, and other savings.
- My total costs (i.e., housing excluding principal) must make me feel like I’m getting good value-for-money compared to renting.
So, like any self-respecting tech worker, I wrote a program! The program takes as input the home’s costs (PITI, utilities / HOA, down, maintenance) and my income (stock, salary, bonus) and spits out all kinds of useful values below.
Income: $120,000
Tax: 29%
Savings Rate: 21%
Home Value: $300,000
Loan Amount: $240,000
Total Obligations (mo): $1,986
Total Costs (mo): $1,548
Remainder: $12,000
Liquid Funds: $28,000
Job Loss: 1 yr 1 mo
Market Crash: inf yr inf mo
Even better, the program goes one step further. It’s all programmatic, so I can use a separate driver
program that iterates through possible home values until it reaches the highest value that satisfies my goal conditions. For example, if I define “worst-case” as a 2008-level recession (stock market dipped 40% and took 5 years to recover) then it will find the highest home value that makes that true.
If anything, this calculator taught me why so many folks end up house-poor and caught out in emergencies. The difference in home value between two definitions of “safe” – one conservative and one optimistic – was more than double. It was the difference between spending $200k and $400k, or $1M and $2M. Amazing!
Nothing about making this program was easy, by the way.
Taxes
My first task was to accurately compute income taxes for a high-income individual, which includes federal and state progressive income taxes, sales tax, mortgage interest deductions vs. standardized deduction, Medicare (including additional medicare), social security (including income caps), etc. To ensure accuracy I programmed this for multiple states and compared against past tax returns.
It came in handy that I keep meticulous records of my taxes paid and refunded.
Budgeting
My second task was to look at spending, which included not only my credit cards – easy to track – but also checks for things like flying, periodic large expenses such as vacations and cars averaged over multiple years, and paid employee benefits such as the health premiums deducted directly from paychecks.
def calc_housing_costs_annual():
if OUTPUT.MORTGAGE is None:
raise Exception()
return OUTPUT.MORTGAGE * 12 + calc_nonmortgage_housing_costs_annual()
def calc_nonmortgage_housing_costs_annual():
return PARAMS.UTILITIES_MO * 12 \
+ (PARAMS.HOME_VALUE * PROPERTY) \
+ PARAMS.HOA \
+ PARAMS.HOME_VALUE * MAINTENANCE_FRACTION \
+ PARAMS.HOMEOWNERS_INSURANCE
(Yes, I used global variables.)
This also meant accounting for total income, which is tricky to handle when it’s salary, stock, bonus (annual and random), and benefits – and it lands across banks, brokerages, and more locations irregularly. It’s quite difficult to track every dollar and despite spending 5-ish hours debugging I never managed to make multiple sources (e.g., bank statements and pay stubs) agree with <1% error.
For this it came in very handy I keep meticulous records of purchases and income in a spreadsheet. (Noticing a pattern?)
This left a “remainder” number for income and assets, i.e. income not already committed to another purpose, whether spending, taxes, or savings. Then the program can plug in some basics such as PITI-UHM (principal, interest, taxes, insurance, utilities, HOA fees, and expected maintenance) and compute the highest price that consumes all remaining income and assets.
That is, if that’s what you want … Which is obviously isn’t.
Instead, my program would iterate over values from “obviously too low” to “obviously too high” until it found the highest home price that satisfied the conditions I wrote, e.g. Market Crash
must be 5 yr 0 mo
or better. It was just up to me to set the conditions and write them into if
statements.
defaults = {
"UTILITIES_MO": 300., # Median in my community
"TOTAL_PERSONAL_INVESTMENTS": 25_000., # Before down
"ANNUAL_INTEREST_RATE": .0511, # .05 = 5%
"HOMEOWNERS_INSURANCE": 800, # Annual
"HOA": 300, # Annual
"CLOSING_COSTS": 2000, # Fees only: no down, no prepaids
}
params = {
"GOOG_STOCK_LOSS": 0.4, # Plan for stock income to drop 40%
"TOTAL_MARKET_LOSS": 0.25, # Plan for assets to drop 25%
"INCOME_SALARY": 50_000, # Current salary
"INCOME_STOCK": 30_000, # Average of last 2 years' stock income
"DOWN": 0.2, # Just enough to eliminate PMI
}
params.update(defaults)
home_values = range(100_000, 10_000_000, increments_of=1000)
max_home_value = (None, None)
for home_value in home_values:
params['HOME_VALUE'] = home_value
o = taxes.simulate(params, print=False)
# Condition 1: Can still afford the mortgage
if o.REMAINDER > 0:
continue
# Condition 2: Have a 6-month emergency fund
yrs = -1 * float(o.LIQUID_FUNDS) / float(o.REMAINDER)
if max_home_value == (None, None) or (yrs >= 0.5 and yrs < max_home_value[1]):
max_home_value = (home_value, yrs)
This program iteratively finds the highest home value I can purchase that meets all my conditions.
The conditions
If you refer back to the bullets above, you can clearly see my requirements. However, these aren’t well-specified enough to use in programming, so I had to come up with definitions for things like “worst-case” and “expected-case”. To do this, I looked back over montly average S&P500 values since ~1920 and identified all the times the value went down instead of up, and then for each tracked how far down it went from the peak and how long it took to recover to the previous peak. I found two particularly awful cases – 1929 and 2007 should be no surprise – and set these as my “worst case” goals.
I also set “expected case” to 25% for 2 years, only – hilariously? – to experience a 25% market downturn within a month of closing on the house. Amazing.
In the end, I bought a house I’m very happy with and that met all my goals for pricing. Everyone makes certain compromises in home-buying, and I’m happy that my compromises didn’t leave me financially over-extended.
Now on to the good part – living in the house and hoping I don’t have to move for at least 6 years, which would make it the longest I’ve stayed in one place since leaving for college.