The precise rate of IRR( Internal Rate of Return ) is found using my program IRR-Versus-NPV, where I used the linear interpolation . However, companies decide to take or reject a project by comparing the IRR value to the minimum required return. If the IRR is greater than the cost of capital the project should go ahead, otherwise the project should be rejected. The NPV (Net Present Value) could also be computed using my program, where projects are accepted or rejected on the basis of the NPV value, if the NPV is greater than zero the project is accepted , otherwise rejected, a positive NPV demonstrate the project is attractive, thus, it will increase the shareholders’ wealth by this amount. NPV and IRR are both superior Project appraisal techniques, yet the NPV method is a better technique, since it shows an exact amount of increase in shareholders’ wealth, and yet the IRR requires a use of a computer program. My program IRR-Versus-NPV will be of a value to ACCA’s students and also to both undergraduate and postgraduate students of Corporate Finance, Accounting, and Business studies.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 | #On the name of ALLAH
#Author : Fouad Teniou
#Date : 07/03/09
#version :2.6.1
""" New in python 2.6 namedtuple function is used in my program IRR-Versus-NPV
with a PresentValue as a typename, and discount rates r_1, r_2 and
number of periods until payments n as fieldnames (PresentValue('r_1','r_2','n'))
IRR-Versus-NPV program provide an NPV and IRR (linear interpolation)
calculations by entering the outflows/inflows values for a project
with 2 different rates r_1 and r_2, and only an NPV if r_2 is equal to zero
The program also returns any value or a series of values from the Present Value
Annuity Tables
"""
import itertools
import operator
import collections
import math as m
class MinusSignError(ArithmeticError):
""" user attempt an operation on negative number"""
pass
class PresentValue(collections.namedtuple('PresentValue', 'r_1,r_2,n')):
"""PresentValue a subclass of namedtuple Python class
with two rates values (r_1,r_2) and a period number n """
#set __slots__ to an empty tuple keep memory requirements low
__slots__ = ()
@property
def DF(self):
"""Compute the discount factor of two values"""
if self.r_1<0 or self.r_2 < 0 or self.n<0:
raise MinusSignError,\
"\n<Rates values and period number should be positive "
try:
discount_factor_1 = "%2.3f" % m.pow((1+self.r_1),-self.n)
discount_factor_2 = "%2.3f" % m.pow((1+self.r_2),-self.n)
return (discount_factor_1,discount_factor_2)
#DF raises Negative number error
except MinusSignError,exception:
print exception
@property
def AF(self):
"""Compute the annuity factor of two values"""
if self.r_1<0 or self.r_2 < 0 or self.n<0:
raise MinusSignError,\
"\n<Rates values and period number should be positive"
try:
annuity_factor_1 = "%2.3f" %((1-((m.pow((1+self.r_1),-self.n))))/self.r_1)
annuity_factor_2 = "%2.3f" %((1-((m.pow((1+self.r_2),-self.n))))/self.r_2)
return (annuity_factor_1,annuity_factor_2)
#AF raises Zero division number error
except ZeroDivisionError:
print "\n<Please choose a rate value greater than zero"
#AF raises Negative number error
except MinusSignError,exception:
print exception
def npvTable(self,*args):
"""Compute the NPV and IRR values of a project with two different rates"""
try:
#You need at least one rate to compute an NPV
assert self.r_1 !=0,"The first rate should not be equal to zero "
res_1 = []
res_2 = []
item_1 =[]
item_2 =[]
count_1 = -1
for arg in args:
count_1 +=1
#outflows/inflows starting at year 0
pv_set = PresentValue(r_1=self.r_1,r_2=self.r_2,n = count_1)
res_1.append(pv_set.DF[0]) # Trigger the Discount factor at rate r_1 and append the res_1
res_2.append(pv_set.DF[1]) # Trigger the Discount factor at rate r_2 and append the res_2
print "\n years \tCash flows \t DF at %s\t PV" %(str(int(self.r_1*100))+'%')
count_2 = -1
for (x_1,y) in (itertools.izip(res_1,args)): #for loop return PV set item_1
item_1.append((float(x_1)*y))
count_2 +=1
print "\n %s\t%s\t\t %s\t\t%s" %(count_2,y,x_1,int(float(x_1)*y))
npv_1 =(reduce(operator.add,item_1)) #Compute the npv_1 total
print '\n\t\t\t\t NPV = %s\n' % int(npv_1)
if self.r_2 == 0: #user attempt only one NPV calculation
print "<No NPV calculation %s=%s" % pv_set._asdict().items()[1]
else:
print "\n years \tCash flows \t DF at %s\t PV" %(str(int(self.r_2*100))+'%')
count_3 = -1
for (x_2,y) in (itertools.izip(res_2,args)): #for loop return PV set item_2
item_2.append((float(x_2)*y))
count_3 +=1
print "\n %s\t%s\t\t %s\t\t%s" %(count_3,y,x_2,int(float(x_2)*y))
npv_2 = (reduce(operator.add,item_2)) #Compute the npv_2 total
print '\n\t\t\t\t NPV = %s\n ' % int(npv_2)
#The IRR computation will depend of the rates and npvs (higher and lower values)
if self.r_1 > self.r_2:
print "<The IRR = %2.1f" % ((self.r_2+(npv_2/(npv_2-npv_1))*(self.r_1-self.r_2))*100)+' %\n'
else:
print "<The IRR = %2.1f" % ((self.r_1+(npv_1/(npv_1-npv_2))*(self.r_2-self.r_1))*100)+' %\n'
print "<The project will be recommended on finanacial grounds, while "
print "ignoring risk, if the IRR is greater than the target rate of "
print "return, otherwise the project will be rejected.\n"
#npvTable raises Negative number error
except MinusSignError,exception:
print exception
if __name__ == "__main__":
p = PresentValue('r_1','r_2','n')
p = p._replace(r_1=0.27,r_2 = 0.13)# n is equal to the numbers of outflows/inflows
p.npvTable(-70000,48000,24000,22000,13000,33000,15000,17000)
s = p._replace(r_1=0.07,r_2 =0.05) #You can set r_2 to zero to get only an NPV but not r_1 since you need at least one rate for the NPV
print " years\t\tDF at%2.0f%s\tAF at%2.0f%s\t DF at%2.0f%s\t AF at%2.0f%s \n" %\
(s.r_1*100,'%',s.r_1*100,'%',s.r_2*100,'%',s.r_2*100,'%')
for i in range(1,11): # you can do it individualy by setting r_1,r_2 and n (eg: PresentValue(r_1 = 0.17,r_2 = 0.07,n=7)
s = p._replace(r_1=0.07,r_2 =0.05,n=i)
print " %s\t\t%s\t\t %s\t\t %s\t\t %s" % \
(i,s.DF[0],s.AF[0],s.DF[1],s.AF[1])
# Another method to display the npv,for the same outflows/inflows values
# using different sets of rates and (n = to the number of outflows/inflows )
# It will save you time to write the same inflows/outflows every time you
# alter the rates
# below is just an example and you can extend your set of values as you wish.
a = [0.07,0.02,'n']
b = [0.04,0.05,'n']
c = [0.04,0.07,'n']
for item in a,b,c:
p = p._make(item)
p.npvTable(-70000,48000,24000,22000,13000,37000)
#Another way to retrieve Annuity factors and Discount factors
#individually or in sets of (r_1,r_2)
g = [0.04,0.07,17]
p = p._make(g)
print p.DF
print p.AF
print p.DF[0]
print p.DF[1]
print p.AF[0]
print p.AF[1]
#########################################################################################
# c:\Python26>python "C:Fouad Teniou\Documents\IRRvNPV.py"
# years Cash flows DF at 27% PV
# 0 -70000 1.000 -70000
# 1 28000 0.787 22036
# 2 24000 0.620 14880
# 3 22500 0.488 10980
# 4 13000 0.384 4992
# 5 33000 0.303 9999
# 6 15000 0.238 3570
# 7 17000 0.188 3196
# NPV = -347
# years Cash flows DF at 13% PV
# 0 -70000 1.000 -70000
# 1 28000 0.885 24780
# 2 24000 0.783 18792
# 3 22500 0.693 15592
# 4 13000 0.613 7969
# 5 33000 0.543 17919
# 6 15000 0.480 7200
# 7 17000 0.425 7225
# NPV = 29477
#<The IRR = 26.8 %
#<The project will be recommended on finanacial grounds, while
#ignoring risk, if the IRR is greater than the target rate of
#return, otherwise the project will be rejected.
# years DF at 7% AF at 7% DF at 5% AF at 5%
# 1 0.935 0.935 0.952 0.952
# 2 0.873 1.808 0.907 1.859
# 3 0.816 2.624 0.864 2.723
# 4 0.763 3.387 0.823 3.546
# 5 0.713 4.100 0.784 4.329
# 6 0.666 4.767 0.746 5.076
# 7 0.623 5.389 0.711 5.786
# 8 0.582 5.971 0.677 6.463
# 9 0.544 6.515 0.645 7.108
# 10 0.508 7.024 0.614 7.722
#c:\Python26>
###########################################################################################
|
I made available today 14/03/09 new methods to display the NPV and IRR without having to rewrite the inflows/outflows every time you alter the rates. However, you can extend or reduce your number of sets as you wish. And I also provided another method to retrieve individual and sets of annuity and discount factor values.
You may be interested in my recipe ( http://code.activestate.com/recipes/576686/ ) which IMHO is simpler, and easier to reuse and understand than the above.
No thanks, I will stick to my program , because there are more interesting functions, and I am not interested in the Payback method, since it is not a very popular method due to its disadvantages, yet my display of information is the one mostly used in Financial and accounting books including the display of Annuity and Discount factors tables. I also used the advanced tools in python 2.6.1, which is only released recently. And I hope you will make a progress and try this new version. However, I know how hard it could be for people with a little knowledge in programming as yourself and as you stated in your previous comment, and I understand that there are no books yet available for this new version 2.6 released only in December 2008, but I will strongly advise you to take a step further,
PS.
I used a factory function called namedtuple( ) Python new version 2.6, from the collections module
Given your stated intention to create a program that is of value to "students of Corporate Finance, Accounting, and Business studies", one has to question your decision to use features only available in the most recently released version of python 2.6.1 (and above) when version 2.5.4 is probably most widespreadly available in current manifestations of OS X, Linux, and Windows -- especially when the use of said features apparently does not contribute to the worthy task of writing simpler and more readable code. (-:
You should know that in this life people need to progress, especially students, and time is very important, thus, ignoring tools, which were available more than three months is called ignorance, yet programmers already posted programs in this site using the new version 2.6.1 tools, and suggesting new functions for the next version 2.7. I understand how hard the new tools available in 2.6 version, but again I do have to remind you that I do write my programs for a no programmers,undergraduate, postgraduates and ACCA’s, students in Finance, Accounting and Mathematics fields and Financial Management Professionals already holding posts within firms in this field, and however, my program is running on Windows and DOS operating systems.
I would like to suggest for you to be creative and try to invent programs of your own, since it will be more helpful for others and it will free yourself to think, the fact that I was confused and chocked to see a program, which did have nearly the same title as mine and similarities in parts of the code in less than a week time, after I launched my program IRR_Versus_NPV. which is a copyright as every other program I wrote and already posted in this site…
PS.
Good luck in your next thinking ( invention!!!).
(-: You cannot imagine how amused I am by your assertion that I have somehow lifted or copied anything from your application.
If you really believe this, then by all means prove it. Please point to a single line in your program which has any semblance of similarity to mine.
From my perspective, the only thing we share are the terms "IRR" and "NPV" in our respective titles, and I am quite positive that you don't own that copyright.