Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
yieldcurve.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 Copyright (C) 2021 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// clang-format off
21#include <boost/test/unit_test.hpp>
22#include <boost/test/data/test_case.hpp>
23// clang-format on
31#include <oret/datapaths.hpp>
32#include <oret/toplevelfixture.hpp>
33
34#include <boost/algorithm/string.hpp>
35#include <boost/make_shared.hpp>
36
37using namespace QuantLib;
38using namespace QuantExt;
39using namespace boost::unit_test_framework;
40using namespace std;
41using namespace ore;
42using namespace ore::data;
43
45
46namespace {
47
48struct ZeroDatum {
49 string date;
50 double zero;
51};
52
53struct ExpectedResult {
54 string date;
55 double rate;
56 double discount;
57 double zero;
58};
59
60class MarketDataLoader : public Loader {
61public:
62 MarketDataLoader();
63 MarketDataLoader(vector<string> data);
64 vector<QuantLib::ext::shared_ptr<MarketDatum>> loadQuotes(const Date&) const override;
65 set<Fixing> loadFixings() const override { return fixings_; }
66 set<QuantExt::Dividend> loadDividends() const override { return dividends_; }
67 void add(QuantLib::Date date, const string& name, QuantLib::Real value) {}
68 void addFixing(QuantLib::Date date, const string& name, QuantLib::Real value) {}
69 void addDividend(const QuantExt::Dividend& div) {}
70
71private:
72 map<Date, vector<QuantLib::ext::shared_ptr<MarketDatum>>> data_;
73 set<Fixing> fixings_;
74 set<QuantExt::Dividend> dividends_;
75};
76
77vector<QuantLib::ext::shared_ptr<MarketDatum>> MarketDataLoader::loadQuotes(const Date& d) const {
78 auto it = data_.find(d);
79 QL_REQUIRE(it != data_.end(), "Loader has no data for date " << d);
80 return it->second;
81}
82
83MarketDataLoader::MarketDataLoader() {
84
85 vector<string> data{"20150831 IR_SWAP/RATE/JPY/2D/6M/2Y 0.0022875"};
86
87 for (auto s : data) {
88 vector<string> tokens;
89 boost::trim(s);
90 boost::split(tokens, s, boost::is_any_of(" "), boost::token_compress_on);
91
92 QL_REQUIRE(tokens.size() == 3, "Invalid market data line, 3 tokens expected " << s);
93 Date date = parseDate(tokens[0]);
94 const string& key = tokens[1];
95 Real value = parseReal(tokens[2]);
96 data_[date].push_back(parseMarketDatum(date, key, value));
97 }
98}
99
100MarketDataLoader::MarketDataLoader(vector<string> data) {
101
102 for (auto s : data) {
103 vector<string> tokens;
104 boost::trim(s);
105 boost::split(tokens, s, boost::is_any_of(" "), boost::token_compress_on);
106
107 QL_REQUIRE(tokens.size() == 3, "Invalid market data line, 3 tokens expected " << s);
108 Date date = parseDate(tokens[0]);
109 const string& key = tokens[1];
110 Real value = parseReal(tokens[2]);
111 data_[date].push_back(parseMarketDatum(date, key, value));
112 }
113}
114
115// List of curve configuration files that set up an ARS-IN-USD curve with various interpolation methods and variables.
116// We have a set of files under ars_in_usd/failing and a set under ars_in_usd/passing:
117// - failing: has the old QuantLib::IterativeBootstrap parameters i.e. 1 attempt with hard bounds
118// - passing: has the default QuantExt::IterativeBootstrap parameters i.e. 5 attempts with widening bounds
119vector<string> curveConfigFiles = {"discount_linear.xml",
120 "discount_loglinear.xml",
121 "discount_natural_cubic.xml",
122 "discount_financial_cubic.xml",
123 "zero_linear.xml",
124 "zero_natural_cubic.xml",
125 "zero_financial_cubic.xml",
126 "forward_linear.xml",
127 "forward_natural_cubic.xml",
128 "forward_financial_cubic.xml",
129 "forward_convex_monotone.xml"};
130
131// Construct and hold the arguments needed to construct a TodaysMarket.
132struct TodaysMarketArguments {
133
134 TodaysMarketArguments(const Date& asof, const string& inputDir, const string& curveConfigFile = "curveconfig.xml")
135 : asof(asof) {
136
137 Settings::instance().evaluationDate() = asof;
138
139 string filename = inputDir + "/conventions.xml";
140 conventions->fromFile(TEST_INPUT_FILE(filename));
141 InstrumentConventions::instance().setConventions(conventions);
142
143 filename = inputDir + "/" + curveConfigFile;
144 curveConfigs->fromFile(TEST_INPUT_FILE(filename));
145
146 filename = inputDir + "/todaysmarket.xml";
147 todaysMarketParameters->fromFile(TEST_INPUT_FILE(filename));
148
149 filename = inputDir + "/market.txt";
150 string fixingsFilename = inputDir + "/fixings.txt";
151 loader = QuantLib::ext::make_shared<CSVLoader>(TEST_INPUT_FILE(filename), TEST_INPUT_FILE(fixingsFilename), false);
152 }
153
154 Date asof;
155 QuantLib::ext::shared_ptr<Conventions> conventions = QuantLib::ext::make_shared<Conventions>();
156 QuantLib::ext::shared_ptr<CurveConfigurations> curveConfigs = QuantLib::ext::make_shared<CurveConfigurations>();
157 QuantLib::ext::shared_ptr<TodaysMarketParameters> todaysMarketParameters = QuantLib::ext::make_shared<TodaysMarketParameters>();
158 QuantLib::ext::shared_ptr<Loader> loader;
159};
160
161// Used to check that the exception message contains the expected message string, expMsg.
162struct ExpErrorPred {
163
164 ExpErrorPred(const string& msg) : expMsg(msg) {}
165
166 bool operator()(const Error& ex) {
167 string errMsg(ex.what());
168 return errMsg.find(expMsg) != string::npos;
169 }
170
171 string expMsg;
172};
173
174// Test yield curve bootstrap from overnight index futures where the first future in the list of instruments may be
175// expired. We use the March 2020 SOFR future contract whose last trade date is 16 Jun 2020 with settlement date 17
176// Jun 2020. A number of cases are tested:
177// 1. Valuation date is 9 Jun 2020. March 2020 SOFR future should be included in bootstrap fine.
178// 2. Valuation date is 16 Jun 2020. March 2020 SOFR future should be included in bootstrap. The final SOFR fixing
179// i.e. the fixing for 16 Jun 2020 will not be known on 16 Jun 2020.
180// 3. Valuation date is 17 Jun 2020. March 2020 SOFR future should be excluded from the bootstrap.
181// 4. Valuation date is 23 Jun 2020. March 2020 SOFR future should be excluded from the bootstrap.
182
183struct FutureCase {
184 Date date;
185 string desc;
186};
187
188vector<FutureCase> oiFutureCases{{Date(9, Jun, 2020), "before_ltd"},
189 {Date(16, Jun, 2020), "on_ltd"},
190 {Date(17, Jun, 2020), "on_settlement"},
191 {Date(23, Jun, 2020), "after_ltd"}};
192
193// Test yield curve bootstrap from money market futures where the first future in the list of instruments has an ibor
194// start date that is before, on and after the valuation date. We use the August 2020 Eurodollar future contract whose
195// last trade date is 17 Aug 2020 with an underlying ibor start date of 19 Aug 2020. Note that the USD-LIBOR-3M fixing
196// is known on 17 Aug 2020 and the future expires on this date with the associated final settlement price. A number of
197// cases are tested:
198// 1. Valuation date is 18 Aug 2020. August 2020 Eurodollar future should be included in bootstrap.
199// 2. Valuation date is 19 Aug 2020. August 2020 Eurodollar future should be included in bootstrap.
200// 3. Valuation date is 20 Aug 2020. August 2020 Eurodollar future should be excluded from the bootstrap.
201vector<FutureCase> mmFutureCases{{Date(18, Aug, 2020), "before_ibor_start"},
202 {Date(19, Aug, 2020), "on_ibor_start"},
203 {Date(20, Aug, 2020), "after_ibor_start"}};
204
205ostream& operator<<(ostream& os, const FutureCase& c) {
206 return os << "Date is " << io::iso_date(c.date) << " and case is " << c.desc << ".";
207}
208
209} // namespace
210
211BOOST_FIXTURE_TEST_SUITE(OREDataTestSuite, ore::test::TopLevelFixture)
212
213BOOST_AUTO_TEST_SUITE(YieldCurveTests)
214
215BOOST_AUTO_TEST_CASE(testBootstrapAndFixings) {
216
217 Date asof(31, August, 2015);
218 Settings::instance().evaluationDate() = asof;
219
220 YieldCurveSpec spec("JPY", "JPY6M");
221
223 vector<QuantLib::ext::shared_ptr<YieldCurveSegment>> segments{QuantLib::ext::make_shared<SimpleYieldCurveSegment>(
224 "Swap", "JPY-SWAP-CONVENTIONS", vector<string>(1, "IR_SWAP/RATE/JPY/2D/6M/2Y"))};
225 QuantLib::ext::shared_ptr<YieldCurveConfig> jpyYieldConfig =
226 QuantLib::ext::make_shared<YieldCurveConfig>("JPY6M", "JPY 6M curve", "JPY", "", segments);
227 curveConfigs.add(CurveSpec::CurveType::Yield, "JPY6M", jpyYieldConfig);
228
229 MarketDataLoader loader;
230
231 // QL >= 1.19 should not throw, no matter if the float convention has the correct calendar
232
233 QuantLib::ext::shared_ptr<Conventions> conventions = QuantLib::ext::make_shared<Conventions>();
234 InstrumentConventions::instance().setConventions(conventions);
235
236 QuantLib::ext::shared_ptr<Convention> convention =
237 QuantLib::ext::make_shared<IRSwapConvention>("JPY-SWAP-CONVENTIONS", "JP", "Semiannual", "MF", "A365", "JPY-LIBOR-6M");
238 conventions->add(convention);
239
240 BOOST_CHECK_NO_THROW(YieldCurve jpyYieldCurve(asof, spec, curveConfigs, loader));
241
242 conventions->clear();
243 convention = QuantLib::ext::make_shared<IRSwapConvention>("JPY-SWAP-CONVENTIONS", "JP,UK", "Semiannual", "MF", "A365",
244 "JPY-LIBOR-6M");
245 conventions->add(convention);
246 BOOST_CHECK_NO_THROW(YieldCurve jpyYieldCurve(asof, spec, curveConfigs, loader));
247}
248
249BOOST_AUTO_TEST_CASE(testBuildDiscountCurveDirectSegment) {
250
251 Date asof(13, October, 2023);
252 Settings::instance().evaluationDate() = asof;
253
254 YieldCurveSpec spec("EUR", "EUR-CURVE");
255
257
258 vector<string> quotes;
259 quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-14");
260 quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-15");
261
262 vector<QuantLib::ext::shared_ptr<YieldCurveSegment>> segments{QuantLib::ext::make_shared<DirectYieldCurveSegment>(
263 "Discount", "", quotes)};
264
265 QuantLib::ext::shared_ptr<YieldCurveConfig> yCConfig =
266 QuantLib::ext::make_shared<YieldCurveConfig>("EUR-CURVE", "ORE YieldCurve built from EUR-CURVE", "EUR", "", segments);
267 curveConfigs.add(CurveSpec::CurveType::Yield, "EUR-CURVE", yCConfig);
268
269 vector<string> data{"2023-10-12 DISCOUNT/RATE/SEK/STINA-CURVE/2023-10-13 0.77",
270 "2023-10-12 DISCOUNT/RATE/EUR/EUR-ANOTHER-CURVE/2023-10-13 0.95",
271 "2023-10-13 DISCOUNT/RATE/EUR/EUR-ANOTHER-CURVE/2023-10-14 0.95",
272 "2023-10-12 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-12 0.88",
273 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-13 1.0",
274 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-14 0.99",
275 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-15 0.98",
276 "2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-10-31 1158.8",
277 "2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-11-01 1160.9",
278 "2023-10-13 COMMODITY_FWD/PRICE/GOLD/USD/2023-11-02 1163.4"};
279 MarketDataLoader loader(data);
280
281 BOOST_CHECK_NO_THROW(YieldCurve yieldCurve(asof, spec, curveConfigs, loader));
282}
283
284BOOST_AUTO_TEST_CASE(testBuildDiscountCurveDirectSegmentWildcard) {
285
286 Date asof(13, October, 2023);
287 Settings::instance().evaluationDate() = asof;
288
289 YieldCurveSpec spec("EUR", "EUR-CURVE");
290
292
293 vector<string> quotes;
294 quotes.emplace_back("DISCOUNT/RATE/EUR/EUR-CURVE/*");
295
296 vector<QuantLib::ext::shared_ptr<YieldCurveSegment>> segments{
297 QuantLib::ext::make_shared<DirectYieldCurveSegment>("Discount", "", quotes)};
298
299 QuantLib::ext::shared_ptr<YieldCurveConfig> yCConfig = QuantLib::ext::make_shared<YieldCurveConfig>(
300 "EUR-CURVE", "ORE YieldCurve built from EUR-CURVE", "EUR", "", segments);
301 curveConfigs.add(CurveSpec::CurveType::Yield, "EUR-CURVE", yCConfig);
302
303 vector<string> data{"2023-10-12 DISCOUNT/RATE/SEK/STINA-CURVE/2023-10-13 0.77",
304 "2023-10-12 DISCOUNT/RATE/EUR/EUR-ANOTHER-CURVE/2023-10-13 0.95",
305 "2023-10-13 DISCOUNT/RATE/EUR/EUR-ANOTHER-CURVE/2023-10-14 0.95",
306 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-13 1.0",
307 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-14 0.99",
308 "2023-10-13 DISCOUNT/RATE/EUR/EUR-CURVE/2023-10-15 0.98",
309 "2023-10-13 EQUITY_FWD/PRICE/SP5/USD/1Y 1500.00",
310 "2023-10-13 EQUITY_FWD/PRICE/SP5/USD/20231014 1500.00",
311 "2023-10-13 EQUITY_DIVIDEND/RATE/SP5/USD/20231015 0.00",
312 "2023-10-13 EQUITY_DIVIDEND/RATE/SP5/USD/2Y 0.00"};
313 MarketDataLoader loader(data);
314
315 BOOST_CHECK_NO_THROW(YieldCurve yieldCurve(asof, spec, curveConfigs, loader));
316}
317
318// Test ARS-IN-USD failures using the old QuantLib::IterativeBootstrap parameters
319BOOST_DATA_TEST_CASE(testBootstrapARSinUSDFailures, bdata::make(curveConfigFiles), curveConfigFile) {
320
321 BOOST_TEST_MESSAGE("Testing ARS-IN-USD fails with configuration file: failing/" << curveConfigFile);
322
323 TodaysMarketArguments tma(Date(25, Sep, 2019), "ars_in_usd", "failing/" + curveConfigFile);
324
325 QuantLib::ext::shared_ptr<TodaysMarket> todaysMarket;
326 BOOST_CHECK_EXCEPTION(todaysMarket =
327 QuantLib::ext::make_shared<TodaysMarket>(tma.asof, tma.todaysMarketParameters, tma.loader,
328 tma.curveConfigs, false, false),
329 Error, ExpErrorPred("yield curve building failed for curve ARS-IN-USD"));
330}
331
332// Test ARS-IN-USD passes using the new QuantExt::IterativeBootstrap parameters
333BOOST_DATA_TEST_CASE(testBootstrapARSinUSDPasses, bdata::make(curveConfigFiles), curveConfigFile) {
334
335 BOOST_TEST_MESSAGE("Testing ARS-IN-USD passes with configuration file: passing/" << curveConfigFile);
336
337 TodaysMarketArguments tma(Date(25, Sep, 2019), "ars_in_usd", "passing/" + curveConfigFile);
338
339 QuantLib::ext::shared_ptr<TodaysMarket> todaysMarket;
340 BOOST_REQUIRE_NO_THROW(todaysMarket =
341 QuantLib::ext::make_shared<TodaysMarket>(tma.asof, tma.todaysMarketParameters, tma.loader,
342 tma.curveConfigs, false, false));
343
344 Handle<YieldTermStructure> yts = todaysMarket->discountCurve("ARS");
345 BOOST_TEST_MESSAGE("Discount: " << std::fixed << std::setprecision(14) << yts->discount(1.0));
346}
347
348BOOST_DATA_TEST_CASE(testOiFirstFutureDateVsValuationDate, bdata::make(oiFutureCases), oiFutureCase) {
349
350 BOOST_TEST_MESSAGE("Testing OI future. " << oiFutureCase);
351
352 BOOST_TEST_CONTEXT(oiFutureCase) {
353
354 TodaysMarketArguments tma(oiFutureCase.date, "oi_future/" + oiFutureCase.desc);
355
356 QuantLib::ext::shared_ptr<TodaysMarket> todaysMarket;
357 BOOST_REQUIRE_NO_THROW(todaysMarket =
358 QuantLib::ext::make_shared<TodaysMarket>(tma.asof, tma.todaysMarketParameters, tma.loader,
359 tma.curveConfigs, false, true));
360
361 Handle<YieldTermStructure> yts;
362 BOOST_REQUIRE_NO_THROW(yts = todaysMarket->discountCurve("USD"));
363 BOOST_REQUIRE_NO_THROW(yts->discount(1.0));
364 }
365}
366
367BOOST_DATA_TEST_CASE(testMmFirstFutureDateVsValuationDate, bdata::make(mmFutureCases), mmFutureCase) {
368
369 BOOST_TEST_MESSAGE("Testing money market future. " << mmFutureCase);
370
371 BOOST_TEST_CONTEXT(mmFutureCase) {
372
373 TodaysMarketArguments tma(mmFutureCase.date, "mm_future/" + mmFutureCase.desc);
374
375 QuantLib::ext::shared_ptr<TodaysMarket> todaysMarket;
376 BOOST_REQUIRE_NO_THROW(todaysMarket =
377 QuantLib::ext::make_shared<TodaysMarket>(tma.asof, tma.todaysMarketParameters, tma.loader,
378 tma.curveConfigs, false, true));
379
380 Handle<YieldTermStructure> yts;
381 BOOST_REQUIRE_NO_THROW(yts = todaysMarket->discountCurve("USD"));
382 BOOST_REQUIRE_NO_THROW(yts->discount(1.0));
383 }
384}
385
386BOOST_AUTO_TEST_CASE(testQuadraticInterpolation) {
387
388 Date asof(24, Mar, 2020);
389 Settings::instance().evaluationDate() = asof;
390
391 std::vector<ZeroDatum> zero_data = {
392 { "2020-03-25", -0.00710652430814573 },
393 { "2020-04-27", -0.00741014330032008 },
394 { "2020-05-26", -0.00756626445863218 },
395 { "2020-06-26", -0.00757302703270679 },
396 { "2020-09-28", -0.00741005956787566 },
397 { "2020-12-29", -0.00741819259807242 },
398 { "2021-03-26", -0.00745035004912764 },
399 { "2022-03-28", -0.00724972360299359 },
400 { "2023-03-27", -0.00694809582571432 },
401 { "2024-03-26", -0.00639564747668298 },
402 { "2025-03-26", -0.0056924815618794 },
403 { "2026-03-26", -0.00491308147033043 },
404 { "2027-03-30", -0.00428289071011978 },
405 { "2028-03-27", -0.00365173027918575 },
406 { "2029-03-26", -0.00312018815108916 },
407 { "2030-03-26", -0.00266352161484584 },
408 { "2032-03-30", -0.00179856872850126 },
409 { "2035-03-27", -0.000800546649163958 },
410 { "2040-03-26", -0.000821931627955741 },
411 { "2045-03-27", -0.00149953900205779 },
412 { "2050-03-28", -0.00228805321739911 },
413 };
414
415 YieldCurveSpec spec("CHF", "CHF-OIS");
416
417 vector<string> quotes(zero_data.size());
418 for (Size i=0; i < zero_data.size(); ++i) {
419 quotes[i] = "ZERO/RATE/CHF/CHF-OIS/A365/" + zero_data[i].date;
420 }
421
423 vector<QuantLib::ext::shared_ptr<YieldCurveSegment>> segments{
424 QuantLib::ext::make_shared<DirectYieldCurveSegment>(
425 "Zero", "CHF-ZERO-CONVENTIONS", quotes)
426 };
427 QuantLib::ext::shared_ptr<YieldCurveConfig> chfYieldConfig =
428 QuantLib::ext::make_shared<YieldCurveConfig>("CHF-OIS", "CHF OIS curve", "CHF",
429 "", segments,
430 "Discount", "LogQuadratic");
431 curveConfigs.add(CurveSpec::CurveType::Yield, "CHF-OIS", chfYieldConfig);
432
433 QuantLib::ext::shared_ptr<Conventions> conventions = QuantLib::ext::make_shared<Conventions>();;
434 InstrumentConventions::instance().setConventions(conventions);
435
436 QuantLib::ext::shared_ptr<Convention> convention =
437 QuantLib::ext::make_shared<ZeroRateConvention>("CHF-ZERO-CONVENTIONS", "A365",
438 "CHF", "Compounded", "Annual");
439 conventions->add(convention);
440
441 vector<string> data(zero_data.size());
442 for (Size i=0; i < zero_data.size(); ++i) {
443 data[i] = to_string(asof) + " " + quotes[i] + " ";
444 data[i] += boost::lexical_cast<std::string>(zero_data[i].zero);
445 }
446
447 MarketDataLoader loader(data);
448 YieldCurve chfYieldCurve(asof, spec, curveConfigs, loader);
449
450 BOOST_TEST_MESSAGE("Test zeroRate from YieldCurve against input");
451 for (Size i=0; i < zero_data.size(); ++i) {
452 BOOST_CHECK_CLOSE(
453 chfYieldCurve.handle()->zeroRate(parseDate(zero_data[i].date),
454 Actual365Fixed(), Compounded,
455 Annual).rate(),
456 zero_data[i].zero, 1e-6
457 );
458 }
459
460 // From Front Arena Prime
461 std::vector<ExpectedResult> expected = {
462 { "2020-03-25", -0.00705200739223866, 1.00001953963179, -0.00710652430814573 },
463 { "2020-04-02", -0.00721390912158171, 1.0001778751147, -0.00718723002828103 },
464 { "2020-04-10", -0.00738227311346984, 1.00033965887219, -0.00726491951444497 },
465 { "2020-04-18", -0.00749059894111781, 1.0005044904488, -0.00733665761295088 },
466 { "2020-04-27", -0.00760320907581491, 1.00069307015329, -0.00741014330031875 },
467 { "2020-04-09", -0.00737384545779651, 1.00031926101022, -0.00725553005947521 },
468 { "2020-04-25", -0.00758478528252393, 1.0006509032529, -0.00739447534752169 },
469 { "2020-05-10", -0.00769596247521598, 1.00096977382034, -0.00749931157112393 },
470 { "2020-05-26", -0.0076429042339754, 1.00131178328636, -0.0075662644586304 },
471 { "2020-04-17", -0.00748320484351694, 1.00048373351725, -0.00732801995321264 },
472 { "2020-05-10", -0.00769596247521598, 1.00096977382034, -0.00749931157112393 },
473 { "2020-06-02", -0.00758166464153831, 1.00146009211018, -0.00757891880297334 },
474 { "2020-06-26", -0.00736149127903651, 1.00195965381451, -0.00757302703270502 },
475 { "2020-05-10", -0.00769596247521598, 1.00096977382034, -0.00749931157112393 },
476 { "2020-06-26", -0.00736149127903651, 1.00195965381451, -0.00757302703270502 },
477 { "2020-08-12", -0.00711900322939663, 1.002904625853, -0.00748005210315095 },
478 { "2020-09-28", -0.00719031149285065, 1.00383824668103, -0.00741005956787366 },
479 { "2020-06-02", -0.00758166464153831, 1.00146009211018, -0.00757891880297334 },
480 { "2020-08-11", -0.00712099069506866, 1.00288478786826, -0.0074820952971888 },
481 { "2020-10-20", -0.00728829236142925, 1.00428240351543, -0.00739981858935435 },
482 { "2020-12-29", -0.00748148784771807, 1.00572822439311, -0.00741819259807019 },
483 { "2020-06-24", -0.00738797434533645, 1.00191855412792, -0.00757552258803451 },
484 { "2020-09-24", -0.00717170989259053, 1.00375818166182, -0.0074134982804841 },
485 { "2020-12-24", -0.00747585963708053, 1.00562378840629, -0.00741575708517861 },
486 { "2021-03-26", -0.00740455196858392, 1.00754755952054, -0.00745035004912542 },
487 { "2020-09-24", -0.00717170989259053, 1.00375818166182, -0.0074134982804841 },
488 { "2021-03-26", -0.00740455196858392, 1.00754755952054, -0.00745035004912542 },
489 { "2021-09-25", -0.00694048485996968, 1.01122053890473, -0.0073775427951106 },
490 { "2022-03-28", -0.0066863454350452, 1.01473957125551, -0.00724972360299103 },
491 { "2020-12-24", -0.00747585963708053, 1.00562378840629, -0.00741575708517861 },
492 { "2021-09-24", -0.0069414029672199, 1.01120103496917, -0.00737820251647103 },
493 { "2022-06-25", -0.00656498953875317, 1.01640540717996, -0.00719077356299158 },
494 { "2023-03-27", -0.00558871194802357, 1.02119585320621, -0.00694809582571021 },
495 { "2021-03-25", -0.00741094632973116, 1.00752681818474, -0.00745025320516035 },
496 { "2022-03-26", -0.00668750137850616, 1.01470187085395, -0.00725106794125541 },
497 { "2023-03-26", -0.00559392063686381, 1.02117998518244, -0.00694927326429007 },
498 { "2024-03-26", -0.00380047798675509, 1.02605103251001, -0.0063956474766812 },
499 { "2021-06-24", -0.00715202046442265, 1.0093822458995, -0.00743079826559478 },
500 { "2022-09-24", -0.00634232121085709, 1.01806767055031, -0.00712529508658977 },
501 { "2023-12-25", -0.00422742334270421, 1.02499844543564, -0.00655192842032992 },
502 { "2025-03-26", -0.00172999929889617, 1.02900328433957, -0.00569248156188507 },
503 { "2021-09-24", -0.0069414029672199, 1.01120103496917, -0.00737820251647103 },
504 { "2023-03-26", -0.00559392063686381, 1.02117998518244, -0.00694927326429007 },
505 { "2024-09-24", -0.00286665434442224, 1.0277915286893, -0.00606391607397783 },
506 { "2026-03-26", -0.000727524210795139, 1.03003380594845, -0.00491308147034686 },
507 { "2021-12-25", -0.00678779318060929, 1.01297597811044, -0.00731440818226603 },
508 { "2023-09-26", -0.00466377889755343, 1.02385925805364, -0.00669595300436709 },
509 { "2025-06-27", -0.00119318667783475, 1.02938907952551, -0.00548847866962621 },
510 { "2027-03-30", 0.000117832613426572, 1.0305853419039, -0.00428289071016552 },
511 { "2022-03-26", -0.00668750137850616, 1.01470187085395, -0.00725106794125541 },
512 { "2024-03-26", -0.00380047798675509, 1.02605103251001, -0.0063956474766812 },
513 { "2026-03-27", -0.000729929427953913, 1.03003588754858, -0.00491118220370035 },
514 { "2028-03-27", 0.00112613114121807, 1.02975141478671, -0.00365173027928756 },
515 { "2022-06-25", -0.00656498953875317, 1.01640540717996, -0.00719077356299158 },
516 { "2024-09-24", -0.00286665434442224, 1.0277915286893, -0.00606391607397783 },
517 { "2026-12-25", -0.000343853350512902, 1.03054949871623, -0.00444232736548467 },
518 { "2029-03-26", 0.00122363405024473, 1.02856007847337, -0.00312018815121784 },
519 { "2022-09-24", -0.00634232121085709, 1.01806767055031, -0.00712529508658977 },
520 { "2025-03-25", -0.00173674463422646, 1.02899832012865, -0.00569463011016269 },
521 { "2027-09-24", 0.000888320704621748, 1.03030851958745, -0.00396957339826431 },
522 { "2030-03-26", 0.0017355869817326, 1.02705961730745, -0.00266352161503269 },
523 { "2023-03-27", -0.00558871194802357, 1.02119585320621, -0.00694809582571021 },
524 { "2026-03-28", -0.000730525490939549, 1.0300379726323, -0.00490928522291956 },
525 { "2029-03-29", 0.00122749406191502, 1.02854958382202, -0.00311622139684964 },
526 { "2032-03-30", 0.00320650937346123, 1.02188263368199, -0.00179856872876094 },
527 { "2023-12-25", -0.00422742334270421, 1.02499844543564, -0.00655192842032992 },
528 { "2027-09-25", 0.000889730574376024, 1.03030598533069, -0.00396780181172551 },
529 { "2031-06-26", 0.00265730529292796, 1.02419866540126, -0.00212067173766495 },
530 { "2035-03-27", 0.00203153226992825, 1.01209877900331, -0.000800546649511458 },
531 { "2025-03-25", -0.00173674463422646, 1.02899832012865, -0.00569463011016269 },
532 { "2030-03-26", 0.0017355869817326, 1.02705961730745, -0.00266352161503269 },
533 { "2035-03-26", 0.00203563762406489, 1.0121045019654, -0.000801068999449428 },
534 { "2040-03-26", -0.00294180811111211, 1.0165973929348, -0.000821931627935868 },
535 { "2026-06-25", -0.000760135138913043, 1.03023087322183, -0.00474822200738056 },
536 { "2032-09-24", 0.00346788193350989, 1.02019108824174, -0.00159634484187743 },
537 { "2038-12-25", -0.00217162595274267, 1.01327109910735, -0.000702248267447581 },
538 { "2045-03-27", -0.00536047202242429, 1.03826766081024, -0.00149953900098565 },
539 { "2027-09-25", 0.000889730574376024, 1.03030598533069, -0.00396780181172551 },
540 { "2035-03-27", 0.00203153226992825, 1.01209877900331, -0.000800546649511458 },
541 { "2042-09-26", -0.00416154603709362, 1.02580615300844, -0.0011305804441839 },
542 { "2050-03-28", -0.00655222665784105, 1.07121045806809, -0.0022880532151871 }
543 };
544
545 BOOST_TEST_MESSAGE("Test rates from YieldCurve cached result");
546 for (Size i=0; i < expected.size(); ++i) {
547 BOOST_CHECK_CLOSE(
548 chfYieldCurve.handle()->zeroRate(parseDate(expected[i].date),
549 Actual365Fixed(), Compounded,
550 Annual).rate(),
551 expected[i].zero, 1e-7
552 );
553 BOOST_CHECK_CLOSE(
554 chfYieldCurve.handle()->discount(parseDate(expected[i].date)),
555 expected[i].discount, 1e-7
556 );
557 }
558 BOOST_TEST_MESSAGE("Test rates from YieldCurve cached result");
559 BOOST_CHECK_EQUAL(chfYieldCurve.handle()->discount(asof), 1);
560}
561
562BOOST_AUTO_TEST_SUITE_END()
563
564BOOST_AUTO_TEST_SUITE_END()
Container class for all Curve Configurations.
Market data loader base class.
Definition: loader.hpp:47
Wrapper class for building yield term structures.
Definition: yieldcurve.hpp:61
const Handle< YieldTermStructure > & handle() const
Definition: yieldcurve.hpp:120
Yield curve description.
Definition: curvespec.hpp:108
SafeStack< ValueType > value
Market Datum Loader Implementation.
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Market Datum Loader Interface.
@ data
Definition: log.hpp:77
Market Datum parser.
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
vector< string > curveConfigs
BOOST_AUTO_TEST_CASE(testBootstrapAndFixings)
Definition: yieldcurve.cpp:215
BOOST_DATA_TEST_CASE(testBootstrapARSinUSDFailures, bdata::make(curveConfigFiles), curveConfigFile)
Definition: yieldcurve.cpp:319
string conversion utilities
An concrete implementation of the Market class that loads todays market and builds the required curve...
string name
Wrapper class for QuantLib term structures.