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.