Last active
June 11, 2018 16:46
-
-
Save tomwhoiscontrary/38ee94f22e1a13428fa1d8d5868317ca to your computer and use it in GitHub Desktop.
Trying to make a curve by blending futures and swaps - see https://imgur.com/a/viMGk6J
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <boost/make_shared.hpp> | |
#include <ql/indexes/ibor/euribor.hpp> | |
#include <ql/math/interpolations/convexmonotoneinterpolation.hpp> | |
#include <ql/termstructures/yield/piecewiseyieldcurve.hpp> | |
#include <ql/termstructures/yield/ratehelpers.hpp> | |
#include <ql/time/daycounters/actual360.hpp> | |
#include <ql/time/daycounters/thirty360.hpp> | |
#include <ql/types.hpp> | |
using QuantLib::Actual360; | |
using QuantLib::BusinessDayConvention; | |
using QuantLib::ConvexMonotone; | |
using QuantLib::Date; | |
using QuantLib::DayCounter; | |
using QuantLib::Euribor; | |
using QuantLib::ForwardRate; | |
using QuantLib::Frequency; | |
using QuantLib::FuturesRateHelper; | |
using QuantLib::Handle; | |
using QuantLib::IborIndex; | |
using QuantLib::InterpolatedForwardCurve; | |
using QuantLib::Month; | |
using QuantLib::Period; | |
using QuantLib::PiecewiseYieldCurve; | |
using QuantLib::Quote; | |
using QuantLib::RateHelper; | |
using QuantLib::Real; | |
using QuantLib::Settings; | |
using QuantLib::SwapRateHelper; | |
using QuantLib::Thirty360; | |
using QuantLib::TimeUnit; | |
using QuantLib::YieldTermStructure; | |
Month mth(unsigned int monthNumber) { return static_cast<Month>(monthNumber); } | |
class NeutralConvexMonotone : public ConvexMonotone { | |
public: | |
NeutralConvexMonotone(Real quadraticity = 0.3, Real monotonicity = 0.7, bool forcePositive = false) | |
: ConvexMonotone(quadraticity, monotonicity, forcePositive) {} | |
}; | |
/* | |
In the shell: | |
blend > blend.csv | |
gnuplot | |
In gnuplot: | |
set datafile separator "," | |
set key autotitle columnhead | |
set xdata time | |
set timefmt '%Y-%m-%d' | |
set format x '%Y-%m-%d' | |
plot "tmp/blend.csv" using 1:2 with lines, \ | |
"tmp/blend.csv" using 1:3 with lines, \ | |
"tmp/blend.csv" using 1:4 with lines | |
*/ | |
int main(int argc, char** argv) { | |
Period blendGap = Period(argc > 1 ? std::stoi(argv[1]) : 0, TimeUnit::Months); | |
Date today = Date(11, Month::June, 2018); | |
Settings::instance().evaluationDate() = today; | |
DayCounter curveDayCounter = Actual360(); | |
// DISCOUNTING CURVE | |
std::map<Date, double> discountingCurveNodes = | |
{{Date(11, mth(6), 2018), -0.00355584210537288}, {Date(20, mth(6), 2018), -0.00355584210537288}, | |
{Date(13, mth(7), 2018), -0.00354847355117201}, {Date(13, mth(9), 2018), -0.00347811838208307}, | |
{Date(13, mth(12), 2018), -0.0035046853117356}, {Date(13, mth(3), 2019), -0.00359597753246646}, | |
{Date(13, mth(6), 2019), -0.00336488221017208}, {Date(13, mth(9), 2019), -0.00283900803118639}, | |
{Date(13, mth(12), 2019), -0.00226724478999542}, {Date(13, mth(3), 2020), -0.00126475754837997}, | |
{Date(15, mth(6), 2020), -4.04082576520525E-4}, {Date(14, mth(6), 2021), 0.00193549877791657}, | |
{Date(13, mth(6), 2022), 0.00541515029337548}, {Date(13, mth(6), 2023), 0.00834596171638419}, | |
{Date(13, mth(6), 2024), 0.0105506898899723}, {Date(13, mth(6), 2025), 0.0127289184432656}, | |
{Date(15, mth(6), 2026), 0.0146859781244856}, {Date(14, mth(6), 2027), 0.0160839038520465}, | |
{Date(13, mth(6), 2028), 0.0171039813057311}, {Date(13, mth(6), 2033), 0.0190037548450844}, | |
{Date(14, mth(6), 2038), 0.0188138594071705}, {Date(15, mth(6), 2043), 0.0162799102512021}, | |
{Date(15, mth(6), 2048), 0.0147848694988243}, {Date(13, mth(6), 2058), 0.0140576373915513}, | |
{Date(13, mth(6), 2068), 0.0120862578337932}}; | |
std::vector<Date> discountingCurveDates; | |
std::vector<double> discountingCurveRates; | |
for (std::pair<const Date, double> dateAndRate : discountingCurveNodes) { | |
discountingCurveDates.push_back(dateAndRate.first); | |
discountingCurveRates.push_back(dateAndRate.second); | |
} | |
boost::shared_ptr<YieldTermStructure> discountingCurve = | |
boost::make_shared<InterpolatedForwardCurve<NeutralConvexMonotone>>(discountingCurveDates, | |
discountingCurveRates, | |
curveDayCounter, | |
NeutralConvexMonotone()); | |
Handle<YieldTermStructure> discountingCurveHandle(discountingCurve); | |
// FORWARD CURVES | |
Date blendDate = today + Period(2, TimeUnit::Years); | |
boost::shared_ptr<IborIndex> index = | |
boost::make_shared<Euribor>(Period(3, TimeUnit::Months), Handle<YieldTermStructure>()); | |
std::vector<boost::shared_ptr<RateHelper>> futuresCurveHelpers; | |
std::vector<boost::shared_ptr<RateHelper>> swapsCurveHelpers; | |
std::vector<boost::shared_ptr<RateHelper>> blendedCurveHelpers; | |
// FUTURES | |
std::map<Date, std::pair<double, double>> futurePrices = | |
{{Date(18, mth(6), 2018), {100.317582176, 6.51945329655112E-7}}, // these are fixing days, not IMM days | |
{Date(17, mth(9), 2018), {100.29345811, 1.66050681924613E-5}}, | |
{Date(17, mth(12), 2018), {100.26624303, 2.88897080688881E-5}}, | |
{Date(18, mth(3), 2019), {100.242551023, 2.91980601922156E-5}}, | |
{Date(17, mth(6), 2019), {100.184444922, 2.66410283674007E-5}}, | |
{Date(16, mth(9), 2019), {100.109963131, 2.89883148058077E-5}}, | |
{Date(16, mth(12), 2019), {100.017761623, 2.9163458982448E-5}}, | |
{Date(16, mth(3), 2020), {99.926027142, 2.93675715979597E-5}}, | |
{Date(15, mth(6), 2020), {99.832434961, 3.35612290842065E-5}}, | |
{Date(14, mth(9), 2020), {99.730683903, 4.63643156983516E-5}}, | |
{Date(14, mth(12), 2020), {99.629396539, 7.17604585175422E-5}}, | |
{Date(15, mth(3), 2021), {99.528613094, 1.14210609420962E-4}}, | |
{Date(14, mth(6), 2021), {99.429723314, 1.77795812011371E-4}}, | |
{Date(13, mth(9), 2021), {99.331323697, 2.66221336240436E-4}}, | |
{Date(13, mth(12), 2021), {99.239333333, 3.83024162904268E-4}}, | |
{Date(14, mth(3), 2022), {99.155351288, 5.30713049104974E-4}}, | |
{Date(13, mth(6), 2022), {99.0725, 7.09806526725978E-4}}, | |
{Date(19, mth(9), 2022), {98.9875, 8.04726635393628E-4}}, | |
{Date(19, mth(12), 2022), {98.905, 8.98671630673705E-4}}, | |
{Date(13, mth(3), 2023), {98.835, 9.90531253531082E-4}}, | |
{Date(19, mth(6), 2023), {98.76, 0.00110267836537918}}, | |
{Date(18, mth(9), 2023), {98.6875, 0.00121159386949753}}, | |
{Date(18, mth(12), 2023), {98.62, 0.0013262637001}}, | |
{Date(18, mth(3), 2024), {98.545, 0.00144677326172775}}}; | |
for (std::pair<const Date, std::pair<double, double>> dateAndPriceAndConvexity : futurePrices) { | |
Date expiryDate = dateAndPriceAndConvexity.first; | |
double price = dateAndPriceAndConvexity.second.first; | |
double convexity = dateAndPriceAndConvexity.second.second; | |
Date valueDate = index->valueDate(expiryDate); | |
boost::shared_ptr<FuturesRateHelper> futureHelper = | |
boost::make_shared<FuturesRateHelper>(price, valueDate, index, convexity); | |
futuresCurveHelpers.push_back(futureHelper); | |
if (futureHelper->pillarDate() < blendDate - blendGap) { | |
blendedCurveHelpers.push_back(futureHelper); | |
} | |
} | |
// SWAPS | |
std::map<Period, double> swapRates = {{Period(1, TimeUnit::Years), -0.002873}, | |
{Period(2, TimeUnit::Years), -0.001762}, | |
{Period(3, TimeUnit::Years), -1.45E-4}, | |
{Period(4, TimeUnit::Years), 0.001585}, | |
{Period(5, TimeUnit::Years), 0.0032175}, | |
{Period(6, TimeUnit::Years), 0.004705}, | |
{Period(7, TimeUnit::Years), 0.0060575}, | |
{Period(8, TimeUnit::Years), 0.007295}, | |
{Period(9, TimeUnit::Years), 0.008395}, | |
{Period(10, TimeUnit::Years), 0.0093975}, | |
{Period(12, TimeUnit::Years), 0.0110675}, | |
{Period(15, TimeUnit::Years), 0.012865}, | |
{Period(20, TimeUnit::Years), 0.014465}, | |
{Period(25, TimeUnit::Years), 0.014995}, | |
{Period(30, TimeUnit::Years), 0.015135}, | |
{Period(40, TimeUnit::Years), 0.01509}, | |
{Period(50, TimeUnit::Years), 0.0148}}; | |
for (std::pair<const Period, double> tenorAndRate : swapRates) { | |
Period tenor = tenorAndRate.first; | |
double rate = tenorAndRate.second; | |
boost::shared_ptr<SwapRateHelper> swapHelper = | |
boost::make_shared<SwapRateHelper>(rate, | |
tenor, | |
index->fixingCalendar(), | |
Frequency::Annual, | |
BusinessDayConvention::ModifiedFollowing, | |
Thirty360(), | |
index, | |
Handle<Quote>(), | |
Period(0, TimeUnit::Days), | |
discountingCurveHandle); | |
swapsCurveHelpers.push_back(swapHelper); | |
if (swapHelper->pillarDate() >= blendDate) { | |
blendedCurveHelpers.push_back(swapHelper); | |
} | |
} | |
boost::shared_ptr<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>> futuresCurve = | |
boost::make_shared<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>>(today, | |
futuresCurveHelpers, | |
curveDayCounter); | |
boost::shared_ptr<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>> swapsCurve = | |
boost::make_shared<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>>(today, | |
swapsCurveHelpers, | |
curveDayCounter); | |
boost::shared_ptr<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>> blendedCurve = | |
boost::make_shared<PiecewiseYieldCurve<ForwardRate, NeutralConvexMonotone>>(today, | |
blendedCurveHelpers, | |
curveDayCounter); | |
// READOUT | |
std::cout << "date, futures, swaps, blended" << '\n'; | |
for (Date date = futuresCurve->dates().front(); date <= futuresCurve->maxDate(); | |
date = index->fixingCalendar().advance(date, 1, TimeUnit::Days)) { | |
std::cout << QuantLib::io::iso_date(date) // | |
<< ", " << futuresCurve->forwardRate(date, date, curveDayCounter, QuantLib::Compounding::Simple).rate() // | |
<< ", " << swapsCurve->forwardRate(date, date, curveDayCounter, QuantLib::Compounding::Simple).rate() // | |
<< ", " << blendedCurve->forwardRate(date, date, curveDayCounter, QuantLib::Compounding::Simple).rate() // | |
<< '\n'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mkdir -p blend_output | |
for g in 0 3 6 9 12 | |
do | |
./blend $g >blend_output/blend.$g.csv | |
cat >blend_output/blend.$g.gnuplot <<-EOF | |
set datafile separator "," | |
set key autotitle columnhead | |
set xdata time | |
set timefmt '%Y-%m-%d' | |
set format x '%Y-%m-%d' | |
set terminal png size 800,600 enhanced font "Helvetica,9" | |
set output 'blend_output/blend.$g.png' | |
plot "blend_output/blend.$g.csv" using 1:2 with lines, \ | |
"blend_output/blend.$g.csv" using 1:3 with lines, \ | |
"blend_output/blend.$g.csv" using 1:4 with lines | |
EOF | |
gnuplot blend_output/blend.$g.gnuplot | |
done | |
ls -1 blend_output/*.png |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment