Skip to main content
3 of 3
added 254 characters in body; edited title

User defined XIRR function: exception handling

This is my first attempt at Python. I started with some code from https://github.com/peliot/XIRR-and-XNPV (which aims to mimic the Excel function XIRR) and tried to 'improve' on it (and the Excel version). But I would like to know if in these few lines I already made beginner's mistakes. I'm particularly interested to learn whether there is a more elegant way to handle the exceptions (an 'improvement' of mine), because this looks a bit clunky. (This is not the only change compare to the original, so the other bits may be not completely correct either.)

Note that the function newton itself may also give rise to an immediate exception.

import datetime
from scipy import optimize

def xnpv(rate, cashflows):
    t0 = min(cashflows, key = lambda t: t[0])[0]
    return sum([cf/(1+rate)**((t-t0).days/365.0) for (t,cf) in cashflows])

def xirr(cashflows,guess=0.1):
    try:
        outc = optimize.newton(lambda r: xnpv(r, cashflows), guess, 
                               maxiter=100)
        if outc.imag == 0:
            return outc
        else:
            raise
    except (RuntimeError, OverflowError):
        try:
            outc = optimize.newton(lambda r: xnpv(r, cashflows), -guess, 
                                   maxiter=100)
            if outc.imag == 0:
                return outc
            else:
                raise
        except (RuntimeError, OverflowError):
            return float("NaN")
        
#cftest = [(datetime.date(2001, 12, 5), -2000), (datetime.date(2007, 12, 5), -10), (datetime.date(2017, 12, 5), 20)]
cftest = [(datetime.date(2001, 12, 5), -2000), (datetime.date(2000, 12, 5), -1000), (datetime.date(2017, 12, 5), 2000)]
#cftest = [(datetime.date(2001, 12, 5), -2000), (datetime.date(2007, 12, 5), -1000), (datetime.date(2017, 12, 5), 20)]
print(cftest)
print(xirr(cftest))