--- title: "Net Present Value" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{net-present-value} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) # Numeric notation in this document # With thanks to https://stackoverflow.com/questions/18965637/set-global-thousand-separator-on-knitr/18967590#18967590 knitr::knit_hooks$set( inline = function(x) { if(!is.numeric(x)){ x } else if(x<100) { prettyNum(round(x, 3), big.mark=",") } else { prettyNum(round(x, 0), big.mark=",") } } ) ``` ## 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: - NPV with static pricing and static uptake - NPV with dynamic pricing and static uptake, with prices increasing regularly and irregularly - NPV with static pricing and dynamic uptake, with constant and variable uptake over time - NPV with both dynamic pricing and dynamic uptake First let us load the packages we will use for this vignette. ```{r setup} 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\%$. ```{r assume1} # 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. | Time | Cashflow | Discount factor | Product | |------|----------|--------------------|---------| | $t$ | $c_t$ | $v^t = (1+i)^{1-t}$ | | | 1 | `r cashflow[1]` | `r vt1[1]` | `r cashflow[1] * vt1[1]` | | 2 | `r cashflow[2]` | `r vt1[2]` | `r cashflow[2] * vt1[2]` | | 3 | `r cashflow[3]` | `r vt1[3]` | `r cashflow[3] * vt1[3]` | | 4 | `r cashflow[4]` | `r vt1[4]` | `r cashflow[4] * vt1[4]` | | 5 | `r cashflow[5]` | `r vt1[5]` | `r cashflow[5] * vt1[5]` | | Total | `r sum(cashflow)` | | `r sum(vt1 * cashflow)` | : Calculation of NPV from a simple cashflow and given discount rate ```{r demo1} # Run dynpv calculation with full output pv1 <- dynpv(payoffs=cashflow, discrate=disc) summary(pv1) ``` The present value of this cashflow is `r total(pv1)`. The same result could have been found more easily than invoking this package. ```{r simpler} sum(vt1 * cashflow) ``` ## 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. ```{r calc2a} # Set up price index pinfl <- 0.01 pindex <- (1+pinfl)^(0:4) pindex # Nominal discount rate nomdisc <- (1+disc)*1.025-1 # Calculate present value pv2 <- dynpv(payoffs=cashflow, prices=pindex, discrate=nomdisc) summary(pv2) ``` The NPV of `r total(pv2)` could still have been calculated using base R functions. ```{r calc2b} # Compare with more base calculations vt2 <- (1+nomdisc)^(-1 * (0:4)) sum(vt2 * cashflow * pindex) ``` ### 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. ```{r calc3a} # Revise the price index to be 0.5 from year 4 pindex[4:5] <- 0.5 pindex # Calculate present value pv3 <- dynpv(payoffs=cashflow, prices=pindex, discrate=nomdisc) summary(pv3) ``` With this dynamic pricing change, the NPV has reduced by `r total(pv2) - total(pv3)`, from `r total(pv2)` to `r total(pv3)`. The corresponding base R code is shown below. ```{r calc3b} # Compare with more base calculations sum(vt2 * cashflow * pindex) ``` ## 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. | 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 | `r cashflow[1]` | - | - | - | - | `r cashflow[1]` |`r vt1[1]` | `r cashflow[1] * vt1[1]` | | 2 | `r cashflow[2]` | `r cashflow[1]` | - | - | - | `r sum(cashflow[1:2])` |`r vt1[2]` | `r sum(cashflow[1:2]) * vt1[2]` | | 3 | `r cashflow[3]` | `r cashflow[2]` |`r cashflow[1]` | - | - | `r sum(cashflow[1:3])` | `r vt1[3]` | `r sum(cashflow[1:3]) * vt1[3]` | | 4 | `r cashflow[4]` | `r cashflow[3]` | `r cashflow[2]` |`r cashflow[1]` | - | `r sum(cashflow[1:4])` | `r vt1[4]` | `r sum(cashflow[1:4]) * vt1[4]` | | 5 | `r cashflow[5]` | `r cashflow[4]` | `r cashflow[3]` | `r cashflow[2]` |`r cashflow[1]` | `r sum(cashflow[1:5])` | `r vt1[5]` | `r sum(cashflow[1:5]) * vt1[5]` | | Total | `r sum(cashflow)` | | | | | | | `r sum(vt1 * cumsum(cashflow))` | : Calculation of NPV from a simple cashflow and given discount rate With `dynamicpv::dynpv()`, we just update the `uptakes` argument. ```{r uptake2} # Uptake vector is (1, 1, 1, 1, 1) uptakes1 <- rep(1, 5) # NPV calculation pv4 <- dynpv(payoffs=cashflow, uptakes=uptakes1, discrate=disc) summary(pv4) ``` There are `r sum(uptakes1)` patients with a total NPV of `r total(pv4)`, which equates to `r mean(pv4)` on average per patient. This can also be calculated in base R. ```{r verify2} sum(vt1 * cumsum(cashflow)) ``` ### 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$ \%. ```{r uptake3} # Uptake vector is (1, 2, 3, 4, 5) uptakes2 <- 1:5 # NPV calculation pv5 <- dynpv(payoffs=cashflow, uptakes=uptakes2, discrate=disc) summary(pv5) ``` There are `r sum(uptakes2)` patients with a total NPV of `r total(pv5)`, which equates to `r mean(pv5)` on average per patient. Verifying this result in base R also becomes more complicated. ```{r verify3} # 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) ``` ## 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. ```{r uptake4} # NPV calculation pv6 <- dynpv(payoffs=cashflow, uptakes=uptakes2, prices=pindex, discrate=nomdisc) # Calculation results pv6 # Total present value = sum of the pv column sum(pv6$pv) summary(pv6) ``` There are `r sum(uptakes2)` patients with a total NPV of `r total(pv6)`, which equates to `r mean(pv6)` on average per patient.