In this section, the reproducible R code will be used to simple DCF calculation with sample data which will result in the display of NPV, IRR, PBP, and DPBP
Setup cf dataframe
cf_df <- data.frame(
Project1 = c(-1000, 1250, 10, 10, 20, 20),
Project2 = c(-1000, -10, 0, 10, 20, 2000)
)
Calculate DCF and CF
dcf <- function(x, r, t0=FALSE){
# calculates discounted cash flows (DCF) given cash flow and discount rate
#
# x - cash flows vector
# r - vector or discount rates, in decimals. Single values will be recycled
# t0 - cash flow starts in year 0, default is FALSE, i.e. discount rate in first period is zero.
if(length(r)==1){
r <- rep(r, length(x))
if(t0==TRUE){r[1]<-0}
}
x/cumprod(1+r)
}
npv <- function(x, r, t0=FALSE){
# calculates net present value (NPV) given cash flow and discount rate
#
# x - cash flows vector
# r - discount rate, in decimals
# t0 - cash flow starts in year 0, default is FALSE
sum(dcf(x, r, t0))
}
pbp <- function(x, ...){
# calculates payback period (PBP)
#
# x - cash flows vector
# ... - ignored
i <- match(1, sign(cumsum(x)))
i-2+(-cumsum(x)[i-1]/x[i])
}
dpbp <- function(x, r, t0=FALSE){
# calculates discounted payback period (DPBP) given cash flow and discount rate
#
# x - cash flows vector
# r - discount rate, in decimals
# t0 - cash flow starts in year 0, default is FALSE
pbp(dcf(x, r, t0))
}
irr <- function(x, t0=FALSE, ...){
# calculates internal rate of return (IRR) given cash flow
#
# x - cash flows vector
# t0 - cash flow starts in year 0, default is FALSE
tryCatch(uniroot(f=function(i){sum(dcf(x, i, t0))},
interval=c(0,1))$root,
error=function(e) return(NA)
)
}
Display the results of the calculation
# Combine these functions with the power of dplyr and
# you will have a toolbox capable of competing with the CFO's favorite spreadsheet:
cf_df %>%
summarise_all(funs(NPV=npv,PBP=pbp, DPBP=dpbp, IRR=irr), r=0.06, t0=TRUE) %>%
gather(key=key, value = value) %>%
separate(key, into = c("Project", "Metric")) %>%
spread(key=Project, value=value) %>%
mutate(Metric=fct_relevel(Metric, "NPV", "IRR", "PBP", "DPBP"),
Metric=fct_recode(Metric,
`Net Present Value (NPV), USD mln`="NPV",
`Internal Rate of Return (IRR), %`="IRR",
`Payback Period, years` = "PBP",
`Discounted Payback Period, years`="DPBP")) %>%
arrange(as.numeric(Metric))
This section will calculate a single integer or a single-point estimate. The standard DCF analysis provides financial managers single-point estimates associated with the Internal Rate of Return (IRR) or even the Present Value (PV) of the cash flow of a firm (Kim & Reinschmidt, 2012).
Calculate DCF using a single integer of NPV.
options(scipen = 999)
start.time<-Sys.time() ## start stopwatch
mydata<-lapply(1:1000, function(i) {
## Net Profit = Sales Volume * (Selling Price - Unit cost) - Fixed costs
## create random uniform integer for SalesVolume
DU = sample(x=1:3,size = 1,replace = T)
if(DU==1){
SalesVolume=100000
SellingPrice=8
}
if(DU==2){
SalesVolume=75000
SellingPrice=10
}
if(DU==3){
SalesVolume=50000
SellingPrice=11
}
## create triangular distribution for unit cost (as per example)
library(triangle)
Unitcost = rtriangle(1,5.5,7.5,c = 6.5) ## c=mode of distribution
#### hist(rtriangle(10000000,5.5,7.5))
Fixedcosts = 120000
NetProfit = SalesVolume * (SellingPrice - Unitcost) - Fixedcosts
})
stop.time<-Sys.time() ## stop stopwatch
time.taken.lapply = stop.time-start.time
NPV = unlist(mydata)
Plot histogram of the results of NPV
hist(NPV)
Find the mean of the results
mean(NPV)
## [1] 92883.73
Summerize the results
summary(NPV)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -68673 57829 99523 92884 130777 212722
In this example, a Monte Carlo simulation will calculate the NPV 10,000 times and find the distribution of the NPV calculations. Monte Carlo can be used to compute the distributions of project value (Balcombe & Smith, 1999).
Setting up loop for Monte Carlo simulation 10,000 times. For the purpose of brevity the R code for the calculation will not be displayed.
start.time.fl<-Sys.time() ## start stopwatch
NetProfits=vector(mode="numeric") ## mind the "s"
SalesVolumes = vector(mode="numeric")
UnitCosts = vector(mode="numeric")
SellingPrices = vector(mode="numeric")
for(i in 1:10000) {
## Net Profit = Sales Volume * (Selling Price - Unit cost) - Fixed costs
## create random uniform integer for SalesVolume
DU = sample(x=1:3,size = 1,replace = T)
if(DU==1){
SalesVolume=100000
SellingPrice=8
}
if(DU==2){
SalesVolume=75000
SellingPrice=10
}
if(DU==3){
SalesVolume=50000
SellingPrice=11
}
## create triangular distribution for unit cost (as per example)
library(triangle)
Unitcost = rtriangle(1,5.5,7.5,c = 6.5) ## c=mode of distribution
#### hist(rtriangle(10000000,5.5,7.5))
Fixedcosts = 120000
NetProfit = SalesVolume * (SellingPrice - Unitcost) - Fixedcosts
NetProfits[i]=NetProfit
SalesVolumes[i] = SalesVolume
UnitCosts[i] = Unitcost
SellingPrices[i] = SellingPrice
}
stop.time.fl<-Sys.time() ## start stopwatch
time.taken.fl <-stop.time.fl - start.time.fl
time.taken.fl
## Time difference of 0.6165287 secs
time.taken.lapply
## Time difference of 0.07970095 secs
time.taken.fl - time.taken.lapply
## Time difference of 0.5368278 secs
Plot the results
par(mfrow = c(2,2))
hist(SalesVolumes)
hist(SellingPrices)
hist(UnitCosts)
hist(NetProfits)
abline(v=mean(NetProfits), col=2)
Summerize the results
par(mfrow = c(1,1))
summary(SalesVolumes)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 50000 50000 75000 74450 100000 100000
summary(SellingPrices)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 8.0 8.0 10.0 9.7 11.0 11.0
summary(UnitCosts)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 5.511 6.198 6.496 6.494 6.787 7.497
summary(NetProfits)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## -69598 62355 102617 93669 132701 215997