[Numpy-discussion] add xirr to numpy financial functions?
josef.pktd@gmai...
josef.pktd@gmai...
Tue May 26 10:07:21 CDT 2009
I rewrote irr to use the iterative solver instead of polynomial roots
so that it can also handle large arrays. For 3000 values, I had to
kill the current np.irr since I didn't want to wait longer than 10
minutes
When writing the test, I found that npv is missing a "when" keyword,
for the case when the first payment is immediate, i.e. in the present,
and that broadcasting has problems:
>>> np.npv(0.05, np.array([[1,1],[1,1]]))
array([ 1.9047619 , 1.81405896])
>>> np.npv(0.05, np.array([[1,1],[1,1],[1,1]]))
Traceback (most recent call last):
File "<pyshell#82>", line 1, in <module>
np.npv(0.05, np.array([[1,1],[1,1],[1,1]]))
File "C:\Programs\Python25\Lib\site-packages\numpy\lib\financial.py",
line 449, in npv
return (values / (1+rate)**np.arange(1,len(values)+1)).sum(axis=0)
ValueError: shape mismatch: objects cannot be broadcast to a single shape
--------------------------
Here is the changed version, that only looks for one root. I added an
optional starting value as keyword argument (as in open office) but
didn't make any other changes:
def irr(values, start=None):
"""
Return the Internal Rate of Return (IRR).
This is the rate of return that gives a net present value of 0.0.
Parameters
----------
values : array_like, shape(N,)
Input cash flows per time period. At least the first value would be
negative to represent the investment in the project.
Returns
-------
out : float
Internal Rate of Return for periodic input values.
Examples
--------
>>> np.irr([-100, 39, 59, 55, 20])
0.2809484211599611
"""
p = np.poly1d(values[::-1])
pd1 = np.polyder(p)
if start is None:
r = 0.99 # starting value, find polynomial root in neighborhood
else:
r = start
# iterative solver for discount factor
for i in range(10):
r = r - p(r)/pd1(r)
## #res = np.roots(values[::-1])
## # Find the root(s) between 0 and 1
## mask = (res.imag == 0) & (res.real > 0) & (res.real <= 1)
## res = res[mask].real
## if res.size == 0:
## return np.nan
rate = 1.0/r - 1
if rate.size == 1:
rate = rate.item()
return rate
def test_irr():
v = [-150000, 15000, 25000, 35000, 45000, 60000]
assert_almost_equal(irr(v),
0.0524, 2)
nper = 300 #Number of periods
freq = 5 #frequency of payment
v = np.zeros(nper)
v[1:nper+1:freq] = 1 # periodic payment
v[0] = -4.3995180296393199
assert_almost_equal(irr(v), 0.05, 10)
nper = 3000 #Number of periods
freq = 5 #frequency of payment
v = np.zeros(nper)
v[1:nper+1:freq] = 1 # periodic payment
v[0] = -4.3995199643479603
assert_almost_equal(irr(v), 0.05, 10)
If this looks ok, I can write a proper patch.
Josef
More information about the Numpy-discussion
mailing list