Net Present Value

Introduction

This vignette describes how to use the dynamicpv package to derive (Net) Present Values (NPVs) that account for dynamic (or static) pricing, and dynamic (or static) uptake. We consider:

First let us load the packages we will use for this vignette.

library(dynamicpv)

NPV with static pricing and static uptake

The NPV of a cashflow \(c_t\) in \(t\) years time, assuming prices constant in real terms and an annual discount rate of \(i_{real}\) is calculated as follows:

\[NPV = \frac{c_t}{(1+i_{real})^{t}}\]

It is overkill rather to use dynamicpv to calculate the NPV of a cashflow that is constant in real terms, since there are simpler routes to doing this. Nevertheless, let us start there, since it helps understand functionality. We use a simple cashflow and \(i=3\%\).

# A simple cashflow
cashflow <- c(110, 120, 130, 140, 150)

# (Real) discount rate of 3\% per timestep (year)
disc <- 0.03
vt1 <- (1 + disc)^(-1 * (0:4))

The calculation can be presented in a table as follows.

Calculation of NPV from a simple cashflow and given discount rate
Time Cashflow Discount factor Product
\(t\) \(c_t\) \(v^t = (1+i)^{1-t}\)
1 110 1 110
2 120 0.971 117
3 130 0.943 123
4 140 0.915 128
5 150 0.888 133
Total 650 610
# Run dynpv calculation with full output
pv1 <- dynpv(payoffs=cashflow, discrate=disc)

summary(pv1)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  1 
#>      Total present value:           610.4352 
#>      Mean present value:            610.4352

The present value of this cashflow is 610. The same result could have been found more easily than invoking this package.

sum(vt1 * cashflow)
#> [1] 610.4352

NPV with dynamic pricing and static uptake

Cashflows may not in general be expected to be constant in real terms. Accordingly it can be preferable to explicitly estimate the cashflow in nominal terms, \(c'_t = c_t \cdot R_t\), and discount with a nominal discount rate that includes expected inflation.

\[ 1+i_{nom} = (1+i_{real})(1+r_g) \] \[NPV = \frac{c'_t}{(1+i_{nom})^t} = \frac{c_t \cdot R_t}{(1+i_{nom})^t} \]

Prices that increase regularly

In this example, let us assume that prices of the resource underlying the cashflow increases at 1 % per year, but that general price inflation is 2.5 % per year. The real discount rate is unchanged at 3 % per year, so the nominal discount rate is therefore approximately 5.5 % per year.

First, we derive a price index to handle the changing price of the resource underlying the cashflow. Then we derive the nominal discount rate, incorporating the general rate of price inflation in the economy. We then combine these inputs with dynpv() to calculate the NPV.

# Set up price index
pinfl <- 0.01
pindex <- (1+pinfl)^(0:4)
pindex
#> [1] 1.000000 1.010000 1.020100 1.030301 1.040604

# Nominal discount rate
nomdisc <- (1+disc)*1.025-1

# Calculate present value
pv2 <- dynpv(payoffs=cashflow, prices=pindex, discrate=nomdisc)

summary(pv2)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  1 
#>      Total present value:           591.9954 
#>      Mean present value:            591.9954

The NPV of 592 could still have been calculated using base R functions.

# Compare with more base calculations
vt2 <- (1+nomdisc)^(-1 * (0:4))
sum(vt2 * cashflow * pindex)
#> [1] 591.9954

Prices that increase irregularly

Where dynamicpv is most relevant is when the price index is more irregular, more dynamic. For example, one might anticipate a sudden future change in a price of a certain resource (e.g. drug price reduction on loss of exclusivity). This can be accommodated in the price index. In this simple example, let us assume that the underlying price of the resource reduces to half its original value from the fourth year.

# Revise the price index to be 0.5 from year 4
pindex[4:5] <- 0.5
pindex
#> [1] 1.0000 1.0100 1.0201 0.5000 0.5000

# Calculate present value
pv3 <- dynpv(payoffs=cashflow, prices=pindex, discrate=nomdisc)

summary(pv3)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  1 
#>      Total present value:           463.6326 
#>      Mean present value:            463.6326

With this dynamic pricing change, the NPV has reduced by 128, from 592 to 464. The corresponding base R code is shown below.

# Compare with more base calculations
sum(vt2 * cashflow * pindex)
#> [1] 463.6326

NPV with static pricing and dynamic uptake

Uptake is constant over time

Suppose we have one new patient each year, and we wish to calculate the total NPV in a time horizon of 5 years. Now we have a payoff triangle as follows.

Calculation of NPV from a simple cashflow and given discount rate
Time Cashflow 1 Cashflow 2 Cashflow 3 Cashflow 4 Cashflow 5 Cashflow Sum Discount factor Product
\(t\) \(c_t\) \(c_{t-1}\) \(c_{t-2}\) \(c_{t-3}\) \(c_{t-4}\) \(v^t = (1+i)^{1-t}\)
1 110 - - - - 110 1 110
2 120 110 - - - 230 0.971 223
3 130 120 110 - - 360 0.943 339
4 140 130 120 110 - 500 0.915 458
5 150 140 130 120 110 650 0.888 578
Total 650 1,708

With dynamicpv::dynpv(), we just update the uptakes argument.

# Uptake vector is (1, 1, 1, 1, 1)
uptakes1 <- rep(1, 5)

# NPV calculation
pv4 <- dynpv(payoffs=cashflow, uptakes=uptakes1, discrate=disc)

summary(pv4)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  5 
#>      Total present value:           1707.723 
#>      Mean present value:            341.5446

There are 5 patients with a total NPV of 1,708, which equates to 342 on average per patient. This can also be calculated in base R.

sum(vt1 * cumsum(cashflow))
#> [1] 1707.723

Uptake varies over time

In general, uptake will not be constant in time. Due to factors such as varying epidemiology (prevalence and incidence), prior treatment pathways (patient testing, patient diagnostics, prior treatment usage), as well as the specific uptake of the treatment of interest (patient share), uptake will also be highly variable over time. In this setting, the total and mean NPVs must reflect weightings applicable to each cashflow.

For example, suppose the number of patients receiving treatment increases by one each year. The weighting given to cashflow 1 would then be \(1/(1+2+3+4+5)=6.67\) %.

# Uptake vector is (1, 2, 3, 4, 5)
uptakes2 <- 1:5

# NPV calculation
pv5 <- dynpv(payoffs=cashflow, uptakes=uptakes2, discrate=disc)

summary(pv5)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  15 
#>      Total present value:           3841.785 
#>      Mean present value:            256.119

There are 15 patients with a total NPV of 3,842, which equates to 256 on average per patient. Verifying this result in base R also becomes more complicated.

# Verifying total NPV is now more complicated
checkpv <- rep(0, 5)
for (i in 1:5) {
  checkpv[i] <- sum(cashflow[1:i] * uptakes2[i:1] * vt1[i])
}
sum(checkpv)
#> [1] 3841.785

NPV with dynamic pricing and dynamic uptake

The package becomes most powerful when considering both dynamic uptake and dynamic pricing. A simple call to dynamicpv::dynpv() replaces what would be rather more complicated with base functions, even in this toy example.

# NPV calculation
pv6 <- dynpv(payoffs=cashflow, uptakes=uptakes2, prices=pindex, discrate=nomdisc)

# Calculation results
pv6
#> # A tibble: 15 × 9
#>        j     k     l     t    uj    pk     R     v    pv
#>    <int> <int> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl>
#>  1     1     1     0     1     1   110  1    1     110  
#>  2     1     2     0     2     1   120  1.01 0.947 115. 
#>  3     1     3     0     3     1   130  1.02 0.897 119. 
#>  4     1     4     0     4     1   140  0.5  0.850  59.5
#>  5     1     5     0     5     1   150  0.5  0.805  60.4
#>  6     2     1     0     2     2   110  1.01 0.947 210. 
#>  7     2     2     0     3     2   120  1.02 0.897 220. 
#>  8     2     3     0     4     2   130  0.5  0.850 110. 
#>  9     2     4     0     5     2   140  0.5  0.805 113. 
#> 10     3     1     0     3     3   110  1.02 0.897 302. 
#> 11     3     2     0     4     3   120  0.5  0.850 153. 
#> 12     3     3     0     5     3   130  0.5  0.805 157. 
#> 13     4     1     0     4     4   110  0.5  0.850 187. 
#> 14     4     2     0     5     4   120  0.5  0.805 193. 
#> 15     5     1     0     5     5   110  0.5  0.805 221.

# Total present value = sum of the pv column
sum(pv6$pv)
#> [1] 2330.349

summary(pv6)
#> Summary of Dynamic Pricing and Uptake
#>      Number of cohorts:             5 
#>      Number of times:               1 
#>      Total uptake:                  15 
#>      Total present value:           2330.349 
#>      Mean present value:            155.3566

There are 15 patients with a total NPV of 2,330, which equates to 155 on average per patient.