views:

194

answers:

3

I am using the NPV() function in VB.NET to get NPV for a set of cash flows.

However, the result of NPV() is not consistent with my results performing the calculation manually (nor the Investopedia NPV calc... which matches my manual results)

My correct manual results and the NPV() results are close, within 5%.. but not the same...

Manually, using the NPV formula: NPV = C0 + C1/(1+r)^1 + C2/(1+r)^2 + C3/(1+r)^3 + .... + Cn/(1+r)^n

The manual result is stored in RunningTotal With rate r = 0.04 and period n = 10

Here is my relevant code:

EDIT: Do I have OBOB somewhere?

    YearCashOutFlow = CDbl(TxtAnnualCashOut.Text)
    YearCashInFlow = CDbl(TxtTotalCostSave.Text)

    YearCount = 1

    PAmount = -1 * (CDbl(TxtPartsCost.Text) + CDbl(TxtInstallCost.Text))
    RunningTotal = PAmount
    YearNPValue = PAmount
    AnnualRateIncrease = CDbl(TxtUtilRateInc.Text)

    While AnnualRateIncrease > 1
        AnnualRateIncrease = AnnualRateIncrease / 100
    End While
    AnnualRateIncrease = 1 + AnnualRateIncrease

    ' ZERO YEAR ENTRIES
    ListBoxNPV.Items.Add(Format(PAmount, "currency"))
    ListBoxCostSave.Items.Add("$0.00")
    ListBoxIRR.Items.Add("-100")
    ListBoxNPVCum.Items.Add(Format(PAmount, "currency"))
    CashFlows(0) = PAmount
    ''''

    Do While YearCount <= CInt(TxtLifeOfProject.Text)
        ReDim Preserve CashFlows(YearCount)

        CashFlows(YearCount) = Math.Round(YearCashInFlow - YearCashOutFlow, 2)
        If CashFlows(YearCount) > 0 Then OnePos = True


        YearNPValue = CashFlows(YearCount) / (1 + DiscountRate) ^ YearCount
        RunningTotal = RunningTotal + YearNPValue

        ListBoxNPVCum.Items.Add(Format(Math.Round(RunningTotal, 2), "currency"))
        ListBoxCostSave.Items.Add(Format(YearCashInFlow, "currency"))

        If OnePos Then
            ListBoxIRR.Items.Add((IRR(CashFlows, 0.1)).ToString)
            ListBoxNPV.Items.Add(Format(NPV(DiscountRate, CashFlows), "currency"))
        Else
            ListBoxIRR.Items.Add("-100")
            ListBoxNPV.Items.Add(Format(RunningTotal, "currency"))
        End If

        YearCount = YearCount + 1
        YearCashInFlow = AnnualRateIncrease * YearCashInFlow
    Loop

EDIT: Using the following values: Discount Rate = 4% Life of Project = 10 years Cash Flow 0 = -78110.00 Cash Flow 1 = 28963.23 Cash Flow 2 = 30701.06 Cash Flow 3 = 32543.12 Cash Flow 4 = 34495.71 Cash Flow 5 = 36565.45 Cash Flow 6 = 38759.38 Cash Flow 7 = 41084.94 Cash Flow 8 = 43550.03 Cash Flow 9 = 46163.04 Cash Flow 10 = 48932.82

Using the calculator at http://www.investopedia.com/calculator/NetPresentValue.aspx And following the manual "textbook" formula I arrive at the same result:

Net Present Value: $225,761.70

I cannot seem to get NPV() to replicate this result... it spits out $217,078.59

I iterate it manually using the example same value... so they must be using a different function than I am...

The MSDN page example clearly states that the initial expense should be included in the cash flows list.

+1  A: 

Normally you wouldn't include the first cashflow in the Visual Basic NPV() function (or at least we don't in the leasing world). You would discount all but the first cash flow, then add that first cash flow amount onto your Net Present Value. Here's an example of what I've done before in a calculation engine (minus error checking to simplify the example):

Dim leaseRentalsDiscounted As Double = 0.0

Dim rebatedCashFlows As IEnumerable(Of LeasePayment) = GetLeaseRentalsPaymentStream()

Dim firstFlow As LeasePayment = rebatedCashFlows(0)

Dim doubleStream As Double() = PaymentToDoubleArray(rebatedCashFlows.Skip(1))

If doubleStream.Length > 0 Then
    Dim rate As Decimal = New Decimal(Me.Lease.DiscountRate / 100.0 / 12.0)
    leaseRentalsDiscounted = NPV(rate, doubleStream)
End If

leaseRentalsDiscounted += firstFlow.Amount

Return leaseRentalsDiscounted

That could account for your 5% -- I know I've run into an issue like this before. To me, in the manual NPV formula you posted, C0 doesn't need to be in the stream that is discounted, so that's why I don't include it in the NPV() function.

Cory Larson
But the function documentation stipulates that at least one must be negative.In my manual example, I am using the initial cash outflow as C0If I leave that out of cashflows() then I will not have the required negative member of the array....
Matthew PK
It's not a requirement, but it's usually true. It all depends on what you're trying to accomplish. For the numbers I'm trying to calculate, we don't need a negative number. The first cashflow in the example I posted will either be 0 or a positive value depending on the accrual method of the lease. Sorry I can't help more :\
Cory Larson
I just tried it my way in Excel and I got the answer you were looking for. For the example in your edit: `=NPV(0.04, 28963.23, 30701.06, 32543.12, 34495.71, 36565.45, 38759.38, 41084.94, 43550.03, 46163.04, 48932.82) + -78110` = `$225,761.70`. Perhaps that's why you marked this as the answer?
Cory Larson
+1  A: 

The MSDN page notes that if your cash outflow begins at the beginning of the first period (instead of the end) the first value must be added to the NPV value and not included in the cash flows array.

Your manual calculation shows that your cash outflow (C0) occurs at time zero (present value), which indicates you should follow the MSDN page's suggestion.

Jeff Meatball Yang
The example on the MSDN page clearly shows the first payment (negative cash flow) being included at the zero-position in the array:Dim values(4) As Double' Business start-up costs.values(0) = -70000' Positive cash flows reflecting income for four successive years.values(1) = 22000values(2) = 25000values(3) = 28000values(4) = 31000
Matthew PK
Hm, all I can say is that from your sample data, the VB's NPV is simply your calculated NPV discounted one more period (225761.7 / 1.04 = 217078.59). This would correspond to the note on MSDN: `If your first cash flow occurs at the beginning of the first period, the first value must be added to the value returned by NPV and must not be included in the cash flow values of ValueArray.`
Jeff Meatball Yang
A: 

Cory Larson is right, in part... but the MSDN documentation seems in error to me.

The problem is that the NPV() function is discounting the very first (n=0) element of the array when it should not; it is beginning at n=1

Even though the MSDN documentation specifics that the first element of the array should be the initial expense this is not the case with their function.

In the NPV() function, the first element of the array (as Cory Larson implied) should be the first real cash flow. Then, after the function returns a result, the result should have the initial expense subtracted.

This is because the NPV() function begins with n=1 using the NPV formula: NPV = C0 + C1/(1+r)^1 + C2/(1+r)^2 + C3/(1+r)^3 + .... + Cn/(1+r)^n

In the manual formula, Cn/(1+r)^n, for n=0 you use your initial expense... then the denominator is 1 (because n=0)

In my opinion, the MSDN example at http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.financial.npv.aspx should be amended to the following:

Exclude the initial -70000 value from the array, shift all element down one in index, and decrease the array size by 1. Then add the initial expense (-70000) to the variable NetPVal to arrive at the actual result.

Somebody should like MS know about their OBOB :D (But it's actually a feature, right?)

EDIT: And the section which says " The array must contain at least one negative value (a payment) and one positive value (a receipt)." In not accurate. As Cory Larson pointed out: a negative value is not required in the array (and, in fact, should be left out!)

Matthew PK
Perhaps I just didn't explain it fully. I proved that it works in a comment on my answer above. Thanks for backing me up (and sticking with me)!
Cory Larson