Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
marketdatumparser.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2016 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
19#include <boost/algorithm/string.hpp>
20#include <boost/make_shared.hpp>
21#include <boost/range.hpp>
22#include <map>
29
30using namespace std;
31using QuantLib::Currency;
32using QuantLib::Days;
33using QuantLib::WeekendsOnly;
34
35namespace ore {
36namespace data {
37
38static MarketDatum::InstrumentType parseInstrumentType(const string& s) {
39
40 static map<string, MarketDatum::InstrumentType> b = {
49 // {"IR_DATED_SWAP", MarketDatum::InstrumentType::IR_DATED_SWAP},
83
84 auto it = b.find(s);
85 if (it != b.end()) {
86 return it->second;
87 } else {
88 QL_FAIL("Cannot convert \"" << s << "\" to InstrumentType");
89 }
90}
91
92static MarketDatum::QuoteType parseQuoteType(const string& s) {
93 static map<string, MarketDatum::QuoteType> b = {
96 {"CONV_CREDIT_SPREAD", MarketDatum::QuoteType::CONV_CREDIT_SPREAD},
102 {"RATE_GVOL", MarketDatum::QuoteType::RATE_LNVOL}, // deprecated
105 {"BASE_CORRELATION", MarketDatum::QuoteType::BASE_CORRELATION},
108 {"TRANSITION_PROBABILITY", MarketDatum::QuoteType::TRANSITION_PROBABILITY}};
109
110 if (s == "RATE_GVOL")
111 LOG("Use of deprecated quote type RATE_GVOL");
112
113 auto it = b.find(s);
114 if (it != b.end()) {
115 return it->second;
116 } else {
117 QL_FAIL("Cannot convert \"" << s << "\" to QuoteType");
118 }
119}
120
121// calls parseDateOrPeriod and returns a Date (either the supplied date or asof+period)
122Date getDateFromDateOrPeriod(const string& token, Date asof, QuantLib::Calendar cal, QuantLib::BusinessDayConvention bdc) {
123 Period term; // gets populated by parseDateOrPeriod
124 Date expiryDate; // gets populated by parseDateOrPeriod
125 bool tmpIsDate; // gets populated by parseDateOrPeriod
126 parseDateOrPeriod(token, expiryDate, term, tmpIsDate); // checks if the market string contains a date or a period
127 if (!tmpIsDate)
128 expiryDate = cal.adjust(asof + term, bdc);
129 return expiryDate;
130}
131
132static FXForwardQuote::FxFwdString parseFxString(const string& s) {
133 static map<string, FXForwardQuote::FxFwdString> b = {
137 };
138
139 auto it = b.find(s);
140 if (it != b.end()) {
141 return it->second;
142 } else {
143 QL_FAIL("Cannot convert \"" << s << "\" to FxFwdString");
144 }
145}
146
147boost::variant<QuantLib::Period, FXForwardQuote::FxFwdString> parseFxPeriod(const string& s) {
148 bool isPeriod = isdigit(s.front());
149 if (isPeriod)
150 return parsePeriod(s);
151 else
152 return parseFxString(s);
153}
154
155namespace {
156
157struct FxTenorGetter : boost::static_visitor<Period> {
158 FxTenorGetter() {}
159 Period operator()(const Period& p) const { return p; }
160 Period operator()(const FXForwardQuote::FxFwdString& p) const {
161 // These are all overnight rates
162 return Period(1, Days);
163 }
164};
165
166struct FxStartTenorGetter : boost::static_visitor<Period> {
167
168 FxStartTenorGetter(const QuantLib::ext::shared_ptr<FXConvention>& fxConvention) :
170
171 Period operator()(const Period& p) const {
172 Integer days = 0;
173 if (fxConvention)
174 days = fxConvention->spotRelative() ? fxConvention->spotDays() : days;
175 return Period(days, Days);
176 }
177
178 Period operator()(const FXForwardQuote::FxFwdString& p) const {
179 Integer days = 0;
181 days = 1;
182 else if (p == FXForwardQuote::FxFwdString::SN && fxConvention) {
183 days = fxConvention->spotDays();
184 }
185 return Period(days, Days);
186 }
187
188 QuantLib::ext::shared_ptr<FXConvention> fxConvention;
189};
190
191struct FxFwdStringCompare : boost::static_visitor<bool> {
192
194
195 bool operator()(const Period& p) const { return false; }
196
197 bool operator()(const FXForwardQuote::FxFwdString& p) const {
198 return p == fxFwdString;
199 }
200
202};
203
204} // namespace
205
206QuantLib::Period fxFwdQuoteTenor(const boost::variant<QuantLib::Period, FXForwardQuote::FxFwdString>& term) {
207 return boost::apply_visitor(FxTenorGetter(), term);
208}
209
210QuantLib::Period fxFwdQuoteStartTenor(const boost::variant<QuantLib::Period, FXForwardQuote::FxFwdString>& term,
211 const QuantLib::ext::shared_ptr<FXConvention>& fxConvention) {
212 return boost::apply_visitor(FxStartTenorGetter(fxConvention), term);
213}
214
215bool matchFxFwdStringTerm(const boost::variant<QuantLib::Period, FXForwardQuote::FxFwdString>& term,
216 const FXForwardQuote::FxFwdString& fxfwdString) {
217 return boost::apply_visitor(FxFwdStringCompare(fxfwdString), term);
218}
219
220//! Function to parse a market datum
221QuantLib::ext::shared_ptr<MarketDatum> parseMarketDatum(const Date& asof, const string& datumName, const Real& value) {
222
223 vector<string> tokens;
224 boost::split(tokens, datumName, boost::is_any_of("/"));
225 QL_REQUIRE(tokens.size() > 2, "more than 2 tokens expected in " << datumName);
226
227 MarketDatum::InstrumentType instrumentType = parseInstrumentType(tokens[0]);
228 MarketDatum::QuoteType quoteType = parseQuoteType(tokens[1]);
229
230 switch (instrumentType) {
231
233 // ZERO/RATE/EUR/EUR1D/A365/1Y
234 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE || quoteType == MarketDatum::QuoteType::YIELD_SPREAD,
235 "Invalid quote type for " << datumName);
236 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
237 const string& ccy = tokens[2];
238 DayCounter dc = parseDayCounter(tokens[4]);
239 // token 5 can be a date, or tenor
240 Date date = Date();
241 Period tenor = Period();
242 bool isDate;
243 parseDateOrPeriod(tokens[5], date, tenor, isDate);
244 return QuantLib::ext::make_shared<ZeroQuote>(value, asof, datumName, quoteType, ccy, date, dc, tenor);
245 }
246
248 // DISCOUNT/RATE/EUR/EUR1D/1Y
249 // DISCOUNT/RATE/EUR/EUR1D/2016-12-15
250 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
251 const string& ccy = tokens[2];
252 // token 4 can be a date, or tenor
253 Date date = Date();
254 Period tenor = Period();
255 bool isDate;
256 parseDateOrPeriod(tokens[4], date, tenor, isDate);
257 return QuantLib::ext::make_shared<DiscountQuote>(value, asof, datumName, quoteType, ccy, date, tenor);
258 }
259
261 QL_REQUIRE(tokens.size() == 5 || tokens.size() == 6, "5 or 6 tokens expected in " << datumName);
262 const string& ccy = tokens[2];
263 Size offset = 0;
264 string indexName;
265 if (tokens.size() == 6) {
266 indexName = tokens[3];
267 offset = 1;
268 }
269 Period fwdStart = parsePeriod(tokens[3 + offset]);
270 Period term = parsePeriod(tokens[4 + offset]);
271 return QuantLib::ext::make_shared<MoneyMarketQuote>(value, asof, datumName, quoteType, ccy, fwdStart, term, indexName);
272 }
273
275 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
276 const string& ccy = tokens[2];
277 const string& expiry = tokens[3];
278 const string& contract = tokens[4];
279 Period term = parsePeriod(tokens[5]);
280 return QuantLib::ext::make_shared<MMFutureQuote>(value, asof, datumName, quoteType, ccy, expiry, contract, term);
281 }
282
284 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
285 const string& ccy = tokens[2];
286 const string& expiry = tokens[3];
287 const string& contract = tokens[4];
288 Period term = parsePeriod(tokens[5]);
289 return QuantLib::ext::make_shared<OIFutureQuote>(value, asof, datumName, quoteType, ccy, expiry, contract, term);
290 }
291
293 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
294 const string& ccy = tokens[2];
295 Period fwdStart = parsePeriod(tokens[3]);
296 Period term = parsePeriod(tokens[4]);
297 return QuantLib::ext::make_shared<FRAQuote>(value, asof, datumName, quoteType, ccy, fwdStart, term);
298 }
299
301 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
302 const string& ccy = tokens[2];
303 string imm1 = tokens[3];
304 string imm2 = tokens[4];
305 unsigned int m1 = parseInteger(imm1);
306 unsigned int m2 = parseInteger(imm2);
307 QL_REQUIRE(m2 > m1, "Second IMM date must be after the first in " << datumName);
308 return QuantLib::ext::make_shared<ImmFraQuote>(value, asof, datumName, quoteType, ccy, m1, m2);
309 }
310
312 QL_REQUIRE(tokens.size() == 6 || tokens.size() == 7, "6 or 7 tokens expected in " << datumName);
313 const string& ccy = tokens[2];
314 Size offset = 0;
315 string indexName;
316 if (tokens.size() == 7) {
317 indexName = tokens[3];
318 offset = 1;
319 }
320 Period tenor = parsePeriod(tokens[4 + offset]);
321 boost::variant<QuantLib::Date, QuantLib::Period> start = parseDateOrPeriod(tokens[3 + offset]);
322 boost::variant<QuantLib::Date, QuantLib::Period> end = parseDateOrPeriod(tokens[5 + offset]);
323
324 if (start.type() == typeid(QuantLib::Period) && end.type() == typeid(QuantLib::Period)) {
325 Period fwdStart = QuantLib::ext::get<QuantLib::Period>(start);
326 Period term = QuantLib::ext::get<QuantLib::Period>(end);
327 return QuantLib::ext::make_shared<SwapQuote>(value, asof, datumName, quoteType, ccy, fwdStart, term, tenor,
328 indexName);
329 } else if (start.type() == typeid(QuantLib::Date) && end.type() == typeid(QuantLib::Date)) {
330 Date startDate = QuantLib::ext::get<QuantLib::Date>(start);
331 Date maturityDate = QuantLib::ext::get<QuantLib::Date>(end);
332 return QuantLib::ext::make_shared<SwapQuote>(value, asof, datumName, quoteType, ccy, startDate, maturityDate, tenor,
333 indexName);
334 } else {
335 QL_FAIL("Expect swap quote with start/end as either periods or dates");
336 }
337 }
338
340 // An optional identifier as a penultimate token supports the following two versions:
341 // BASIS_SWAP/BASIS_SPREAD/3M/1D/USD/5Y
342 // BASIS_SWAP/BASIS_SPREAD/3M/1D/USD/foobar/5Y
343 QL_REQUIRE(tokens.size() == 6 || tokens.size() == 7, "Either 6 or 7 tokens expected in " << datumName);
344 Period flatTerm = parsePeriod(tokens[2]);
345 Period term = parsePeriod(tokens[3]);
346 const string& ccy = tokens[4];
347 Period maturity;
348 if (tokens.size() == 7) {
349 maturity = parsePeriod(tokens[6]);
350 } else {
351 maturity = parsePeriod(tokens[5]);
352 }
353 return QuantLib::ext::make_shared<BasisSwapQuote>(value, asof, datumName, quoteType, flatTerm, term, ccy, maturity);
354 }
355
357 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
358 const string& ccy = tokens[2];
359 Period term = parsePeriod(tokens[3]);
360 Period maturity = parsePeriod(tokens[4]);
361 return QuantLib::ext::make_shared<BMASwapQuote>(value, asof, datumName, quoteType, term, ccy, maturity);
362 }
363
365 QL_REQUIRE(tokens.size() == 7, "7 tokens expected in " << datumName);
366 const string& flatCcy = tokens[2];
367 Period flatTerm = parsePeriod(tokens[3]);
368 const string& ccy = tokens[4];
369 Period term = parsePeriod(tokens[5]);
370 Period maturity = parsePeriod(tokens[6]);
371 return QuantLib::ext::make_shared<CrossCcyBasisSwapQuote>(value, asof, datumName, quoteType, flatCcy, flatTerm, ccy,
372 term, maturity);
373 }
374
376 // CC_FIX_FLOAT_SWAP/RATE/USD/3M/TRY/1Y/5Y
377 QL_REQUIRE(tokens.size() == 7, "7 tokens expected in " << datumName);
378 Period floatTenor = parsePeriod(tokens[3]);
379 Period fixedTenor = parsePeriod(tokens[5]);
380 Period maturity = parsePeriod(tokens[6]);
381 return QuantLib::ext::make_shared<CrossCcyFixFloatSwapQuote>(value, asof, datumName, quoteType, tokens[2], floatTenor,
382 tokens[4], fixedTenor, maturity);
383 }
384
386 // CDS/[CONV_]CREDIT_SPREAD/Name/Seniority/ccy/term
387 // CDS/[CONV_]CREDIT_SPREAD/Name/Seniority/ccy/term/runningSpread
388 // CDS/[CONV_]CREDIT_SPREAD/Name/Seniority/ccy/doc/term
389 // CDS/[CONV_]CREDIT_SPREAD/Name/Seniority/ccy/doc/term/runningSpread
390 // CDS/PRICE/Name/Seniority/ccy/term
391 // CDS/PRICE/Name/Seniority/ccy/term/runningSpread
392 // CDS/PRICE/Name/Seniority/ccy/doc/term
393 // CDS/PRICE/Name/Seniority/ccy/doc/term/runningSpread
394 QL_REQUIRE(tokens.size() == 6 || tokens.size() == 7 || tokens.size() == 8,
395 "6, 7 or 8 tokens expected in " << datumName);
396 const string& underlyingName = tokens[2];
397 const string& seniority = tokens[3];
398 const string& ccy = tokens[4];
399
400 string docClause;
401 Period term;
402 Real runningSpread = Null<Real>();
403 if (tokens.size() == 6) {
404 term = parsePeriod(tokens[5]);
405 } else if (tokens.size() == 8) {
406 docClause = tokens[5];
407 term = parsePeriod(tokens[6]);
408 runningSpread = parseReal(tokens[7]) / 10000;
409 } else {
410 // 7 tokens => [5]/[6] = doc/term or term/runningSpread
411 CdsDocClause cdsDocClause;
412 if (tryParse<CdsDocClause>(tokens[5], cdsDocClause, &parseCdsDocClause)) {
413 docClause = tokens[5];
414 term = parsePeriod(tokens[6]);
415 } else {
416 term = parsePeriod(tokens[5]);
417 runningSpread = parseReal(tokens[6]) / 10000;
418 }
419 }
420
421 return QuantLib::ext::make_shared<CdsQuote>(value, asof, datumName, quoteType, underlyingName,
422 seniority, ccy, term, docClause, runningSpread);
423 }
424
426 QL_REQUIRE(tokens.size() == 6 || tokens.size() == 7, "6 or 7 tokens expected in " << datumName);
427 const string& underlyingName = tokens[2];
428 const string& seniority = tokens[3];
429 const string& ccy = tokens[4];
430 string docClause = tokens.size() == 7 ? tokens[5] : "";
431 Period term = parsePeriod(tokens.back());
432 return QuantLib::ext::make_shared<HazardRateQuote>(value, asof, datumName, underlyingName, seniority, ccy, term,
433 docClause);
434 }
435
437 QL_REQUIRE(tokens.size() == 3 || tokens.size() == 5 || tokens.size() == 6,
438 "3, 5 or 6 tokens expected in " << datumName);
439 const string& underlyingName = tokens[2]; // issuer name for CDS, security ID for bond specific RRs
440 string seniority = "";
441 string ccy = "";
442 string docClause = "";
443 if (tokens.size() >= 5) {
444 // CDS
445 seniority = tokens[3];
446 ccy = tokens[4];
447 if (tokens.size() == 6)
448 docClause = tokens[5];
449 }
450 return QuantLib::ext::make_shared<RecoveryRateQuote>(value, asof, datumName, underlyingName, seniority, ccy, docClause);
451 }
452
454 QL_REQUIRE((tokens.size() >= 8 && tokens.size() <= 10) || tokens.size() == 4 || tokens.size() == 5,
455 "Either 4, 5 or 8, 9, 10 tokens expected in " << datumName);
456 const string& ccy = tokens[2];
457 Size offset = 0;
458 std::string indexName;
459 Size hasCapFloorToken = (tokens.back() == "C" || tokens.back() == "F") ? 1 : 0;
460 QL_REQUIRE(quoteType != MarketDatum::QuoteType::PRICE || hasCapFloorToken == 1,
461 "CAPFLOOR PRICE quotes must specify whether the datum represents a cap or a floor with a \"C\" or"
462 " \"F\" as the final token.");
463
464 if (tokens.size() == 9 + hasCapFloorToken || tokens.size() == 5 + hasCapFloorToken) {
465 // has an index name token... all later tokens are offset by 1
466 offset = 1;
467 indexName = tokens[3];
468 }
469 if (tokens.size() == 8 + hasCapFloorToken || tokens.size() == 9 + hasCapFloorToken) {
470 Period term = parsePeriod(tokens[3 + offset]);
471 Period tenor = parsePeriod(tokens[4 + offset]);
472 bool atm = parseBool(tokens[5 + offset].c_str());
473 bool relative = parseBool(tokens[6 + offset].c_str());
474 Real strike = parseReal(tokens[7 + offset]);
475 bool isCap = !(hasCapFloorToken==1 && tokens.back() == "F"); // assume cap if omitted
476 return QuantLib::ext::make_shared<CapFloorQuote>(value, asof, datumName, quoteType, ccy, term, tenor, atm, relative,
477 strike, indexName, isCap);
478 } else {
479 // not enough tokens, must be a shift quote
480 Period indexTenor = parsePeriod(tokens[3 + offset]);
481 return QuantLib::ext::make_shared<CapFloorShiftQuote>(value, asof, datumName, quoteType, ccy, indexTenor,
482 indexName);
483 }
484 }
485
487 QL_REQUIRE(tokens.size() >= 4 && tokens.size() <= 9, "4...9 tokens expected in " << datumName);
488 const string& ccy = tokens[2];
489 Size offset = isOnePeriod(tokens[3]) ? 0 : 1;
490 std::string quoteTag;
491 Size hasPayReceiveToken = (tokens.back() == "P" || tokens.back() == "R") ? 1 : 0;
492 QL_REQUIRE(quoteType != MarketDatum::QuoteType::PRICE || hasPayReceiveToken == 1,
493 "SWAPTION PRICE quotes must specify whether the datum represents a payer or a receiver"
494 " swaption with a \"P\" or \"R\" as the final token.");
495
496 if (offset == 1)
497 quoteTag = tokens[3];
498 if (tokens.size() >= 6 + offset + hasPayReceiveToken) { // volatility
499 Period expiry = parsePeriod(tokens[3 + offset]);
500 Period term = parsePeriod(tokens[4 + offset]);
501 const string& dimension = tokens[5 + offset];
502 Real strike = 0.0;
503 if (dimension == "ATM")
504 QL_REQUIRE(tokens.size() == 6 + offset + hasPayReceiveToken, 6 + offset + hasPayReceiveToken
505 << " tokens expected in ATM quote " << datumName);
506 else if (dimension == "Smile") {
507 QL_REQUIRE(tokens.size() == 7 + offset + hasPayReceiveToken, 7 + offset + hasPayReceiveToken
508 << " tokens expected in Smile quote " << datumName);
509 strike = parseReal(tokens[6 + offset]);
510 } else
511 QL_FAIL("Swaption vol quote dimension " << dimension << " not recognised");
512 bool isPayer = !(hasPayReceiveToken == 1 && tokens.back() == "R"); // assume payer if omitted
513 return QuantLib::ext::make_shared<SwaptionQuote>(value, asof, datumName, quoteType, ccy, expiry, term, dimension,
514 strike, quoteTag, isPayer);
515 } else { // SLN volatility shift
516 return QuantLib::ext::make_shared<SwaptionShiftQuote>(value, asof, datumName, quoteType, ccy,
517 parsePeriod(tokens[3 + offset]), quoteTag);
518 }
519 }
520
522 QL_REQUIRE(tokens.size() == 4 || tokens.size() == 6, "4 or 6 tokens expected in " << datumName);
523 const string& qualifier = tokens[2];
524 Period expiry = tokens.size() == 6 ? parsePeriod(tokens[3]) : Period(0 * QuantLib::Days);
525 Period term = tokens.size() == 6 ? parsePeriod(tokens[4]) : parsePeriod(tokens[3]);
526 if (tokens.size() == 6) { // volatility
527 QL_REQUIRE(tokens[5] == "ATM", "only ATM allowed for bond option quotes");
528 return QuantLib::ext::make_shared<BondOptionQuote>(value, asof, datumName, quoteType, qualifier, expiry, term);
529 } else { // SLN volatility shift
530 return QuantLib::ext::make_shared<BondOptionShiftQuote>(value, asof, datumName, quoteType, qualifier, term);
531 }
532 }
533
535 QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName);
536 const string& unitCcy = tokens[2];
537 const string& ccy = tokens[3];
538 return QuantLib::ext::make_shared<FXSpotQuote>(value, asof, datumName, quoteType, unitCcy, ccy);
539 }
540
542 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
543 const string& unitCcy = tokens[2];
544 const string& ccy = tokens[3];
545 boost::variant<QuantLib::Period, FXForwardQuote::FxFwdString> term = parseFxPeriod(tokens[4]);
546 return QuantLib::ext::make_shared<FXForwardQuote>(value, asof, datumName, quoteType, unitCcy, ccy, term);
547 }
548
550 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
551 const string& unitCcy = tokens[2];
552 const string& ccy = tokens[3];
553 Period expiry = parsePeriod(tokens[4]);
554 const string& strike = tokens[5];
555 return QuantLib::ext::make_shared<FXOptionQuote>(value, asof, datumName, quoteType, unitCcy, ccy, expiry, strike);
556 }
557
559 QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName);
560 const string& index = tokens[2];
561 Period term = parsePeriod(tokens[3]);
562 return QuantLib::ext::make_shared<ZcInflationSwapQuote>(value, asof, datumName, index, term);
563 }
564
566 QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName);
567 const string& index = tokens[2];
568 Period term = parsePeriod(tokens[3]);
569 return QuantLib::ext::make_shared<YoYInflationSwapQuote>(value, asof, datumName, index, term);
570 }
571
573 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
574 const string& index = tokens[2];
575 Period term = parsePeriod(tokens[3]);
576 QL_REQUIRE(tokens[4] == "C" || tokens[4] == "F",
577 "expected C or F for Cap or Floor at position 5 in " << datumName);
578 bool isCap = tokens[4] == "C";
579 string strike = tokens[5];
580 return QuantLib::ext::make_shared<ZcInflationCapFloorQuote>(value, asof, datumName, quoteType, index, term, isCap,
581 strike);
582 }
583
585 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
586 const string& index = tokens[2];
587 Period term = parsePeriod(tokens[3]);
588 QL_REQUIRE(tokens[4] == "C" || tokens[4] == "F",
589 "expected C or F for Cap or Floor at position 5 in " << datumName);
590 bool isCap = tokens[4] == "C";
591 string strike = tokens[5];
592 return QuantLib::ext::make_shared<YyInflationCapFloorQuote>(value, asof, datumName, quoteType, index, term, isCap,
593 strike);
594 }
595
597 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
598 const string& index = tokens[3];
599 const string& type = tokens[2];
600 const string& month = tokens[4];
601 return QuantLib::ext::make_shared<SeasonalityQuote>(value, asof, datumName, index, type, month);
602 }
604 QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName);
605 QL_REQUIRE(quoteType == MarketDatum::QuoteType::PRICE, "Invalid quote type for " << datumName);
606 const string& equityName = tokens[2];
607 const string& ccy = tokens[3];
608 return QuantLib::ext::make_shared<EquitySpotQuote>(value, asof, datumName, quoteType, equityName, ccy);
609 }
610
612 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
613 QL_REQUIRE(quoteType == MarketDatum::QuoteType::PRICE, "Invalid quote type for " << datumName);
614 const string& equityName = tokens[2];
615 const string& ccy = tokens[3];
616 Date expiryDate = getDateFromDateOrPeriod(tokens[4], asof);
617 return QuantLib::ext::make_shared<EquityForwardQuote>(value, asof, datumName, quoteType, equityName, ccy, expiryDate);
618 }
619
621 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
622 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE, "Invalid quote type for " << datumName);
623 const string& equityName = tokens[2];
624 const string& ccy = tokens[3];
625 Date tenorDate = getDateFromDateOrPeriod(tokens[4], asof);
626 return QuantLib::ext::make_shared<EquityDividendYieldQuote>(value, asof, datumName, quoteType, equityName, ccy,
627 tenorDate);
628 }
629
631 QL_REQUIRE(tokens.size() >= 6 || tokens.size() <= 9, "6 - 9 tokens expected in " << datumName);
632 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE_LNVOL || quoteType == MarketDatum::QuoteType::PRICE,
633 "Invalid quote type for " << datumName);
634 const string& equityName = tokens[2];
635 const string& ccy = tokens[3];
636 string expiryString = tokens[4];
637 // do we have a call or put flag as the last token?
638 bool hasCallPutToken = tokens.back() == "C" || tokens.back() == "P";
639 // the following tokens represent the strike, except the last one, if we have a call/put token
640 string strikeStr;
641 for(Size i=5; i < tokens.size() - (hasCallPutToken ? 1 : 0); ++i) {
642 strikeStr += (i > 5 ? "/" : "") + tokens[i];
643 }
644 QuantLib::ext::shared_ptr<BaseStrike> strike;
645 // we support ATM, ATMF as aliases for ATM/AtmSpot, ATM/AtmFwd, plus absolute strikes and MNY/[Spot/Fwd]/1.2
646 if(strikeStr == "ATM")
647 strike = QuantLib::ext::make_shared<AtmStrike>(QuantLib::DeltaVolQuote::AtmType::AtmSpot);
648 else if(strikeStr == "ATMF")
649 strike = QuantLib::ext::make_shared<AtmStrike>(QuantLib::DeltaVolQuote::AtmType::AtmFwd);
650 else
651 strike = parseBaseStrike(strikeStr);
652 bool isCall = true;
653 if (hasCallPutToken) {
654 QL_REQUIRE(tokens.back() == "C" || tokens.back() == "P",
655 "expected C or P for Call or Put at position " << tokens.size() << " in " << datumName);
656 isCall = tokens.back() == "C";
657 }
658
659 // note how we only store the expiry string - to ensure we can support both Periods and Dates being specified in
660 // the vol curve-config.
661 return QuantLib::ext::make_shared<EquityOptionQuote>(value, asof, datumName, quoteType, equityName, ccy, expiryString,
662 strike, isCall);
663 }
664
666 QL_REQUIRE(tokens.size() == 3, "3 tokens expected in " << datumName);
667 const string& securityID = tokens[2];
669 return QuantLib::ext::make_shared<SecuritySpreadQuote>(value, asof, datumName, securityID);
670 else if (quoteType == MarketDatum::QuoteType::PRICE)
671 return QuantLib::ext::make_shared<BondPriceQuote>(value, asof, datumName, securityID);
672 }
673
675 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
676 QL_REQUIRE(quoteType == MarketDatum::QuoteType::BASE_CORRELATION, "Invalid quote type for " << datumName);
677 const string& cdsIndexName = tokens[2];
678 Period term = parsePeriod(tokens[3]);
679 Real detachmentPoint = parseReal(tokens[4]);
680 return QuantLib::ext::make_shared<BaseCorrelationQuote>(value, asof, datumName, quoteType, cdsIndexName, term,
681 detachmentPoint);
682 }
683
685
686 // Expects the following form. The strike is optional. The index term is optional for backwards compatibility.
687 // INDEX_CDS_OPTION/RATE_LNVOL/<INDEX_NAME>[/<INDEX_TERM>]/<EXPIRY>[/<STRIKE>]
688 QL_REQUIRE(tokens.size() >= 4 || tokens.size() <= 6, "4, 5 or 6 tokens expected in " << datumName);
689 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE_LNVOL, "Invalid quote type for " << datumName);
690
691 QuantLib::ext::shared_ptr<Expiry> expiry;
692 QuantLib::ext::shared_ptr<BaseStrike> strike;
693 string indexTerm;
694 if (tokens.size() == 6) {
695 // We have been given an index term, an expiry and a strike.
696 indexTerm = tokens[3];
697 expiry = parseExpiry(tokens[4]);
698 strike = parseBaseStrike(tokens[5]);
699 } else if (tokens.size() == 5) {
700 // We have been given either 1) an index term and an expiry or 2) an expiry and a strike.
701 // If the last token is a number, we have 2) an expiry and a strike.
702 Real tmp;
703 if (tryParseReal(tokens[4], tmp)) {
704 expiry = parseExpiry(tokens[3]);
705 strike = parseBaseStrike(tokens[4]);
706 } else {
707 indexTerm = tokens[3];
708 expiry = parseExpiry(tokens[4]);
709 }
710 } else {
711 // We have just been given the expiry.
712 expiry = parseExpiry(tokens[3]);
713 }
714
715 return QuantLib::ext::make_shared<IndexCDSOptionQuote>(value, asof, datumName, tokens[2], expiry, indexTerm, strike);
716 }
717
719 QL_REQUIRE(tokens.size() == 4, "4 tokens expected in " << datumName);
720 QL_REQUIRE(quoteType == MarketDatum::QuoteType::PRICE, "Invalid quote type for " << datumName);
721
722 return QuantLib::ext::make_shared<CommoditySpotQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3]);
723 }
724
726 // Expects the following form:
727 // COMMODITY_FWD/PRICE/<COMDTY_NAME>/<CCY>/<DATE/TENOR>
728 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
729 QL_REQUIRE(quoteType == MarketDatum::QuoteType::PRICE, "Invalid quote type for " << datumName);
730
731 // The last token can be a string defining a special tenor i.e. ON, TN or SN
732 if (tokens[4] == "ON") {
733 return QuantLib::ext::make_shared<CommodityForwardQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3],
734 1 * Days, 0 * Days);
735 } else if (tokens[4] == "TN") {
736 return QuantLib::ext::make_shared<CommodityForwardQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3],
737 1 * Days, 1 * Days);
738 } else if (tokens[4] == "SN") {
739 return QuantLib::ext::make_shared<CommodityForwardQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3],
740 1 * Days);
741 }
742
743 // The last token can be a date or a standard tenor
744 Date date;
745 Period tenor;
746 bool isDate;
747 parseDateOrPeriod(tokens[4], date, tenor, isDate);
748
749 if (isDate) {
750 return QuantLib::ext::make_shared<CommodityForwardQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3],
751 date);
752 } else {
753 return QuantLib::ext::make_shared<CommodityForwardQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3],
754 tenor);
755 }
756 }
757
759 // Expects one of the following forms:
760 // COMMODITY_OPTION/<QT>/<COMDTY_NAME>/<CCY>/<EXPIRY>/<STRIKE>
761 // COMMODITY_OPTION/<QT>/<COMDTY_NAME>/<CCY>/<EXPIRY>/<STRIKE>/<OT>
762 // where QT = RATE_LNVOL or PRICE and OT = C (for Call) or P (for Put)
763 using QT = MarketDatum::QuoteType;
764 QL_REQUIRE(tokens.size() >= 6, "At least 6 tokens expected in " << datumName);
765 QL_REQUIRE(quoteType == QT::RATE_LNVOL || quoteType == QT::PRICE,
766 "Quote type for " << datumName << " should be 'RATE_LNVOL' or 'PRICE'");
767
768 QuantLib::ext::shared_ptr<Expiry> expiry = parseExpiry(tokens[4]);
769
770 // If the last token is C or P, process it and update bounds of strike portion.
771 auto itStkBeg = tokens.begin() + 5;
772 auto itStkEnd = tokens.end();
773 Option::Type optionType = Option::Call;
774 if (tokens.back() == "C" || tokens.back() == "P") {
775 if (tokens.back() == "P")
776 optionType = Option::Put;
777 itStkEnd = prev(itStkEnd);
778 }
779
780 // Parse the strike
781 QL_REQUIRE(itStkBeg != itStkEnd, "");
782 string strStrike = boost::algorithm::join(boost::make_iterator_range(itStkBeg, itStkEnd), "/");
783 QuantLib::ext::shared_ptr<BaseStrike> strike = parseBaseStrike(strStrike);
784
785 return QuantLib::ext::make_shared<CommodityOptionQuote>(value, asof, datumName, quoteType, tokens[2],
786 tokens[3], expiry, strike, optionType);
787 }
788
790 // Expects the following form:
791 // CORRELATION/RATE/<INDEX1>/<INDEX2>/<TENOR>/<STRIKE>
792 QL_REQUIRE(tokens.size() == 6, "6 tokens expected in " << datumName);
793 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE || quoteType == MarketDatum::QuoteType::PRICE,
794 "Quote type for " << datumName << " should be 'CORRELATION' or 'PRICE'");
795
796 return QuantLib::ext::make_shared<CorrelationQuote>(value, asof, datumName, quoteType, tokens[2], tokens[3], tokens[4],
797 tokens[5]);
798 }
799
801 QL_REQUIRE(tokens.size() == 3, "3 tokens expected in " << datumName);
802 const string& securityID = tokens[2];
803 QL_REQUIRE(quoteType == MarketDatum::QuoteType::RATE, "Invalid quote type for " << datumName);
804 return QuantLib::ext::make_shared<CPRQuote>(value, asof, datumName, securityID);
805 }
806
808 QL_REQUIRE(tokens.size() == 5, "5 tokens expected in " << datumName);
809 const string& name = tokens[2];
810 const string& fromRating = tokens[3];
811 const string& toRating = tokens[4];
812 QL_REQUIRE(quoteType == MarketDatum::QuoteType::TRANSITION_PROBABILITY, "Invalid quote type for " << datumName);
813 return QuantLib::ext::make_shared<TransitionProbabilityQuote>(value, asof, datumName, name, fromRating, toRating);
814 }
815
816 default:
817 QL_FAIL("Cannot convert \"" << datumName << "\" to MarketDatum");
818 } // switch instrument type
819} // parseMarketDatum
820} // namespace data
821} // namespace ore
InstrumentType
Supported market instrument types.
Definition: marketdatum.hpp:82
QuoteType
Supported market quote types.
SafeStack< ValueType > value
A class to hold credit default swap data.
Classes for representing an expiry for use in market quotes.
QuantLib::ext::shared_ptr< MarketDatum > parseMarketDatum(const Date &asof, const string &datumName, const Real &value)
Function to parse a market datum.
Date getDateFromDateOrPeriod(const string &token, Date asof, QuantLib::Calendar cal, QuantLib::BusinessDayConvention bdc)
Get a date from a date string or period.
boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > parseFxPeriod(const string &s)
Convert text to QuantLib::Period of Fx forward string.
bool tryParseReal(const string &s, QuantLib::Real &result)
Attempt to convert text to Real.
Definition: parsers.cpp:126
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
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
Classes for representing a strike using various conventions.
QuantLib::ext::shared_ptr< FXConvention > fxConvention
FXForwardQuote::FxFwdString fxFwdString
Market Datum parser.
Time maturity
Definition: utilities.cpp:66
CdsDocClause
CDS documentation clause enumeration.
bool isOnePeriod(const string &s)
return true if s represents a period of the form [0-9][D|W|M|Y] (i.e. 1Y6M would return false)
Definition: parsers.cpp:159
CdsDocClause parseCdsDocClause(const string &s)
bool matchFxFwdStringTerm(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const FXForwardQuote::FxFwdString &fxfwdString)
QuantLib::Period fxFwdQuoteStartTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const QuantLib::ext::shared_ptr< FXConvention > &fxConvention)
QuantLib::ext::shared_ptr< Expiry > parseExpiry(const string &strExpiry)
Parse an Expiry from its string representation, strExpiry.
Definition: expiry.cpp:110
QuantLib::ext::shared_ptr< BaseStrike > parseBaseStrike(const string &strStrike)
Parse a Strike from its string representation, strStrike.
Definition: strike.cpp:262
QuantLib::Period fxFwdQuoteTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
string name