在Excel中,有一个公式(IRR.Payment: https://support.microsoft.com/fr-fr/office/fonction-tri-paiements-de1242ec-6477-445b-b11b-a303ad9adc9d )计算债券的 IRR。我正在尝试在 python 算法上重现这一点,以便能够在我的代码中计算它。我在网上找到了这段代码:
import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize
def tri(cashflows, periods_per_year):
##:param periods_per_year: number of periods per year (1 for annualy, 2 for half-yearly, 4 for quarterly)
def npv(rate):
npv = 0
for cf in cashflows:
npv += cf / (1 + rate / periods_per_year) ** (cashflows.index(cf) / (periods_per_year) + 1)
return npv
def f(rate):
return npv(rate)
def df(rate):
d = 0
for i, cf in enumerate(cashflows):
d -= (i + 1) * cf / (1 + rate / periods_per_year) ** ((i + 1) / periods_per_year + 1)
return d
guess = 0.1 # Valeur initiale pour la recherche du TRI
tri_value = optimize.newton(f, guess, fprime=df) * periods_per_year * 100
return tri_value
# Example n°1
cashflows = [-1000, 50, 50, 50, 50, 1050]
periods_per_year1 = 1
print("TRI :", tri(cashflows, periods_per_year), "%")
#Example n°2
cashflows2 = [-500,150,150,150,150]
print("TRI 2 :", tri(cashflows2, periods_per_year), "%")
#Example n°3
cashflows3= [-10000,2750,4250,3250,2750]
periods_per_year3 = 2
print("TRI 3 :", tri(cashflows3, periods_per_year3), "%")
但是,通过进行一些测试来检查一切是否正常工作,我发现了差异。这是我在 excel 上的示例和结果的屏幕截图 excel 上的示例
示例 n°1 在我的 python 代码中给出了 5.3%,在 excel 上给出了 4.99% 示例 n°2 在我的 python 代码中给出 19.99%,在 excel 中给出 7.7% 示例 #3 在 python 中失败并出现以下错误: Traceback(最近一次调用最后一次): 文件“/tmp/main.py”,第 31 行,位于 导入用户代码 文件“/tmp/user_code.py”,第 45 行,位于 print("TRI 3 :", tri(cashflows3, period_per_year3), "%") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件“/tmp/user_code.py”,第 30 行,三 tri_value = optimize.newton(f, 猜测, fprime=df) * period_per_year * 100 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 文件“/usr/local/lib/python3.11/dist-packages/scipy/optimize/_zeros_py.py”,第 391 行,牛顿 引发运行时错误(消息) RuntimeError: 50 次迭代后无法收敛,值为 0.6855681985991275。
有人可以向我解释一下为什么存在这些差异以及如何确保代码不会出现运行时错误吗?
我没有任何线索做什么
让我们来分解一下这些差异以及如何改进你的 Python 代码。
1. 差异和运行时错误
你所看到的差异主要源于 IRR 计算的本质,以及你在 Python 代码和 Excel 的 XIRR 函数中处理此问题的方式。
-
IRR 的迭代性质: IRR 的计算不是一个直接的公式。它是一个迭代过程,从一个初始猜测开始,并反复细化,直到找到一个使净现值 (NPV) 大致等于零的折现率。此迭代过程中的细微差异会导致结果略有不同。
-
初始猜测和收敛: 你的 Python 代码使用
scipy.optimize.newton
函数,它需要一个初始猜测(你在本例中将其设置为 0.1)。牛顿法(一种用于求解方程的根的算法)可能对初始猜测很敏感。如果初始猜测距离实际根太远,它可能会无法收敛,或者可能收敛到不同的根,从而导致你看到的运行时错误或不准确的结果。 -
Excel 的 XIRR: Excel 的 XIRR 函数也使用迭代方法,但它可能有不同的收敛标准或用于初始猜测的内部机制,这会导致结果略有不同。
2. 改进你的 Python 代码
以下是改进 Python 代码的一些方法:
-
更好的初始猜测: 不要对所有情况都使用固定的初始猜测 (0.1),而是尝试找到一个更接近实际 IRR 的更好的初始猜测。一种方法是使用一个范围内的多个初始猜测,或使用其他数值方法来获得更接近的初始猜测。
-
收敛容差: 你可以调整
scipy.optimize.newton
函数的收敛容差,使其对结果更严格或更宽松。这可以通过设置tol
参数来完成。 -
替代求解器: 除了
scipy.optimize.newton
之外,SciPy 还提供了其他求根算法,例如scipy.optimize.brentq
或scipy.optimize.fsolve
。这些求解器可能更稳健,并且不太可能受到初始猜测的影响。
3. 改进的 Python 代码
这是一个使用
scipy.optimize.fsolve
的改进后的 Python 代码版本:
import numpy as np
from scipy.optimize import fsolve
def tri(cashflows, periods_per_year):
"""
计算现金流序列的内部收益率 (IRR)。
Args:
cashflows (list): 现金流列表,第一个元素是初始投资。
periods_per_year (int): 每年期数。
Returns:
float: 内部收益率 (IRR),以百分比表示。
"""
def npv(rate):
"""计算给定折现率的净现值 (NPV)。"""
return np.sum([cf / (1 + rate / periods_per_year)**((i+1)/periods_per_year)
for i, cf in enumerate(cashflows)])
# 使用 fsolve 查找 NPV = 0 的折现率
guess = 0.1 # 初始猜测
tri_value = fsolve(npv, guess)[0] * periods_per_year * 100
return tri_value
# 测试用例
cashflows = [-1000, 50, 50, 50, 50, 1050]
periods_per_year1 = 1
print("IRR:", tri(cashflows, periods_per_year1), "%")
cashflows2 = [-500, 150, 150, 150, 150]
print("IRR 2:", tri(cashflows2, periods_per_year1), "%")
cashflows3 = [-10000, 2750, 4250, 3250, 2750]
periods_per_year3 = 2
print("IRR 3:", tri(cashflows3, periods_per_year3), "%")
此代码应该提供更准确且更可靠的 IRR 计算结果,并减少运行时错误的可能性。
标签:python,finance,irr From: 78782190