在Python中计算XIRR

7
我需要计算一段时间内的金融投资的XIRR。在numpy、pandas或纯python中有没有相应的函数可以实现? 参考:什么是XIRR? 原问题的被接受答案是不正确的,需要改进。

3
可能是 financial python library that has xirr and xnpv function? 的重复问题。 - Bharath M Shetty
我同意这是一个可能的重复问题。我该如何删除这个问题?我发现人们很喜欢“踩票”,并且不希望造成更多的损害。 - DaSarfyCode
一旦问题得到回答,就无法删除。回答者花费了时间和精力来回答问题。 - Bharath M Shetty
@Bharathshetty 在我看到这个之前我就已经回答了,我应该删除这里的回答然后把它移动到链接那里吗? - pyCthon
我认为这样做并不合适。你的答案明显比原问题中给出的更好。 - DaSarfyCode
3个回答

9

创建了一个用于快速计算XIRR的包:PyXIRR

它没有外部依赖项,并且比任何现有的实现都更快。

from datetime import date
from pyxirr import xirr

dates = [date(2020, 1, 1), date(2021, 1, 1), date(2022, 1, 1)]
amounts = [-1000, 1000, 1000]

# feed columnar data
xirr(dates, amounts)

# feed tuples
xirr(zip(dates, amounts))

# feed DataFrame
import pandas as pd
xirr(pd.DataFrame({"dates": dates, "amounts": amounts}))

4

这里是从这个链接中获取的实现。

import datetime
from scipy import optimize

def xnpv(rate,cashflows):
    chron_order = sorted(cashflows, key = lambda x: x[0])
    t0 = chron_order[0][0]
    return sum([cf/(1+rate)**((t-t0).days/365.0) for (t,cf) in chron_order])

def xirr(cashflows,guess=0.1):
    return optimize.newton(lambda r: xnpv(r,cashflows),guess)

1
由于在xnpv中没有使用cashflows变量,这可能会让人感到困惑。目前(2018-02-13)该方法在存储库中的外观有些不同。你能更新一下你的答案吗? - leberknecht
不需要按时间对现金流进行排序。 - undefined

0

这个实现只计算一次时间差,然后向量化 NPV 计算。对于较大的数据集,它应该比 @pyCthon 的解决方案运行得更快。输入是一个带有日期索引的 pandas 系列现金流。

代码

import pandas as pd
import numpy as np
from scipy import optimize

def xirr2(valuesPerDate):
  """  Calculate the irregular rate of return.
  valuesPerDate is a pandas series of cashflows with index of dates.
  """

  # Clean values
  valuesPerDateCleaned = valuesPerDate[valuesPerDate != 0]

  # Check for sign change
  if valuesPerDateCleaned.min() * valuesPerDateCleaned.max() >= 0:
    return np.nan

  # Set index to time delta in years
  valuesPerDateCleaned.index = (valuesPerDateCleaned.index - valuesPerDateCleaned.index.min()).days / 365.0

  result = np.nan
  try:
    result = optimize.newton(lambda r: (valuesPerDateCleaned / ((1 + r) ** valuesPerDateCleaned.index)).sum(), x0=0, rtol=1e-4)
  except (RuntimeError, OverflowError): 
    result = optimize.brentq(lambda r: (valuesPerDateCleaned / ((1 + r) ** valuesPerDateCleaned.index)).sum(), a=-0.999999999999999, b=100, maxiter=10**4)

  if not isinstance(result, complex):
    return result
  else:
    return np.nan

测试

valuesPerDate = pd.Series()
for d in pd.date_range(start='1990-01-01', end='2019-12-31', freq='M'):
  valuesPerDate[d] = 10*np.random.uniform(-0.5,1)
valuesPerDate[0] = -100

print(xirr2(valuesPerDate))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接