Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
indexparser.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/*! \file ored/utilities/indexparser.cpp
21 \brief
22 \ingroup utilities
23*/
24
25#include <boost/algorithm/string.hpp>
26#include <boost/make_shared.hpp>
27#include <boost/regex.hpp>
28#include <map>
37#include <ql/errors.hpp>
38#include <ql/indexes/all.hpp>
39#include <ql/time/calendars/target.hpp>
40#include <ql/time/daycounters/all.hpp>
43#include <qle/indexes/cacpi.hpp>
46#include <qle/indexes/decpi.hpp>
47#include <qle/indexes/dkcpi.hpp>
49#include <qle/indexes/escpi.hpp>
50#include <qle/indexes/frcpi.hpp>
106#include <qle/indexes/secpi.hpp>
109
110using namespace QuantLib;
111using namespace QuantExt;
112using namespace std;
114
115namespace ore {
116namespace data {
117
118// Helper base class to build an IborIndex with a specific period and term structure given an instance of the same
119// IborIndex
120class IborIndexParser {
121public:
122 virtual ~IborIndexParser() {}
123 virtual QuantLib::ext::shared_ptr<IborIndex> build(Period p, const Handle<YieldTermStructure>& h) const = 0;
124 virtual string family() const = 0;
125};
126
127// General case
128template <class T> class IborIndexParserWithPeriod : public IborIndexParser {
129public:
130 QuantLib::ext::shared_ptr<IborIndex> build(Period p, const Handle<YieldTermStructure>& h) const override {
131 return QuantLib::ext::make_shared<T>(p, h);
132 }
133 string family() const override { return T(3 * Months).familyName(); }
134};
135
136// MXN TIIE
137// If tenor equates to 28 Days, i.e. tenor is 4W or 28D, ensure that the index is created
138// with a tenor of 4W under the hood. Things work better this way especially cap floor stripping.
139// We do the same with 91D -> 3M (a la KRW CD below)
140template <> class IborIndexParserWithPeriod<MXNTiie> : public IborIndexParser {
141public:
142 QuantLib::ext::shared_ptr<IborIndex> build(Period p, const Handle<YieldTermStructure>& h) const override {
143 if (p.units() == Days && p.length() == 28) {
144 return QuantLib::ext::make_shared<MXNTiie>(4 * Weeks, h);
145 } else if (p.units() == Days && p.length() == 91) {
146 return QuantLib::ext::make_shared<MXNTiie>(3 * Months, h);
147 } else if (p.units() == Days && (p.length() >= 180 || p.length() <= 183)) {
148 return QuantLib::ext::make_shared<MXNTiie>(6 * Months, h);
149 } else {
150 return QuantLib::ext::make_shared<MXNTiie>(p, h);
151 }
152 }
153
154 string family() const override { return MXNTiie(4 * Weeks).familyName(); }
155};
156
157// KRW CD
158// If tenor equates to 91 Days, ensure that the index is created with a tenor of 3M under the hood.
159template <> class IborIndexParserWithPeriod<KRWCd> : public IborIndexParser {
160public:
161 QuantLib::ext::shared_ptr<IborIndex> build(Period p, const Handle<YieldTermStructure>& h) const override {
162 if (p.units() == Days && p.length() == 91) {
163 return QuantLib::ext::make_shared<KRWCd>(3 * Months, h);
164 } else {
165 return QuantLib::ext::make_shared<KRWCd>(p, h);
166 }
167 }
168
169 string family() const override { return KRWCd(3 * Months).familyName(); }
170};
171
172// CNY REPOFIX
173// If tenor equates to 7 Days, i.e. tenor is 1W or 7D, ensure that the index is created
174// with a tenor of 1W under the hood. Similarly for 14 days, i.e. 2W.
175template <> class IborIndexParserWithPeriod<CNYRepoFix> : public IborIndexParser {
176public:
177 QuantLib::ext::shared_ptr<IborIndex> build(Period p, const Handle<YieldTermStructure>& h) const override {
178 if (p.units() == Days && p.length() == 7) {
179 return QuantLib::ext::make_shared<CNYRepoFix>(1 * Weeks, h);
180 } else if (p.units() == Days && p.length() == 14) {
181 return QuantLib::ext::make_shared<CNYRepoFix>(2 * Weeks, h);
182 } else {
183 return QuantLib::ext::make_shared<CNYRepoFix>(p, h);
184 }
185 }
186
187 string family() const override { return CNYRepoFix(1 * Weeks).familyName(); }
188};
189
190// Helper function to check that index name to index object is a one-to-one mapping
191void checkOneToOne(const map<string, QuantLib::ext::shared_ptr<OvernightIndex>>& onIndices,
192 const map<string, QuantLib::ext::shared_ptr<IborIndexParser>>& iborIndices) {
193
194 // Should not attempt to add the same family name to the set if the provided mappings are one to one
195 set<string> familyNames;
196
197 for (const auto& kv : onIndices) {
198 auto p = familyNames.insert(kv.second->familyName());
199 QL_REQUIRE(p.second, "Duplicate mapping for overnight index family " << *p.first << " not allowed");
200 }
201
202 for (const auto& kv : iborIndices) {
203 auto p = familyNames.insert(kv.second->family());
204 QL_REQUIRE(p.second, "Duplicate mapping for ibor index family " << *p.first << " not allowed");
205 }
206}
207
208QuantLib::ext::shared_ptr<FxIndex> parseFxIndex(const string& s, const Handle<Quote>& fxSpot,
209 const Handle<YieldTermStructure>& sourceYts,
210 const Handle<YieldTermStructure>& targetYts, const bool useConventions) {
211 std::vector<string> tokens;
212 split(tokens, s, boost::is_any_of("-"));
213 QL_REQUIRE(tokens.size() == 4, "four tokens required in " << s << ": FX-TAG-CCY1-CCY2");
214 QL_REQUIRE(tokens[0] == "FX", "expected first token to be FX");
215 Natural fixingDays = 0;
216 Calendar fixingCalendar = NullCalendar();
217 BusinessDayConvention bdc;
218 if (useConventions)
219 std::tie(fixingDays, fixingCalendar, bdc) = getFxIndexConventions(s);
220 auto index = QuantLib::ext::make_shared<FxIndex>(tokens[1], fixingDays, parseCurrency(tokens[2]), parseCurrency(tokens[3]),
221 fixingCalendar, fxSpot, sourceYts, targetYts);
222
223 IndexNameTranslator::instance().add(index->name(), s);
224 return index;
225}
226
227QuantLib::ext::shared_ptr<QuantExt::EquityIndex2> parseEquityIndex(const string& s) {
228 std::vector<string> tokens;
229 split(tokens, s, boost::is_any_of("-"));
230 QL_REQUIRE(tokens.size() == 2, "two tokens required in " << s << ": EQ-NAME");
231 QL_REQUIRE(tokens[0] == "EQ", "expected first token to be EQ");
232 auto index = QuantLib::ext::make_shared<QuantExt::EquityIndex2>(tokens[1], NullCalendar(), Currency());
233 IndexNameTranslator::instance().add(index->name(), s);
234 return index;
235}
236
237QuantLib::ext::shared_ptr<QuantLib::Index> parseGenericIndex(const string& s) {
238 QL_REQUIRE(boost::starts_with(s, "GENERIC-"), "generic index expected to be of the form GENERIC-*");
239 auto index = QuantLib::ext::make_shared<GenericIndex>(s);
240 IndexNameTranslator::instance().add(index->name(), s);
241 return index;
242}
243
244bool tryParseIborIndex(const string& s, QuantLib::ext::shared_ptr<IborIndex>& index) {
245 try {
246 index = parseIborIndex(s, Handle<YieldTermStructure>());
247 } catch (const std::exception& e) {
248 DLOG("tryParseIborIndex(" << s << ") failed: " << e.what());
249 return false;
250 }
251 return true;
252}
253
254QuantLib::ext::shared_ptr<IborIndex> parseIborIndex(const string& s, const Handle<YieldTermStructure>& h) {
255 string dummy;
256 return parseIborIndex(s, dummy, h);
257}
258
259QuantLib::ext::shared_ptr<IborIndex> parseIborIndex(const string& s, string& tenor, const Handle<YieldTermStructure>& h) {
260
261 // Check the index string is of the required form before doing anything
262 vector<string> tokens;
263 split(tokens, s, boost::is_any_of("-"));
264 QL_REQUIRE(tokens.size() == 2 || tokens.size() == 3,
265 "Two or three tokens required in " << s << ": CCY-INDEX or CCY-INDEX-TERM");
266
267 // Variables used below
268 string indexStem = tokens[0] + "-" + tokens[1];
269 if (tokens.size() == 3) {
270 tenor = tokens[2];
271 } else {
272 tenor = "";
273 }
274
275 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
276 QuantLib::ext::shared_ptr<Convention> c;
277 if (conventions->has(s, Convention::Type::IborIndex) || conventions->has(s, Convention::Type::OvernightIndex))
278 c = conventions->get(s);
279
280 // if we have a convention given, set up the index using this convention, this overrides the parsing from
281 // hardcoded strings below if there is an overlap
282 if (c) {
283 QL_REQUIRE(c->id() == s, "ibor index convention id ('"
284 << c->id() << "') not matching ibor index string to parse ('" << s << "'");
285 Currency ccy = parseCurrency(tokens[0]);
286 if (auto conv = QuantLib::ext::dynamic_pointer_cast<OvernightIndexConvention>(c)) {
287 QL_REQUIRE(tenor.empty(), "no tenor allowed for convention based overnight index ('" << s << "')");
288 auto res = QuantLib::ext::make_shared<OvernightIndex>(tokens[0] + "-" + tokens[1], conv->settlementDays(), ccy,
289 parseCalendar(conv->fixingCalendar()),
290 parseDayCounter(conv->dayCounter()), h);
291 IndexNameTranslator::instance().add(res->name(), s);
292 return res;
293 } else if (auto conv = QuantLib::ext::dynamic_pointer_cast<IborIndexConvention>(c)) {
294 QL_REQUIRE(!tenor.empty(), "no tenor given for convention based Ibor index ('" << s << "'");
295 auto res = QuantLib::ext::make_shared<IborIndex>(tokens[0] + "-" + tokens[1], parsePeriod(tenor),
296 conv->settlementDays(), ccy, parseCalendar(conv->fixingCalendar()),
297 parseBusinessDayConvention(conv->businessDayConvention()),
298 conv->endOfMonth(), parseDayCounter(conv->dayCounter()), h);
299 IndexNameTranslator::instance().add(res->name(), s);
300 return res;
301 } else {
302 QL_FAIL("invalid convention passed to parseIborIndex(): expected OvernightIndexConvention or "
303 "IborIndexConvention");
304 }
305 }
306
307 // if we do not have a convention, look up the index in the hardcoded maps below
308
309 // Map from our _unique internal name_ to an overnight index
310 static map<string, QuantLib::ext::shared_ptr<OvernightIndex>> onIndices = {
311 {"EUR-EONIA", QuantLib::ext::make_shared<Eonia>()},
312 {"EUR-ESTER", QuantLib::ext::make_shared<Estr>()},
313 {"GBP-SONIA", QuantLib::ext::make_shared<Sonia>()},
314 {"JPY-TONAR", QuantLib::ext::make_shared<Tonar>()},
315 {"SGD-SORA", QuantLib::ext::make_shared<Sora>()},
316 {"CHF-TOIS", QuantLib::ext::make_shared<CHFTois>()},
317 {"CHF-SARON", QuantLib::ext::make_shared<CHFSaron>()},
318 {"USD-FedFunds", QuantLib::ext::make_shared<FedFunds>()},
319 {"USD-SOFR", QuantLib::ext::make_shared<Sofr>()},
320 {"USD-Prime", QuantLib::ext::make_shared<PrimeIndex>()},
321 {"USD-AMERIBOR", QuantLib::ext::make_shared<USDAmeribor>()},
322 {"AUD-AONIA", QuantLib::ext::make_shared<Aonia>()},
323 {"CAD-CORRA", QuantLib::ext::make_shared<CORRA>()},
324 {"DKK-DKKOIS", QuantLib::ext::make_shared<DKKOis>()},
325 {"SEK-SIOR", QuantLib::ext::make_shared<SEKSior>()},
326 {"COP-IBR", QuantLib::ext::make_shared<COPIbr>()},
327 {"BRL-CDI", QuantLib::ext::make_shared<BRLCdi>()},
328 {"NOK-NOWA", QuantLib::ext::make_shared<Nowa>()},
329 {"CLP-CAMARA", QuantLib::ext::make_shared<CLPCamara>()},
330 {"NZD-OCR", QuantLib::ext::make_shared<Nzocr>()},
331 {"PLN-POLONIA", QuantLib::ext::make_shared<PLNPolonia>()},
332 {"INR-MIBOROIS", QuantLib::ext::make_shared<INRMiborOis>()},
333 {"GBP-BoEBase", QuantLib::ext::make_shared<BOEBaseRateIndex>()},
334 {"HKD-HONIA", QuantLib::ext::make_shared<HKDHonia>()},
335 {"SEK-STINA", QuantLib::ext::make_shared<SEKStina>()},
336 {"DKK-CITA", QuantLib::ext::make_shared<DKKCita>()},
337 {"THB-THOR", QuantLib::ext::make_shared<THBThor>()}};
338
339 // Map from our _unique internal name_ to an ibor index (the period does not matter here)
340 static map<string, QuantLib::ext::shared_ptr<IborIndexParser>> iborIndices = {
341 {"AUD-BBSW", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Bbsw>>()},
342 {"AUD-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<AUDLibor>>()},
343 {"EUR-EURIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Euribor>>()},
344 {"EUR-EURIBOR365", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Euribor365>>()},
345 {"CAD-CDOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Cdor>>()},
346 {"CNY-SHIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Shibor>>()},
347 {"CZK-PRIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CZKPribor>>()},
348 {"EUR-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<EURLibor>>()},
349 {"USD-AMBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<USDAmbor>>()},
350 {"USD-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<USDLibor>>()},
351 {"GBP-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<GBPLibor>>()},
352 {"JPY-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<JPYLibor>>()},
353 {"JPY-TIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Tibor>>()},
354 {"JPY-EYTIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<JPYEYTIBOR>>()},
355 {"CAD-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CADLibor>>()},
356 {"CHF-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CHFLibor>>()},
357 {"SEK-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SEKLibor>>()},
358 {"SEK-STIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SEKStibor>>()},
359 {"NOK-NIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<NOKNibor>>()},
360 {"HKD-HIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<HKDHibor>>()},
361 {"CNH-HIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CNHHibor>>()},
362 {"CNH-SHIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CNHShibor>>()},
363 {"SAR-SAIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SAibor>>()},
364 {"SGD-SIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SGDSibor>>()},
365 {"SGD-SOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SGDSor>>()},
366 {"DKK-CIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<DKKCibor>>()},
367 {"DKK-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<DKKLibor>>()},
368 {"HUF-BUBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<HUFBubor>>()},
369 {"IDR-IDRFIX", QuantLib::ext::make_shared<IborIndexParserWithPeriod<IDRIdrfix>>()},
370 {"IDR-JIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<IDRJibor>>()},
371 {"ILS-TELBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<ILSTelbor>>()},
372 {"INR-MIFOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<INRMifor>>()},
373 {"MXN-TIIE", QuantLib::ext::make_shared<IborIndexParserWithPeriod<MXNTiie>>()},
374 {"PLN-WIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Wibor>>()},
375 {"SKK-BRIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<SKKBribor>>()},
376 {"NZD-BKBM", QuantLib::ext::make_shared<IborIndexParserWithPeriod<NZDBKBM>>()},
377 {"TRY-TRLIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<TRLibor>>()},
378 {"TWD-TAIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<TWDTaibor>>()},
379 {"MYR-KLIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<MYRKlibor>>()},
380 {"KRW-CD", QuantLib::ext::make_shared<IborIndexParserWithPeriod<KRWCd>>()},
381 {"KRW-KORIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<KRWKoribor>>()},
382 {"ZAR-JIBAR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Jibar>>()},
383 {"RUB-MOSPRIME", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Mosprime>>()},
384 {"RUB-KEYRATE", QuantLib::ext::make_shared<IborIndexParserWithPeriod<RUBKeyRate>>()},
385 {"THB-BIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<THBBibor>>()},
386 {"THB-THBFIX", QuantLib::ext::make_shared<IborIndexParserWithPeriod<THBFIX>>()},
387 {"PHP-PHIREF", QuantLib::ext::make_shared<IborIndexParserWithPeriod<PHPPhiref>>()},
388 {"RON-ROBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<Robor>>()},
389 {"DEM-LIBOR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<DEMLibor>>()},
390 {"CNY-REPOFIX", QuantLib::ext::make_shared<IborIndexParserWithPeriod<CNYRepoFix>>()},
391 {"USD-SOFR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<QuantExt::SofrTerm>>()},
392 {"GBP-SONIA", QuantLib::ext::make_shared<IborIndexParserWithPeriod<QuantExt::SoniaTerm>>()},
393 {"JPY-TONAR", QuantLib::ext::make_shared<IborIndexParserWithPeriod<QuantExt::TonarTerm>>()},
394 {"CAD-CORRA", QuantLib::ext::make_shared<IborIndexParserWithPeriod<QuantExt::CORRATerm>>()}};
395
396 // Check (once) that we have a one-to-one mapping
397 static bool checked = false;
398 if (!checked) {
399 checkOneToOne(onIndices, iborIndices);
400 checked = true;
401 }
402
403 // Simple single case for USD-SIFMA (i.e. BMA)
404 if (indexStem == "USD-SIFMA") {
405 QL_REQUIRE(tenor.empty(), "A tenor is not allowed with USD-SIFMA as it is implied");
406 auto res = QuantLib::ext::make_shared<BMAIndexWrapper>(QuantLib::ext::make_shared<BMAIndex>(h));
407 IndexNameTranslator::instance().add(res->name(), s);
408 return res;
409 }
410
411 // Ibor indices with a tenor, this includes OIS term rates like USD-SOFR-3M
412 auto it = iborIndices.find(indexStem);
413 if (it != iborIndices.end() && !tenor.empty()) {
414 Period p = parsePeriod(tenor);
415 auto res = it->second->build(p, h);
416 IndexNameTranslator::instance().add(res->name(), s);
417 return res;
418 }
419
420 // Overnight indices
421 auto onIt = onIndices.find(indexStem);
422 if (onIt != onIndices.end()) {
423 QL_REQUIRE(tenor.empty(),
424 "A tenor is not allowed with the overnight index " << indexStem << " as it is implied");
425 auto res = onIt->second->clone(h);
426 IndexNameTranslator::instance().add(res->name(), s);
427 return res;
428 }
429
430 // GENERIC indices
431 if (tokens[1] == "GENERIC") {
432 Period p = parsePeriod(tenor);
433 auto ccy = parseCurrency(tokens[0]);
434 auto res = QuantLib::ext::make_shared<GenericIborIndex>(p, ccy, h);
435 IndexNameTranslator::instance().add(res->name(), s);
436 return res;
437 }
438
439 QL_FAIL("parseIborIndex \"" << s << "\" not recognized");
440}
441
442bool isGenericIborIndex(const string& indexName) { return indexName.find("-GENERIC-") != string::npos; }
443
444pair<bool, QuantLib::ext::shared_ptr<ZeroInflationIndex>> isInflationIndex(const string& indexName) {
445
446 QuantLib::ext::shared_ptr<ZeroInflationIndex> index;
447 try {
448 // Currently, only way to have an inflation index is to have a ZeroInflationIndex
449 index = parseZeroInflationIndex(indexName, Handle<ZeroInflationTermStructure>());
450 } catch (...) {
451 return make_pair(false, nullptr);
452 }
453 return make_pair(true, index);
454}
455
456bool isEquityIndex(const string& indexName) {
457 try {
458 parseEquityIndex(indexName);
459 } catch (...) {
460 return false;
461 }
462 return true;
463}
464
465bool isCommodityIndex(const string& indexName) {
466 try {
467 parseCommodityIndex(indexName);
468 } catch (...) {
469 return false;
470 }
471 return true;
472}
473
474bool isGenericIndex(const string& indexName) {
475 try {
476 parseGenericIndex(indexName);
477 }
478 catch (...) {
479 return false;
480 }
481 return true;
482}
483
484// Swap Index Parser base
485class SwapIndexParser {
486public:
487 virtual ~SwapIndexParser() {}
488 virtual QuantLib::ext::shared_ptr<SwapIndex> build(Period p, const Handle<YieldTermStructure>& f,
489 const Handle<YieldTermStructure>& d) const = 0;
490};
491
492// We build with both a forwarding and discounting curve
493template <class T> class SwapIndexParserDualCurve : public SwapIndexParser {
494public:
495 QuantLib::ext::shared_ptr<SwapIndex> build(Period p, const Handle<YieldTermStructure>& f,
496 const Handle<YieldTermStructure>& d) const override {
497 return QuantLib::ext::make_shared<T>(p, f, d);
498 }
499};
500
501QuantLib::ext::shared_ptr<SwapIndex> parseSwapIndex(const string& s, const Handle<YieldTermStructure>& f,
502 const Handle<YieldTermStructure>& d) {
503
504 std::vector<string> tokens;
505 split(tokens, s, boost::is_any_of("-"));
506 QL_REQUIRE(tokens.size() == 3 || tokens.size() == 4,
507 "three or four tokens required in " << s << ": CCY-CMS-TENOR or CCY-CMS-TAG-TENOR");
508 QL_REQUIRE(tokens[0].size() == 3, "invalid currency code in " << s);
509 QL_REQUIRE(tokens[1] == "CMS", "expected CMS as middle token in " << s);
510 Period p = parsePeriod(tokens.back());
511 // use default family name, if none is given
512 string familyName = tokens.size() == 4 ? tokens[0] + "-CMS-" + tokens[2] : tokens[0] + "LiborSwapIsdaFix";
513 Currency ccy = parseCurrency(tokens[0]);
514
515 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
516 QuantLib::ext::shared_ptr<SwapIndexConvention> swapIndexConvention;
517 QuantLib::ext::shared_ptr<IRSwapConvention> irSwapConvention;
518 QuantLib::ext::shared_ptr<OisConvention> oisCompConvention;
519 QuantLib::ext::shared_ptr<AverageOisConvention> oisAvgConvention;
520 if (conventions && conventions->has(s, Convention::Type::SwapIndex)) {
521 swapIndexConvention = QuantLib::ext::dynamic_pointer_cast<SwapIndexConvention>(conventions->get(s));
522 QL_REQUIRE(swapIndexConvention, "internal error: could not cast to SwapIndexConvention");
523 QL_REQUIRE(conventions->has(swapIndexConvention->conventions(), Convention::Type::Swap) ||
524 conventions->has(swapIndexConvention->conventions(), Convention::Type::OIS) ||
525 conventions->has(swapIndexConvention->conventions(), Convention::Type::AverageOIS),
526 "do not have swap or ois conventions for '"
527 << swapIndexConvention->conventions() << "', required from swap index convention '" << s << "'");
528 irSwapConvention =
529 QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(conventions->get(swapIndexConvention->conventions()));
530 oisCompConvention =
531 QuantLib::ext::dynamic_pointer_cast<OisConvention>(conventions->get(swapIndexConvention->conventions()));
532 oisAvgConvention =
533 QuantLib::ext::dynamic_pointer_cast<AverageOisConvention>(conventions->get(swapIndexConvention->conventions()));
534 QL_REQUIRE(irSwapConvention || oisCompConvention || oisAvgConvention,
535 "internal error: could not cast to IRSwapConvention, OisConvention, AverageOisConvention");
536 } else {
537 // set default conventions using a generic ibor index
538 irSwapConvention = QuantLib::ext::make_shared<IRSwapConvention>("dummy_swap_conv_" + tokens[0], tokens[0], "Annual",
539 "MF", "A365", tokens[0] + "-GENERIC-3M");
540 swapIndexConvention = QuantLib::ext::make_shared<SwapIndexConvention>("dummy_swapindex_conv_" + tokens[0],
541 "dummy_swap_conv_" + tokens[0], "");
542 }
543
544 QuantLib::ext::shared_ptr<SwapIndex> index;
545 if (irSwapConvention) {
546 Calendar fixingCalendar = swapIndexConvention->fixingCalendar().empty()
547 ? irSwapConvention->fixedCalendar()
548 : parseCalendar(swapIndexConvention->fixingCalendar());
549 index = QuantLib::ext::make_shared<SwapIndex>(familyName, p, irSwapConvention->index()->fixingDays(), ccy,
550 fixingCalendar, Period(irSwapConvention->fixedFrequency()),
551 irSwapConvention->fixedConvention(), irSwapConvention->fixedDayCounter(),
552 irSwapConvention->index()->clone(f), d);
553 } else if (oisCompConvention) {
554 Calendar fixingCalendar = swapIndexConvention->fixingCalendar().empty()
555 ? oisCompConvention->index()->fixingCalendar()
556 : parseCalendar(swapIndexConvention->fixingCalendar());
557 index = QuantLib::ext::make_shared<OvernightIndexedSwapIndex>(
558 familyName, p, oisCompConvention->spotLag(), ccy,
559 QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(oisCompConvention->index()->clone(f)), true,
560 RateAveraging::Compound, Period(oisCompConvention->fixedFrequency()), d);
561 } else if (oisAvgConvention) {
562 Calendar fixingCalendar = swapIndexConvention->fixingCalendar().empty()
563 ? oisAvgConvention->index()->fixingCalendar()
564 : parseCalendar(swapIndexConvention->fixingCalendar());
565 auto index = QuantLib::ext::make_shared<OvernightIndexedSwapIndex>(
566 familyName, p, oisAvgConvention->spotLag(), ccy,
567 QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(oisAvgConvention->index()->clone(f)), true,
568 RateAveraging::Simple, Period(oisAvgConvention->fixedFrequency()), d);
569 IndexNameTranslator::instance().add(index->name(), s);
570 return index;
571 } else {
572 QL_FAIL("internal error: expected irSwapConvention, oisConvention, averageOisConvention to be not null");
573 }
574 IndexNameTranslator::instance().add(index->name(), s);
575 return index;
576}
577
578// Zero Inflation Index Parser
579class ZeroInflationIndexParserBase {
580public:
581 virtual ~ZeroInflationIndexParserBase() {}
582 virtual QuantLib::ext::shared_ptr<ZeroInflationIndex> build(const Handle<ZeroInflationTermStructure>& h) const = 0;
583 virtual QL_DEPRECATED QuantLib::ext::shared_ptr<ZeroInflationIndex>
584 build(bool isInterpolated, const Handle<ZeroInflationTermStructure>& h) const = 0;
585};
586
587template <class T> class ZeroInflationIndexParser : public ZeroInflationIndexParserBase {
588public:
589 QuantLib::ext::shared_ptr<ZeroInflationIndex> build(const Handle<ZeroInflationTermStructure>& h) const override {
590 return QuantLib::ext::make_shared<T>(h);
591 }
592
593 QL_DEPRECATED QuantLib::ext::shared_ptr<ZeroInflationIndex> build(bool isInterpolated,
594 const Handle<ZeroInflationTermStructure>& h) const override {
595 return QuantLib::ext::make_shared<T>(isInterpolated, h);
596 }
597};
598
599template <class T> class ZeroInflationIndexParserWithFrequency : public ZeroInflationIndexParserBase {
600public:
601 ZeroInflationIndexParserWithFrequency(Frequency frequency) : frequency_(frequency) {}
602
603 QuantLib::ext::shared_ptr<ZeroInflationIndex> build(const Handle<ZeroInflationTermStructure>& h) const override {
604 return QuantLib::ext::make_shared<T>(frequency_, false, h);
605 }
606
607 QuantLib::ext::shared_ptr<ZeroInflationIndex> build(bool isInterpolated,
608 const Handle<ZeroInflationTermStructure>& h) const override {
609 return QuantLib::ext::make_shared<T>(frequency_, false, isInterpolated, h);
610 }
611
612private:
613 Frequency frequency_;
614};
615
616QuantLib::ext::shared_ptr<ZeroInflationIndex> parseZeroInflationIndex(const string& s,
617 const Handle<ZeroInflationTermStructure>& h) {
618 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
619
620 // If conventions are non-null and we have provided a convention of type InflationIndex with a name equal to the
621 // string s, we use that convention to construct the inflation index.
622 if (conventions) {
623 pair<bool, QuantLib::ext::shared_ptr<Convention>> p = conventions->get(s, Convention::Type::ZeroInflationIndex);
624 if (p.first) {
625 auto c = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndexConvention>(p.second);
626 auto index = QuantLib::ext::make_shared<ZeroInflationIndex>(s, c->region(), c->revised(),
627 c->frequency(), c->availabilityLag(), c->currency(), h);
628 IndexNameTranslator::instance().add(index->name(), s);
629 return index;
630 }
631 }
632
633 static map<string, QuantLib::ext::shared_ptr<ZeroInflationIndexParserBase>> m = {
634 {"AUCPI", QuantLib::ext::make_shared<ZeroInflationIndexParserWithFrequency<AUCPI>>(Quarterly)},
635 {"AU CPI", QuantLib::ext::make_shared<ZeroInflationIndexParserWithFrequency<AUCPI>>(Quarterly)},
636 {"BEHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<BEHICP>>()},
637 {"BE HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<BEHICP>>()},
638 {"EUHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICP>>()},
639 {"EU HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICP>>()},
640 {"EUHICPXT", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICPXT>>()},
641 {"EU HICPXT", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICPXT>>()},
642 {"FRHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRHICP>>()},
643 {"FR HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRHICP>>()},
644 {"FRCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRCPI>>()},
645 {"FR CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRCPI>>()},
646 {"UKRPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<UKRPI>>()},
647 {"UK RPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<UKRPI>>()},
648 {"USCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<USCPI>>()},
649 {"US CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<USCPI>>()},
650 {"ZACPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ZACPI>>()},
651 {"ZA CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ZACPI>>()},
652 {"SECPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<SECPI>>()},
653 {"DKCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DKCPI>>()},
654 {"CACPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<CACPI>>()},
655 {"ESCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ESCPI>>()},
656 {"DECPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DECPI>>()},
657 {"DE CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DECPI>>()}};
658
659 auto it = m.find(s);
660 if (it != m.end()) {
661 auto index = it->second->build(h);
662 IndexNameTranslator::instance().add(index->name(), s);
663 return index;
664 } else {
665 QL_FAIL("parseZeroInflationIndex: \"" << s << "\" not recognized");
666 }
667}
668
669
670QuantLib::ext::shared_ptr<ZeroInflationIndex> parseZeroInflationIndex(const string& s,
671 bool isInterpolated,
672 const Handle<ZeroInflationTermStructure>& h) {
673
674 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
675
676 // If conventions are non-null and we have provided a convention of type InflationIndex with a name equal to the
677 // string s, we use that convention to construct the inflation index.
678 if (conventions) {
679 pair<bool, QuantLib::ext::shared_ptr<Convention>> p = conventions->get(s, Convention::Type::ZeroInflationIndex);
680 if (p.first) {
681 auto c = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndexConvention>(p.second);
682 auto index = QuantLib::ext::make_shared<ZeroInflationIndex>(s, c->region(), c->revised(), isInterpolated,
683 c->frequency(), c->availabilityLag(), c->currency(), h);
684 IndexNameTranslator::instance().add(index->name(), s);
685 return index;
686 }
687 }
688
689 static map<string, QuantLib::ext::shared_ptr<ZeroInflationIndexParserBase>> m = {
690 {"AUCPI", QuantLib::ext::make_shared<ZeroInflationIndexParserWithFrequency<AUCPI>>(Quarterly)},
691 {"AU CPI", QuantLib::ext::make_shared<ZeroInflationIndexParserWithFrequency<AUCPI>>(Quarterly)},
692 {"BEHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<BEHICP>>()},
693 {"BE HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<BEHICP>>()},
694 {"EUHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICP>>()},
695 {"EU HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICP>>()},
696 {"EUHICPXT", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICPXT>>()},
697 {"EU HICPXT", QuantLib::ext::make_shared<ZeroInflationIndexParser<EUHICPXT>>()},
698 {"FRHICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRHICP>>()},
699 {"FR HICP", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRHICP>>()},
700 {"FRCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRCPI>>()},
701 {"FR CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<FRCPI>>()},
702 {"UKRPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<UKRPI>>()},
703 {"UK RPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<UKRPI>>()},
704 {"USCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<USCPI>>()},
705 {"US CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<USCPI>>()},
706 {"ZACPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ZACPI>>()},
707 {"ZA CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ZACPI>>()},
708 {"SECPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<SECPI>>()},
709 {"DKCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DKCPI>>()},
710 {"CACPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<CACPI>>()},
711 {"ESCPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<ESCPI>>()},
712 {"DECPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DECPI>>()},
713 {"DE CPI", QuantLib::ext::make_shared<ZeroInflationIndexParser<DECPI>>()}
714 };
715
716 auto it = m.find(s);
717 if (it != m.end()) {
718 QL_DEPRECATED_DISABLE_WARNING
719 auto index = it->second->build(isInterpolated, h);
720 QL_DEPRECATED_ENABLE_WARNING
721 IndexNameTranslator::instance().add(index->name(), s);
722 return index;
723 } else {
724 QL_FAIL("parseZeroInflationIndex: \"" << s << "\" not recognized");
725 }
726}
727
728QuantLib::ext::shared_ptr<BondIndex> parseBondIndex(const string& name) {
729
730 // Make sure the prefix is correct
731 string prefix = name.substr(0, 5);
732 QL_REQUIRE(prefix == "BOND-", "A bond index string must start with 'BOND-' but got " << prefix);
733
734 // Now take the remainder of the string
735 // for spot indices, this should just be the bond name
736 // for future indices, this is of the form NAME-YYYY-MM or NAME-YYYY-MM-DD where NAME is the commodity name
737 // (possibly containing hyphens) and YYYY-MM(-DD) is the expiry date of the futures contract
738 Date expiry;
739 string nameWoPrefix = name.substr(5);
740 string bondName = nameWoPrefix;
741
742 // Check for form NAME-YYYY-MM-DD
743 if (nameWoPrefix.size() > 10) {
744 string test = nameWoPrefix.substr(nameWoPrefix.size() - 10);
745 if (boost::regex_match(test, boost::regex("\\d{4}-\\d{2}-\\d{2}"))) {
746 expiry = parseDate(test);
747 bondName = nameWoPrefix.substr(0, nameWoPrefix.size() - test.size() - 1);
748 }
749 }
750
751 // Check for form NAME-YYYY-MM if NAME-YYYY-MM-DD failed
752 if (expiry == Date() && nameWoPrefix.size() > 7) {
753 string test = nameWoPrefix.substr(nameWoPrefix.size() - 7);
754 if (boost::regex_match(test, boost::regex("\\d{4}-\\d{2}"))) {
755 expiry = parseDate(test + "-01");
756 bondName = nameWoPrefix.substr(0, nameWoPrefix.size() - test.size() - 1);
757 }
758 }
759
760 // Create and return the required future index
761 QuantLib::ext::shared_ptr<BondIndex> index;
762 if (expiry != Date()) {
763 index= QuantLib::ext::make_shared<BondFuturesIndex>(expiry, bondName);
764 } else {
765 index= QuantLib::ext::make_shared<BondIndex>(bondName);
766 }
767 IndexNameTranslator::instance().add(index->name(), name);
768 return index;
769}
770
771QuantLib::ext::shared_ptr<ConstantMaturityBondIndex> parseConstantMaturityBondIndex(const string& name) {
772 // Expected bondId structure with at least three tokens, separated by "-", of the form CMB-FAMILY-TERM, for example:
773 // CMB-US-CMT-5Y, CMB-US-TIPS-10Y, CMB-UK-GILT-5Y, CMB-DE-BUND-10Y
774 // with two tokens in the middle to define the family
775 std::vector<string> tokens;
776 split(tokens, name, boost::is_any_of("-"));
777 QL_REQUIRE(tokens.size() >= 3, "Generic Bond ID with at least two tokens separated by - expected, found " << name);
778
779 // Make sure the prefix is correct
780 std::string prefix = tokens[0];
781 QL_REQUIRE(prefix == "CMB", "A constant maturity bond yield index string must start with 'CMB' but got " << prefix);
782
783 std::string securityFamily = tokens[1];
784 for (Size i = 2; i < tokens.size() - 1; ++i)
785 securityFamily = securityFamily + "-" + tokens[i];
786 Period underlyingPeriod = parsePeriod(tokens.back());
787 QuantLib::ext::shared_ptr<ConstantMaturityBondIndex> i;
788 try {
789 i = QuantLib::ext::make_shared<ConstantMaturityBondIndex>(prefix + "-" + securityFamily, underlyingPeriod);
790 } catch(std::exception& e) {
791 ALOG("error creating CMB index: " << e.what());
792 }
793 IndexNameTranslator::instance().add(i->name(), name);
794 return i;
795}
796
797QuantLib::ext::shared_ptr<QuantExt::CommodityIndex> parseCommodityIndex(const string& name, bool hasPrefix,
798 const Handle<PriceTermStructure>& ts,
799 const Calendar& cal, const bool enforceFutureIndex) {
800
801 // Whether we check for "COMM-" prefix depends on hasPrefix.
802 string commName = name;
803 if (hasPrefix) {
804 // Make sure the prefix is correct
805 string prefix = name.substr(0, 5);
806 QL_REQUIRE(prefix == "COMM-", "A commodity index string must start with 'COMM-' but got " << prefix);
807 commName = name.substr(5);
808 }
809
810 // Now take the remainder of the string
811 // for spot indices, this should just be the commodity name (possibly containing hyphens)
812 // for future indices, this is of the form NAME-YYYY-MM or NAME-YYYY-MM-DD where NAME is the commodity name
813 // (possibly containing hyphens) and YYYY-MM(-DD) is the expiry date of the futures contract
814 Date expiry;
815
816 // Check for form NAME-YYYY-MM-DD
817 if (commName.size() > 10) {
818 string test = commName.substr(commName.size() - 10);
819 if (boost::regex_match(test, boost::regex("\\d{4}-\\d{2}-\\d{2}"))) {
820 expiry = parseDate(test);
821 commName = commName.substr(0, commName.size() - test.size() - 1);
822 }
823 }
824
825 // Check for form NAME-YYYY-MM if NAME-YYYY-MM-DD failed
826 if (expiry == Date() && commName.size() > 7) {
827 string test = commName.substr(commName.size() - 7);
828 if (boost::regex_match(test, boost::regex("\\d{4}-\\d{2}"))) {
829 expiry = parseDate(test + "-01");
830 commName = commName.substr(0, commName.size() - test.size() - 1);
831 }
832 }
833
834 // Name to use when creating the index. This may be updated if we have a commodity future convention and IndexName
835 // is provided by the convention.
836 string indexName = commName;
837
838 // Do we have a commodity future convention for the commodity.
839 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
840 pair<bool, QuantLib::ext::shared_ptr<Convention>> p = conventions->get(commName, Convention::Type::CommodityFuture);
841 QuantLib::ext::shared_ptr<CommodityFutureConvention> convention;
842 if (p.first) {
843
844 convention = QuantLib::ext::dynamic_pointer_cast<CommodityFutureConvention>(p.second);
845
846 if (!convention->indexName().empty())
847 indexName = convention->indexName();
848
849 // If we have provided OffPeakPowerIndexData, we use that to construct the off peak power commodity index.
850 if (convention->offPeakPowerIndexData()) {
851
852 const auto& oppIdxData = *convention->offPeakPowerIndexData();
853
854 if (expiry == Date()) {
855 // If expiry is still not set use any date (off peak index is calendar daily)
856 expiry = Settings::instance().evaluationDate();
857 }
858 string suffix = "-" + to_string(expiry);
859
860 auto offPeakIndex = QuantLib::ext::dynamic_pointer_cast<CommodityFuturesIndex>(parseCommodityIndex(
861 oppIdxData.offPeakIndex() + suffix, false));
862 auto peakIndex = QuantLib::ext::dynamic_pointer_cast<CommodityFuturesIndex>(parseCommodityIndex(
863 oppIdxData.peakIndex() + suffix, false));
864
865 auto index = QuantLib::ext::make_shared<OffPeakPowerIndex>(indexName, expiry, offPeakIndex, peakIndex,
866 oppIdxData.offPeakHours(), oppIdxData.peakCalendar(), ts);
867 IndexNameTranslator::instance().add(index->name(), hasPrefix ? name : "COMM-" + name);
868 DLOG("parseCommodityIndex(" << name << ") -> " << index->name() << " with expiry " << index->expiryDate());
869 return index;
870 }
871 }
872
873 // Create and return the required future index
874 QuantLib::ext::shared_ptr<CommodityIndex> index;
875 if (expiry != Date() || (convention && enforceFutureIndex)) {
876
877 // If expiry is empty, just use any valid expiry.
878 if (expiry == Date()) {
879 ConventionsBasedFutureExpiry feCalc(*convention);
880 expiry = feCalc.nextExpiry();
881 }
882
883 bool keepDays = convention && convention->contractFrequency() == Daily;
884
885 Calendar cdr = cal;
886 if (convention && cdr == NullCalendar()) {
887 cdr = convention->calendar();
888 }
889
890 auto basisCurve = ts.empty() ? nullptr :
891 QuantLib::ext::dynamic_pointer_cast<CommodityBasisPriceTermStructure>(*ts);
892
893 if (basisCurve) {
894 index = QuantLib::ext::make_shared<CommodityBasisFutureIndex>(indexName, expiry, cdr, basisCurve);
895 } else {
896 index = QuantLib::ext::make_shared<CommodityFuturesIndex>(indexName, expiry, cdr, keepDays, ts);
897 }
898
899
900
901 } else {
902 index = QuantLib::ext::make_shared<CommoditySpotIndex>(commName, cal, ts);
903 }
904 IndexNameTranslator::instance().add(index->name(), index->name());
905 DLOG("parseCommodityIndex(" << name << ") -> " << index->name() << " with expiry " << index->expiryDate());
906 return index;
907}
908
909QuantLib::ext::shared_ptr<Index> parseIndex(const string& s) {
910 QuantLib::ext::shared_ptr<QuantLib::Index> ret_idx;
911 try {
912 ret_idx = parseEquityIndex(s);
913 } catch (...) {
914 }
915 if (!ret_idx) {
916 try {
917 ret_idx = parseBondIndex(s);
918 } catch (...) {
919 }
920 }
921 if (!ret_idx) {
922 try {
923 ret_idx = parseCommodityIndex(s, true, QuantLib::Handle<QuantExt::PriceTermStructure>(), QuantLib::NullCalendar(), false);
924 } catch (...) {
925 }
926 }
927 if (!ret_idx) {
928 try {
929 ret_idx = parseFxIndex(s);
930 } catch (...) {
931 }
932 }
933 if (!ret_idx) {
934 try {
935 ret_idx = parseGenericIndex(s);
936 } catch (...) {
937 }
938 }
939 if (!ret_idx) {
940 try {
942 } catch (...) {
943 }
944 }
945 if (!ret_idx) {
946 try {
947 ret_idx = parseIborIndex(s);
948 } catch (...) {
949 }
950 }
951 if (!ret_idx) {
952 try {
953 ret_idx = parseSwapIndex(s, Handle<YieldTermStructure>(), Handle<YieldTermStructure>());
954 } catch (...) {
955 }
956 }
957 if (!ret_idx) {
958 try {
959 ret_idx = parseZeroInflationIndex(s, Handle<ZeroInflationTermStructure>());
960 } catch (...) {
961 }
962 }
963 QL_REQUIRE(ret_idx, "parseIndex \"" << s << "\" not recognized");
964 return ret_idx;
965}
966
967bool isOvernightIndex(const string& indexName) {
968
969 QuantLib::ext::shared_ptr<IborIndex> index;
970 if (tryParseIborIndex(indexName, index)) {
971 auto onIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index);
972 if (onIndex)
973 return true;
974 }
975
976 return false;
977}
978
979bool isBmaIndex(const string& indexName) {
980 QuantLib::ext::shared_ptr<IborIndex> index;
981 if (tryParseIborIndex(indexName, index)) {
982 // in ore a bma index is parsed to a BMAIndexWrapper instance!
983 return QuantLib::ext::dynamic_pointer_cast<BMAIndexWrapper>(index) != nullptr;
984 }
985 return false;
986}
987
988string internalIndexName(const string& indexName) {
989
990 // Check that the indexName string is of the required form
991 vector<string> tokens;
992 split(tokens, indexName, boost::is_any_of("-"));
993 QL_REQUIRE(tokens.size() == 2 || tokens.size() == 3,
994 "Two or three tokens required in " << indexName << ": CCY-INDEX or CCY-INDEX-TERM");
995
996 // Static map of allowable alternative external names to our unique internal name
997 static map<string, string> m = {{"DKK-TNR", "DKK-DKKOIS"}, {"EUR-EURIB", "EUR-EURIBOR"}, {"CAD-BA", "CAD-CDOR"},
998 {"EUR-ESTR", "EUR-ESTER"}, {"EUR-STR", "EUR-ESTER"}, {"JPY-TONA", "JPY-TONAR"},
999 {"JPY-TORF", "JPY-TONAR"}};
1000
1001 // Is start of indexName covered by the map? If so, update it.
1002 string tmpName = tokens[0] + "-" + tokens[1];
1003 if (m.count(tmpName) == 1) {
1004 tmpName = m.at(tmpName);
1005 }
1006
1007 // If there were only two tokens, return the possibly updated two tokens.
1008 if (tokens.size() == 2) {
1009 return tmpName;
1010 }
1011
1012 // Check if we have an overnight index
1013 // This covers cases like USD-FedFunds-1D and returns USD-FedFunds
1014 // (no need to check convention based overnight indices, they are always of the form CCY-INDEX)
1015 if (parsePeriod(tokens[2]) == 1 * Days && isOvernightIndex(tmpName)) {
1016 return tmpName;
1017 }
1018
1019 // Allow USD-SIFMA-1W or USD-SIFMA-7D externally. USD-SIFMA is used internally.
1020 if (tmpName == "USD-SIFMA" && (tokens[2] == "1W" || tokens[2] == "7D")) {
1021 return tmpName;
1022 }
1023
1024 return tmpName + "-" + tokens[2];
1025}
1026
1027bool isFxIndex(const std::string& indexName) {
1028 std::vector<string> tokens;
1029 split(tokens, indexName, boost::is_any_of("-"));
1030 return tokens.size() == 4 && tokens[0] == "FX";
1031}
1032
1033std::string inverseFxIndex(const std::string& indexName) {
1034 std::vector<string> tokens;
1035 split(tokens, indexName, boost::is_any_of("-"));
1036 QL_REQUIRE(tokens.size() == 4 && tokens[0] == "FX", "no fx index given (" << indexName << ")");
1037 return "FX-" + tokens[1] + "-" + tokens[3] + "-" + tokens[2];
1038}
1039
1040} // namespace data
1041} // namespace ore
Abstract base class for convention objects.
Definition: conventions.hpp:55
Perform date calculations for future contracts based on conventions.
QuantLib::Date nextExpiry(bool includeExpiry=true, const QuantLib::Date &referenceDate=QuantLib::Date(), QuantLib::Natural offset=0, bool forOption=false) override
Currency and instrument specific conventions/defaults.
Base class for classes that perform date calculations for future contracts.
QuantLib::ext::shared_ptr< ZeroInflationIndex > parseZeroInflationIndex(const string &s, const Handle< ZeroInflationTermStructure > &h)
Convert std::string to QuantLib::ZeroInflationIndex.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
QuantLib::ext::shared_ptr< SwapIndex > parseSwapIndex(const string &s, const Handle< YieldTermStructure > &f, const Handle< YieldTermStructure > &d)
Convert std::string to QuantLib::SwapIndex.
bool isEquityIndex(const string &indexName)
Return true if the indexName is that of an EquityIndex, otherwise false.
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
bool isOvernightIndex(const string &indexName)
Return true if the indexName is that of an overnight index, otherwise false.
bool isBmaIndex(const string &indexName)
Return true if the indexName is that of an bma/sifma index, otherwise false.
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > parseEquityIndex(const string &s)
Convert std::string (e.g SP5) to QuantExt::EquityIndex.
QuantLib::ext::shared_ptr< FxIndex > parseFxIndex(const string &s, const Handle< Quote > &fxSpot, const Handle< YieldTermStructure > &sourceYts, const Handle< YieldTermStructure > &targetYts, const bool useConventions)
Convert std::string to QuantExt::FxIndex.
pair< bool, QuantLib::ext::shared_ptr< ZeroInflationIndex > > isInflationIndex(const string &indexName)
bool isCommodityIndex(const string &indexName)
Return true if the indexName is that of an CommodityIndex, otherwise false.
bool tryParseIborIndex(const string &s, QuantLib::ext::shared_ptr< IborIndex > &index)
Try to convert std::string to QuantLib::IborIndex.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
string internalIndexName(const string &indexName)
bool isGenericIndex(const string &indexName)
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
QuantLib::ext::shared_ptr< BondIndex > parseBondIndex(const string &name)
Convert std::string to QuantExt::BondIndex.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
bool isGenericIborIndex(const string &indexName)
Return true if the indexName is that of a generic ibor index, otherwise false.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
QuantLib::ext::shared_ptr< Index > parseIndex(const string &s)
Convert std::string to QuantLib::Index.
QuantLib::ext::shared_ptr< QuantLib::Index > parseGenericIndex(const string &s)
Convert std::string (GENERIC-...) to QuantExt::Index.
QuantLib::ext::shared_ptr< ConstantMaturityBondIndex > parseConstantMaturityBondIndex(const string &name)
Convert std::string to QuantExt::ConstantMaturityBondIndex.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
translates between QuantLib::Index::name() and ORE names
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
market data related utilties
bool isFxIndex(const std::string &indexName)
Size size(const ValueType &v)
Definition: value.cpp:145
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
void checkOneToOne(const map< string, QuantLib::ext::shared_ptr< OvernightIndex > > &onIndices, const map< string, QuantLib::ext::shared_ptr< IborIndexParser > > &iborIndices)
std::tuple< Natural, Calendar, BusinessDayConvention > getFxIndexConventions(const string &index)
Definition: marketdata.cpp:160
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
std::string inverseFxIndex(const std::string &indexName)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
string conversion utilities
string name