Estoy intentando obtener una curva cero de una serie de tipos OIS basados en EONIA con Quantlib. Al comparar mi resultado con el de Bloomberg, encuentro algunas diferencias (ver al final de la pregunta), y no consigo encontrar lo que estoy haciendo mal (Es la primera vez que hago bootstraping de tasas OIS).
He consultado la documentación de Quantlib y he intentado seguir su método sin suerte. Entonces, si alguien detecta dónde puede estar el problema y me lo hace saber, ¡estaría súper agradecido!
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)
A continuación, los tipos al contado que obtengo, comparados con los que se encuentran en 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