Reputation: 11
I want to find the internal rate of return (IRR), basically the 'rate' that makes my NPV function go to zero, using the optim
function.
My current code for the NPV function (which works) is:
npv <- function(rate, cf){
r_v <- rep (rate,length (cf))
t_v <- as.numeric (seq(1:length (cf)))
pv <- cf * exp (-t_v*r_v)
sum (pv)
}
I tried using the following optim
function:
InternalRateReturn <- optim(c(0,1), npv, cf = testcf2, gr = NULL, method = "L-BFGS-B", lower = -Inf, upper = Inf,control=list(), hessian = FALSE)
but it is not coming back with the correct answer for InternalRateReturn$par
as opposed to using the uniroot
method below.
May I ask how to modify this code (to reiterate, I just want to optimize the rate in the npv
function such that the npv
function equals zero)?
The IRR function using uniroot
is as per below:
irr1 <- function(cf) {
uniroot(npv, c(0, 1), cf=cf)$root
}
Upvotes: 1
Views: 1347
Reputation: 3055
There's pretty cool example of using optim
to calculate IRR by Matt Brigida
### IRR Function: Takes a vector of payments and returns a list which includes the internal rate of return ($IRR) and possible word of warning ($beware) ----
irr <- function(x, period = 1, starting.value = .1){
### This should detect the number of sign changes. Should correctly not warn if there are many negative cash flows (so long as there is only 1 change in sign).
irr.func <- function(r){ ( sum(x / (1 + r)^{0:(length(x)-1)}) )^2 }
result <- optim(par = starting.value, fn = irr.func, method = "Brent", lower = -1000000, upper = 1000000)
## detecting number of sign changes
x.ge.0 <- 1 * (x >= 0)
changes <- diff(x.ge.0)
changes <- changes * changes
num.changes <- sum(changes)
if( num.changes > 1) {
statement <- "Your cash flows change more than once -- so you may have multiple IRRs. This function will only return the first IRR it finds. To find the others, you can try different starting values. However, note the IRR does not make sense if the signs change more than once (try Modified IRR or NPV)."
value <- period * result$par
return(list(beware = statement, IRR = value))
} else {
return(list(IRR = period * result$par))
}
}
Matt also has a pretty useful function for more realistic modified IRR (which does not make unreasonable assumptions about the reinvestment rate)
### Modified IRR (MIRR) Function: Takes a vector of payments and returns the MIRR by ----
mirr <- function(x, period = 1, starting.value = .1, discount.rate = 0.1, investment.rate = 0.05){
## move cash flows
## negative
cf.neg <- (x < 0) * x
## discounted
pv.cf.neg <- cf.neg / (1 + discount.rate)^{0:(length(x)-1)}
pv <- sum(pv.cf.neg)
## positive
cf.pos <- (x > 0) * x
fv.cf.pos <- cf.pos * (1 + investment.rate)^{0:(length(x)-1)}
fv <- sum(fv.cf.pos)
mirr.per.period <- ( fv / abs(pv) )^{1 / (length(x))} - 1
return( period * mirr.per.period )
}
Upvotes: 2
Reputation: 2988
If you simply need to compute IRR or NPV (or MIRR), and since it is not clear why you would absolutely need to use optim
, you may simply consider packages financial
or FinCal
instead of hacking your own function. Like this:
> require(financial)
> cf(c(-123400, 36200, 54800, 48100), i = 2.5)
Cash Flow Model
Flows:
1 2 3 4
-123400 36200 54800 48100
IRR%: 5.96
NPV Extremes at I%:
I% NPV NFV NUS
1 2.5 8742.13 9414.32 3060.95
> require(FinCal)
> npv(c(-123400, 36200, 54800, 48100), r = 0.025)
[1] 8742.134
> irr(c(-123400, 36200, 54800, 48100))
[1] 0.05959787
Upvotes: 0