I am trying to get a zero curve from a series of EONIA-based OIS rates with Quantlib. When comparing my output with Bloomberg, I find some differences (see at the end of the question), and and I don't get to find what I am doing wrong (It is my first time bootstraping OIS rates).
I went through the Quantlib documentation, and I tried to follow their method without luck. Then, if someone spots where the problem could be and lets me know, I would be super grateful!
today = ql.Date(22, 9, 2020)
ql.Settings.instance().evaluationDate = today
OIS_rate = [-0.47, -0.472, -0.4755, -0.481, -0.485, -0.489, -0.505, -0.519, -0.54, -0.552, -0.559, -0.5502, -0.5308, -0.5, -0.462, -0.4257, -0.382, -0.337, -0.2435, -0.1385, -0.056, -0.049, -0.078, -0.128, -0.1723]
terms = [1, 2, 3, 4, 5, 6, 9, 12, 18, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 30, 40, 50]
calendar = ql.TARGET()
bussiness_convention = ql.Following
day_count = ql.Actual360()
#Overnigth Rate
depo_facility = -0.5
depo_helper = [ql.DepositRateHelper(ql.QuoteHandle(ql.SimpleQuote(depo_facility/100)), ql.Period(1,ql.Days), 1, calendar, ql.Unadjusted, False, day_count)]
settlement_days_EONIA = 1
EONIA = ql.OvernightIndex("EONIA", settlement_days_EONIA, ql.EURCurrency(),ql.TARGET(), day_count)
# Build OIS helpers
OIS_helpers = []
for i in range(len(terms)):
if i < 8:
coupon_frequency = ql.Once
tenor = ql.Period(terms[i],ql.Months)
rate = OIS_rate[i]
#OIS_helpers.append(ql.SwapRateHelper(ql.QuoteHandle(ql.SimpleQuote(rate/100.0)),tenor, calendar,coupon_frequency, bussiness_convention,day_count,ql.Euribor3M()))
OIS_helpers.append(ql.OISRateHelper(settlement_days_EONIA, tenor, ql.QuoteHandle(ql.SimpleQuote(rate/100)), EONIA))
elif i == 8:
coupon_frequency = ql.Semiannual
tenor = ql.Period(terms[i],ql.Months)
rate = OIS_rate[i]
OIS_helpers.append(ql.OISRateHelper(settlement_days_EONIA, tenor, ql.QuoteHandle(ql.SimpleQuote(rate/100)), EONIA))
else:
coupon_frequency = ql.Semiannual
tenor = ql.Period(terms[i],ql.Years)
rate = OIS_rate[i]
OIS_helpers.append(ql.OISRateHelper(settlement_days_EONIA, tenor, ql.QuoteHandle(ql.SimpleQuote(rate/100)), EONIA))
rate_helpers = depo_helper + OIS_helpers
yieldcurve = ql.PiecewiseLogCubicDiscount(today,rate_helpers,day_count)
spots = []
tenors = []
for d in yieldcurve.dates():
yrs = day_count.yearFraction(today, d)
compounding = ql.Simple
freq = ql.Semiannual
zero_rate = yieldcurve.zeroRate(yrs, compounding, freq)
tenors.append(yrs)
eq_rate = zero_rate.equivalentRate(day_count,compounding,freq,today,d).rate()
spots.append(100*eq_rate)
datatable = {'Dates':yieldcurve.dates(),'Tenors':tenors,'spots':spots}
df = pd.DataFrame.from_dict(datatable)
Hereunder the spot rates I get, compared to those found in Bloomberg <SWDF 133 8>
Tenor Bloomberg Output
1 MO -0.469 -0.47102
2 MO -0.4711 -0.472474
3 MO -0.4747 -0.475779
4 MO -0.4802 -0.48116
5 MO -0.4843 -0.485102
6 MO -0.4884 -0.489064
9 MO -0.5047 -0.504981
12 MO -0.519 -0.518946
18 MO -0.5397 -0.538899
2 YR -0.5519 -0.550289
3 YR -0.5589 -0.555675
4 YR -0.5503 -0.545571
5 YR -0.531 -0.525296
6 YR -0.5006 -0.494237
7 YR -0.463 -0.456508
8 YR -0.4271 -0.420624
9 YR -0.3837 -0.377845
10 YR -0.3391 -0.333913
12 YR -0.2459 -0.242628
15 YR -0.1405 -0.139172
20 YR -0.057 -0.056707
25 YR -0.0497 -0.049446
30 YR -0.0787 -0.077762
40 YR -0.1278 -0.124637
50 YR -0.1705 -0.163544