19#include <boost/make_shared.hpp>
20#include <boost/test/unit_test.hpp>
30#include <oret/toplevelfixture.hpp>
31#include <ql/cashflows/digitalcoupon.hpp>
32#include <ql/termstructures/volatility/swaption/swaptionconstantvol.hpp>
33#include <ql/termstructures/yield/flatforward.hpp>
34#include <ql/time/calendars/target.hpp>
35#include <ql/time/daycounters/actualactual.hpp>
41using namespace boost::unit_test_framework;
52 asof_ = Date(3, Feb, 2016);
65 QuantLib::ext::shared_ptr<Conventions> conventions = QuantLib::ext::make_shared<Conventions>();
69 "EUR-6M-SWAP-CONVENTIONS",
"TARGET",
"Annual",
"MF",
"30/360",
"EUR-EURIBOR-6M"));
70 conventions->add(swapEURConv);
71 QuantLib::ext::shared_ptr<ore::data::Convention> swapIndexEURLongConv1(
73 QuantLib::ext::shared_ptr<ore::data::Convention> swapIndexEURLongConv2(
75 conventions->add(swapIndexEURLongConv1);
76 conventions->add(swapIndexEURLongConv2);
78 InstrumentConventions::instance().setConventions(conventions);
87 Handle<YieldTermStructure> flatRateYts(Real forward) {
88 QuantLib::ext::shared_ptr<YieldTermStructure> yts(
new FlatForward(0, NullCalendar(), forward, ActualActual(ActualActual::ISDA)));
89 return Handle<YieldTermStructure>(yts);
91 Handle<SwaptionVolatilityStructure> flatRateSvs(Volatility forward) {
92 QuantLib::ext::shared_ptr<SwaptionVolatilityStructure> Svs(
93 new ConstantSwaptionVolatility(0, NullCalendar(), ModifiedFollowing, forward, ActualActual(ActualActual::ISDA)));
94 return Handle<SwaptionVolatilityStructure>(Svs);
96 Handle<QuantExt::CorrelationTermStructure> flatCorr(Real corr) {
97 QuantLib::ext::shared_ptr<QuantExt::CorrelationTermStructure> cs(
100 return Handle<QuantExt::CorrelationTermStructure>(cs);
125 vector<double> notionals;
127 QuantLib::ext::shared_ptr<ore::data::Swap> makeDigitalCmsSpreadOption(
bool call, vector<double> strikes,
128 vector<double> payoffs) {
131 vector<LegData> legData;
132 QuantLib::ext::shared_ptr<DigitalCMSSpreadLegData> cmsLegData;
134 cmsLegData = QuantLib::ext::make_shared<DigitalCMSSpreadLegData>(
135 QuantLib::ext::make_shared<CMSSpreadLegData>(
136 index1, index2, fixingdays, isinarrears, vector<double>(), vector<string>(), vector<double>(),
137 vector<string>(), vector<double>(), vector<string>(), vector<double>(), vector<string>(),
false),
138 Position::Long,
false, strikes, vector<string>(), payoffs, vector<string>());
140 cmsLegData = QuantLib::ext::make_shared<DigitalCMSSpreadLegData>(
141 QuantLib::ext::make_shared<CMSSpreadLegData>(
142 index1, index2, fixingdays, isinarrears, vector<double>(), vector<string>(), vector<double>(),
143 vector<string>(), vector<double>(), vector<string>(), vector<double>(), vector<string>(),
false),
144 Position::Long,
false, vector<double>(), vector<string>(), vector<double>(), vector<string>(),
145 Position::Long,
false, strikes, vector<string>(), payoffs);
148 LegData leg(cmsLegData, isPayer, ccy, cmsSchedule, fixDC, notionals);
149 legData.push_back(leg);
152 QuantLib::ext::shared_ptr<ore::data::Swap> swap(
new ore::data::Swap(env, legData));
156 QuantLib::ext::shared_ptr<ore::data::Swap> makeCmsSpreadOption(vector<double> spreads) {
159 vector<LegData> legData;
160 CMSSpreadLegData cmsLegData(index1, index2, fixingdays, isinarrears, spreads, vector<string>(),
161 vector<double>(), vector<string>(), vector<double>(), vector<string>(),
162 vector<double>(), vector<string>(),
false);
164 LegData leg(QuantLib::ext::make_shared<CMSSpreadLegData>(cmsLegData), isPayer, ccy, cmsSchedule, fixDC, notionals);
165 legData.push_back(leg);
168 QuantLib::ext::shared_ptr<ore::data::Swap> swap(
new ore::data::Swap(env, legData));
172 QuantLib::ext::shared_ptr<ore::data::Swap> makeCmsSpreadFloor(vector<double> floors) {
175 vector<LegData> legData;
176 CMSSpreadLegData cmsLegData(index1, index2, fixingdays, isinarrears, vector<double>(), vector<string>(),
177 vector<double>(), vector<string>(), floors, vector<string>(), vector<double>(),
178 vector<string>(),
false);
180 LegData leg(QuantLib::ext::make_shared<CMSSpreadLegData>(cmsLegData), isPayer, ccy, cmsSchedule, fixDC, notionals);
181 legData.push_back(leg);
184 QuantLib::ext::shared_ptr<ore::data::Swap> swap(
new ore::data::Swap(env, legData));
188 QuantLib::ext::shared_ptr<ore::data::Swap> makeCmsSpreadCap(vector<double> caps) {
191 vector<LegData> legData;
192 CMSSpreadLegData cmsLegData(index1, index2, fixingdays, isinarrears, vector<double>(), vector<string>(), caps,
193 vector<string>(), vector<double>(), vector<string>(), vector<double>(),
194 vector<string>(),
false);
196 LegData leg(QuantLib::ext::make_shared<CMSSpreadLegData>(cmsLegData), isPayer, ccy, cmsSchedule, fixDC, notionals);
197 legData.push_back(leg);
200 QuantLib::ext::shared_ptr<ore::data::Swap> swap(
new ore::data::Swap(env, legData));
204 CommonVars() : ccy(
"EUR"), isPayer(false), start(
"20160301"), end(
"20360301"), fixtenor(
"1Y"), cmstenor(
"6M") {
206 longShort = isPayer ?
"Short" :
"Long";
213 index1 =
"EUR-CMS-30Y";
214 index2 =
"EUR-CMS-2Y";
218 notionals.push_back(10000000);
222void outputCoupons(QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap) {
223 Leg leg = cmsSwap->legs().at(0);
224 for (
auto cf : leg) {
225 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(cf);
227 BOOST_TEST_MESSAGE(
"Coupon Date: " << frc->date() <<
"; Rate: " << frc->rate()
228 <<
"; DayCount: " << frc->dayCounter());
230 BOOST_TEST_MESSAGE(
"Coupon Date: " << cf->date() <<
" - not a floating rate coupon!");
236BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
238BOOST_AUTO_TEST_SUITE(DigitalCmsTests)
242 BOOST_TEST_MESSAGE(
"Testing CMS Digital CMS Spread coupon...");
245 QuantLib::ext::shared_ptr<Market> market = QuantLib::ext::make_shared<TestMarket>();
246 Settings::instance().evaluationDate() = market->asofDate();
250 QuantLib::ext::shared_ptr<EngineData> engineData = QuantLib::ext::make_shared<EngineData>();
251 engineData->model(
"CMS") =
"LinearTSR";
252 engineData->engine(
"CMS") =
"LinearTSRPricer";
254 map<string, string> engineparams1;
255 engineparams1[
"MeanReversion"] =
"0.0";
256 engineparams1[
"Policy"] =
"RateBound";
257 engineparams1[
"LowerRateBoundLogNormal"] =
"0.0001";
258 engineparams1[
"UpperRateBoundLogNormal"] =
"2";
259 engineparams1[
"LowerRateBoundNormal"] =
"-2";
260 engineparams1[
"UpperRateBoundNormal"] =
"2";
261 engineparams1[
"VegaRatio"] =
"0.01";
262 engineparams1[
"PriceThreshold"] =
"0.0000001";
263 engineparams1[
"BsStdDev"] =
"3";
264 engineData->engineParameters(
"CMS") = engineparams1;
266 engineData->model(
"CMSSpread") =
"BrigoMercurio";
267 engineData->engine(
"CMSSpread") =
"Analytic";
268 map<string, string> engineparams2;
269 engineparams2[
"IntegrationPoints"] =
"16";
270 engineData->engineParameters(
"CMSSpread") = engineparams2;
271 engineData->model(
"Swap") =
"DiscountedCashflows";
272 engineData->engine(
"Swap") =
"DiscountingSwapEngineOptimised";
274 QuantLib::ext::shared_ptr<EngineFactory> engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData, market);
283 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
284 vars.makeDigitalCmsSpreadOption(
true, vector<double>(1, strike), vector<double>(1, pay));
285 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
286 vars.makeDigitalCmsSpreadOption(
false, vector<double>(1, strike), vector<double>(1, pay));
287 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadOption(vector<double>(1, pay));
288 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadOption(vector<double>(1, 0.0));
289 cmsDigitalSwapCall->build(engineFactory);
290 cmsDigitalSwapPut->build(engineFactory);
291 cmsSwap1->build(engineFactory);
292 cmsSwap2->build(engineFactory);
294 BOOST_TEST_MESSAGE(
"digital call coupons");
295 outputCoupons(cmsDigitalSwapCall);
296 BOOST_TEST_MESSAGE(
"digital put coupons");
297 outputCoupons(cmsDigitalSwapPut);
298 BOOST_TEST_MESSAGE(
"coupon 1");
299 outputCoupons(cmsSwap1);
300 BOOST_TEST_MESSAGE(
"coupon 2");
301 outputCoupons(cmsSwap2);
303 BOOST_TEST_MESSAGE(
"NPV Call = " << cmsDigitalSwapCall->instrument()->NPV());
304 BOOST_TEST_MESSAGE(
"NPV Put = " << cmsDigitalSwapPut->instrument()->NPV());
305 BOOST_TEST_MESSAGE(
"NPV1 = " << cmsSwap1->instrument()->NPV());
306 BOOST_TEST_MESSAGE(
"NPV2 = " << cmsSwap2->instrument()->NPV());
308 BOOST_CHECK_CLOSE(cmsDigitalSwapCall->instrument()->NPV(), cmsSwap2->instrument()->NPV(), 0.1);
309 BOOST_CHECK_CLOSE(cmsDigitalSwapPut->instrument()->NPV(), cmsSwap1->instrument()->NPV(), 0.1);
314 double strike = 0.0001;
317 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
318 vars.makeDigitalCmsSpreadOption(
false, vector<double>(1, strike), vector<double>(1, pay));
319 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadFloor(vector<double>(1, strike + eps / 2));
320 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadFloor(vector<double>(1, strike - eps / 2));
321 cmsDigitalSwapPut->build(engineFactory);
322 cmsSwap1->build(engineFactory);
323 cmsSwap2->build(engineFactory);
325 Leg leg = cmsDigitalSwapPut->legs().at(0);
326 Leg leg1 = cmsSwap1->legs().at(0);
327 Leg leg2 = cmsSwap2->legs().at(0);
329 for (Size i = 0; i < leg.size(); i++) {
330 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
331 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
332 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
334 double r = pay * (frc1->rate() - frc2->rate()) / eps;
336 BOOST_CHECK_CLOSE(r, dc->putOptionRate(), 0.1);
342 double strike = 0.0001;
345 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
346 vars.makeDigitalCmsSpreadOption(
true, vector<double>(1, strike), vector<double>(1, pay));
347 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadCap(vector<double>(1, strike + eps / 2));
348 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadCap(vector<double>(1, strike - eps / 2));
349 cmsDigitalSwapCall->build(engineFactory);
350 cmsSwap1->build(engineFactory);
351 cmsSwap2->build(engineFactory);
353 Leg leg = cmsDigitalSwapCall->legs().at(0);
354 Leg leg1 = cmsSwap1->legs().at(0);
355 Leg leg2 = cmsSwap2->legs().at(0);
357 for (Size i = 0; i < leg.size(); i++) {
358 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
359 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
360 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
362 double r = pay * (frc1->rate() - frc2->rate()) / eps;
364 BOOST_CHECK_CLOSE(r, dc->callOptionRate(), 0.1);
369 double strike = 0.0001;
371 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapPut =
372 vars.makeDigitalCmsSpreadOption(
false, vector<double>(1, strike), vector<double>());
373 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadFloor(vector<double>(1, strike + eps / 2));
374 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadFloor(vector<double>(1, strike - eps / 2));
375 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap3 = vars.makeCmsSpreadFloor(vector<double>(1, strike));
376 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap4 = vars.makeCmsSpreadFloor(vector<double>());
377 cmsDigitalSwapPut->build(engineFactory);
378 cmsSwap1->build(engineFactory);
379 cmsSwap2->build(engineFactory);
380 cmsSwap3->build(engineFactory);
381 cmsSwap4->build(engineFactory);
383 Leg leg = cmsDigitalSwapPut->legs().at(0);
384 Leg leg1 = cmsSwap1->legs().at(0);
385 Leg leg2 = cmsSwap2->legs().at(0);
386 Leg leg3 = cmsSwap3->legs().at(0);
387 Leg leg4 = cmsSwap4->legs().at(0);
389 for (Size i = 0; i < leg.size(); i++) {
390 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
391 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
392 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
393 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc3 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg3[i]);
394 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc4 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg4[i]);
396 double r = strike * (frc1->rate() - frc2->rate()) / eps;
397 double put = -frc4->rate() + frc3->rate();
398 BOOST_TEST_MESSAGE(frc4->rate() <<
" " << frc3->rate() <<
" " << r <<
" " << put);
400 BOOST_CHECK_CLOSE(r - put, dc->putOptionRate(), 0.1);
406 double strike = 0.0001;
408 QuantLib::ext::shared_ptr<ore::data::Swap> cmsDigitalSwapCall =
409 vars.makeDigitalCmsSpreadOption(
true, vector<double>(1, strike), vector<double>());
410 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap1 = vars.makeCmsSpreadCap(vector<double>(1, strike + eps / 2));
411 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap2 = vars.makeCmsSpreadCap(vector<double>(1, strike - eps / 2));
412 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap3 = vars.makeCmsSpreadCap(vector<double>(1, strike));
413 QuantLib::ext::shared_ptr<ore::data::Swap> cmsSwap4 = vars.makeCmsSpreadCap(vector<double>());
414 cmsDigitalSwapCall->build(engineFactory);
415 cmsSwap1->build(engineFactory);
416 cmsSwap2->build(engineFactory);
417 cmsSwap3->build(engineFactory);
418 cmsSwap4->build(engineFactory);
420 Leg leg = cmsDigitalSwapCall->legs().at(0);
421 Leg leg1 = cmsSwap1->legs().at(0);
422 Leg leg2 = cmsSwap2->legs().at(0);
423 Leg leg3 = cmsSwap3->legs().at(0);
424 Leg leg4 = cmsSwap4->legs().at(0);
426 for (Size i = 0; i < leg.size(); i++) {
427 QuantLib::ext::shared_ptr<DigitalCoupon> dc = QuantLib::ext::dynamic_pointer_cast<DigitalCoupon>(leg[i]);
428 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc1 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg1[i]);
429 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc2 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg2[i]);
430 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc3 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg3[i]);
431 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc4 = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(leg4[i]);
433 double r = strike * (frc1->rate() - frc2->rate()) / eps;
434 double call = frc4->rate() - frc3->rate();
436 BOOST_CHECK_CLOSE(r + call, dc->callOptionRate(), 0.1);
441BOOST_AUTO_TEST_SUITE_END()
443BOOST_AUTO_TEST_SUITE_END()
Ibor cap, floor or collar trade data model and serialization.
Serializable CMS Spread Leg Data.
Serializable object holding generic trade data, reporting dimensions.
Container for storing Interest Rate Swap conventions.
Serializable object holding leg data.
static const string defaultConfiguration
Default configuration label.
map< tuple< string, string, string >, Handle< QuantExt::CorrelationTermStructure > > correlationCurves_
map< tuple< string, YieldCurveType, string >, Handle< YieldTermStructure > > yieldCurves_
map< pair< string, string >, Handle< IborIndex > > iborIndices_
map< pair< string, string >, Handle< QuantLib::SwaptionVolatilityStructure > > swaptionCurves_
void addSwapIndex(const string &swapindex, const string &discountIndex, const string &configuration=Market::defaultConfiguration) const
add a swap index to the market
Serializable schedule data.
Serializable object holding schedule Rules data.
Serializable Swap, Single and Cross Currency.
Container for storing Swap Index conventions.
builder that returns an engine to price capped floored ibor legs
BOOST_AUTO_TEST_CASE(testDigitalCMSSpreadCoupon)
A class to hold pricing engine parameters.
trade envelope data model and serialization
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
Map text representations to QuantLib/QuantExt types.
leg data model and serialization
An implementation of the Market class that stores the required objects in maps.
trade schedule data model and serialization
Swap trade data model and serialization.