The program
First, for the sake of brevity, required market data (Eonia rates) has been hard-coded into map container. Then, container will be iterated through for constructing all required rate helpers. After this, piecewise yield term structure will be created by using constructed rate helpers. Finally, an equally-spaced time grid (monthly) will be created and discount factors are requested from bootstrapped Eonia curve for each grid time point (screenshot below). The curve itself (eurOisCurve) could now be used as a discounting curve in a dual-curve valuation scheme in QuantLib.
Thanks for reading this blog.
-Mike
#include <iostream> #include <ql\quantlib.hpp> #include <algorithm> #include <map> using namespace QuantLib; int main() { try { // create common data Date today(7, Jul, 2017); DayCounter dayCounter = Actual360(); Calendar calendar = TARGET(); Date settlementDate = calendar.advance(today, Period(2, Days)); Natural settlementDays = settlementDate - today; Settings::instance().evaluationDate() = today; // create overnight index for euro currency auto eoniaIndex = boost::make_shared<Eonia>(); // create container for rate helpers std::vector<boost::shared_ptr<RateHelper>> rateHelpers; // create first 1d cash instrument for eonia curve - using deposit rate helper auto Q1D = boost::make_shared<SimpleQuote>(-0.0036); rateHelpers.push_back(boost::make_shared<DepositRateHelper> (Handle<Quote>(Q1D), Period(1, Days), eoniaIndex->fixingDays(), eoniaIndex->fixingCalendar(), eoniaIndex->businessDayConvention(), eoniaIndex->endOfMonth(), eoniaIndex->dayCounter())); // create source data for eonia curve (period, rate) std::map<Period, Real> eoniaCurveData; eoniaCurveData.insert(std::make_pair(Period(1, Weeks), -0.00358)); eoniaCurveData.insert(std::make_pair(Period(2, Weeks), -0.00357)); eoniaCurveData.insert(std::make_pair(Period(3, Weeks), -0.00356)); eoniaCurveData.insert(std::make_pair(Period(1, Months), -0.00358)); eoniaCurveData.insert(std::make_pair(Period(2, Months), -0.00358)); eoniaCurveData.insert(std::make_pair(Period(3, Months), -0.00358)); eoniaCurveData.insert(std::make_pair(Period(4, Months), -0.00357)); eoniaCurveData.insert(std::make_pair(Period(5, Months), -0.00356)); eoniaCurveData.insert(std::make_pair(Period(6, Months), -0.00353)); eoniaCurveData.insert(std::make_pair(Period(7, Months), -0.00351)); eoniaCurveData.insert(std::make_pair(Period(8, Months), -0.00349)); eoniaCurveData.insert(std::make_pair(Period(9, Months), -0.00344)); eoniaCurveData.insert(std::make_pair(Period(10, Months), -0.0034)); eoniaCurveData.insert(std::make_pair(Period(11, Months), -0.00336)); eoniaCurveData.insert(std::make_pair(Period(1, Years), -0.00331)); eoniaCurveData.insert(std::make_pair(Period(15, Months), -0.00314)); eoniaCurveData.insert(std::make_pair(Period(18, Months), -0.00295)); eoniaCurveData.insert(std::make_pair(Period(21, Months), -0.00273)); eoniaCurveData.insert(std::make_pair(Period(2, Years), -0.00248)); eoniaCurveData.insert(std::make_pair(Period(3, Years), -0.00138)); eoniaCurveData.insert(std::make_pair(Period(4, Years), -0.0001245)); eoniaCurveData.insert(std::make_pair(Period(5, Years), 0.0011945)); eoniaCurveData.insert(std::make_pair(Period(6, Years), 0.00254)); eoniaCurveData.insert(std::make_pair(Period(7, Years), 0.00387)); eoniaCurveData.insert(std::make_pair(Period(8, Years), 0.0052)); eoniaCurveData.insert(std::make_pair(Period(9, Years), 0.006474)); eoniaCurveData.insert(std::make_pair(Period(10, Years), 0.007634)); eoniaCurveData.insert(std::make_pair(Period(11, Years), 0.00868)); eoniaCurveData.insert(std::make_pair(Period(12, Years), 0.0096045)); eoniaCurveData.insert(std::make_pair(Period(15, Years), 0.0117245)); eoniaCurveData.insert(std::make_pair(Period(17, Years), 0.0126797)); eoniaCurveData.insert(std::make_pair(Period(20, Years), 0.0136245)); eoniaCurveData.insert(std::make_pair(Period(25, Years), 0.01441)); eoniaCurveData.insert(std::make_pair(Period(30, Years), 0.01479)); // create other instruments for eonia curve - using ois rate helper std::for_each(eoniaCurveData.begin(), eoniaCurveData.end(), [settlementDays, &rateHelpers, &eoniaIndex](std::pair<Period, Real> p) -> void { rateHelpers.push_back(boost::make_shared<OISRateHelper>(settlementDays, p.first, Handle<Quote>(boost::make_shared<SimpleQuote>(p.second)), eoniaIndex)); }); // create piecewise term structure Handle<YieldTermStructure> eurOisCurve(boost::make_shared<PiecewiseYieldCurve<Discount, LogLinear>> (settlementDays, eoniaIndex->fixingCalendar(), rateHelpers, eoniaIndex->dayCounter())); // create equally-spaced (monthly) time grid Time maturity = 30.0; Size steps = 360; TimeGrid grid(maturity, steps); // print monthly discount factors std::for_each(grid.begin(), grid.end(), [&eurOisCurve](Time t) -> void { std::cout << eurOisCurve->discount(t) << std::endl; }); } catch (std::exception& e) { std::cout << e.what() << std::endl; } return 0; }
Hi Mikael, had a quick doubt which I hoped you could help me understand it, as it may be just a rookie type of doubt. Does the OIS rate helper take into account the different conventions of the OIS instruments respective to their tenor. Per example, as I understand, above 1y, OIS are priced as swaps. So does the rate helper take into account this vs the <1y which can be priced as zero coupon bonds?
ReplyDeleteI am constructing the OIS curve, where the Index is the FED Funds. Does the following appears correct to you?
Kind regards,
Luis Aguiar
PS: Its in Python
OIS_tenors = [ql.Period(1, ql.Weeks), ql.Period(2, 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(7, ql.Months),
ql.Period(8, ql.Months), ql.Period(9, ql.Months), ql.Period(10, ql.Months),
ql.Period(11, 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)]
OIS_bid_offer_rates = [(0.039, 0.067), (0.043, 0.063),
(0.045, 0.060), (0.048, 0.058),
(0.047, 0.057),(0.044, 0.055),
(0.042, 0.052), (0.039, 0.052),
(0.038, 0.048), (0.036, 0.047),
(0.033, 0.047), (0.032, 0.042),
(0.029, 0.041), (0.030, 0.040),
(0.017, 0.027), (0.014, 0.025),
(0.030, 0.040), (0.052, 0.102),
(0.109, 0.159), (0.170, 0.220),
(0.236, 0.286), (0.316, 0.326),
(0.344, 0.394), (0.388, 0.438),
(0.479, 0.529), (0.556, 0.606),
(0.643, 0.693), (0.673, 0.723),
(0.703, 0.713)]
OIS_rates = []
for i in OIS_bid_offer_rates:
OIS_rates.append((i[0]+i[1])/2)
OIS_data = []
for i in range(len(OIS_rates)):
OIS_data.append([OIS_rates[i], OIS_tenors[i]])
cal = ql.TARGET()
today = ql.Date(11,9,2009)
settlementDays = 2
dc = ql.Actual360()
settlement = cal.advance(today, settlementDays, ql.Days)
ql.Settings.instance().evaluationDate = today
FedFunds = ql.FedFunds()
helper = [ql.OISRateHelper(settlementDays, tenor, ql.QuoteHandle(ql.SimpleQuote(rate/100)), FedFunds)
for rate, tenor in OIS_data]
OIS_curve = ql.PiecewiseLogCubicDiscount(0, cal, helper, ql.Actual365Fixed())