# Import necessary packages here
# ==========================================================================================
# ==========================================================================================
# File: mortgage.py
# Date: September 14, 2023
# Author: Jonathan A. Webb
# Purpose: This file contains functions and classes that can be used to estimate
# purchasing power when buying a home
# ==========================================================================================
# ==========================================================================================
# Insert Code here
[docs]
class Mortgage:
"""
:param value: The total value of the property to be purchased
:param payment: The total down-payment for the property
:param interest: The annual interest rate for the loan, defaulted to the
2023 value of 7.145%
:param months: The duration of the loan in units of months. Defaulted to 360
:param tax: The annual tax rate for the property, defaulted to 1.16%
:param ins_rate: The annual insurance rate for the property, defaulted
to 0.42%.
:param pmi_rate: The annual rate for private mortgage insurance, defaulted
to 1.0%
This class will determine the monthly payments to be made on a purchased property
over an entire Amoratized mortgage time line. This class does not account for
HOA fees. This class has the following public attributes.
:ivar value: The value of the property.
:ivar payment: The down payment on the property.
:ivar interest: The interests rate for the loan.
:ivar months: The number of months over which the loan is distributed.
:ivar tax: The rate the property is taxed at.
:ivar ins_rate: The insurance rate for the property.
:ivar pmi_rate: The Private Mortgage Inusrance. Only applicable when the down
payment is less than 20% of the home value.
:ivar loan_amount: The value of the loan, value - payment.
:ivar monthly_taxes: The tax value paid per month.
:ivar monthly_insurance: The insurance paid monthly.
:ivar monthly_total: The total amount paid on the property per month.
Examples
--------
Example showing how to instantiate a class and how to access and print attributes.
.. code-block:: python
from mortgage_calc.mortgage import Mortgage
# Instantiate class with custom mortage period and interest rate
value = 500000.0 # Propertry value
payment = 300000.0 # down payment on property
rate = 4.5
months = 150.0
property = Mortgage(value, payments, interest=rate, months=months)
# Print all attributes
print(property)
# Print specifc attribute
print(property.monthly_total)
.. code-block:: bash
Down Payment: $400000.00
Loan Amount: $200000.00
Primary Mortgage: $63986.77
Taxes: $580.00
Insurance: $210.00
Total Monthly Payment: $64776.77
64776.77
"""
def __init__(
self,
value: float,
payment: float,
interest: float = 7.145,
months: float = 360,
tax: float = 1.16,
ins_rate: float = 0.42,
pmi_rate: float = 1.0,
):
self.value = value
self.payment = payment
self.interest = interest
self.months = months
self.tax = tax
self.ins_rate = ins_rate
self.pmi_rate = pmi_rate
self.loan_amount = value - payment
self.mortgage_payment = self._amoratized_payments()
self.monthly_taxes = value * (tax / 100.0) / 12.0
self.monthly_insurance = value * (ins_rate / 100.0) / 12.0
self.monthly_total = self._monthly_total()
# ------------------------------------------------------------------------------------------
[docs]
def total_interest(self) -> float:
"""
Calculate the total amount of interest paid over the amortized period.
Example
-------
.. code-block:: python
from mortgage_calc.mortgage import Mortgage
home = Mortgage(600000.0, 400000.0, interest=3.15, tax=0.45)
interest = home.total_interest()
print(f"Total Interest: {interest:.2f}")
.. code-block:: bash
>> Total Interest: 109410.55
"""
total_interest_paid = 0
remaining_loan = self.loan_amount
for month in range(int(self.months)):
monthly_interest_payment = remaining_loan * (self.interest / 100.0) / 12.0
total_interest_paid += monthly_interest_payment
remaining_loan -= self.mortgage_payment - monthly_interest_payment
return total_interest_paid
# ------------------------------------------------------------------------------------------
[docs]
def total_pmi(self) -> float:
"""
Calculate the total amount paid in Private Mortgage Insurance (PMI).
Assumes PMI is paid until 20% equity is achieved.
Example
-------
.. code-block:: python
from mortgage_calc.mortgage import Mortgage
home = Mortgage(600000.0, 100000.0, interest=3.15, tax=0.45)
pmi = home.total_pmi()
print("Total PMI paid: {pmi:.2f}")
.. code-block:: bash
>> Total PMI paid: 10203.35
"""
total_pmi_paid = 0
percent_down = self.payment / self.value
remaining_loan = self.loan_amount
for month in range(int(self.months)):
if percent_down < 0.20:
monthly_pmi_payment = remaining_loan * (self.pmi_rate / 100.0) / 12.0
total_pmi_paid += monthly_pmi_payment
# Check if 20% equity has been achieved, and stop PMI payments
if (self.value - remaining_loan) / self.value >= 0.20:
break
monthly_interest_payment = remaining_loan * (self.interest / 100.0) / 12.0
remaining_loan -= self.mortgage_payment - monthly_interest_payment
return total_pmi_paid
# ==========================================================================================
# PRIVE-LIKE METHODS
def _amoratized_payments(self) -> None:
"""
This method will determine the monthly mortgage payment based on the loan
value, the total valu of the property, and the interest rage
"""
# Convert annual interest rate to monthly rate
monthly_interest_rate = (self.interest / 100.0) / 12.0
# Calcuate the monthly mortgage payment using the formula
monthly_payment = (self.loan_amount * monthly_interest_rate) / (
1.0 - (1.0 + monthly_interest_rate) ** -self.months
)
return monthly_payment
# ------------------------------------------------------------------------------------------
def __str__(self) -> str:
print_value = f"Property Value: ${self.value}\n"
print_value += f"Down Payment: ${self.payment:.2f}\n"
print_value += f"Loan Amount: ${self.loan_amount:.2f}\n"
print_value += f"Primary Mortgage: ${self.mortgage_payment:.2f}\n"
print_value += f"Taxes: ${self.monthly_taxes:.2f}\n"
print_value += f"Insurance: ${self.monthly_insurance:.2f}\n"
percent_down = self.payment / self.value
pmi = self.loan_amount * (self.pmi_rate / 100.0) / 12.0
if percent_down < 0.20:
total_value = (
self.mortgage_payment + self.monthly_taxes + self.monthly_insurance + pmi
)
print_value += f"PMI: {pmi}"
else:
total_value = (
self.mortgage_payment + self.monthly_taxes + self.monthly_insurance
)
print_value += f"Total Monthly Payment: ${total_value:.2f}"
return print_value
# ------------------------------------------------------------------------------------------
def _monthly_total(self) -> float:
percent_down = self.payment / self.value
pmi = self.loan_amount * (self.pmi_rate / 100.0) / 12.0
if percent_down < 0.20:
total_value = (
self.mortgage_payment + self.monthly_taxes + self.monthly_insurance + pmi
)
else:
total_value = (
self.mortgage_payment + self.monthly_taxes + self.monthly_insurance
)
return total_value
# ==========================================================================================
# ==========================================================================================
[docs]
def affordable_home_value(
monthly_total: float,
down_payment: float,
interest: float = 7.145,
months: float = 360,
tax: float = 1.16,
ins_rate: float = 0.42,
) -> float:
"""
Calculate the total value of a home that can be afforded based on a given
monthly payment and down payment.
:param monthly_total: The total monthly payment, including tax and insurance but
excluding PMI.
:param down_payment: The down payment for the home.
:param interest: The annual interest rate for the loan (defaulted to 7.145%).
:param months: The duration of the loan in months (defaulted to 360).
:param tax: The annual tax rate for the property (defaulted to 1.16%).
:param ins_rate: The annual insurance rate for the property
(defaulted to 0.42%).
:return: The total value of the home that can be afforded.
Example
-------
.. code-block:: python
from mortgage_calc.Mortgage import affordable_home_value)
val = affordable_home_value(2815.21, 300000.0, months=360,
interest=7.145, tax=1.16)
print(f"Home Value: {val:.2f}")
.. code-block:: bash
>> 600000.00
"""
tolerance = 1e-4
# Set an initial guess for the affordable home value
affordable_home_value = down_payment + (monthly_total * months)
# Create an instance of the Mortgage class to access the monthly_total attribute
while True:
home = Mortgage(
affordable_home_value, down_payment, interest, months, tax, ins_rate
)
calculated_monthly_total = home.monthly_total
if abs(calculated_monthly_total - monthly_total) < tolerance:
break
# Adjust the affordable home value based on the difference in monthly totals
affordable_home_value += (monthly_total - calculated_monthly_total) * (
months / 12.0
)
return affordable_home_value
# ==========================================================================================
# ==========================================================================================
# eof