用python计算基金内部收益率-基于scipy科学计算库的数值解
??最近在計(jì)算基金內(nèi)部收益率的時(shí)候首先選擇的是用純python編寫的sympy科學(xué)計(jì)算庫,sympy在計(jì)算常微分方程,偏微分方程,一般線性方程組以及取微分、積分、極限等方面依靠其強(qiáng)大的符號體系游刃有余,并且編程語法更簡單易懂,但是當(dāng)用其求解高階非線性方程的時(shí)候就暴露出python運(yùn)行速度慢的短板,而在求解基金內(nèi)部收益率的時(shí)候往往樣本區(qū)間數(shù)據(jù)量很多,比如本文接下來將要采用的這支基金的數(shù)據(jù)就有80期。(其實(shí)我之前寫完代碼點(diǎn)擊運(yùn)行之后就去睡覺了,第二天起來仍然沒有算出結(jié)果,可以說python面對這種問題從來不耽誤人睡覺休息)
??其實(shí)python的numpy庫已經(jīng)內(nèi)置了內(nèi)部收益率計(jì)算函數(shù),可以直接調(diào)用numpy.irr([NCF],round(n))。(就不要追問我寫這篇博客的意義在哪里了!)接下來本文將會(huì)展示調(diào)用scipy.optimize最優(yōu)化函數(shù)求內(nèi)部收益率的高階非線性方程的數(shù)值解。
??開始之前,需要介紹一下基金內(nèi)部收益率(Internal Rate of Return, IRR)的計(jì)算方法,基金內(nèi)部收益率的計(jì)算需要用到基金期末、期初的總凈值(Total Net Asset, TNA)和各期現(xiàn)金流(Net Cash Flow, NCF),其計(jì)算公式如下:
TNA0(1+IRR)T+∑t=1TNCFt(1+IRR)(T?t)=TNAT(1)TNA_0{(1+IRR)^T}+\sum_{t=1}^TNCF_t{(1+IRR)^{(T-t)}}=TNA_T \tag{1}TNA0?(1+IRR)T+t=1∑T?NCFt?(1+IRR)(T?t)=TNAT?(1)
??其中NCFtNCF_tNCFt?的計(jì)算為:
NCFt=TNAt?TNAt?1(1+Rt)(2)NCF_t=TNA_t-TNA_{t-1}(1+R_t)\tag{2}NCFt?=TNAt??TNAt?1?(1+Rt?)(2)
??這里的RtR_tRt?表示的是基金第ttt期的收益率,TNA0TNA_0TNA0?和TNATTNA_TTNAT?分別為基金期初的總資產(chǎn)凈值和期末的總資產(chǎn)凈值??梢娎胮ython的求解內(nèi)部收益率IRRIRRIRR速度主要就取決于TTT的大小。
??首先,展示本文所使用到的數(shù)據(jù),數(shù)據(jù)已經(jīng)上傳到百度云盤(提取碼:6whe)。
??導(dǎo)入數(shù)據(jù),這里所使用的是基金月度的單月回報(bào)RRR和單月總凈值TNATNATNA。
??這里的T=80T=80T=80,當(dāng)然如果有好奇用sympy求解內(nèi)部收益率到底是什么情況的小伙伴,在本文末尾我將展示用sympy計(jì)算內(nèi)部收益率的代碼。
?? 按照公式(2)計(jì)算出基金各期的凈現(xiàn)金流NCFtNCF_tNCFt?
??Python的科學(xué)計(jì)算庫scipy的優(yōu)化器optimize中提供了基于hybrd和hybrj算法的內(nèi)置函數(shù)fsolve,可以求高階的非線性方程的數(shù)值解。這里需要設(shè)定求解內(nèi)部收益率的方程,其實(shí)就是基于本文的數(shù)據(jù)按照公式(1)編寫函數(shù)
def func(x):function=Fund.TNA[0]*(1+x)**(len(NCF)-1)-Fund.TNA[-1]#len(NCF)包括了NaN空值for i in range(1,len(NCF)): #由于NCF的第一期值為空function+=NCF[i]*(1+x)**(len(NCF)-i-1) #i只能取到(len(NCF)-1)return function??fsolve(func,x0)主要有兩個(gè)參數(shù),func為被求解方程,方程的等號右邊為0,左邊就是上面所定義的函數(shù);x0為方程func的初始值,以列表的新式輸入,返回值也為列表形式。將初始值設(shè)定為0,求解最終得到基金的內(nèi)部收益率為-0.00419273。
from scipy.optimize import fsolve root=fsolve(func,[0]) # x的初始值設(shè)為0,需要用list的形式輸入 >>>print(root) [-0.00419273]??由于fsolve在優(yōu)化過程中采用迭代的方式求解非線性方程的數(shù)值解,所以我們只得到了一個(gè)解,熟悉一元二次拋物線方程的小伙伴都知道這類方程的未知數(shù)xxx最高次有幾次就會(huì)有多少個(gè)解,如果是嚴(yán)格按照這種方法求解,我們應(yīng)該得到80個(gè)解,當(dāng)然其中包括了復(fù)數(shù)解。求出這80個(gè)解其實(shí)是沒有必要的,而純python編寫的科學(xué)計(jì)算庫sympy就可以做到,先附上代碼
import pandas as pd import sympy as sy Fund=pd.read_csv("C:\\Users\\psj\\Desktop\\Fund.csv",index_col="Date",header=0) Fund.index=pd.to_datetime(Fund.index) NCF=Fund.TNA-Fund.TNA.shift(1)*(1+Fund.R) x=sy.symbols("x") f=Fund.TNA[0]*(1+x)**(len(NCF)-1)-Fund.TNA[-1] for j in range(1,len(NCF)):f=f+NCF[j]*(1+x)**(len(NCF)-j-1) result=sy.solve(f,x) print(result)??要得到運(yùn)行結(jié)果可能是很久之后的事情了,當(dāng)然也不是本人寫的代碼有bug算不出來,當(dāng)我們把TTT設(shè)定為5時(shí),只需要一段小小的等待就能得到方程的全部5個(gè)解。
Fund=Fund.iloc[:6,:] NCF=Fund.TNA-Fund.TNA.shift(1)*(1+Fund.R) x=sy.symbols("x") f=Fund.TNA[0]*(1+x)**(len(NCF)-1)-Fund.TNA[-1] for j in range(1,len(NCF)):f=f+NCF[j]*(1+x)**(len(NCF)-j-1) result=sy.solve(f,x) >>>print(result) [-0.00685850972132560, -1.62439354544479 - 0.206726589366808*I, -1.62439354544479 + 0.206726589366808*I, -0.872177199759201 - 0.925545835792086*I, -0.872177199759201 + 0.925545835792086*I]??最后,我們可以發(fā)現(xiàn)采用sympy.solve()求解得到的內(nèi)部收益率只有第一個(gè)是實(shí)數(shù),其余全部為復(fù)數(shù),這在我之前的實(shí)踐當(dāng)中也得到了反復(fù)驗(yàn)證,所以可見采用數(shù)值計(jì)算是完全合理科學(xué)高效的。
總結(jié)
以上是生活随笔為你收集整理的用python计算基金内部收益率-基于scipy科学计算库的数值解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pycharm在win7下键盘错乱
- 下一篇: python 简单爬虫获取气象数据发送气