零息票收益率曲线

零息票债券是指低于债券面值价格发行,债券发行人不需要给债券持有人支付利息,只用在债券到期日支付给债券持有人债券面值金额的一类债券。本模型研究如何根据选择的数据生成息票收益率曲线。
数据如图:


表格数据

一.收益率计算规则

复利计算

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    连续复利的算法
# 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()

你可能感兴趣的:(零息票收益率曲线)