Search code examples
pythonpython-3.xfinance

Function that calculates NPV from a list of cash flows


trying to write a function that will calculate present value of list of cash flows. I know that numpy can do this very easily but for an assignment I have to write my own function for this :/.

Here are the three cash flows in a list as well as discount rate.

cfList = [20, 50, 90]           
r = 0.05                        

Here's the function i've written so far. f = 0 because I want to start with the first cash flow (in this case 20). i = 1 because for the first flow its raised to the 1st power and the second flow (50) will be squared and so on.

def npv(cfList, r):
    f = 0
    i = 1

    pv = cfList[f] / ((1 + r) ** i)

    while i < len(cfList):
        f += 1
        i += 1
        return pv


print(npv(cfList, r))

However, this output only gives me the PV of the first cashflow, and not the sum of all three from the list. If you can help i appreciate it so much thanks !


Solution

  • You need to sum the individual cashflows within your function and return that. At the moment you are returning the value of pv of the first cashflow as you have a return statement in your for loop.

    Also, I think the way you check your while loop against i will mean that you'll miss the last payment value. Usually you don't need to instantiate counter variables yourself (see my examples below):

    def npv(cfList, r):
        f = 0
        i = 1
    
        pv = cfList[f] / ((1 + r) ** i)  # <-- this needs to be in the loop
    
        while i < len(cfList): # <-- i will break loop before last payment is calculated.
            f += 1
            i += 1
            return pv  # <-- this return here is the issue
    
    
    print(npv(cfList, r))
    

    NPV being the sum of PV of all future cashflows, that is what you need to calculate. E.g.:

    def npv(cfList, r):
    
        sum_pv = 0  # <-- variable used to sum result
    
        for i, pmt in enumerate(cfList, start=1):  # <-- use of enumerate allows you to do away with the counter variables.
            sum_pv += pmt / ((1 + r) ** i)  # <-- add pv of one of the cash flows to the sum variable
    
        return sum_pv  # <-- only return the sum after your loop has completed.
    

    Always remember that a return statement in a for-loop will break out of the loop the first time the return is encountered.

    An alternate implementation would be to yield individual PVs from a PV generator and sum the results:

    def pv_gen(cfList, r):
    
        for i, pmt in enumerate(cfList, start=1):
    
            yield pmt / ((1 + r) ** i)
    
    print(sum(pv_gen(cfList, r)))