# [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,

>>> 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)
##    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
```