Annuity Calculator
Annuity Calculator
Annuity Calculator
annuities
#Authors: Kate McCoy, Blake Ellerbusch, Clare Krajewski, and Lexi Hanna
import math
from graphics import*
def x(interest):
"""Calculates the present value multiplyer
Parameters:
interest: a float
Returns:
1 / (1 + interest)
Preconditions:
interest must be a number
Postconditions:
The present value multiplyer is calculated
"""
v = 1 / (1+interest)
return v
Parameters:
interest: a float
duration: an integer
Returns:
a angle duration using interest as the interest rate
Preconditions:
interest and duration must be a number
Postconditions:
a angle, the annuity present value multiplyer is calculated
"""
PV = (1-(x(interest)**duration))/interest
return PV
Parameters:
interest: a float
duration: an integer
Returns:
s angle duration using interest as the interest rate
Preconditions:
interest and duration must be a number
Postconditions:
s angle, the annuity future value multiplyer is calculated
"""
FV = (((1+interest)**duration)-1)/interest
return FV
Parameters:
interest: a float
duration: an integer
Returns:
a double dot duration using interest as the interest rate
Preconditions:
interest and duration must be a number
Postconditions:
a double dot, the annuity present value multiplyer for annuities due is
calculated
"""
d = ConvertIRtoDR(interest)
PV = (1-(x(interest)**duration))/d
return PV
Parameters:
interest: a float
duration: an integer
Returns:
s double dot duration using interest as the interest rate
Preconditions:
interest and duration must be a number
Postconditions:
s double dot, the annuity future value multiplyer for annuities due
"""
d = ConvertIRtoDR(interest)
FV= (((1+interest)**duration)-1)/d
return FV
def ConvertIRtoDR(interest):
"""Converts an interest rate to a discount rate
Parameters:
interest: a float
Returns:
the interest rate converted to a discount rate
Preconditions:
interest must be a number
Postconditions:
the interest rate is converted to a discount rate
"""
discount = (interest)/(1+interest)
return discount
def clear(win):
"""Clears the graphics window of any objects
Parameters:
win: a GraphWin object
Returns:
a blank graphics window
Preconditions:
win must be a GraphWin object
Postconditions:
the objects from the graphics window are cleared
"""
for item in win.items[:]:
item.undraw()
win.update()
class Calculator:
"""Displays screens of the calculator and gets values from the user"""
def DisplayType(self):
"""Displays the first screen of the program where the user can choose
the type of annuity"""
rec = Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.draw(self.win)
annuity.draw(self.win)
perpetuity.draw(self.win)
geometric.draw(self.win)
arithmatic.draw(self.win)
annuity_text.draw(self.win)
perpetuity_text.draw(self.win)
geometric_text.draw(self.win)
arithmatic_text.draw(self.win)
def DisplayRegValues(self):
"""Displays a screen where users can input values and what they are
trying to calculate"""
#specified for a regular annuity
rec = Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.draw(self.win)
present = Rectangle(Point(15,50),Point(250,150))
present.draw(self.win)
pBox = Entry(Point(130,135), 20)
pBox.draw(self.win)
pBox.setTextColor("black")
self.pBox = pBox #Make input boxes instance variables to use later
ptext = Text(Point(130,90),"Present Value")
ptext.draw(self.win)
PV = Rectangle(Point(10,400), Point(90,475))
PV.draw(self.win)
PVtext = Text(Point(50,435),"PV")
PVtext.draw(self.win)
FV = Rectangle(Point(90,400), Point(170,475))
FV.draw(self.win)
FVtext = Text(Point(130,435),"FV")
FVtext.draw(self.win)
N = Rectangle(Point(330,400),Point(410,475))
N.draw(self.win)
Ntext = Text(Point(370,435),"N")
Ntext.draw(self.win)
IntAmt = Rectangle(Point(410,400),Point(490,475))
IntAmt.draw(self.win)
Inttext = Text(Point(450,435),"Total\nInterest")
Inttext.draw(self.win)
def GetRegValues(self):
"""Creates a dictionary with the values the user typed and its
corresponding label"""
#specified for a regular annuity
self.values = values
def GetRegSolveFor(self):
"""Waits for user to click a solve for box, calls the get values
method, and identifies the solve for"""
#specified for a regular annuity
try:
click = self.win.getMouse()
except:
break
if 90 < click.getX() < 170 and 400 < click.getY() < 475:
self.GetRegValues()
self.SolveFor = 'FV'
break
if 170 < click.getX() < 250 and 400 < click.getY() < 475:
self.GetRegValues()
self.SolveFor = 'PMT'
break
if 250 < click.getX() < 330 and 400 < click.getY() < 475:
self.GetRegValues()
self.SolveFor = 'IRR'
break
if 330 < click.getX() < 410 and 400 < click.getY() < 475:
self.GetRegValues()
self.SolveFor = 'N'
break
if 410 < click.getX() < 490 and 400 < click.getY() < 475:
self.GetRegValues()
self.SolveFor = 'IntAmt'
break
def DisplayPerpValues(self):
"""Displays a screen where users can input values and what they are
trying to calculate"""
#specified for a perpetuity
rec=Rectangle(Point(0,0), Point(500,500))
rec.setFill("white")
rec.draw(self.win)
present=Rectangle(Point(15,50),Point(250,150))
present.draw(self.win)
pBox=Entry(Point(130,135),20)
pBox.draw(self.win)
pBox.setTextColor("black")
self.pBox=pBox
ptext=Text(Point(130,90), "Present Value")
ptext.draw(self.win)
frstpmt=Rectangle(Point(250,150),Point(485,50))
frstpmt.draw(self.win)
fpBox = Entry(Point(370,135), 20)
fpBox.draw(self.win)
fpBox.setTextColor("black")
self.fpBox=fpBox
fptext=Text(Point(370,90),"Immediate or Due")
fptext.draw(self.win)
payment=Rectangle(Point(15,150), Point(250,250))
payment.draw(self.win)
pmtBox=Entry(Point(130,235),20)
pmtBox.draw(self.win)
pmtBox.setTextColor("black")
self.pmtBox=pmtBox
paytext=Text(Point(130,190),"Payment Amount")
paytext.draw(self.win)
interest=Rectangle(Point(250,250), Point(485,150))
interest.draw(self.win)
iBox=Entry(Point(370,235),20)
iBox.draw(self.win)
iBox.setTextColor("black")
self.iBox=iBox
itext=Text(Point(370,190),"Interest Rate\n(written as decimal)")
itext.draw(self.win)
PV=Rectangle(Point(100,400), Point(200,475))
PV.draw(self.win)
PVtext=Text(Point(150,435), "PV")
PVtext.draw(self.win)
PMT=Rectangle(Point(200,400), Point(300,475))
PMT.draw(self.win)
PMTtext=Text(Point(250,435),"PMT")
PMTtext.draw(self.win)
IRR=Rectangle(Point(300,400),Point(400,475))
IRR.draw(self.win)
IRRtext=Text(Point(350,435),"IRR")
IRRtext.draw(self.win)
def GetPerpValues(self):
"""Creates a dictionary with the values the user typed and its
corresponding label"""
#specified for a perpetuity
presentvalue = self.pBox.getText()
payment = self.pmtBox.getText()
interest = self.iBox.getText()
frstpmt = self.fpBox.getText()
self.FP = frstpmt.lower()
values = {'PV':presentvalue, 'PMT':payment, 'IRR':interest}
try:
for item in values.keys():
if values[item] == '':
values[item] = values[item]
else:
value = values[item]
values[item] = float(value)
except:
raise ValueError("Values must be numbers")
self.values = values
def GetPerpSolveFor(self):
"""Waits for user to click a solve for box, calls the get values
method, and identifies the solve for"""
#specified for a perpetuity
while self.win.isOpen():
try:
click = self.win.getMouse()
except:
break
if 100 < click.getX() < 200 and 400 < click.getY() < 475:
self.GetPerpValues()
self.SolveFor = 'PV'
break
if 200 < click.getX() < 300 and 400 < click.getY() < 475:
self.GetPerpValues()
self.SolveFor = 'PMT'
break
if 300 < click.getX() < 400 and 400 < click.getY() < 475:
self.GetPerpValues()
self.SolveFor = 'IRR'
break
def DisplayGeoValues(self):
"""Displays a screen where users can input values and what they are
trying to calculate"""
#specified for geometric
rec=Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.draw(self.win)
present=Rectangle(Point(15,50), Point(250,150))
present.draw(self.win)
pBox=Entry(Point(130,135),20)
pBox.draw(self.win)
pBox.setTextColor("black")
self.pBox=pBox
ptext=Text(Point(130,90),"Present Value")
ptext.draw(self.win)
future=Rectangle(Point(250,150),Point(485,50))
future.draw(self.win)
fBox=Entry(Point(370,135),20)
fBox.draw(self.win)
fBox.setTextColor("black")
self.fBox=fBox
ftext=Text(Point(370,90),"Future Value")
ftext.draw(self.win)
payment=Rectangle(Point(15,150), Point(250,250))
payment.draw(self.win)
pmtBox=Entry(Point(130,235), 20)
pmtBox.draw(self.win)
pmtBox.setTextColor("black")
self.pmtBox=pmtBox
paytext=Text(Point(130,190), "Payment Amount")
paytext.draw(self.win)
interest=Rectangle(Point(250,250), Point(485,150))
interest.draw(self.win)
iBox=Entry(Point(370,235), 20)
iBox.draw(self.win)
iBox.setTextColor("black")
self.iBox=iBox
itext=Text(Point(370,190), "Interest Rate\n(written as decimal)")
itext.draw(self.win)
duration=Rectangle(Point(15,250), Point(250,350))
duration.draw(self.win)
dBox=Entry(Point(130,335), 20)
dBox.draw(self.win)
dBox.setTextColor("black")
self.dBox=dBox
dtext=Text(Point(130,290), "Duration")
dtext.draw(self.win)
K=Rectangle(Point(250,350), Point(485,250))
K.draw(self.win)
KBox=Entry(Point(370,335),20)
KBox.draw(self.win)
KBox.setTextColor("black")
self.KBox=KBox
Ktext=Text(Point(370,290),"Percent Increase\n(written as decimal)")
Ktext.draw(self.win)
PV=Rectangle(Point(10,400), Point(90,475))
PV.draw(self.win)
PVtext=Text(Point(50,435),"PV")
PVtext.draw(self.win)
FV=Rectangle(Point(90,400),Point(170,475))
FV.draw(self.win)
FVtext=Text(Point(130,435), "FV")
FVtext.draw(self.win)
PMT=Rectangle(Point(170,400),Point(250,475))
PMT.draw(self.win)
pmttext=Text(Point(210,435),"PMT")
pmttext.draw(self.win)
N=Rectangle(Point(250,400), Point(330,475))
N.draw(self.win)
Ntext= Text(Point(290,435),"N")
Ntext.draw(self.win)
IntAmt = Rectangle(Point(330,400),Point(410,475))
IntAmt.draw(self.win)
IntAmttext = Text(Point(370,435),"Total\nInterest")
IntAmttext.draw(self.win)
def GetGeoValues(self):
"""Creates a dictionary with the values the user typed and its
corresponding label"""
#specified for geometric
presentvalue = self.pBox.getText()
futurevalue = self.fBox.getText()
payment = self.pmtBox.getText()
interest = self.iBox.getText()
duration = self.dBox.getText()
K = self.KBox.getText()
values = {'PV':presentvalue, 'FV':futurevalue, 'PMT':payment,
'IRR':interest, 'N':duration, 'K':K}
try:
for item in values.keys():
if values[item] == '':
values[item] = values[item]
else:
value = values[item]
values[item] = float(value)
except:
raise ValueError("Values must be numbers")
self.values = values
def GetGeoSolveFor(self):
"""Waits for user to click a solve for box, calls the get values
method, and identifies the solve for"""
#specified for geometric
while self.win.isOpen():
try:
click = self.win.getMouse()
except:
break
if 10 < click.getX() < 90 and 400 < click.getY() < 475:
self.GetGeoValues()
self.SolveFor = 'PV'
break
if 90 < click.getX() < 170 and 400 < click.getY() < 475:
self.GetGeoValues()
self.SolveFor = 'FV'
break
if 170 < click.getX() < 250 and 400 < click.getY() < 475:
self.GetGeoValues()
self.SolveFor = 'PMT'
break
if 250 < click.getX() < 330 and 400 < click.getY() < 475:
self.GetGeoValues()
self.SolveFor = 'N'
break
if 330 < click.getX() < 410 and 400 < click.getY() < 475:
self.GetGeoValues()
self.SolveFor = 'IntAmt'
break
def DisplayArithValues(self):
"""Displays a screen where users can input values and what they are
trying to calculate"""
#specified for arithmetic
rec=Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.draw(self.win)
present=Rectangle(Point(15,50), Point(250,150))
present.draw(self.win)
pBox=Entry(Point(130,135),20)
pBox.draw(self.win)
pBox.setTextColor("black")
self.pBox=pBox
ptext=Text(Point(130,90),"Present Value")
ptext.draw(self.win)
future=Rectangle(Point(250,150),Point(485,50))
future.draw(self.win)
fBox=Entry(Point(370,135),20)
fBox.draw(self.win)
fBox.setTextColor("black")
self.fBox=fBox
ftext=Text(Point(370,90),"Future Value")
ftext.draw(self.win)
payment=Rectangle(Point(15,150), Point(250,250))
payment.draw(self.win)
pmtBox=Entry(Point(130,235), 20)
pmtBox.draw(self.win)
pmtBox.setTextColor("black")
self.pmtBox=pmtBox
paytext=Text(Point(130,190), "Payment Amount")
paytext.draw(self.win)
interest=Rectangle(Point(250,250), Point(485,150))
interest.draw(self.win)
iBox=Entry(Point(370,235), 20)
iBox.draw(self.win)
iBox.setTextColor("black")
self.iBox=iBox
itext=Text(Point(370,190), "Interest Rate\n(written as decimal)")
itext.draw(self.win)
duration=Rectangle(Point(15,250), Point(250,350))
duration.draw(self.win)
dBox=Entry(Point(130,335), 20)
dBox.draw(self.win)
dBox.setTextColor("black")
self.dBox=dBox
dtext=Text(Point(130,290), "Duration")
dtext.draw(self.win)
Q=Rectangle(Point(250,350), Point(485,250))
Q.draw(self.win)
QBox=Entry(Point(370,335),20)
QBox.draw(self.win)
QBox.setTextColor("black")
self.QBox=QBox
Qtext=Text(Point(370,290),"Payment Change")
Qtext.draw(self.win)
PV=Rectangle(Point(10,400), Point(90,475))
PV.draw(self.win)
PVtext=Text(Point(50,435),"PV")
PVtext.draw(self.win)
FV=Rectangle(Point(90,400),Point(170,475))
FV.draw(self.win)
FVtext=Text(Point(130,435), "FV")
FVtext.draw(self.win)
PMT=Rectangle(Point(170,400),Point(250,475))
PMT.draw(self.win)
pmttext=Text(Point(210,435),"PMT")
pmttext.draw(self.win)
Increase=Rectangle(Point(250,400), Point(330,475))
Increase.draw(self.win)
Increasetext= Text(Point(290,435),"Payment\nChange")
Increasetext.draw(self.win)
IntAmt=Rectangle(Point(330,400), Point(410,475))
IntAmt.draw(self.win)
IntAmttext= Text(Point(370,435),"Total\nInterest")
IntAmttext.draw(self.win)
def GetArithValues(self):
"""Creates a dictionary with the values the user typed and its
corresponding label"""
#specified for arithmetic
presentvalue = self.pBox.getText()
futurevalue = self.fBox.getText()
payment = self.pmtBox.getText()
duration = self.dBox.getText()
interest = self.iBox.getText()
Q = self.QBox.getText()
values = {'PV':presentvalue, 'FV':futurevalue, 'PMT':payment,
'IRR':interest, 'N':duration, 'Q':Q}
try:
for item in values.keys():
if values[item] == '':
values[item] = values[item]
else:
value = values[item]
values[item] = float(value)
except:
raise ValueError("Values must be numbers")
self.values = values
def GetArithSolveFor(self):
"""Waits for user to click a solve for box, calls the get values
method, and identifies the solve for"""
#specified for arithmetic
while self.win.isOpen():
try:
click = self.win.getMouse()
except:
break
if 10 < click.getX() < 90 and 400 < click.getY() < 475:
self.GetArithValues()
self.SolveFor = 'PV'
break
if 90 < click.getX() < 170 and 400 < click.getY() < 475:
self.GetArithValues()
self.SolveFor = 'FV'
break
if 170 < click.getX() < 250 and 400 < click.getY() < 475:
self.GetArithValues()
self.SolveFor = 'PMT'
break
if 250 < click.getX() < 330 and 400 < click.getY() < 475:
self.GetArithValues()
self.SolveFor = 'Q'
break
if 330 < click.getX() < 410 and 400 < click.getY() < 475:
self.GetArithValues()
self.SolveFor = 'IntAmt'
break
clear(self.win)
rec = Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.draw(self.win)
answer = str(answer)
final = Text(Point(250,200), "The " + solvefor + " of your investment
is " + answer)
final.draw(self.win)
click = Text(Point(250, 300), "Click to see your investment grow.")
click.draw(self.win)
x = point.getX()
y = point.getY()
head = Polygon(point, Point(x+10, y+20), Point(x-10, y+20))
head.setFill("black")
head.draw(self.win)
arrow = Rectangle(Point(x-3,y+30), Point(x+2, y+20))
arrow.setFill("black")
arrow.draw(self.win)
rec = Rectangle(Point(0,0),Point(500,500))
rec.setFill("white")
rec.setOutline("white")
rec.draw(self.win)
line = Line(Point(15, 250), Point(485, 250))
line.draw(self.win)
#create an empty list for the loop and calculate present value
pvalues = []
PV = annuity.CalcPV()
for i in range(N+1): #creates list of all present values at each
increment of time
presentvalue = PV * ((1+annuity.IRR)**i)
pvalues.append(presentvalue)
for i in pvalues:
#identify postion in list
pos = pvalues.index(i)
try:
click3 = self.win.getMouse()
except:
break
#creates arrow
self.arrow(Point(15 + (space*pos), 300))
rec = Rectangle(Point((space*pos) - (space -5) , 300),
Point((space*pos)- (space-25), 330))
rec.draw(self.win) #cover up previous arrow with white
box
rec.setFill("white")
rec.setOutline("white")
def DisplayEnd(self):
"""Displays a prompt to click to exit and closes the window when the
user clicks"""
class Annuity:
"""Calculates and returns values of a regular annuity"""
self.PV = presentvalue
self.FV = futurevalue
self.N = duration
self.PMT = payment
self.IRR = interestrate
self.FP = firstpayment
def CalcN(self):
"""Returns the duration of the annuity"""
try:
if self.N != '': #if n has already been entered, return n
n = self.N
elif self.FV == '': #if there is no future value value, use the
present value to calculate
v = x(self.IRR)
n = (math.log(1 - ((self.PV*self.IRR)/self.PMT))) /
(math.log(v))
else:
n = (math.log(((self.FV * self.IRR)/self.PMT) + 1)) /
(math.log(1 + math.IRR))
return n
except:
raise UnboundLocalError("payment, interest, and present value or
future value is needed to calculate N")
def CalcPV(self):
"""Returns the present value of the annuity"""
try:
if self.PV != '':
PV = self.PV
elif self.FV != '':
PV = self.FV * (x(self.IRR) ** self.N)
else:
if self.FP == 'immediate':
PV = self.PMT * a_angle(self.IRR, self.N)
if self.FP == 'due':
PV = self.PMT * a_doubledot(self.IRR, self.N)
return PV
except:
raise UnboundLocalError("future value or payment, interest,
duration, and the nature of the first payment are needed to calculate PV")
def CalcFV(self):
"""Returns the future value of the annuity"""
try:
if self.FV != '':
FV = self.FV
elif self.PV != '':
FV = self.PV * ((1 + self.IRR)**self.N)
else:
if self.FP == 'immediate':
FV = self.PMT * s_angle(self.IRR, self.N)
if self.FP == 'due':
FV = self.PMT * s_doubledot(self.IRR, self.N)
return FV
except:
raise UnboundLocalError("present value or payment, interest,
duration, and the nature of the first payment are needed to calculate FV")
def CalcPMT(self):
"""Returns the payment amount of the annuity"""
try:
if self.PMT != '':
PMT = self.PMT
elif self.FV == '':
if self.FP == 'immediate':
PMT = self.PV / a_angle(self.IRR, self.N)
elif self.FP == 'due':
PMT = self.PV / a_doubledot(self.IRR, self.N)
else:
if self.FP == 'immediate':
PMT = self.FV / s_angle(self.IRR, self.N)
elif self.FP == 'due':
PMT = self.FV / s_doubledot(self.IRR, self.N)
return PMT
except:
raise UnboundLocalError("present value or future value, interest,
duration, and the nature of the first payment are needed to calculate PV")
def CalcIRR(self):
"""Returns the interest rate of the annuity"""
try:
if self.IRR != '':
i = self.IRR
else:
PV = self.CalcPV()
PMT = self.CalcPMT()
a = PV / PMT
IRR = (2*(self.N - a)) / (a * (self.N + 1))
return IRR
except:
raise UnboundLocalError("present value or future value, duration,
and the nature of the first payment are needed to calculate IRR")
def CalcTotalInterest(self):
"""Returns the total interest the investor would recieve at the end of
the annuity"""
try:
PV = self.CalcPV()
PMT = self.CalcPMT()
N = self.CalcN()
totalinterest = (PMT * N) - PV
return totalinterest
except:
raise UnboundLocalError("more values are needed to calculate Total
Interest")
class Perpetuity:
"""Calculates and returns values of a perpetuity"""
self.PV = presentvalue
self.PMT = payment
self.IRR = interestrate
self.FP = firstpayment
def CalcN(self):
"""Returns an empty string to indicate an infinite duration"""
return ''
def CalcPV(self):
"""Returns the present value of the perpetuity"""
try:
if self.PV != '':
PV = self.PV
else:
if self.FP == 'immediate':
PV = self.PMT / self.IRR
elif self.FP == 'due':
d = ConvertIRtoDR(self.IRR)
PV = self.PMT / d
return PV
except:
raise UnboundLocalError("payment, interest, and the nature of the
first payment are needed to calculate PV")
def CalcPMT(self):
"""Returns the payment amount of the perpetuity"""
try:
if self.PMT != '':
PMT = self.PMT
else:
if self.FP == 'immediate':
PMT = self.PV * self.IRR
if self.FP == 'due':
d = ConvertIRtoDR(self.IRR)
PMT = self.PV * d
return PMT
except:
raise UnboundLocalError("present value, interest, and the nature of
the first payment are needed to calculate PMT")
def CalcIRR(self):
"""Returns the interest rate of the perpetuity"""
try:
if self.IRR != '':
IRR = self.IRR
else:
if self.FP == 'immediate':
IRR = self.PMT / self.PV
if self.FP == 'due':
d = self.PMT / self.PV
IRR = d / (1-d)
return IRR
except:
raise UnboundLocalError("present value, payment, and the nature of
the first payment are needed to calculate IRR")
class Geometric:
"""Calculates and returns values of a geometric annuity"""
self.PV = presentvalue
self.FV = futurevalue
self.PMT = payment
self.K = k
self.N = duration
self.IRR = interestrate
def CalcN(self):
"""Returns the duration of the geometric annuity"""
try:
if self.N != '':
n = self.N
else:
PV = self.CalcPV()
n = (math.log(1-((PV*(self.IRR-self.K)) / self.PMT))) /
(math.log((1 + self.K) / (1 + self.IRR)))
return n
except:
raise UnboundLocalError("present value or future value, duration,
payment, interest, and percent increase are needed to calculate N")
def CalcPV(self):
"""Returns the present value of the geometric annuity"""
try:
if self.PV != '':
PV = self.PV
elif self.FV != '':
PV = self.FV * (x(self.IRR) ** self.N)
else:
PV = self.PMT * ((1-(((1+self.K)/(1+self.IRR))**self.N)) /
(self.IRR - self.K))
return PV
except:
raise UnboundLocalError("payment and percent increase or future
value, interest, and duration are needed to calculate PV")
def CalcFV(self):
"""Returns the future value of the geometric annuity"""
try:
if self.FV != '':
FV = self.FV
elif self.PV != '':
FV = self.PV * ((1+self.IRR)**self.N)
else:
PV = self.CalcPV()
FV = PV * ((1+self.IRR)**self.N)
return FV
except:
raise UnboundLocalError("payment and percent increase or present
value, interest, and duration are needed to calculate FV")
def CalcPMT(self):
"""Returns the initial payment amount of the geometric annuity"""
try:
if self.PMT != '':
PMT = self.PMT
elif self.PV == '':
PV = self.CalcPV()
PMT = PV / ((1-(((1+self.K)/(1+self.IRR))**self.N)) / (self.IRR
- self.K))
return PMT
except:
raise UnboundLocalError("present value or future value, interest,
percent increase, and duration are needed to calculate PMT")
def CalcTotalInterest(self):
"""Returns the total interest the investor would recieve at the end of
the annuity"""
try:
total = 0
PMT = self.CalcPMT()
N = self.CalcN()
for i in range(self.N):
total = total + (PMT*((1+self.K)**i))
PV = self.CalcPV()
totalinterest = total - PV
return totalinterest
except:
raise UnboundLocalError("more values are needed to calculate Total
Interest")
class Arithmetic:
"""Calculates and returns values of a arithmetic annuity"""
self.PV = presentvalue
self.FV = futurevalue
self.PMT = payment
self.Q = Q
self.N = duration
self.IRR = interestrate
def CalcN(self):
"""Returns the duration of the arithmetic annuity"""
try:
return self.N
except:
raise UnboundLocalError("duration cannot be calculated")
def CalcPV(self):
"""Returns the present value of the arithmetic annuity"""
try:
if self.PV != '':
PV = self.PV
elif self.FV != '':
PV = self.FV * (x(self.IRR)**self.N)
else:
PV = (self.PMT * a_angle(self.IRR, self.N)) + (self.Q *
((a_angle(self.IRR, self.N) - (self.N * (x(self.IRR)**self.N)))/self.IRR))
return PV
except:
raise UnboundLocalError("payment and payment change or future
value, interest, and duration are needed to calculate PV")
def CalcFV(self):
"""Returns the future value of the arithmetic annuity"""
try:
if self.FV != '':
FV = self.FV
elif self.PV != '':
FV = self.PV * ((1+self.IRR)**self.N)
else:
FV = (self.PMT * s_angle(self.IRR, self.N)) + (self.Q
*((s_angle(self.IRR, self.N) - self.N) / self.IRR))
return FV
except:
raise UnboundLocalError("payment and payment change or present
value, interest, and duration are needed to calculate FV")
def CalcPMT(self):
"""Returns the initial payment amount of the arithmetic annuity"""
try:
if self.PMT != '':
PMT = self.PMT
elif PV == '':
PMT = (self.FV - (self.Q *((s_angle(self.IRR, self.N) - self.N)
/ self.IRR))) / s_angle(self.IRR, self.N)
elif FV == '':
PMT = (self.PV - (self.Q * ((a_angle(self.IRR, self.N) -
(self.N * (x(self.IRR)**self.N)))/self.IRR))) / a_angle(self.IRR,self.N)
return PMT
except:
raise UnboundLocalError("present value or future value, payment
change, interest, and duration are needed to calculate PMT")
def CalcQ(self):
"""Returns the change in payment amount of the arithmetic annuity"""
try:
if self.Q != '':
Q = self.Q
elif PV == '':
Q = (self.FV - (self.PMT * s_angle(self.IRR, self.N))) /
((s_angle(self.IRR, self.N) - self.N) / self.IRR)
else:
Q = (self.PV - (self.PMT * a_angle(self.IRR, self.N))) /
((a_angle(self.IRR, self.N) - (self.N * (x(self.IRR)**self.N)))/self.IRR)
return FV
except:
raise UnboundLocalError("present value or future value, payment,
interest, and duration are needed to calculate Payment Change")
def CalcTotalInterest(self):
"""Returns the total interest the investor would recieve at the end of
the annuity"""
try:
total = 0
PMT = self.CalcPMT()
N = self.CalcN()
Q = self.CalcQ()
for i in range(self.N):
total = total + PMT + (i*Q)
PV = self.CalcPV()
totalinterest = total - PV
return totalinterest
except:
raise UnboundLocalError("more values are needed to calculate Total
Interest")
def main():
#Create window, identify calculator class, and display the first screen
win = GraphWin("Annuities",500,500)
calculator = Calculator(win)
calculator.DisplayType()
try:
click = calculator.win.getMouse()
except:
break
#Displays the right values and gets the right solve for based on what
was clicked
#indexes the values dictionary to use as the parameters for the
corresponding class
if 15 < click.getX() < 240 and 200 < click.getY() < 300:
Type = 'Annuity'
calculator.DisplayRegValues()
calculator.GetRegSolveFor()
values = calculator.values
annuity = Annuity(values['PV'], values['FV'], values['N'],
values['PMT'], values['IRR'], calculator.FP)
if 260 < click.getX() < 485 and 200 < click.getY() < 300:
Type = 'Perpetuity'
calculator.DisplayPerpValues()
calculator.GetPerpSolveFor()
values = calculator.values
annuity = Perpetuity(values['PV'], values['PMT'], values['IRR'],
calculator.FP)
if 15 < click.getX() < 240 and 330 < click.getY() < 480:
Type = 'Geometric'
calculator.DisplayGeoValues()
calculator.GetGeoSolveFor()
values = calculator.values
annuity = Geometric(values['PV'], values['FV'], values['PMT'],
values['K'], values['N'], values['IRR'])
if 260 < click.getX() < 485 and 330 < click.getY() < 480:
Type = 'Arithmetic'
calculator.DisplayArithValues()
calculator.GetArithSolveFor()
values = calculator.values
annuity = Arithmetic(values['PV'], values['FV'], values['PMT'],
values['Q'], values['N'], values['IRR'])
main()