Swaps

QuantLib Python 掉期收益率曲線自舉日期和到期日

  • November 19, 2016

這與我在這裡提出的問題有些相關,但更簡單。我正在嘗試從掉期引導收益率曲線,並且對即將出現的日期/到期日有問題。我正在使用的程式碼如下,我遇到的問題是當返回結果時,Maturities 欄位與我輸入的期限不匹配。

import QuantLib as ql
from pandas import DataFrame
import matplotlib.pyplot as plt
import csv

def get_spot_rates(yieldcurve, day_count, calendar=ql.UnitedStates(), months=121):
   spots = []
   tenors = []
   ref_date = yieldcurve.referenceDate()
   calc_date = ref_date
   for yrs in yieldcurve.times():
       d = calendar.advance(ref_date, ql.Period(int(yrs*365.25), ql.Days))
       compounding = ql.Compounded
       freq = ql.Semiannual
       zero_rate = yieldcurve.zeroRate(yrs, compounding, freq)
       tenors.append(yrs)
       eq_rate = zero_rate.equivalentRate(day_count,compounding,freq,calc_date,d).rate()
       spots.append(eq_rate*100)
   return DataFrame(list(zip(tenors, spots)),columns=["Maturities","Curve"],index=['']*len(tenors))

swap_maturities = [ql.Date(9,9,2016),
ql.Date(15,9,2016),
ql.Date(22,9,2016),
ql.Date(29,9,2016),
ql.Date(11,10,2016),
ql.Date(9,11,2016),
ql.Date(8,12,2016),
ql.Date(10,1,2017),
ql.Date(8,2,2017),
ql.Date(8,3,2017),
ql.Date(8,6,2017),
ql.Date(8,9,2017),
ql.Date(8,3,2018),
ql.Date(10,9,2018),
ql.Date(10,9,2019),
ql.Date(10,9,2020),
ql.Date(9,9,2021),
ql.Date(8,9,2022),
ql.Date(8,9,2023),
ql.Date(10,9,2024),
ql.Date(10,9,2025),
ql.Date(10,9,2026),
ql.Date(8,9,2028),
ql.Date(10,9,2031),
ql.Date(10,9,2036),
ql.Date(10,9,2041),
ql.Date(10,9,2046),
ql.Date(8,9,2056)
]

swap_periods = [ql.Period(1,ql.Days),
ql.Period(1,ql.Weeks),
ql.Period(2,ql.Weeks),
ql.Period(3,ql.Weeks),
ql.Period(1,ql.Months),
ql.Period(2,ql.Months),
ql.Period(3,ql.Months),
ql.Period(4,ql.Months),
ql.Period(5,ql.Months),
ql.Period(6,ql.Months),
ql.Period(9,ql.Months),
ql.Period(1,ql.Years),
ql.Period(18,ql.Months),
ql.Period(2,ql.Years),
ql.Period(3,ql.Years),
ql.Period(4,ql.Years),
ql.Period(5,ql.Years),
ql.Period(6,ql.Years),
ql.Period(7,ql.Years),
ql.Period(8,ql.Years),
ql.Period(9,ql.Years),
ql.Period(10,ql.Years),
ql.Period(12,ql.Years),
ql.Period(15,ql.Years),
ql.Period(20,ql.Years),
ql.Period(25,ql.Years),
ql.Period(30,ql.Years),
ql.Period(40,ql.Years)
]

swap_rates = [0.37,
0.4025,
0.4026,
0.399,
0.3978,
0.4061,
0.41,
0.4155,
0.4273,
0.4392,
0.461,
0.4805,
0.5118,
0.538,
0.587,
0.638,
0.7,
0.756,
0.818,
0.865,
0.913,
0.962,
1.045,
1.137,
1.2355,
1.281,
1.305,
1.346
]

""" Parameter Setup """
calc_date = ql.Date(1,9,2016)
ql.Settings.instance().evaluationDate = calc_date
calendar = ql.UnitedStates()
bussiness_convention = ql.ModifiedFollowing
day_count = ql.Actual360()
coupon_frequency = ql.Annual

""" SwapRateHelper """
swap_helpers = []
for rate,tenor in list(zip(swap_rates,swap_periods)):


swap_helpers.append(ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100.0)),
       tenor, calendar,
       coupon_frequency, bussiness_convention,
       day_count,
       ql.Euribor3M()))

rate_helpers = swap_helpers
yc_linearzero = ql.PiecewiseLinearZero(calc_date,rate_helpers,day_count)
yc_cubiczero = ql.PiecewiseCubicZero(calc_date,rate_helpers,day_count)

max_maturity = 40*12

splz = get_spot_rates(yc_linearzero, day_count, months=max_maturity + 1)
spcz = get_spot_rates(yc_cubiczero, day_count, months=max_maturity + 1)

max_rate = swap_rates[-1]
min_rate = min(splz.Curve)
max_rate = max(splz.Curve)

"""Plotting"""
plt.plot(splz["Maturities"],splz["Curve"],'--', label="LinearZero")
plt.plot(spcz["Maturities"],spcz["Curve"],label="CubicZero")
plt.xlabel("Years", size=12)
plt.ylabel("Zero Rate", size=12)
plt.xlim(0,max_maturity/12.0)
plt.ylim([min_rate * 0.9,max_rate * 1.1])
plt.legend()

plt.show()

rows = zip(splz.Maturities,splz.Curve)

with open('OISBootstrap.csv','w',newline='') as f:
   writer = csv.writer(f)
   for row in rows:
       writer.writerow(row)

任何使用 Python 和 QL 的人都可以執行整個程序並查看結果,但例如,我得到最後五個到期日的以下值:15.2361111111、20.3111111111、25.3777777778、30.45、40.5972222222 而不是 15、20、25、30,和 40。

提前感謝我認為是一個非常新的問題。

根據您告訴曲線使用的日期計數器,15 年確實對應於 t=15.236。

首先,無論如何你都不能準確地得到 15。您的計算日期為 2016 年 9 月 1 日;根據通常的慣例,您所報價的掉期利率從即期開始,即計算日期後的兩個工作日。考慮到週末(您的計算日期是星期四)和勞動節(9 月 4 日)的假期,您將在 9 月 6 日登陸。因此,15 年期互換將於 2031 年 9 月 6 日到期;但那是星期六,所以它滾動到 2031 年 9 月 8 日(另外,您的輸入到期日是 9 月 10 日,所以您可能也想檢查一下)。那是您的計算日期之後的 15 年零一周,對於您的曲線也是 t=0(因為您將它作為參考日期傳遞給它的建構子)。

第二:您將實際/360 的天數約定傳遞給曲線,其中一年不對應於 1,而是對應於 365/360=1.01389(或閏年的 366/360)。

綜上所述,計算日期和 15 年互換到期之間的 5485 天對應於 5485/360=5.23611。類似的計算適用於其他期限。

使用 Actual/365 (Fixed) 可以使結果更接近您的預期,因為它對應於“正常”年份的 t=1;但由於閏年對應 366/365,你仍然得到 t=5485/365=15.0274。

其他日計數器具有更好的計算利率的屬性(例如,Act/Act 為您提供 1 年的 t=1),但我不建議在期限結構中使用它們,因為它們缺乏其他屬性;例如,存在成對的日期 $ d_1 $ 和 $ d_2 $ 時間 $ T(d_1,d_2) $ 它們之間是 0,或三倍 $ d_1 $ , $ d_2 $ , $ d_3 $ 為此 $ T(d_1,d_3) \neq T(d_1,d_2) + T(d_2,d_3) $ .

相反,我建議您直接使用日期。在您的get_spot_rates函式中,而不是嘗試將到期日期重新計算為

d = calendar.advance(ref_date, ql.Period(int(yrs*365.25), ql.Days))

call yieldcurve.nodes(),它為您提供與每個到期日對應的對 (date,rate) 列表。您可以在對 的呼叫中使用這些日期equivalentRate,就像您已經做的那樣,也可以在對 的呼叫中使用這些日期yieldcurve.zeroRate

(順便說一句,calendar.advance(ref_date, 365, Days)不會像你想的那樣做。它將日期提前 365工作日,比一年多得多。)

引用自:https://quant.stackexchange.com/questions/31073