IRR是计算信用卡分期、小额贷款、汽车租赁实际利率的重要参考,本文主要介绍如何在R语言中编写IRR函数。
关于使用Excel内置公式计算IRR的相关文章已有很多,那么为何要使用R语言编写函数呢?原因就在于R语言可以借助向量化操作方式实现irr的批量查询。
1、自定义函数
在编写IRR之前,我们先简单回忆一下初等数学中一个最简单的函数形式:$f(x, y) = x + y$。
R语言自定义函数非常简单,其形式如下:
f <- function(x,y){x + y}
编写函数的语法包括:
- 函数名:可以用便于记忆的词汇定义函数名,例如上段代码中的f。
- 关键词:funciton,说明此数据对象为函数。
- 参数:供用户后续输入的变量,例如上段代码中的x、y。
- 函数主体:函数的表达式。
- 返回值:默认返回函数主体的最后一个表达式的结果,可以用returun()函数指定要返回的值。
输入参数x = 2, y = 3, 则f(2, 3) = 2 + 3 = 5,下面我们来验证一下结果。
f(2, 3)## 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函数的完整代码如下:
irr <- function(cf){ N <- length(cf) - 1n <- 0 : Nf <- function(r, n) (1 + r) ^ nr <- seq(0.0001,1,0.0001)pv <- cf / t(outer(r, n, f))npv <- colSums(pv)irr <- r[abs(npv) == min(abs(npv))]return(irr)}
下面逐一解释此段代码。
cf## 现金流cf可作为一个向量输入N <- length(cf) - 1## 求后期现金流对应的总期数n <- 0 : N## 生成一个长度为N + 1的序列r <- seq(0.0001,1,0.0001)## 定义折现率的区间范围,提高计算效率pv <- cf / t(outer(r, n, f))## 外积向量化操作替代for循环,生成一个length(r) x length(n)矩阵npv <- colSums(pv)## 矩阵的列和即为净现值irr <- r[abs(npv) == min(abs(npv))]## 穷举法求npv最接近于0时的r值,即irrreturn(irr)## 返回irr
3、应用
问题的提出:贷款金额10万元,24期,利率10%,费率1%(提前收取),10%保证金(放款时扣除,最后一期退还),求实际IRR?
按照前述方法,先定义一个pmt函数:
pmt <- function(R, N, PV){(1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV}
S <- 100000N <- 24R <- 0.1fee <- 0.01deposit <- 0.1cf <- c(-S + S * deposit + S * fee, rep(pmt(R, N, S), N - 1), pmt(R, N, S) - S * deposit)## 期初现金流出为(-贷款金额 + 保证金 + 手续费),中间(N - 1)期现金流为月供款,最后一期现金流为(月供款 - 保证金)。irr(cf)*12## 0.1344## 计算结果为13.44%(年化)
以上为单一现金流的IRR计算,关于多个现金流的批量IRR计算方式,后续更新。
资金时间价值理论
fv = pv* (1+r)
编写函数
2、函数基础
R中一切
下面以一个最简单的函数形式为例,说明R语言如何编写函数。
编写实例:
R语言函数的编写分为函数名、函数、参数三个部分
f(2,3)
公式编写
- 月供公式:
函数形式: $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$
interest <- function(R, N, PV){(1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV * N - PV}
3. 费率公式
$ratio = f(R, N, PV){3} = \frac{f(R, N, PV){2}}{PV}$
ratio <- function(R, N, PV){((1 + R / 12) ^ N / ((1 + R / 12) ^ N - 1) * R / 12 * PV * N - PV) / PV}
4. irr公式
irr <- function(cf){ n <- 0 : (length(cf) - 1)f <- function(r, n) (1 + r) ^ nr <- seq(0.0001,1,0.0001)pv <- cf / t(outer(r, n, f)) ##外积向量化操作替代for循环npv <- colSums(pv)irr <- r[abs(npv) == min(abs(npv))] ##穷举法替代求根公式return(irr)}
应用
- 费率与利率的线性拟合
R <- seq(from = 0.06, to = 0.12, by = 0.01)ratio <- ratio(R, 24, 100000)lm(ratio~R)summary(ratio / R)df <- data.frame(R,ratio)library(ggplot2)ggplot(df,aes(R,ratio)) + geom_point()
2.irr计算
总价10万元,10%首付,10%保证金,利率10%,费率1%,24期,求实际IRR?
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)sale_price <- 100000DP <- 0.1deposit <- 0.1fee <- 0.01R <- 0.1N <- 24cf <- 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)irr(cf)*12
- 保证金与irr的线性拟合
sale_price <- 100000DP <- 0.1deposit <- seq(0, 0.5, 0.05)fee <- 0.01R <- 0.1N <- 24cf <- 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)irr(cf)*12
拓展资源
FinCal包
npv <- function(r,cf){ n <- 0 : (length(cf) - 1)f <- function(r, n) (1 + r) ^ npv <- cf / t(outer(r, n, f)) ##外积向量化操作替代for循环,且可求多个R值对应的npv,fincal包只能求单个r值的npvnpv <- colSums(pv)return(npv)}npv(c(0.12,0.13),c(-5, 1.6, 2.4, 2.8))# 等价于sapply(c(0.12,0.13),function(r) npv(r,c(-5, 1.6, 2.4, 2.8)))irr <- function (cf){uniroot(function(r) npv(r, cf), interval = c(1e-10,1e+10), extendInt = "yes")$root## 求解一元多次方程}
