零息票債券是指低于債券面值價格發(fā)行剩胁,債券發(fā)行人不需要給債券持有人支付利息诉植,只用在債券到期日支付給債券持有人債券面值金額的一類債券。本模型研究如何根據選擇的數據生成息票收益率曲線昵观。
數據如圖:
表格數據
一.收益率計算規(guī)則
復利計算
1.無年息票的計算:零息票年收益率YTM=YTM=(面值/價格)^1/期限-1
r1 = pow(100/97.5,1/0.25)-1
r2 = pow(100/94.5,1/0.5)-1
r3 = pow(100/90,1/1)-1
print('第0.25年年息票收益率:',round(r1,5))
print('第0.5年年息票收益率:',round(r2,5))
print('第1年年息票收益率:',round(r3,5))
2.每半年付息一次的有年息票的收益率YTM:
超過一年期的零息票年收益率YTM=(面值/價格)開期限n的次方根減1
零息票年收益率=[(年息票/2+面值)/(債券價格-年息票/2*(前期價格/面值))^1/期限]-1
# 有年息票的計算:
# 1.5年:96=4*e^(-r0.5*0.5)+4*e^(-r1*1)+104*e^(-r1.5*1.5)
# r1.5=log(104/(96-4[e^(-r0.5*0.5)+e^(-r1*1)]))/1.5=0.1068
# 簡化[e^(-r0.5*0.5)+e^(-r1*1)]得到:
# r1.5=[log(104/(96-4*(94.5/100+90/100))]/1.5 連續(xù)復利的算法
# pow(104/((96-(90+94.5)/100*4)),2/3)-1 #復利的算法
rate2 = math.pow(100 / 84.99, float(1) / float(3))-1
print(rate2)
r4 = pow(104/((96-(90+94.5)/100*4)),2/3)-1#pow((104/88.604),2/3)
print('第1.5年年息票收益率:',round(r4,5))
r5 = pow(106/(101.6-(1.849*6+88.604/104*6)),1/2)-1#np.log(106/85.394)/2
print('第2年年息票收益率:',round(r5,5))
3.表中有數據就需要根據給定的數據來計算晾腔,表中沒有數據就需要用到線性插值
#線性插值
#第0.75年年息票收益率在0.5年和1年之間插值:
r6 = (r2+r3)/2
print('第0.75年年息票收益率:',round(r6,5))
#第1.25年年息票收益率在1年和1.5年之間插值:
r7 = (r3+r4)/2
print('第1.25年年息票收益率:',round(r7,5))
#第1.75年年息票收益率:
r8 = (r4+r5)/2
print('第1.75年年息票收益率:',round(r8,5))
#第2.25年年息票收益率:
r9 = 2(r5)/3 +(r'第2.75年年息票收益率')/3
print('第2.25年年息票收益率:',round(r9,5))
二.息票收益率曲線計算的完整代碼
input.csv
import pandas as pd
import numpy as np
df = pd.read_csv("input.csv")
bondsCount = df.shape[0]
dicE4Calc = {} #定義一個空的價格比計算表。價格/面值
dicResult = {} #定義一個空的結果表
#定義一個價格合計啊犬,根據這個合計來進行迭代計算
def getPreSum(pCoupon, targetTerm, startTerm):
#前期價格合計
sum = 0
p = startTerm
while (p < targetTerm): #要小于目標的期限
sum += dicE4Calc[str(p)] * pCoupon
p += Period #期限以0.5遞增
return sum
#定義線性插值法計算灼擂,利用前后兩期數據可以求出中間的值
def LinearInterpolation(pCoupon, targetTerm, interval):
#線性插值法利用中位數求利率
sum = 0
p = interval
while p < targetTerm:
if str(p) not in dicResult: #結果表中沒有的數據,left為前面一期椒惨,right為后面一期
r_Left = str(p - interval)
r_Right = str(p + interval)
if r_Left in dicResult and r_Right in dicResult: #結果表中有前后的數據就用插值法計算
r = (dicResult[r_Left] + dicResult[r_Right]) / 2
elif r_Left in dicResult and r_Right not in dicResult:
r_Left2 = str(p - interval - interval) #left為前2期
r = dicResult[r_Left2] + (dicResult[r_Left] - dicResult[r_Left2]) / (interval) * (p - float(r_Left2))
dicResult[str(p)] = r
dicE4Calc[str(p)] = pow(math.e, -r * p) #e的(-r*p)次方
p += interval
Period = 1 / df['CouponFrequency'].max() #付息頻率步長為0.5
df['Coupon']=df['Coupon'].fillna(0)
for i in range(bondsCount):
FaceValue = df.loc[i, 'FaceValue']
Price = df.loc[i, 'Price']
Term = df.loc[i, 'Term_Y']
Coupon = df.loc[i, 'Coupon']
CouponFrequency = df.loc[i, 'CouponFrequency']
YTM = 0
e4Calc = 0
#計算有年息和無年息的收益率
if Coupon == 0:
e4Calc = Price / FaceValue #價格/面值
YTM = pow(FaceValue / Price,1/ Term) -1 #YTM=(面值/價格)^1/期限-1
else:
PeriodCoupon = Coupon * Period ##年息票的0.5
if Term % Period == 0: #從0.5年開始
LinearInterpolation(PeriodCoupon, Term, Period)
e4Calc = (Price - getPreSum(PeriodCoupon, Term, Period)) / (FaceValue + PeriodCoupon)
else: #不是從0.5開始缤至,需要在起始日期以0.5年遞增
LinearInterpolation(PeriodCoupon, Term, Term % Period)
e4Calc = (Price - getPreSum(PeriodCoupon, Term, Term % Period)) / (FaceValue + PeriodCoupon)
YTM = pow(1 / e4Calc,1/ Term) - 1
dicE4Calc[str(Term)] = e4Calc
dicResult[str(Term)] = round(YTM,6)
sorted_dicResult = sorted(dicResult.items(),key =operator.itemgetter(0))
print(sorted_dicResult)
Term = [i[0] for i in sorted_dicResult ]
Yield = [i[1] for i in sorted_dicResult ]
#數據輸出為DataFrame
data={"Term":Term,"Yield":Yield}
columns=['Term','Yield']
df=pd.DataFrame(data=data,columns=columns)
df['TermBase']='Y'
df = df.set_index("TermBase")
print(df)
#可視化展示
x = Term
y = Yield
plt.plot(x,y)
plt.xlabel('CouponFrequency')
plt.ylabel('YTM')
plt.title('Zero coupon yield curve')
plt.show()