VB6Parse / Library / Financial / npv

VB6 Library Reference

NPV Function

Returns a Double specifying the net present value of an investment based on a series of periodic cash flows (payments and receipts) and a discount rate.

Syntax

NPV(rate, values())

Parameters

Return Value

Returns a Double specifying the net present value of the investment.

Remarks

The NPV (Net Present Value) function calculates the present value of a series of future cash flows, discounted at a specified rate. It's a fundamental tool in capital budgeting and investment analysis.

Key Characteristics:

Important Note on Initial Investment:

Unlike some implementations, VB6's NPV does NOT include an initial investment (period 0) in the values array. If you have an initial investment, subtract it from the NPV result:

netPV = NPV(rate, cashFlows()) - initialInvestment

Common Use Cases:

Typical Uses

  1. Investment Evaluation - Determine if an investment is worthwhile
  2. Project Comparison - Compare multiple investment opportunities
  3. Capital Budgeting - Decide which projects to fund
  4. Equipment Purchases - Evaluate equipment vs. leasing decisions
  5. Real Estate - Analyze property investment returns
  6. Business Acquisition - Value businesses based on projected cash flows
  7. Cost-Benefit Analysis - Compare costs and benefits over time
  8. Break-even Analysis - Find discount rate where NPV = 0 (IRR)

Basic Examples

' Example 1: Simple investment with 5-year cash flows
Dim cashFlows(1 To 5) As Double
Dim npvResult As Double
Dim initialInvestment As Double
initialInvestment = 10000
cashFlows(1) = 3000
cashFlows(2) = 3000
cashFlows(3) = 3000
cashFlows(4) = 3000
cashFlows(5) = 3000
' Calculate NPV at 10% discount rate
npvResult = NPV(0.1, cashFlows) - initialInvestment
' Result: approximately $1,372 (good investment)
' Example 2: Evaluate equipment purchase
Dim savings(1 To 3) As Double
Dim equipmentCost As Double
Dim netValue As Double
equipmentCost = 5000
savings(1) = 2000 ' Year 1 savings
savings(2) = 2500 ' Year 2 savings
savings(3) = 3000 ' Year 3 savings
netValue = NPV(0.08, savings) - equipmentCost
If netValue > 0 Then
    MsgBox "Good investment: NPV = $" & Format(netValue, "#,##0.00")
End If
' Example 3: Compare two projects
Dim project1(1 To 4) As Double
Dim project2(1 To 4) As Double
Dim npv1 As Double, npv2 As Double
' Project 1: Higher initial investment, steady returns
project1(1) = 4000: project1(2) = 4000: project1(3) = 4000: project1(4) = 4000
npv1 = NPV(0.1, project1) - 12000
' Project 2: Lower investment, increasing returns
project2(1) = 2000: project2(2) = 3000: project2(3) = 4000: project2(4) = 5000
npv2 = NPV(0.1, project2) - 10000
If npv2 > npv1 Then
    MsgBox "Project 2 has better NPV"
End If
' Example 4: Real estate investment analysis
Dim rentalIncome(1 To 10) As Double
Dim purchasePrice As Double
Dim i As Integer
purchasePrice = 200000
' Annual rental income for 10 years
For i = 1 To 10
    rentalIncome(i) = 24000 ' $2,000/month
Next i
Dim propertyNPV As Double
propertyNPV = NPV(0.08, rentalIncome) - purchasePrice
MsgBox "Property NPV: $" & Format(propertyNPV, "#,##0.00")

Common Patterns

' Pattern 1: Basic NPV calculation with initial investment
Function CalculateInvestmentNPV(initialCost As Double, _
                               cashFlows() As Double, _
                               discountRate As Double) As Double
    CalculateInvestmentNPV = NPV(discountRate, cashFlows) - initialCost
End Function
' Pattern 2: Investment decision helper
Function ShouldInvest(initialInvestment As Double, _
                     cashFlows() As Double, _
                     requiredReturn As Double) As Boolean
    Dim npvResult As Double
    npvResult = NPV(requiredReturn, cashFlows) - initialInvestment
    ShouldInvest = (npvResult > 0)
End Function
' Pattern 3: Sensitivity analysis
Sub AnalyzeNPVSensitivity(initialCost As Double, cashFlows() As Double)
    Dim rate As Double
    Dim npvResult As Double
    Debug.Print "NPV Sensitivity Analysis"
    Debug.Print String(40, "-")
    For rate = 0.05 To 0.20 Step 0.01
        npvResult = NPV(rate, cashFlows) - initialCost
        Debug.Print Format(rate * 100, "0.0") & "%: $" & Format(npvResult, "#,##0.00")
    Next rate
End Sub
' Pattern 4: Profitability Index
Function CalculateProfitabilityIndex(initialInvestment As Double, _
                                     cashFlows() As Double, _
                                     discountRate As Double) As Double
    Dim presentValue As Double
    presentValue = NPV(discountRate, cashFlows)
    If initialInvestment = 0 Then
        CalculateProfitabilityIndex = 0
    Else
        CalculateProfitabilityIndex = presentValue / initialInvestment
    End If
End Function
' Pattern 5: Compare multiple projects
Function SelectBestProject(projects As Collection, discountRate As Double) As String
    Dim project As Variant
    Dim bestNPV As Double
    Dim bestProject As String
    Dim currentNPV As Double
    bestNPV = -999999
    For Each project In projects
        currentNPV = NPV(discountRate, project.CashFlows) - project.InitialCost
        If currentNPV > bestNPV Then
            bestNPV = currentNPV
            bestProject = project.Name
        End If
    Next project
    SelectBestProject = bestProject
End Function
' Pattern 6: Break-even discount rate (approximation of IRR)
Function FindBreakEvenRate(initialInvestment As Double, _
                          cashFlows() As Double) As Double
    Dim rate As Double
    Dim npvResult As Double
    Dim increment As Double
    increment = 0.001
    For rate = 0 To 1 Step increment
        npvResult = NPV(rate, cashFlows) - initialInvestment
        If npvResult <= 0 Then
            FindBreakEvenRate = rate
            Exit Function
        End If
    Next rate
    FindBreakEvenRate = -1 ' Not found
End Function
' Pattern 7: NPV with growing cash flows
Function NPVWithGrowth(initialInvestment As Double, _
                       firstYearCashFlow As Double, _
                       growthRate As Double, _
                       years As Integer, _
                       discountRate As Double) As Double
    Dim cashFlows() As Double
    Dim i As Integer
    ReDim cashFlows(1 To years)
    For i = 1 To years
        cashFlows(i) = firstYearCashFlow * ((1 + growthRate) ^ (i - 1))
    Next i
    NPVWithGrowth = NPV(discountRate, cashFlows) - initialInvestment
End Function
' Pattern 8: Payback period with NPV
Function CalculateDiscountedPayback(initialInvestment As Double, _
                                    cashFlows() As Double, _
                                    discountRate As Double) As Double
    Dim i As Integer
    Dim cumulativeNPV As Double
    Dim periodCashFlows() As Double
    For i = LBound(cashFlows) To UBound(cashFlows)
        ReDim periodCashFlows(LBound(cashFlows) To i)
        Dim j As Integer
        For j = LBound(cashFlows) To i
            periodCashFlows(j) = cashFlows(j)
        Next j
        cumulativeNPV = NPV(discountRate, periodCashFlows) - initialInvestment
        If cumulativeNPV >= 0 Then
            CalculateDiscountedPayback = i
            Exit Function
        End If
    Next i
    CalculateDiscountedPayback = -1 ' Never pays back
End Function
' Pattern 9: NPV with terminal value
Function NPVWithTerminalValue(initialInvestment As Double, _
                              cashFlows() As Double, _
                              terminalValue As Double, _
                              discountRate As Double) As Double
    Dim i As Integer
    Dim modifiedCashFlows() As Double
    ReDim modifiedCashFlows(LBound(cashFlows) To UBound(cashFlows))
    For i = LBound(cashFlows) To UBound(cashFlows) - 1
        modifiedCashFlows(i) = cashFlows(i)
    Next i
    ' Add terminal value to final period
    modifiedCashFlows(UBound(cashFlows)) = cashFlows(UBound(cashFlows)) + terminalValue
    NPVWithTerminalValue = NPV(discountRate, modifiedCashFlows) - initialInvestment
End Function
' Pattern 10: Risk-adjusted NPV
Function RiskAdjustedNPV(initialInvestment As Double, _
                        expectedCashFlows() As Double, _
                        riskFreeRate As Double, _
                        riskPremium As Double) As Double
    Dim adjustedRate As Double
    adjustedRate = riskFreeRate + riskPremium
    RiskAdjustedNPV = NPV(adjustedRate, expectedCashFlows) - initialInvestment
End Function

Advanced Usage

Example 1: Investment Analyzer Class

' Class: InvestmentAnalyzer
' Comprehensive investment analysis with NPV and related metrics
Option Explicit
Private m_initialInvestment As Double
Private m_cashFlows() As Double
Private m_discountRate As Double
Public Sub Initialize(initialInvestment As Double, _
                     cashFlows() As Double, _
                     discountRate As Double)
    m_initialInvestment = initialInvestment
    m_cashFlows = cashFlows
    m_discountRate = discountRate
End Sub
Public Function GetNPV() As Double
    GetNPV = NPV(m_discountRate, m_cashFlows) - m_initialInvestment
End Function
Public Function GetProfitabilityIndex() As Double
    Dim pvCashFlows As Double
    pvCashFlows = NPV(m_discountRate, m_cashFlows)
    GetProfitabilityIndex = pvCashFlows / m_initialInvestment
End Function
Public Function IsAcceptable() As Boolean
    IsAcceptable = (GetNPV() > 0)
End Function
Public Function GetApproximateIRR() As Double
    Dim rate As Double
    Dim npvResult As Double
    Dim lastRate As Double
    Dim lastNPV As Double
    ' Binary search for IRR
    Dim lowRate As Double, highRate As Double
    lowRate = 0
    highRate = 1
    Do While (highRate - lowRate) > 0.0001
        rate = (lowRate + highRate) / 2
        npvResult = NPV(rate, m_cashFlows) - m_initialInvestment
        If npvResult > 0 Then
            lowRate = rate
        Else
            highRate = rate
        End If
    Loop
    GetApproximateIRR = rate
End Function
Public Function GenerateReport() As String
    Dim report As String
    Dim npvValue As Double
    Dim pi As Double
    Dim irr As Double
    npvValue = GetNPV()
    pi = GetProfitabilityIndex()
    irr = GetApproximateIRR()
    report = "Investment Analysis Report" & vbCrLf
    report = report & String(50, "=") & vbCrLf & vbCrLf
    report = report & "Initial Investment: $" & Format(m_initialInvestment, "#,##0.00") & vbCrLf
    report = report & "Discount Rate: " & Format(m_discountRate * 100, "0.00") & "%" & vbCrLf
    report = report & "Number of Periods: " & UBound(m_cashFlows) & vbCrLf & vbCrLf
    report = report & "Net Present Value: $" & Format(npvValue, "#,##0.00") & vbCrLf
    report = report & "Profitability Index: " & Format(pi, "0.00") & vbCrLf
    report = report & "Approx. IRR: " & Format(irr * 100, "0.00") & "%" & vbCrLf & vbCrLf
    If IsAcceptable() Then
        report = report & "Recommendation: ACCEPT - Positive NPV"
    Else
        report = report & "Recommendation: REJECT - Negative NPV"
    End If
    GenerateReport = report
End Function
Public Function RunSensitivityAnalysis() As String
    Dim result As String
    Dim rate As Double
    Dim npvValue As Double
    result = "NPV Sensitivity to Discount Rate" & vbCrLf
    result = result & String(40, "-") & vbCrLf
    For rate = 0.05 To 0.25 Step 0.05
        npvValue = NPV(rate, m_cashFlows) - m_initialInvestment
        result = result & Format(rate * 100, "0.0") & "%: $" & _
                 Format(npvValue, "#,##0.00") & vbCrLf
    Next rate
    RunSensitivityAnalysis = result
End Function

Example 2: Project Portfolio Manager

' Class: ProjectPortfolioManager
' Manages and ranks multiple investment projects
Option Explicit
Private Type Project
    name As String
    initialInvestment As Double
    cashFlows() As Double
    npv As Double
    pi As Double
    rank As Integer
End Type
Private m_projects As Collection
Private m_discountRate As Double
Public Sub Initialize(discountRate As Double)
    Set m_projects = New Collection
    m_discountRate = discountRate
End Sub
Public Sub AddProject(name As String, _
                     initialInvestment As Double, _
                     cashFlows() As Double)
    Dim proj As Project
    proj.name = name
    proj.initialInvestment = initialInvestment
    proj.cashFlows = cashFlows
    proj.npv = NPV(m_discountRate, cashFlows) - initialInvestment
    Dim pvCashFlows As Double
    pvCashFlows = NPV(m_discountRate, cashFlows)
    proj.pi = pvCashFlows / initialInvestment
    m_projects.Add proj, name
End Sub
Public Sub RankByNPV()
    ' Simple ranking based on NPV
    Dim projects() As Project
    Dim i As Integer, j As Integer
    ReDim projects(1 To m_projects.Count)
    For i = 1 To m_projects.Count
        projects(i) = m_projects(i)
    Next i
    ' Sort by NPV (descending)
    For i = 1 To UBound(projects) - 1
        For j = i + 1 To UBound(projects)
            If projects(j).npv > projects(i).npv Then
                Dim temp As Project
                temp = projects(i)
                projects(i) = projects(j)
                projects(j) = temp
            End If
        Next j
    Next i
    ' Assign ranks
    For i = 1 To UBound(projects)
        projects(i).rank = i
    Next i
End Sub
Public Function GetPortfolioNPV() As Double
    Dim proj As Project
    Dim totalNPV As Double
    Dim i As Integer
    totalNPV = 0
    For i = 1 To m_projects.Count
        proj = m_projects(i)
        totalNPV = totalNPV + proj.npv
    Next i
    GetPortfolioNPV = totalNPV
End Function
Public Function SelectProjectsWithBudget(budget As Double) As Collection
    Dim selectedProjects As New Collection
    Dim remainingBudget As Double
    Dim proj As Project
    Dim i As Integer
    RankByNPV
    remainingBudget = budget
    For i = 1 To m_projects.Count
        proj = m_projects(i)
        If proj.npv > 0 And proj.initialInvestment <= remainingBudget Then
            selectedProjects.Add proj
            remainingBudget = remainingBudget - proj.initialInvestment
        End If
    Next i
    Set SelectProjectsWithBudget = selectedProjects
End Function
Public Function GenerateRankingReport() As String
    Dim report As String
    Dim proj As Project
    Dim i As Integer
    RankByNPV
    report = "Project Portfolio Ranking" & vbCrLf
    report = report & String(80, "=") & vbCrLf
    report = report & "Rank  Project Name          Investment       NPV          PI" & vbCrLf
    report = report & String(80, "-") & vbCrLf
    For i = 1 To m_projects.Count
        proj = m_projects(i)
        report = report & Format(proj.rank, "0") & "     "
        report = report & Left(proj.name & String(20, " "), 20) & "  "
        report = report & Format(proj.initialInvestment, "$#,##0") & "  "
        report = report & Format(proj.npv, "$#,##0") & "  "
        report = report & Format(proj.pi, "0.00") & vbCrLf
    Next i
    report = report & vbCrLf & "Total Portfolio NPV: $" & _
             Format(GetPortfolioNPV(), "#,##0.00")
    GenerateRankingReport = report
End Function

Example 3: Real Estate Investment Analyzer

' Module: RealEstateAnalyzer
' Analyzes real estate investments using NPV
Option Explicit
Public Function AnalyzeRentalProperty(purchasePrice As Double, _
                                     annualRent As Double, _
                                     annualExpenses As Double, _
                                     holdingYears As Integer, _
                                     appreciationRate As Double, _
                                     discountRate As Double) As String
    Dim cashFlows() As Double
    Dim i As Integer
    Dim salePrice As Double
    Dim npvValue As Double
    Dim result As String
    ReDim cashFlows(1 To holdingYears)
    ' Calculate annual net cash flows
    For i = 1 To holdingYears - 1
        cashFlows(i) = annualRent - annualExpenses
    Next i
    ' Final year includes property sale
    salePrice = purchasePrice * ((1 + appreciationRate) ^ holdingYears)
    cashFlows(holdingYears) = (annualRent - annualExpenses) + salePrice
    npvValue = NPV(discountRate, cashFlows) - purchasePrice
    result = "Real Estate Investment Analysis" & vbCrLf
    result = result & String(50, "=") & vbCrLf
    result = result & "Purchase Price: $" & Format(purchasePrice, "#,##0") & vbCrLf
    result = result & "Annual Rent: $" & Format(annualRent, "#,##0") & vbCrLf
    result = result & "Annual Expenses: $" & Format(annualExpenses, "#,##0") & vbCrLf
    result = result & "Holding Period: " & holdingYears & " years" & vbCrLf
    result = result & "Appreciation Rate: " & Format(appreciationRate * 100, "0.0") & "%" & vbCrLf
    result = result & "Discount Rate: " & Format(discountRate * 100, "0.0") & "%" & vbCrLf
    result = result & "Estimated Sale Price: $" & Format(salePrice, "#,##0") & vbCrLf & vbCrLf
    result = result & "Net Present Value: $" & Format(npvValue, "#,##0.00") & vbCrLf
    If npvValue > 0 Then
        result = result & "Recommendation: Good investment opportunity"
    Else
        result = result & "Recommendation: Consider other opportunities"
    End If
    AnalyzeRentalProperty = result
End Function
Public Function CompareBuyVsLease(equipmentCost As Double, _
                                 leaseCosts() As Double, _
                                 buyingCashFlows() As Double, _
                                 discountRate As Double) As String
    Dim buyNPV As Double
    Dim leaseNPV As Double
    Dim result As String
    buyNPV = NPV(discountRate, buyingCashFlows) - equipmentCost
    leaseNPV = NPV(discountRate, leaseCosts)
    result = "Buy vs. Lease Analysis" & vbCrLf
    result = result & String(40, "-") & vbCrLf
    result = result & "Buying NPV: $" & Format(buyNPV, "#,##0.00") & vbCrLf
    result = result & "Leasing NPV: $" & Format(leaseNPV, "#,##0.00") & vbCrLf
    result = result & vbCrLf
    If buyNPV > leaseNPV Then
        result = result & "Recommendation: BUY (NPV advantage: $" & _
                 Format(buyNPV - leaseNPV, "#,##0.00") & ")"
    Else
        result = result & "Recommendation: LEASE (NPV advantage: $" & _
                 Format(leaseNPV - buyNPV, "#,##0.00") & ")"
    End If
    CompareBuyVsLease = result
End Function

Example 4: Business Valuation Tool

' Class: BusinessValuationTool
' Values businesses using discounted cash flow (DCF) method
Option Explicit
Private m_projectedCashFlows() As Double
Private m_terminalValue As Double
Private m_discountRate As Double
Public Sub ProjectCashFlows(baseCashFlow As Double, _
                           growthRate As Double, _
                           years As Integer)
    Dim i As Integer
    ReDim m_projectedCashFlows(1 To years)
    For i = 1 To years
        m_projectedCashFlows(i) = baseCashFlow * ((1 + growthRate) ^ i)
    Next i
End Sub
Public Sub CalculateTerminalValue(finalYearCashFlow As Double, _
                                 perpetualGrowthRate As Double, _
                                 discountRate As Double)
    ' Terminal value using Gordon Growth Model
    m_terminalValue = (finalYearCashFlow * (1 + perpetualGrowthRate)) / _
                      (discountRate - perpetualGrowthRate)
End Sub
Public Function GetEnterpriseValue(discountRate As Double) As Double
    Dim i As Integer
    Dim cashFlowsWithTerminal() As Double
    m_discountRate = discountRate
    ' Create array including terminal value
    ReDim cashFlowsWithTerminal(1 To UBound(m_projectedCashFlows))
    For i = 1 To UBound(m_projectedCashFlows) - 1
        cashFlowsWithTerminal(i) = m_projectedCashFlows(i)
    Next i
    ' Add terminal value to final year
    cashFlowsWithTerminal(UBound(m_projectedCashFlows)) = _
        m_projectedCashFlows(UBound(m_projectedCashFlows)) + m_terminalValue
    GetEnterpriseValue = NPV(discountRate, cashFlowsWithTerminal)
End Function
Public Function GetEquityValue(enterpriseValue As Double, _
                              debt As Double, _
                              cash As Double) As Double
    GetEquityValue = enterpriseValue - debt + cash
End Function
Public Function GenerateValuationReport(companyName As String, _
                                       debt As Double, _
                                       cash As Double) As String
    Dim report As String
    Dim ev As Double
    Dim equity As Double
    ev = GetEnterpriseValue(m_discountRate)
    equity = GetEquityValue(ev, debt, cash)
    report = "Business Valuation: " & companyName & vbCrLf
    report = report & String(60, "=") & vbCrLf & vbCrLf
    report = report & "Discounted Cash Flow Analysis" & vbCrLf
    report = report & "Discount Rate (WACC): " & Format(m_discountRate * 100, "0.00") & "%" & vbCrLf
    report = report & "Projection Period: " & UBound(m_projectedCashFlows) & " years" & vbCrLf
    report = report & vbCrLf
    report = report & "Enterprise Value: $" & Format(ev, "#,##0,000") & vbCrLf
    report = report & "Less: Debt: $" & Format(debt, "#,##0,000") & vbCrLf
    report = report & "Plus: Cash: $" & Format(cash, "#,##0,000") & vbCrLf
    report = report & String(60, "-") & vbCrLf
    report = report & "Equity Value: $" & Format(equity, "#,##0,000")
    GenerateValuationReport = report
End Function

Error Handling

On Error Resume Next
Dim npvResult As Double
npvResult = NPV(rate, cashFlows())
If Err.Number <> 0 Then
    MsgBox "Error calculating NPV: " & Err.Description & vbCrLf & _
           "Ensure cash flows array is properly dimensioned and rate is valid."
End If
On Error GoTo 0

Performance Considerations

Best Practices

  1. Remember initial investment - Subtract it from NPV result (not in array)
  2. Use appropriate discount rate - Match to risk and period
  3. Validate cash flow array - Ensure proper dimensioning
  4. Check for mixed signs - Need both positive and negative flows
  5. Consider risk - Use higher discount rate for riskier investments
  6. Document assumptions - State discount rate rationale
  7. Sensitivity analysis - Test multiple discount rates
  8. Compare to alternatives - Use NPV to rank projects
  9. Account for inflation - Use real rates or inflate cash flows
  10. Validate results - Ensure NPV makes sense given inputs
Function Purpose Key Difference
NPV Net present value Assumes end-of-period cash flows
PV Present value Single/annuity payments only
IRR Internal rate of return Finds rate where NPV = 0
MIRR Modified IRR Uses separate financing/reinvestment rates
FV Future value Calculates future amount, not present

Platform Notes

Limitations

VB6 Parser Notes

NPV is parsed as a regular function call (CallExpression). This module exists primarily for documentation purposes to provide comprehensive reference material for VB6 developers working with financial analysis, investment evaluation, capital budgeting, and discounted cash flow calculations.

← Back to Financial | View all functions