收益率曲线(Yield Curve)是显示一组货币和信贷风险均相同,但期限不同的债券或其他金融工具收益率的图表。纵轴代表收益率,横轴则是距离到期的时间。在此用python建模分析零息票收益率曲线,输出图表并制图。
首先要理解收益率的计算方法,然后计算出连续复利和复利。再根据计算步骤在python中编写代码建模
此为连续复利的计算
# 没有年息票的一年期以内的零息票年收益率YTM=(log(面值/价格))/期限 r1 = np.log(100/97.5)/0.25 r2 = np.log(100/94.9)/0.5 r3 = np.log(100/90)/1 print('第0.25年年息票收益率:',round(r1,5)) print('第0.5年年息票收益率:',round(r2,5)) print('第1年年息票收益率:',round(r3,5))
#每半年付息一次的有年息票的零息票年收益率YTM:零息票年收益率=[log((年息票/2+面值)/(债券价格-年息票/2*(前期价格/面值)))]/期限 #价格=(年息票/2)*e^(-r2*0.5)+(年息票/2)*e^(-r3*1)+(年息票/2+面值)*e^(-r4*1.5) # r4=[log(104/(94-(94.9+90)/100)]/1.5 #超过一年期的零息票年收益率YTM=(面值/价格)开期限n的次方根减1 rate2 = math.pow(100 / 84.99, float(1) / float(3))-1 print(rate2) # 96=4*(1+0.5*r2)^-1+4*(1+r3)^-1+104*(1+r4)^-1.5 r4 = np.log(104/88.604)/1.5 print('第1.5年年息票收益率:',round(r4,5)) r5 = np.log(106/(101.6-(1.849*6+88.604/104*6)))/2#np.log(106/85.394)/2 print('第2年年息票收益率:',round(r5,5))
#线性插值 #第0.75年年息票收益率: r6 = (r2+r3)/2 print('第0.75年年息票收益率:',round(r6,5)) #第1.25年年息票收益率: 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))
1.我们需要在python中加载相应的模块来进行开发调式
import pandas as pd import numpy as np import matplotlib.pyplot as plt import math import os import operator import sys#实现从程序外部向程序传递参数。 import xlrd
2.确定输入及输出的文件路径,读取文件
InputPath=sys.argv[1]#输入路径 OutputPath=sys.argv[2]#输出路径 filePath = InputPath#处理的文件为在输入路径中读取的文件
3.明确表中的字段,定义两个空字典输出计算的数值
上表为输入表,根据表中的字段来计算收益率,Period为付息频率,我们需要取CouponFrequency中的最大值来进行计算
df = pd.read_excel(filePath) bondsCount = df.shape[0] dicE4Calc = {}#定义一个空的价格比计算表。价格/面值 dicResult = {}#定义一个空的结果表 Period = 1 / df['CouponFrequency'].max()#步长为0.5
4.定义一个价格合计,根据这个合计来进行迭代计算
def getPreSum(pCoupon, targetTerm, startTerm):#前期价格合计 sum = 0 p = startTerm while (p < targetTerm):#要小于目标的期限 sum += dicE4Calc[str(p)] * pCoupon p += Period#期限以0.5递增 return sum#返回的是新计算出来的价格
5.定义线性插值法计算,利用前后两期数据可以求出中间的值
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
6.读取表格
df['Coupon']=df['Coupon'].fillna(0)#若Coupon为空值则填充为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
7.计算有年息和无年息的收益率
if Coupon == 0: e4Calc = Price / FaceValue YTM = math.log(FaceValue / Price) / Term 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 = math.log(1 / e4Calc) / Term dicE4Calc[str(Term)] = e4Calc dicResult[str(Term)] = round(YTM, 9)
8.把计算结果写到输出表中
sorted_dicResult = sorted(dicResult.items(),key =operator.itemgetter(0))#把求出的收益率按期限排序,把字典转为列表 # print(dicResult) print(sorted_dicResult) Term = [i[0] for i in sorted_dicResult ]#遍历列表中的期限 Yield = [i[1] for i in sorted_dicResult ]#遍历列表中的 data={"Term":Term,"Yield":Yield} columns=['Term','Yield'] df=pd.DataFrame(data=data,columns=columns) df['TermBase']='Y' df = df.set_index("TermBase") df.to_excel(OutputPath,sheet_name='OutPut') print(df)
9.绘制出收益率曲线图
x = Term y = Yield plt.plot(x,y) plt.xlabel('CouponFrequency')#期限 plt.ylabel('YTM')#收益率 plt.title('Zero coupon yield curve')#命名 plt.show()
最终结果如下:
复利的计算也类似,完整代码如下:
#复利计算 import pandas as pd import numpy as np import matplotlib.pyplot as plt import math import os import operator import sys import xlrd from openpyxl import Workbook from openpyxl import load_workbook from openpyxl.utils import get_column_letter from openpyxl.compat import range InputPath=sys.argv[1] OutputPath=sys.argv[2] print(InputPath) print(OutputPath) filePath = InputPath df = pd.read_excel(filePath) bondsCount = df.shape[0] dicE4Calc = {} dicResult = {} Period = 0.5 def getPreSum(pCoupon, targetTerm, startTerm): sum = 0 p = startTerm while (p < targetTerm): sum += dicE4Calc[str(p)] * pCoupon p += Period return sum def LinearInterpolation(pCoupon, targetTerm, interval): sum = 0 p = interval while p < targetTerm: if str(p) not in dicResult: 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) 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) p += interval Period = 1 / df['CouponFrequency'].max() 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 else: PeriodCoupon = Coupon * Period if Term % Period == 0: LinearInterpolation(PeriodCoupon, Term, Period) e4Calc = (Price - getPreSum(PeriodCoupon, Term, Period)) / (FaceValue + PeriodCoupon) else: 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, 9) # print(dicE4Calc) # print(dicResult) sorted_dicResult = sorted(dicResult.items(),key =operator.itemgetter(0)) # print(dicResult) print(sorted_dicResult) Term = [i[0] for i in sorted_dicResult ] Yield = [i[1] for i in sorted_dicResult ] data={"Term":Term,"Yield":Yield} columns=['Term','Yield'] df=pd.DataFrame(data=data,columns=columns) df['TermBase']='Y' df = df.set_index("TermBase") df.to_excel(OutputPath,sheet_name='OutPut') print(df) x = Term y = Yield plt.plot(x,y) plt.xlabel('CouponFrequency') plt.ylabel('YTM') plt.title('Zero coupon yield curve') plt.show()