Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
legdata.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
41
65
66#include <ql/cashflow.hpp>
67#include <ql/cashflows/averagebmacoupon.hpp>
68#include <ql/cashflows/capflooredcoupon.hpp>
69#include <ql/cashflows/capflooredinflationcoupon.hpp>
70#include <ql/cashflows/cashflowvectors.hpp>
71#include <ql/cashflows/cpicoupon.hpp>
72#include <ql/cashflows/cpicouponpricer.hpp>
73#include <ql/cashflows/digitalcmscoupon.hpp>
74#include <ql/cashflows/fixedratecoupon.hpp>
75#include <ql/cashflows/iborcoupon.hpp>
76#include <ql/cashflows/simplecashflow.hpp>
77#include <ql/errors.hpp>
78#include <ql/experimental/coupons/digitalcmsspreadcoupon.hpp>
79#include <ql/experimental/coupons/strippedcapflooredcoupon.hpp>
80#include <ql/utilities/vectors.hpp>
81
82#include <boost/algorithm/string.hpp>
83#include <boost/make_shared.hpp>
84#include <boost/range/adaptor/transformed.hpp>
85
86using namespace QuantLib;
87using namespace QuantExt;
88
89namespace ore {
90namespace data {
91
92bool lessThan(const string& s1, const string& s2) { return s1 < s2; }
93
95 // allow for empty Cashflow legs without any payments
96 if(node == nullptr)
97 return;
99 amounts_ =
100 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Cashflow", "Amount", "date", dates_, &parseReal, false);
101
105}
106
108 XMLNode* node = doc.allocNode(legNodeName());
109 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Cashflow", "Amount", amounts_, "date", dates_);
110 return node;
111}
112
115 rates_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Rates", "Rate", "startDate", rateDates_, parseReal,
116 true);
117}
118
120 XMLNode* node = doc.allocNode(legNodeName());
121 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Rates", "Rate", rates_, "startDate", rateDates_);
122 return node;
123}
124
127 rates_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Rates", "Rate", "startDate", rateDates_, &parseReal,
128 true);
129 XMLNode* compNode = XMLUtils::getChildNode(node, "Compounding");
130 if (compNode)
131 compounding_ = XMLUtils::getChildValue(node, "Compounding", true);
132 else
133 compounding_ = "Compounded";
134 QL_REQUIRE(compounding_ == "Compounded" || compounding_ == "Simple",
135 "Compounding method " << compounding_ << " not supported");
136 XMLNode* subtractNotionalNode = XMLUtils::getChildNode(node, "SubtractNotional");
137 if (subtractNotionalNode)
138 subtractNotional_ = XMLUtils::getChildValueAsBool(node, "SubtractNotional", true);
139 else
140 subtractNotional_ = true;
141}
142
144 XMLNode* node = doc.allocNode(legNodeName());
145 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Rates", "Rate", rates_, "startDate", rateDates_);
146 XMLUtils::addChild(doc, node, "Compounding", compounding_);
147 XMLUtils::addChild(doc, node, "SubtractNotional", subtractNotional_);
148 return node;
149}
150
153 index_ = internalIndexName(XMLUtils::getChildValue(node, "Index", true));
154 indices_.insert(index_);
155 // These are all optional
156 spreads_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Spreads", "Spread", "startDate", spreadDates_,
157 &parseReal);
158 isInArrears_ = boost::none;
159 lastRecentPeriod_ = boost::none;
161 if (XMLNode* arrNode = XMLUtils::getChildNode(node, "IsInArrears"))
163 if (XMLNode* lrNode = XMLUtils::getChildNode(node, "LastRecentPeriod"))
165 lastRecentPeriodCalendar_ = XMLUtils::getChildValue(node, "LastRecentPeriodCalendar", false);
166 if (XMLNode* avgNode = XMLUtils::getChildNode(node, "IsAveraged"))
168 if (XMLNode* spNode = XMLUtils::getChildNode(node, "HasSubPeriods"))
170 if (XMLNode* incSpNode = XMLUtils::getChildNode(node, "IncludeSpread"))
172 if (auto n = XMLUtils::getChildNode(node, "FixingDays"))
174 else
175 fixingDays_ = Null<Size>();
176 if (auto n = XMLUtils::getChildNode(node, "Lookback"))
178 else
179 lookback_ = 0 * Days;
180 if (auto n = XMLUtils::getChildNode(node, "RateCutoff"))
182 else
183 rateCutoff_ = Null<Size>();
184 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
185 floors_ =
186 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
187 gearings_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Gearings", "Gearing", "startDate", gearingDates_,
188 &parseReal, false);
189 if (XMLUtils::getChildNode(node, "NakedOption"))
190 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
191 else
192 nakedOption_ = false;
193
194 if (XMLUtils::getChildNode(node, "LocalCapFloor"))
195 localCapFloor_ = XMLUtils::getChildValueAsBool(node, "LocalCapFloor", false);
196 else
197 localCapFloor_ = false;
198
199 if (auto tmp = XMLUtils::getChildNode(node, "FixingSchedule")) {
201 }
202 if (auto tmp = XMLUtils::getChildNode(node, "ResetSchedule")) {
204 }
205 vector<std::string> histFixingDates;
206 vector<QuantLib::Real> histFixingValues = XMLUtils::getChildrenValuesWithAttributes<Real>(
207 node, "HistoricalFixings", "Fixing", "fixingDate", histFixingDates,
208 &parseReal);
209
210 QL_REQUIRE(histFixingDates.size() == histFixingValues.size(), "Mismatch Fixing values and dates");
211 for (size_t i = 0; i < histFixingDates.size(); ++i) {
212 auto dt = parseDate(histFixingDates[i]);
213 historicalFixings_[dt] = histFixingValues[i];
214 }
215}
216
218 XMLNode* node = doc.allocNode(legNodeName());
219 XMLUtils::addChild(doc, node, "Index", index_);
220 if (isInArrears_)
221 XMLUtils::addChild(doc, node, "IsInArrears", *isInArrears_);
223 XMLUtils::addChild(doc, node, "LastRecentPeriod", *lastRecentPeriod_);
224 if (!lastRecentPeriodCalendar_.empty())
225 XMLUtils::addChild(doc, node, "LastRecentPeriodCalendar", lastRecentPeriodCalendar_);
226 XMLUtils::addChild(doc, node, "IsAveraged", isAveraged_);
227 XMLUtils::addChild(doc, node, "HasSubPeriods", hasSubPeriods_);
228 XMLUtils::addChild(doc, node, "IncludeSpread", includeSpread_);
229 if (fixingDays_ != Null<Size>())
230 XMLUtils::addChild(doc, node, "FixingDays", static_cast<int>(fixingDays_));
231 if (lookback_ != 0 * Days)
232 XMLUtils::addChild(doc, node, "Lookback", ore::data::to_string(lookback_));
233 if (rateCutoff_ != Null<Size>())
234 XMLUtils::addChild(doc, node, "RateCutoff", static_cast<int>(rateCutoff_));
235 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
236 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
237 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Gearings", "Gearing", gearings_, "startDate",
239 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Spreads", "Spread", spreads_, "startDate", spreadDates_);
240 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
241 if (localCapFloor_)
242 XMLUtils::addChild(doc, node, "LocalCapFloor", localCapFloor_);
243 if (fixingSchedule_.hasData()) {
244 auto tmp = fixingSchedule_.toXML(doc);
245 XMLUtils::setNodeName(doc, tmp, "FixingSchedule");
246 XMLUtils::appendNode(node, tmp);
247 }
248 if (resetSchedule_.hasData()) {
249 auto tmp = resetSchedule_.toXML(doc);
250 XMLUtils::setNodeName(doc, tmp, "ResetSchedule");
251 XMLUtils::appendNode(node, tmp);
252 }
253 if (!historicalFixings_.empty()) {
254 auto histFixings = XMLUtils::addChild(doc, node, "HistoricalFixings");
255 for (const auto& [fixingDate, fixingValue] : historicalFixings_) {
256 XMLUtils::addChild(doc, histFixings, "Fixing", to_string(fixingValue), "fixingDate", to_string(fixingDate));
257 }
258 }
259 return node;
260}
261
264 index_ = XMLUtils::getChildValue(node, "Index", true);
265 startDate_ = XMLUtils::getChildValue(node, "StartDate", false);
266 indices_.insert(index_);
267 baseCPI_ = XMLUtils::getChildValueAsDouble(node, "BaseCPI", false, QuantLib::Null<QuantLib::Real>());
268 observationLag_ = XMLUtils::getChildValue(node, "ObservationLag", false, "");
269 // for backwards compatibility only
270 if (auto c = XMLUtils::getChildNode(node, "Interpolated")) {
271 QL_REQUIRE(XMLUtils::getChildNode(node, "Interpolation") == nullptr,
272 "can not have both Interpolated and Interpolation node in CPILegData");
273 interpolation_ = parseBool(XMLUtils::getNodeValue(c)) ? "Linear" : "Flat";
274 } else {
275 interpolation_ = XMLUtils::getChildValue(node, "Interpolation", false, "");
276 }
277 XMLNode* subNomNode = XMLUtils::getChildNode(node, "SubtractInflationNotional");
278 if (subNomNode)
279 subtractInflationNominal_ = XMLUtils::getChildValueAsBool(node, "SubtractInflationNotional", true);
280 else
282
283 XMLNode* subNomCpnsNode = XMLUtils::getChildNode(node, "SubtractInflationNotionalAllCoupons");
284 if (subNomCpnsNode)
286 XMLUtils::getChildValueAsBool(node, "SubtractInflationNotionalAllCoupons", true);
287 else
289
290 rates_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Rates", "Rate", "startDate", rateDates_, &parseReal,
291 true);
292 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
293 floors_ =
294 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
295
296 finalFlowCap_ = Null<Real>();
297 if (auto n = XMLUtils::getChildNode(node, "FinalFlowCap")) {
298 string v = XMLUtils::getNodeValue(n);
299 if (!v.empty())
301 }
302
303 finalFlowFloor_ = Null<Real>();
304 if (auto n = XMLUtils::getChildNode(node, "FinalFlowFloor")) {
305 string v = XMLUtils::getNodeValue(n);
306 if (!v.empty())
308 }
309
310 if (XMLUtils::getChildNode(node, "NakedOption"))
311 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
312 else
313 nakedOption_ = false;
314}
315
317 XMLNode* node = doc.allocNode(legNodeName());
318 XMLUtils::addChild(doc, node, "Index", index_);
319 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Rates", "Rate", rates_, "startDate", rateDates_);
320 if (baseCPI_ != Null<Real>()) {
321 XMLUtils::addChild(doc, node, "BaseCPI", baseCPI_);
322 }
323 XMLUtils::addChild(doc, node, "StartDate", startDate_);
324 if (!observationLag_.empty()) {
325 XMLUtils::addChild(doc, node, "ObservationLag", observationLag_);
326 }
327 if (!interpolation_.empty()) {
328 XMLUtils::addChild(doc, node, "Interpolation", interpolation_);
329 }
330 XMLUtils::addChild(doc, node, "SubtractInflationNotional", subtractInflationNominal_);
331 XMLUtils::addChild(doc, node, "SubtractInflationNotionalAllCoupons", subtractInflationNominalCoupons_);
332 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
333 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
334 if (finalFlowCap_ != Null<Real>())
335 XMLUtils::addChild(doc, node, "FinalFlowCap", finalFlowCap_);
336 if (finalFlowFloor_ != Null<Real>())
337 XMLUtils::addChild(doc, node, "FinalFlowFloor", finalFlowFloor_);
338 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
339 return node;
340}
341
344 index_ = XMLUtils::getChildValue(node, "Index", true);
345 indices_.insert(index_);
346 fixingDays_ = XMLUtils::getChildValueAsInt(node, "FixingDays", true);
347 observationLag_ = XMLUtils::getChildValue(node, "ObservationLag", false, "");
348 gearings_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Gearings", "Gearing", "startDate", gearingDates_,
349 &parseReal);
350 spreads_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Spreads", "Spread", "startDate", spreadDates_,
351 &parseReal);
352 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
353 floors_ =
354 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
355 if (XMLUtils::getChildNode(node, "NakedOption"))
356 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
357 else
358 nakedOption_ = false;
359 if (XMLUtils::getChildNode(node, "AddInflationNotional"))
360 addInflationNotional_ = XMLUtils::getChildValueAsBool(node, "AddInflationNotional", false);
361 else
362 addInflationNotional_ = false;
363 if (XMLUtils::getChildNode(node, "IrregularYoY"))
364 irregularYoY_ = XMLUtils::getChildValueAsBool(node, "IrregularYoY", false);
365 else
366 irregularYoY_ = false;
367}
368
370 XMLNode* node = doc.allocNode(legNodeName());
371 XMLUtils::addChild(doc, node, "Index", index_);
372 if (!observationLag_.empty()) {
373 XMLUtils::addChild(doc, node, "ObservationLag", observationLag_);
374 }
375 XMLUtils::addChild(doc, node, "FixingDays", static_cast<int>(fixingDays_));
376 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Gearings", "Gearing", gearings_, "startDate",
378 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Spreads", "Spread", spreads_, "startDate", spreadDates_);
379 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
380 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
381 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
382 XMLUtils::addChild(doc, node, "AddInflationNotional", addInflationNotional_);
383 XMLUtils::addChild(doc, node, "IrregularYoY", irregularYoY_);
384 return node;
385}
386
388 XMLNode* node = doc.allocNode(legNodeName());
389 XMLUtils::addChild(doc, node, "Index", swapIndex_);
390 XMLUtils::addChild(doc, node, "IsInArrears", isInArrears_);
391 if (fixingDays_ != Null<Size>())
392 XMLUtils::addChild(doc, node, "FixingDays", static_cast<int>(fixingDays_));
393 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
394 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
395 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Gearings", "Gearing", gearings_, "startDate",
397 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Spreads", "Spread", spreads_, "startDate", spreadDates_);
398 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
399 return node;
400}
401
404 swapIndex_ = XMLUtils::getChildValue(node, "Index", true);
405 indices_.insert(swapIndex_);
406 // These are all optional
407 spreads_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Spreads", "Spread", "startDate", spreadDates_,
408 &parseReal);
409 XMLNode* arrNode = XMLUtils::getChildNode(node, "IsInArrears");
410 if (arrNode)
411 isInArrears_ = XMLUtils::getChildValueAsBool(node, "IsInArrears", true);
412 else
413 isInArrears_ = false; // default to fixing-in-advance
414 if (auto n = XMLUtils::getChildNode(node, "FixingDays"))
416 else
417 fixingDays_ = Null<Size>();
418 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
419 floors_ =
420 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
421 gearings_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Gearings", "Gearing", "startDate", gearingDates_,
422 &parseReal);
423 if (XMLUtils::getChildNode(node, "NakedOption"))
424 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
425 else
426 nakedOption_ = false;
427}
428
430 XMLNode* node = doc.allocNode(legNodeName());
431 XMLUtils::addChild(doc, node, "Index", genericBond_);
432 XMLUtils::addChild(doc, node, "IsInArrears", isInArrears_);
433 XMLUtils::addChild(doc, node, "FixingDays", static_cast<int>(fixingDays_));
434 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
435 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
436 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Gearings", "Gearing", gearings_, "startDate",
438 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Spreads", "Spread", spreads_, "startDate", spreadDates_);
439 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
440 XMLUtils::addChild(doc, node, "CreditRisk", hasCreditRisk_);
441 return node;
442}
443
446 genericBond_ = XMLUtils::getChildValue(node, "Index", true);
447 //indices_.insert(swapIndex_);
448 // These are all optional
449 spreads_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Spreads", "Spread", "startDate", spreadDates_,
450 &parseReal);
451 XMLNode* arrNode = XMLUtils::getChildNode(node, "IsInArrears");
452 if (arrNode)
453 isInArrears_ = XMLUtils::getChildValueAsBool(node, "IsInArrears", true);
454 else
455 isInArrears_ = false; // default to fixing-in-advance
456 fixingDays_ = XMLUtils::getChildValueAsInt(node, "FixingDays", true);
457 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
458 floors_ =
459 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
460 gearings_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Gearings", "Gearing", "startDate", gearingDates_,
461 &parseReal);
462 if (XMLUtils::getChildNode(node, "NakedOption"))
463 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
464 else
465 nakedOption_ = false;
466
467 if (XMLUtils::getChildNode(node, "CreditRisk"))
468 hasCreditRisk_ = XMLUtils::getChildValueAsBool(node, "CreditRisk", false);
469 else
470 hasCreditRisk_ = true;
471}
472
474 XMLNode* node = doc.allocNode(legNodeName());
475 XMLUtils::appendNode(node, underlying_->toXML(doc));
476
477 if (callStrikes_.size() > 0) {
478 XMLUtils::addChild(doc, node, "CallPosition", to_string(callPosition_));
479 XMLUtils::addChild(doc, node, "IsCallATMIncluded", isCallATMIncluded_);
480 XMLUtils::addChildren(doc, node, "CallStrikes", "Strike", callStrikes_);
481 XMLUtils::addChildren(doc, node, "CallPayoffs", "Payoff", callPayoffs_);
482 }
483
484 if (putStrikes_.size() > 0) {
485 XMLUtils::addChild(doc, node, "PutPosition", to_string(putPosition_));
486 XMLUtils::addChild(doc, node, "IsPutATMIncluded", isPutATMIncluded_);
487 XMLUtils::addChildren(doc, node, "PutStrikes", "Strike", putStrikes_);
488 XMLUtils::addChildren(doc, node, "PutPayoffs", "Payoff", putPayoffs_);
489 }
490
491 return node;
492}
493
496
497 XMLNode* underlyingNode = XMLUtils::getChildNode(node, "CMSLegData");
498 underlying_ = QuantLib::ext::make_shared<CMSLegData>();
499 underlying_->fromXML(underlyingNode);
500 indices_ = underlying_->indices();
501
502 callStrikes_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "CallStrikes", "Strike", "startDate",
504 if (callStrikes_.size() > 0) {
505 string cp = XMLUtils::getChildValue(node, "CallPosition", true);
507 isCallATMIncluded_ = XMLUtils::getChildValueAsBool(node, "IsCallATMIncluded", true);
508 callPayoffs_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "CallPayoffs", "Payoff", "startDate",
510 }
511
512 putStrikes_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "PutStrikes", "Strike", "startDate",
514 if (putStrikes_.size() > 0) {
515 string pp = XMLUtils::getChildValue(node, "PutPosition", true);
517 isPutATMIncluded_ = XMLUtils::getChildValueAsBool(node, "IsPutATMIncluded", true);
518 putPayoffs_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "PutPayoffs", "Payoff", "startDate",
520 }
521}
522
524 XMLNode* node = doc.allocNode(legNodeName());
525 XMLUtils::addChild(doc, node, "Index1", swapIndex1_);
526 XMLUtils::addChild(doc, node, "Index2", swapIndex2_);
527 XMLUtils::addChild(doc, node, "IsInArrears", isInArrears_);
528 if (fixingDays_ != Null<Size>())
529 XMLUtils::addChild(doc, node, "FixingDays", static_cast<int>(fixingDays_));
530 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Spreads", "Spread", spreads_, "startDate", spreadDates_);
531 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Caps", "Cap", caps_, "startDate", capDates_);
532 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Floors", "Floor", floors_, "startDate", floorDates_);
533 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Gearings", "Gearing", gearings_, "startDate",
535 XMLUtils::addChild(doc, node, "NakedOption", nakedOption_);
536 return node;
537}
538
541 swapIndex1_ = XMLUtils::getChildValue(node, "Index1", true);
542 swapIndex2_ = XMLUtils::getChildValue(node, "Index2", true);
543 indices_.insert(swapIndex1_);
544 indices_.insert(swapIndex2_);
545 // These are all optional
546 spreads_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Spreads", "Spread", "startDate", spreadDates_,
547 &parseReal);
548 XMLNode* arrNode = XMLUtils::getChildNode(node, "IsInArrears");
549 if (arrNode)
550 isInArrears_ = XMLUtils::getChildValueAsBool(node, "IsInArrears", true);
551 else
552 isInArrears_ = false; // default to fixing-in-advance
553 if (auto n = XMLUtils::getChildNode(node, "FixingDays"))
555 else
556 fixingDays_ = Null<Size>();
557 caps_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Caps", "Cap", "startDate", capDates_, &parseReal);
558 floors_ =
559 XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Floors", "Floor", "startDate", floorDates_, &parseReal);
560 gearings_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Gearings", "Gearing", "startDate", gearingDates_,
561 &parseReal);
562 if (XMLUtils::getChildNode(node, "NakedOption"))
563 nakedOption_ = XMLUtils::getChildValueAsBool(node, "NakedOption", false);
564 else
565 nakedOption_ = false;
566}
567
569 XMLNode* node = doc.allocNode(legNodeName());
570 XMLUtils::appendNode(node, underlying_->toXML(doc));
571
572 if (callStrikes_.size() > 0) {
573 XMLUtils::addChild(doc, node, "CallPosition", to_string(callPosition_));
574 XMLUtils::addChild(doc, node, "IsCallATMIncluded", isCallATMIncluded_);
575 XMLUtils::addChildren(doc, node, "CallStrikes", "Strike", callStrikes_);
576 XMLUtils::addChildren(doc, node, "CallPayoffs", "Payoff", callPayoffs_);
577 }
578
579 if (putStrikes_.size() > 0) {
580 XMLUtils::addChild(doc, node, "PutPosition", to_string(putPosition_));
581 XMLUtils::addChild(doc, node, "IsPutATMIncluded", isPutATMIncluded_);
582 XMLUtils::addChildren(doc, node, "PutStrikes", "Strike", putStrikes_);
583 XMLUtils::addChildren(doc, node, "PutPayoffs", "Payoff", putPayoffs_);
584 }
585
586 return node;
587}
588
591
592 XMLNode* underlyingNode = XMLUtils::getChildNode(node, "CMSSpreadLegData");
593 underlying_ = QuantLib::ext::make_shared<CMSSpreadLegData>();
594 underlying_->fromXML(underlyingNode);
595 indices_ = underlying_->indices();
596
597 callStrikes_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "CallStrikes", "Strike", "startDate",
599 if (callStrikes_.size() > 0) {
600 string cp = XMLUtils::getChildValue(node, "CallPosition", true);
602 isCallATMIncluded_ = XMLUtils::getChildValueAsBool(node, "IsCallATMIncluded", true);
603 callPayoffs_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "CallPayoffs", "Payoff", "startDate",
605 }
606
607 putStrikes_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "PutStrikes", "Strike", "startDate",
609 if (putStrikes_.size() > 0) {
610 string pp = XMLUtils::getChildValue(node, "PutPosition", true);
612 isPutATMIncluded_ = XMLUtils::getChildValueAsBool(node, "IsPutATMIncluded", true);
613 putPayoffs_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "PutPayoffs", "Payoff", "startDate",
615 }
616}
617
621 if (returnType_ == EquityReturnType::Total && XMLUtils::getChildNode(node, "DividendFactor"))
622 dividendFactor_ = XMLUtils::getChildValueAsDouble(node, "DividendFactor", true);
623 else
624 dividendFactor_ = 1.0;
625 XMLNode* utmp = XMLUtils::getChildNode(node, "Underlying");
626 if (!utmp)
627 utmp = XMLUtils::getChildNode(node, "Name");
629 indices_.insert("EQ-" + eqName());
630 if (XMLUtils::getChildNode(node, "InitialPrice"))
631 initialPrice_ = XMLUtils::getChildValueAsDouble(node, "InitialPrice");
632 else
633 initialPrice_ = Null<Real>();
634 initialPriceCurrency_ = XMLUtils::getChildValue(node, "InitialPriceCurrency", false);
635 fixingDays_ = XMLUtils::getChildValueAsInt(node, "FixingDays");
636 XMLNode* tmp = XMLUtils::getChildNode(node, "ValuationSchedule");
637 if (tmp)
639 if (XMLUtils::getChildNode(node, "NotionalReset"))
640 notionalReset_ = XMLUtils::getChildValueAsBool(node, "NotionalReset");
641 else
642 notionalReset_ = true;
643
644 XMLNode* fxt = XMLUtils::getChildNode(node, "FXTerms");
645 if (fxt) {
646 eqCurrency_ = XMLUtils::getChildValue(fxt, "EquityCurrency", false);
647 fxIndex_ = XMLUtils::getChildValue(fxt, "FXIndex", true);
648 if (XMLUtils::getChildNode(fxt, "FXIndexFixingDays")) {
649 WLOG("EquityLegData::fromXML, node FXIndexFixingDays has been deprecated, fixing days are "
650 "taken from conventions.");
651 }
652 if (XMLUtils::getChildNode(fxt, "FXIndexCalendar")) {
653 WLOG("EquityLegData::fromXML, node FXIndexCalendar has been deprecated, fixing calendar is "
654 "taken from conventions.");
655 }
656 indices_.insert(fxIndex_);
657 }
658
659 if (XMLNode* qty = XMLUtils::getChildNode(node, "Quantity"))
661 else
662 quantity_ = Null<Real>();
663}
664
666 XMLNode* node = doc.allocNode(legNodeName());
667 if (quantity_ != Null<Real>())
668 XMLUtils::addChild(doc, node, "Quantity", quantity_);
669
670 XMLUtils::addChild(doc, node, "ReturnType", to_string(returnType_));
671 if (returnType_ == EquityReturnType::Total)
672 XMLUtils::addChild(doc, node, "DividendFactor", dividendFactor_);
673
675 if (initialPrice_ != Null<Real>())
676 XMLUtils::addChild(doc, node, "InitialPrice", initialPrice_);
677 if (!initialPriceCurrency_.empty())
678 XMLUtils::addChild(doc, node, "InitialPriceCurrency", initialPriceCurrency_);
679 XMLUtils::addChild(doc, node, "NotionalReset", notionalReset_);
680
682 XMLNode* schedNode = valuationSchedule_.toXML(doc);
683 XMLUtils::setNodeName(doc, schedNode, "ValuationSchedule");
684 XMLUtils::appendNode(node, schedNode);
685 } else {
686 XMLUtils::addChild(doc, node, "FixingDays", static_cast<Integer>(fixingDays_));
687 }
688
689 if (fxIndex_ != "") {
690 XMLNode* fxNode = doc.allocNode("FXTerms");
691 XMLUtils::addChild(doc, fxNode, "EquityCurrency", eqCurrency_);
692 XMLUtils::addChild(doc, fxNode, "FXIndex", fxIndex_);
693 XMLUtils::appendNode(node, fxNode);
694 }
695 return node;
696}
697
699 XMLUtils::checkNode(node, "AmortizationData");
700 type_ = XMLUtils::getChildValue(node, "Type");
701 value_ = XMLUtils::getChildValueAsDouble(node, "Value", false, Null<Real>());
702 startDate_ = XMLUtils::getChildValue(node, "StartDate", false);
703 endDate_ = XMLUtils::getChildValue(node, "EndDate", false);
704 frequency_ = XMLUtils::getChildValue(node, "Frequency", false);
705 underflow_ = XMLUtils::getChildValueAsBool(node, "Underflow", false, false);
706 initialized_ = true;
707 validate();
708}
709
711 XMLNode* node = doc.allocNode("AmortizationData");
712 XMLUtils::addChild(doc, node, "Type", type_);
713 if (value_ != Null<Real>())
714 XMLUtils::addChild(doc, node, "Value", value_);
715 if (!startDate_.empty())
716 XMLUtils::addChild(doc, node, "StartDate", startDate_);
717 if (!endDate_.empty())
718 XMLUtils::addChild(doc, node, "EndDate", endDate_);
719 if (!frequency_.empty())
720 XMLUtils::addChild(doc, node, "Frequency", frequency_);
721 XMLUtils::addChild(doc, node, "Underflow", underflow_);
722 return node;
723}
724
726 QL_REQUIRE(type_ == "LinearToMaturity" || value_ != Null<Real>(), "AmortizationData requires Value");
727 QL_REQUIRE(type_ == "LinearToMaturity" || value_ != Null<Real>(), "AmortizationData requires Underflow");
728}
729
730LegData::LegData(const QuantLib::ext::shared_ptr<LegAdditionalData>& concreteLegData, bool isPayer, const string& currency,
731 const ScheduleData& scheduleData, const string& dayCounter, const std::vector<double>& notionals,
732 const std::vector<string>& notionalDates, const string& paymentConvention,
733 const bool notionalInitialExchange, const bool notionalFinalExchange,
734 const bool notionalAmortizingExchange, const bool isNotResetXCCY, const string& foreignCurrency,
735 const double foreignAmount, const string& fxIndex,
736 const std::vector<AmortizationData>& amortizationData, const string& paymentLag,
737 const string& notionalPaymentLag, const string& paymentCalendar, const vector<string>& paymentDates,
738 const std::vector<Indexing>& indexing, const bool indexingFromAssetLeg,
739 const string& lastPeriodDayCounter)
740 : concreteLegData_(concreteLegData), isPayer_(isPayer), currency_(currency), schedule_(scheduleData),
741 dayCounter_(dayCounter), notionals_(notionals), notionalDates_(notionalDates),
742 paymentConvention_(paymentConvention), notionalInitialExchange_(notionalInitialExchange),
743 notionalFinalExchange_(notionalFinalExchange), notionalAmortizingExchange_(notionalAmortizingExchange),
744 isNotResetXCCY_(isNotResetXCCY), foreignCurrency_(foreignCurrency), foreignAmount_(foreignAmount),
745 fxIndex_(fxIndex), amortizationData_(amortizationData), paymentLag_(paymentLag),
746 notionalPaymentLag_(notionalPaymentLag), paymentCalendar_(paymentCalendar), paymentDates_(paymentDates),
747 indexing_(indexing), indexingFromAssetLeg_(indexingFromAssetLeg), lastPeriodDayCounter_(lastPeriodDayCounter) {
748
749 indices_ = concreteLegData_->indices();
750
751 if (!fxIndex_.empty())
752 indices_.insert(fxIndex_);
753
754 for (auto const& i : indexing)
755 if (i.hasData())
756 indices_.insert(i.index());
757}
758
760 XMLUtils::checkNode(node, "LegData");
761 string legType = XMLUtils::getChildValue(node, "LegType", true);
763 currency_ = XMLUtils::getChildValue(node, "Currency", false);
764 dayCounter_ = XMLUtils::getChildValue(node, "DayCounter"); // optional
765 paymentConvention_ = XMLUtils::getChildValue(node, "PaymentConvention");
766 paymentLag_ = XMLUtils::getChildValue(node, "PaymentLag");
767 notionalPaymentLag_ = XMLUtils::getChildValue(node, "NotionalPaymentLag");
768 paymentCalendar_ = XMLUtils::getChildValue(node, "PaymentCalendar", false);
769 // if not given, default of getChildValueAsBool is true, which fits our needs here
770 notionals_ = XMLUtils::getChildrenValuesWithAttributes<Real>(node, "Notionals", "Notional", "startDate",
772 isNotResetXCCY_ = true;
776 if (auto tmp = XMLUtils::getChildNode(node, "Notionals")) {
777 XMLNode* fxResetNode = XMLUtils::getChildNode(tmp, "FXReset");
778 if (fxResetNode) {
779 isNotResetXCCY_ = false;
780 foreignCurrency_ = XMLUtils::getChildValue(fxResetNode, "ForeignCurrency", true);
781 foreignAmount_ = XMLUtils::getChildValueAsDouble(fxResetNode, "ForeignAmount", true);
782 fxIndex_ = XMLUtils::getChildValue(fxResetNode, "FXIndex", true);
783 indices_.insert(fxIndex_);
784 if (XMLUtils::getChildNode(node, "FixingDays")) {
785 WLOG("LegData::fromXML, node FixingDays has been deprecated, fixing days are "
786 "taken from conventions.");
787 }
788 if (XMLUtils::getChildNode(node, "FixingCalendar")) {
789 WLOG("LegData::fromXML, node FixingCalendar has been deprecated, fixing calendar is "
790 "taken from conventions.");
791 }
792 // TODO add schedule
793 }
794 XMLNode* exchangeNode = XMLUtils::getChildNode(tmp, "Exchanges");
795 if (exchangeNode) {
796
797 notionalInitialExchange_ = XMLUtils::getChildValueAsBool(exchangeNode, "NotionalInitialExchange");
798 notionalFinalExchange_ = XMLUtils::getChildValueAsBool(exchangeNode, "NotionalFinalExchange");
799 if (XMLUtils::getChildNode(exchangeNode, "NotionalAmortizingExchange"))
800 notionalAmortizingExchange_ = XMLUtils::getChildValueAsBool(exchangeNode, "NotionalAmortizingExchange");
801 }
802 }
803
804 XMLNode* amortizationParentNode = XMLUtils::getChildNode(node, "Amortizations");
805 if (amortizationParentNode) {
806 auto adNodes = XMLUtils::getChildrenNodes(amortizationParentNode, "AmortizationData");
807 for (auto const& a : adNodes) {
809 amortizationData_.back().fromXML(a);
810 }
811 }
812
813 if (auto tmp = XMLUtils::getChildNode(node, "ScheduleData"))
814 schedule_.fromXML(tmp);
815
816 paymentDates_ = XMLUtils::getChildrenValues(node, "PaymentDates", "PaymentDate", false);
817 if (!paymentDates_.empty()) {
818 WLOG("Usage of PaymentDates is deprecated, use PaymentSchedule instead.");
819 }
820
821 strictNotionalDates_ = XMLUtils::getChildValueAsBool(node, "StrictNotionalDates", false, false);
822
823 if (auto tmp = XMLUtils::getChildNode(node, "PaymentSchedule")) {
825 QL_REQUIRE(paymentDates_.empty(), "Both PaymentDates and PaymentSchedule is given. Remove one of them. "
826 "PaymentDates is deprecated, so preferably use PaymentSchedule.");
827 }
828
829 if (auto tmp = XMLUtils::getChildNode(node, "Indexings")) {
830 if (auto n = XMLUtils::getChildNode(tmp, "FromAssetLeg")) {
832 } else {
833 indexingFromAssetLeg_ = false;
834 }
835 auto indexings = XMLUtils::getChildrenNodes(tmp, "Indexing");
836 for (auto const& i : indexings) {
837 indexing_.push_back(Indexing());
838 indexing_.back().fromXML(i);
839 }
840 }
841
842 lastPeriodDayCounter_ = XMLUtils::getChildValue(node, "LastPeriodDayCounter", false);
843
845 concreteLegData_->fromXML(XMLUtils::getChildNode(node, concreteLegData_->legNodeName()));
846
847 indices_.insert(concreteLegData_->indices().begin(), concreteLegData_->indices().end());
848}
849
850QuantLib::ext::shared_ptr<LegAdditionalData> LegData::initialiseConcreteLegData(const string& legType) {
851 auto legData = LegDataFactory::instance().build(legType);
852 QL_REQUIRE(legData, "Leg type " << legType << " has not been registered with the leg data factory.");
853 return legData;
854}
855
857 XMLNode* node = doc.allocNode("LegData");
858 QL_REQUIRE(node, "Failed to create LegData node");
859 XMLUtils::addChild(doc, node, "LegType", legType());
860 XMLUtils::addChild(doc, node, "Payer", isPayer_);
861 XMLUtils::addChild(doc, node, "Currency", currency_);
862 if (paymentConvention_ != "")
863 XMLUtils::addChild(doc, node, "PaymentConvention", paymentConvention_);
864 if (!paymentLag_.empty())
865 XMLUtils::addChild(doc, node, "PaymentLag", paymentLag_);
866 if (!notionalPaymentLag_.empty())
867 XMLUtils::addChild(doc, node, "NotionalPaymentLag", notionalPaymentLag_);
868 if (!paymentCalendar_.empty())
869 XMLUtils::addChild(doc, node, "PaymentCalendar", paymentCalendar_);
870 if (dayCounter_ != "")
871 XMLUtils::addChild(doc, node, "DayCounter", dayCounter_);
872 XMLUtils::addChildrenWithOptionalAttributes(doc, node, "Notionals", "Notional", notionals_, "startDate",
874 XMLNode* notionalsNodePtr = XMLUtils::getChildNode(node, "Notionals");
875
876 if (!isNotResetXCCY_) {
877 XMLNode* resetNode = doc.allocNode("FXReset");
878 XMLUtils::addChild(doc, resetNode, "ForeignCurrency", foreignCurrency_);
879 XMLUtils::addChild(doc, resetNode, "ForeignAmount", foreignAmount_);
880 XMLUtils::addChild(doc, resetNode, "FXIndex", fxIndex_);
881 XMLUtils::appendNode(notionalsNodePtr, resetNode);
882 }
883
884 XMLNode* exchangeNode = doc.allocNode("Exchanges");
885 XMLUtils::addChild(doc, exchangeNode, "NotionalInitialExchange", notionalInitialExchange_);
886 XMLUtils::addChild(doc, exchangeNode, "NotionalFinalExchange", notionalFinalExchange_);
887 XMLUtils::addChild(doc, exchangeNode, "NotionalAmortizingExchange", notionalAmortizingExchange_);
888 XMLUtils::appendNode(notionalsNodePtr, exchangeNode);
889
891
892 if (!paymentDates_.empty())
893 XMLUtils::addChildren(doc, node, "PaymentDates", "PaymentDate", paymentDates_);
894
895 if (!amortizationData_.empty()) {
896 XMLNode* amortisationsParentNode = doc.allocNode("Amortizations");
897 for (auto& amort : amortizationData_) {
898 if (amort.initialized()) {
899 XMLUtils::appendNode(amortisationsParentNode, amort.toXML(doc));
900 }
901 }
902 XMLUtils::appendNode(node, amortisationsParentNode);
903 }
904
906 XMLUtils::addChild(doc, node, "StrictNotionalDates", strictNotionalDates_);
907 }
908
910 auto tmp = paymentSchedule_.toXML(doc);
911 XMLUtils::setNodeName(doc, tmp, "PaymentSchedule");
912 XMLUtils::appendNode(node, tmp);
913 }
914
915 if (!indexing_.empty() || indexingFromAssetLeg_) {
916 XMLNode* indexingsNode = doc.allocNode("Indexings");
918 XMLUtils::addChild(doc, indexingsNode, "FromAssetLeg", indexingFromAssetLeg_);
919 for (auto& i : indexing_) {
920 if (i.hasData())
921 XMLUtils::appendNode(indexingsNode, i.toXML(doc));
922 }
923 XMLUtils::appendNode(node, indexingsNode);
924 }
925
926 if (!lastPeriodDayCounter_.empty())
927 XMLUtils::addChild(doc, node, "LastPeriodDayCounter", lastPeriodDayCounter_);
928
929 XMLUtils::appendNode(node, concreteLegData_->toXML(doc));
930 return node;
931}
932
933// Functions
934Leg makeSimpleLeg(const LegData& data) {
935 QuantLib::ext::shared_ptr<CashflowData> cashflowData = QuantLib::ext::dynamic_pointer_cast<CashflowData>(data.concreteLegData());
936 QL_REQUIRE(cashflowData, "Wrong LegType, expected CashFlow, got " << data.legType());
937
938 const vector<double>& amounts = cashflowData->amounts();
939 const vector<string>& dates = cashflowData->dates();
940 QL_REQUIRE(amounts.size() == dates.size(), "Amounts / Date size mismatch in makeSimpleLeg."
941 << "Amounts:" << amounts.size() << ", Dates:" << dates.size());
942 Leg leg;
943 for (Size i = 0; i < dates.size(); i++) {
944 Date d = parseDate(dates[i]);
945 leg.push_back(QuantLib::ext::shared_ptr<CashFlow>(new SimpleCashFlow(amounts[i], d)));
946 }
947 return leg;
948}
949
950Leg makeFixedLeg(const LegData& data, const QuantLib::Date& openEndDateReplacement) {
951
952 QuantLib::ext::shared_ptr<FixedLegData> fixedLegData = QuantLib::ext::dynamic_pointer_cast<FixedLegData>(data.concreteLegData());
953 QL_REQUIRE(fixedLegData, "Wrong LegType, expected Fixed, got " << data.legType());
954
955 // build schedules
956
957 Schedule schedule;
958 Schedule paymentSchedule;
959 ScheduleBuilder scheduleBuilder;
960 scheduleBuilder.add(schedule, data.schedule());
961 scheduleBuilder.add(paymentSchedule, data.paymentSchedule());
962 scheduleBuilder.makeSchedules(openEndDateReplacement);
963
964 // Get explicit payment dates, if given
965
966 vector<Date> paymentDates;
967
968 if (!paymentSchedule.empty()) {
969 paymentDates = paymentSchedule.dates();
970 } else if (!data.paymentDates().empty()) {
971 BusinessDayConvention paymentDatesConvention =
972 data.paymentConvention().empty() ? Unadjusted : parseBusinessDayConvention(data.paymentConvention());
973 Calendar paymentDatesCalendar =
974 data.paymentCalendar().empty() ? NullCalendar() : parseCalendar(data.paymentCalendar());
975 paymentDates = parseVectorOfValues<Date>(data.paymentDates(), &parseDate);
976 for (Size i = 0; i < paymentDates.size(); i++)
977 paymentDates[i] = paymentDatesCalendar.adjust(paymentDates[i], paymentDatesConvention);
978 }
979
980 // set payment calendar
981
982 Calendar paymentCalendar;
983 if (!data.paymentCalendar().empty())
984 paymentCalendar = parseCalendar(data.paymentCalendar());
985 else if (!paymentSchedule.calendar().empty())
986 paymentCalendar = paymentSchedule.calendar();
987 else if (!schedule.calendar().empty())
988 paymentCalendar = schedule.calendar();
989
990 // set day counter and bdc
991
992 DayCounter dc = parseDayCounter(data.dayCounter());
993 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
994
995 // build standard schedules (for non-strict notional dates)
996
997 vector<double> rates = buildScheduledVector(fixedLegData->rates(), fixedLegData->rateDates(), schedule);
998 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
999
1000 // parse payment lag
1001
1002 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1003
1004 // apply amortization
1005
1006 applyAmortization(notionals, data, schedule, true, rates);
1007
1008 // build leg
1009
1010 if (!data.strictNotionalDates()) {
1011
1012 // no strict notional dates
1013
1014 Leg leg = FixedRateLeg(schedule)
1015 .withNotionals(notionals)
1016 .withCouponRates(rates, dc)
1017 .withPaymentAdjustment(bdc)
1018 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1019 .withPaymentCalendar(paymentCalendar)
1020 .withLastPeriodDayCounter(data.lastPeriodDayCounter().empty()
1021 ? DayCounter()
1022 : parseDayCounter(data.lastPeriodDayCounter()))
1023 .withPaymentDates(paymentDates);
1024 return leg;
1025
1026 } else {
1027
1028 // strict notional dates
1029
1030 std::vector<Date> notionalDatesAsDates;
1031 std::vector<Date> rateDatesAsDates;
1032
1033 for (auto const& d : data.notionalDates()) {
1034 if (!d.empty())
1035 notionalDatesAsDates.push_back(parseDate(d));
1036 }
1037
1038 for (auto const& d : fixedLegData->rateDates()) {
1039 if (!d.empty())
1040 rateDatesAsDates.push_back(parseDate(d));
1041 }
1042
1043 return makeNonStandardFixedLeg(schedule.dates(), paymentDates, data.notionals(), notionalDatesAsDates,
1044 fixedLegData->rates(), rateDatesAsDates, data.strictNotionalDates(), dc,
1045 paymentCalendar, bdc, boost::apply_visitor(PaymentLagPeriod(), paymentLag));
1046 }
1047}
1048
1049Leg makeZCFixedLeg(const LegData& data, const QuantLib::Date& openEndDateReplacement) {
1050 QuantLib::ext::shared_ptr<ZeroCouponFixedLegData> zcFixedLegData =
1051 QuantLib::ext::dynamic_pointer_cast<ZeroCouponFixedLegData>(data.concreteLegData());
1052 QL_REQUIRE(zcFixedLegData, "Wrong LegType, expected Zero Coupon Fixed, got " << data.legType());
1053
1054 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
1055
1056 Calendar paymentCalendar;
1057 if (data.paymentCalendar().empty())
1058 paymentCalendar = schedule.calendar();
1059 else
1060 paymentCalendar = parseCalendar(data.paymentCalendar());
1061
1062 BusinessDayConvention payConvention = parseBusinessDayConvention(data.paymentConvention());
1063 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1064 Natural paymentLagDays = boost::apply_visitor(PaymentLagInteger(), paymentLag);
1065
1066 DayCounter dc = parseDayCounter(data.dayCounter());
1067
1068 Size numNotionals = data.notionals().size();
1069 Size numRates = zcFixedLegData->rates().size();
1070 Size numDates = schedule.size();
1071
1072 QL_REQUIRE(numDates >= 2, "Incorrect number of schedule dates entered, expected at least 2, got " << numDates);
1073 QL_REQUIRE(numNotionals >= 1,
1074 "Incorrect number of notional values entered, expected at least1, got " << numNotionals);
1075 QL_REQUIRE(numRates >= 1, "Incorrect number of rate values entered, expected at least 1, got " << numRates);
1076
1077 vector<Date> dates = schedule.dates();
1078
1079 vector<double> rates = buildScheduledVector(zcFixedLegData->rates(), zcFixedLegData->rateDates(), schedule);
1080 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1081
1082 Compounding comp = parseCompounding(zcFixedLegData->compounding());
1083 QL_REQUIRE(comp == QuantLib::Compounded || comp == QuantLib::Simple,
1084 "Compounding method " << zcFixedLegData->compounding() << " not supported");
1085
1086 Leg leg;
1087 vector<Date> cpnDates;
1088 cpnDates.push_back(dates.front());
1089
1090 for (Size i = 0; i < numDates - 1; i++) {
1091
1092 double currentNotional = i < notionals.size() ? notionals[i] : notionals.back();
1093 double currentRate = i < rates.size() ? rates[i] : rates.back();
1094 cpnDates.push_back(dates[i + 1]);
1095 Date paymentDate = paymentCalendar.advance(dates[i + 1], paymentLagDays, Days, payConvention);
1096 leg.push_back(QuantLib::ext::make_shared<ZeroFixedCoupon>(paymentDate, currentNotional, currentRate, dc, cpnDates, comp,
1097 zcFixedLegData->subtractNotional()));
1098 }
1099 return leg;
1100}
1101
1102Leg makeIborLeg(const LegData& data, const QuantLib::ext::shared_ptr<IborIndex>& index,
1103 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
1104 const QuantLib::Date& openEndDateReplacement) {
1105
1106 QuantLib::ext::shared_ptr<FloatingLegData> floatData = QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(data.concreteLegData());
1107 QL_REQUIRE(floatData, "Wrong LegType, expected Floating, got " << data.legType());
1108
1109 // build schedules
1110
1111 Schedule schedule;
1112 Schedule fixingSchedule;
1113 Schedule resetSchedule;
1114 Schedule paymentSchedule;
1115 ScheduleBuilder scheduleBuilder;
1116 scheduleBuilder.add(schedule, data.schedule());
1117 scheduleBuilder.add(fixingSchedule, floatData->fixingSchedule());
1118 scheduleBuilder.add(resetSchedule, floatData->resetSchedule());
1119 scheduleBuilder.add(paymentSchedule, data.paymentSchedule());
1120 scheduleBuilder.makeSchedules(openEndDateReplacement);
1121
1122 // Get explicit payment dates, if given
1123
1124 vector<Date> paymentDates;
1125
1126 if (!paymentSchedule.empty()) {
1127 paymentDates = paymentSchedule.dates();
1128 } else if (!data.paymentDates().empty()) {
1129 BusinessDayConvention paymentDatesConvention =
1130 data.paymentConvention().empty() ? Unadjusted : parseBusinessDayConvention(data.paymentConvention());
1131 Calendar paymentDatesCalendar =
1132 data.paymentCalendar().empty() ? NullCalendar() : parseCalendar(data.paymentCalendar());
1133 paymentDates = parseVectorOfValues<Date>(data.paymentDates(), &parseDate);
1134 for (Size i = 0; i < paymentDates.size(); i++)
1135 paymentDates[i] = paymentDatesCalendar.adjust(paymentDates[i], paymentDatesConvention);
1136 }
1137
1138 // set payment calendar
1139
1140 Calendar paymentCalendar;
1141 if (!data.paymentCalendar().empty())
1142 paymentCalendar = parseCalendar(data.paymentCalendar());
1143 else if (!paymentSchedule.calendar().empty())
1144 paymentCalendar = paymentSchedule.calendar();
1145 else if (!schedule.calendar().empty())
1146 paymentCalendar = schedule.calendar();
1147
1148 // set day counter and bdc
1149
1150 DayCounter dc = parseDayCounter(data.dayCounter());
1151 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1152
1153 // flag whether caps / floors are present
1154
1155 bool hasCapsFloors = floatData->caps().size() > 0 || floatData->floors().size() > 0;
1156
1157 // build standard schedules (for non-strict notional dates)
1158
1159 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1160 vector<double> spreads =
1161 buildScheduledVectorNormalised(floatData->spreads(), floatData->spreadDates(), schedule, 0.0);
1162 vector<double> gearings =
1163 buildScheduledVectorNormalised(floatData->gearings(), floatData->gearingDates(), schedule, 1.0);
1164
1165 // set fixing days and in arrears flag
1166
1167 Size fixingDays = floatData->fixingDays() == Null<Size>() ? index->fixingDays() : floatData->fixingDays();
1168 bool isInArrears = floatData->isInArrears() ? *floatData->isInArrears() : false;
1169
1170 // apply amortization
1171
1172 applyAmortization(notionals, data, schedule, true);
1173
1174 // handle float annuity, which is not done in applyAmortization, for this we can only have one block
1175
1176 if (!data.amortizationData().empty()) {
1177 AmortizationType amortizationType = parseAmortizationType(data.amortizationData().front().type());
1178 if (amortizationType == AmortizationType::Annuity) {
1179 LOG("Build floating annuity notional schedule");
1180 QL_REQUIRE(data.amortizationData().size() == 1,
1181 "Can have one AmortizationData block only for floating leg annuities");
1182 QL_REQUIRE(!hasCapsFloors, "Caps/Floors not supported in floating annuity coupons");
1183 QL_REQUIRE(floatData->gearings().size() == 0, "Gearings not supported in floating annuity coupons");
1184 DayCounter dc = index->dayCounter();
1185 Date startDate = data.amortizationData().front().startDate().empty()
1186 ? Date::minDate()
1187 : parseDate(data.amortizationData().front().startDate());
1188 double annuity = data.amortizationData().front().value();
1189 bool underflow = data.amortizationData().front().underflow();
1190 vector<QuantLib::ext::shared_ptr<Coupon>> coupons;
1191 for (Size i = 0; i < schedule.size() - 1; i++) {
1192 Date paymentDate = paymentCalendar.adjust(schedule[i + 1], bdc);
1193 if (schedule[i] < startDate || i == 0) {
1194 QuantLib::ext::shared_ptr<FloatingRateCoupon> coupon;
1195 if (!floatData->hasSubPeriods()) {
1196 coupon = QuantLib::ext::make_shared<IborCoupon>(paymentDate, notionals[i], schedule[i], schedule[i + 1],
1197 fixingDays, index, gearings[i], spreads[i], Date(),
1198 Date(), dc, isInArrears);
1199 coupon->setPricer(QuantLib::ext::make_shared<BlackIborCouponPricer>());
1200 } else {
1201 coupon = QuantLib::ext::make_shared<QuantExt::SubPeriodsCoupon1>(
1202 paymentDate, notionals[i], schedule[i], schedule[i + 1], index,
1203 floatData->isAveraged() ? QuantExt::SubPeriodsCoupon1::Averaging
1205 index->businessDayConvention(), spreads[i], dc, floatData->includeSpread(), gearings[i]);
1206 coupon->setPricer(QuantLib::ext::make_shared<QuantExt::SubPeriodsCouponPricer1>());
1207 }
1208 coupons.push_back(coupon);
1209 LOG("FloatingAnnuityCoupon: " << i << " " << coupon->nominal() << " " << coupon->amount());
1210 } else {
1211 QL_REQUIRE(coupons.size() > 0,
1212 "FloatingAnnuityCoupon needs at least one predecessor, e.g. a plain IborCoupon");
1213 LOG("FloatingAnnuityCoupon, previous nominal/coupon: " << i << " " << coupons.back()->nominal()
1214 << " " << coupons.back()->amount());
1215 QuantLib::ext::shared_ptr<QuantExt::FloatingAnnuityCoupon> coupon =
1216 QuantLib::ext::make_shared<QuantExt::FloatingAnnuityCoupon>(
1217 annuity, underflow, coupons.back(), paymentDate, schedule[i], schedule[i + 1], fixingDays,
1218 index, gearings[i], spreads[i], Date(), Date(), dc, isInArrears);
1219 coupons.push_back(coupon);
1220 LOG("FloatingAnnuityCoupon: " << i << " " << coupon->nominal() << " " << coupon->amount());
1221 }
1222 }
1223 Leg leg;
1224 for (Size i = 0; i < coupons.size(); i++)
1225 leg.push_back(coupons[i]);
1226 LOG("Floating annuity notional schedule done");
1227 return leg;
1228 }
1229 }
1230
1231 // handle sub periods leg
1232
1233 if (floatData->hasSubPeriods()) {
1234 QL_REQUIRE(floatData->caps().empty() && floatData->floors().empty(),
1235 "SubPeriodsLegs does not support caps or floors");
1236 QL_REQUIRE(!isInArrears, "SubPeriodLegs do not support in arrears fixings");
1237 Leg leg = QuantExt::SubPeriodsLeg1(schedule, index)
1238 .withNotionals(notionals)
1241 .withGearings(gearings)
1242 .withSpreads(spreads)
1243 .withType(floatData->isAveraged() ? QuantExt::SubPeriodsCoupon1::Averaging
1245 .includeSpread(floatData->includeSpread());
1246 QuantExt::setCouponPricer(leg, QuantLib::ext::make_shared<QuantExt::SubPeriodsCouponPricer1>());
1247 return leg;
1248 }
1249
1250 // parse payment lag
1251
1252 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1253
1254 // handle ibor leg
1255
1256 Leg tmpLeg;
1257 bool isNonStandard;
1258
1259 if (!data.strictNotionalDates() && fixingSchedule.empty() && resetSchedule.empty()) {
1260
1261 // no strict notional dates, no fixing or reset schedule
1262
1263 IborLeg iborLeg = IborLeg(schedule, index)
1264 .withNotionals(notionals)
1265 .withSpreads(spreads)
1266 .withPaymentCalendar(paymentCalendar)
1267 .withPaymentDayCounter(dc)
1268 .withPaymentAdjustment(bdc)
1269 .withFixingDays(fixingDays)
1270 .inArrears(isInArrears)
1271 .withGearings(gearings)
1272 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1273 .withPaymentDates(paymentDates);
1274 if (floatData->caps().size() > 0)
1275 iborLeg.withCaps(buildScheduledVector(floatData->caps(), floatData->capDates(), schedule));
1276 if (floatData->floors().size() > 0)
1277 iborLeg.withFloors(buildScheduledVector(floatData->floors(), floatData->floorDates(), schedule));
1278
1279 tmpLeg = iborLeg;
1280 isNonStandard = false;
1281
1282 } else {
1283
1284 // strict notional dates, fixing or reset schedule present
1285
1286 QL_REQUIRE(!hasCapsFloors, "Ibor leg with strict notional or reset dates, explicit fixing or reset schedule "
1287 "does not support cap / floors");
1288
1289 std::vector<Date> notionalDatesAsDates;
1290 std::vector<Date> spreadDatesAsDates;
1291 std::vector<Date> gearingDatesAsDates;
1292
1293 for (auto const& d : data.notionalDates()) {
1294 if (!d.empty())
1295 notionalDatesAsDates.push_back(parseDate(d));
1296 }
1297
1298 for (auto const& d : floatData->spreadDates()) {
1299 if (!d.empty())
1300 spreadDatesAsDates.push_back(parseDate(d));
1301 }
1302
1303 for (auto const& d : floatData->gearingDates()) {
1304 if (!d.empty())
1305 gearingDatesAsDates.push_back(parseDate(d));
1306 }
1307
1308 tmpLeg = makeNonStandardIborLeg(index, schedule.dates(), paymentDates, fixingSchedule.dates(),
1309 resetSchedule.dates(), fixingDays, data.notionals(), notionalDatesAsDates,
1310 floatData->spreads(), spreadDatesAsDates, floatData->gearings(),
1311 gearingDatesAsDates, data.strictNotionalDates(), dc, paymentCalendar, bdc,
1312 boost::apply_visitor(PaymentLagPeriod(), paymentLag), isInArrears);
1313
1314 isNonStandard = true;
1315 }
1316
1317 if (attachPricer && (hasCapsFloors || isInArrears || isNonStandard)) {
1318 auto builder = engineFactory->builder("CapFlooredIborLeg");
1319 QL_REQUIRE(builder, "No builder found for CapFlooredIborLeg");
1320 auto cappedFlooredIborBuilder = QuantLib::ext::dynamic_pointer_cast<CapFlooredIborLegEngineBuilder>(builder);
1321 auto couponPricer = cappedFlooredIborBuilder->engine(IndexNameTranslator::instance().oreName(index->name()));
1322 QuantLib::setCouponPricer(tmpLeg, couponPricer);
1323 }
1324
1325 // build naked option leg if required
1326
1327 if (floatData->nakedOption()) {
1328 tmpLeg = StrippedCappedFlooredCouponLeg(tmpLeg);
1329 }
1330
1331 // return the leg
1332
1333 return tmpLeg;
1334}
1335
1336Leg makeOISLeg(const LegData& data, const QuantLib::ext::shared_ptr<OvernightIndex>& index,
1337 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
1338 const QuantLib::Date& openEndDateReplacement) {
1339 QuantLib::ext::shared_ptr<FloatingLegData> floatData = QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(data.concreteLegData());
1340 QL_REQUIRE(floatData, "Wrong LegType, expected Floating, got " << data.legType());
1341
1342 auto tmp = data.schedule();
1343
1344 /* For schedules with 1D tenor, this ensures that the index calendar supersedes the calendar provided
1345 in the trade XML and using "following" rolling conventions to avoid differing calendars and subsequent
1346 "degenerate schedule" errors in the building of the overnight coupon value date schedules.
1347 Generally, "1D" is an unusual tenor to use (and often just an error in the input data), but we want to
1348 make sure that this edge case works technically. */
1349 for (auto& r : tmp.modifyRules()) {
1350 if (r.tenor() == "1D") {
1351 r.modifyCalendar() = to_string(index->fixingCalendar());
1352 r.modifyConvention() = "F";
1353 r.modifyTermConvention() = "F";
1354 }
1355 }
1356
1357 Schedule schedule = makeSchedule(tmp, openEndDateReplacement);
1358 DayCounter dc = parseDayCounter(data.dayCounter());
1359 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1360 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1361
1362 // Get explicit payment dates which in most cases should be empty
1363 vector<Date> paymentDates;
1364 if (!data.paymentDates().empty()) {
1365 BusinessDayConvention paymentDatesConvention =
1366 data.paymentConvention().empty() ? Unadjusted : parseBusinessDayConvention(data.paymentConvention());
1367 Calendar paymentDatesCalendar =
1368 data.paymentCalendar().empty() ? NullCalendar() : parseCalendar(data.paymentCalendar());
1369 paymentDates = parseVectorOfValues<Date>(data.paymentDates(), &parseDate);
1370 for (Size i = 0; i < paymentDates.size(); i++)
1371 paymentDates[i] = paymentDatesCalendar.adjust(paymentDates[i], paymentDatesConvention);
1372 }
1373
1374 // try to set the rate computation period based on the schedule tenor
1375 Period rateComputationPeriod = 0 * Days;
1376 if (!tmp.rules().empty() && !tmp.rules().front().tenor().empty())
1377 rateComputationPeriod = parsePeriod(tmp.rules().front().tenor());
1378 else if (!tmp.dates().empty() && !tmp.dates().front().tenor().empty())
1379 rateComputationPeriod = parsePeriod(tmp.dates().front().tenor());
1380
1381 Calendar paymentCalendar;
1382 if (data.paymentCalendar().empty())
1383 paymentCalendar = index->fixingCalendar();
1384 else
1385 paymentCalendar = parseCalendar(data.paymentCalendar());
1386
1387 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1388 vector<double> spreads =
1389 buildScheduledVectorNormalised(floatData->spreads(), floatData->spreadDates(), schedule, 0.0);
1390 vector<double> gearings =
1391 buildScheduledVectorNormalised(floatData->gearings(), floatData->gearingDates(), schedule, 1.0);
1392 bool isInArrears = floatData->isInArrears() ? *floatData->isInArrears() : true;
1393
1394 applyAmortization(notionals, data, schedule, false);
1395
1396 if (floatData->isAveraged()) {
1397
1398 QuantLib::ext::shared_ptr<QuantExt::AverageONIndexedCouponPricer> couponPricer =
1399 QuantLib::ext::make_shared<QuantExt::AverageONIndexedCouponPricer>();
1400
1401 QuantLib::ext::shared_ptr<QuantExt::CapFlooredAverageONIndexedCouponPricer> cfCouponPricer;
1402 if (attachPricer && (floatData->caps().size() > 0 || floatData->floors().size() > 0)) {
1403 auto builder = QuantLib::ext::dynamic_pointer_cast<CapFlooredAverageONIndexedCouponLegEngineBuilder>(
1404 engineFactory->builder("CapFlooredAverageONIndexedCouponLeg"));
1405 QL_REQUIRE(builder, "No builder found for CapFlooredAverageONIndexedCouponLeg");
1406 cfCouponPricer = QuantLib::ext::dynamic_pointer_cast<CapFlooredAverageONIndexedCouponPricer>(
1407 builder->engine(IndexNameTranslator::instance().oreName(index->name()), rateComputationPeriod));
1408 QL_REQUIRE(cfCouponPricer, "internal error, could not cast to CapFlooredAverageONIndexedCouponPricer");
1409 }
1410
1412 QuantExt::AverageONLeg(schedule, index)
1413 .withNotionals(notionals)
1414 .withSpreads(spreads)
1415 .withPaymentCalendar(paymentCalendar)
1416 .withGearings(gearings)
1419 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1420 .withInArrears(isInArrears)
1421 .withLastRecentPeriod(floatData->lastRecentPeriod())
1422 .withLastRecentPeriodCalendar(floatData->lastRecentPeriodCalendar().empty()
1423 ? Calendar()
1424 : parseCalendar(floatData->lastRecentPeriodCalendar()))
1425 .withLookback(floatData->lookback())
1426 .withRateCutoff(floatData->rateCutoff() == Null<Size>() ? 0 : floatData->rateCutoff())
1427 .withFixingDays(floatData->fixingDays())
1428 .withCaps(buildScheduledVectorNormalised<Real>(floatData->caps(), floatData->capDates(), schedule,
1429 Null<Real>()))
1430 .withFloors(buildScheduledVectorNormalised<Real>(floatData->floors(), floatData->capDates(), schedule,
1431 Null<Real>()))
1432 .withNakedOption(floatData->nakedOption())
1433 .includeSpreadInCapFloors(floatData->includeSpread())
1434 .withLocalCapFloor(floatData->localCapFloor())
1437 .withTelescopicValueDates(floatData->telescopicValueDates())
1438 .withPaymentDates(paymentDates);
1439 return leg;
1440
1441 } else {
1442
1443 QuantLib::ext::shared_ptr<QuantExt::OvernightIndexedCouponPricer> couponPricer =
1444 QuantLib::ext::make_shared<QuantExt::OvernightIndexedCouponPricer>();
1445
1446 QuantLib::ext::shared_ptr<QuantExt::CappedFlooredOvernightIndexedCouponPricer> cfCouponPricer;
1447 if (attachPricer && (floatData->caps().size() > 0 || floatData->floors().size() > 0)) {
1448 auto builder = QuantLib::ext::dynamic_pointer_cast<CapFlooredOvernightIndexedCouponLegEngineBuilder>(
1449 engineFactory->builder("CapFlooredOvernightIndexedCouponLeg"));
1450 QL_REQUIRE(builder, "No builder found for CapFlooredOvernightIndexedCouponLeg");
1451 cfCouponPricer = QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredOvernightIndexedCouponPricer>(
1452 builder->engine(IndexNameTranslator::instance().oreName(index->name()), rateComputationPeriod));
1453 QL_REQUIRE(cfCouponPricer, "internal error, could not cast to CapFlooredAverageONIndexedCouponPricer");
1454 }
1455
1456 Leg leg = QuantExt::OvernightLeg(schedule, index)
1457 .withNotionals(notionals)
1458 .withSpreads(spreads)
1461 .withPaymentCalendar(paymentCalendar)
1462 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1463 .withGearings(gearings)
1464 .withInArrears(isInArrears)
1465 .withLastRecentPeriod(floatData->lastRecentPeriod())
1466 .withLastRecentPeriodCalendar(floatData->lastRecentPeriodCalendar().empty()
1467 ? Calendar()
1468 : parseCalendar(floatData->lastRecentPeriodCalendar()))
1469 .includeSpread(floatData->includeSpread())
1470 .withLookback(floatData->lookback())
1471 .withFixingDays(floatData->fixingDays())
1472 .withRateCutoff(floatData->rateCutoff() == Null<Size>() ? 0 : floatData->rateCutoff())
1473 .withCaps(buildScheduledVectorNormalised<Real>(floatData->caps(), floatData->capDates(), schedule,
1474 Null<Real>()))
1475 .withFloors(buildScheduledVectorNormalised<Real>(floatData->floors(), floatData->capDates(),
1476 schedule, Null<Real>()))
1477 .withNakedOption(floatData->nakedOption())
1478 .withLocalCapFloor(floatData->localCapFloor())
1481 .withTelescopicValueDates(floatData->telescopicValueDates())
1482 .withPaymentDates(paymentDates);
1483
1484 // If the overnight index is BRL CDI, we need a special coupon pricer
1485 QuantLib::ext::shared_ptr<BRLCdi> brlCdiIndex = QuantLib::ext::dynamic_pointer_cast<BRLCdi>(index);
1486 if (brlCdiIndex)
1487 QuantExt::setCouponPricer(leg, QuantLib::ext::make_shared<BRLCdiCouponPricer>());
1488
1489 return leg;
1490 }
1491}
1492
1493Leg makeBMALeg(const LegData& data, const QuantLib::ext::shared_ptr<QuantExt::BMAIndexWrapper>& indexWrapper,
1494 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const QuantLib::Date& openEndDateReplacement) {
1495 QuantLib::ext::shared_ptr<FloatingLegData> floatData = QuantLib::ext::dynamic_pointer_cast<FloatingLegData>(data.concreteLegData());
1496 QL_REQUIRE(floatData, "Wrong LegType, expected Floating, got " << data.legType());
1497 QuantLib::ext::shared_ptr<BMAIndex> index = indexWrapper->bma();
1498
1499 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
1500 DayCounter dc = parseDayCounter(data.dayCounter());
1501 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1502 Calendar paymentCalendar;
1503
1504 if (data.paymentCalendar().empty())
1505 paymentCalendar = schedule.calendar();
1506 else
1507 paymentCalendar = parseCalendar(data.paymentCalendar());
1508
1509 vector<Real> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1510 vector<Real> spreads =
1511 buildScheduledVectorNormalised(floatData->spreads(), floatData->spreadDates(), schedule, 0.0);
1512 vector<Real> gearings =
1513 buildScheduledVectorNormalised(floatData->gearings(), floatData->gearingDates(), schedule, 1.0);
1514 vector<Real> caps =
1515 buildScheduledVectorNormalised(floatData->caps(), floatData->capDates(), schedule, (Real)Null<Real>());
1516 vector<Real> floors =
1517 buildScheduledVectorNormalised(floatData->floors(), floatData->floorDates(), schedule, (Real)Null<Real>());
1518
1519 applyAmortization(notionals, data, schedule, false);
1520
1521 Leg leg = AverageBMALeg(schedule, index)
1522 .withNotionals(notionals)
1523 .withSpreads(spreads)
1524 .withPaymentDayCounter(dc)
1525 .withPaymentCalendar(paymentCalendar)
1526 .withPaymentAdjustment(bdc)
1527 .withGearings(gearings);
1528
1529 // try to set the rate computation period based on the schedule tenor
1530
1531 Period rateComputationPeriod = 0 * Days;
1532 if (!data.schedule().rules().empty() && !data.schedule().rules().front().tenor().empty())
1533 rateComputationPeriod = parsePeriod(data.schedule().rules().front().tenor());
1534 else if (!data.schedule().dates().empty() && !data.schedule().dates().front().tenor().empty())
1535 rateComputationPeriod = parsePeriod(data.schedule().dates().front().tenor());
1536
1537 // handle caps / floors
1538
1539 if (floatData->caps().size() > 0 || floatData->floors().size() > 0) {
1540
1541 QuantLib::ext::shared_ptr<QuantExt::CapFlooredAverageBMACouponPricer> cfCouponPricer;
1542 auto builder = QuantLib::ext::dynamic_pointer_cast<CapFlooredAverageBMACouponLegEngineBuilder>(
1543 engineFactory->builder("CapFlooredAverageBMACouponLeg"));
1544 QL_REQUIRE(builder, "No builder found for CapFlooredAverageBMACouponLeg");
1545 cfCouponPricer = QuantLib::ext::dynamic_pointer_cast<CapFlooredAverageBMACouponPricer>(
1546 builder->engine(IndexNameTranslator::instance().oreName(index->name()), rateComputationPeriod));
1547 QL_REQUIRE(cfCouponPricer, "internal error, could not cast to CapFlooredAverageBMACouponPricer");
1548
1549 for (Size i = 0; i < leg.size(); ++i) {
1550 auto bmaCpn = QuantLib::ext::dynamic_pointer_cast<AverageBMACoupon>(leg[i]);
1551 QL_REQUIRE(bmaCpn, "makeBMALeg(): internal error, exepcted AverageBMACoupon. Contact dev.");
1552 if (caps[i] != Null<Real>() || floors[i] != Null<Real>()) {
1553 auto cpn = QuantLib::ext::make_shared<CappedFlooredAverageBMACoupon>(
1554 bmaCpn, caps[i], floors[i], floatData->nakedOption(), floatData->includeSpread());
1555 cpn->setPricer(cfCouponPricer);
1556 leg[i] = cpn;
1557 }
1558 }
1559 }
1560
1561 // return the leg
1562
1563 return leg;
1564}
1565
1566Leg makeNotionalLeg(const Leg& refLeg, const bool initNomFlow, const bool finalNomFlow, const bool amortNomFlow,
1567 const Natural notionalPaymentLag, const BusinessDayConvention paymentConvention,
1568 const Calendar paymentCalendar, const bool excludeIndexing) {
1569
1570 // Assumption - Cashflows on Input Leg are all coupons
1571 // This is the Leg to be populated
1572 Leg leg;
1573
1574 // Initial Flow Amount
1575 if (initNomFlow) {
1576 auto coupon = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(refLeg[0]);
1577 QL_REQUIRE(coupon, "makeNotionalLeg does not support non-coupon legs");
1578 double initFlowAmt = (excludeIndexing ? unpackIndexedCoupon(coupon) : coupon)->nominal();
1579 Date initDate = coupon->accrualStartDate();
1580 initDate = paymentCalendar.advance(initDate, notionalPaymentLag, Days, paymentConvention);
1581 if (initFlowAmt != 0)
1582 leg.push_back(QuantLib::ext::shared_ptr<CashFlow>(new SimpleCashFlow(-initFlowAmt, initDate)));
1583 }
1584
1585 // Amortization Flows
1586 if (amortNomFlow) {
1587 for (Size i = 1; i < refLeg.size(); i++) {
1588 auto coupon = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(refLeg[i]);
1589 QL_REQUIRE(coupon, "makeNotionalLeg does not support non-coupon legs");
1590 auto coupon2 = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(refLeg[i - 1]);
1591 QL_REQUIRE(coupon, "makeNotionalLeg does not support non-coupon legs");
1592 Date flowDate = coupon->accrualStartDate();
1593 flowDate = paymentCalendar.advance(flowDate, notionalPaymentLag, Days, paymentConvention);
1594 Real initNom = (excludeIndexing ? unpackIndexedCoupon(coupon2) : coupon2)->nominal();
1595 Real newNom = (excludeIndexing ? unpackIndexedCoupon(coupon) : coupon)->nominal();
1596 Real flow = initNom - newNom;
1597 if (flow != 0)
1598 leg.push_back(QuantLib::ext::shared_ptr<CashFlow>(new SimpleCashFlow(flow, flowDate)));
1599 }
1600 }
1601
1602 // Final Nominal Return at Maturity
1603 if (finalNomFlow) {
1604 auto coupon = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(refLeg.back());
1605 QL_REQUIRE(coupon, "makeNotionalLeg does not support non-coupon legs");
1606 double finalNomFlow = (excludeIndexing ? unpackIndexedCoupon(coupon) : coupon)->nominal();
1607 Date finalDate = coupon->accrualEndDate();
1608 finalDate = paymentCalendar.advance(finalDate, notionalPaymentLag, Days, paymentConvention);
1609 if (finalNomFlow != 0)
1610 leg.push_back(QuantLib::ext::shared_ptr<CashFlow>(new SimpleCashFlow(finalNomFlow, finalDate)));
1611 }
1612
1613 return leg;
1614}
1615
1616Leg makeCPILeg(const LegData& data, const QuantLib::ext::shared_ptr<ZeroInflationIndex>& index,
1617 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const QuantLib::Date& openEndDateReplacement) {
1618
1619 QuantLib::ext::shared_ptr<CPILegData> cpiLegData = QuantLib::ext::dynamic_pointer_cast<CPILegData>(data.concreteLegData());
1620 QL_REQUIRE(cpiLegData, "Wrong LegType, expected CPI, got " << data.legType());
1621
1622 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
1623 DayCounter dc = parseDayCounter(data.dayCounter());
1624 Calendar paymentCalendar;
1625
1626 if (data.paymentCalendar().empty())
1627 paymentCalendar = schedule.calendar();
1628 else
1629 paymentCalendar = parseCalendar(data.paymentCalendar());
1630 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1631
1632 QuantLib::ext::shared_ptr<InflationSwapConvention> cpiSwapConvention = nullptr;
1633
1634 auto inflationConventions = InstrumentConventions::instance().conventions()->get(
1635 cpiLegData->index() + "_INFLATIONSWAP", Convention::Type::InflationSwap);
1636
1637 if (inflationConventions.first)
1638 cpiSwapConvention = QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(inflationConventions.second);
1639
1640 Period observationLag;
1641 if (cpiLegData->observationLag().empty()) {
1642 QL_REQUIRE(cpiSwapConvention,
1643 "observationLag is not specified in legData and couldn't find convention for "
1644 << cpiLegData->index() << ". Please add field to trade xml or add convention");
1645 DLOG("Build CPI Leg and use observation lag from standard inflationswap convention");
1646 observationLag = cpiSwapConvention->observationLag();
1647 } else {
1648 observationLag = parsePeriod(cpiLegData->observationLag());
1649 }
1650
1651 CPI::InterpolationType interpolationMethod;
1652 if (cpiLegData->interpolation().empty()) {
1653 QL_REQUIRE(cpiSwapConvention,
1654 "Interpolation is not specified in legData and couldn't find convention for "
1655 << cpiLegData->index() << ". Please add field to trade xml or add convention");
1656 DLOG("Build CPI Leg and use observation lag from standard inflationswap convention");
1657 interpolationMethod = cpiSwapConvention->interpolated() ? CPI::Linear : CPI::Flat;
1658 } else {
1659 interpolationMethod = parseObservationInterpolation(cpiLegData->interpolation());
1660 }
1661
1662 vector<double> rates = buildScheduledVector(cpiLegData->rates(), cpiLegData->rateDates(), schedule);
1663 vector<double> notionals = buildScheduledVector(data.notionals(), data.notionalDates(), schedule);
1664 bool couponCap = cpiLegData->caps().size() > 0;
1665 bool couponFloor = cpiLegData->floors().size() > 0;
1666 bool couponCapFloor = cpiLegData->caps().size() > 0 || cpiLegData->floors().size() > 0;
1667 bool finalFlowCapFloor = cpiLegData->finalFlowCap() != Null<Real>() || cpiLegData->finalFlowFloor() != Null<Real>();
1668
1669 applyAmortization(notionals, data, schedule, false);
1670 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1671
1672 QuantExt::CPILeg cpiLeg =
1673 QuantExt::CPILeg(schedule, index,
1674 engineFactory->market()->discountCurve(data.currency(),
1675 engineFactory->configuration(MarketContext::pricing)),
1676 cpiLegData->baseCPI(), observationLag)
1677 .withNotionals(notionals)
1680 .withPaymentCalendar(paymentCalendar)
1681 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1682 .withFixedRates(rates)
1683 .withObservationInterpolation(interpolationMethod)
1684 .withSubtractInflationNominal(cpiLegData->subtractInflationNominal())
1685 .withSubtractInflationNominalAllCoupons(cpiLegData->subtractInflationNominalCoupons());
1686
1687 // the cpi leg uses the first schedule date as the start date, which only makes sense if there are at least
1688 // two dates in the schedule, otherwise the only date in the schedule is the pay date of the cf and a separate
1689 // start date is expected; if both the separate start date and a schedule with more than one date is given
1690 const string& start = cpiLegData->startDate();
1691 if (schedule.size() < 2) {
1692 QL_REQUIRE(!start.empty(), "makeCPILeg(): only one schedule date, a 'StartDate' must be given.");
1693 cpiLeg.withStartDate(parseDate(start));
1694 } else if (!start.empty()) {
1695 DLOG("Schedule with more than 2 dates was provided. The first schedule date "
1696
1697 << io::iso_date(schedule.dates().front()) << " is used as the start date. The 'StartDate' of " << start
1698 << " is not used.");
1699 }
1700 if (couponCap)
1701 cpiLeg.withCaps(buildScheduledVector(cpiLegData->caps(), cpiLegData->capDates(), schedule));
1702
1703 if (couponFloor)
1704 cpiLeg.withFloors(buildScheduledVector(cpiLegData->floors(), cpiLegData->floorDates(), schedule));
1705
1706 if (cpiLegData->finalFlowCap() != Null<Real>())
1707 cpiLeg.withFinalFlowCap(cpiLegData->finalFlowCap());
1708
1709 if (cpiLegData->finalFlowFloor() != Null<Real>())
1710 cpiLeg.withFinalFlowFloor(cpiLegData->finalFlowFloor());
1711
1712 Leg leg = cpiLeg.operator Leg();
1713 Size n = leg.size();
1714 QL_REQUIRE(n > 0, "Empty CPI Leg");
1715
1716 if (couponCapFloor || finalFlowCapFloor) {
1717
1718 string indexName = cpiLegData->index();
1719
1720 // get a coupon pricer for the leg
1721 QuantLib::ext::shared_ptr<EngineBuilder> cpBuilder = engineFactory->builder("CappedFlooredCpiLegCoupons");
1722 QL_REQUIRE(cpBuilder, "No builder found for CappedFlooredCpiLegCoupons");
1723 QuantLib::ext::shared_ptr<CapFlooredCpiLegCouponEngineBuilder> cappedFlooredCpiCouponBuilder =
1724 QuantLib::ext::dynamic_pointer_cast<CapFlooredCpiLegCouponEngineBuilder>(cpBuilder);
1725 QuantLib::ext::shared_ptr<InflationCouponPricer> couponPricer = cappedFlooredCpiCouponBuilder->engine(indexName);
1726
1727 // get a cash flow pricer for the leg
1728 QuantLib::ext::shared_ptr<EngineBuilder> cfBuilder = engineFactory->builder("CappedFlooredCpiLegCashFlows");
1729 QL_REQUIRE(cfBuilder, "No builder found for CappedFlooredCpiLegCashFLows");
1730 QuantLib::ext::shared_ptr<CapFlooredCpiLegCashFlowEngineBuilder> cappedFlooredCpiCashFlowBuilder =
1731 QuantLib::ext::dynamic_pointer_cast<CapFlooredCpiLegCashFlowEngineBuilder>(cfBuilder);
1732 QuantLib::ext::shared_ptr<InflationCashFlowPricer> cashFlowPricer = cappedFlooredCpiCashFlowBuilder->engine(indexName);
1733
1734 // set coupon pricer for the leg
1735 for (Size i = 0; i < leg.size(); i++) {
1736 // nothing to do for the plain CPI Coupon, because the pricer is already set when the leg builder is called
1737 // nothing to do for the plain CPI CashFlow either, because it does not require a pricer
1738
1739 QuantLib::ext::shared_ptr<CappedFlooredCPICoupon> cfCpiCoupon =
1740 QuantLib::ext::dynamic_pointer_cast<CappedFlooredCPICoupon>(leg[i]);
1741 if (cfCpiCoupon && couponCapFloor) {
1742 cfCpiCoupon->setPricer(couponPricer);
1743 }
1744
1745 QuantLib::ext::shared_ptr<CappedFlooredCPICashFlow> cfCpiCashFlow =
1746 QuantLib::ext::dynamic_pointer_cast<CappedFlooredCPICashFlow>(leg[i]);
1747 if (cfCpiCashFlow && finalFlowCapFloor && i == (leg.size() - 1)) {
1748 cfCpiCashFlow->setPricer(cashFlowPricer);
1749 }
1750 }
1751 }
1752
1753 // QuantLib CPILeg automatically adds a Notional Cashflow at maturity date on a CPI swap
1754 if (!data.notionalFinalExchange()) {
1755 leg.pop_back();
1756 }
1757
1758 // build naked option leg if required and we have at least one cap/floor present in the coupon or the final flow
1759 if ((couponCapFloor || finalFlowCapFloor) && cpiLegData->nakedOption()) {
1761 }
1762
1763 return leg;
1764}
1765
1766Leg makeYoYLeg(const LegData& data, const QuantLib::ext::shared_ptr<InflationIndex>& index,
1767 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const QuantLib::Date& openEndDateReplacement) {
1768 QuantLib::ext::shared_ptr<YoYLegData> yoyLegData = QuantLib::ext::dynamic_pointer_cast<YoYLegData>(data.concreteLegData());
1769 QL_REQUIRE(yoyLegData, "Wrong LegType, expected YoY, got " << data.legType());
1770
1771 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
1772 DayCounter dc = parseDayCounter(data.dayCounter());
1773 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1774 Calendar paymentCalendar;
1775
1776 QuantLib::ext::shared_ptr<InflationSwapConvention> cpiSwapConvention = nullptr;
1777
1778 auto inflationConventions = InstrumentConventions::instance().conventions()->get(
1779 yoyLegData->index() + "_INFLATIONSWAP", Convention::Type::InflationSwap);
1780
1781 if (inflationConventions.first)
1782 cpiSwapConvention = QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(inflationConventions.second);
1783
1784 Period observationLag;
1785 if (yoyLegData->observationLag().empty()) {
1786 QL_REQUIRE(cpiSwapConvention,
1787 "observationLag is not specified in legData and couldn't find convention for "
1788 << yoyLegData->index() << ". Please add field to trade xml or add convention");
1789 DLOG("Build CPI Leg and use observation lag from standard inflationswap convention");
1790 observationLag = cpiSwapConvention->observationLag();
1791 } else {
1792 observationLag = parsePeriod(yoyLegData->observationLag());
1793 }
1794
1795 if (data.paymentCalendar().empty())
1796 paymentCalendar = schedule.calendar();
1797 else
1798 paymentCalendar = parseCalendar(data.paymentCalendar());
1799
1800 vector<double> gearings =
1801 buildScheduledVectorNormalised(yoyLegData->gearings(), yoyLegData->gearingDates(), schedule, 1.0);
1802 vector<double> spreads =
1803 buildScheduledVectorNormalised(yoyLegData->spreads(), yoyLegData->spreadDates(), schedule, 0.0);
1804 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1805
1806 bool irregularYoY = yoyLegData->irregularYoY();
1807 bool couponCap = yoyLegData->caps().size() > 0;
1808 bool couponFloor = yoyLegData->floors().size() > 0;
1809 bool couponCapFloor = yoyLegData->caps().size() > 0 || yoyLegData->floors().size() > 0;
1810 bool addInflationNotional = yoyLegData->addInflationNotional();
1811
1812 applyAmortization(notionals, data, schedule, false);
1813 Leg leg;
1814 if (!irregularYoY) {
1815 auto yoyIndex = QuantLib::ext::dynamic_pointer_cast<YoYInflationIndex>(index);
1816 QL_REQUIRE(yoyIndex, "Need a YoY Inflation Index");
1818 QuantExt::yoyInflationLeg(schedule, paymentCalendar, yoyIndex, observationLag)
1819 .withNotionals(notionals)
1822 .withFixingDays(yoyLegData->fixingDays())
1823 .withGearings(gearings)
1824 .withSpreads(spreads)
1825 .withInflationNotional(addInflationNotional)
1826 .withRateCurve(engineFactory->market()->discountCurve(
1827 data.currency(), engineFactory->configuration(MarketContext::pricing)));
1828
1829 if (couponCap)
1830 yoyLeg.withCaps(buildScheduledVector(yoyLegData->caps(), yoyLegData->capDates(), schedule));
1831
1832 if (couponFloor)
1833 yoyLeg.withFloors(buildScheduledVector(yoyLegData->floors(), yoyLegData->floorDates(), schedule));
1834
1835 leg = yoyLeg.operator Leg();
1836
1837 if (couponCapFloor) {
1838 // get a coupon pricer for the leg
1839 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder("CapFlooredYYLeg");
1840 QL_REQUIRE(builder, "No builder found for CapFlooredYYLeg");
1841 QuantLib::ext::shared_ptr<CapFlooredYoYLegEngineBuilder> cappedFlooredYoYBuilder =
1842 QuantLib::ext::dynamic_pointer_cast<CapFlooredYoYLegEngineBuilder>(builder);
1843 string indexname = yoyLegData->index();
1844 QuantLib::ext::shared_ptr<InflationCouponPricer> couponPricer =
1845 cappedFlooredYoYBuilder->engine(IndexNameTranslator::instance().oreName(indexname));
1846
1847 // set coupon pricer for the leg
1848
1849 for (Size i = 0; i < leg.size(); i++) {
1850 QuantLib::ext::dynamic_pointer_cast<QuantExt::CappedFlooredYoYInflationCoupon>(leg[i])->setPricer(
1851 QuantLib::ext::dynamic_pointer_cast<QuantLib::YoYInflationCouponPricer>(couponPricer));
1852 }
1853
1854 // build naked option leg if required
1855 if (yoyLegData->nakedOption()) {
1857 for (auto const& t : leg) {
1858 auto s = QuantLib::ext::dynamic_pointer_cast<StrippedCappedFlooredYoYInflationCoupon>(t);
1859 }
1860 }
1861 }
1862 } else {
1863 QuantLib::CPI::InterpolationType interpolation = QuantLib::CPI::Flat;
1864 if (cpiSwapConvention && cpiSwapConvention->interpolated()) {
1865 interpolation = QuantLib::CPI::Linear;
1866 }
1867 auto zcIndex = QuantLib::ext::dynamic_pointer_cast<ZeroInflationIndex>(index);
1868 QL_REQUIRE(zcIndex, "Need a Zero Coupon Inflation Index");
1870 QuantExt::NonStandardYoYInflationLeg(schedule, schedule.calendar(), zcIndex, observationLag)
1871 .withNotionals(notionals)
1874 .withFixingDays(yoyLegData->fixingDays())
1875 .withGearings(gearings)
1876 .withSpreads(spreads)
1877 .withRateCurve(engineFactory->market()->discountCurve(
1878 data.currency(), engineFactory->configuration(MarketContext::pricing)))
1879 .withInflationNotional(addInflationNotional)
1880 .withObservationInterpolation(interpolation);
1881
1882 if (couponCap)
1883 yoyLeg.withCaps(buildScheduledVector(yoyLegData->caps(), yoyLegData->capDates(), schedule));
1884
1885 if (couponFloor)
1886 yoyLeg.withFloors(buildScheduledVector(yoyLegData->floors(), yoyLegData->floorDates(), schedule));
1887
1888 leg = yoyLeg.operator Leg();
1889
1890 if (couponCapFloor) {
1891 // get a coupon pricer for the leg
1892 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder("CapFlooredNonStdYYLeg");
1893 QL_REQUIRE(builder, "No builder found for CapFlooredNonStdYYLeg");
1894 QuantLib::ext::shared_ptr<CapFlooredNonStandardYoYLegEngineBuilder> cappedFlooredYoYBuilder =
1895 QuantLib::ext::dynamic_pointer_cast<CapFlooredNonStandardYoYLegEngineBuilder>(builder);
1896 string indexname = zcIndex->name();
1897 QuantLib::ext::shared_ptr<InflationCouponPricer> couponPricer =
1898 cappedFlooredYoYBuilder->engine(IndexNameTranslator::instance().oreName(indexname));
1899
1900 // set coupon pricer for the leg
1901
1902 for (Size i = 0; i < leg.size(); i++) {
1903 QuantLib::ext::dynamic_pointer_cast<QuantExt::NonStandardCappedFlooredYoYInflationCoupon>(leg[i])->setPricer(
1904 QuantLib::ext::dynamic_pointer_cast<QuantExt::NonStandardYoYInflationCouponPricer>(couponPricer));
1905 }
1906
1907 // build naked option leg if required
1908 if (yoyLegData->nakedOption()) {
1910 for (auto const& t : leg) {
1911 auto s = QuantLib::ext::dynamic_pointer_cast<StrippedCappedFlooredYoYInflationCoupon>(t);
1912 }
1913 }
1914 }
1915 }
1916 return leg;
1917}
1918
1919Leg makeCMSLeg(const LegData& data, const QuantLib::ext::shared_ptr<QuantLib::SwapIndex>& swapIndex,
1920 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
1921 const QuantLib::Date& openEndDateReplacement) {
1922 QuantLib::ext::shared_ptr<CMSLegData> cmsData = QuantLib::ext::dynamic_pointer_cast<CMSLegData>(data.concreteLegData());
1923 QL_REQUIRE(cmsData, "Wrong LegType, expected CMS, got " << data.legType());
1924
1925 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
1926 DayCounter dc = parseDayCounter(data.dayCounter());
1927 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
1928 Calendar paymentCalendar;
1929 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
1930
1931 if (data.paymentCalendar().empty())
1932 paymentCalendar = schedule.calendar();
1933 else
1934 paymentCalendar = parseCalendar(data.paymentCalendar());
1935
1936 vector<double> spreads =
1937 ore::data::buildScheduledVectorNormalised(cmsData->spreads(), cmsData->spreadDates(), schedule, 0.0);
1938 vector<double> gearings =
1939 ore::data::buildScheduledVectorNormalised(cmsData->gearings(), cmsData->gearingDates(), schedule, 1.0);
1940 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
1941 Size fixingDays = cmsData->fixingDays() == Null<Size>() ? swapIndex->fixingDays() : cmsData->fixingDays();
1942
1943 applyAmortization(notionals, data, schedule, false);
1944
1945 CmsLeg cmsLeg = CmsLeg(schedule, swapIndex)
1946 .withNotionals(notionals)
1947 .withSpreads(spreads)
1948 .withGearings(gearings)
1949 .withPaymentCalendar(paymentCalendar)
1950 .withPaymentDayCounter(dc)
1951 .withPaymentAdjustment(bdc)
1952 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
1953 .withFixingDays(fixingDays)
1954 .inArrears(cmsData->isInArrears());
1955
1956 if (cmsData->caps().size() > 0)
1957 cmsLeg.withCaps(buildScheduledVector(cmsData->caps(), cmsData->capDates(), schedule));
1958
1959 if (cmsData->floors().size() > 0)
1960 cmsLeg.withFloors(buildScheduledVector(cmsData->floors(), cmsData->floorDates(), schedule));
1961
1962 if (!attachPricer)
1963 return cmsLeg;
1964
1965 // Get a coupon pricer for the leg
1966 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder("CMS");
1967 QL_REQUIRE(builder, "No builder found for CmsLeg");
1968 QuantLib::ext::shared_ptr<CmsCouponPricerBuilder> cmsSwapBuilder =
1969 QuantLib::ext::dynamic_pointer_cast<CmsCouponPricerBuilder>(builder);
1970 QuantLib::ext::shared_ptr<FloatingRateCouponPricer> couponPricer =
1971 cmsSwapBuilder->engine(IndexNameTranslator::instance().oreName(swapIndex->iborIndex()->name()));
1972
1973 // Loop over the coupons in the leg and set pricer
1974 Leg tmpLeg = cmsLeg;
1975 QuantLib::setCouponPricer(tmpLeg, couponPricer);
1976
1977 // build naked option leg if required
1978 if (cmsData->nakedOption()) {
1979 tmpLeg = StrippedCappedFlooredCouponLeg(tmpLeg);
1980 }
1981 return tmpLeg;
1982}
1983
1984Leg makeCMBLeg(const LegData& data, const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
1985 const QuantLib::Date& openEndDateReplacement) {
1986 QuantLib::ext::shared_ptr<CMBLegData> cmbData = QuantLib::ext::dynamic_pointer_cast<CMBLegData>(data.concreteLegData());
1987 QL_REQUIRE(cmbData, "Wrong LegType, expected CMB, got " << data.legType());
1988
1989 std::string bondIndexName = cmbData->genericBond();
1990 // Expected bondIndexName structure with at least two tokens, separated by "-", of the form FAMILY-TERM or
1991 // FAMILY-MUN, for example: US-CMT-5Y, US-TIPS-10Y, UK-GILT-5Y, DE-BUND-10Y
1992 std::vector<string> tokens;
1993 split(tokens, bondIndexName, boost::is_any_of("-"));
1994 QL_REQUIRE(tokens.size() >= 2,
1995 "Generic Bond Index with at least two tokens separated by - expected, found " << bondIndexName);
1996 std::string securityFamily = tokens[0];
1997 for (Size i = 1; i < tokens.size() - 1; ++i)
1998 securityFamily = securityFamily + "-" + tokens[i];
1999 string underlyingTerm = tokens.back();
2000 Period underlyingPeriod = parsePeriod(underlyingTerm);
2001 LOG("Generic bond id " << bondIndexName << " has family " << securityFamily << " and term " << underlyingPeriod);
2002
2003 Schedule schedule = makeSchedule(data.schedule());
2004 Calendar calendar = schedule.calendar();
2005 int fixingDays = cmbData->fixingDays();
2006 BusinessDayConvention convention = schedule.businessDayConvention();
2007 bool creditRisk = cmbData->hasCreditRisk();
2008
2009 // Get the generic bond reference data, notional 1, credit risk as specified in the leg data
2010 BondData bondData(securityFamily, 1.0, creditRisk);
2011 bondData.populateFromBondReferenceData(engineFactory->referenceData());
2012 DLOG("Bond data for security id " << securityFamily << " loaded");
2013 QL_REQUIRE(bondData.coupons().size() == 1,
2014 "multiple reference bond legs not covered by the CMB leg");
2015 QL_REQUIRE(bondData.coupons().front().schedule().rules().size() == 1,
2016 "multiple bond schedule rules not covered by the CMB leg");
2017 QL_REQUIRE(bondData.coupons().front().schedule().dates().size() == 0,
2018 "dates based bond schedules not covered by the CMB leg");
2019
2020 // Get bond yield conventions
2021 auto ret = InstrumentConventions::instance().conventions()->get(securityFamily, Convention::Type::BondYield);
2022 QuantLib::ext::shared_ptr<BondYieldConvention> conv;
2023 if (ret.first)
2024 conv = QuantLib::ext::dynamic_pointer_cast<BondYieldConvention>(ret.second);
2025 else {
2026 conv = QuantLib::ext::make_shared<BondYieldConvention>();
2027 ALOG("BondYield conventions not found for security " << securityFamily << ", falling back on defaults:"
2028 << " compounding=" << conv->compoundingName()
2029 << ", priceType=" << conv->priceTypeName()
2030 << ", accuracy=" << conv->accuracy()
2031 << ", maxEvaluations=" << conv->maxEvaluations()
2032 << ", guess=" << conv->guess());
2033 }
2034
2035 Schedule bondSchedule = makeSchedule(bondData.coupons().front().schedule());
2036 DayCounter bondDayCounter = parseDayCounter(bondData.coupons().front().dayCounter());
2037 Currency bondCurrency = parseCurrency(bondData.currency());
2038 Calendar bondCalendar = parseCalendar(bondData.calendar());
2039 Size bondSettlementDays = parseInteger(bondData.settlementDays());
2040 BusinessDayConvention bondConvention = bondSchedule.businessDayConvention();
2041 bool bondEndOfMonth = bondSchedule.endOfMonth();
2042 Frequency bondFrequency = bondSchedule.tenor().frequency();
2043
2044 DayCounter dayCounter = parseDayCounter(data.dayCounter());
2045
2046 // Create a ConstantMaturityBondIndex for each schedule start date
2047 DLOG("Create Constant Maturity Bond Indices for each period");
2048 std::vector<QuantLib::ext::shared_ptr<QuantExt::ConstantMaturityBondIndex>> bondIndices;
2049 for (Size i = 0; i < schedule.dates().size() - 1; ++i) {
2050 // Construct bond with start date = accrual start date and maturity = accrual start date + term
2051 // or start = accrual end if in arrears. Adjusted for fixing lag, ignoring bond settlement lags for now.
2052 Date refDate = cmbData->isInArrears() ? schedule[i+1] : schedule[i];
2053 Date start = calendar.advance(refDate, -fixingDays, Days, Preceding);
2054 std::string startDate = to_string(start);
2055 std::string endDate = to_string(start + underlyingPeriod);
2056 bondData.populateFromBondReferenceData(engineFactory->referenceData(), startDate, endDate);
2057 Bond bondTrade(Envelope(), bondData);
2058 bondTrade.build(engineFactory);
2059 auto bond = QuantLib::ext::dynamic_pointer_cast<QuantLib::Bond>(bondTrade.instrument()->qlInstrument());
2060 QuantLib::ext::shared_ptr<QuantExt::ConstantMaturityBondIndex> bondIndex
2061 = QuantLib::ext::make_shared<QuantExt::ConstantMaturityBondIndex>(securityFamily, underlyingPeriod,
2062 // from bond reference data
2063 bondSettlementDays, bondCurrency, bondCalendar, bondDayCounter, bondConvention, bondEndOfMonth,
2064 // underlying forward starting bond
2065 bond,
2066 // yield calculation parameters from conventions, except frequency which is from bond reference data
2067 conv->compounding(), bondFrequency, conv->accuracy(), conv->maxEvaluations(), conv->guess(), conv->priceType());
2068 bondIndices.push_back(bondIndex);
2069 }
2070
2071 // Create a sequence of floating rate coupons linked to those indexes and concatenate them to a leg
2072 DLOG("Create CMB leg");
2073 vector<double> spreads = buildScheduledVectorNormalised(cmbData->spreads(), cmbData->spreadDates(), schedule, 0.0);
2074 vector<double> gearings = buildScheduledVectorNormalised(cmbData->gearings(), cmbData->gearingDates(), schedule, 1.0);
2075 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
2076
2077 // FIXME: Move the following into CmbLeg in cmbcoupon.xpp
2078 QL_REQUIRE(bondIndices.size() == schedule.size() - 1,
2079 "vector size mismatch between schedule (" << schedule.size() << ") "
2080 << "and bond indices (" << bondIndices.size() << ")");
2081 Leg leg;
2082 for (Size i = 0; i < schedule.size() - 1; i++) {
2083 Date paymentDate = calendar.adjust(schedule[i + 1], convention);
2084 DLOG("Coupon " << i << ": "
2085 << io::iso_date(paymentDate) << " "
2086 << notionals[i] << " "
2087 << io::iso_date(schedule[i]) << " "
2088 << io::iso_date(schedule[i+1]) << " "
2089 << cmbData->fixingDays() << " "
2090 << gearings[i] << " "
2091 << spreads[i] << " "
2092 << dayCounter.name());
2093 QuantLib::ext::shared_ptr<CmbCoupon> coupon
2094 = QuantLib::ext::make_shared<CmbCoupon>(paymentDate, notionals[i], schedule[i], schedule[i + 1],
2095 cmbData->fixingDays(), bondIndices[i], gearings[i], spreads[i], Date(), Date(),
2096 dayCounter, cmbData->isInArrears());
2097 auto pricer = QuantLib::ext::make_shared<CmbCouponPricer>();
2098 coupon->setPricer(pricer);
2099 leg.push_back(coupon);
2100 }
2101
2102 return leg;
2103}
2104
2105Leg makeDigitalCMSLeg(const LegData& data, const QuantLib::ext::shared_ptr<QuantLib::SwapIndex>& swapIndex,
2106 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
2107 const QuantLib::Date& openEndDateReplacement) {
2108 auto digitalCmsData = QuantLib::ext::dynamic_pointer_cast<DigitalCMSLegData>(data.concreteLegData());
2109 QL_REQUIRE(digitalCmsData, "Wrong LegType, expected DigitalCMS");
2110
2111 auto cmsData = QuantLib::ext::dynamic_pointer_cast<CMSLegData>(digitalCmsData->underlying());
2112 QL_REQUIRE(cmsData, "Incomplete DigitalCms Leg, expected CMS data");
2113
2114 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
2115
2116 DayCounter dc = parseDayCounter(data.dayCounter());
2117 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
2118 vector<double> spreads =
2119 ore::data::buildScheduledVectorNormalised(cmsData->spreads(), cmsData->spreadDates(), schedule, 0.0);
2120 vector<double> gearings =
2121 ore::data::buildScheduledVectorNormalised(cmsData->gearings(), cmsData->gearingDates(), schedule, 1.0);
2122 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
2123
2124 double eps = 1e-4;
2125 vector<double> callStrikes =
2126 ore::data::buildScheduledVector(digitalCmsData->callStrikes(), digitalCmsData->callStrikeDates(), schedule);
2127
2128 for (Size i = 0; i < callStrikes.size(); i++) {
2129 if (std::fabs(callStrikes[i]) < eps / 2) {
2130 callStrikes[i] = eps / 2;
2131 }
2132 }
2133
2134 vector<double> callPayoffs =
2135 ore::data::buildScheduledVector(digitalCmsData->callPayoffs(), digitalCmsData->callPayoffDates(), schedule);
2136
2137 vector<double> putStrikes =
2138 ore::data::buildScheduledVector(digitalCmsData->putStrikes(), digitalCmsData->putStrikeDates(), schedule);
2139 vector<double> putPayoffs =
2140 ore::data::buildScheduledVector(digitalCmsData->putPayoffs(), digitalCmsData->putPayoffDates(), schedule);
2141
2142 Size fixingDays = cmsData->fixingDays() == Null<Size>() ? swapIndex->fixingDays() : cmsData->fixingDays();
2143
2144 applyAmortization(notionals, data, schedule, false);
2145
2146 DigitalCmsLeg digitalCmsLeg = DigitalCmsLeg(schedule, swapIndex)
2147 .withNotionals(notionals)
2148 .withSpreads(spreads)
2149 .withGearings(gearings)
2150 // .withPaymentCalendar(paymentCalendar)
2151 .withPaymentDayCounter(dc)
2152 .withPaymentAdjustment(bdc)
2153 .withFixingDays(fixingDays)
2154 .inArrears(cmsData->isInArrears())
2155 .withCallStrikes(callStrikes)
2156 .withLongCallOption(digitalCmsData->callPosition())
2157 .withCallATM(digitalCmsData->isCallATMIncluded())
2158 .withCallPayoffs(callPayoffs)
2159 .withPutStrikes(putStrikes)
2160 .withLongPutOption(digitalCmsData->putPosition())
2161 .withPutATM(digitalCmsData->isPutATMIncluded())
2162 .withPutPayoffs(putPayoffs)
2163 .withReplication(QuantLib::ext::make_shared<DigitalReplication>())
2164 .withNakedOption(cmsData->nakedOption());
2165
2166 if (cmsData->caps().size() > 0 || cmsData->floors().size() > 0)
2167 QL_FAIL("caps/floors not supported in DigitalCMSOptions");
2168
2169 if (!attachPricer)
2170 return digitalCmsLeg;
2171
2172 // Get a coupon pricer for the leg
2173 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder("CMS");
2174 QL_REQUIRE(builder, "No CMS builder found for CmsLeg");
2175 QuantLib::ext::shared_ptr<CmsCouponPricerBuilder> cmsBuilder = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricerBuilder>(builder);
2176 auto cmsPricer = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricer>(
2177 cmsBuilder->engine(IndexNameTranslator::instance().oreName(swapIndex->iborIndex()->name())));
2178 QL_REQUIRE(cmsPricer, "Expected CMS Pricer");
2179
2180 // Loop over the coupons in the leg and set pricer
2181 Leg tmpLeg = digitalCmsLeg;
2182 QuantLib::setCouponPricer(tmpLeg, cmsPricer);
2183
2184 return tmpLeg;
2185}
2186
2187Leg makeCMSSpreadLeg(const LegData& data, const QuantLib::ext::shared_ptr<QuantLib::SwapSpreadIndex>& swapSpreadIndex,
2188 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory, const bool attachPricer,
2189 const QuantLib::Date& openEndDateReplacement) {
2190 QuantLib::ext::shared_ptr<CMSSpreadLegData> cmsSpreadData =
2191 QuantLib::ext::dynamic_pointer_cast<CMSSpreadLegData>(data.concreteLegData());
2192 QL_REQUIRE(cmsSpreadData, "Wrong LegType, expected CMSSpread, got " << data.legType());
2193
2194 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
2195 DayCounter dc = parseDayCounter(data.dayCounter());
2196 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
2197 Calendar paymentCalendar;
2198 if (data.paymentCalendar().empty())
2199 paymentCalendar = schedule.calendar();
2200 else
2201 paymentCalendar = parseCalendar(data.paymentCalendar());
2202
2203 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
2204
2205 vector<double> spreads = ore::data::buildScheduledVectorNormalised(cmsSpreadData->spreads(),
2206 cmsSpreadData->spreadDates(), schedule, 0.0);
2207 vector<double> gearings = ore::data::buildScheduledVectorNormalised(cmsSpreadData->gearings(),
2208 cmsSpreadData->gearingDates(), schedule, 1.0);
2209 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
2210 Size fixingDays =
2211 cmsSpreadData->fixingDays() == Null<Size>() ? swapSpreadIndex->fixingDays() : cmsSpreadData->fixingDays();
2212
2213 applyAmortization(notionals, data, schedule, false);
2214
2215 CmsSpreadLeg cmsSpreadLeg = CmsSpreadLeg(schedule, swapSpreadIndex)
2216 .withNotionals(notionals)
2217 .withSpreads(spreads)
2218 .withGearings(gearings)
2219 .withPaymentCalendar(paymentCalendar)
2220 .withPaymentDayCounter(dc)
2221 .withPaymentAdjustment(bdc)
2222 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
2223 .withFixingDays(fixingDays)
2224 .inArrears(cmsSpreadData->isInArrears());
2225
2226 if (cmsSpreadData->caps().size() > 0)
2227 cmsSpreadLeg.withCaps(buildScheduledVector(cmsSpreadData->caps(), cmsSpreadData->capDates(), schedule));
2228
2229 if (cmsSpreadData->floors().size() > 0)
2230 cmsSpreadLeg.withFloors(buildScheduledVector(cmsSpreadData->floors(), cmsSpreadData->floorDates(), schedule));
2231
2232 if (!attachPricer)
2233 return cmsSpreadLeg;
2234
2235 // Get a coupon pricer for the leg
2236 auto builder1 = engineFactory->builder("CMS");
2237 QL_REQUIRE(builder1, "No CMS builder found for CmsSpreadLeg");
2238 auto cmsBuilder = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricerBuilder>(builder1);
2239 auto cmsPricer = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricer>(cmsBuilder->engine(
2240 IndexNameTranslator::instance().oreName(swapSpreadIndex->swapIndex1()->iborIndex()->name())));
2241 QL_REQUIRE(cmsPricer, "Expected CMS Pricer");
2242 auto builder2 = engineFactory->builder("CMSSpread");
2243 QL_REQUIRE(builder2, "No CMS Spread builder found for CmsSpreadLeg");
2244 auto cmsSpreadBuilder = QuantLib::ext::dynamic_pointer_cast<CmsSpreadCouponPricerBuilder>(builder2);
2245 auto cmsSpreadPricer = cmsSpreadBuilder->engine(swapSpreadIndex->currency(), cmsSpreadData->swapIndex1(),
2246 cmsSpreadData->swapIndex2(), cmsPricer);
2247 QL_REQUIRE(cmsSpreadPricer, "Expected CMS Spread Pricer");
2248
2249 // Loop over the coupons in the leg and set pricer
2250 Leg tmpLeg = cmsSpreadLeg;
2251 QuantLib::setCouponPricer(tmpLeg, cmsSpreadPricer);
2252
2253 // build naked option leg if required
2254 if (cmsSpreadData->nakedOption()) {
2255 tmpLeg = StrippedCappedFlooredCouponLeg(tmpLeg);
2256 }
2257 return tmpLeg;
2258}
2259
2260Leg makeDigitalCMSSpreadLeg(const LegData& data, const QuantLib::ext::shared_ptr<QuantLib::SwapSpreadIndex>& swapSpreadIndex,
2261 const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory,
2262 const QuantLib::Date& openEndDateReplacement) {
2263 auto digitalCmsSpreadData = QuantLib::ext::dynamic_pointer_cast<DigitalCMSSpreadLegData>(data.concreteLegData());
2264 QL_REQUIRE(digitalCmsSpreadData, "Wrong LegType, expected DigitalCMSSpread");
2265
2266 auto cmsSpreadData = QuantLib::ext::dynamic_pointer_cast<CMSSpreadLegData>(digitalCmsSpreadData->underlying());
2267 QL_REQUIRE(cmsSpreadData, "Incomplete DigitalCmsSpread Leg, expected CMSSpread data");
2268
2269 Schedule schedule = makeSchedule(data.schedule(), openEndDateReplacement);
2270 DayCounter dc = parseDayCounter(data.dayCounter());
2271 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
2272
2273 Calendar paymentCalendar;
2274 if (data.paymentCalendar().empty())
2275 paymentCalendar = schedule.calendar();
2276 else
2277 paymentCalendar = parseCalendar(data.paymentCalendar());
2278
2279 vector<double> spreads = ore::data::buildScheduledVectorNormalised(cmsSpreadData->spreads(),
2280 cmsSpreadData->spreadDates(), schedule, 0.0);
2281 vector<double> gearings = ore::data::buildScheduledVectorNormalised(cmsSpreadData->gearings(),
2282 cmsSpreadData->gearingDates(), schedule, 1.0);
2283 vector<double> notionals = buildScheduledVectorNormalised(data.notionals(), data.notionalDates(), schedule, 0.0);
2284
2285 double eps = 1e-4;
2286 vector<double> callStrikes = ore::data::buildScheduledVector(digitalCmsSpreadData->callStrikes(),
2287 digitalCmsSpreadData->callStrikeDates(), schedule);
2288
2289 for (Size i = 0; i < callStrikes.size(); i++) {
2290 if (std::fabs(callStrikes[i]) < eps / 2) {
2291 callStrikes[i] = eps / 2;
2292 }
2293 }
2294
2295 vector<double> callPayoffs = ore::data::buildScheduledVector(digitalCmsSpreadData->callPayoffs(),
2296 digitalCmsSpreadData->callPayoffDates(), schedule);
2297
2298 vector<double> putStrikes = ore::data::buildScheduledVector(digitalCmsSpreadData->putStrikes(),
2299 digitalCmsSpreadData->putStrikeDates(), schedule);
2300 vector<double> putPayoffs = ore::data::buildScheduledVector(digitalCmsSpreadData->putPayoffs(),
2301 digitalCmsSpreadData->putPayoffDates(), schedule);
2302
2303 Size fixingDays =
2304 cmsSpreadData->fixingDays() == Null<Size>() ? swapSpreadIndex->fixingDays() : cmsSpreadData->fixingDays();
2305
2306 applyAmortization(notionals, data, schedule, false);
2307
2308 DigitalCmsSpreadLeg digitalCmsSpreadLeg = DigitalCmsSpreadLeg(schedule, swapSpreadIndex)
2309 .withNotionals(notionals)
2310 .withSpreads(spreads)
2311 .withGearings(gearings)
2312 .withPaymentDayCounter(dc)
2313 .withPaymentCalendar(paymentCalendar)
2314 .withPaymentAdjustment(bdc)
2315 .withFixingDays(fixingDays)
2316 .inArrears(cmsSpreadData->isInArrears())
2317 .withCallStrikes(callStrikes)
2318 .withLongCallOption(digitalCmsSpreadData->callPosition())
2319 .withCallATM(digitalCmsSpreadData->isCallATMIncluded())
2320 .withCallPayoffs(callPayoffs)
2321 .withPutStrikes(putStrikes)
2322 .withLongPutOption(digitalCmsSpreadData->putPosition())
2323 .withPutATM(digitalCmsSpreadData->isPutATMIncluded())
2324 .withPutPayoffs(putPayoffs)
2325 .withReplication(QuantLib::ext::make_shared<DigitalReplication>())
2326 .withNakedOption(cmsSpreadData->nakedOption());
2327
2328 if (cmsSpreadData->caps().size() > 0 || cmsSpreadData->floors().size() > 0)
2329 QL_FAIL("caps/floors not supported in DigitalCMSSpreadOptions");
2330
2331 // Get a coupon pricer for the leg
2332 auto builder1 = engineFactory->builder("CMS");
2333 QL_REQUIRE(builder1, "No CMS builder found for CmsSpreadLeg");
2334 auto cmsBuilder = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricerBuilder>(builder1);
2335 auto cmsPricer = QuantLib::ext::dynamic_pointer_cast<CmsCouponPricer>(cmsBuilder->engine(
2336 IndexNameTranslator::instance().oreName(swapSpreadIndex->swapIndex1()->iborIndex()->name())));
2337 QL_REQUIRE(cmsPricer, "Expected CMS Pricer");
2338 auto builder2 = engineFactory->builder("CMSSpread");
2339 QL_REQUIRE(builder2, "No CMS Spread builder found for CmsSpreadLeg");
2340 auto cmsSpreadBuilder = QuantLib::ext::dynamic_pointer_cast<CmsSpreadCouponPricerBuilder>(builder2);
2341 auto cmsSpreadPricer = cmsSpreadBuilder->engine(swapSpreadIndex->currency(), cmsSpreadData->swapIndex1(),
2342 cmsSpreadData->swapIndex2(), cmsPricer);
2343 QL_REQUIRE(cmsSpreadPricer, "Expected CMS Spread Pricer");
2344
2345 // Loop over the coupons in the leg and set pricer
2346 Leg tmpLeg = digitalCmsSpreadLeg;
2347 QuantLib::setCouponPricer(tmpLeg, cmsSpreadPricer);
2348
2349 return tmpLeg;
2350}
2351
2352Leg makeEquityLeg(const LegData& data, const QuantLib::ext::shared_ptr<EquityIndex2>& equityCurve,
2353 const QuantLib::ext::shared_ptr<QuantExt::FxIndex>& fxIndex, const QuantLib::Date& openEndDateReplacement) {
2354 QuantLib::ext::shared_ptr<EquityLegData> eqLegData = QuantLib::ext::dynamic_pointer_cast<EquityLegData>(data.concreteLegData());
2355 QL_REQUIRE(eqLegData, "Wrong LegType, expected Equity, got " << data.legType());
2356
2357 DayCounter dc;
2358 if (data.dayCounter().empty())
2359 dc = Actual365Fixed();
2360 else
2361 dc = parseDayCounter(data.dayCounter());
2362 BusinessDayConvention bdc = parseBusinessDayConvention(data.paymentConvention());
2363
2364 Real dividendFactor = eqLegData->dividendFactor();
2365 Real initialPrice = eqLegData->initialPrice();
2366 bool initialPriceIsInTargetCcy = false;
2367
2368 if (!eqLegData->initialPriceCurrency().empty()) {
2369 // parse currencies to handle minor currencies
2370 Currency initialPriceCurrency = parseCurrencyWithMinors(eqLegData->initialPriceCurrency());
2371 Currency dataCurrency = parseCurrencyWithMinors(data.currency());
2372 Currency eqCurrency;
2373 // set equity currency
2374 if (!eqLegData->eqCurrency().empty())
2375 eqCurrency = parseCurrencyWithMinors(eqLegData->eqCurrency());
2376 else if (!equityCurve->currency().empty())
2377 eqCurrency = equityCurve->currency();
2378 else
2379 TLOG("Cannot find currency for equity " << equityCurve->name());
2380
2381 // initial price currency must match leg or equity currency
2382 QL_REQUIRE(initialPriceCurrency == dataCurrency || initialPriceCurrency == eqCurrency || eqCurrency.empty(),
2383 "initial price ccy (" << initialPriceCurrency << ") must match either leg ccy (" << dataCurrency
2384 << ") or equity ccy (if given, got '" << eqCurrency << "')");
2385 initialPriceIsInTargetCcy = initialPriceCurrency == dataCurrency;
2386 // adjust for minor currency
2387 initialPrice = convertMinorToMajorCurrency(eqLegData->initialPriceCurrency(), initialPrice);
2388 }
2389 bool notionalReset = eqLegData->notionalReset();
2390 Natural fixingDays = eqLegData->fixingDays();
2391 PaymentLag paymentLag = parsePaymentLag(data.paymentLag());
2392
2393 ScheduleBuilder scheduleBuilder;
2394
2395 ScheduleData scheduleData = data.schedule();
2396 Schedule schedule;
2397 scheduleBuilder.add(schedule, scheduleData);
2398
2399 ScheduleData valuationData = eqLegData->valuationSchedule();
2400 Schedule valuationSchedule;
2401 if (valuationData.hasData())
2402 scheduleBuilder.add(valuationSchedule, valuationData);
2403
2404 scheduleBuilder.makeSchedules(openEndDateReplacement);
2405
2406 vector<double> notionals = buildScheduledVector(data.notionals(), data.notionalDates(), schedule);
2407
2408 Calendar paymentCalendar;
2409 if (data.paymentCalendar().empty())
2410 paymentCalendar = schedule.calendar();
2411 else
2412 paymentCalendar = parseCalendar(data.paymentCalendar());
2413
2414 applyAmortization(notionals, data, schedule, false);
2415 Leg leg = EquityLeg(schedule, equityCurve, fxIndex)
2416 .withNotionals(notionals)
2417 .withQuantity(eqLegData->quantity())
2420 .withPaymentCalendar(paymentCalendar)
2421 .withPaymentLag(boost::apply_visitor(PaymentLagInteger(), paymentLag))
2422 .withReturnType(eqLegData->returnType())
2423 .withDividendFactor(dividendFactor)
2424 .withInitialPrice(initialPrice)
2425 .withInitialPriceIsInTargetCcy(initialPriceIsInTargetCcy)
2426 .withNotionalReset(notionalReset)
2427 .withFixingDays(fixingDays)
2428 .withValuationSchedule(valuationSchedule);
2429
2430 QL_REQUIRE(leg.size() > 0, "Empty Equity Leg");
2431
2432 return leg;
2433}
2434
2435Real currentNotional(const Leg& leg) {
2436 Date today = Settings::instance().evaluationDate();
2437 // assume the leg is sorted
2438 // We just take the first coupon::nominal we find, otherwise return 0
2439 for (auto cf : leg) {
2440 if (cf->date() > today) {
2441 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(cf);
2442 if (coupon)
2443 return coupon->nominal();
2444 }
2445 }
2446 return 0;
2447}
2448
2449Real originalNotional(const Leg& leg) {
2450 // assume the leg is sorted
2451 // We just take the first coupon::nominal we find, otherwise return 0
2452 if (leg.size() > 0) {
2453 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(leg.front());
2454 if (coupon)
2455 return coupon->nominal();
2456 }
2457 return 0;
2458}
2459
2460vector<double> buildAmortizationScheduleFixedAmount(const vector<double>& notionals, const Schedule& schedule,
2461 const AmortizationData& data) {
2462 DLOG("Build fixed amortization notional schedule");
2463 vector<double> nominals = normaliseToSchedule(notionals, schedule, (Real)Null<Real>());
2464 Date startDate = data.startDate().empty() ? Date::minDate() : parseDate(data.startDate());
2465 Date endDate = data.endDate().empty() ? Date::maxDate() : parseDate(data.endDate());
2466 bool underflow = data.underflow();
2467 Period amortPeriod = data.frequency().empty() ? 0 * Days : parsePeriod(data.frequency());
2468 double amort = data.value();
2469 Date lastAmortDate = Date::minDate();
2470 for (Size i = 0; i < schedule.size() - 1; i++) {
2471 if (i > 0 && (lastAmortDate == Date::minDate() || schedule[i] > lastAmortDate + amortPeriod - 4 * Days) &&
2472 schedule[i] >= startDate && schedule[i] < endDate) { // FIXME: tolerance
2473 nominals[i] = nominals[i - 1] - amort;
2474 lastAmortDate = schedule[i];
2475 } else if (i > 0 && lastAmortDate > Date::minDate()) {
2476 nominals[i] = nominals[i - 1];
2477 }
2478 if (amort > nominals[i] && underflow == false)
2479 amort = std::max(nominals[i], 0.0);
2480 }
2481 DLOG("Fixed amortization notional schedule done");
2482 return nominals;
2483}
2484
2485vector<double> buildAmortizationScheduleRelativeToInitialNotional(const vector<double>& notionals,
2486 const Schedule& schedule,
2487 const AmortizationData& data) {
2488 DLOG("Build notional schedule with amortizations expressed as percentages of initial notional");
2489 vector<double> nominals = normaliseToSchedule(notionals, schedule, (Real)Null<Real>());
2490 Date startDate = data.startDate().empty() ? Date::minDate() : parseDate(data.startDate());
2491 Date endDate = data.endDate().empty() ? Date::maxDate() : parseDate(data.endDate());
2492 bool underflow = data.underflow();
2493 Period amortPeriod = data.frequency().empty() ? 0 * Days : parsePeriod(data.frequency());
2494 double amort = data.value() * nominals.front();
2495 Date lastAmortDate = Date::minDate();
2496 for (Size i = 0; i < schedule.size() - 1; i++) {
2497 if (i > 0 && (lastAmortDate == Date::minDate() || schedule[i] > lastAmortDate + amortPeriod - 4 * Days) &&
2498 schedule[i] >= startDate && schedule[i] < endDate) { // FIXME: tolerance
2499 nominals[i] = nominals[i - 1] - amort;
2500 lastAmortDate = schedule[i];
2501 } else if (i > 0 && lastAmortDate > Date::minDate())
2502 nominals[i] = nominals[i - 1];
2503 if (amort > nominals[i] && underflow == false) {
2504 amort = std::max(nominals[i], 0.0);
2505 }
2506 }
2507 DLOG("Fixed amortization notional schedule done");
2508 return nominals;
2509}
2510
2511vector<double> buildAmortizationScheduleRelativeToPreviousNotional(const vector<double>& notionals,
2512 const Schedule& schedule,
2513 const AmortizationData& data) {
2514 DLOG("Build notional schedule with amortizations expressed as percentages of previous notionals");
2515 vector<double> nominals = normaliseToSchedule(notionals, schedule, (Real)Null<Real>());
2516 Date startDate = data.startDate().empty() ? Date::minDate() : parseDate(data.startDate());
2517 Date endDate = data.endDate().empty() ? Date::maxDate() : parseDate(data.endDate());
2518 Period amortPeriod = data.frequency().empty() ? 0 * Days : parsePeriod(data.frequency());
2519 double fraction = data.value();
2520 QL_REQUIRE(fraction < 1.0 || close_enough(fraction, 1.0),
2521 "amortization fraction " << fraction << " expected to be <= 1");
2522 Date lastAmortDate = Date::minDate();
2523 for (Size i = 0; i < schedule.size() - 1; i++) {
2524 if (i > 0 && (lastAmortDate == Date::minDate() || schedule[i] > lastAmortDate + amortPeriod - 4 * Days) &&
2525 schedule[i] >= startDate && schedule[i] < endDate) { // FIXME: tolerance
2526 nominals[i] = nominals[i - 1] * (1.0 - fraction);
2527 lastAmortDate = schedule[i];
2528 } else if (i > 0 && lastAmortDate > Date::minDate())
2529 nominals[i] = nominals[i - 1];
2530 }
2531 DLOG("Fixed amortization notional schedule done");
2532 return nominals;
2533}
2534
2535vector<double> buildAmortizationScheduleFixedAnnuity(const vector<double>& notionals, const vector<double>& rates,
2536 const Schedule& schedule, const AmortizationData& data,
2537 const DayCounter& dc) {
2538 DLOG("Build fixed annuity notional schedule");
2539 vector<double> nominals = normaliseToSchedule(notionals, schedule, (Real)Null<Real>());
2540 Date startDate = data.startDate().empty() ? Date::minDate() : parseDate(data.startDate());
2541 Date endDate = data.endDate().empty() ? Date::maxDate() : parseDate(data.endDate());
2542 bool underflow = data.underflow();
2543 double annuity = data.value();
2544 Real amort = 0.0;
2545 Date lastAmortDate = Date::minDate();
2546 for (Size i = 0; i < schedule.size() - 1; i++) {
2547 if (i > 0 && schedule[i] >= startDate && schedule[i] < endDate) {
2548 nominals[i] = nominals[i - 1] - amort;
2549 lastAmortDate = schedule[i];
2550 } else if (i > 0 && lastAmortDate > Date::minDate())
2551 nominals[i] = nominals[i - 1];
2552 Real dcf = dc.yearFraction(schedule[i], schedule[i + 1]);
2553 Real rate = i < rates.size() ? rates[i] : rates.back();
2554 amort = annuity - rate * nominals[i] * dcf;
2555 if (amort > nominals[i] && underflow == false) {
2556 amort = std::max(nominals[i], 0.0);
2557 }
2558 }
2559 DLOG("Fixed Annuity notional schedule done");
2560 return nominals;
2561}
2562
2563vector<double> buildAmortizationScheduleLinearToMaturity(const vector<double>& notionals, const Schedule& schedule,
2564 const AmortizationData& data) {
2565 DLOG("Build linear-to-maturity notional schedule");
2566 vector<double> nominals = normaliseToSchedule(notionals, schedule, (Real)Null<Real>());
2567 Date startDate = data.startDate().empty() ? Date::minDate() : parseDate(data.startDate());
2568 Date endDate = data.endDate().empty() ? Date::maxDate() : parseDate(data.endDate());
2569 Period amortPeriod = data.frequency().empty() ? 0 * Days : parsePeriod(data.frequency());
2570 Date lastAmortDate = Date::minDate();
2571 Real periodAmortization = Null<Real>();
2572 Real accumulatedAmortization = 0.0;
2573 for (Size i = 0; i < schedule.size() - 1; ++i) {
2574 if (schedule[i] >= startDate && periodAmortization == Null<Real>()) {
2575 periodAmortization = nominals[i] / static_cast<Real>(schedule.size() - i);
2576 }
2577 if (i > 0 && schedule[i] >= startDate && schedule[i] < endDate) {
2578 accumulatedAmortization += periodAmortization;
2579 }
2580 if (i > 0 && (lastAmortDate == Date::minDate() || schedule[i] > lastAmortDate + amortPeriod - 4 * Days) &&
2581 schedule[i] >= startDate && schedule[i] < endDate) {
2582 nominals[i] = nominals[i - 1] - accumulatedAmortization;
2583 accumulatedAmortization = 0.0;
2584 lastAmortDate = schedule[i];
2585 } else if (i > 0 && lastAmortDate > Date::minDate()) {
2586 nominals[i] = nominals[i - 1];
2587 }
2588 }
2589 DLOG("Linear-to-maturity notional schedule done");
2590 return nominals;
2591}
2592
2593void applyAmortization(std::vector<Real>& notionals, const LegData& data, const Schedule& schedule,
2594 const bool annuityAllowed, const std::vector<Real>& rates) {
2595 Date lastEndDate = Date::minDate();
2596 for (Size i = 0; i < data.amortizationData().size(); ++i) {
2597 const AmortizationData& amort = data.amortizationData()[i];
2598 if (!amort.initialized())
2599 continue;
2600 QL_REQUIRE(i == 0 || !amort.startDate().empty(),
2601 "All AmortizationData blocks except the first require a StartDate");
2602 Date startDate = amort.startDate().empty() ? Date::minDate() : parseDate(amort.startDate());
2603 QL_REQUIRE(startDate >= lastEndDate, "Amortization start date ("
2604 << startDate << ") is earlier than last end date (" << lastEndDate
2605 << ")");
2606 lastEndDate = amort.endDate().empty() ? Date::minDate() : parseDate(amort.endDate());
2607 AmortizationType amortizationType = parseAmortizationType(amort.type());
2608 if (amortizationType == AmortizationType::FixedAmount)
2609 notionals = buildAmortizationScheduleFixedAmount(notionals, schedule, amort);
2610 else if (amortizationType == AmortizationType::RelativeToInitialNotional)
2611 notionals = buildAmortizationScheduleRelativeToInitialNotional(notionals, schedule, amort);
2612 else if (amortizationType == AmortizationType::RelativeToPreviousNotional)
2613 notionals = buildAmortizationScheduleRelativeToPreviousNotional(notionals, schedule, amort);
2614 else if (amortizationType == AmortizationType::Annuity) {
2615 QL_REQUIRE(annuityAllowed, "Amortization type Annuity not allowed for leg type " << data.legType());
2616 if (!rates.empty())
2617 notionals = buildAmortizationScheduleFixedAnnuity(notionals, rates, schedule, amort,
2618 parseDayCounter(data.dayCounter()));
2619 } else if (amortizationType == AmortizationType::LinearToMaturity) {
2620 notionals = buildAmortizationScheduleLinearToMaturity(notionals, schedule, amort);
2621 } else {
2622 QL_FAIL("AmortizationType " << amort.type() << " not supported");
2623 }
2624 // check that for a floating leg we only have one amortization block, if the type is annuity
2625 // we recognise a floating leg by an empty (fixed) rates vector
2626 if (rates.empty() && amortizationType == AmortizationType::Annuity) {
2627 QL_REQUIRE(data.amortizationData().size() == 1,
2628 "Floating Leg supports only one amortisation block of type Annuity");
2629 }
2630 }
2631}
2632
2633void applyIndexing(Leg& leg, const LegData& data, const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory,
2634 RequiredFixings& requiredFixings, const QuantLib::Date& openEndDateReplacement,
2635 const bool useXbsCurves) {
2636 for (auto const& indexing : data.indexing()) {
2637 if (indexing.hasData()) {
2638 DLOG("apply indexing (index='" << indexing.index() << "') to leg of type " << data.legType());
2639 QL_REQUIRE(engineFactory, "applyIndexing: engineFactory required");
2640
2641 // we allow indexing by equity, commodity and FX indices (technically any QuantLib::Index
2642 // will work, so the list of index types can be extended here if required)
2643 QuantLib::ext::shared_ptr<Index> index;
2644 string config = engineFactory->configuration(MarketContext::pricing);
2645 if (boost::starts_with(indexing.index(), "EQ-")) {
2646 string eqName = indexing.index().substr(3);
2647 index = *engineFactory->market()->equityCurve(eqName, config);
2648 } else if (boost::starts_with(indexing.index(), "FX-")) {
2649 auto tmp = parseFxIndex(indexing.index());
2650 Currency ccy1 = tmp->targetCurrency();
2651 Currency ccy2 = tmp->sourceCurrency();
2652 QL_REQUIRE(ccy1.code() == data.currency() || ccy2.code() == data.currency(),
2653 "applyIndexing: fx index '" << indexing.index() << "' ccys do not match leg ccy ("
2654 << data.currency() << ")");
2655 std::string domestic = data.currency();
2656 std::string foreign = ccy1.code() == domestic ? ccy2.code() : ccy1.code();
2657 index = buildFxIndex(indexing.index(), domestic, foreign, engineFactory->market(),
2658 engineFactory->configuration(MarketContext::pricing), useXbsCurves);
2659
2660 } else if (boost::starts_with(indexing.index(), "COMM-")) {
2661 auto tmp = parseCommodityIndex(indexing.index());
2662 index = parseCommodityIndex(indexing.index(), true,
2663 engineFactory->market()->commodityPriceCurve(tmp->underlyingName(), config),
2664 tmp->fixingCalendar());
2665 } else if (boost::starts_with(indexing.index(), "BOND-")) {
2666 // if we build a bond index, we add the required fixings for the bond underlying
2667 QuantLib::ext::shared_ptr<BondIndex> bi = parseBondIndex(indexing.index());
2668 QL_REQUIRE(!(QuantLib::ext::dynamic_pointer_cast<BondFuturesIndex>(bi)),
2669 "BondFuture Legs are not yet supported");
2670 BondData bondData(bi->securityName(), 1.0);
2671 BondIndexBuilder bondIndexBuilder(bondData, indexing.indexIsDirty(), indexing.indexIsRelative(),
2672 parseCalendar(indexing.fixingCalendar()),
2673 indexing.indexIsConditionalOnSurvival(), engineFactory);
2674 index = bondIndexBuilder.bondIndex();
2675 bondIndexBuilder.addRequiredFixings(requiredFixings, leg);
2676 } else {
2677 QL_FAIL("invalid index '" << indexing.index()
2678 << "' in indexing data, expected EQ-, FX-, COMM-, BOND- index");
2679 }
2680
2681 QL_REQUIRE(index, "applyIndexing(): index is null, this is unexpected");
2682
2683 // apply the indexing
2684 IndexedCouponLeg indLeg(leg, indexing.quantity(), index);
2685 indLeg.withInitialFixing(indexing.initialFixing());
2686 // we set the initial notional fixing only if we have an initial exchange, otherwise this is applied to the
2687 // first notional payment appearing in the leg
2688 if (data.notionalInitialExchange())
2689 indLeg.withInitialNotionalFixing(indexing.initialNotionalFixing());
2690 indLeg.withFixingDays(indexing.fixingDays());
2691 indLeg.inArrearsFixing(indexing.inArrearsFixing());
2692 if (indexing.valuationSchedule().hasData())
2693 indLeg.withValuationSchedule(makeSchedule(indexing.valuationSchedule(), openEndDateReplacement));
2694 if (!indexing.fixingCalendar().empty())
2695 indLeg.withFixingCalendar(parseCalendar(indexing.fixingCalendar()));
2696 if (!indexing.fixingConvention().empty())
2697 indLeg.withFixingConvention(parseBusinessDayConvention(indexing.fixingConvention()));
2698 leg = indLeg;
2699 }
2700 }
2701}
2702
2703Leg joinLegs(const std::vector<Leg>& legs) {
2704 Leg masterLeg;
2705 Size lastLeg = Null<Size>();
2706 for (Size i = 0; i < legs.size(); ++i) {
2707 // skip empty legs
2708 if (legs[i].empty())
2709 continue;
2710 // check if the periods of adjacent legs are consistent
2711 if (lastLeg != Null<Size>()) {
2712 auto lcpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(legs[lastLeg].back());
2713 auto fcpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(legs[i].front());
2714 QL_REQUIRE(lcpn, "joinLegs: expected coupon as last cashflow in leg #" << lastLeg);
2715 QL_REQUIRE(fcpn, "joinLegs: expected coupon as first cashflow in leg #" << i);
2716 QL_REQUIRE(lcpn->accrualEndDate() == fcpn->accrualStartDate(),
2717 "joinLegs: accrual end date of last coupon in leg #"
2718 << lastLeg << " (" << lcpn->accrualEndDate()
2719 << ") is not equal to accrual start date of first coupon in leg #" << i << " ("
2720 << fcpn->accrualStartDate() << ")");
2721 lastLeg = i;
2722 }
2723 // copy legs together
2724 masterLeg.insert(masterLeg.end(), legs[i].begin(), legs[i].end());
2725 }
2726 return masterLeg;
2727}
2728
2729Leg buildNotionalLeg(const LegData& data, const Leg& leg, RequiredFixings& requiredFixings,
2730 const QuantLib::ext::shared_ptr<Market>& market, const std::string& configuration) {
2731
2732 if (!data.isNotResetXCCY()) {
2733 // If we have an FX resetting leg, add the notional amount at the start and end of each coupon period.
2734 DLOG("Building Resetting XCCY Notional leg");
2735 Real foreignNotional = data.foreignAmount();
2736
2737 QL_REQUIRE(!data.fxIndex().empty(), "buildNotionalLeg(): need fx index for fx resetting leg");
2738 auto fxIndex =
2739 buildFxIndex(data.fxIndex(), data.currency(), data.foreignCurrency(), market, configuration, true);
2740
2741 PaymentLag notionalPayLag = parsePaymentLag(data.notionalPaymentLag());
2742 Natural payLagInteger = boost::apply_visitor(PaymentLagInteger(), notionalPayLag);
2743 const Calendar& payCalendar = parseCalendar(data.paymentCalendar());
2744 const BusinessDayConvention& payConvention = parseBusinessDayConvention(data.paymentConvention());
2745
2746 Leg resettingLeg;
2747 for (Size j = 0; j < leg.size(); j++) {
2748
2749 QuantLib::ext::shared_ptr<Coupon> c = QuantLib::ext::dynamic_pointer_cast<Coupon>(leg[j]);
2750 QL_REQUIRE(c, "Expected each cashflow in FX resetting leg to be of type Coupon");
2751
2752 const Date& initFlowDate = payCalendar.advance(c->accrualStartDate(), payLagInteger, Days, payConvention);
2753 const Date& finalFlowDate = payCalendar.advance(c->accrualEndDate(), payLagInteger, Days, payConvention);
2754
2755 // Build a pair of notional flows, one at the start and one at the end of the accrual period.
2756 // They both have the same FX fixing date => same amount in this leg's currency.
2757 QuantLib::ext::shared_ptr<CashFlow> outCf;
2758 QuantLib::ext::shared_ptr<CashFlow> inCf;
2759 Date fixingDate;
2760 if (j == 0) {
2761
2762 // Two possibilities for first coupon:
2763 // 1. we have not been given a domestic notional so it is an FX linked coupon
2764 // 2. we have been given an explicit domestic notional so it is a simple cashflow
2765 if (data.notionals().size() == 0) {
2766 fixingDate = fxIndex->fixingDate(c->accrualStartDate());
2767 if (data.notionalInitialExchange()) {
2768 outCf = QuantLib::ext::make_shared<FXLinkedCashFlow>(initFlowDate, fixingDate, -foreignNotional,
2769 fxIndex);
2770 }
2771 // if there is only one period we generate the cash flow at the period end
2772 // only if there is a final notional exchange
2773 if (leg.size() > 1 || data.notionalFinalExchange()) {
2774 inCf = QuantLib::ext::make_shared<FXLinkedCashFlow>(finalFlowDate, fixingDate, foreignNotional,
2775 fxIndex);
2776 }
2777 } else {
2778 if (data.notionalInitialExchange()) {
2779 outCf = QuantLib::ext::make_shared<SimpleCashFlow>(-c->nominal(), initFlowDate);
2780 }
2781 if (leg.size() > 1 || data.notionalFinalExchange()) {
2782 inCf = QuantLib::ext::make_shared<SimpleCashFlow>(c->nominal(), finalFlowDate);
2783 }
2784 }
2785 } else {
2786 fixingDate = fxIndex->fixingDate(c->accrualStartDate());
2787 outCf =
2788 QuantLib::ext::make_shared<FXLinkedCashFlow>(initFlowDate, fixingDate, -foreignNotional, fxIndex);
2789 // we don't want a final one, unless there is notional exchange
2790 if (j < leg.size() - 1 || data.notionalFinalExchange()) {
2791 inCf =
2792 QuantLib::ext::make_shared<FXLinkedCashFlow>(finalFlowDate, fixingDate, foreignNotional, fxIndex);
2793 }
2794 }
2795
2796 // Add the cashflows to the notional leg if they have been populated
2797 if (outCf) {
2798 resettingLeg.push_back(outCf);
2799 if (fixingDate != Date())
2800 requiredFixings.addFixingDate(fixingDate, data.fxIndex(), outCf->date());
2801 }
2802 if (inCf) {
2803 resettingLeg.push_back(inCf);
2804 if (fixingDate != Date())
2805 requiredFixings.addFixingDate(fixingDate, data.fxIndex(), inCf->date());
2806 }
2807 }
2808
2809 if (data.notionalAmortizingExchange()) {
2810 QL_FAIL("Cannot have an amortizing notional with FX reset");
2811 }
2812
2813 return resettingLeg;
2814
2815 } else if ((data.notionalInitialExchange() || data.notionalFinalExchange() || data.notionalAmortizingExchange()) &&
2816 (data.legType() != "CPI")) {
2817
2818 // check for notional exchanges on non FX reseting trades
2819
2820 PaymentLag notionalPayLag = parsePaymentLag(data.notionalPaymentLag());
2821 Natural notionalPayLagInteger = boost::apply_visitor(PaymentLagInteger(), notionalPayLag);
2822
2823 return makeNotionalLeg(leg, data.notionalInitialExchange(), data.notionalFinalExchange(),
2824 data.notionalAmortizingExchange(), notionalPayLagInteger,
2825 parseBusinessDayConvention(data.paymentConvention()),
2826 parseCalendar(data.paymentCalendar()), true);
2827 } else {
2828 return Leg();
2829 }
2830}
2831
2832namespace {
2833std::string getCmbLegSecurity(const std::string& genericBond) {
2834 return genericBond.substr(0, genericBond.find_last_of('-'));
2835}
2836
2837QuantLib::ext::shared_ptr<BondReferenceDatum> getCmbLegRefData(const CMBLegData& cmbData,
2838 const QuantLib::ext::shared_ptr<ReferenceDataManager>& refData) {
2839 QL_REQUIRE(refData, "getCmbLegCreditQualifierMapping(): reference data is null");
2840 std::string security = getCmbLegSecurity(cmbData.genericBond());
2841 if (refData->hasData(ore::data::BondReferenceDatum::TYPE, security)) {
2842 auto bondRefData = QuantLib::ext::dynamic_pointer_cast<ore::data::BondReferenceDatum>(
2843 refData->getData(ore::data::BondReferenceDatum::TYPE, security));
2844 QL_REQUIRE(bondRefData != nullptr, "getCmbLegRefData(): internal error, could not cast to BondReferenceDatum");
2845 return bondRefData;
2846 }
2847 return nullptr;
2848}
2849} // namespace
2850
2851std::string getCmbLegCreditRiskCurrency(const CMBLegData& ld, const QuantLib::ext::shared_ptr<ReferenceDataManager>& refData) {
2852 if (auto bondRefData = getCmbLegRefData(ld, refData)) {
2853 std::string security = getCmbLegSecurity(ld.genericBond());
2854 BondData bd(security, 1.0);
2855 bd.populateFromBondReferenceData(bondRefData);
2856 return bd.currency();
2857 }
2858 return std::string();
2859}
2860
2861std::pair<std::string, SimmCreditQualifierMapping>
2862getCmbLegCreditQualifierMapping(const CMBLegData& ld, const QuantLib::ext::shared_ptr<ReferenceDataManager>& refData,
2863 const std::string& tradeId, const std::string& tradeType) {
2864 string source;
2866 std::string security = getCmbLegSecurity(ld.genericBond());
2867 if (auto bondRefData = getCmbLegRefData(ld, refData)) {
2868 source = ore::data::securitySpecificCreditCurveName(security, bondRefData->bondData().creditCurveId);
2869 target.targetQualifier = security;
2870 target.creditGroup = bondRefData->bondData().creditGroup;
2871 }
2872 if (source.empty() || target.targetQualifier.empty()) {
2873 ore::data::StructuredTradeErrorMessage(tradeId, tradeType, "getCmbLegCreditQualifierMapping()",
2874 "Could not set mapping for CMB Leg security '" +
2875 security +
2876 "'. Check security name and reference data.")
2877 .log();
2878 }
2879 return std::make_pair(source, target);
2880}
2881
2882} // namespace data
2883} // namespace ore
Bond trade data model and serialization.
Interface for building a bond index.
builder that returns an engine to price capped floored avg BMA legs
builder that returns an engine to price capped floored ibor legs
builder that returns an engine to price capped floored ibor legs
builder that returns an engine to price capped floored yoy inflation legs
AverageONLeg & withLastRecentPeriod(const boost::optional< Period > &lastRecentPeriod)
AverageONLeg & withPaymentDates(const std::vector< QuantLib::Date > &paymentDates)
AverageONLeg & withPaymentDayCounter(const DayCounter &dayCounter)
AverageONLeg & includeSpreadInCapFloors(bool includeSpread)
AverageONLeg & withPaymentLag(Natural lag)
AverageONLeg & withLookback(const Period &lookback)
AverageONLeg & withRateCutoff(Natural rateCutoff)
AverageONLeg & withLastRecentPeriodCalendar(const Calendar &lastRecentPeriodCalendar)
AverageONLeg & withPaymentCalendar(const Calendar &calendar)
AverageONLeg & withNakedOption(const bool nakedOption)
AverageONLeg & withLocalCapFloor(const bool localCapFloor)
AverageONLeg & withTelescopicValueDates(bool telescopicValueDates)
AverageONLeg & withPaymentAdjustment(BusinessDayConvention convention)
AverageONLeg & withCapFlooredAverageONIndexedCouponPricer(const boost::shared_ptr< CapFlooredAverageONIndexedCouponPricer > &couponPricer)
AverageONLeg & withNotionals(const std::vector< Real > &notionals)
AverageONLeg & withSpreads(const std::vector< Spread > &spreads)
AverageONLeg & withInArrears(const bool inArrears)
AverageONLeg & withCaps(Rate cap)
AverageONLeg & withFloors(Rate floor)
AverageONLeg & withFixingDays(const Size fixingDays)
AverageONLeg & withAverageONIndexedCouponPricer(const boost::shared_ptr< AverageONIndexedCouponPricer > &couponPricer)
AverageONLeg & withGearings(const std::vector< Real > &gearings)
CPILeg & withNotionals(Real notional)
CPILeg & withPaymentAdjustment(BusinessDayConvention)
CPILeg & withFinalFlowCap(Rate cap)
CPILeg & withSubtractInflationNominal(bool)
CPILeg & withFixedRates(Real fixedRate)
CPILeg & withFinalFlowFloor(Rate floor)
CPILeg & withCaps(Rate cap)
CPILeg & withPaymentDayCounter(const DayCounter &)
CPILeg & withStartDate(const Date &startDate)
CPILeg & withPaymentCalendar(const Calendar &)
CPILeg & withFloors(Rate floor)
CPILeg & withSubtractInflationNominalAllCoupons(bool subtractInflationNominalAllCoupons)
CPILeg & withObservationInterpolation(CPI::InterpolationType)
EquityLeg & withInitialPriceIsInTargetCcy(bool)
EquityLeg & withDividendFactor(Real)
EquityLeg & withPaymentCalendar(const Calendar &calendar)
EquityLeg & withFixingDays(Natural)
EquityLeg & withNotionalReset(bool)
EquityLeg & withQuantity(Real)
EquityLeg & withNotionals(const std::vector< Real > &notionals)
EquityLeg & withInitialPrice(Real)
EquityLeg & withPaymentDayCounter(const DayCounter &dayCounter)
EquityLeg & withValuationSchedule(const Schedule &valuationSchedule)
EquityLeg & withPaymentAdjustment(BusinessDayConvention convention)
EquityLeg & withPaymentLag(Natural paymentLag)
EquityLeg & withReturnType(EquityReturnType)
IndexedCouponLeg & withInitialNotionalFixing(const Real initialNotionalFixing)
IndexedCouponLeg & withFixingCalendar(const Calendar &fixingCalendar)
IndexedCouponLeg & inArrearsFixing(const bool inArrearsFixing=true)
IndexedCouponLeg & withInitialFixing(const Real initialFixing)
IndexedCouponLeg & withFixingDays(const Size fixingDays)
IndexedCouponLeg & withValuationSchedule(const Schedule &valuationSchedule)
IndexedCouponLeg & withFixingConvention(const BusinessDayConvention &fixingConvention)
NonStandardYoYInflationLeg & withPaymentAdjustment(BusinessDayConvention)
NonStandardYoYInflationLeg & withFloors(Rate floor)
NonStandardYoYInflationLeg & withFixingDays(Natural fixingDays)
NonStandardYoYInflationLeg & withRateCurve(const Handle< YieldTermStructure > &rateCurve)
NonStandardYoYInflationLeg & withSpreads(Spread spread)
NonStandardYoYInflationLeg & withPaymentDayCounter(const DayCounter &)
NonStandardYoYInflationLeg & withGearings(Real gearing)
NonStandardYoYInflationLeg & withNotionals(Real notional)
NonStandardYoYInflationLeg & withObservationInterpolation(QuantLib::CPI::InterpolationType interpolation)
NonStandardYoYInflationLeg & withCaps(Rate cap)
NonStandardYoYInflationLeg & withInflationNotional(bool addInflationNotional_)
OvernightLeg & withLookback(const Period &lookback)
OvernightLeg & withGearings(Real gearing)
OvernightLeg & withPaymentCalendar(const Calendar &)
OvernightLeg & withLastRecentPeriod(const boost::optional< Period > &lastRecentPeriod)
OvernightLeg & withFloors(Rate floor)
OvernightLeg & withCapFlooredOvernightIndexedCouponPricer(const boost::shared_ptr< CappedFlooredOvernightIndexedCouponPricer > &couponPricer)
OvernightLeg & withTelescopicValueDates(bool telescopicValueDates)
OvernightLeg & withPaymentAdjustment(BusinessDayConvention)
OvernightLeg & withNakedOption(const bool nakedOption)
OvernightLeg & withFixingDays(const Natural fixingDays)
OvernightLeg & withNotionals(Real notional)
OvernightLeg & withOvernightIndexedCouponPricer(const boost::shared_ptr< OvernightIndexedCouponPricer > &couponPricer)
OvernightLeg & withRateCutoff(const Natural rateCutoff)
OvernightLeg & withCaps(Rate cap)
OvernightLeg & withPaymentDayCounter(const DayCounter &)
OvernightLeg & withInArrears(const bool inArrears)
OvernightLeg & withSpreads(Spread spread)
OvernightLeg & withPaymentDates(const std::vector< Date > &paymentDates)
OvernightLeg & withLocalCapFloor(const bool localCapFloor)
OvernightLeg & includeSpread(bool includeSpread)
OvernightLeg & withPaymentLag(Natural lag)
OvernightLeg & withLastRecentPeriodCalendar(const Calendar &lastRecentPeriodCalendar)
SubPeriodsLeg1 & withPaymentDayCounter(const DayCounter &dayCounter)
SubPeriodsLeg1 & withType(SubPeriodsCoupon1::Type type)
SubPeriodsLeg1 & withSpreads(const std::vector< Spread > &spreads)
SubPeriodsLeg1 & includeSpread(bool includeSpread)
SubPeriodsLeg1 & withGearings(const std::vector< Real > &gearings)
SubPeriodsLeg1 & withNotionals(const std::vector< Real > &notionals)
SubPeriodsLeg1 & withPaymentAdjustment(BusinessDayConvention convention)
yoyInflationLeg & withRateCurve(const Handle< YieldTermStructure > &rateCurve)
yoyInflationLeg & withSpreads(Spread spread)
yoyInflationLeg & withFloors(Rate floor)
yoyInflationLeg & withPaymentAdjustment(BusinessDayConvention)
yoyInflationLeg & withNotionals(Real notional)
yoyInflationLeg & withGearings(Real gearing)
yoyInflationLeg & withPaymentDayCounter(const DayCounter &)
yoyInflationLeg & withCaps(Rate cap)
yoyInflationLeg & withInflationNotional(bool addInflationNotional_)
yoyInflationLeg & withFixingDays(Natural fixingDays)
Serializable object holding amortization rules.
Definition: legdata.hpp:805
const string & endDate() const
Amortization end date.
Definition: legdata.hpp:825
const string & startDate() const
Amortization start date.
Definition: legdata.hpp:823
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:698
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:710
const string & type() const
FixedAmount, RelativeToInitialNotional, RelativeToPreviousNotional, Annuity.
Definition: legdata.hpp:819
const string & currency() const
Definition: bond.hpp:94
const std::vector< LegData > & coupons() const
Definition: bond.hpp:93
void populateFromBondReferenceData(const QuantLib::ext::shared_ptr< BondReferenceDatum > &referenceDatum, const std::string &startDate="", const std::string &endDate="")
populate data from reference datum and check data for completeness
Definition: bond.cpp:175
const string & settlementDays() const
Definition: bond.hpp:88
const string & calendar() const
Definition: bond.hpp:89
Serializable Bond.
Definition: bond.hpp:153
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Trade interface.
Definition: bond.cpp:228
QuantLib::ext::shared_ptr< QuantExt::BondIndex > bondIndex() const
void addRequiredFixings(RequiredFixings &requiredFixings, Leg leg={})
static constexpr const char * TYPE
Serializable Constant Maturity Bond Yield Leg Data.
Definition: legdata.hpp:687
vector< string > gearingDates_
Definition: legdata.hpp:746
vector< double > gearings_
Definition: legdata.hpp:745
const string & genericBond() const
Definition: legdata.hpp:705
vector< double > floors_
Definition: legdata.hpp:743
vector< string > floorDates_
Definition: legdata.hpp:744
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:444
vector< double > spreads_
Definition: legdata.hpp:739
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:429
vector< string > capDates_
Definition: legdata.hpp:742
vector< double > caps_
Definition: legdata.hpp:741
vector< string > spreadDates_
Definition: legdata.hpp:740
vector< string > gearingDates_
Definition: legdata.hpp:471
vector< double > gearings_
Definition: legdata.hpp:470
vector< double > floors_
Definition: legdata.hpp:468
vector< string > floorDates_
Definition: legdata.hpp:469
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:402
vector< double > spreads_
Definition: legdata.hpp:464
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:387
vector< string > capDates_
Definition: legdata.hpp:467
vector< double > caps_
Definition: legdata.hpp:466
vector< string > spreadDates_
Definition: legdata.hpp:465
vector< string > gearingDates_
Definition: legdata.hpp:612
vector< double > gearings_
Definition: legdata.hpp:611
vector< double > floors_
Definition: legdata.hpp:609
vector< string > floorDates_
Definition: legdata.hpp:610
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:539
vector< double > spreads_
Definition: legdata.hpp:605
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:523
vector< string > capDates_
Definition: legdata.hpp:608
vector< double > caps_
Definition: legdata.hpp:607
vector< string > spreadDates_
Definition: legdata.hpp:606
vector< double > floors_
Definition: legdata.hpp:337
vector< string > floorDates_
Definition: legdata.hpp:338
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:262
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:316
vector< string > rateDates_
Definition: legdata.hpp:333
bool subtractInflationNominalCoupons_
Definition: legdata.hpp:342
vector< string > capDates_
Definition: legdata.hpp:336
vector< double > caps_
Definition: legdata.hpp:335
vector< double > rates_
Definition: legdata.hpp:332
bool subtractInflationNominal_
Definition: legdata.hpp:334
vector< string > dates_
Definition: legdata.hpp:110
void fromXML(XMLNode *node) override
Definition: legdata.cpp:94
XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:107
vector< double > amounts_
Definition: legdata.hpp:109
Position::Type callPosition_
Definition: legdata.hpp:529
vector< double > callPayoffs_
Definition: legdata.hpp:533
vector< double > callStrikes_
Definition: legdata.hpp:531
Position::Type putPosition_
Definition: legdata.hpp:536
vector< string > callStrikeDates_
Definition: legdata.hpp:532
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:494
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:473
vector< string > putPayoffDates_
Definition: legdata.hpp:541
QuantLib::ext::shared_ptr< CMSLegData > underlying_
Definition: legdata.hpp:527
vector< double > putPayoffs_
Definition: legdata.hpp:540
vector< string > putStrikeDates_
Definition: legdata.hpp:539
vector< string > callPayoffDates_
Definition: legdata.hpp:534
vector< double > putStrikes_
Definition: legdata.hpp:538
vector< string > callStrikeDates_
Definition: legdata.hpp:671
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:589
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:568
vector< string > putPayoffDates_
Definition: legdata.hpp:680
vector< string > putStrikeDates_
Definition: legdata.hpp:678
vector< string > callPayoffDates_
Definition: legdata.hpp:673
QuantLib::ext::shared_ptr< CMSSpreadLegData > underlying_
Definition: legdata.hpp:666
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
ScheduleData valuationSchedule_
Definition: legdata.hpp:797
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:618
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:665
EquityReturnType returnType_
Definition: legdata.hpp:791
EquityUnderlying equityUnderlying_
Definition: legdata.hpp:793
void fromXML(XMLNode *node) override
Definition: underlying.cpp:81
XMLNode * toXML(XMLDocument &doc) const override
Definition: underlying.cpp:102
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:113
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:119
vector< string > rateDates_
Definition: legdata.hpp:138
vector< double > rates_
Definition: legdata.hpp:137
vector< string > gearingDates_
Definition: legdata.hpp:265
std::map< QuantLib::Date, double > historicalFixings_
Definition: legdata.hpp:273
vector< double > gearings_
Definition: legdata.hpp:264
ScheduleData resetSchedule_
Definition: legdata.hpp:272
QuantLib::Size rateCutoff_
Definition: legdata.hpp:253
vector< double > floors_
Definition: legdata.hpp:262
vector< string > floorDates_
Definition: legdata.hpp:263
boost::optional< Period > lastRecentPeriod_
Definition: legdata.hpp:268
boost::optional< bool > isInArrears_
Definition: legdata.hpp:254
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:151
vector< double > spreads_
Definition: legdata.hpp:258
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:217
std::string lastRecentPeriodCalendar_
Definition: legdata.hpp:269
ScheduleData fixingSchedule_
Definition: legdata.hpp:271
QuantLib::Size fixingDays_
Definition: legdata.hpp:251
vector< string > capDates_
Definition: legdata.hpp:261
vector< double > caps_
Definition: legdata.hpp:260
QuantLib::Period lookback_
Definition: legdata.hpp:252
vector< string > spreadDates_
Definition: legdata.hpp:259
Serializable object holding indexing data.
Definition: indexing.hpp:39
void log() const
generate Boost log record to pass to corresponding sinks
Definition: log.cpp:491
std::set< std::string > indices_
Definition: legdata.hpp:77
const string & legNodeName() const
Definition: legdata.hpp:70
Serializable object holding leg data.
Definition: legdata.hpp:844
std::set< std::string > indices_
Definition: legdata.hpp:926
string notionalPaymentLag_
Definition: legdata.hpp:946
bool notionalFinalExchange_
Definition: legdata.hpp:939
vector< double > notionals_
Definition: legdata.hpp:935
LegData()
Default constructor.
Definition: legdata.hpp:847
bool indexingFromAssetLeg_
Definition: legdata.hpp:950
bool notionalInitialExchange_
Definition: legdata.hpp:938
const std::vector< Indexing > & indexing() const
Definition: legdata.hpp:894
std::vector< std::string > paymentDates_
Definition: legdata.hpp:948
virtual QuantLib::ext::shared_ptr< LegAdditionalData > initialiseConcreteLegData(const string &)
Definition: legdata.cpp:850
ScheduleData schedule_
Definition: legdata.hpp:933
QuantLib::ext::shared_ptr< LegAdditionalData > concreteLegData_
Definition: legdata.hpp:929
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:759
ScheduleData paymentSchedule_
Definition: legdata.hpp:952
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:856
double foreignAmount_
Definition: legdata.hpp:943
const string & legType() const
Definition: legdata.hpp:890
std::vector< Indexing > indexing_
Definition: legdata.hpp:949
bool strictNotionalDates_
Definition: legdata.hpp:953
std::string paymentCalendar_
Definition: legdata.hpp:947
vector< string > notionalDates_
Definition: legdata.hpp:936
string lastPeriodDayCounter_
Definition: legdata.hpp:951
string paymentConvention_
Definition: legdata.hpp:937
std::vector< AmortizationData > amortizationData_
Definition: legdata.hpp:945
bool notionalAmortizingExchange_
Definition: legdata.hpp:940
string foreignCurrency_
Definition: legdata.hpp:942
void addFixingDate(const QuantLib::Date &fixingDate, const std::string &indexName, const QuantLib::Date &payDate=Date::maxDate(), const bool alwaysAddIfPaysOnSettlement=false, const bool mandatoryFixing=true)
void makeSchedules(const QuantLib::Date &openEndDateReplacement=QuantLib::Null< QuantLib::Date >())
Definition: schedule.cpp:214
void add(QuantLib::Schedule &schedule, const ScheduleData &scheduleData)
Definition: schedule.cpp:209
Serializable schedule data.
Definition: schedule.hpp:202
bool hasData() const
Check if has any dates/rules/derived schedules.
Definition: schedule.hpp:223
virtual void fromXML(XMLNode *node) override
Definition: schedule.cpp:179
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: schedule.cpp:198
Utility class for Structured Trade errors, contains the Trade ID and Type.
const QuantLib::ext::shared_ptr< InstrumentWrapper > & instrument() const
Definition: trade.hpp:141
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
static void addChildren(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values)
Definition: xmlutils.cpp:502
static void checkNode(XMLNode *n, const string &expectedName)
Definition: xmlutils.cpp:175
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
Definition: xmlutils.cpp:428
static Real getChildValueAsDouble(XMLNode *node, const string &name, bool mandatory=false, double defaultValue=0.0)
Definition: xmlutils.cpp:286
static string getChildValue(XMLNode *node, const string &name, bool mandatory=false, const string &defaultValue=string())
Definition: xmlutils.cpp:277
static bool getChildValueAsBool(XMLNode *node, const string &name, bool mandatory=false, bool defaultValue=true)
Definition: xmlutils.cpp:296
static XMLNode * getChildNode(XMLNode *n, const string &name="")
Definition: xmlutils.cpp:387
static void addChildrenWithOptionalAttributes(XMLDocument &doc, XMLNode *n, const string &names, const string &name, const vector< T > &values, const string &attrName, const vector< string > &attrs)
Definition: xmlutils.cpp:542
static string getNodeValue(XMLNode *node)
Get a node's value.
Definition: xmlutils.cpp:489
static int getChildValueAsInt(XMLNode *node, const string &name, bool mandatory=false, int defaultValue=0)
Definition: xmlutils.cpp:291
static vector< string > getChildrenValues(XMLNode *node, const string &names, const string &name, bool mandatory=false)
Definition: xmlutils.cpp:306
static void setNodeName(XMLDocument &doc, XMLNode *node, const string &name)
Definition: xmlutils.cpp:478
static XMLNode * addChild(XMLDocument &doc, XMLNode *n, const string &name)
Definition: xmlutils.cpp:181
static void appendNode(XMLNode *parent, XMLNode *child)
Definition: xmlutils.cpp:406
vector< string > gearingDates_
Definition: legdata.hpp:398
vector< double > gearings_
Definition: legdata.hpp:397
vector< double > floors_
Definition: legdata.hpp:403
vector< string > floorDates_
Definition: legdata.hpp:404
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:342
vector< double > spreads_
Definition: legdata.hpp:399
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:369
vector< string > capDates_
Definition: legdata.hpp:402
vector< double > caps_
Definition: legdata.hpp:401
vector< string > spreadDates_
Definition: legdata.hpp:400
virtual void fromXML(XMLNode *node) override
Definition: legdata.cpp:125
virtual XMLNode * toXML(XMLDocument &doc) const override
Definition: legdata.cpp:143
builder that returns an engine to price capped floored ibor legs
builder that returns a cms spread coupon pricer
void setCouponPricer(const Leg &leg, const boost::shared_ptr< FloatingRateCouponPricer > &)
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
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.
Currency parseCurrencyWithMinors(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:310
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
string internalIndexName(const string &indexName)
QuantLib::Real convertMinorToMajorCurrency(const std::string &s, QuantLib::Real value)
Convert a value from a minor ccy to major.
Definition: parsers.cpp:324
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.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Definition: parsers.cpp:173
QuantLib::CPI::InterpolationType parseObservationInterpolation(const std::string &s)
Convert string to observation interpolation.
Definition: parsers.cpp:682
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
Compounding parseCompounding(const string &s)
Convert text to QuantLib::Compounding;.
Definition: parsers.cpp:376
PaymentLag parsePaymentLag(const string &s)
Convert text to PaymentLag.
Definition: parsers.cpp:628
Real parseReal(const string &s)
Convert text to Real.
Definition: parsers.cpp:112
void apply_permutation_in_place(std::vector< T > &vec, const std::vector< std::size_t > &p)
Definition: vectorutils.hpp:51
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
Definition: parsers.cpp:136
std::vector< std::size_t > sort_permutation(const std::vector< T > &vec, Compare &compare)
Definition: vectorutils.hpp:38
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
translates between QuantLib::Index::name() and ORE names
leg data model and serialization
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 WLOG(text)
Logging Macro (Level = Warning)
Definition: log.hpp:550
#define TLOG(text)
Logging Macro (Level = Data)
Definition: log.hpp:556
make functions for non-standard ibor and fixed legs
market data related utilties
Calendar calendar
Definition: utilities.cpp:441
QuantLib::Date fixingDate(const QuantLib::Date &d, const QuantLib::Period obsLag, const QuantLib::Frequency freq, bool interpolated)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
boost::shared_ptr< Coupon > unpackIndexedCoupon(const boost::shared_ptr< Coupon > &c)
EquityReturnType parseEquityReturnType(const std::string &str)
Leg makeOISLeg(const LegData &data, const QuantLib::ext::shared_ptr< OvernightIndex > &index, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1336
vector< T > normaliseToSchedule(const vector< T > &values, const Schedule &schedule, const T &defaultValue)
Definition: legdata.hpp:1131
vector< T > buildScheduledVectorNormalised(const vector< T > &values, const vector< string > &dates, const Schedule &schedule, const T &defaultValue, const bool checkAllValuesAppearInResult=false)
Definition: legdata.hpp:1139
Leg makeDigitalCMSLeg(const LegData &data, const QuantLib::ext::shared_ptr< QuantLib::SwapIndex > &swapIndex, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:2105
Leg makeSimpleLeg(const LegData &data)
Definition: legdata.cpp:934
vector< double > buildAmortizationScheduleLinearToMaturity(const vector< double > &notionals, const Schedule &schedule, const AmortizationData &data)
Definition: legdata.cpp:2563
vector< double > buildAmortizationScheduleFixedAmount(const vector< double > &notionals, const Schedule &schedule, const AmortizationData &data)
Definition: legdata.cpp:2460
vector< double > buildAmortizationScheduleRelativeToInitialNotional(const vector< double > &notionals, const Schedule &schedule, const AmortizationData &data)
Definition: legdata.cpp:2485
Real currentNotional(const Leg &leg)
Definition: legdata.cpp:2435
std::pair< std::string, SimmCreditQualifierMapping > getCmbLegCreditQualifierMapping(const CMBLegData &ld, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refData, const std::string &tradeId, const std::string &tradeType)
Definition: legdata.cpp:2862
void applyAmortization(std::vector< Real > &notionals, const LegData &data, const Schedule &schedule, const bool annuityAllowed, const std::vector< Real > &rates)
Definition: legdata.cpp:2593
vector< double > buildAmortizationScheduleRelativeToPreviousNotional(const vector< double > &notionals, const Schedule &schedule, const AmortizationData &data)
Definition: legdata.cpp:2511
void applyIndexing(Leg &leg, const LegData &data, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, RequiredFixings &requiredFixings, const QuantLib::Date &openEndDateReplacement, const bool useXbsCurves)
Definition: legdata.cpp:2633
Leg makeBMALeg(const LegData &data, const QuantLib::ext::shared_ptr< QuantExt::BMAIndexWrapper > &indexWrapper, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1493
Size size(const ValueType &v)
Definition: value.cpp:145
vector< double > buildAmortizationScheduleFixedAnnuity(const vector< double > &notionals, const vector< double > &rates, const Schedule &schedule, const AmortizationData &data, const DayCounter &dc)
Definition: legdata.cpp:2535
Leg buildNotionalLeg(const LegData &data, const Leg &leg, RequiredFixings &requiredFixings, const QuantLib::ext::shared_ptr< Market > &market, const std::string &configuration)
Definition: legdata.cpp:2729
Real originalNotional(const Leg &leg)
Definition: legdata.cpp:2449
Leg makeCMBLeg(const LegData &data, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1984
Leg makeYoYLeg(const LegData &data, const QuantLib::ext::shared_ptr< InflationIndex > &index, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1766
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
vector< T > buildScheduledVector(const vector< T > &values, const vector< string > &dates, const Schedule &schedule, const bool checkAllValuesAppearInResult=false)
Definition: legdata.hpp:1061
Leg makeCMSSpreadLeg(const LegData &data, const QuantLib::ext::shared_ptr< QuantLib::SwapSpreadIndex > &swapSpreadIndex, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:2187
Leg makeDigitalCMSSpreadLeg(const LegData &data, const QuantLib::ext::shared_ptr< QuantLib::SwapSpreadIndex > &swapSpreadIndex, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:2260
Leg makeCPILeg(const LegData &data, const QuantLib::ext::shared_ptr< ZeroInflationIndex > &index, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1616
Leg makeCMSLeg(const LegData &data, const QuantLib::ext::shared_ptr< QuantLib::SwapIndex > &swapIndex, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1919
AmortizationType parseAmortizationType(const std::string &s)
Definition: parsers.cpp:651
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > parseCommodityIndex(const string &name, bool hasPrefix, const Handle< PriceTermStructure > &ts, const Calendar &cal, const bool enforceFutureIndex)
Leg makeEquityLeg(const LegData &data, const QuantLib::ext::shared_ptr< EquityIndex2 > &equityCurve, const QuantLib::ext::shared_ptr< QuantExt::FxIndex > &fxIndex, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:2352
std::string getCmbLegCreditRiskCurrency(const CMBLegData &ld, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refData)
Definition: legdata.cpp:2851
Leg makeZCFixedLeg(const LegData &data, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1049
Leg makeIborLeg(const LegData &data, const QuantLib::ext::shared_ptr< IborIndex > &index, const QuantLib::ext::shared_ptr< EngineFactory > &engineFactory, const bool attachPricer, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:1102
bool lessThan(const string &s1, const string &s2)
Definition: legdata.cpp:92
Leg makeFixedLeg(const LegData &data, const QuantLib::Date &openEndDateReplacement)
Definition: legdata.cpp:950
boost::variant< QuantLib::Period, QuantLib::Natural > PaymentLag
Definition: types.hpp:32
Leg makeNotionalLeg(const Leg &refLeg, const bool initNomFlow, const bool finalNomFlow, const bool amortNomFlow, const Natural notionalPaymentLag, const BusinessDayConvention paymentConvention, const Calendar paymentCalendar, const bool excludeIndexing)
Definition: legdata.cpp:1566
QuantLib::ext::shared_ptr< QuantExt::FxIndex > buildFxIndex(const string &fxIndex, const string &domestic, const string &foreign, const QuantLib::ext::shared_ptr< Market > &market, const string &configuration, bool useXbsCurves)
Definition: marketdata.cpp:137
Leg joinLegs(const std::vector< Leg > &legs)
Definition: legdata.cpp:2703
Leg makeNonStandardIborLeg(const QuantLib::ext::shared_ptr< IborIndex > &index, const std::vector< Date > &calcDates, const std::vector< Date > &payDatesInput, const std::vector< Date > &fixingDatesInput, const std::vector< Date > &resetDatesInput, const Size fixingDays, const std::vector< Real > &notionals, const std::vector< Date > &notionalDatesInput, const std::vector< Real > &spreadsInput, const std::vector< Date > &spreadDatesInput, const std::vector< Real > &gearingsInput, const std::vector< Date > &gearingDatesInput, const bool strictNotionalDates, const DayCounter &dayCounter, const Calendar &payCalendar, const BusinessDayConvention payConv, const Period &payLag, const bool isInArrears)
std::string securitySpecificCreditCurveName(const std::string &securityId, const std::string &creditCurveId)
Definition: marketdata.cpp:79
Schedule makeSchedule(const ScheduleDates &data)
Definition: schedule.cpp:263
Leg makeNonStandardFixedLeg(const std::vector< Date > &calcDates, const std::vector< Date > &payDatesInput, const std::vector< Real > &notionals, const std::vector< Date > &notionalDatesInput, const std::vector< Real > &rates, const std::vector< Date > &rateDatesInput, const bool strictNotionalDates, const DayCounter &dayCounter, const Calendar &payCalendar, const BusinessDayConvention payConv, const Period &payLag)
AmortizationType
Definition: parsers.hpp:346
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Reference data model and serialization.
Structured Trade Error class.
string conversion utilities
payment lag
Utilities for sorting vectors using permutations.