【问题标题】:Using Loops in Python Newton-Raphson Algorithm for NPV and IRR在 NPV 和 IRR 的 Python Newton-Raphson 算法中使用循环
【发布时间】:2021-05-29 21:03:31
【问题描述】:

我想创建一个名为“npv_zero”的函数。 它的输入参数应该是一个现金流向量和一个起始值。它的输出参数应该是 NPV(r) 的零。我想包括 Newton-Raphson 方法来计算函数 NPV(x)=C1+2C2x+3C3x**2+...

的零

带有显式导数。最后我想重新转换 x 并获得 IRR(内部收益率)。总结一下,我想使用迭代步骤 k=10 和容差 eps=10**-5。

我尝试了这段代码,但它不包含这两个输入参数,我不知道如何使用向量创建 Newton-Raphson,这就是我创建这些单独值 C0、C1、C2、C3 的原因。

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve

# Defining variables for Newton Raphson Calculation
CO = -100 # Cashflow in t=0
C1 = 10 # Cashflow in t=1
C2 = 20 # Cashflow in t=2
C3 = 60 # Cashflow in t=3
x = 0.88 # the inital guess

# Newton Raphson function
def npv_zero(fn, x, tol = 0.00000000001, maxiter = 100):
    for i in range(maxiter):
        x_new = x - fn[0](x)/fn[1](x)
        if abs(x_new - x) < tol: break
        x = x_new
    return x_new, i

y = [lambda x: CO + C1*x + C2*x**2 + C3*x**3, # f(x)
     lambda x: C1 + 2*C1*x + 3*C3*x**2] # f'(x)
x, n = npv_zero(y, 0.88)
print('the root is %f at %d iterations.' % (x,n))

结果:1​​1 次迭代的根为 1.041930。 接下来是 IRR 计算:

# IRR-Calculation
def irr(x):
    """
    Function to calculate the IRR of a project
    Parameter
    ---------
    x (numpy array): cashflow vector
    Returns
    -------
    float: IRR
    """
    t = np.arange(len(x))
    npv = lambda r: x @ (1 / (1+r)) ** t
    return fsolve(npv, 0)

cashflow = [CO, C1, C2, C3]
print(irr(cashflow))
print(np.npv(0.11397637333244609, cashflow))

结果:-0.04024282,-31.503021914119515

欢迎在下方发表评论! 问候:)

【问题讨论】:

  • 您好,感谢您邀请我写评论。我的评论是:你的问题到底是什么?
  • 我还有一条评论:您显示的代码没有正确缩进。
  • 你好 mkrieger1,我的问题是如何通过使用现金流量向量而不是变量来改进我的实际代码。这是我目前学习中的一项练习。对于我写的任何情况,我感到抱歉。这是我第一次提问

标签: python function numpy loops finance


【解决方案1】:

类似这样的东西,虽然我没有检查为什么它收敛得更快。我怀疑您的 lambda 函数更快,但是以程序方式处理 fn 和 fn' 似乎很有趣。

顺便说一句,您在问题中的缩进肯定很糟糕。花了我一些时间来弄清楚你的真正意图。

# Defining variables for Newton Raphson Calculation
CO = -100  # Cashflow in t=0
C1 = 10  # Cashflow in t=1
C2 = 20  # Cashflow in t=2
C3 = 60  # Cashflow in t=3
x = 0.88  # the inital guess


def npv_zero(coeff_vector, x, tol=0.00000000001, maxiter=100):
    """Newton Raphson function."""
    def fn(x):
        return sum(c*x**i for i, c in enumerate(coeff_vector))

    def fn_(x):
        return sum((i+1)*c*x**i for i, c in enumerate(coeff_vector[1:]))

    for _i in range(maxiter):
        x_new = x - fn(x) / fn_(x)
        if abs(x_new - x) < tol:
            break
        x = x_new
    return x_new, _i


x, n = npv_zero([CO, C1, C2, C3], 0.88)
print('the root is %f at %d iterations.' % (x, n))

【讨论】:

  • 嗨 jwal,对不起我的糟糕问题.. 但这似乎很不错!非常感谢您的回答。
  • @Joneslu 不是一个糟糕的问题。在 Python 中,准确地缩进只是真的很重要。
【解决方案2】:

要在代码中使用np.arrays,现金流数组可以乘以折扣因子数组。 d_npv 函数使用相同的折扣因子数组设置一个索引,现金流乘以(一次)np.arange

sum( [ c0, c1, c2, c3 ] * [ 1, x, x**2, x**3 ] ) => npv
sum( [ c0*0, c1*1, c2*2, c3*3 ] * [ 1, 1, x, x**2 ] ) => d_npv

这是在下面的funcs() 中实现的。

import numpy as np
from scipy.optimize import fsolve

CO = -100 # Cashflow in t=0
C1 = 10 # Cashflow in t=1
C2 = 20 # Cashflow in t=2
C3 = 60 # Cashflow in t=3
x = 0.88 # the inital guess

def funcs( cashflow ):
    """  Return npv and npv' functions for cashflow.
         cashflow is an np.array. 
    """
    gradient_coeffs = cashflow * np.arange( len(cashflow) )
    discount_factors = np.ones( len(cashflow) + 1 )
    # Recalculated for each run of npv for x.

    # discount_factors = [ 1, 1, x, x**2, x**3 ]
    # for npv calc          [ 1, x, x**2, x**3 ] ;  discount_factors[ 1: ]
    # fpr d_npv calc     [ 1, 1, x, x**2 ]       ;  discount_factors[ : -1 ]

    def npv( x ):
        """ npv calculation: assumes the first cashflow takes place at t = 0.
            i.e the discount factor for t=0 is 1.
        """
        nonlocal discount_factors
        discount_factors[ 2: ] = x
        discount_factors = discount_factors.cumprod()
        return np.array( [(cashflow * discount_factors[1:]).sum()] )

    def d_npv( x ):
        return np.array( [ ( gradient_coeffs * discount_factors[ : -1 ]).sum() ] )

    return npv, d_npv

func, fprime  = funcs( cashflow ) 

print( "Using fsolve: ", fsolve( func, x, fprime = fprime ) )
# Using fsolve:  [1.04193021]

# Newton Raphson function
fs = list( funcs( cashflow ) )
def npv_zero(fn, x, tol = 0.00000000001, maxiter = 100 ):
    for i in range(maxiter):
        x_new = x - fn[0](x)/fn[1](x)
        if abs(x_new - x) < tol: break
        x = x_new
    return x_new, i

print( "Using npv_zero: ", npv_zero( fs, x ) )
# Using npv_zero:  (array([1.04193021]), 4)

【讨论】:

  • 嘿,克里斯,这看起来也很漂亮!感谢您的评论。祝你度过愉快的一周:)
猜你喜欢
  • 2014-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-13
  • 1970-01-01
  • 1970-01-01
  • 2020-08-09
  • 1970-01-01
相关资源
最近更新 更多