IRR是计算信用卡分期、小额贷款、汽车租赁实际利率的重要参考,本文主要介绍如何在R语言中编写IRR函数。

关于使用Excel内置公式计算IRR的相关文章已有很多,那么为何要使用R语言编写函数呢?原因就在于R语言可以借助向量化操作方式实现irr的批量查询。

1、自定义函数

在编写IRR之前,我们先简单回忆一下初等数学中一个最简单的函数形式:$f(x, y) = x + y$。

R语言自定义函数非常简单,其形式如下:

  1. f <- function(x,y){
  2. x + y
  3. }

编写函数的语法包括:

  • 函数名:可以用便于记忆的词汇定义函数名,例如上段代码中的f。
  • 关键词:funciton,说明此数据对象为函数。
  • 参数:供用户后续输入的变量,例如上段代码中的x、y。
  • 函数主体:函数的表达式。
  • 返回值:默认返回函数主体的最后一个表达式的结果,可以用returun()函数指定要返回的值。

输入参数x = 2, y = 3, 则f(2, 3) = 2 + 3 = 5,下面我们来验证一下结果。

  1. f(2, 3)
  2. ## 5

2、编写IRR函数

内部收益率(Internal Rate of Return (IRR)),就是资金流入现值总额与资金流出现值总额相等、净现值等于零时的折现率。

根据资金的时间价值理论,我们将每一期现金流进行折现,求净现值为0时的折现率,其本质是求解一个一元多次方程的根。

设r为折现率,N为后期现金流对应的总期限,Cn为每一期的现金流,n为现金流对应的期限,则一元多次方程为:
$\begin{equation}
npv = \sum_{n = 0} ^ N\frac{C_n}{(1 + r) ^ n} = 0
\end{equation
}$

根据前述函数编写说明,定义IRR函数的完整代码如下:

  1. irr <- function(cf)
  2. { N <- length(cf) - 1
  3. n <- 0 : N
  4. f <- function(r, n) (1 + r) ^ n
  5. r <- seq(0.0001,1,0.0001)
  6. pv <- cf / t(outer(r, n, f))
  7. npv <- colSums(pv)
  8. irr <- r[abs(npv) == min(abs(npv))]
  9. return(irr)
  10. }

下面逐一解释此段代码。

  1. cf
  2. ## 现金流cf可作为一个向量输入
  3. N <- length(cf) - 1
  4. ## 求后期现金流对应的总期数
  5. n <- 0 : N
  6. ## 生成一个长度为N + 1的序列
  7. r <- seq(0.0001,1,0.0001)
  8. ## 定义折现率的区间范围,提高计算效率
  9. pv <- cf / t(outer(r, n, f))
  10. ## 外积向量化操作替代for循环,生成一个length(r) x length(n)矩阵
  11. npv <- colSums(pv)
  12. ## 矩阵的列和即为净现值
  13. irr <- r[abs(npv) == min(abs(npv))]
  14. ## 穷举法求npv最接近于0时的r值,即irr
  15. return(irr)
  16. ## 返回irr

3、应用

问题的提出:贷款金额10万元,24期,利率10%,费率1%(提前收取),10%保证金(放款时扣除,最后一期退还),求实际IRR?

按照前述方法,先定义一个pmt函数:

  1. pmt <- function(R, N, PV){
  2. (1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV
  3. }
  1. S <- 100000
  2. N <- 24
  3. R <- 0.1
  4. fee <- 0.01
  5. deposit <- 0.1
  6. cf <- c(-S + S * deposit + S * fee, rep(pmt(R, N, S), N - 1), pmt(R, N, S) - S * deposit)
  7. ## 期初现金流出为(-贷款金额 + 保证金 + 手续费),中间(N - 1)期现金流为月供款,最后一期现金流为(月供款 - 保证金)。
  8. irr(cf)*12
  9. ## 0.1344
  10. ## 计算结果为13.44%(年化)

以上为单一现金流的IRR计算,关于多个现金流的批量IRR计算方式,后续更新。

资金时间价值理论

fv = pv* (1+r)

编写函数

2、函数基础

R中一切

下面以一个最简单的函数形式为例,说明R语言如何编写函数。

编写实例:

R语言函数的编写分为函数名、函数、参数三个部分

  1. f(2,3)

公式编写

  1. 月供公式:

函数形式: $pmt = f(R, N, PV)_{1} = \frac{(1 + R / 12) ^ N R / 12 PV}{(1 + R / 12) ^ N - 1}$

r为利率,n为期限

2. 利息公式

$interest = f(R, N, PV){2} = f(R, N, PV){1} * N - PV$

  1. interest <- function(R, N, PV){
  2. (1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV * N - PV
  3. }

3. 费率公式

$ratio = f(R, N, PV){3} = \frac{f(R, N, PV){2}}{PV}$

  1. ratio <- function(R, N, PV){
  2. ((1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV * N - PV) / PV
  3. }

4. irr公式

  1. irr <- function(cf)
  2. { n <- 0 : (length(cf) - 1)
  3. f <- function(r, n) (1 + r) ^ n
  4. r <- seq(0.0001,1,0.0001)
  5. pv <- cf / t(outer(r, n, f)) ##外积向量化操作替代for循环
  6. npv <- colSums(pv)
  7. irr <- r[abs(npv) == min(abs(npv))] ##穷举法替代求根公式
  8. return(irr)
  9. }

应用

  1. 费率与利率的线性拟合
  1. R <- seq(from = 0.06, to = 0.12, by = 0.01)
  2. ratio <- ratio(R, 24, 100000)
  3. lm(ratio~R)
  4. summary(ratio / R)
  5. df <- data.frame(R,ratio)
  6. library(ggplot2)
  7. ggplot(df,aes(R,ratio)) + geom_point()

2.irr计算

总价10万元,10%首付,10%保证金,利率10%,费率1%,24期,求实际IRR?

  1. cf <- c(-100000*0.9+90000*0.1+90000*0.01, rep(pmt(0.1,24,90000),23),pmt(0.1,24,90000)-0.1*90000)
  2. sale_price <- 100000
  3. DP <- 0.1
  4. deposit <- 0.1
  5. fee <- 0.01
  6. R <- 0.1
  7. N <- 24
  8. cf <- c(- sale_price * (1 - DP) + sale_price * (1 - DP) * deposit +sale_price * (1 - DP) * fee, rep(pmt(R, N, sale_price * (1 - DP)), N-1), pmt(R, N, sale_price * (1 - DP)) - sale_price * (1 - DP) * deposit)
  9. irr(cf)*12
  1. 保证金与irr的线性拟合
  1. sale_price <- 100000
  2. DP <- 0.1
  3. deposit <- seq(0, 0.5, 0.05)
  4. fee <- 0.01
  5. R <- 0.1
  6. N <- 24
  7. cf <- c(- sale_price * (1 - DP) + sale_price * (1 - DP) * deposit +sale_price * (1 - DP) * fee, rep(pmt(R, N, sale_price * (1 - DP)), N-1), pmt(R, N, sale_price * (1 - DP)) - sale_price * (1 - DP) * deposit)
  8. irr(cf)*12

拓展资源

FinCal包

  1. npv <- function(r,cf)
  2. { n <- 0 : (length(cf) - 1)
  3. f <- function(r, n) (1 + r) ^ n
  4. pv <- cf / t(outer(r, n, f)) ##外积向量化操作替代for循环,且可求多个R值对应的npv,fincal包只能求单个r值的npv
  5. npv <- colSums(pv)
  6. return(npv)
  7. }
  8. npv(c(0.12,0.13),c(-5, 1.6, 2.4, 2.8))
  9. # 等价于
  10. sapply(c(0.12,0.13),function(r) npv(r,c(-5, 1.6, 2.4, 2.8)))
  11. irr <- function (cf)
  12. {
  13. uniroot(function(r) npv(r, cf), interval = c(1e-10,
  14. 1e+10), extendInt = "yes")$root
  15. ## 求解一元多次方程
  16. }