Author: Nicholas Martin Hunt-Walker
Last Updated: February 1, 2014
The goal of this notebook is to provide a simple calculator for compound interest with regular contributions of a fixed amount over a designated amount of time. The inputs are the principal amount (can be zero or any positive number), the interest rate (fixed over the time period), the number of years, the number amount of the monthly contribution (can be zero or positive), and the frequency at which the amount is compounded (a string. See the function for more.). At the bottom there will be two plots: one showing the amount accrued over time for different interest rates, and the other showing the amount of interest being reinvested into the account each month.
# Setting up the initial packages necessary for
# this script
import numpy as np
import matplotlib.pyplot as plt
import locale
%matplotlib inline
locale.setlocale(locale.LC_ALL,'')
# This is so that any money displayed on the
# output plot is in dollars, separated by
# commas per three digits
'en_US.UTF-8'
def compoundInt(principal,rate,years,contr,compounded='monthly'):
# This is where the magic happens
# This function takes in:
# the principal amount in dollars
# the APY interest rate in x%
# the number of years of in question
# the amount contributed per compounding period
# how often interest is compounded per year; default is monthly
#
# This function then returns:
# the array for the amount of money accumulated at each compounding period
# the array for the amount of money deposited at each compounding period
if compounded == 'monthly':
N_comp = 12.
elif compounded == 'daily':
N_comp = 365.
elif compounded == 'weekly':
N_comp = 52.
elif compounded == 'quarterly':
N_comp = 4.
elif compounded == 'semi-annually':
N_comp = 2.
elif compounded == 'annually':
N_comp = 1.
rate = rate/100.
N = int(years*N_comp) # the number of compounding periods total
tot = np.zeros(N + 1) # array that will contain the total amount
# of money accrued over time from both
# deposits and interest
tot[0] = principal
deposits = np.zeros(N + 1) # array that will contain the total
# amount of money deposited over time
deposits[0] = principal
for i in range(N):
# Formula for compound interest with deposits
# Compound Interest Formula: A_comp = principal * ((1 + rate/N_comp)**(i+1 periods))
# Added Value from Contributions: A_contr = contr * ((1 + rate/N_comp)**(i+1 periods)-1.)/(rate/N_comp)
# Total: tot[i+1] = A_comp + A_contr
#
# Deposits to-date: deposits[i+1] = deposits[i] + contr
tot[i+1] = ((1+rate/N_comp)**(i+1))*tot[0] + contr*((1 + rate/N_comp)**(i+1)-1.)/(rate/N_comp)
deposits[i+1] = deposits[i] + contr
return tot,deposits
## These are going to be your input values
## Nyrs -- The number of years over which your investment grows
##
## rates -- Array of interest rates that you want to compare, in percents.
## Note: You don't need three. You can have as many as
## you want. However, three is what I plot with
##
## princ -- The principal investment in dollars
##
## contr -- Your monthly contribution, in dollars
Nyrs = 40.
rates = [10.,7.,4.] #
princ = 0.
contr = 450.
## This is where the calculation occurs. You need one set of
## these lines for each rate you want to examine
p_hi, amt = compoundInt(princ,rates[0],Nyrs,contr)
intrst_hi = p_hi[1:]-p_hi[:-1] - contr
p_avg, amt = compoundInt(princ,rates[1],Nyrs,contr)
intrst_avg = p_avg[1:]-p_avg[:-1] - contr
p_lo, amt = compoundInt(princ,rates[2],Nyrs,contr)
intrst_lo = p_lo[1:]-p_lo[:-1] - contr
## All of the plotting. If you didn't change anything above,
## just hit Control+Enter
yrs = np.linspace(0,Nyrs,int(Nyrs*12)+1)
fig = plt.figure(figsize=(8,9))
fig.subplots_adjust(hspace=0)
plt.suptitle('Principal - '+locale.currency(princ, grouping=True)+'\n Monthly Contribution - '+locale.currency(contr)+'\n Time - %i Years' % Nyrs+'\n Total Contribution - '+locale.currency(amt[-1], grouping=True))
ax = plt.subplot2grid((2,1),(0,0))
ax.fill_between(yrs,p_hi/1.0E3,p_avg/1.0E3,alpha=0.5,color='g')
ax.fill_between(yrs,p_avg/1.0E3,p_lo/1.0E3,alpha=0.5,color='r')
ax.plot(yrs,p_hi/1.0E3,color='g',linewidth=2)
ax.plot(yrs,p_lo/1.0E3,color='r',linewidth=2)
ax.plot(yrs,p_avg/1.0E3,color='k',linewidth=2)
ax.plot([0,41],[p_hi[-1]/1.0E3,p_hi[-1]/1.0E3],linestyle='--',color='g')
ax.plot([0,41],[p_lo[-1]/1.0E3,p_lo[-1]/1.0E3],linestyle='--',color='r')
ax.plot([0,41],[p_avg[-1]/1.0E3,p_avg[-1]/1.0E3],linestyle='--',color='k')
ax.text(2,p_hi[-1]/1000.-.05*(p_hi[-1]/1000.),locale.currency(p_hi[-1], grouping=True) + ' (10% Interest)')
ax.text(2,p_avg[-1]/1000.-.05*(p_hi[-1]/1000.),locale.currency(p_avg[-1], grouping=True) + ' (7% Interest)')
ax.text(2,p_lo[-1]/1000.-.05*(p_hi[-1]/1000.),locale.currency(p_lo[-1], grouping=True) + ' (4% Interest)')
ax.minorticks_on()
ax.set_xlabel('Years')
ax.set_xlim(1,Nyrs)
ax.set_ylim(0,max(p_hi/1000.)+.1*(p_hi[-1]/1000.))
ax.set_ylabel('Investment Values (x $1000)')
ax = plt.subplot2grid((2,1),(1,0))
ax.fill_between(yrs[1:],intrst_avg/1.0E3,intrst_hi/1.0E3,alpha=0.5,color='g')
ax.fill_between(yrs[1:],intrst_lo/1.0E3,intrst_avg/1.0E3,alpha=0.5,color='r')
ax.plot(yrs[1:],intrst_hi/1.0E3,c='g',linewidth=2)
ax.plot(yrs[1:],intrst_lo/1.0E3,c='r',linewidth=2)
ax.plot(yrs[1:],intrst_avg/1.0E3,c='k',linewidth=2)
ax.minorticks_on()
ax.set_xlabel('Years')
ax.set_ylabel('Interest Value (x $1000)')
ax.set_xlim(1,Nyrs)
ax.set_ylim(0,max(intrst_hi/1.0E3))
plt.show()
## This cell shows you how many years and months
## it would take for your interest to exceed
## your principal investment
mask_hi = np.where(p_hi-amt > amt)[0]
print 'Amount gained from an interest rate of %.2f%%\n\t...%s\nis more than the amount deposited after %i years and %.1f months\n\t...%s\n' % (rates[0],locale.currency(p_hi[mask_hi[0]]-amt[mask_hi[0]], grouping=True),int(yrs[mask_hi[0]]),(yrs[mask_hi[0]]-int(yrs[mask_hi[0]]))*12,locale.currency(amt[mask_hi[0]], grouping=True))
mask_avg = np.where(p_avg-amt > amt)[0]
print 'Amount gained from an interest rate of %.2f%%\n\t...%s\nis more than the amount deposited after %i years and %.1f months\n\t...%s\n' % (rates[1],locale.currency(p_avg[mask_avg[0]]-amt[mask_avg[0]], grouping=True),int(yrs[mask_avg[0]]),(yrs[mask_avg[0]]-int(yrs[mask_avg[0]]))*12,locale.currency(amt[mask_avg[0]], grouping=True))
mask_lo = np.where(p_lo-amt > amt)[0]
print 'Amount gained from an interest rate of %.2f%%\n\t...%s\nis more than the amount deposited after %i years and %.1f months\n\t...%s\n' % (rates[2],locale.currency(p_lo[mask_lo[0]]-amt[mask_lo[0]], grouping=True),int(yrs[mask_lo[0]]),(yrs[mask_lo[0]]-int(yrs[mask_lo[0]]))*12,locale.currency(amt[mask_lo[0]], grouping=True))
Amount gained from an interest rate of 10.00% ...$69,381.60 is more than the amount deposited after 12 years and 9.0 months ...$68,850.00 Amount gained from an interest rate of 7.00% ...$97,755.10 is more than the amount deposited after 18 years and 1.0 months ...$97,650.00 Amount gained from an interest rate of 4.00% ...$170,968.82 is more than the amount deposited after 31 years and 7.0 months ...$170,550.00
## All of the plotting. If you didn't change anything above,
## just hit Control+Enter
yrs = np.linspace(0,Nyrs,int(Nyrs*12)+1)
fig = plt.figure(figsize=(10,7))
fig.subplots_adjust(hspace=0)
ax = plt.subplot2grid((1,1),(0,0))
ax.fill_between(yrs,p_hi/1.0E3,p_avg/1.0E3,alpha=0.5,color='g')
ax.fill_between(yrs,p_avg/1.0E3,p_lo/1.0E3,alpha=0.5,color='r')
ax.plot(yrs,p_hi/1.0E3,color='g',linewidth=2)
ax.plot(yrs,p_lo/1.0E3,color='r',linewidth=2)
ax.plot(yrs,p_avg/1.0E3,color='k',linewidth=2)
ax.plot([0,41],[p_hi[-1]/1.0E3,p_hi[-1]/1.0E3],linestyle='--',color='g')
ax.plot([0,41],[p_lo[-1]/1.0E3,p_lo[-1]/1.0E3],linestyle='--',color='r')
ax.plot([0,41],[p_avg[-1]/1.0E3,p_avg[-1]/1.0E3],linestyle='--',color='k')
growth_hi = (p_hi[-1]-amt[-1])/amt[-1] * 100.
growth_avg = (p_avg[-1]-amt[-1])/amt[-1] * 100.
growth_lo = (p_lo[-1]-amt[-1])/amt[-1] * 100.
ax.text(2,p_hi[-1]/1000.-.05*(p_hi[-1]/1000.),locale.format("%d",growth_hi, grouping=True) + '% growth at 10% Interest')
ax.text(2,p_avg[-1]/1000.-.05*(p_hi[-1]/1000.),locale.format("%d",growth_avg, grouping=True) + '% growth at 7% Interest')
ax.text(2,p_lo[-1]/1000.-.05*(p_hi[-1]/1000.),locale.format("%d",growth_lo, grouping=True) + '% growth at 4% Interest')
ax.minorticks_on()
ax.set_xlim(1,Nyrs)
ax.set_ylim(0,max(p_hi/1000.)+.1*(p_hi[-1]/1000.))
plt.show()
print amt[-1]
print p_hi[-1]
growth_hi = (p_hi[-1]-amt[-1])/amt[-1] * 100.
print growth_hi
216000.0 2845835.81141 1217.51657936
compoundInt(100,10,50,0,compounded='monthly')[0][10]
108.65288007072382