GSatterwhite
GSatterwhite

Reputation: 301

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 !

Upvotes: 0

Views: 6469

Answers (3)

SuperShoot
SuperShoot

Reputation: 10871

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

Upvotes: 2

mackdelany
mackdelany

Reputation: 198

If you're iterating across the list using the while loop, then you should have the action taking line of code within the while loop.

It also looks like your loop will be cutting early as i = 2 = len(cflist) on the second iteration (don't forget that python uses 0 based indexing) and because the return call is within the while loop.

This should work:

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

    pv = 0

    while f <= len(cfList):
        pv += (cfList[f] / ((1 + r) ** i))
        f += 1
        i += 1
    return pv

Upvotes: 1

AChampion
AChampion

Reputation: 30268

Returning the NPV of a list of cash flows would look like:

def npv(cfList, r):
    return sum(f / ((1 + r) ** i) for i, f in enumerate(cfList, 1))

In []:
cfList = [20, 50, 90]
r = 0.05
npv(cfList, r)

Out[]:
142.14447683835436

Upvotes: 1

Related Questions