Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
parser.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 Copyright (C) 2023 Skandinaviska Enskilda Banken AB (publ)
4 All rights reserved.
5
6 This file is part of ORE, a free-software/open-source library
7 for transparent pricing and risk analysis - http://opensourcerisk.org
8
9 ORE is free software: you can redistribute it and/or modify it
10 under the terms of the Modified BSD License. You should have received a
11 copy of the license along with this program.
12 The license is also available online at <http://opensourcerisk.org>
13
14 This program is distributed on the basis that it will form a useful
15 contribution to risk analytics and model standardisation, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <boost/test/unit_test.hpp>
21#include <iostream>
25#include <oret/toplevelfixture.hpp>
26#include <ql/currencies/america.hpp>
27#include <ql/math/comparison.hpp>
28#include <ql/time/calendars/austria.hpp>
29#include <ql/time/calendars/chile.hpp>
30#include <ql/time/calendars/france.hpp>
31#include <ql/time/calendars/jointcalendar.hpp>
32#include <ql/time/calendars/thailand.hpp>
33#include <ql/time/daycounters/all.hpp>
40
41using namespace QuantLib;
42using namespace QuantExt;
43using namespace boost::unit_test_framework;
44using namespace std;
45
51
52namespace {
53
54struct test_daycounter_data {
55 const char* str;
56 DayCounter dc;
57};
58
59static struct test_daycounter_data daycounter_data[] = {
60 {"A360", Actual360()},
61 {"Actual/360", Actual360()},
62 {"ACT/360", Actual360()},
63 {"A365", Actual365Fixed()},
64 {"A365F", Actual365Fixed()},
65 {"Actual/365 (Fixed)", Actual365Fixed()},
66 {"ACT/365", Actual365Fixed()},
67 {"T360", Thirty360(Thirty360::USA)},
68 {"30/360", Thirty360(Thirty360::USA)},
69 {"30/360 (Bond Basis)", Thirty360(Thirty360::BondBasis)},
70 {"ACT/nACT", Thirty360(Thirty360::USA)},
71 {"30E/360 (Eurobond Basis)", Thirty360(Thirty360::European)},
72 {"30E/360", Thirty360(Thirty360::European)},
73 {"30/360 (Italian)", Thirty360(Thirty360::Italian)},
74 {"ActActISDA", ActualActual(ActualActual::ISDA)},
75 {"Actual/Actual (ISDA)", ActualActual(ActualActual::ISDA)},
76 {"ACT/ACT", ActualActual(ActualActual::ISDA)},
77 {"ACT29", ActualActual(ActualActual::AFB)},
78 {"ACT", ActualActual(ActualActual::ISDA)},
79 {"ActActISMA", ActualActual(ActualActual::ISMA)},
80 {"Actual/Actual (ISMA)", ActualActual(ActualActual::ISMA)},
81 {"ActActAFB", ActualActual(ActualActual::AFB)},
82 {"Actual/Actual (AFB)", ActualActual(ActualActual::AFB)},
83 {"1/1", OneDayCounter()},
84 {"BUS/252", Business252()},
85 {"Business/252", Business252()},
86 {"Actual/365 (No Leap)", Actual365Fixed(Actual365Fixed::NoLeap)},
87 {"Act/365 (NL)", Actual365Fixed(Actual365Fixed::NoLeap)},
88 {"NL/365", Actual365Fixed(Actual365Fixed::NoLeap)},
89 {"Actual/365 (JGB)", Actual365Fixed(Actual365Fixed::NoLeap)},
90 {"Actual/364", Actual364()}};
91
92struct test_freq_data {
93 const char* str;
94 Frequency freq;
95};
96
97static struct test_freq_data freq_data[] = {{"Z", Once},
98 {"Once", Once},
99 {"A", Annual},
100 {"Annual", Annual},
101 {"S", Semiannual},
102 {"Semiannual", Semiannual},
103 {"Q", Quarterly},
104 {"Quarterly", Quarterly},
105 {"B", Bimonthly},
106 {"Bimonthly", Bimonthly},
107 {"M", Monthly},
108 {"Monthly", Monthly},
109 {"L", EveryFourthWeek},
110 {"Lunarmonth", EveryFourthWeek},
111 {"W", Weekly},
112 {"Weekly", Weekly},
113 {"D", Daily},
114 {"Daily", Daily}};
115
116struct test_comp_data {
117 const char* str;
118 Compounding comp;
119};
120
121static struct test_comp_data comp_data[] = {
122 {"Simple", Simple},
123 {"Compounded", Compounded},
124 {"Continuous", Continuous},
125 {"SimpleThenCompounded", SimpleThenCompounded},
126};
127
128void checkStrikeParser(const std::string& s, const ore::data::Strike::Type expectedType, const Real expectedValue) {
129 if (ore::data::parseStrike(s).type != expectedType) {
130 BOOST_FAIL("unexpected strike type parsed from input string " << s);
131 }
132 if (!close_enough(ore::data::parseStrike(s).value, expectedValue)) {
133 BOOST_FAIL("unexpected strike value parsed from input string " << s);
134 }
135 return;
136}
137
138void checkCalendars(const std::set<Date>& expectedHolidays, const std::vector<Date>& testHolidays) {
139
140 for (auto eh : expectedHolidays) {
141 if (std::find(testHolidays.begin(), testHolidays.end(), eh) == testHolidays.end())
142 BOOST_FAIL("expected holiday was " << eh << " not found ");
143 }
144}
145
146} // namespace
147
148BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
149
150BOOST_AUTO_TEST_SUITE(ParserTests)
151
152BOOST_AUTO_TEST_CASE(testDayCounterParsing) {
153
154 BOOST_TEST_MESSAGE("Testing day counter parsing...");
155
156 Size len = sizeof(daycounter_data) / sizeof(daycounter_data[0]);
157 for (Size i = 0; i < len; ++i) {
158 string str(daycounter_data[i].str);
159 QuantLib::DayCounter d;
160
161 try {
163 } catch (...) {
164 BOOST_FAIL("Day Counter Parser failed to parse " << str);
165 }
166 if (d.empty() || d != daycounter_data[i].dc) {
167 BOOST_FAIL("Day Counter Parser(" << str << ") returned day counter " << d << " expected "
168 << daycounter_data[i].dc);
169
170 BOOST_TEST_MESSAGE("Parsed \"" << str << "\" and got " << d);
171 }
172 }
173}
174
175BOOST_AUTO_TEST_CASE(testFrequencyParsing) {
176
177 BOOST_TEST_MESSAGE("Testing frequency parsing...");
178
179 Size len = sizeof(freq_data) / sizeof(freq_data[0]);
180 for (Size i = 0; i < len; ++i) {
181 string str(freq_data[i].str);
182
183 try {
184 QuantLib::Frequency f = ore::data::parseFrequency(str);
185 if (f) {
186 if (f != freq_data[i].freq)
187 BOOST_FAIL("Frequency Parser(" << str << ") returned frequency " << f << " expected "
188 << freq_data[i].freq);
189 BOOST_TEST_MESSAGE("Parsed \"" << str << "\" and got " << f);
190 }
191 } catch (...) {
192 BOOST_FAIL("Frequency Parser failed to parse " << str);
193 }
194 }
195}
196
197BOOST_AUTO_TEST_CASE(testCompoundingParsing) {
198
199 BOOST_TEST_MESSAGE("Testing Compounding parsing...");
200
201 Size len = sizeof(comp_data) / sizeof(comp_data[0]);
202 for (Size i = 0; i < len; ++i) {
203 string str(comp_data[i].str);
204
205 try {
206 QuantLib::Compounding c = ore::data::parseCompounding(str);
207 if (c) {
208 if (c != comp_data[i].comp)
209 BOOST_FAIL("Compounding Parser(" << str << ") returned Compounding " << c << " expected "
210 << comp_data[i].comp);
211 BOOST_TEST_MESSAGE("Parsed \"" << str << "\" and got " << c);
212 }
213 } catch (...) {
214 BOOST_FAIL("Compounding Parser failed to parse " << str);
215 }
216 }
217}
218
219BOOST_AUTO_TEST_CASE(testStrikeParsing) {
220
221 BOOST_TEST_MESSAGE("Testing Strike parsing...");
222
223 checkStrikeParser("ATM", ore::data::Strike::Type::ATM, 0.0);
224 checkStrikeParser("atm", ore::data::Strike::Type::ATM, 0.0);
225 checkStrikeParser("ATMF", ore::data::Strike::Type::ATMF, 0.0);
226 checkStrikeParser("atmf", ore::data::Strike::Type::ATMF, 0.0);
227 checkStrikeParser("ATM+0", ore::data::Strike::Type::ATM_Offset, 0.0);
228 checkStrikeParser("ATM-1", ore::data::Strike::Type::ATM_Offset, -1.0);
229 checkStrikeParser("ATM+1", ore::data::Strike::Type::ATM_Offset, 1.0);
230 checkStrikeParser("ATM-0.01", ore::data::Strike::Type::ATM_Offset, -0.01);
231 checkStrikeParser("ATM+0.01", ore::data::Strike::Type::ATM_Offset, 0.01);
232 checkStrikeParser("atm+0", ore::data::Strike::Type::ATM_Offset, 0.0);
233 checkStrikeParser("atm-1", ore::data::Strike::Type::ATM_Offset, -1.0);
234 checkStrikeParser("atm+1", ore::data::Strike::Type::ATM_Offset, 1.0);
235 checkStrikeParser("atm-0.01", ore::data::Strike::Type::ATM_Offset, -0.01);
236 checkStrikeParser("atm+0.01", ore::data::Strike::Type::ATM_Offset, 0.01);
237 checkStrikeParser("1", ore::data::Strike::Type::Absolute, 1.0);
238 checkStrikeParser("0.01", ore::data::Strike::Type::Absolute, 0.01);
239 checkStrikeParser("+0.01", ore::data::Strike::Type::Absolute, 0.01);
240 checkStrikeParser("-0.01", ore::data::Strike::Type::Absolute, -0.01);
241 checkStrikeParser("10d", ore::data::Strike::Type::Delta, 10.0);
242 checkStrikeParser("10.0d", ore::data::Strike::Type::Delta, 10.0);
243 checkStrikeParser("+10d", ore::data::Strike::Type::Delta, 10.0);
244 checkStrikeParser("+10.0d", ore::data::Strike::Type::Delta, 10.0);
245 checkStrikeParser("-25d", ore::data::Strike::Type::Delta, -25.0);
246 checkStrikeParser("-25.0d", ore::data::Strike::Type::Delta, -25.0);
247 checkStrikeParser("10D", ore::data::Strike::Type::Delta, 10.0);
248 checkStrikeParser("10.0D", ore::data::Strike::Type::Delta, 10.0);
249 checkStrikeParser("+10D", ore::data::Strike::Type::Delta, 10.0);
250 checkStrikeParser("+10.0D", ore::data::Strike::Type::Delta, 10.0);
251 checkStrikeParser("-25D", ore::data::Strike::Type::Delta, -25.0);
252 checkStrikeParser("-25.0D", ore::data::Strike::Type::Delta, -25.0);
253 checkStrikeParser("10C", ore::data::Strike::Type::DeltaCall, 10.0);
254 checkStrikeParser("10c", ore::data::Strike::Type::DeltaCall, 10.0);
255 checkStrikeParser("20P", ore::data::Strike::Type::DeltaPut, 20.0);
256 checkStrikeParser("20p", ore::data::Strike::Type::DeltaPut, 20.0);
257 checkStrikeParser("25BF", ore::data::Strike::Type::BF, 25.0);
258 checkStrikeParser("25bf", ore::data::Strike::Type::BF, 25.0);
259 checkStrikeParser("25RR", ore::data::Strike::Type::RR, 25.0);
260 checkStrikeParser("25rr", ore::data::Strike::Type::RR, 25.0);
261 BOOST_CHECK(true);
262}
263
264BOOST_AUTO_TEST_CASE(testDatePeriodParsing) {
265
266 BOOST_TEST_MESSAGE("Testing Date and Period parsing...");
267
268 BOOST_CHECK_EQUAL(ore::data::parseDate("20170605"), Date(5, Jun, 2017));
269 //
270 BOOST_CHECK_EQUAL(ore::data::parseDate("2017-06-05"), Date(5, Jun, 2017));
271 BOOST_CHECK_EQUAL(ore::data::parseDate("2017/06/05"), Date(5, Jun, 2017));
272 BOOST_CHECK_EQUAL(ore::data::parseDate("2017.06.05"), Date(5, Jun, 2017));
273 //
274 BOOST_CHECK_EQUAL(ore::data::parseDate("05-06-2017"), Date(5, Jun, 2017));
275 BOOST_CHECK_EQUAL(ore::data::parseDate("05/06/2017"), Date(5, Jun, 2017));
276 BOOST_CHECK_EQUAL(ore::data::parseDate("05.06.2017"), Date(5, Jun, 2017));
277 //
278 BOOST_CHECK_EQUAL(ore::data::parseDate("05-06-17"), Date(5, Jun, 2017));
279 BOOST_CHECK_EQUAL(ore::data::parseDate("05/06/17"), Date(5, Jun, 2017));
280 BOOST_CHECK_EQUAL(ore::data::parseDate("05.06.17"), Date(5, Jun, 2017));
281 //
282 BOOST_CHECK_THROW(ore::data::parseDate("1Y"), QuantLib::Error);
283 BOOST_CHECK_THROW(ore::data::parseDate("05-06-1Y"), QuantLib::Error);
284 BOOST_CHECK_THROW(ore::data::parseDate("X5-06-17"), QuantLib::Error);
285 BOOST_CHECK_THROW(ore::data::parseDate("2017-06-05-"), QuantLib::Error);
286 BOOST_CHECK_THROW(ore::data::parseDate("-2017-06-05"), QuantLib::Error);
287 BOOST_CHECK_THROW(ore::data::parseDate("xx17-06-05"), QuantLib::Error);
288
289 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3Y"), 3 * Years);
290 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3y"), 3 * Years);
291 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3M"), 3 * Months);
292 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3m"), 3 * Months);
293 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3W"), 3 * Weeks);
294 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3w"), 3 * Weeks);
295 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3D"), 3 * Days);
296 BOOST_CHECK_EQUAL(ore::data::parsePeriod("3d"), 3 * Days);
297 //
298 BOOST_CHECK_EQUAL(ore::data::parsePeriod("1Y6M"), 1 * Years + 6 * Months);
299 BOOST_CHECK_EQUAL(ore::data::parsePeriod("6M0W"), 6 * Months + 0 * Weeks);
300 BOOST_CHECK_EQUAL(ore::data::parsePeriod("6M0D"), 6 * Months + 0 * Days);
301 //
302 BOOST_CHECK_THROW(ore::data::parsePeriod("20170605"), QuantLib::Error);
303 BOOST_CHECK_THROW(ore::data::parsePeriod("3X"), QuantLib::Error);
304 BOOST_CHECK_THROW(ore::data::parsePeriod("xY"), QuantLib::Error);
305 // QL moved to std::stoi in its period and date parsers
306 // BOOST_CHECK_THROW(ore::data::parsePeriod(".3M"), QuantLib::Error);
307 BOOST_CHECK_THROW(ore::data::parsePeriod("3M."), QuantLib::Error);
308
309 Date d;
310 Period p;
311 bool isDate;
312
313 ore::data::parseDateOrPeriod("20170605", d, p, isDate);
314 BOOST_CHECK(isDate && d == Date(5, Jun, 2017));
315 ore::data::parseDateOrPeriod("3Y", d, p, isDate);
316 BOOST_CHECK(!isDate && p == 3 * Years);
317 ore::data::parseDateOrPeriod("3M", d, p, isDate);
318 BOOST_CHECK(!isDate && p == 3 * Months);
319 ore::data::parseDateOrPeriod("3W", d, p, isDate);
320 BOOST_CHECK(!isDate && p == 3 * Weeks);
321 ore::data::parseDateOrPeriod("3D", d, p, isDate);
322 BOOST_CHECK(!isDate && p == 3 * Days);
323 ore::data::parseDateOrPeriod("1Y6M", d, p, isDate);
324 BOOST_CHECK(!isDate && p == 1 * Years + 6 * Months);
325 ore::data::parseDateOrPeriod("20170605D", d, p, isDate);
326 BOOST_CHECK(!isDate && p == 20170605 * Days);
327 //
328 BOOST_CHECK_THROW(ore::data::parseDateOrPeriod("5Y2017", d, p, isDate), QuantLib::Error);
329 // QL moved to std::stoi in its period and date parsers
330 // BOOST_CHECK_THROW(ore::data::parseDateOrPeriod("2017-06-05D", d, p, isDate), QuantLib::Error);
331 // BOOST_CHECK_THROW(ore::data::parseDateOrPeriod(".3M", d, p, isDate), QuantLib::Error);
332 BOOST_CHECK_THROW(ore::data::parseDateOrPeriod("3M.", d, p, isDate), QuantLib::Error);
333 BOOST_CHECK_THROW(ore::data::parseDateOrPeriod("xx17-06-05", d, p, isDate), QuantLib::Error);
334}
335
336BOOST_AUTO_TEST_CASE(testMarketDatumParsing) {
337
338 BOOST_TEST_MESSAGE("Testing market datum parsing...");
339
340 BOOST_TEST_MESSAGE("Testing cap/floor market datum parsing...");
341
342 { // test capfloor normal vol ATM
343 Date d(1, Jan, 1990);
344 Real value = 0.01;
345
346 string input = "CAPFLOOR/RATE_NVOL/USD/5Y/3M/0/0/0";
347
348 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
349
350 BOOST_CHECK(datum->asofDate() == d);
351 BOOST_CHECK(datum->quote()->value() == value);
352 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
353 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE_NVOL);
354
355 QuantLib::ext::shared_ptr<ore::data::CapFloorQuote> capfloorVolDatum =
356 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorQuote>(datum);
357
358 BOOST_CHECK(capfloorVolDatum->ccy() == "USD");
359 BOOST_CHECK(capfloorVolDatum->term() == Period(5, Years));
360 BOOST_CHECK(capfloorVolDatum->underlying() == Period(3, Months));
361 BOOST_CHECK(capfloorVolDatum->atm() == false);
362 BOOST_CHECK(capfloorVolDatum->relative() == false);
363 BOOST_CHECK_CLOSE(capfloorVolDatum->strike(), 0.0, 1e-12);
364 }
365
366 { // test capfloor shifted lognormal vol ATM w/ index name
367 Date d(1, Jan, 1990);
368 Real value = 0.01;
369
370 string input = "CAPFLOOR/RATE_SLNVOL/JPY/EYTIBOR/5Y/3M/1/1/0.0075";
371
372 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
373
374 BOOST_CHECK(datum->asofDate() == d);
375 BOOST_CHECK(datum->quote()->value() == value);
376 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
377 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE_SLNVOL);
378
379 QuantLib::ext::shared_ptr<ore::data::CapFloorQuote> capfloorVolDatum =
380 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorQuote>(datum);
381
382 BOOST_CHECK(capfloorVolDatum->ccy() == "JPY");
383 BOOST_CHECK(capfloorVolDatum->indexName() == "EYTIBOR");
384 BOOST_CHECK(capfloorVolDatum->term() == Period(5, Years));
385 BOOST_CHECK(capfloorVolDatum->underlying() == Period(3, Months));
386 BOOST_CHECK(capfloorVolDatum->atm() == true);
387 BOOST_CHECK(capfloorVolDatum->relative() == true);
388 BOOST_CHECK_CLOSE(capfloorVolDatum->strike(), 0.0075, 1e-12);
389 }
390
391 { // test capfloor shift
392 Date d(1, Jan, 1990);
393 Real value = 0.01;
394
395 string input = "CAPFLOOR/SHIFT/USD/5Y";
396
397 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
398
399 BOOST_CHECK(datum->asofDate() == d);
400 BOOST_CHECK(datum->quote()->value() == value);
401 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
402 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::SHIFT);
403
404 QuantLib::ext::shared_ptr<ore::data::CapFloorShiftQuote> capfloorShiftDatum =
405 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorShiftQuote>(datum);
406
407 BOOST_CHECK(capfloorShiftDatum->ccy() == "USD");
408 BOOST_CHECK(capfloorShiftDatum->indexTenor() == Period(5, Years));
409 }
410
411 { // test capfloor shift w/name
412 Date d(1, Jan, 1990);
413 Real value = 0.01;
414
415 string input = "CAPFLOOR/SHIFT/JPY/EYTIBOR/5Y";
416
417 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
418
419 BOOST_CHECK(datum->asofDate() == d);
420 BOOST_CHECK(datum->quote()->value() == value);
421 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
422 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::SHIFT);
423
424 QuantLib::ext::shared_ptr<ore::data::CapFloorShiftQuote> capfloorShiftDatum =
425 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorShiftQuote>(datum);
426
427 BOOST_CHECK(capfloorShiftDatum->ccy() == "JPY");
428 BOOST_CHECK(capfloorShiftDatum->indexName() == "EYTIBOR");
429 BOOST_CHECK(capfloorShiftDatum->indexTenor() == Period(5, Years));
430 }
431
432 { // test capfloor price ATM
433 Date d(1, Jan, 1990);
434 Real value = 0.01;
435
436 string input = "CAPFLOOR/PRICE/USD/5Y/3M/0/0/0/C";
437
438 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
439
440 BOOST_CHECK(datum->asofDate() == d);
441 BOOST_CHECK(datum->quote()->value() == value);
442 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
443 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::PRICE);
444
445 QuantLib::ext::shared_ptr<ore::data::CapFloorQuote> capfloorPremiumDatum =
446 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorQuote>(datum);
447
448 BOOST_CHECK(capfloorPremiumDatum->ccy() == "USD");
449 BOOST_CHECK(capfloorPremiumDatum->term() == Period(5, Years));
450 BOOST_CHECK(capfloorPremiumDatum->underlying() == Period(3, Months));
451 BOOST_CHECK(capfloorPremiumDatum->atm() == false);
452 BOOST_CHECK(capfloorPremiumDatum->relative() == false);
453 BOOST_CHECK_CLOSE(capfloorPremiumDatum->strike(), 0.0, 1e-12);
454 BOOST_CHECK(capfloorPremiumDatum->isCap() == true);
455 }
456
457 { // test capfloor shifted lognormal vol ATM w/ index name
458 Date d(1, Jan, 1990);
459 Real value = 0.01;
460
461 string input = "CAPFLOOR/PRICE/JPY/EYTIBOR/5Y/3M/1/1/-0.0075/F";
462
463 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
464
465 BOOST_CHECK(datum->asofDate() == d);
466 BOOST_CHECK(datum->quote()->value() == value);
467 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CAPFLOOR);
468 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::PRICE);
469
470 QuantLib::ext::shared_ptr<ore::data::CapFloorQuote> capfloorVolDatum =
471 QuantLib::ext::dynamic_pointer_cast<ore::data::CapFloorQuote>(datum);
472
473 BOOST_CHECK(capfloorVolDatum->ccy() == "JPY");
474 BOOST_CHECK(capfloorVolDatum->indexName() == "EYTIBOR");
475 BOOST_CHECK(capfloorVolDatum->term() == Period(5, Years));
476 BOOST_CHECK(capfloorVolDatum->underlying() == Period(3, Months));
477 BOOST_CHECK(capfloorVolDatum->atm() == true);
478 BOOST_CHECK(capfloorVolDatum->relative() == true);
479 BOOST_CHECK_CLOSE(capfloorVolDatum->strike(), -0.0075, 1e-12);
480 BOOST_CHECK(capfloorVolDatum->isCap() == false);
481 }
482
483 { // test parsing throws
484 Date d(3, Mar, 2018);
485 Real value = 10;
486
487 BOOST_CHECK_THROW(
488 ore::data::parseMarketDatum(d, "CAPFLOOR/RATE_LNVOL/JPY/EYTIBOR/fortnight/3M/1/1/0.0075", value),
489 QuantLib::Error);
490 BOOST_CHECK_THROW(
491 ore::data::parseMarketDatum(d, "CAPFLOOR/RATE_LNVOL/JPY/EYTIBOR/5Y/fortnight/1/1/0.0075", value),
492 QuantLib::Error);
493 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CAPFLOOR/RATE_LNVOL/JPY/EYTIBOR/5Y/3M/2Y/1/0.0075", value),
494 QuantLib::Error);
495 BOOST_CHECK_THROW(
496 ore::data::parseMarketDatum(d, "CAPFLOOR/RATE_LNVOL/JPY/EYTIBOR/5Y/3M/1/string/0.0075", value),
497 QuantLib::Error);
498 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CAPFLOOR/PRICE/JPY/EYTIBOR/5Y/3M/1/1/one/F", value),
499 QuantLib::Error);
500 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CAPFLOOR/PRICE/JPY/EYTIBOR/5Y/3M/1/1/0.0075/straddle", value),
501 QuantLib::Error);
502 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CAPFLOOR/PRICE/JPY/EYTIBOR/5Y/3M/1/1/0.0", value),
503 QuantLib::Error);
504 }
505
506 BOOST_TEST_MESSAGE("Testing swaption market datum parsing...");
507
508 { // test swaption normal vol ATM
509 Date d(1, Jan, 1990);
510 Real value = 0.01;
511
512 string input = "SWAPTION/RATE_NVOL/EUR/10Y/30Y/ATM";
513
514 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
515
516 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
517 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE_NVOL);
518
519 QuantLib::ext::shared_ptr<ore::data::SwaptionQuote> swaptionVolDatum =
520 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionQuote>(datum);
521
522 BOOST_CHECK(swaptionVolDatum->ccy() == "EUR");
523 BOOST_CHECK(swaptionVolDatum->expiry() == Period(10, Years));
524 BOOST_CHECK(swaptionVolDatum->term() == Period(30, Years));
525 BOOST_CHECK(swaptionVolDatum->dimension() == "ATM");
526 BOOST_CHECK_CLOSE(swaptionVolDatum->strike(), 0.0, 1e-12);
527 BOOST_CHECK(swaptionVolDatum->quoteTag() == "");
528 }
529
530 { // test swaption normal vol smile
531 Date d(1, Jan, 1990);
532 Real value = 0.01;
533
534 string input = "SWAPTION/RATE_NVOL/EUR/EURIBOR/10Y/30Y/Smile/-0.0025";
535
536 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
537
538 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
539 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE_NVOL);
540
541 QuantLib::ext::shared_ptr<ore::data::SwaptionQuote> swaptionVolDatum =
542 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionQuote>(datum);
543
544 BOOST_CHECK(swaptionVolDatum->ccy() == "EUR");
545 BOOST_CHECK(swaptionVolDatum->expiry() == Period(10, Years));
546 BOOST_CHECK(swaptionVolDatum->term() == Period(30, Years));
547 BOOST_CHECK(swaptionVolDatum->dimension() == "Smile");
548 BOOST_CHECK_CLOSE(swaptionVolDatum->strike(), -0.0025, 1e-12);
549 BOOST_CHECK(swaptionVolDatum->quoteTag() == "EURIBOR");
550 }
551
552 { // test swaption shifted lognormal vol smile
553 Date d(1, Jan, 1990);
554 Real value = 0.01;
555
556 string input = "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/10Y/30Y/Smile/-0.0025";
557
558 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
559
560 BOOST_CHECK(datum->asofDate() == d);
561 BOOST_CHECK(datum->quote()->value() == value);
562 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
563 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE_SLNVOL);
564
565 QuantLib::ext::shared_ptr<ore::data::SwaptionQuote> swaptionVolDatum =
566 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionQuote>(datum);
567
568 BOOST_CHECK(swaptionVolDatum->ccy() == "EUR");
569 BOOST_CHECK(swaptionVolDatum->expiry() == Period(10, Years));
570 BOOST_CHECK(swaptionVolDatum->term() == Period(30, Years));
571 BOOST_CHECK(swaptionVolDatum->dimension() == "Smile");
572 BOOST_CHECK_CLOSE(swaptionVolDatum->strike(), -0.0025, 1e-12);
573 BOOST_CHECK(swaptionVolDatum->quoteTag() == "EURIBOR");
574 }
575
576 { // test swaption shift
577 Date d(1, Jan, 1990);
578 Real value = 0.01;
579
580 string input = "SWAPTION/SHIFT/EUR/EURIBOR/30Y";
581
582 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
583
584 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
585 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::SHIFT);
586
587 QuantLib::ext::shared_ptr<ore::data::SwaptionShiftQuote> swaptionShiftDatum =
588 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionShiftQuote>(datum);
589
590 BOOST_CHECK(swaptionShiftDatum->ccy() == "EUR");
591 BOOST_CHECK(swaptionShiftDatum->term() == Period(30, Years));
592 BOOST_CHECK(swaptionShiftDatum->quoteTag() == "EURIBOR");
593 }
594
595 { // test payer swaption ATM premium
596 Date d(1, Jan, 1990);
597 Real value = 0.01;
598
599 string input = "SWAPTION/PRICE/EUR/10Y/30Y/ATM/P";
600
601 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
602
603 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
604 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::PRICE);
605
606 QuantLib::ext::shared_ptr<ore::data::SwaptionQuote> swaptionPremiumDatum =
607 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionQuote>(datum);
608
609 BOOST_CHECK(swaptionPremiumDatum->ccy() == "EUR");
610 BOOST_CHECK(swaptionPremiumDatum->expiry() == Period(10, Years));
611 BOOST_CHECK(swaptionPremiumDatum->term() == Period(30, Years));
612 BOOST_CHECK(swaptionPremiumDatum->dimension() == "ATM");
613 BOOST_CHECK_CLOSE(swaptionPremiumDatum->strike(), 0.0, 1e-12);
614 BOOST_CHECK(swaptionPremiumDatum->quoteTag() == "");
615 BOOST_CHECK(swaptionPremiumDatum->isPayer() == true);
616 }
617
618 { // test receiver swaption smile premium
619 Date d(1, Jan, 1990);
620 Real value = 0.01;
621
622 string input = "SWAPTION/PRICE/EUR/EURIBOR/10Y/30Y/Smile/-0.0025/R";
623
624 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
625
626 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::SWAPTION);
627 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::PRICE);
628
629 QuantLib::ext::shared_ptr<ore::data::SwaptionQuote> swaptionPremiumDatum =
630 QuantLib::ext::dynamic_pointer_cast<ore::data::SwaptionQuote>(datum);
631
632 BOOST_CHECK(swaptionPremiumDatum->ccy() == "EUR");
633 BOOST_CHECK(swaptionPremiumDatum->expiry() == Period(10, Years));
634 BOOST_CHECK(swaptionPremiumDatum->term() == Period(30, Years));
635 BOOST_CHECK(swaptionPremiumDatum->dimension() == "Smile");
636 BOOST_CHECK_CLOSE(swaptionPremiumDatum->strike(), -0.0025, 1e-12);
637 BOOST_CHECK(swaptionPremiumDatum->quoteTag() == "EURIBOR");
638 BOOST_CHECK(swaptionPremiumDatum->isPayer() == false);
639 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "SWAPTION/543/EUR/EURIBOR/10Y/30Y/Smile/-0.0025", value),
640 QuantLib::Error);
641 BOOST_CHECK_THROW(
642 ore::data::parseMarketDatum(d, "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/TodayWasGonna/30Y/Smile/-0.0025", value),
643 QuantLib::Error);
644 BOOST_CHECK_THROW(
645 ore::data::parseMarketDatum(d, "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/10Y/BeTheDay/Smile/-0.0025", value),
646 QuantLib::Error);
647 BOOST_CHECK_THROW(
648 ore::data::parseMarketDatum(d, "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/10Y/30Y/ButTheyll/-0.0025", value),
649 QuantLib::Error);
650 BOOST_CHECK_THROW(
651 ore::data::parseMarketDatum(d, "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/10Y/30Y/Smile/NeverThrowIt", value),
652 QuantLib::Error);
653 BOOST_CHECK_THROW(
654 ore::data::parseMarketDatum(d, "SWAPTION/RATE_SLNVOL/EUR/EURIBOR/10Y/30Y/Smile/0.001/BackToYou", value),
655 QuantLib::Error);
656 }
657
658 BOOST_TEST_MESSAGE("Testing correlation market datum parsing...");
659
660 { // test rate quote
661 Date d(1, Jan, 1990);
662 Real value = 1;
663
664 string input = "CORRELATION/RATE/INDEX1/INDEX2/1Y/ATM";
665
666 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
667
668 BOOST_CHECK(datum->asofDate() == d);
669 BOOST_CHECK(datum->quote()->value() == value);
670 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CORRELATION);
671 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::RATE);
672
673 QuantLib::ext::shared_ptr<ore::data::CorrelationQuote> spreadDatum =
674 QuantLib::ext::dynamic_pointer_cast<ore::data::CorrelationQuote>(datum);
675
676 BOOST_CHECK(spreadDatum->index1() == "INDEX1");
677 BOOST_CHECK(spreadDatum->index2() == "INDEX2");
678 BOOST_CHECK(spreadDatum->expiry() == "1Y");
679 BOOST_CHECK(spreadDatum->strike() == "ATM");
680 }
681
682 { // test price quote
683 Date d(3, Mar, 2018);
684 Real value = 10;
685
686 string input = "CORRELATION/PRICE/INDEX1/INDEX2/1Y/0.1";
687
688 QuantLib::ext::shared_ptr<ore::data::MarketDatum> datum = ore::data::parseMarketDatum(d, input, value);
689
690 BOOST_CHECK(datum->asofDate() == d);
691 BOOST_CHECK(datum->quote()->value() == value);
692 BOOST_CHECK(datum->instrumentType() == ore::data::MarketDatum::InstrumentType::CORRELATION);
693 BOOST_CHECK(datum->quoteType() == ore::data::MarketDatum::QuoteType::PRICE);
694
695 QuantLib::ext::shared_ptr<ore::data::CorrelationQuote> spreadDatum =
696 QuantLib::ext::dynamic_pointer_cast<ore::data::CorrelationQuote>(datum);
697
698 BOOST_CHECK(spreadDatum->index1() == "INDEX1");
699 BOOST_CHECK(spreadDatum->index2() == "INDEX2");
700 BOOST_CHECK(spreadDatum->expiry() == "1Y");
701 BOOST_CHECK(spreadDatum->strike() == "0.1");
702 }
703
704 { // test parsing throws
705 Date d(3, Mar, 2018);
706 Real value = 10;
707
708 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CORRELATION/PRICE/INDEX1/INDEX2/1Y/SS", value),
709 QuantLib::Error);
710 BOOST_CHECK_THROW(ore::data::parseMarketDatum(d, "CORRELATION/PRICE/INDEX1/INDEX2/6X/0.1", value),
711 QuantLib::Error);
712 }
713
714 BOOST_TEST_MESSAGE("Testing commodity spot market datum parsing...");
715
716 // test normal parsing
717 {
718 Date d(29, Jul, 2019);
719 Real value = 1418.1;
720
721 string input = "COMMODITY/PRICE/PM:XAUUSD/USD";
722
723 QuantLib::ext::shared_ptr<MarketDatum> datum = parseMarketDatum(d, input, value);
724
725 BOOST_CHECK(datum->asofDate() == d);
726 BOOST_CHECK(datum->quote()->value() == value);
727 BOOST_CHECK(datum->instrumentType() == MarketDatum::InstrumentType::COMMODITY_SPOT);
728 BOOST_CHECK(datum->quoteType() == MarketDatum::QuoteType::PRICE);
729
730 QuantLib::ext::shared_ptr<CommoditySpotQuote> q = QuantLib::ext::dynamic_pointer_cast<CommoditySpotQuote>(datum);
731
732 BOOST_CHECK(q->commodityName() == "PM:XAUUSD");
733 BOOST_CHECK(q->quoteCurrency() == "USD");
734 }
735
736 // test possible exceptions
737 {
738 Date d(29, Jul, 2019);
739 Real value = 1418.1;
740
741 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY_SPOT/PRICE/PM:XAUUSD/USD", value), Error);
742 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY/RATE/PM:XAUUSD/USD", value), Error);
743 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY/PRICE/USD", value), Error);
744 }
745
746 BOOST_TEST_MESSAGE("Testing commodity forward market datum parsing...");
747
748 // test normal parsing
749 {
750 Date d(29, Jul, 2019);
751 Real value = 300.16535;
752
753 // Tenor based quote
754 string input = "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/1M";
755 QuantLib::ext::shared_ptr<MarketDatum> datum = parseMarketDatum(d, input, value);
756
757 BOOST_CHECK(datum->asofDate() == d);
758 BOOST_CHECK(datum->quote()->value() == value);
759 BOOST_CHECK(datum->instrumentType() == MarketDatum::InstrumentType::COMMODITY_FWD);
760 BOOST_CHECK(datum->quoteType() == MarketDatum::QuoteType::PRICE);
761
762 QuantLib::ext::shared_ptr<CommodityForwardQuote> q = QuantLib::ext::dynamic_pointer_cast<CommodityForwardQuote>(datum);
763 BOOST_CHECK(q->commodityName() == "PM:XAUUSD");
764 BOOST_CHECK(q->quoteCurrency() == "USD");
765 BOOST_CHECK(q->tenorBased());
766 BOOST_CHECK(q->expiryDate() == Date());
767 BOOST_CHECK(q->tenor() == 1 * Months);
768 BOOST_CHECK(q->startTenor() == boost::none);
769
770 // Date based quote
771 input = "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/2019-08-30";
772 datum = parseMarketDatum(d, input, value);
773 q = QuantLib::ext::dynamic_pointer_cast<CommodityForwardQuote>(datum);
774 BOOST_CHECK(q->commodityName() == "PM:XAUUSD");
775 BOOST_CHECK(q->quoteCurrency() == "USD");
776 BOOST_CHECK(!q->tenorBased());
777 BOOST_CHECK(q->expiryDate() == Date(30, Aug, 2019));
778 BOOST_CHECK(q->tenor() == Period());
779 BOOST_CHECK(q->startTenor() == boost::none);
780
781 // Special tenor based quotes
782
783 // Overnight
784 input = "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/ON";
785 datum = parseMarketDatum(d, input, value);
786 q = QuantLib::ext::dynamic_pointer_cast<CommodityForwardQuote>(datum);
787 BOOST_CHECK(q->tenorBased());
788 BOOST_CHECK(q->expiryDate() == Date());
789 BOOST_CHECK(q->tenor() == 1 * Days);
790 BOOST_CHECK(q->startTenor() == 0 * Days);
791
792 // Tom-next
793 input = "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/TN";
794 datum = parseMarketDatum(d, input, value);
795 q = QuantLib::ext::dynamic_pointer_cast<CommodityForwardQuote>(datum);
796 BOOST_CHECK(q->tenorBased());
797 BOOST_CHECK(q->expiryDate() == Date());
798 BOOST_CHECK(q->tenor() == 1 * Days);
799 BOOST_CHECK(q->startTenor() == 1 * Days);
800
801 // Spot-next
802 input = "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/SN";
803 datum = parseMarketDatum(d, input, value);
804 q = QuantLib::ext::dynamic_pointer_cast<CommodityForwardQuote>(datum);
805 BOOST_CHECK(q->tenorBased());
806 BOOST_CHECK(q->expiryDate() == Date());
807 BOOST_CHECK(q->tenor() == 1 * Days);
808 BOOST_CHECK(q->startTenor() == boost::none);
809 }
810
811 // test possible exceptions
812 {
813 Date d(29, Jul, 2019);
814 Real value = 300.16535;
815
816 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY_FORWARD/PRICE/PM:XAUUSD/USD/1M", value), Error);
817 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY_FWD/RATE/PM:XAUUSD/USD/1M", value), Error);
818 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY_FWD/PRICE/USD/1M", value), Error);
819 BOOST_CHECK_THROW(parseMarketDatum(d, "COMMODITY_FWD/PRICE/PM:XAUUSD/USD/2019-12", value), Error);
820 }
821
822 BOOST_TEST_MESSAGE("Testing fx option market datum parsing...");
823
824 // test normal parsing
825 {
826 Date d(29, Jul, 2019);
827 Real value = 1.234;
828
829 // ATM quote
830 string input = "FX_OPTION/RATE_LNVOL/EUR/USD/1M/ATM";
831 QuantLib::ext::shared_ptr<MarketDatum> datum = parseMarketDatum(d, input, value);
832
833 BOOST_CHECK(datum->asofDate() == d);
834 BOOST_CHECK(datum->quote()->value() == value);
835 BOOST_CHECK(datum->instrumentType() == MarketDatum::InstrumentType::FX_OPTION);
836 BOOST_CHECK(datum->quoteType() == MarketDatum::QuoteType::RATE_LNVOL);
837
838 QuantLib::ext::shared_ptr<FXOptionQuote> q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
839 BOOST_CHECK(q->unitCcy() == "EUR");
840 BOOST_CHECK(q->ccy() == "USD");
841 BOOST_CHECK(q->expiry() == Period(1, Months));
842 BOOST_CHECK(q->strike() == "ATM");
843
844 // Butterfly quote
845 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/25BF";
846 datum = parseMarketDatum(d, input, value);
847 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
848 BOOST_CHECK(q->unitCcy() == "EUR");
849 BOOST_CHECK(q->ccy() == "USD");
850 BOOST_CHECK(q->expiry() == Period(2, Months));
851 BOOST_CHECK(q->strike() == "25BF");
852
853 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/10BF";
854 datum = parseMarketDatum(d, input, value);
855 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
856 BOOST_CHECK(q->unitCcy() == "EUR");
857 BOOST_CHECK(q->ccy() == "USD");
858 BOOST_CHECK(q->expiry() == Period(2, Months));
859 BOOST_CHECK(q->strike() == "10BF");
860
861 // Risk Reversal quote
862 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/25RR";
863 datum = parseMarketDatum(d, input, value);
864 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
865 BOOST_CHECK(q->unitCcy() == "EUR");
866 BOOST_CHECK(q->ccy() == "USD");
867 BOOST_CHECK(q->expiry() == Period(2, Months));
868 BOOST_CHECK(q->strike() == "25RR");
869
870 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/10RR";
871 datum = parseMarketDatum(d, input, value);
872 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
873 BOOST_CHECK(q->unitCcy() == "EUR");
874 BOOST_CHECK(q->ccy() == "USD");
875 BOOST_CHECK(q->expiry() == Period(2, Months));
876 BOOST_CHECK(q->strike() == "10RR");
877
878 // Strike based quote
879 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/10C";
880 datum = parseMarketDatum(d, input, value);
881 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
882 BOOST_CHECK(q->unitCcy() == "EUR");
883 BOOST_CHECK(q->ccy() == "USD");
884 BOOST_CHECK(q->expiry() == Period(2, Months));
885 BOOST_CHECK(q->strike() == "10C");
886
887 input = "FX_OPTION/RATE_LNVOL/EUR/USD/2M/20P";
888 datum = parseMarketDatum(d, input, value);
889 q = QuantLib::ext::dynamic_pointer_cast<FXOptionQuote>(datum);
890 BOOST_CHECK(q->unitCcy() == "EUR");
891 BOOST_CHECK(q->ccy() == "USD");
892 BOOST_CHECK(q->expiry() == Period(2, Months));
893 BOOST_CHECK(q->strike() == "20P");
894
895 // test possible exceptions
896 {
897 Date d(29, Jul, 2019);
898 Real value = 300.16535;
899
900 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/1M/ATMF", value), Error);
901 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/1M/BBFF", value), Error);
902 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/1M/1LRR", value), Error);
903 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/1M/10D", value), Error);
904 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/1M", value), Error);
905 BOOST_CHECK_THROW(parseMarketDatum(d, "FX_OPTION/RATE_LNVOL/EUR/USD/2019-12", value), Error);
906 }
907 }
908}
909
910BOOST_AUTO_TEST_CASE(testJointCalendar) {
911
912 std::vector<Calendar> cals;
913 std::set<Date> expectedHolidays;
914 // add peruvian holidays
915 expectedHolidays.insert(Date(1, January, 2018));
916 expectedHolidays.insert(Date(29, March, 2018));
917 expectedHolidays.insert(Date(30, March, 2018));
918 expectedHolidays.insert(Date(1, May, 2018));
919 expectedHolidays.insert(Date(29, June, 2018));
920 expectedHolidays.insert(Date(27, July, 2018));
921 expectedHolidays.insert(Date(30, August, 2018));
922 expectedHolidays.insert(Date(31, August, 2018));
923 expectedHolidays.insert(Date(8, October, 2018));
924 expectedHolidays.insert(Date(1, November, 2018));
925 expectedHolidays.insert(Date(2, November, 2018));
926 expectedHolidays.insert(Date(25, December, 2018));
927
928 Calendar peru = QuantExt::Peru();
929
930 cals.push_back(peru);
931 Calendar joint1 = QuantLib::JointCalendar(cals);
932
933 std::vector<Date> hol = joint1.holidayList(Date(1, January, 2018), Date(31, December, 2018));
934 BOOST_CHECK(hol.size() == expectedHolidays.size());
935
936 checkCalendars(expectedHolidays, hol);
937
938 // add columbian holidays
939 expectedHolidays.insert(Date(1, January, 2018));
940 expectedHolidays.insert(Date(8, January, 2018));
941 expectedHolidays.insert(Date(19, March, 2018));
942 expectedHolidays.insert(Date(29, March, 2018));
943 expectedHolidays.insert(Date(30, March, 2018));
944 expectedHolidays.insert(Date(1, May, 2018));
945 expectedHolidays.insert(Date(14, May, 2018));
946 expectedHolidays.insert(Date(4, June, 2018));
947 expectedHolidays.insert(Date(11, June, 2018));
948 expectedHolidays.insert(Date(2, July, 2018));
949 expectedHolidays.insert(Date(20, July, 2018));
950 expectedHolidays.insert(Date(7, August, 2018));
951 expectedHolidays.insert(Date(20, August, 2018));
952 expectedHolidays.insert(Date(15, October, 2018));
953 expectedHolidays.insert(Date(5, November, 2018));
954 expectedHolidays.insert(Date(12, November, 2018));
955 expectedHolidays.insert(Date(25, December, 2018));
956
957 Calendar col = Colombia();
958 cals.push_back(col);
959 Calendar joint2 = QuantLib::JointCalendar(cals);
960
961 hol = joint2.holidayList(Date(1, January, 2018), Date(31, December, 2018));
962 BOOST_CHECK(hol.size() == expectedHolidays.size());
963 checkCalendars(expectedHolidays, hol);
964
965 // add philippines holidays
966 expectedHolidays.insert(Date(1, January, 2018));
967 expectedHolidays.insert(Date(2, January, 2018));
968 expectedHolidays.insert(Date(29, March, 2018));
969 expectedHolidays.insert(Date(30, March, 2018));
970 expectedHolidays.insert(Date(9, April, 2018));
971 expectedHolidays.insert(Date(1, May, 2018));
972 expectedHolidays.insert(Date(12, June, 2018));
973 expectedHolidays.insert(Date(21, August, 2018));
974 expectedHolidays.insert(Date(27, August, 2018));
975 expectedHolidays.insert(Date(1, November, 2018));
976 expectedHolidays.insert(Date(30, November, 2018));
977 expectedHolidays.insert(Date(25, December, 2018));
978 expectedHolidays.insert(Date(31, December, 2018));
979
980 Calendar phil = Philippines();
981 cals.push_back(phil);
982 Calendar joint3 = QuantLib::JointCalendar(cals);
983
984 hol = joint3.holidayList(Date(1, January, 2018), Date(31, December, 2018));
985 BOOST_CHECK(hol.size() == expectedHolidays.size());
986 checkCalendars(expectedHolidays, hol);
987
988 // add thailand holidays
989 expectedHolidays.insert(Date(1, January, 2018));
990 expectedHolidays.insert(Date(2, January, 2018));
991 expectedHolidays.insert(Date(1, March, 2018)); // Makha Bucha Day
992 expectedHolidays.insert(Date(6, April, 2018));
993 expectedHolidays.insert(Date(13, April, 2018));
994 expectedHolidays.insert(Date(16, April, 2018));
995 expectedHolidays.insert(Date(1, May, 2018));
996 expectedHolidays.insert(Date(29, May, 2018)); // Wisakha Bucha Day
997 expectedHolidays.insert(Date(27, July, 2018)); // Asarnha Bucha Day
998 expectedHolidays.insert(Date(30, July, 2018));
999 expectedHolidays.insert(Date(13, August, 2018));
1000 expectedHolidays.insert(Date(15, October, 2018));
1001 expectedHolidays.insert(Date(23, October, 2018));
1002 expectedHolidays.insert(Date(5, December, 2018));
1003 expectedHolidays.insert(Date(10, December, 2018));
1004 expectedHolidays.insert(Date(31, December, 2018));
1005
1006 Calendar thai = Thailand();
1007 cals.push_back(thai);
1008 Calendar joint4 = QuantLib::JointCalendar(cals);
1009
1010 hol = joint4.holidayList(Date(1, January, 2018), Date(31, December, 2018));
1011 BOOST_CHECK(hol.size() == expectedHolidays.size());
1012 checkCalendars(expectedHolidays, hol);
1013
1014 // add malaysia holidays
1015 expectedHolidays.insert(Date(1, January, 2018));
1016 expectedHolidays.insert(Date(1, February, 2018));
1017 expectedHolidays.insert(Date(1, May, 2018));
1018 expectedHolidays.insert(Date(31, August, 2018));
1019 expectedHolidays.insert(Date(17, September, 2018));
1020 expectedHolidays.insert(Date(25, December, 2018));
1021
1022 Calendar mal = Malaysia();
1023 cals.push_back(mal);
1024 Calendar joint5 = QuantLib::JointCalendar(cals);
1025
1026 hol = joint5.holidayList(Date(1, January, 2018), Date(31, December, 2018));
1027 BOOST_CHECK(hol.size() == expectedHolidays.size());
1028 checkCalendars(expectedHolidays, hol);
1029
1030 // add chilean calendar
1031 expectedHolidays.insert(Date(1, January, 2018));
1032 expectedHolidays.insert(Date(30, March, 2018));
1033 expectedHolidays.insert(Date(1, May, 2018));
1034 expectedHolidays.insert(Date(21, May, 2018));
1035 expectedHolidays.insert(Date(2, July, 2018));
1036 expectedHolidays.insert(Date(16, July, 2018));
1037 expectedHolidays.insert(Date(15, August, 2018));
1038 expectedHolidays.insert(Date(17, September, 2018));
1039 expectedHolidays.insert(Date(18, September, 2018));
1040 expectedHolidays.insert(Date(19, September, 2018));
1041 expectedHolidays.insert(Date(15, October, 2018));
1042 expectedHolidays.insert(Date(1, November, 2018));
1043 expectedHolidays.insert(Date(2, November, 2018));
1044 expectedHolidays.insert(Date(25, December, 2018));
1045
1046 Calendar chil = Chile();
1047 cals.push_back(chil);
1048 Calendar joint6 = QuantLib::JointCalendar(cals);
1049
1050 hol = joint6.holidayList(Date(1, January, 2018), Date(31, December, 2018));
1051 BOOST_CHECK(hol.size() == expectedHolidays.size());
1052 checkCalendars(expectedHolidays, hol);
1053
1054 // add netherlands calendar
1055 expectedHolidays.insert(Date(1, January, 2018));
1056 expectedHolidays.insert(Date(30, March, 2018));
1057 expectedHolidays.insert(Date(2, April, 2018));
1058 expectedHolidays.insert(Date(27, April, 2018));
1059 expectedHolidays.insert(Date(10, May, 2018));
1060 expectedHolidays.insert(Date(21, May, 2018));
1061 expectedHolidays.insert(Date(25, December, 2018));
1062 expectedHolidays.insert(Date(26, December, 2018));
1063
1064 Calendar net = Netherlands();
1065 cals.push_back(net);
1066 Calendar joint7 = QuantLib::JointCalendar(cals);
1067
1068 hol = joint7.holidayList(Date(1, January, 2018), Date(31, December, 2018));
1069 BOOST_CHECK(hol.size() == expectedHolidays.size());
1070 checkCalendars(expectedHolidays, hol);
1071
1072 // add French calendar
1073 expectedHolidays.insert(Date(1, January, 2018));
1074 expectedHolidays.insert(Date(30, March, 2018));
1075 expectedHolidays.insert(Date(2, April, 2018));
1076 expectedHolidays.insert(Date(1, May, 2018));
1077 expectedHolidays.insert(Date(8, May, 2018));
1078 expectedHolidays.insert(Date(10, May, 2018));
1079 expectedHolidays.insert(Date(21, May, 2018));
1080 expectedHolidays.insert(Date(15, August, 2018));
1081 expectedHolidays.insert(Date(1, November, 2018));
1082 expectedHolidays.insert(Date(25, December, 2018));
1083 expectedHolidays.insert(Date(26, December, 2018));
1084
1085 Calendar fre = France();
1086 cals.push_back(fre);
1087 Calendar joint8 = QuantLib::JointCalendar(cals);
1088
1089 hol = joint8.holidayList(Date(1, January, 2018), Date(31, December, 2018));
1090 BOOST_CHECK(hol.size() == expectedHolidays.size());
1091 checkCalendars(expectedHolidays, hol);
1092}
1093
1094BOOST_AUTO_TEST_CASE(testParseBoostAny) {
1095
1096 BOOST_TEST_MESSAGE("Testing parsing of Boost::Any...");
1097
1098 // For QuantLib::Array
1099 Array arr(5, 3);
1100 boost::any any_array = boost::any_cast<Array>(arr);
1101 std::pair<std::string, std::string> result;
1102 BOOST_REQUIRE_NO_THROW(result = ore::data::parseBoostAny(any_array, 0));
1103 BOOST_CHECK_EQUAL(result.first, "array");
1104 BOOST_CHECK_EQUAL(result.second, "[ 3; 3; 3; 3; 3 ]");
1105}
1106
1107BOOST_AUTO_TEST_CASE(testParseBoostAnyWithCurrency) {
1108
1109 BOOST_TEST_MESSAGE("Testing parsing of Boost::Any...");
1110
1111 Currency usd = USDCurrency();
1112 std::pair<std::string, std::string> result;
1113 BOOST_REQUIRE_NO_THROW(result = ore::data::parseBoostAny(usd));
1114 BOOST_CHECK_EQUAL(result.first, "currency");
1115 BOOST_CHECK_EQUAL(result.second, "USD");
1116}
1117
1118BOOST_AUTO_TEST_SUITE_END()
1119
1120BOOST_AUTO_TEST_SUITE_END()
Commodity forward quote class.
Commodity spot quote class.
FX Option data class.
Base market data class.
Definition: marketdatum.hpp:78
SafeStack< ValueType > value
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
Strike parseStrike(const std::string &s)
Convert text to Strike.
Definition: strike.cpp:30
pair< string, string > parseBoostAny(const boost::any &anyType, Size precision)
Definition: parsers.cpp:859
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
boost::variant< QuantLib::Date, QuantLib::Period > parseDateOrPeriod(const string &s)
Convert text to QuantLib::Period or QuantLib::Date.
Definition: parsers.cpp:493
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
Frequency parseFrequency(const string &s)
Convert text to QuantLib::Frequency.
Definition: parsers.cpp:348
Compounding parseCompounding(const string &s)
Convert text to QuantLib::Compounding;.
Definition: parsers.cpp:376
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
Market Datum parser.
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
void checkCalendars(const std::vector< Date > &expectedHolidays, const std::vector< Date > &testHolidays)
BOOST_AUTO_TEST_CASE(testDayCounterParsing)
Definition: parser.cpp:152
Map text representations to QuantLib/QuantExt types.
strike description