An Easy Amortization Schedule Function

Corrected 1/17/22 – lesson learned about not importing code in visual mode – sorry if it inconvenienced anyone.

Any loan amount (mortgage, car loan, etc.) where a lender gives you a valuable lump sum now for a series of payments at a fixed rate of interest is called a present value annuity.

To produce an amortization table for the payout on this type of cash flow all we need is any three out of four pieces of information:

the amount loaned (present value),
the periodic interest rate, and
the periodic payment amount, or
the number of periods

…and we can calculate whatever else we need. if we fix the payment amount, the number of periods are mathematically determined; if we fix the number of periods, the payment amount is mathematically dictated. You must fix one, but you can not fix both.  With any three we can produce that chipped-in-stone schedule that shows the pounds of flesh to be stripped away and the time it will take to satisfy the debt. If we want to assign dates to those payments, that can add a charming little accessory but it isn’t necessary in practice. If the payment is made at the first of the period (“in advance”) instead of, as is usual, being made at the end of the period (“in arrears”) a different formula is required – or rather an adjustment to the in arrears formula.

Let’s ignore all the side options and concentrate on producing the easy, 99%-of-the-time table we know we usually want to create. We are going to assume we have monthly payments on our loan at a fixed APR. So we know and will require (1) the loan amount, (2) the annual interest percentage rate, and (3) the monthly payment amount.  In this case, it is the number of payment that will be mathematically determined. The assumption is that the compounding period is the same as the payment period. If not, you would have to pre-calculate the effective rate of interest and use that instead of the actual “posted” annual interest rate.  We also assume regular, even, sequential periods.  Again, this conforms with the real world 99.9% of the time.

With those we will produce a table showing (1) the period number, (2) the $ interest paid for that period, (3) the principal paid for that period and (4) the balance due after the payment for that period, until it is zero.

We will use these variables as we plow through our machinations:
loan      – the starting present value or amount of the loan
apr        – the annual percentage rate as an fp,  that is. .035 not 3.5%
payment – the monthly cash out to reduce the loan, including both principal and interest
rper       – the interest percentage rate per period
period    – the sequential number of the period
intamt    – the amount of interest accumulated in a period
paidamt – the amount of principal paid off in a period
balance – the principal remaining at the end of a period

To be honest, we don’t really need to use all these variables, but they are used here just in order to make the process as easy to follow as possible. This table display is made simple and accurate using the new f-string formatting found in Python 3.6.

The odd numbers chosen below were taken from an actual amortization schedule produced by a large financial institution and the results do not vary more than a penny in any given month. Here we go:

# Simple Amortization Table
# corrected 1/17/22

def simple_amort_tbl(loan, apr, payment):
    # initialize values
    rper = apr/12
    period = 0
    principal = loan
    # print header
    la = "Loan Amount: $ "
    ap = "APR: "
    pa = "Payment: $"
    print(f"{la: >15s}{principal: >11,.2f}")
    print(f"{ap: >15s}{apr: >11.4f}   *simple monthly compounding")
    print(f"{pa: >15s}{payment: >11.2f}")
    print()
    c1 = "Period #"
    c2 = "Interest $"
    c3 = "Principal $"
    c4 = "New Balance $"
    spacer = " "
    print(f"{c1: <11s}{spacer}{pa: <15s}{spacer}{c2: <13s}{spacer}{c3: <15s}{spacer}{c4: <20s}")
    # print payment info by period
    while principal > 0:
        period += 1
        intamt = rper * principal
        paidamt = payment - intamt
        principal = principal - paidamt
        print (f"{period: ^11}{spacer}{payment: <15.2f}{spacer}{intamt: <13.2f}{spacer}{paidamt: <15,.2f}{spacer}{principal: <20,.2f}")

        if principal + (principal * rper) <= payment:
            period +=1
            intamt = principal * rper
            paidamt = principal
            payment = principal + intamt
            principal = principal - paidamt            
            print (f"{period: ^11}{spacer}{payment: <15.2f}{spacer}{intamt: <13.2f}{spacer}{paidamt: <15,.2f}{spacer}{principal: <20,.2f}")
    print("principal is: ", str(principal))

#test
l = 67661.54
a = .035
p = 673.78
simple_amort_tbl(l, a, p)

Later on this web site you will find this routine at the heart of a small GUI application. Here the emphasis is on the math and the display format. There the emphasis is on the tkinter presentation. This is the link to the tkinter GUI version:

tkinter GUI amortization version