用Python(pandas)计算可变现金流量IRR

我有一个无法预测的现金流量和无法预测的期间长度的DataFrame,我需要生成一个后向IRR。

使用求解器在Excel中进行操作非常简单,想知道是否存在在Python中实现它的好方法。(我认为我可以利用openpyxl来使求解器在python中以excel的形式工作,但这感觉不必要地麻烦)。

问题很简单:

现金流量的净现值=((现金流量)/(1 + IRR)^ years_ago)

目标:找到IRR,其中SUM(NPV)= 0

我的数据框看起来像这样:

cash_flow    |years_ago

-----------------------

-3.60837e+06 |4.09167

31462 |4.09167

1.05956e+06 |3.63333

-1.32718e+06 |3.28056

-4.46554e+06 |3.03889

似乎其他IRR计算器(例如numpy.irr)都假定严格的截止期限(每3个月,1年等),这是行不通的。另一个选择似乎是迭代路线,在该路线中,我不断猜测,检查和迭代,但这似乎是解决此问题的错误方法。理想情况下,我正在寻找可以做到这一点的东西:

irr = calc_irr((cash_flow1,years_ago1),(cash_flow2,years_ago2),etc)

编辑:这是我从中运行问题的代码。我有一个交易清单,我选择按ID创建临时表。

for id in df_tran.id.unique():

temp_df = df_tran[df_tran.id == id]

cash_flow = temp_df.cash_flows.values

years = temp_df.years.values

print(id, cash_flow)

print(years)

#irr_calc = irr(cfs=cash_flow, yrs=years,x0=0.100000)

#print(sid, irr_calc)

df_tran(temp_df所基于的地方)的外观如下:

    cash_flow       |years     |id

0 -3.60837e+06 4.09167 978237

1 31462 4.09167 978237

4 1.05956e+06 3.63333 978237

6 -1.32718e+06 3.28056 978237

8 -4.46554e+06 3.03889 978237

10 -3.16163e+06 2.81944 978237

12 -5.07288e+06 2.58889 978237

14 268833 2.46667 978237

17 -4.74703e+06 1.79167 978237

20 -964987 1.40556 978237

22 -142920 1.12222 978237

24 163894 0.947222 978237

26 -2.2064e+06 0.655556 978237

27 1.23804e+06 0.566667 978237

29 180655 0.430556 978237

30 -85297 0.336111 978237

34 -2.3529e+07 0.758333 1329483

36 21935 0.636111 1329483

38 -3.55067e+06 0.366667 1329483

41 -4e+06 4.14167 1365051

temp_df看起来与df_tran相同,只不过它仅保存单个ID的事务。

回答:

您可以使用scipy.optimize.fsolve

给定初始估计值,返回由func(x)= 0定义的(非线性)方程的根。

首先定义将成为func参数的函数fsolve。由于您的内部收益率,现金流量和年数,这是净现值。(使用NumPy矢量化。)

import numpy as np

def npv(irr, cfs, yrs):

return np.sum(cfs / (1. + irr) ** yrs)

一个例子:

cash_flow = np.array([-2., .5, .75, 1.35])

years = np.arange(4)

# A guess

print(npv(irr=0.10, cfs=cash_flow, yrs=years))

0.0886551465064

现在使用fsolve

from scipy.optimize import fsolve

def irr(cfs, yrs, x0):

return np.asscalar(fsolve(npv, x0=x0, args=(cfs, yrs)))

您的内部收益率是:

print(irr(cfs=cash_flow, yrs=years, x0=0.10))

0.12129650313214262

您可以确认这使您的NPV为0:

res = irr(cfs=cash_flow, yrs=years, x0=0.10)

print(np.allclose(npv(res, cash_flow, years), 0.))

True

所有代码一起:

import numpy as np

from scipy.optimize import fsolve

def npv(irr, cfs, yrs):

return np.sum(cfs / (1. + irr) ** yrs)

def irr(cfs, yrs, x0, **kwargs):

return np.asscalar(fsolve(npv, x0=x0, args=(cfs, yrs), **kwargs))

为了使其与您的熊猫示例兼容,只需使用

cash_flow = df.cash_flow.values

years = df.years_ago.values

更新:您的问题中的值似乎有点荒谬(如果IRR甚至存在,您的IRR将会是一个天文数字),但是这是您的运行方式:

cash_flow = np.array([-3.60837e+06, 31462, 1.05956e+06, -1.32718e+06, -4.46554e+06])    

years_ago = np.array([4.09167, 4.09167, 3.63333, 3.28056, 3.03889])

print(irr(cash_flow, years_ago, x0=0.10, maxfev=10000))

1.3977721900669127e+82

第二次更新:您的代码中有一些次要的错别字,您的实际$流量和计时结果对无意义的IRR起作用,但是下面是您要执行的操作。例如,请注意您有一个ID,其中包含一个负交易,即负无限IRR。

for i, df in df_tran.groupby('id'):

cash_flow = df.cash_flow.values

years = df.years.values

print('id:', i, 'irr:', irr(cash_flow, years, x0=0.))

id: 978237 irr: 347.8254979851405

id: 1329483 irr: 3.2921314448062817e+114

id: 1365051 irr: 1.0444951674872467e+25

以上是 用Python(pandas)计算可变现金流量IRR 的全部内容, 来源链接: utcz.com/qa/402088.html

回到顶部