Getting different results from same calculation done different way - why?

Sorry for a long post. I’m trying to make a simple program that amortizes a loan balance with a list of payments from the user. It seems to work but I wanted to double-check the numbers using Excel, which I’m more familiar with, and I got a different result. So I created an even simpler python script with all the numbers hardcoded, and got the same result as Excel. So now I’m trying to figure out why my fancier version, which takes user input, is giving different results.

The test data is a $1000 loan on 1/1/2000, 10% interest rate, and 3 monthly payments of $100 each on the 1st of the month, beginning 2/1/2000. My intention is to calculate the interest each month, add it to the principal, then subtract the payment to get the new balance. Column 1 of the CSV file is “date” and Col. 2 is “amount”

The “fancy” version gives a final balance of $724.934. Excel and the simplified version give $722.642. I can’t figure out why.

Here’s the fancy version:

from datetime import datetime
import dateutil.parser
from decimal import Decimal #needed for financial stuff
import pandas as pd

pymtfile = 'C:/pymts.csv'
pymtdata= pd.read_csv(pymtfile)

rate = Decimal('.1')
dailyrate = round(Decimal(rate/365),6)
startbal = 1000
startdate = '1/1/2000' 
startdate = dateutil.parser.parse(startdate)

for row in pymtdata.itertuples():  
    if row.Index == 0: 
        days = 31 
        interest = Decimal(days*startbal*dailyrate)
        print(days, "of interest = $", interest)
        newbal = startbal+interest-row[2]
        print("New balance = $",newbal,"\n")
    else: 
        prevpymt = pymtdata.loc[row.Index-1]
        prevpymtdate = dateutil.parser.parse(prevpymt['date'])
        currpymtdate = dateutil.parser.parse(row[1])
        days = (currpymtdate - prevpymtdate).days
        interest = Decimal(days*startbal*dailyrate)
        print(days, "of interest = $", interest)
        newbal = newbal+interest-row[2]
        print("New balance = $",newbal,"\n")

Here’s the simplified version:

from decimal import Decimal

pymt = 100
rate = Decimal('.1')
dailyrate = round(Decimal(rate/365),6)
print(dailyrate)
startbal = 1000


#1
interest = startbal*dailyrate*31
print('interest=',interest)
newbal=startbal+interest-pymt
print('newbal=',newbal, "\n")

#2
interest = newbal*dailyrate*29
print('interest=',interest)
newbal=newbal+interest-pymt
print('newbal=',newbal, "\n")

#3
interest = newbal*dailyrate*31
print('interest=',interest)
newbal=newbal+interest-pymt
print('newbal=',newbal, "\n")

Hello,

it appears that what is causing the difference in the final balance between the fancy and the simplified versions is the interest rate calculator function Decimal from the decimal library. In the following test script, I replaced:

interest = startbal*dailyrate*31

with:

interest = Decimal(31*startbal*dailyrate)

After having done so, I too get a final balance of: $724.934.

Here is your “simplified version“ test script with the interest rate formula replaced with the one from the decimal library:

from decimal import Decimal

pymt = 100
rate = Decimal('.1')
dailyrate = round(Decimal(rate/365),6)
print(dailyrate)
startbal = 1000

#1
interest = Decimal(31*startbal*dailyrate)
print('interest=',interest)
newbal=startbal+interest-pymt
print('newbal=',newbal, "\n")

#2
interest = Decimal(29*startbal*dailyrate)
print('interest=',interest)
newbal=newbal+interest-pymt
print('newbal=',newbal, "\n")

#3
interest = Decimal(31*startbal*dailyrate)
print('interest=',interest)
newbal=newbal+interest-pymt
print('newbal=',newbal, "\n")

The difference does not come from using Decimal or not. It comes from computing the interest based on startbal at every iteration instead of using newbal in the second and following iterations.

1 Like

Thanks. Happy it was such an easy fix. Embarrassed it was such a stupid mistake.