McAuliffe Home Purchase

Author

William McAuliffe

Introduction

The goal is to anticipate how much our costs will be for purchasing a house and servicing the mortgage.

We’ll start by setting a randomization seed and uploading packages.

library(tidyverse)
library(FinancialMath)
set.seed(123)

Now we also create some functions we will use throughout. In all cases, we will sample from a distributions composed of 100,000 samples. This will help us capture uncertainty in how much things will cost.

# sample from lognormal distribution
sample_logn <- function(mean, sd) {
  logn_dist <- rlnorm(n = 100000,
                      meanlog = log(mean^2 / sqrt(mean^2 + sd^2)),
                      sdlog = sqrt(log(1 + (sd^2/mean^2))))
  return(logn_dist)
}

#sample from the beta distribution by specifying the mean proportion an its standard deviation
sample_beta <- function(mean_val, sd_val) {
  n <- 100000
  # calculate alpha and beta parameters
  var_val <- sd_val^2
  alpha <- ((1 - mean_val) / var_val - 1 / mean_val) * mean_val^2
  beta <- alpha * (1 / mean_val - 1)
  # Check and adjust alpha and beta to ensure they are valid for the beta distribution
  if (alpha <= 0 | beta <= 0) {
    stop("Invalid shape parameters: alpha and beta must be greater than 0.")
  }
  # sample from beta distribution
  return(rbeta(n, alpha, beta))
}

#Summary statistics 
calculate_summary_stats <- function(data) {
  result <- data.frame(
    Value = c(mean(data), median(data), quantile(data, 0.05), quantile(data, 0.95))
  )
  # Set row names
  row.names(result) <- c("Mean", "Median", "5_Percentile", "95_Percentile")
  return(result)
}


#I modified a tutorial on the FinancialMath package to generate a amortization table for a given loan. See:
# https://medium.com/analytics-vidhya/calculating-a-fixed-rate-mortgage-payment-in-r-2ce58b2d929e
# i = annual interest rate. it is divided by 12 to get monthly rate
# n = 12*30 monthly payments
generate_amort_table <- function(principal, interest_rate) {
  amortization_table<-amort.table(Loan = principal, i = interest_rate/12, n = 12*30)
# Extract relevant values
  monthly_payment <- amortization_table$Schedule[1, "Payment"]
  total_paid <- amortization_table$Other["Total Paid", "Details"]
  total_interest <- amortization_table$Other["Total Interest", "Details"]
return(c(monthly_payment = monthly_payment, total_paid = total_paid, total_interest = total_interest))
}

Home Cost

We can either:

(1) choose a home price that we want and see what we would need to obtain it, or

(2) choose a savings strategy and a purchase date and see how expensive of a home we could afford.

I’ll start with (1) for now. The home price determines everything else. I created a distribution centered on $500,000. It is slightly positively skewed to reflect that we’re more likely to spend less than $500,000. On this model, there is a 90% chance our costs between ~$353,000 and ~$679,000.

# Sample from lognormal distribution 
house_cost_samples <- sample_logn(500000, 100000)  

#median, 90% of samples
calculate_summary_stats(house_cost_samples)
                 Value
Mean          500088.6
Median        490382.2
5_Percentile  353830.0
95_Percentile 678937.6
#plot distribution
ggplot(data.frame(x = house_cost_samples), aes(x)) +   
geom_histogram(binwidth = 20000, fill = "blue", color = "black", alpha = 0.7) +   labs(title = "Housing Cost",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Assumptions

The calculations are based on the following assumptions:

  • 30-year fixed mortgage. This is the most common choice, although it means that we pay a lot more in interest over the long-run than, say, a 15-year loan.

  • No broker fees. In Florida, the seller usually pays the broker.

  • No refinancing the mortgage. This is a conservative assumption. If interest rates did substantially decline after we bought the house, we could lock in a lower rate, lowering our monthly bill.

  • No earmarked reserves. Lenders want to see that we have 2+ months of mortgage payments in savings; however, we can use funds set aside for other purposes to demonstrate adequate reserves.

  • No change in property value. This is also highly conservative, homes typically appreciate in value over time. That said, assuming a constant price will actually underestimate how much we pay in property taxes over time.

Upfront Costs

Down Payment

I assume a down payment of 20%, which will allow us to avoid paying for mortgage insurance. There is a 90% chance the down payment will cost between ~$70,000 and ~$136,000.

down_payment<- house_cost_samples*.20

#median, 90% of samples
calculate_summary_stats(down_payment)
                  Value
Mean          100017.72
Median         98076.45
5_Percentile   70766.00
95_Percentile 135787.52
#plot distribution
ggplot(data.frame(x = down_payment), aes(x)) +   
geom_histogram(binwidth = 5000, fill = "orange", color = "black", alpha = 0.7) +   labs(title = "Down Payment",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Closing Costs

I assume the total closing cost is somewhere between 2 and 5%of the loan principal (i.e., sticker price minus down payment). These costs are due to the appraisal, home inspection, etc.

There is a 90% chance the costs fall between ~$7,600 and ~$22,000.

#uniform distribution between 2 and 5%, expressed as a proportion
cc_prop<-runif(n = 100000, min = .02, max = .05) 

closing_costs<- cc_prop*(house_cost_samples*.80) 

#median, 90% of samples
calculate_summary_stats(closing_costs)      
                  Value
Mean          14011.955
Median        13519.296
5_Percentile   7630.957
95_Percentile 22158.010
#plot distribution
ggplot(data.frame(x = closing_costs), aes(x)) +   
geom_histogram(binwidth = 1000, fill = "yellow", color = "black", alpha = 0.7) +   labs(title = "Closing Costs",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Moving

I assume moving within Miami will cost somewhere between $1,500 and $3000.

moving_costs<-runif(n = 100000, min = 1500, max = 3000) 

Total Upfront

total_upfront<-down_payment+closing_costs+moving_costs

#median, 90% of samples
calculate_summary_stats(total_upfront)      
                  Value
Mean          116280.21
Median        114021.14
5_Percentile   82535.56
95_Percentile 157606.81
#plot distribution
ggplot(data.frame(x = total_upfront), aes(x)) +   
geom_histogram(binwidth = 1000, fill = "green", color = "black", alpha = 0.7) +   labs(title = "Total Upfront Cost",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Ongoing Costs

Mortgage Payment

The average annual interest rate for the top credit score category is currently 6.73%. Based on recent variation I’ll assume a standard deviation of 0.75%. That is, there is a 90% chance that the mortgage rate will be between 5.5% and 8%.

interest_rate_samples<-sample_beta(.0673, .0075)

#median, 90% of samples
calculate_summary_stats(interest_rate_samples)  
                   Value
Mean          0.06728094
Median        0.06705330
5_Percentile  0.05539785
95_Percentile 0.08007114
ggplot(data.frame(x = interest_rate_samples), aes(x)) +
  geom_histogram(binwidth = 0.001, fill = "red", color = "black", alpha = 0.7) +
  labs(title = "Mortgage Annual Interest Rate",
       x = "Value",
       y = "Frequency") +
  theme_minimal()+
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Even though the interest rate remains fixed across years, the amount we pay in interest decreases over time. This is because the interest rate applies to the outstanding loan balance, which decreases as we pay off more and more of the principal. Nevertheless, the loan is amortized, so the actual amount we pay month-to-month remains constant over time.

# Use mapply to apply the function to all combinations of principals and interest rates
mortgage_payment_samples <- mapply(generate_amort_table, (house_cost_samples*.80), interest_rate_samples)


monthly_payment<-calculate_summary_stats(mortgage_payment_samples["monthly_payment",])
total_paid<-calculate_summary_stats(mortgage_payment_samples["total_paid",])
total_interest<-calculate_summary_stats(mortgage_payment_samples["total_interest",])

mortgage_summary<-cbind(monthly_payment, total_paid, total_interest)
colnames(mortgage_summary) <- c("Monthly Payment", "Total Paid", "Total Interest")
mortgage_summary
              Monthly Payment Total Paid Total Interest
Mean                 2592.220   933199.1       533128.2
Median               2534.480   912413.3       518646.3
5_Percentile         1789.590   644254.1       349259.7
95_Percentile        3591.662  1292998.8       767727.1
#plot distribution
ggplot(data.frame(x = mortgage_payment_samples["monthly_payment",]), aes(x)) +   
geom_histogram(binwidth = 100, fill = "purple", color = "black", alpha = 0.7) +   labs(title = "Monthly Mortgage Payment",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

Property Taxes

The median property tax rate in Miami-Dade county is 1.02%. I am not sure what types of uncertainty the website I linked to accounted for, so I will assume the true percentage could be 10 basis points higher or lower. We use the cost of the home as a proxy for the property value, which should be realistic for at least the first few years of home ownership.

#expressed as a proportion of the home value.
property_tax_percentage_samples<- runif(100000, min = 0.0092, max = .0112)

property_tax_samples<-(property_tax_percentage_samples*house_cost_samples)/12

#monthly payment
monthly_property_tax<-calculate_summary_stats(property_tax_samples)
colnames(monthly_property_tax)[colnames(monthly_property_tax) == "Value"] <- "Monthly Property Tax Payment"
monthly_property_tax
              Monthly Property Tax Payment
Mean                              425.1350
Median                            416.1098
5_Percentile                      296.4351
95_Percentile                     584.1514

Homeowners Insurance

The average annual cost in Miami depends on the coverage amount:

  • $3,572 for $300,000 in coverage

  • $4,717 for $400,000 in coverage

  • $5,961 for $500,000 in coverage

In each case, the cost is ~1.2% of the amount of the dwelling coverage, the amount needed to rebuild your home. Rebuilding your home costs somewhere around $125 per square foot in Miami right now. How many square feet we get depends a lot on whether we get a house or condo. Based on places we have looked at so far, I’ll create a positively skewed distribution centered on 1,500 square feet.

square_footage <- sample_logn(1500, 250)  

homeowners_monthly_samples<- ((square_footage*125)*.012)/12


#monthly payment
homeowners_insurance<-calculate_summary_stats(homeowners_monthly_samples)
colnames(homeowners_insurance)[colnames(homeowners_insurance) == "Value"] <- "Monthly Homeowner's Insurance Payment"
homeowners_insurance
              Monthly Homeowner's Insurance Payment
Mean                                       187.3990
Median                                     184.8355
5_Percentile                               140.8737
95_Percentile                              242.3965

Flood Insurance

In Miami-Dade county, the average cost of flood insurance per year is $477. The minimum in the Florida range is $261, so we’ll go with a standard deviation of $100.

yearly_flood_samples<-rnorm(100000, mean = 477, sd = 100)
monthly_flood_samples<-yearly_flood_samples/12

monthly_flood_summary<-calculate_summary_stats(monthly_flood_samples)
colnames(monthly_flood_summary)[colnames(monthly_flood_summary) == "Value"] <- "Monthly Flood Insurance Payment"
monthly_flood_summary
              Monthly Flood Insurance Payment
Mean                                 39.76385
Median                               39.76488
5_Percentile                         26.14220
95_Percentile                        53.43399

Maintenance

A rule of thumb is spending 1% of a home’s cost per year on maintenance, though 3% is safer for home if the home is “older than 30 years” or “located in a wet, humid, or stormy climate” or “built with lower-life materials.” For safety, we’ll assume we need to set 3% per year in a rainy-day fund. Below I estimate the implications for saving money on a monthly basis.

monthly_maitenance_samples<-(house_cost_samples*.03)/12

monthly_maitenance_summary<-calculate_summary_stats(monthly_maitenance_samples)
colnames(monthly_maitenance_summary)[colnames(monthly_maitenance_summary) == "Value"] <- "Monthly Savings for Maitenance"
monthly_maitenance_summary
              Monthly Savings for Maitenance
Mean                               1250.2215
Median                             1225.9556
5_Percentile                        884.5749
95_Percentile                      1697.3440

Utilities

  • We currently pay $80 for internet for month, so I’ll assume that for internet.

  • This website says the average payment water, gas, and electricity in Miami is $128 per month. However, we keep the house cold and pay ~$116 a month for electricity alone; assuming gas and water are about $20 a month each, it is probably safer to assume $156 per month.

  • The same website says while garbage collection is $484 per year (~$40 per month).

utilities_monthly_samples<-rnorm(100000, mean = (80+156+40), sd = 50)

HOA Fees

Average HOA fees in Miami are ~$650. I’ll assume a standard deviation of $100.

HOA fees only apply if we live in the condo. Of course, the amenities a condo provides may save us money we would spend on a gym membership, lawn maintenance, and so on. As a guess I treat 70% of the HOA fee as an added cost.

hoa_monthly_samples<-rnorm(100000, mean = (650*.7), sd = 100)

Total Ongoing Costs

The average monthly cost if we buy a house is $4,772. There is a 90% chance that it will be between $3,494 and $6,352.

house_total<- mortgage_payment_samples["monthly_payment",]+property_tax_samples+homeowners_monthly_samples+monthly_flood_samples+monthly_maitenance_samples+utilities_monthly_samples

house_summary<-calculate_summary_stats(house_total)
colnames(house_summary)[colnames(house_summary) == "Value"] <- "Monthly Ongoing Costs"
house_summary
              Monthly Ongoing Costs
Mean                       4770.715
Median                     4681.745
5_Percentile               3491.930
95_Percentile              6345.353
#plot distribution
ggplot(data.frame(x = house_total), aes(x)) +   
geom_histogram(binwidth = 100, fill = "purple", color = "black", alpha = 0.7) +   labs(title = "Monthly House Costs",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title

The average monthly cost if we buy a condo is $5,227. There is a 90% chance that it will be between $3,934 and $6,810.

condo_total<- mortgage_payment_samples["monthly_payment",]+property_tax_samples+homeowners_monthly_samples+monthly_flood_samples+monthly_maitenance_samples+utilities_monthly_samples+hoa_monthly_samples

condo_summary<-calculate_summary_stats(condo_total)
colnames(condo_summary)[colnames(condo_summary) == "Value"] <- "Monthly Ongoing Costs"
condo_summary
              Monthly Ongoing Costs
Mean                       5225.154
Median                     5139.731
5_Percentile               3932.807
95_Percentile              6809.459
#plot distribution
ggplot(data.frame(x = condo_total), aes(x)) +   
geom_histogram(binwidth = 100, fill = "blue", color = "black", alpha = 0.7) +   labs(title = "Monthly Ongoing Costs",x = "USD",y = "Number of Samples") +   scale_x_continuous(labels = scales::comma) +    
theme_minimal() +
theme(plot.title = element_text(hjust = 0.5))  # Center the title