Pages

Thursday, March 29, 2012

Create a mortgage amortization table in Python

Home ownership is considered one piece of the American Dream by many. Today we'll look at another seemingly integral part of the American Dream: A home mortgage.

Like it or not, most people don't buy their houses with cash, instead having to take out a loan through a bank. A key part of that loan is the amortization schedule, which is a schedule of payments over the life of the loan, showing what portion of each payment is going towards the balance of the loan, and what portion is paying interest on the loan.

For this I created two functions: amortization_table prints out the amortization schedule, while pmt calculates the monthly payment amount.

Note that due to the nature of the beast, getting the numbers to be exactly right could be nigh unto impossible, due to rounding and such. But the idea's the important thing!

Let's put the following in mortgage.py:

# Mortgage amortization

from decimal import *

def amortization_table(principal, rate, term):
    ''' Prints the amortization table for a loan.

    Prints the amortization table for a loan given
    the principal, the interest rate (as an APR), and
    the term (in months).'''

    payment = pmt(principal, rate, term)
    begBal = principal

    # Print headers
    print 'Pmt no'.rjust(6), ' ', 'Beg. bal.'.ljust(13), ' ',
    print 'Payment'.ljust(9), ' ', 'Principal'.ljust(9), ' ',
    print 'Interest'.ljust(9), ' ', 'End. bal.'.ljust(13)
    print ''.rjust(6, '-'), ' ', ''.ljust(13, '-'), ' ',
    print ''.rjust(9, '-'), ' ', ''.ljust(9, '-'), ' ',
    print ''.rjust(9, '-'), ' ', ''.ljust(13, '-'), ' '
    # Print data
    for num in range(1, term + 1):
        
        interest = round(begBal * (rate / (12 * 100.0)), 2)
        applied = round(payment - interest, 2)
        endBal = round(begBal - applied, 2)
        
        print str(num).center(6), ' ',
        print '{0:,.2f}'.format(begBal).rjust(13), ' ',
        print '{0:,.2f}'.format(payment).rjust(9), ' ',
        print '{0:,.2f}'.format(applied).rjust(9), ' ',
        print '{0:,.2f}'.format(interest).rjust(9), ' ',
        print '{0:,.2f}'.format(endBal).rjust(13)

        begBal = endBal
    
def pmt(principal, rate, term):
    '''Calculates the payment on a loan.

    Returns the payment amount on a loan given
    the principal, the interest rate (as an APR),
    and the term (in months).'''
    
    ratePerTwelve = rate / (12 * 100.0)
    
    result = principal * (ratePerTwelve / (1 - (1 + ratePerTwelve) ** (-term)))

    # Convert to decimal and round off to two decimal
    # places.
    result = Decimal(result)
    result = round(result, 2)
    return result

What happens if we run this? To use the amortization_table function, we call it with the loan amount, the interest rate (as an APR), and the term of the loan in months. Let's try a loan for $150,000 at 4% for fifteen years (180 months):

>>> import mortgage
>>> mortgage.amortization_table(150000, 4, 180)
Pmt no   Beg. bal.       Payment     Principal   Interest    End. bal.    
------   -------------   ---------   ---------   ---------   -------------  
  1         150,000.00    1,109.53      609.53      500.00      149,390.47
  2         149,390.47    1,109.53      611.56      497.97      148,778.91
  3         148,778.91    1,109.53      613.60      495.93      148,165.31
  4         148,165.31    1,109.53      615.65      493.88      147,549.66
  5         147,549.66    1,109.53      617.70      491.83      146,931.96
...output deleted...
 175          6,580.75    1,109.53    1,087.59       21.94        5,493.16
 176          5,493.16    1,109.53    1,091.22       18.31        4,401.94
 177          4,401.94    1,109.53    1,094.86       14.67        3,307.08
 178          3,307.08    1,109.53    1,098.51       11.02        2,208.57
 179          2,208.57    1,109.53    1,102.17        7.36        1,106.40
 180          1,106.40    1,109.53    1,105.84        3.69            0.56

And if we check the handy-dandy calculator at BankRate.com, we find that our numbers are quite nearly the same!

But why aren't they the same? Well, I think it's because I'm switching back and forth between Decimal and float. I need to learn how to use Decimal exclusively, as it is more accurate...

What does this mean? We'll probably revisit this later.

2 comments:

  1. I've proper selected to build a blog, which I hold been deficient to do for a during. Acknowledges for this inform, it's really serviceable! freedom mortgage

    ReplyDelete
  2. Mortgage broker bond ensures proper performance of mortgage business without any default act of the mortgage broker or lender. Mortgage broker bonds are issued all over the different parts of the states and most of the industries analyzed the need of mortgage broker bond in the state. https://rateconnect.ca

    ReplyDelete