利用Numpy求解投資內部收益率IRR


一、 內部收益率和凈現值

內部收益率(Internal Rate of Return, IRR)其實要和凈現值(Net Present Value, NPV)結合起來講。凈現值指的是某個投資項目給公司或企業帶來的價值增值,可以簡單地用以下公式去計算。

1.凈現值:

NPV = CF0 + CF1/(1+r1) + ... + CFt/(1+rt)^t

其中,CF0是初始投資額,是一個負值,代表現金的流出;t表示時間,指第t期;后面的CF1,CF2,...,CFt這些是每期的回報金額,為正值,表示投資所得的收益。r1,r2,...、rt是指每期的折現率。

舉個比較通俗的例子,我們花100萬元投資了一個一年期理財產品,預期收益率為10%,一年期國債利率為5%,投資是否合算?

這里涉及到折現率的相關知識,簡單介紹一下:我們都知道銀行存款是有利率的,我們把10000塊錢存到銀行,一年后,連本帶息就會超過10000元。如果我們不把錢存銀行,一年后還是10000元錢,不存錢相當於虧掉了那么多利息的錢。也就是說,在存入銀行后,一年后的10000元的拿到現在來看,實際是不到10000元的,我可能存9500,一年后就能拿到10000。這就是一個折現的概念,用時間來換利息。

我們再看這個問題,
1年后,預期的現金流就是:
100×(1+10%)=110(萬元),
然后,我們按照國債的利率5%來對其折現(假設該產品與國債信用風險相當),即:一年后的110萬元,如果我們按信用等級較高的國債去投資,現在價值多少?
答案是:110/(1+5%)。
計算凈現值:
NPV = -100 + 110/(1+5%)= 4.7619(萬元)
凈現值是正的,說明這筆投資合算。當然,這里其實只看年利率就可以做出簡單的判斷,實際情況下,不論是理財產品還是國債利率都是浮動的。

2.內部收益率

前面我們取的折現率是國債的利率,是一個與投資決策之外的值,也可以理解是外部的收益率。這里內部收益率,指的是使凈現值等於0時的折現率,就稱為內部收益率(IRR)。我們用一個固定的折現率r去計算,令NPV=0,則
0 = CF0 + CF1/(1+r) + ... + CFt/(1+r)^t
那么,此時的r在數值上與IRR相等。因此,我們只要知道每年的現金流量情況,就能計算出該筆投資的IRR,將IRR與r相比,若IRR>r,則該項目值得投資;若IRR<r,則該項目不值得投資,不如去買同期的穩定國債之類的產品。

3.內部收益率的簡單計算

如下表所示,第0年也就是現在,產生了-500萬的現金流量,即用500萬元去做一個投資,1年、2年、3年后的現金流量均為正的100萬元、200萬元和300萬元。假設還是以5%的國債利率去做折現,這筆投資是否值得?

年份 現金流 (萬元)
0 -500
1 100
2 200
3 300

計算內部收益率,將其與國債利率比較,
-500 + 100/(1+IRR) + 200/(1+IRR)^2 + 300/(1+IRR)^3 vs 5%
計算得到
IRR約為8% >5%,該筆投資值得。
從另一個角度看,這筆投資3年后累計現金流為+100萬元,如果買3年期利率為5%的國債,則累計現金流為
500×(1+5%)^3-500=78.8125(萬元) < 100(萬元)

二、Numpy計算內部收益率IRR

1.源碼解讀

直接上源碼:

def irr(values):
    """
    Return the Internal Rate of Return (IRR).
    .. deprecated:: 1.18
       `irr` is deprecated; for details, see NEP 32 [1]_.
       Use the corresponding function in the numpy-financial library,
       https://pypi.org/project/numpy-financial.
    This is the "average" periodically compounded rate of return
    that gives a net present value of 0.0; for a more complete explanation,
    see Notes below.
    :class:`decimal.Decimal` type is not supported.
    Parameters
    ----------
    values : array_like, shape(N,)
        Input cash flows per time period.  By convention, net "deposits"
        are negative and net "withdrawals" are positive.  Thus, for
        example, at least the first element of `values`, which represents
        the initial investment, will typically be negative.
    Returns
    -------
    out : float
        Internal Rate of Return for periodic input values.
    Notes
    -----
    The IRR is perhaps best understood through an example (illustrated
    using np.irr in the Examples section below).  Suppose one invests 100
    units and then makes the following withdrawals at regular (fixed)
    intervals: 39, 59, 55, 20.  Assuming the ending value is 0, one's 100
    unit investment yields 173 units; however, due to the combination of
    compounding and the periodic withdrawals, the "average" rate of return
    is neither simply 0.73/4 nor (1.73)^0.25-1.  Rather, it is the solution
    (for :math:`r`) of the equation:
    .. math:: -100 + \\frac{39}{1+r} + \\frac{59}{(1+r)^2}
     + \\frac{55}{(1+r)^3} + \\frac{20}{(1+r)^4} = 0
    In general, for `values` :math:`= [v_0, v_1, ... v_M]`,
    irr is the solution of the equation: [2]_
    .. math:: \\sum_{t=0}^M{\\frac{v_t}{(1+irr)^{t}}} = 0
    References
    ----------
    .. [1] NumPy Enhancement Proposal (NEP) 32,
       https://numpy.org/neps/nep-0032-remove-financial-functions.html
    .. [2] L. J. Gitman, "Principles of Managerial Finance, Brief," 3rd ed.,
       Addison-Wesley, 2003, pg. 348.
    Examples
    --------
    >>> round(np.irr([-100, 39, 59, 55, 20]), 5)
    0.28095
    >>> round(np.irr([-100, 0, 0, 74]), 5)
    -0.0955
    >>> round(np.irr([-100, 100, 0, -7]), 5)
    -0.0833
    >>> round(np.irr([-100, 100, 0, 7]), 5)
    0.06206
    >>> round(np.irr([-5, 10.5, 1, -8, 1]), 5)
    0.0886
    """
    # `np.roots` call is why this function does not support Decimal type.
    #
    # Ultimately Decimal support needs to be added to np.roots, which has
    # greater implications on the entire linear algebra module and how it does
    # eigenvalue computations.
    res = np.roots(values[::-1])  # 求根,對於n次多項式,p[0] * x**n + p[1] * x**(n-1) + ... + p[n-1]*x + p[n],傳入p的列表參數[p[0],p[1],...p[n]].
    mask = (res.imag == 0) & (res.real > 0)  # 虛部為0,實部為非負數。
    if not mask.any():  # 判斷是否有滿足條件的實根
        return np.nan  # 不滿足,返回Not A Number
    res = res[mask].real
    # NPV(rate) = 0 can have more than one solution so we return
    # only the solution closest to zero.
    rate = 1/res - 1  # 這里解出的res,也就是符合條件的x,其實等於1/(1+r),因此要做一個變換回去,r=1/x-1
    rate = rate.item(np.argmin(np.abs(rate)))  # argmin()取最小值的下標,也就是說可能會計算出多個折現率,我們取最小那個
    return rate

2.實例計算

我們直接調用numpy.irr()進行計算,參數為一個數組,每年的現金流量。然后用round()函數將其約到小數點后四位。
計算結果為:0.0821。我們發現這里還報了一個DeprecationWarning,在NumPy 1.20版本,irr()函數將被移除,有一個專門計算金融的Python包從Numpy中獨立出來了,叫做numpy_financial,大致看了一下,可以計算fv、pmt、nper、impt、ppmt、pv、rate、irr、npv、mirr等,感興趣的可以點擊進去看一看。

>>> import numpy as np
>>> print(round(np.irr([-500, 100, 200, 300]),4))

Warning (from warnings module):
  File "C:\Users\Administrator\Desktop\func1.py", line 2
    print(round(np.irr([-100, 39, 59, 55, 20]),4))
DeprecationWarning: numpy.irr is deprecated and will be removed from NumPy 1.20. Use numpy_financial.irr instead (https://pypi.org/project/numpy-financial/).
0.0821


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM