Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
utilities.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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
21
23
29
30#include <ql/models/marketmodels/browniangenerators/mtbrowniangenerator.hpp>
31#include <ql/settings.hpp>
33
34#include <boost/algorithm/string.hpp>
35
36namespace ore {
37namespace data {
38using namespace QuantLib;
39using namespace QuantExt;
40
41std::vector<Date> coarsenDateGrid(const std::vector<Date>& dates, const std::string& rule, const Date& referenceDate) {
42
43 // if rule is empty return original grid
44
45 if (rule.empty())
46 return dates;
47
48 // get ref date and prepare result vector
49
50 Date refDate = referenceDate == Null<Date>() ? Settings::instance().evaluationDate() : referenceDate;
51
52 std::vector<Date> result;
53
54 // parse the rule
55
56 std::vector<std::pair<Period, Period>> grid;
57 std::vector<std::string> tokens;
58 boost::split(tokens, rule, boost::is_any_of(","));
59 for (auto const& t : tokens) {
60 std::vector<std::string> tmp;
61 boost::split(tmp, t, boost::is_any_of("()"));
62 QL_REQUIRE(tmp.size() == 3, "coarsenGrid: invalid rule token '" << t << "', expected e.g. '10Y(1M)'");
63 grid.push_back(std::make_pair(parsePeriod(tmp[0]), parsePeriod(tmp[1])));
64 }
65
66 // keep all dates <= refDate
67
68 auto d = dates.begin();
69 for (; d != dates.end() && *d <= refDate; ++d) {
70 result.push_back(*d);
71 }
72
73 // step through the rule grid...
74
75 Date start = refDate;
76 for (auto const& p : grid) {
77 Date end = refDate + p.first;
78
79 do {
80
81 // look at subperiods defined by the second tenor in the rule
82
83 start = std::min(end, start + p.second);
84
85 // avoid too short stubs at the end
86 if (static_cast<double>(end - start) / static_cast<double>(end - (end - p.second)) < 0.2)
87 start = end;
88
89 // for each subperiod keep at most one date, if there are several in the subperiod, keep the latest one
90
91 std::vector<Date> candidates;
92 while (d != dates.end() && *d <= start)
93 candidates.push_back(*d++);
94
95 if (!candidates.empty())
96 result.push_back(candidates.back());
97 } while (start < end);
98
99 start = end;
100 }
101
102 return result;
103}
104
105std::pair<std::string, ScriptedTradeScriptData> getScript(const ScriptedTrade& scriptedTrade,
106 const ScriptLibraryData& scriptLibrary,
107 const std::string& purpose,
108 const bool fallBackOnEmptyPurpose) {
109 if (!scriptedTrade.scriptName().empty()) {
110 DLOG("get script '" << scriptedTrade.scriptName() << "' for purpose '" << purpose
111 << "' (fallBackOnEmptyPurpose=" << std::boolalpha << fallBackOnEmptyPurpose
112 << ") from script library");
113 return scriptLibrary.get(scriptedTrade.scriptName(), purpose, fallBackOnEmptyPurpose);
114 } else {
115 DLOG("get script for purpose '" << purpose << "' (fallBackOnEmptyPurpose=" << std::boolalpha
116 << fallBackOnEmptyPurpose << ") from inline script in scripted trade");
117 return std::make_pair(scriptedTrade.productTag(), scriptedTrade.script(purpose, fallBackOnEmptyPurpose));
118 }
119}
120
121ASTNodePtr parseScript(const std::string& code) {
122 ScriptParser parser(code);
123 DLOG("parsing script (size " << code.size() << ")");
124 if (parser.success()) {
125 DLOG("successfully parsed the script");
126 } else {
127 ALOG("an error occured during script parsing:");
128 LOGGERSTREAM(parser.error());
129 LOG("full script is:");
130 LOG("<<<<<<<<<<");
131 LOGGERSTREAM(code);
132 LOG(">>>>>>>>>>");
133 QL_FAIL("scripted trade could not be built due to parser errors, see log for more details.");
134 }
135 return parser.ast();
136}
137
138std::pair<std::string, Period> convertIndexToCamCorrelationEntry(const std::string& i) {
139 IndexInfo info(i);
140 if (info.isIr()) {
141 return std::make_pair("IR#" + info.ir()->currency().code(), info.ir()->tenor());
142 } else if (info.isInf()) {
143 return std::make_pair("INF#" + info.infName(), 0 * Days);
144 } else if (info.isFx()) {
145 return std::make_pair("FX#" + info.fx()->sourceCurrency().code() + info.fx()->targetCurrency().code(),
146 0 * Days);
147 } else if (info.isEq()) {
148 return std::make_pair("EQ#" + info.eq()->name(), 0 * Days);
149 } else if (info.isComm()) {
150 return std::make_pair("COM#" + info.commName(), 0 * Days);
151 } else {
152 QL_FAIL("convertIndextoCamCorrelationEntry(): index '" << i << "' not recognised");
153 }
154}
155
156void checkDuplicateName(const QuantLib::ext::shared_ptr<Context> context, const std::string& name) {
157 auto scalar = context->scalars.find(name);
158 auto array = context->arrays.find(name);
159 QL_REQUIRE(scalar == context->scalars.end() && array == context->arrays.end(),
160 "variable '" << name << "' already declared.");
161}
162
163QuantLib::ext::shared_ptr<Context> makeContext(Size nPaths, const std::string& gridCoarsening,
164 const std::vector<std::string>& schedulesEligibleForCoarsening,
165 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceData,
166 const std::vector<ScriptedTradeEventData>& events,
167 const std::vector<ScriptedTradeValueTypeData>& numbers,
168 const std::vector<ScriptedTradeValueTypeData>& indices,
169 const std::vector<ScriptedTradeValueTypeData>& currencies,
170 const std::vector<ScriptedTradeValueTypeData>& daycounters) {
171
172 TLOG("make context");
173
174 auto context = QuantLib::ext::make_shared<Context>();
175
176
177 map<string, ScriptedTradeEventData> derivedSchedules;
178 for (auto const& x : events) {
179 TLOG("adding event " << x.name());
180 if (x.type() == ScriptedTradeEventData::Type::Value) {
181 checkDuplicateName(context, x.name());
182 Date d = parseDate(x.value());
183 context->scalars[x.name()] = EventVec{nPaths, d};
184 } else if (x.type() == ScriptedTradeEventData::Type::Array) {
185 checkDuplicateName(context, x.name());
186 QuantLib::Schedule s;
187 try {
188 s = makeSchedule(x.schedule());
189 } catch (const std::exception& e) {
190 QL_FAIL("failed building schedule '" << x.name() << "': " << e.what());
191 }
192 std::vector<Date> c;
193 if (std::find(schedulesEligibleForCoarsening.begin(), schedulesEligibleForCoarsening.end(), x.name()) !=
194 schedulesEligibleForCoarsening.end()) {
195 c = coarsenDateGrid(s.dates(), gridCoarsening);
196 if (!gridCoarsening.empty()) {
197 TLOG("apply grid coarsening rule = " << gridCoarsening << " to '" << x.name()
198 << "', resulting grid:")
199 for (auto const& d : c) {
200 TLOG("date " << ore::data::to_string(d));
201 }
202 }
203 } else {
204 c = s.dates();
205 }
206 std::vector<ValueType> tmp;
207 for (auto const& d : c)
208 tmp.push_back(EventVec{nPaths, d});
209 context->arrays[x.name()] = tmp;
210 QL_REQUIRE(!tmp.empty(), "empty event array '" << x.name() << "' not allowed");
211 } else if (x.type() == ScriptedTradeEventData::Type::Derived) {
212 derivedSchedules[x.name()] = x;
213 } else {
214 QL_FAIL("unexpected ScriptedTradeEventData::Type");
215 }
216 context->constants.insert(x.name());
217 }
218
219 bool calculated;
220 while (derivedSchedules.size() > 0) {
221 calculated = false;
222 for (auto& ds : derivedSchedules) {
223 auto base = context->arrays.find(ds.second.baseSchedule());
224 checkDuplicateName(context, ds.second.name());
225 if (base != context->arrays.end()) {
226 try {
227 Calendar cal = parseCalendar(ds.second.calendar());
228 BusinessDayConvention conv = parseBusinessDayConvention(ds.second.convention());
229 Period shift = parsePeriod(ds.second.shift());
230 std::vector<ValueType> tmp;
231 for (auto const& d : base->second) {
232 QL_REQUIRE(d.which() == ValueTypeWhich::Event,
233 "expected event in base schedule, got " << valueTypeLabels.at(d.which()));
234 EventVec e = QuantLib::ext::get<EventVec>(d);
235 tmp.push_back(EventVec{nPaths, cal.advance(e.value, shift, conv)});
236 }
237 context->arrays[ds.second.name()] = tmp;
238 derivedSchedules.erase(ds.second.name());
239 calculated = true;
240 } catch (const std::exception& e) {
241 QL_FAIL("failed building derived schedule '" << ds.second.name() << "': " << e.what());
242 }
243 break;
244 }
245 }
246
247 // If, after looping through the full list of derived schedules, we are unable to build any of them.
248 if (!calculated) {
249 for (const auto& ds : derivedSchedules) {
250 ALOG("Failed to build the derived schedule: " << ds.first);
251 }
252 QL_FAIL("Failed to build at least one derived schedule");
253 break;
254 }
255 }
256
257 for (auto const& x : numbers) {
258 TLOG("adding number " << x.name());
259 checkDuplicateName(context, x.name());
260 if (!x.isArray()) {
261 double d = parseReal(x.value());
262 context->scalars[x.name()] = RandomVariable(nPaths, d);
263 } else {
264 std::vector<ValueType> tmp;
265 for (auto const& d : x.values())
266 tmp.push_back(RandomVariable(nPaths, parseReal(d)));
267 context->arrays[x.name()] = tmp;
268 QL_REQUIRE(!tmp.empty(), "empty number array '" << x.name() << "' not allowed");
269 }
270 context->constants.insert(x.name());
271 }
272
273 for (auto const& x : indices) {
274 TLOG("adding index " << x.name());
275 checkDuplicateName(context, x.name());
276 if (!x.isArray()) {
277 context->scalars[x.name()] = IndexVec{nPaths, x.value()};
278 } else {
279 std::vector<ValueType> tmp;
280 for (auto const& d : x.values())
281 tmp.push_back(IndexVec{nPaths, d});
282 context->arrays[x.name()] = tmp;
283 QL_REQUIRE(!tmp.empty(), "empty index array '" << x.name() << "' not allowed");
284 }
285 context->constants.insert(x.name());
286 }
287
288 for (auto const& x : currencies) {
289 TLOG("adding currency " << x.name());
290 checkDuplicateName(context, x.name());
291 if (!x.isArray()) {
292 context->scalars[x.name()] = CurrencyVec{nPaths, x.value()};
293 } else {
294 std::vector<ValueType> tmp;
295 for (auto const& d : x.values())
296 tmp.push_back(CurrencyVec{nPaths, d});
297 context->arrays[x.name()] = tmp;
298 QL_REQUIRE(!tmp.empty(), "empty currency array '" << x.name() << "' not allowed");
299 }
300 context->constants.insert(x.name());
301 }
302
303 for (auto const& x : daycounters) {
304 TLOG("adding daycounter " << x.name());
305 checkDuplicateName(context, x.name());
306 if (!x.isArray()) {
307 context->scalars[x.name()] = DaycounterVec{nPaths, x.value()};
308 } else {
309 std::vector<ValueType> tmp;
310 for (auto const& d : x.values())
311 tmp.push_back(DaycounterVec{nPaths, d});
312 context->arrays[x.name()] = tmp;
313 QL_REQUIRE(!tmp.empty(), "empty currency array '" << x.name() << "' not allowed");
314 }
315 context->constants.insert(x.name());
316 }
317
318 DLOG("context built with " << context->scalars.size() << " scalars and " << context->arrays.size() << " arrays.");
319 return context;
320}
321
322void addNewSchedulesToContext(QuantLib::ext::shared_ptr<Context> context,
323 const std::vector<ScriptedTradeScriptData::NewScheduleData>& newSchedules) {
324 for (auto const& x : newSchedules) {
325 DLOG("adding new schedule " << x.name());
326 checkDuplicateName(context, x.name());
327 std::vector<std::vector<ValueType>> sources;
328 for (auto const& s : x.sourceSchedules()) {
329 auto d = context->arrays.find(s);
330 QL_REQUIRE(d != context->arrays.end(),
331 "ScriptedTradeGenericEngineBuilder::engineBuilder(): did not find source schedule '"
332 << s << "' when building new schedule '" << x.name() << "'");
333 sources.push_back(d->second);
334 }
335 std::vector<ValueType> result;
336 if (x.operation() == "Join") {
337 std::set<QuantLib::Date> tmp;
338 Size n = 0;
339 for (auto const& s : sources) {
340 for (auto const& d : s) {
341 tmp.insert(QuantLib::ext::get<EventVec>(d).value);
342 n = QuantLib::ext::get<EventVec>(d).size;
343 }
344 }
345 for (auto const& d : tmp) {
346 result.push_back(EventVec{n, d});
347 }
348 context->arrays[x.name()] = result;
349 context->constants.insert(x.name());
350 } else {
351 QL_FAIL("new schedule operation '" << x.operation() << "' not supported");
352 }
353 }
354}
355
356namespace {
357
358struct SizeSetter : public boost::static_visitor<void> {
359 explicit SizeSetter(const Size newSize) : newSize_(newSize) {}
360 void operator()(RandomVariable& v) const {
361 QL_REQUIRE(v.deterministic(), "can only change size of determinstic random variables");
362 v = RandomVariable(newSize_, v.at(0));
363 }
364 void operator()(Filter& v) const {
365 QL_REQUIRE(v.deterministic(), "can only change size of determinstic filters");
366 v = Filter(newSize_, v.at(0));
367 }
368 void operator()(EventVec& c) const { c.size = newSize_; }
369 void operator()(CurrencyVec& c) const { c.size = newSize_; }
370 void operator()(IndexVec& c) const { c.size = newSize_; }
371 void operator()(DaycounterVec& c) const { c.size = newSize_; }
372
373private:
375};
376
377} // namespace
378
379void amendContextVariablesSizes(QuantLib::ext::shared_ptr<Context> context, const Size newSize) {
380 SizeSetter setter(newSize);
381 for (auto& x : context->scalars)
382 boost::apply_visitor(setter, x.second);
383 for (auto& v : context->arrays)
384 for (auto& x : v.second)
385 boost::apply_visitor(setter, x);
386}
387
388IndexInfo::IndexInfo(const std::string& name, const QuantLib::ext::shared_ptr<Market>& market) : name_(name), market_(market) {
390 bool done = false;
391 // first handle the index types that we can recognise by a prefix
392 if (boost::starts_with(name, "COMM-")) {
393 // index will be created on the fly, since it depends on the obsDate in general
394 isComm_ = done = true;
395 std::vector<std::string> tokens;
396 boost::split(tokens, name, boost::is_any_of("#!"));
397 QL_REQUIRE(!tokens.empty(), "IndexInfo: no commodity name found for '" << name << "'");
398 commName_ = parseCommodityIndex(tokens.front())->underlyingName();
399 } else if (boost::starts_with(name, "FX-")) {
400 // parse fx index using conventions
401 fx_ = parseFxIndex(name, Handle<Quote>(), Handle<YieldTermStructure>(), Handle<YieldTermStructure>(), true);
402 isFx_ = done = true;
403 } else if (boost::starts_with(name, "EQ-")) {
405 if (market_ != nullptr) {
406 try {
407 eq_ = *market_->equityCurve(eq_->name());
408 } catch (...) {
409 }
410 }
411 isEq_ = done = true;
412 } else if (boost::starts_with(name, "GENERIC-")) {
414 isGeneric_ = done = true;
415 }
416 // no easy way to see if it is an Ibor index, so try and error
417 if (!done) {
418 try {
420 ir_ = irIbor_;
421 isIr_ = isIrIbor_ = done = true;
422 } catch (...) {
423 }
424 }
425 // same for swap
426 if (!done) {
427 try {
428 irSwap_ = parseSwapIndex(name, Handle<YieldTermStructure>(), Handle<YieldTermStructure>());
429 ir_ = irSwap_;
430 isIr_ = isIrSwap_ = done = true;
431 } catch (...) {
432 }
433 }
434 // and same for inflation
435 if (!done) {
436 try {
438 inf_ = res.first;
439 infName_ = res.second;
440 isInf_ = done = true;
441 } catch (...) {
442 }
443 }
444 QL_REQUIRE(done, "Could not build index info for '"
445 << name
446 << "', expected a valid COMM, FX, EQ, GENERIC, Ibor, Swap, Inflation index identifier.");
447}
448
449QuantLib::ext::shared_ptr<Index> IndexInfo::index(const Date& obsDate) const {
450 if (isFx_)
451 return fx_;
452 else if (isEq_)
453 return eq_;
454 else if (isIr_)
455 return ir_;
456 else if (isInf_)
457 return inf_;
458 else if (isGeneric_)
459 return generic_;
460 else if (isComm_) {
461 return comm(obsDate);
462 } else {
463 QL_FAIL("could not parse index '" << name_ << "'");
464 }
465}
466
467QuantLib::ext::shared_ptr<CommodityIndex> IndexInfo::comm(const Date& obsDate) const {
468 if (isComm())
469 return parseScriptedCommodityIndex(name(), obsDate);
470 else
471 return nullptr;
472}
473
474std::string IndexInfo::commName() const {
475 QL_REQUIRE(isComm(), "IndexInfo::commName(): commodity index required, got " << *this);
476 return commName_;
477}
478
479std::string IndexInfo::infName() const {
480 QL_REQUIRE(isInf(), "IndexInfo::infName(): inflation index required, got " << *this);
481 return infName_;
482}
483
484std::ostream& operator<<(std::ostream& o, const IndexInfo& i) {
485 o << "index '" << i.name() << "'";
486 if (i.isFx())
487 o << ", type FX, index name '" << i.fx()->name() << "'";
488 if (i.isEq())
489 o << ", type EQ, index name '" << i.eq()->name() << "'";
490 if (i.isComm())
491 o << ", type COMM";
492 if (i.isIrIbor())
493 o << ", type IR Ibor, index name '" << i.irIbor()->name() << "'";
494 if (i.isIrSwap())
495 o << ", type IR Swap, index name '" << i.irSwap()->name() << "'";
496 if (i.isGeneric())
497 o << ", type Generic, index name '" << i.generic()->name() << "'";
498 return o;
499}
500
501QuantLib::ext::shared_ptr<FallbackIborIndex> IndexInfo::irIborFallback(const IborFallbackConfig& iborFallbackConfig,
502 const Date& asof) const {
503 if (isIrIbor_ && iborFallbackConfig.isIndexReplaced(name_, asof)) {
504 auto data = iborFallbackConfig.fallbackData(name_);
505 // we don't support convention based rfr fallback indices, with ore ticket 1758 this might change
506 auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(parseIborIndex(data.rfrIndex));
507 QL_REQUIRE(on, "IndexInfo::irIborFallback(): could not cast rfr index '"
508 << data.rfrIndex << "' for ibor fallback index '" << name_ << "' to an overnight index");
509 return QuantLib::ext::make_shared<FallbackIborIndex>(irIbor_, on, data.spread, data.switchDate, false);
510 }
511 return nullptr;
512}
513
514QuantLib::ext::shared_ptr<FallbackOvernightIndex> IndexInfo::irOvernightFallback(const IborFallbackConfig& iborFallbackConfig,
515 const Date& asof) const {
516 if (isIrIbor_ && iborFallbackConfig.isIndexReplaced(name_, asof)) {
517 auto data = iborFallbackConfig.fallbackData(name_);
518 // we don't support convention based rfr fallback indices, with ore ticket 1758 this might change
519 auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(parseIborIndex(data.rfrIndex));
520 QL_REQUIRE(on, "IndexInfo::irIborFallback(): could not cast rfr index '"
521 << data.rfrIndex << "' for ibor fallback index '" << name_ << "' to an overnight index");
522 if (auto original = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(irIbor_))
523 return QuantLib::ext::make_shared<FallbackOvernightIndex>(original, on, data.spread, data.switchDate, false);
524 else
525 return nullptr;
526 }
527 return nullptr;
528}
529
530QuantLib::ext::shared_ptr<QuantExt::CommodityIndex> parseScriptedCommodityIndex(const std::string& indexName,
531 const QuantLib::Date& obsDate) {
532
533 QL_REQUIRE(!indexName.empty(), "parseScriptedCommodityIndex(): empty index name");
534 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
535 std::vector<std::string> tokens;
536 boost::split(tokens, indexName, boost::is_any_of("#!"));
537 std::string plainIndexName = tokens.front();
538 std::string commName = parseCommodityIndex(plainIndexName)->underlyingName();
539
540 QuantLib::ext::shared_ptr<CommodityFutureConvention> convention;
541 if (conventions->has(commName)) {
542 convention = QuantLib::ext::dynamic_pointer_cast<CommodityFutureConvention>(conventions->get(commName));
543 }
544 Calendar fixingCalendar = convention ? convention->calendar() : NullCalendar();
545
546 std::vector<std::string> tokens1;
547 boost::split(tokens1, indexName, boost::is_any_of("#"));
548 std::vector<std::string> tokens2;
549 boost::split(tokens2, indexName, boost::is_any_of("!"));
550
551 QuantLib::ext::shared_ptr<CommodityIndex> res;
552 if (tokens1.size() >= 2) {
553 // handle form 3)- 5), i.e. COMM-name#N#D#Cal, COMM-name#N#D, COMM-name#N
554 QL_REQUIRE(tokens.size() <= 4,
555 "parseScriptedCommodityIndex(): expected COMM-Name#N, Comm-Name#N#D, Comm-Name#N#D#Cal, got '"
556 << indexName << "'");
557 QL_REQUIRE(convention,
558 "parseScriptedCommodityIndex(): commodity future convention required for '" << indexName << "'");
559 QL_REQUIRE(obsDate != Date(), "parseScriptedCommodityIndex(): obsDate required for '" << indexName << "'");
560 int offset = std::stoi(tokens[1]);
561 int deliveryRollDays = 0;
562 if (tokens.size() >= 3)
563 deliveryRollDays = parseInteger(tokens[2]);
564 Calendar rollCal = tokens.size() == 4 ? parseCalendar(tokens[3]) : fixingCalendar;
565 ConventionsBasedFutureExpiry expiryCalculator(*convention);
566 Date adjustedObsDate = deliveryRollDays != 0 ? rollCal.advance(obsDate, deliveryRollDays * Days) : obsDate;
567 res = parseCommodityIndex(commName, false, Handle<PriceTermStructure>(), fixingCalendar, true);
568 res = res->clone(expiryCalculator.nextExpiry(true, adjustedObsDate, offset));
569 } else if (tokens2.size() >= 2) {
570 // handle form 6), i.e. COMM-name!N
571 QL_REQUIRE(tokens.size() <= 2,
572 "parseScriptedCommodityIndex(): expected COMM-Name!N, got '" << indexName << "'");
573 QL_REQUIRE(convention,
574 "parseScriptedCommodityIndex(): commodity future convention required for '" << indexName << "'");
575 QL_REQUIRE(obsDate != Date(), "parseScriptedCommodityIndex(): obsDate required for '" << indexName << "'");
576 int offset = std::stoi(tokens[1]);
577 ConventionsBasedFutureExpiry expiryCalculator(*convention);
578 res = parseCommodityIndex(commName, false, Handle<PriceTermStructure>(), fixingCalendar, true);
579 res = res->clone(expiryCalculator.expiryDate(obsDate, offset));
580 } else {
581 // handle 0), 1) and 2)
582 res = parseCommodityIndex(indexName, true, QuantLib::Handle<QuantExt::PriceTermStructure>(), fixingCalendar,
583 false);
584 }
585
586 TLOG("parseScriptCommodityIndex(" << indexName << "," << QuantLib::io::iso_date(obsDate) << ") = " << res->name());
587 return res;
588}
589
590QL_DEPRECATED_DISABLE_WARNING
591// Remove in the next release, interpolation has to happen in the coupon (script) and not in the index
592std::pair<QuantLib::ext::shared_ptr<QuantLib::ZeroInflationIndex>, std::string>
593parseScriptedInflationIndex(const std::string& indexName) {
594 QL_REQUIRE(!indexName.empty(), "parseScriptedInflationIndex(): empty index name");
595 std::vector<std::string> tokens;
596 boost::split(tokens, indexName, boost::is_any_of("#"));
597 std::string plainIndexName = tokens.front();
598 bool interpolated = false;
599 if (tokens.size() == 1) {
600 interpolated = false;
601 } else if (tokens.size() == 2) {
602 QL_REQUIRE(tokens[1] == "F" || tokens[1] == "L", "parseScriptedInflationIndex(): expected ...#[L|F], got ...#"
603 << tokens[1] << " in '" << indexName << "'");
604 interpolated = tokens[1] == "L";
605 } else {
606 QL_FAIL("parseScriptedInflationIndex(): expected IndexName or IndexName#[F|L], got '" << indexName << "'");
607 }
608 return std::make_pair(
609 parseZeroInflationIndex(plainIndexName, interpolated, Handle<ZeroInflationTermStructure>()),
610 plainIndexName);
611}
612QL_DEPRECATED_ENABLE_WARNING
613
614std::string scriptedIndexName(const QuantLib::ext::shared_ptr<Underlying>& underlying) {
615 if (underlying->type() == "Equity") {
616 return "EQ-" + underlying->name();
617 } else if (underlying->type() == "FX") {
618 return "FX-" + underlying->name();
619 } else if (underlying->type() == "Commodity") {
620 QuantLib::ext::shared_ptr<CommodityUnderlying> comUnderlying =
621 QuantLib::ext::dynamic_pointer_cast<CommodityUnderlying>(underlying);
622 std::string tmp = "COMM-" + comUnderlying->name();
623 if (comUnderlying->priceType().empty() || comUnderlying->priceType() == "Spot") {
624 return tmp;
625 } else if (comUnderlying->priceType() == "FutureSettlement") {
626 tmp += "#" + std::to_string(comUnderlying->futureMonthOffset() == Null<Size>()
627 ? 0
628 : comUnderlying->futureMonthOffset());
629 if (comUnderlying->deliveryRollDays() != Null<Size>()) {
630 tmp += "#" + std::to_string(comUnderlying->deliveryRollDays());
631 if (!comUnderlying->deliveryRollCalendar().empty()) {
632 tmp += "#" + comUnderlying->deliveryRollCalendar();
633 }
634 }
635 return tmp;
636 } else {
637 QL_FAIL("underlying price type '" << comUnderlying->priceType() << "' for commodity underlying '"
638 << comUnderlying->name() << "' not handled.");
639 }
640 } else if (underlying->type() == "InterestRate") {
641 return underlying->name();
642 } else if (underlying->type() == "Inflation") {
643 QuantLib::ext::shared_ptr<InflationUnderlying> infUnderlying =
644 QuantLib::ext::dynamic_pointer_cast<InflationUnderlying>(underlying);
645 if (infUnderlying->interpolation() == QuantLib::CPI::InterpolationType::Linear)
646 return underlying->name() + "#L";
647 else if (infUnderlying->interpolation() == QuantLib::CPI::InterpolationType::Flat)
648 return underlying->name() + "#F";
649 else {
650 QL_FAIL("observation interpolation " << infUnderlying->interpolation()
651 << " not covered in scripted inflation indexes");
652 }
653 } else if (underlying->type() == "Basic") {
654 return underlying->name();
655 } else {
656 QL_FAIL("underlying type '" << underlying->type() << "' not handled.");
657 }
658}
659
660Size getInflationSimulationLag(const QuantLib::ext::shared_ptr<ZeroInflationIndex>& index) {
661 // this is consistent with the lag computation in CrossAssetModel::infDki()
662 Date d1 = index->zeroInflationTermStructure()->baseDate();
663 Date d2 = index->zeroInflationTermStructure()->referenceDate();
664 QL_DEPRECATED_DISABLE_WARNING
665 if (!index->interpolated()) {
666 d2 = inflationPeriod(d2, index->frequency()).first;
667 }
668 QL_DEPRECATED_ENABLE_WARNING
669 return d2 - d1;
670}
671
672std::map<std::string, std::vector<Real>>
673getCalibrationStrikes(const std::vector<ScriptedTradeScriptData::CalibrationData>& calibrationSpec,
674 const QuantLib::ext::shared_ptr<Context>& context) {
675 std::map<std::string, std::vector<Real>> result;
676 for (auto const& c : calibrationSpec) {
677
678 std::vector<std::string> indexNames;
679 // set up index
680 auto index = context->scalars.find(c.index());
681 if (index != context->scalars.end()) {
682 QL_REQUIRE(index->second.which() == ValueTypeWhich::Index,
683 "calibration index variable '" << c.index() << "' must evaluate to an index");
684 std::string indexName = QuantLib::ext::get<IndexVec>(index->second).value;
685 // replace fixing source tag in FX indices by GENERIC, since this is what is passed to the model
686 // TODO FX indices might be reorganised vs. a base ccy != their original target ccy, is there anything
687 // we can do to get an effective calibration at the specified deal strike?
688 IndexInfo info(indexName);
689 if (info.isFx())
690 indexName =
691 "FX-GENERIC-" + info.fx()->sourceCurrency().code() + "-" + info.fx()->targetCurrency().code();
692 indexNames.push_back(indexName);
693 } else {
694 auto indexes = context->arrays.find(c.index());
695 if (indexes != context->arrays.end()) {
696 for (Size i = 0; i < indexes->second.size(); ++i) {
697 QL_REQUIRE(indexes->second[i].which() == ValueTypeWhich::Index,
698 "calibration strike variable '" << c.index() << "[" << i
699 << "]' must evaluate to an index");
700 auto indexName = QuantLib::ext::get<IndexVec>(indexes->second[i]).value;
701 IndexInfo info(indexName);
702 if (info.isFx())
703 indexName = "FX-GENERIC-" + info.fx()->sourceCurrency().code() + "-" +
704 info.fx()->targetCurrency().code();
705 indexNames.push_back(indexName);
706 }
707 } else
708 QL_FAIL("did not find calibration index variable '" << c.index()
709 << "' (as scalar or array) in context");
710 }
711
712
713 // loop over calibration strikes for index
714 for (auto const& strikeStr : c.strikes()) {
715 auto strike = context->scalars.find(strikeStr);
716 if (strike != context->scalars.end()) {
717 QL_REQUIRE(strike->second.which() == ValueTypeWhich::Number,
718 "calibration strike variable '" << strikeStr << "' must evaluate to a number");
719 auto strikeNum = QuantLib::ext::get<RandomVariable>(strike->second);
720 QL_REQUIRE(strikeNum.deterministic(), "calibration strike variable '"
721 << strikeStr << "' must be deterministic, got "
722 << strikeNum);
723 QL_REQUIRE(indexNames.size() == 1, "Can only have one index if one strike provided");
724 result[indexNames.at(0)].push_back(strikeNum.at(0));
725 DLOG("add calibration strike for index '" << indexNames.at(0) << "': " << strikeNum.at(0));
726 } else {
727 auto strikeVec = context->arrays.find(strikeStr);
728 if (strikeVec != context->arrays.end()) {
729 QL_REQUIRE(strikeVec->second.size() % indexNames.size() == 0,
730 "StrikeVec must contain the same number of strikes for each index");
731 auto strikeSize = strikeVec->second.size() / indexNames.size();
732 Size ind = 0;
733 for (Size j = 0; j < indexNames.size(); j++) {
734 for (Size i = 0; i < strikeSize; ++i) {
735 QL_REQUIRE(strikeVec->second[ind].which() == ValueTypeWhich::Number,
736 "calibration strike variable '" << strikeStr << "[" << i
737 << "]' must evaluate to a number");
738 auto strikeNum = QuantLib::ext::get<RandomVariable>(strikeVec->second[ind]);
739 QL_REQUIRE(strikeNum.deterministic(), "calibration strike variable '"
740 "calibration strike variable '"
741 << strikeStr << "[" << i
742 << "]' must be deterministic, got "
743 << strikeNum);
744 result[indexNames[j]].push_back(strikeNum.at(0));
745 DLOG("add calibration strike for index '" << indexNames[j] << "' from : '" << strikeStr
746 << "[" << i << "]' " << strikeNum.at(0));
747 ind++;
748 }
749 }
750 } else {
751 WLOG("getCalibrationStrikes: did not find calibration strike variable '" << strikeStr
752 << "' (as scalar or array) in context forcalibration index variable '" << c.index());
753 }
754 }
755 }
756 }
757 return result;
758}
759
760} // namespace data
761} // namespace ore
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
QuantLib::Date expiryDate(const QuantLib::Date &contractDate, QuantLib::Natural monthOffset=0, bool forOption=false) override
const FallbackData & fallbackData(const string &iborIndex) const
bool isIndexReplaced(const string &iborIndex, const QuantLib::Date &asof=QuantLib::Date::maxDate()) const
QuantLib::ext::shared_ptr< Index > index(const Date &obsDate=Date()) const
Definition: utilities.cpp:449
std::string infName() const
Definition: utilities.cpp:479
QuantLib::ext::shared_ptr< Market > market_
Definition: utilities.hpp:142
QuantLib::ext::shared_ptr< ZeroInflationIndex > inf_
Definition: utilities.hpp:149
std::string name() const
Definition: utilities.hpp:98
QuantLib::ext::shared_ptr< Index > generic() const
Definition: utilities.hpp:124
QuantLib::ext::shared_ptr< IborIndex > irIbor_
Definition: utilities.hpp:147
bool isComm() const
Definition: utilities.hpp:102
QuantLib::ext::shared_ptr< SwapIndex > irSwap() const
Definition: utilities.hpp:122
bool isIr() const
Definition: utilities.hpp:103
QuantLib::ext::shared_ptr< FxIndex > fx_
Definition: utilities.hpp:144
IndexInfo(const std::string &name, const QuantLib::ext::shared_ptr< Market > &market=nullptr)
Definition: utilities.cpp:388
bool isIrIbor() const
Definition: utilities.hpp:104
std::string infName_
Definition: utilities.hpp:151
QuantLib::ext::shared_ptr< InterestRateIndex > ir_
Definition: utilities.hpp:146
QuantLib::ext::shared_ptr< EquityIndex2 > eq_
Definition: utilities.hpp:145
QuantLib::ext::shared_ptr< EquityIndex2 > eq() const
Definition: utilities.hpp:110
QuantLib::ext::shared_ptr< FallbackIborIndex > irIborFallback(const IborFallbackConfig &iborFallbackConfig, const Date &asof=QuantLib::Date::maxDate()) const
Definition: utilities.cpp:501
bool isGeneric() const
Definition: utilities.hpp:107
QuantLib::ext::shared_ptr< SwapIndex > irSwap_
Definition: utilities.hpp:148
QuantLib::ext::shared_ptr< InterestRateIndex > ir() const
Definition: utilities.hpp:114
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > comm(const Date &obsDate=Date()) const
Definition: utilities.cpp:467
QuantLib::ext::shared_ptr< IborIndex > irIbor() const
Definition: utilities.hpp:115
std::string commName_
Definition: utilities.hpp:151
QuantLib::ext::shared_ptr< Index > generic_
Definition: utilities.hpp:150
bool isFx() const
Definition: utilities.hpp:100
QuantLib::ext::shared_ptr< FxIndex > fx() const
Definition: utilities.hpp:109
bool isIrSwap() const
Definition: utilities.hpp:105
bool isEq() const
Definition: utilities.hpp:101
QuantLib::ext::shared_ptr< FallbackOvernightIndex > irOvernightFallback(const IborFallbackConfig &iborFallbackConfig, const Date &asof=QuantLib::Date::maxDate()) const
Definition: utilities.cpp:514
std::string commName() const
Definition: utilities.cpp:474
bool isInf() const
Definition: utilities.hpp:106
std::pair< std::string, ScriptedTradeScriptData > get(const std::string &scriptName, const std::string &purpose, const bool fallBackOnEmptyPurpose=true) const
ASTNodePtr ast() const
const ParserError & error() const
const std::string & productTag() const
const std::map< std::string, ScriptedTradeScriptData > & script() const
const std::string & scriptName() const
SafeStack< ValueType > value
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.
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
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.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
QuantLib::ext::shared_ptr< QuantLib::Index > parseGenericIndex(const string &s)
Convert std::string (GENERIC-...) to QuantExt::Index.
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
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define LOG(text)
Logging Macro (Level = Notice)
Definition: log.hpp:552
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
#define ALOG(text)
Logging Macro (Level = Alert)
Definition: log.hpp:544
#define LOGGERSTREAM(text)
Definition: log.hpp:631
#define WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
Date referenceDate
Definition: utilities.cpp:442
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
void amendContextVariablesSizes(QuantLib::ext::shared_ptr< Context > context, const Size newSize)
Definition: utilities.cpp:379
QL_DEPRECATED_ENABLE_WARNING std::string scriptedIndexName(const QuantLib::ext::shared_ptr< Underlying > &underlying)
Definition: utilities.cpp:614
std::vector< Date > coarsenDateGrid(const std::vector< Date > &dates, const std::string &rule, const Date &referenceDate)
Definition: utilities.cpp:41
ASTNodePtr parseScript(const std::string &code)
Definition: utilities.cpp:121
QL_DEPRECATED_DISABLE_WARNING std::pair< QuantLib::ext::shared_ptr< QuantLib::ZeroInflationIndex >, std::string > parseScriptedInflationIndex(const std::string &indexName)
Definition: utilities.cpp:593
void addNewSchedulesToContext(QuantLib::ext::shared_ptr< Context > context, const std::vector< ScriptedTradeScriptData::NewScheduleData > &newSchedules)
Definition: utilities.cpp:322
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
std::map< std::string, std::vector< Real > > getCalibrationStrikes(const std::vector< ScriptedTradeScriptData::CalibrationData > &calibrationSpec, const QuantLib::ext::shared_ptr< Context > &context)
Definition: utilities.cpp:673
void checkDuplicateName(const QuantLib::ext::shared_ptr< Context > context, const std::string &name)
Definition: utilities.cpp:156
Size getInflationSimulationLag(const QuantLib::ext::shared_ptr< ZeroInflationIndex > &index)
Definition: utilities.cpp:660
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
std::pair< std::string, ScriptedTradeScriptData > getScript(const ScriptedTrade &scriptedTrade, const ScriptLibraryData &scriptLibrary, const std::string &purpose, const bool fallBackOnEmptyPurpose)
Definition: utilities.cpp:105
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseScriptedCommodityIndex(const std::string &indexName, const QuantLib::Date &obsDate)
Definition: utilities.cpp:530
Schedule makeSchedule(const ScheduleDates &data)
Definition: schedule.cpp:263
std::pair< std::string, Period > convertIndexToCamCorrelationEntry(const std::string &i)
Definition: utilities.cpp:138
QuantLib::ext::shared_ptr< ASTNode > ASTNodePtr
Definition: ast.hpp:46
QuantLib::ext::shared_ptr< Context > makeContext(Size nPaths, const std::string &gridCoarsening, const std::vector< std::string > &schedulesEligibleForCoarsening, const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceData, const std::vector< ScriptedTradeEventData > &events, const std::vector< ScriptedTradeValueTypeData > &numbers, const std::vector< ScriptedTradeValueTypeData > &indices, const std::vector< ScriptedTradeValueTypeData > &currencies, const std::vector< ScriptedTradeValueTypeData > &daycounters)
Definition: utilities.cpp:163
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
Size newSize_
Definition: utilities.cpp:374
some utility functions
script parser
bool deterministic() const
bool at(const Size i) const
Real at(const Size i) const
bool deterministic() const
std::string value
Definition: value.hpp:47
std::string value
Definition: value.hpp:57
std::string value
Definition: value.hpp:52
string conversion utilities
string name