【手把手教你】Python金融財務分析
內容來自:微信公眾號:python金融量化
關注可瞭解更多的金融與Python乾貨。
內容目錄
- 貨幣時間價值
- 年金計算
- 實際利率
- 專案投資分析
- 單利與複利增長
關於CuteHand
1. 貨幣時間價值
實際上numpy和scipy很強大,包含了計算各種財務指標的函式,可以直接呼叫,終值(fv)、現值(pv)、淨現值(npv)、每期支付金額(pmt)、內部收益率(irr)、修正內部收益率(mirr)、定期付款期數(nper)、利率(rate)等等。
其中,PV為現值,FV為終值;C為現金流,r貼現率,n期限。
2. 年金計算
在n個時期內,每個時期可以獲得等額現金流PMT,利率為r,以下是考試筆算時的公式:
普通年金現值:
普通年金終值:
永續債券現值:
其中,c為未來每期可以獲得的現金收入,g是c的固定增長率。
年金計算比較簡單,相當於等比數列求和。
#自定義計算一系列現金流現值(如年金)的函式 def pv_f(c,r,n,when=1): ''' c代表每期現金流,可以每期不一樣, 如c=[100,90,80,120], r貼現率,也可以每期不一樣,如相應的, r=[2%,3%,2%,4%], n為期數, when=1表示期末計數,預設,即普通年金 when=0表示期初計數,即預付年金 ''' import numpy as np #匯入numpy庫 c=np.array(c) r=np.array(r) if when==1: n=np.arange(1,n+1) else: n=np.arange(0,n) pv=c/(1+r)**n return pv.sum()
應用例項1: 有個五年的普通年金年金,每年可獲得20000元,假設貼現率為5%,現值是多少?
擴充套件:如果是預付年金呢?
c=20000 r=0.05 n=5 #呼叫前文定義的函式pv_f(c,r,n,when=1) pv1=pv_f(c,r,n,when=1) print("普通年金現值(年末):%.2f"% pv1) #如果是預付年金,則when=0 pv2=pv_f(c,r,n,when=0) print("預付年金現值(年初):%.2f" % pv2) 普通年金現值(年末):86589.53 預付年金現值(年初):90919.01 #使用上2.年金計算公式驗證下我們自定義函式是否正確 pv1=20000/0.05*(1-1/(1+0.05)**5) print("使用計算公式計算(年末): {:.2f}" .format(pv1)) pv2=20000/0.05*(1-1/(1+0.05)**5)*(1+0.05) print("使用計算公式計算(年初): {:.2f}" .format(pv2)) #使用numpy自帶函式驗證 import numpy as np print("numpy自帶公式計算(年末):{:.2f} ".format(np.pv(r,5,-c),when=0)) print("numpy自帶公式計算(年初):{:.2f} ".format(np.pv(r,5,-c,when=1))) #結果一致 使用計算公式計算(年末):86589.53 使用計算公式計算(年初):90919.01 numpy自帶公式計算(年末):86589.53 numpy自帶公式計算(年初):90919.01
如果要計算一系列現金流的終值呢?
#自定義終值函式
def fv_f(c,r,n,when=1):
import numpy as np
c=np.array(c)
r=np.array(r)
if when==1:
n=sorted(np.arange(0,n),
reverse=True) #注意n與pv裡的n不一樣
else:
n=sorted(np.arange(1,n+1),
reverse=True)
fv=c*(1+r)**n
return fv.sum()
#可以將二者合成一個函式,直接輸出現值和終值
def pv_fv(c,r,n,when=1,fv=0):
'''
c,r,n引數同上;
when用來判斷期初還是期末現金流,預設期末
fv判斷求現值還是終值,預設是現值
'''
import numpy as np
c=np.array(c)
r=np.array(r)
if fv==0:
if when==1:
n=np.arange(1,n+1)
else:
n=np.arange(n)
pv=c/(1+r)**n
return pv.sum()
else:
if when==1:
n=sorted(np.arange(0,n),
reverse=True)
else:
n=sorted(np.arange(1,n+1),
reverse=True)
fv=c*(1+r)**n
return fv.sum()
應用例項2:未來五年年末分別收到100、200、300、100、500元,每年貼現率分別為4%、5%、6%、8%和10%,求現值和終值。
c=[100,200,300,100,500]
r=[0.04,0.05,0.06,0.08,0.10]
n=5
pv1=pv_f(c,r,n) #預設when=1可不寫
pv2=pv_fv(c,r,n) #預設when=1,fv=0,
fv1=fv_f(c,r,n) #統一函式下
fv2=pv_fv(c,r,n,fv=1) #統一函式下
print("現值:%.2f元; %.2f元" % (pv1,pv2))
print("終值:%.2f元; %.2f元" % (fv1,fv2))
現值:913.41元; 913.41元
終值:1293.59元; 1293.59元
已知現值或終值,利率和時期,求每期支出或收入現金流呢?
#定義一個計算每期現金流的函式
def pmt(r,n,pv=0,fv=0,when=1):
import numpy as np
pv=np.array(pv)
fv=np.array(fv)
r=np.array(r)
if fv==0:
if when==1:
n=np.arange(1,(n+1))
else:
n=np.arange(n)
pv_pmt=pv/(1/(1+r)**n).sum()
return pv_pmt
else:
if when==1:
n=sorted(np.arange(0,n),
reverse=True)
else:
n=sorted(np.arange(1,n+1),
reverse=True)
fv_pmt=fv/((1+r)**n).sum()
#知道終值求每期現金流
return fv_pmt
應用例項3:假設向某銀行貸款200萬元買房,貸款利率5.0%,按月還款,30年還清本息,請問每月應該還多少錢?
pv=2000000
r=0.05/12
n=30*12
pmt1=pmt(r,n,pv) #套用上面公式
#numpy自帶公式計算
pmt2=np.pmt(r,n,pv,fv=0,when='end')
print("自定義函式計算:%.2f元" % pmt1)
print("numpy自帶公式計算:%.2f元"% pmt2)
#負號代表現金流支出
自定義函式計算:10736.43元
numpy自帶公式計算:-10736.43元
應用例項3擴充套件:假設計息利率調整一次,前15年利率保持5%,後15年利率上調到6%。可以理解為:假設前15年每月按照10736元還款,後15年如果利率上升到6%,應該每月還多少?
c0=10736
n0=n1=15*12
r0=0.05/12
r1=0.07/12
pv0=pv_f(c0,r0,n0) #每月還10736,還15現值
pv1=pv-pv0 #還完15年後剩餘還款現值
pv2=pv1*(1+0.05)**15 #轉化成15年後的終值
pmt1=pmt(r1,n1,pv2) #以6%利率接著還剩下的15年
print("後15年每年應還款金額:%.2f元" % pmt1)
後15年每年應還款金額:12003.44
應用例項4:假設計劃15年後要給小孩準備一筆300萬元的留學資金,投資收益率為8%,請問從現在開始每月需要投入多少錢?
fv=3000000
r=0.08/12
n=15*12
#使用自定義公式
pmt1=pmt(r,n,fv=fv,when=0)
#使用numpy自帶公式
pmt2=np.pmt(r,n,pv=0,fv=fv,when='begin')
print("自定義函式計算:%.2f元" % pmt1)
print("numpy自帶公式計算:%.2f元"% pmt2)
#可見如果每年投資收益率可以達到8%,
#每月只需投資8612.15元,15年後就可以收到300萬元啦
#問題是普通工人大眾很難持續獲得8%/年的投資收益率,
#一般是放銀行定期,5年以上5%以內
pmt3=pmt(0.05/12,n,fv=fv,when=0)
#每月投資支出增加
p=(pmt3-pmt1)/pmt1
print("假設利率為5%情況:{0:.2f}元,
每月支出增加比例:{1:.2f} %".format(pmt3,p*100))
#如果考慮通貨膨脹,實際也沒多少收益率了
自定義函式計算:8612.15元
numpy自帶公式計算:-8612.15元
假設利率為5%情況:11177.24元,
每月支出增加比例:29.78 %
3. 實際利率
其中,EAR為實際年利率(effective annual rate);AP為名義年利率(Annual Percentage Rate);m是一年內複利的頻率。
連續複利(Continuously compounded interest rate)
知識回顧
名義利率與實際利率跟通脹率對應的名義利率不同。實際利率是什麼呢?
情景一:年初存入銀行100塊錢,銀行承諾利率12%。於是年末能拿到112塊錢。這裡的12塊錢就是利息,12%就是實際利率。
情景二:年初存入銀行100塊錢,銀行承諾利率12%。聰明的人發現一個漏洞(假設半年就是12%/2),銀行承諾12%,也就是半年利率可記為6%。然後當存入100塊半年後,取出來106塊錢,接著轉身去另一個櫃員處存入106塊半年,期末將得106*(1+6%)=112.36白白多得3毛6。這裡的實際利率就是12.36%。
情景三:年初存入銀行100塊錢,銀行承諾利率12%。更加聰明的人把100塊錢存取了三次,就是100*(1+4%)^3=112.4864比聰明的人還多得1毛2分6釐4。此時的實際利率是12.4864%。
【這裡銀行承諾的就是名義利率,而實際所得的是實際利率。(當然現實生活中的商業銀行會把半年利率調低,而不是單純的用一年的利率除以期數。)而後面兩種情景的計息方式為 複利。俗稱利滾利。不要以為利滾利就能滾上天,有一個條件限制住了它,叫名義利率。隨著存取次數的不斷增加,每一個期數內的利率也在逐漸減小。現在把計息次數擴大到∞,實際利率就變成了(1+12%/∞)∞,而這玩意計算出來就是e12%。這就是所謂的連續複利。】
4. 專案投資分析
金融財務分析裡關於專案投資分析判斷的方法有很多,比較常用的有淨現值、回收期、內部收益率法等。
淨現值法 (Net present value,NPV)
專案投資NPV法判斷依據:
def npv_f(rate,cashflows):
total=0.0
for i, cashflow in enumerate(cashflows):
total+=cashflow/(1+rate)**i
return total
回收期法(Payback period)
與淨現值法相比,優點是簡單易懂,缺點:
不考慮時間價值
基準回收期的確定比較主觀
內部收益率法(IRR)
IRR:使得淨現值為0的貼現率。
def IRR_f(cashflows,interations=10000):
rate=1.0
inv=cashflows[0]
for i in range(1,interations+1):
rate*=(1-npv_f(rate,cashflows)/inv)
return rate
應用例項5:假設貼現率為5%,有A、B兩個專案,前期均需投入120萬, A專案第一年至五年分別收入10、30、50、40、10萬,而專案B第一至五年分別收入30、40、40、20、10萬,專案A和B哪個投資價值高?
#分析:如果光從金額看都是投資120萬元,
#回報都是140萬元,
#從回收期法來看,二者都是在第四年才收回成本
#但由於貨幣的時間價值,下面從淨現值的角度進行分析
r=0.05
C_A=[-120, 10, 30, 50, 40, 10]
C_B=[-120, 30, 40, 40, 20, 10]
npv_A=npv_f(r,C_A)
npv_B=npv_f(r,C_B)
print("專案A的淨現值:%.2f萬元" % npv_A)
print("專案B的淨現值:%.2f萬元" % npv_B)
專案A的淨現值:0.67萬元
專案B的淨現值:3.70萬元
#內部收益率法比較
irr_A=IRR_f(C_A,interations=10000)
irr_B=IRR_f(C_B,interations=10000)
print("專案A的內部收益率:%.2f%%" % (irr_A*100))
print("專案B的內部收益率:%.2f%%" % (irr_B*100))
專案A的內部收益率:5.19%
專案B的內部收益率:6.28%
NPV與IRR比較
NPV:優點:計算相對簡便易懂,結果直觀,容易理解;侷限性:沒有消除初始投資額不同的差異,也沒有消除投資專案期限的差異。
IRR:優點:跟NPV比較消除了初始投資額不同和專案投資期限的差異,直觀反映專案本身的報酬率;缺點是計算量大,可能存在多解或無解。
淨現值和內部收益率適用範圍不同,淨現值適用於互斥方案間的擇優,而內部收益率用於獨立方案間的擇優。
應用例項6:有專案C、D,一次性投入均為100萬元,其中,C專案前六年無現金流入,第7年現金流入200萬;D專案前六年每年現金流入12萬,最後一年現金流入112萬,選擇哪個?
C=[-100,0,0,0,0,0,200]
D=[-100,12,12,12,12,12,112]
irr_C=IRR_f(C)*100
irr_D=IRR_f(D)*100
print("內部收益率:C專案{0:.0f}%,D專案
{1:.0f}%" .format(irr_C,irr_D))
print("淨現值:C專案{0:.2f}萬元,D專案
{1:.2f}萬元".format(npv_f(0.1,C),
npv_f(0.1,D)))
#請問你會選哪一個呢?
內部收益率:C專案12%,D專案12%
淨現值:C專案12.89萬元,D專案8.71萬元
#應用例項6擴充套件1
E=[-100,90,50,0,0,10]
F=[-100,0,0,0,0,350]
irr_E=IRR_f(E)*100
irr_F=IRR_f(F)*100
print("內部收益率:E專案{0:.0f}%,F專案
{1:.0f}%" .format(irr_E,irr_F))
print("淨現值:E專案{0:.2f}萬元,F專案
{1:.2f}萬元".format(npv_f(0.1,E),
npv_f(0.1,F)))
#你又會選哪一個呢?
內部收益率:E專案31%,F專案28%
淨現值:E專案29.35萬元,F專案117.32萬元
#應用例項6擴充套件2
G=[-100,90,50,0,0,10]
H=[-150,0,50,50,50,150]
irr_G=IRR_f(E)*100
irr_H=IRR_f(F)*100
print("內部收益率:G專案{0:.0f}%,H專案
{1:.0f}%".format(irr_G,irr_H))
print("淨現值:G專案{0:.2f}萬元,H專案
{1:.2f}萬元".format(npv_f(0.1,G),
npv_f(0.1,H)))
#你又會選哪一個呢?
內部收益率:G專案31%,H專案20%
淨現值:G專案29.35萬元,H專案56.18萬元
5. 單利與複利增長
#單利和複利
import numpy as np
%matplotlib inline
from matplotlib import pyplot as plt
#解決中文亂碼
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
pv=1000
r=0.08
n=10
t=np.linspace(0,n,n)
y1=np.ones(len(t))*pv
y2=pv*(1+r*t)
y3=pv*(1+r)**t
plt.figure(figsize=(10,8))
plt.title('單利和複利')
plt.xlabel('年')
plt.ylabel('終值')
plt.xlim(0,11)
plt.ylim(800,2200)
plt.plot(t,y1,'b-')
plt.plot(t,y2,'g--')
plt.plot(t,y3,'r-')