Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
trswrapper.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
21
23
25
26#include <ql/cashflows/cashflows.hpp>
27#include <ql/cashflows/fixedratecoupon.hpp>
28#include <ql/currencies/exchangeratemanager.hpp>
31namespace ore {
32namespace data {
33
34using namespace QuantLib;
35using namespace QuantExt;
36
38 const std::vector<QuantLib::ext::shared_ptr<ore::data::Trade>>& underlying,
39 const std::vector<QuantLib::ext::shared_ptr<Index>>& underlyingIndex, const std::vector<Real> underlyingMultiplier,
40 const bool includeUnderlyingCashflowsInReturn, const Real initialPrice, const Currency& initialPriceCurrency,
41 const std::vector<Currency>& assetCurrency, const Currency& returnCurrency,
42 const std::vector<Date>& valuationSchedule, const std::vector<Date>& paymentSchedule,
43 const std::vector<Leg>& fundingLegs, const std::vector<TRS::FundingData::NotionalType>& fundingNotionalTypes,
44 const Currency& fundingCurrency, const Size fundingResetGracePeriod, const bool paysAsset, const bool paysFunding,
45 const Leg& additionalCashflowLeg, const bool additionalCashflowLegPayer, const Currency& additionalCashflowCurrency,
46 const std::vector<QuantLib::ext::shared_ptr<FxIndex>>& fxIndexAsset, const QuantLib::ext::shared_ptr<FxIndex>& fxIndexReturn,
47 const QuantLib::ext::shared_ptr<FxIndex>& fxIndexAdditionalCashflows,
48 const std::map<std::string, QuantLib::ext::shared_ptr<QuantExt::FxIndex>>& addFxIndices)
49 : underlying_(underlying), underlyingIndex_(underlyingIndex), underlyingMultiplier_(underlyingMultiplier),
50 includeUnderlyingCashflowsInReturn_(includeUnderlyingCashflowsInReturn), initialPrice_(initialPrice),
51 initialPriceCurrency_(initialPriceCurrency), assetCurrency_(assetCurrency), returnCurrency_(returnCurrency),
52 valuationSchedule_(valuationSchedule), paymentSchedule_(paymentSchedule), fundingLegs_(fundingLegs),
53 fundingNotionalTypes_(fundingNotionalTypes), fundingCurrency_(fundingCurrency),
54 fundingResetGracePeriod_(fundingResetGracePeriod), paysAsset_(paysAsset), paysFunding_(paysFunding),
55 additionalCashflowLeg_(additionalCashflowLeg), additionalCashflowLegPayer_(additionalCashflowLegPayer),
56 additionalCashflowCurrency_(additionalCashflowCurrency), fxIndexAsset_(fxIndexAsset),
57 fxIndexReturn_(fxIndexReturn), fxIndexAdditionalCashflows_(fxIndexAdditionalCashflows),
58 addFxIndices_(addFxIndices) {
59
60 QL_REQUIRE(!paymentSchedule_.empty(), "TRSWrapper::TRSWrapper(): payment schedule must not be empty()");
61
62 QL_REQUIRE(valuationSchedule_.size() == paymentSchedule_.size() + 1,
63 "TRSWrapper::TRSWrapper(): valuation schedule size ("
64 << valuationSchedule_.size() << ") must be payment schedule size (" << paymentSchedule_.size()
65 << ") plus one");
66
67 for (Size i = 0; i < valuationSchedule_.size() - 1; ++i) {
68 QL_REQUIRE(valuationSchedule_[i] < valuationSchedule_[i + 1],
69 "TRSWrapper::TRSWrapper(): valuation schedule dates must be monotonic, at "
70 << i << ": " << valuationSchedule_[i] << ", " << valuationSchedule_[i + 1]);
71 }
72
73 for (Size i = 0; i < paymentSchedule_.size() - 1; ++i) {
74 QL_REQUIRE(paymentSchedule_[i] < paymentSchedule_[i + 1],
75 "TRSWrapper::TRSWrapper(): payment schedule dates must be monotonic, at "
76 << i << ": " << paymentSchedule_[i] << ", " << paymentSchedule_[i + 1]);
77 }
78
79 for (Size i = 0; i < paymentSchedule_.size(); ++i) {
80 QL_REQUIRE(paymentSchedule_[i] >= valuationSchedule_[i + 1], "TRSWrapper::TRSWrapper(): payment date at "
81 << i << " (" << paymentSchedule_[i]
82 << ") must be >= valuation date ("
83 << valuationSchedule_[i + 1]);
84 }
85
86 QL_REQUIRE(fundingLegs_.size() == fundingNotionalTypes_.size(), "TRSWrapper::TRSWrapper(): number of funding legs ("
87 << fundingLegs_.size()
88 << ") must match funding notitional types ("
89 << fundingNotionalTypes_.size() << ")");
90
91 QL_REQUIRE(!underlying_.empty(), "TRSWrapper::TRSWrapper(): no underlying given, at least one is required");
92 QL_REQUIRE(underlying.size() == underlyingIndex.size(),
93 "TRSWrapper::TRSWrapper(): number of underlyings ("
94 << underlying.size() << ") does not match underlying index size (" << underlyingIndex.size() << ")");
95 QL_REQUIRE(underlying.size() == underlyingMultiplier.size(), "TRSWrapper::TRSWrapper(): number of underlyings ("
96 << underlying.size()
97 << ") does not match underlying index size ("
98 << underlyingMultiplier.size() << ")");
99 QL_REQUIRE(underlying.size() == assetCurrency.size(),
100 "TRSWrapper::TRSWrapper(): number of underlyings ("
101 << underlying.size() << ") does not match asset currency size (" << assetCurrency.size() << ")");
102 QL_REQUIRE(underlying.size() == fxIndexAsset.size(),
103 "TRSWrapper::TRSWrapper(): number of underlyings ("
104 << underlying.size() << ") does not match fx index asset size (" << fxIndexAsset.size() << ")");
105
106 for (Size i = 0; i < underlying_.size(); ++i) {
107 registerWith(underlying_[i]->instrument()->qlInstrument());
108 registerWith(underlyingIndex_[i]);
109 }
110
111 for (Size i = 0; i < fundingLegs_.size(); ++i) {
112 for (Size j = 0; j < fundingLegs_[i].size(); ++j) {
113 registerWith(fundingLegs_[i][j]);
114 }
115 }
116
117 for (auto const& f : fxIndexAsset)
118 registerWith(f);
119 registerWith(fxIndexReturn);
120 registerWith(fxIndexAdditionalCashflows);
121
122 // compute last payment date, after this date the TRS is considered expired
123
124 lastDate_ = Date::minDate();
125 for (auto const& d : paymentSchedule_)
126 lastDate_ = std::max(lastDate_, d);
127 for (auto const& l : fundingLegs_)
128 for (auto const& c : l)
129 lastDate_ = std::max(lastDate_, c->date());
130 for (auto const& c : additionalCashflowLeg_)
131 lastDate_ = std::max(lastDate_, c->date());
132}
133
134bool TRSWrapper::isExpired() const { return detail::simple_event(lastDate_).hasOccurred(); }
135
137 TRSWrapper::arguments* a = dynamic_cast<TRSWrapper::arguments*>(args);
138 QL_REQUIRE(a != nullptr, "wrong argument type in TRSWrapper");
162}
163
165 QL_REQUIRE(!initialPriceCurrency_.empty(), "empty initial price currency");
166 for (auto const& a : assetCurrency_)
167 QL_REQUIRE(!a.empty(), "empty asset currency");
168 QL_REQUIRE(!returnCurrency_.empty(), "empty return currency");
169 QL_REQUIRE(!fundingCurrency_.empty(), "empty funding currency");
170}
171
172void TRSWrapper::fetchResults(const PricingEngine::results* r) const { Instrument::fetchResults(r); }
173
174bool TRSWrapperAccrualEngine::computeStartValue(std::vector<Real>& underlyingStartValue,
175 std::vector<Real>& fxConversionFactor, QuantLib::Date& startDate,
176 QuantLib::Date& endDate, bool& usingInitialPrice,
177 const Size nth) const {
178 Date today = Settings::instance().evaluationDate();
179 Size payIdx =
180 std::distance(arguments_.paymentSchedule_.begin(),
181 std::upper_bound(arguments_.paymentSchedule_.begin(), arguments_.paymentSchedule_.end(), today)) +
182 nth;
183 Date v0 = payIdx < arguments_.valuationSchedule_.size() ? arguments_.valuationSchedule_[payIdx] : Date::maxDate();
184 Date v1 =
185 payIdx < arguments_.valuationSchedule_.size() - 1 ? arguments_.valuationSchedule_[payIdx + 1] : Date::maxDate();
186
187 /* Check whether there is a "nth" current valuation period, nth > 0. */
188 if (nth > 0 && (payIdx >= arguments_.paymentSchedule_.size() || v0 > today))
189 return false;
190
191 std::fill(underlyingStartValue.begin(), underlyingStartValue.end(), 0.0);
192 std::fill(fxConversionFactor.begin(), fxConversionFactor.end(), 1.0);
193 startDate = Null<Date>();
194 endDate = Null<Date>();
195 usingInitialPrice = false;
196
197 for (Size i = 0; i < arguments_.underlying_.size(); ++i) {
198 if (payIdx < arguments_.paymentSchedule_.size()) {
199 if (v0 > today) {
200 // The start valuation date is > today: we return null, except an initial price is given, in which case
201 // we return this price (possibly converted with todays FX rate to return ccy). This allows for a
202 // reasonable asset leg npv estimation, which would otherwise be zero and jump to its actual value on v0
203 // + 1. Internal consistency check: make sure that v0 is the initial date of the valuation schedule
204 QL_REQUIRE(payIdx == 0, "TRSWrapper: internal error, expected valuation date "
205 << v0 << " for pay date = " << arguments_.paymentSchedule_[payIdx]
206 << " to be the first valuation date, since it is > today (" << today
207 << ")");
208 if (nth == 0 && arguments_.initialPrice_ != Null<Real>()) {
209 if (i == 0) {
210 Real s0 =
211 arguments_.initialPrice_ *
212 (arguments_.underlyingMultiplier_.size() == 1 ? arguments_.underlyingMultiplier_[i] : 1.0);
213 Real fx0 = getFxConversionRate(today, arguments_.initialPriceCurrency_,
214 arguments_.returnCurrency_, false);
215 DLOG("start value (underlying "
216 << std::to_string(i + 1) << "): s0=" << s0 << " (from fixed initial price), fx0=" << fx0
217 << " => " << fx0 * s0 << " on today (valuation start date is " << v0 << ")");
218 underlyingStartValue[i] = s0;
219 fxConversionFactor[i] = fx0;
220 startDate = v0;
221 if(v1 <= today)
222 endDate = v1;
223 usingInitialPrice = true;
224 } else {
225 underlyingStartValue[i] = 0.0;
226 fxConversionFactor[i] = 1.0;
227 }
228 } else {
229 DLOG("start value (underlying " << std::to_string(i + 1) << ") is null, because eval date ("
230 << today << ") is <= start valuation date (" << v0
231 << ") for nth current period " << nth
232 << " and no intiial price is given");
233 underlyingStartValue[i] = Null<Real>();
234 fxConversionFactor[i] = Null<Real>();
235 startDate = Null<Date>();
236 }
237 } else {
238 // The start valuation date is <= today, we determine the start value from the initial price or a
239 // historical fixing
240 Real s0 = 0.0, fx0 = 1.0;
241 if (nth == 0 && arguments_.initialPrice_ != Null<Real>() &&
242 v0 == arguments_.valuationSchedule_.front()) {
243 if (i == 0) {
244 DLOG("initial price is given as " << arguments_.initialPrice_ << " "
245 << arguments_.initialPriceCurrency_);
246 s0 = arguments_.initialPrice_ *
247 (arguments_.underlying_.size() == 1 ? arguments_.underlyingMultiplier_[i] : 1.0);
248 fx0 = getFxConversionRate(v0, arguments_.initialPriceCurrency_, arguments_.returnCurrency_,
249 false);
250 usingInitialPrice = true;
251 }
252 } else {
253 s0 = getUnderlyingFixing(i, v0, false) * arguments_.underlyingMultiplier_[i];
254 fx0 = getFxConversionRate(v0, arguments_.assetCurrency_[i], arguments_.returnCurrency_, false);
255 }
256 DLOG("start value (underlying " << std::to_string(i + 1) << "): s0=" << s0 << " fx0=" << fx0 << " => "
257 << fx0 * s0 << " on " << v0 << " in nth current period " << nth);
258 underlyingStartValue[i] = s0;
259 fxConversionFactor[i] = fx0;
260 startDate = v0;
261 if(v1 <= today)
262 endDate = v1;
263 }
264 } else {
265 // we are beyond the last date in the payment schedule => return null
266 DLOG("start value (underlying " << std::to_string(i + 1) << ") is null, because eval date (" << today
267 << ") is >= last date in payment schedule ("
268 << arguments_.paymentSchedule_.back() << ") in nth current period " << nth);
269 underlyingStartValue[i] = Null<Real>();
270 fxConversionFactor[i] = Null<Real>();
271 startDate = Null<Date>();
272 }
273 } // loop over underlyings
274
275 return true;
276}
277
278namespace {
279Real getFxIndexFixing(const QuantLib::ext::shared_ptr<FxIndex>& fx, const Currency& source, const Date& d,
280 const bool enforceProjection) {
281 bool invert = fx->targetCurrency() == source;
282 Real res;
283 if (enforceProjection) {
284 res = fx->forecastFixing(0.0);
285 } else {
286 Date adjustedDate = fx->fixingCalendar().adjust(d, Preceding);
287 res = fx->fixing(adjustedDate, false);
288 }
289 return invert ? 1.0 / res : res;
290}
291} // namespace
292
293Real TRSWrapperAccrualEngine::getFxConversionRate(const Date& date, const Currency& source, const Currency& target,
294 const bool enforceProjection) const {
295
296 if (source == target)
297 return 1.0;
298
299 Real result1 = 1.0;
300 if (source != arguments_.fundingCurrency_) {
301 bool found = false;
302 for (Size i = 0; i < arguments_.fxIndexAsset_.size(); ++i) {
303 if (arguments_.fxIndexAsset_[i] == nullptr)
304 continue;
305 if (source == arguments_.fxIndexAsset_[i]->sourceCurrency() ||
306 source == arguments_.fxIndexAsset_[i]->targetCurrency()) {
307 result1 = getFxIndexFixing(arguments_.fxIndexAsset_[i], source, date, enforceProjection);
308 found = true;
309 }
310 }
311 if (!found) {
312 if (arguments_.fxIndexReturn_ != nullptr && (source == arguments_.fxIndexReturn_->sourceCurrency() ||
313 source == arguments_.fxIndexReturn_->targetCurrency())) {
314 result1 = getFxIndexFixing(arguments_.fxIndexReturn_, source, date, enforceProjection);
315 } else if (arguments_.fxIndexAdditionalCashflows_ != nullptr &&
316 (source == arguments_.fxIndexAdditionalCashflows_->sourceCurrency() ||
317 source == arguments_.fxIndexAdditionalCashflows_->targetCurrency())) {
318 result1 = getFxIndexFixing(arguments_.fxIndexAdditionalCashflows_, source, date, enforceProjection);
319 } else {
320 QL_FAIL("TRSWrapperAccrualEngine: could not convert " << source.code() << " to funding currency "
321 << arguments_.fundingCurrency_
322 << ", are all required FXTerms set up?");
323 }
324 }
325 }
326
327 Real result2 = 1.0;
328 if (target != arguments_.fundingCurrency_) {
329 bool found = false;
330 for (Size i = 0; i < arguments_.fxIndexAsset_.size(); ++i) {
331 if (arguments_.fxIndexAsset_[i] == nullptr)
332 continue;
333 if (target == arguments_.fxIndexAsset_[i]->sourceCurrency() ||
334 target == arguments_.fxIndexAsset_[i]->targetCurrency()) {
335 result2 = getFxIndexFixing(arguments_.fxIndexAsset_[i], target, date, enforceProjection);
336 found = true;
337 }
338 }
339 if (!found) {
340 if (arguments_.fxIndexReturn_ != nullptr && (target == arguments_.fxIndexReturn_->sourceCurrency() ||
341 target == arguments_.fxIndexReturn_->targetCurrency())) {
342 result2 = getFxIndexFixing(arguments_.fxIndexReturn_, target, date, enforceProjection);
343 } else if (arguments_.fxIndexAdditionalCashflows_ != nullptr &&
344 (target == arguments_.fxIndexAdditionalCashflows_->sourceCurrency() ||
345 target == arguments_.fxIndexAdditionalCashflows_->targetCurrency())) {
346 result2 = getFxIndexFixing(arguments_.fxIndexAdditionalCashflows_, target, date, enforceProjection);
347 } else {
348 QL_FAIL("TRSWrapperAccrualEngine: could not convert " << source.code() << " to funding currency "
349 << arguments_.fundingCurrency_
350 << ", are all required FXTerms set up?");
351 }
352 }
353 }
354
355 return result1 / result2;
356}
357
358Real TRSWrapperAccrualEngine::getUnderlyingFixing(const Size i, const Date& date, const bool enforceProjection) const {
359 Date today = Settings::instance().evaluationDate();
360 QL_REQUIRE(date <= today, "TRSWrapperAccrualEngine: internal error, getUnderlyingFixing("
361 << date << ") for future date requested (today=" << today << ")");
362 if (enforceProjection) {
363 return arguments_.underlying_[i]->instrument()->NPV() / arguments_.underlyingMultiplier_[i];
364 }
365 Date adjustedDate = arguments_.underlyingIndex_[i]->fixingCalendar().adjust(date, Preceding);
366 try {
367 auto tmp = arguments_.underlyingIndex_[i]->fixing(adjustedDate);
368 return tmp;
369 } catch (const std::exception&) {
370 if (adjustedDate == today)
371 return arguments_.underlying_[i]->instrument()->NPV() / arguments_.underlyingMultiplier_[i];
372 else
373 throw;
374 }
375}
376
378
379 Date today = Settings::instance().evaluationDate();
380
381 DLOG("TRSWrapperAccrualEngine: today = " << today << ", paysAsset = " << std::boolalpha << arguments_.paysAsset_
382 << ", paysFunding = " << std::boolalpha << arguments_.paysFunding_);
383
384 Real assetMultiplier = (arguments_.paysAsset_ ? -1.0 : 1.0);
385 Real fundingMultiplier = (arguments_.paysFunding_ ? -1.0 : 1.0);
386
387 results_.additionalResults["returnCurrency"] = arguments_.returnCurrency_.code();
388 results_.additionalResults["fundingCurrency"] = arguments_.fundingCurrency_.code();
389 results_.additionalResults["returnLegInitialPrice"] = arguments_.initialPrice_;
390 results_.additionalResults["returnLegInitialPriceCurrency"] = arguments_.initialPriceCurrency_.code();
391
392 // asset leg valuation (accrual method)
393
394 Real assetLegNpv = 0.0;
395 Size nthCurrentPeriod = 0;
396 std::vector<CashFlowResults> cfResults;
397
398 std::vector<Real> underlyingStartValue(arguments_.underlying_.size(), 0.0);
399 std::vector<Real> fxConversionFactor(arguments_.underlying_.size(), 1.0);
400 Date startDate = Null<Date>();
401 Date endDate = Null<Date>();
402 bool usingInitialPrice;
403
404 while (computeStartValue(underlyingStartValue, fxConversionFactor, startDate, endDate, usingInitialPrice,
405 nthCurrentPeriod)) {
406
407 // vector holding cashflow results, we store these as an additional result
408
409 for (Size i = 0; i < arguments_.underlying_.size(); ++i) {
410
411 std::string resultSuffix = arguments_.underlying_.size() > 1 ? "_" + std::to_string(i + 1) : "";
412 if (nthCurrentPeriod > 0)
413 resultSuffix += "_nth(" + std::to_string(nthCurrentPeriod) + ")";
414
415 results_.additionalResults["underlyingCurrency" + resultSuffix] = arguments_.assetCurrency_[i].code();
416
417 if (underlyingStartValue[i] != Null<Real>()) {
418 Real s1, fx1;
419 if (endDate == Null<Date>()) {
420 s1 = arguments_.underlying_[i]->instrument()->NPV();
421 fx1 = getFxConversionRate(today, arguments_.assetCurrency_[i], arguments_.returnCurrency_, true);
422 } else {
423 s1 = getUnderlyingFixing(i, endDate, false) * arguments_.underlyingMultiplier_[i];
424 fx1 = getFxConversionRate(endDate, arguments_.assetCurrency_[i], arguments_.returnCurrency_, false);
425 }
426 assetLegNpv += fx1 * s1 - underlyingStartValue[i] * fxConversionFactor[i];
427 DLOG("end value (underlying " << std::to_string(i + 1) << "): s1=" << s1 << " fx1=" << fx1 << " => "
428 << fx1 * s1 << " on "
429 << io::iso_date(endDate == Null<Date>() ? today : endDate));
430
431 // add details return leg valuation to additional results
432 results_.additionalResults["s0" + resultSuffix] = underlyingStartValue[i];
433 results_.additionalResults["fx0" + resultSuffix] = fxConversionFactor[i];
434 results_.additionalResults["s1" + resultSuffix] = s1;
435 results_.additionalResults["fx1" + resultSuffix] = fx1;
436 results_.additionalResults["underlyingMultiplier" + resultSuffix] = arguments_.underlyingMultiplier_[i];
437
438 // add return cashflow to additional results
439 cfResults.emplace_back();
440 cfResults.back().amount = fx1 * s1;
441 if (arguments_.underlying_.size() == 1 || !usingInitialPrice) {
442 cfResults.back().amount -= underlyingStartValue[i] * fxConversionFactor[i];
443 }
444 cfResults.back().amount *= assetMultiplier;
445 cfResults.back().payDate = today;
446 cfResults.back().currency = arguments_.returnCurrency_.code();
447 cfResults.back().legNumber = 0;
448 cfResults.back().type = "AccruedReturn" + resultSuffix;
449 cfResults.back().accrualStartDate = startDate;
450 cfResults.back().accrualEndDate = endDate == Null<Date>() ? today : endDate;
451 cfResults.back().fixingValue = s1 / arguments_.underlyingMultiplier_[i];
452 cfResults.back().notional = underlyingStartValue[i] * fxConversionFactor[i];
453
454 // if initial price is used and there is more than one underlying, add cf for initialPrice
455 if (arguments_.underlying_.size() > 1 && usingInitialPrice && i == 0) {
456 cfResults.emplace_back();
457 cfResults.back().amount = -underlyingStartValue[i] * fxConversionFactor[i];
458 cfResults.back().payDate = today;
459 cfResults.back().currency = arguments_.returnCurrency_.code();
460 cfResults.back().legNumber = 0;
461 cfResults.back().type = "AccruedReturn" + resultSuffix;
462 cfResults.back().accrualStartDate = startDate;
463 cfResults.back().accrualEndDate = endDate == Null<Date>() ? today : endDate;
464 cfResults.back().notional = underlyingStartValue[i] * fxConversionFactor[i];
465 }
466
467 // startDate might be >= today, if an initial price is given, see the comment in startValue() above
468 if (arguments_.includeUnderlyingCashflowsInReturn_ && startDate != Null<Date>() && startDate < today) {
469 // add cashflows in return period
470 Real cf = 0.0;
471 for (auto const& l : arguments_.underlying_[i]->legs()) {
472 for (auto const& c : l) {
473 if (!c->hasOccurred(startDate) && c->hasOccurred(today)) {
474 Real tmp = c->amount() * arguments_.underlyingMultiplier_[i];
475 cf += tmp;
476 // add intermediate cashflows to additional results
477 cfResults.emplace_back();
478 cfResults.back().amount = assetMultiplier * (tmp * fx1);
479 cfResults.back().payDate = c->date();
480 cfResults.back().currency = arguments_.returnCurrency_.code();
481 cfResults.back().legNumber = 1;
482 cfResults.back().type = "UnderlyingCashFlow" + resultSuffix;
483 cfResults.back().notional = underlyingStartValue[i] * fxConversionFactor[i];
484 }
485 }
486 }
487 // account for dividends
488 Real dividends = 0.0;
489 if (auto e = QuantLib::ext::dynamic_pointer_cast<EquityIndex2>(arguments_.underlyingIndex_[i])) {
490 dividends +=
491 e->dividendsBetweenDates(startDate + 1, today) * arguments_.underlyingMultiplier_[i];
492 } else if (auto e = QuantLib::ext::dynamic_pointer_cast<CompositeIndex>(arguments_.underlyingIndex_[i])) {
493 dividends +=
494 e->dividendsBetweenDates(startDate + 1, today) * arguments_.underlyingMultiplier_[i];
495 }
496 cf += dividends;
497 if (!close_enough(dividends, 0.0)) {
498 // add dividends as one cashflow to additional results
499 cfResults.emplace_back();
500 cfResults.back().amount = assetMultiplier * (dividends * fx1);
501 cfResults.back().payDate = today;
502 cfResults.back().currency = arguments_.returnCurrency_.code();
503 cfResults.back().legNumber = 2;
504 cfResults.back().type = "UnderlyingDividends" + resultSuffix;
505 cfResults.back().notional = underlyingStartValue[i] * fxConversionFactor[i];
506 }
507
508 DLOG("add cashflows in return period (" << io::iso_date(startDate) << ", " << io::iso_date(today)
509 << "]: amount in asset ccy = " << cf << ", fx conversion "
510 << fx1 << " => " << cf * fx1);
511
512 results_.additionalResults["underlyingCashflows" + resultSuffix] = cf;
513
514 assetLegNpv += cf * fx1;
515 }
516 }
517 } // loop over underlyings
518
519 ++nthCurrentPeriod;
520 } // loop over nth current period
521
522 results_.additionalResults["assetLegNpv"] = assetMultiplier * assetLegNpv;
523 results_.additionalResults["assetLegNpvCurency"] = arguments_.returnCurrency_.code();
524 DLOG("asset leg npv = " << assetMultiplier * assetLegNpv << " " << arguments_.returnCurrency_.code());
525
526 // funding leg valuation (accrual method)
527
528 Real fundingLegNpv = 0.0;
529
530 for (Size i = 0; i < arguments_.fundingLegs_.size(); ++i) {
531
532 Size nthCpn = 0;
533 for (Size cpnNo = 0; cpnNo < arguments_.fundingLegs_[i].size(); ++cpnNo) {
534
535 Real localFundingLegNpv = 0.0; // local per funding coupon
536
537 auto cpn = QuantLib::ext::dynamic_pointer_cast<QuantLib::Coupon>(arguments_.fundingLegs_[i][cpnNo]);
538 if (cpn == nullptr || cpn->date() <= today || cpn->accrualStartDate() >= today)
539 continue;
540
541 // look up latest valuation date <= funding start date, fall back to first valuation date, if no such
542 // date exists
543 Date fundingStartDate = cpn->accrualStartDate();
544 Real fundingCouponNotional = cpn->nominal();
545 Size currentIdx = std::distance(arguments_.valuationSchedule_.begin(),
546 std::upper_bound(arguments_.valuationSchedule_.begin(),
547 arguments_.valuationSchedule_.end(),
548 fundingStartDate + arguments_.fundingResetGracePeriod_));
549 if (currentIdx > 0)
550 --currentIdx;
551
552 if (arguments_.valuationSchedule_[currentIdx] > today) {
553 DLOG("fundingLegNpv = 0 for funding leg #" << (i + 1) << ", because last relevant valuation date ("
554 << arguments_.valuationSchedule_[currentIdx]
555 << ") is >= eval date (" << today << ")");
556 continue;
557 }
558
559 localFundingLegNpv = cpn->accruedAmount(today);
560 Real fundingLegNotionalFactor = 0.0;
561 std::string resultSuffix = arguments_.fundingLegs_.size() > 1 ? "_" + std::to_string(i + 1) : "";
562
563 try {
564 results_.additionalResults["fundingCouponRate" + resultSuffix] = cpn->rate();
565 } catch (...) {
566 }
567
568 bool isOvernightCoupon = QuantLib::ext::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(cpn) != nullptr;
569
570 for (Size j = 0; j < arguments_.underlying_.size(); ++j) {
571
572 std::string resultSuffix2 = arguments_.underlying_.size() > 1 ? "_" + std::to_string(j + 1) : "";
573
574 if (nthCpn > 0)
575 resultSuffix2 += "_nth(" + std::to_string(nthCpn) + ")";
576
577 if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::Fixed) {
578
579 fundingLegNotionalFactor = 1.0;
580
581 } else if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::PeriodReset) {
582
583 Real localNotionalFactor = 0.0, localFxFactor = 1.0; // local per underlying
584 if (currentIdx == 0 && arguments_.initialPrice_ != Null<Real>()) {
585 if (j == 0) {
586 localNotionalFactor =
587 arguments_.initialPrice_ *
588 (arguments_.underlying_.size() == 1 ? arguments_.underlyingMultiplier_[j] : 1.0);
589 localFxFactor = getFxConversionRate(arguments_.valuationSchedule_[currentIdx],
590 arguments_.initialPriceCurrency_,
591 arguments_.fundingCurrency_, false);
592 }
593 } else {
594 localNotionalFactor = arguments_.underlyingMultiplier_[j] *
595 getUnderlyingFixing(j, arguments_.valuationSchedule_[currentIdx], false);
596 localFxFactor =
597 getFxConversionRate(arguments_.valuationSchedule_[currentIdx], arguments_.assetCurrency_[j],
598 arguments_.fundingCurrency_, false);
599 }
600
601 fundingLegNotionalFactor += localNotionalFactor * localFxFactor;
602
603 results_.additionalResults["fundingLegNotional" + resultSuffix + resultSuffix2] =
604 localNotionalFactor;
605 results_.additionalResults["fundingLegFxRate" + resultSuffix + resultSuffix2] = localFxFactor;
606
607 } else if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::DailyReset &&
608 (QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(cpn) ||
609 QuantLib::ext::dynamic_pointer_cast<IborCoupon>(cpn))) {
610
611 Real dcfTotal =
612 cpn->dayCounter().yearFraction(cpn->accrualStartDate(), std::min(cpn->accrualEndDate(), today));
613 for (QuantLib::Date d = cpn->accrualStartDate(); d < std::min(cpn->accrualEndDate(), today); ++d) {
614 Real dcfLocal = cpn->dayCounter().yearFraction(d, d + 1);
615 Date fixingDate = arguments_.underlyingIndex_[j]->fixingCalendar().adjust(d, Preceding);
616 Real localNotionalFactor = getUnderlyingFixing(j, fixingDate, false) *
617 arguments_.underlyingMultiplier_[j] * dcfLocal / dcfTotal;
618 Real localFxFactor = getFxConversionRate(fixingDate, arguments_.assetCurrency_[j],
619 arguments_.fundingCurrency_, false);
620 fundingLegNotionalFactor += localNotionalFactor * localFxFactor;
621
622 results_.additionalResults["fundingLegNotional" + resultSuffix + resultSuffix2 + "_" +
623 ore::data::to_string(d)] = localNotionalFactor;
624 results_.additionalResults["fundingLegFxRate" + resultSuffix + resultSuffix2 + "_" +
625 ore::data::to_string(d)] = localFxFactor;
626 }
627 } else if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::DailyReset &&
628 isOvernightCoupon) {
629 auto overnightCpn = QuantLib::ext::dynamic_pointer_cast<QuantExt::OvernightIndexedCoupon>(cpn);
630 auto valueDates = overnightCpn->valueDates();
631 auto fixingValues = overnightCpn->indexFixings();
632 auto dts = overnightCpn->dt();
633 double accruedInterest = 0;
634 double accruedSpreadInterest = 0;
635 double gearing = overnightCpn->gearing();
636 double spread = overnightCpn->spread();
637 for (size_t i = 0; i < valueDates.size() - 1; ++i) {
638 const Date& valueDate = valueDates[i];
639 double dt = dts[i];
640 double irFixing = fixingValues[i];
641 if (overnightCpn->includeSpread())
642 irFixing += overnightCpn->spread();
643 if (valueDate < today) {
644 Date fixingDate =
645 arguments_.underlyingIndex_[j]->fixingCalendar().adjust(valueDate, Preceding);
646 Real localNotional =
647 getUnderlyingFixing(j, fixingDate, false) * arguments_.underlyingMultiplier_[j];
648 Real localFxFactor = getFxConversionRate(fixingDate, arguments_.assetCurrency_[j],
649 arguments_.fundingCurrency_, false);
650 results_.additionalResults["fundingLegNotional" + resultSuffix + resultSuffix2 + "_" +
651 ore::data::to_string(valueDate)] = localNotional;
652 results_.additionalResults["fundingLegFxRate" + resultSuffix + resultSuffix2 + "_" +
653 ore::data::to_string(valueDate)] = localFxFactor;
654 results_.additionalResults["fundingLegOISRate" + resultSuffix + resultSuffix2 + "_" +
655 ore::data::to_string(valueDate)] = irFixing;
656 results_.additionalResults["fundingLegDCF" + resultSuffix + resultSuffix2 + "_" +
657 ore::data::to_string(valueDate)] = dt;
658 localNotional *= localFxFactor;
659 accruedInterest = localNotional * irFixing * dt + accruedInterest * (1 + irFixing * dt);
660 if (!overnightCpn->includeSpread()) {
661 accruedSpreadInterest += localNotional * spread * dt;
662 }
663 results_.additionalResults["fundingLegAccruedInterest" + resultSuffix + resultSuffix2 +
664 "_" + ore::data::to_string(valueDate)] =
665 accruedInterest + accruedSpreadInterest;
666 }
667 }
668 fundingLegNotionalFactor = (gearing * accruedInterest + accruedSpreadInterest) / localFundingLegNpv;
669 } else if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::DailyReset &&
670 QuantLib::ext::dynamic_pointer_cast<AverageONIndexedCoupon>(cpn) != nullptr) {
671 auto overnightCpn = QuantLib::ext::dynamic_pointer_cast<QuantExt::AverageONIndexedCoupon>(cpn);
672 auto valueDates = overnightCpn->valueDates();
673 auto fixingValues = overnightCpn->indexFixings();
674 auto dts = overnightCpn->dt();
675 double accruedInterest = 0;
676 double spread = overnightCpn->spread();
677 double gearing = overnightCpn->gearing();
678 for (size_t i = 0; i < valueDates.size() - 1; ++i) {
679 const Date& valueDate = valueDates[i];
680 double dt = dts[i];
681 double irFixing = fixingValues[i];
682
683 if (valueDate < today) {
684 Date fixingDate =
685 arguments_.underlyingIndex_[j]->fixingCalendar().adjust(valueDate, Preceding);
686 Real localNotional =
687 getUnderlyingFixing(j, fixingDate, false) * arguments_.underlyingMultiplier_[j];
688 Real localFxFactor = getFxConversionRate(fixingDate, arguments_.assetCurrency_[j],
689 arguments_.fundingCurrency_, false);
690 results_.additionalResults["fundingLegNotional" + resultSuffix + resultSuffix2 + "_" +
691 ore::data::to_string(valueDate)] = localNotional;
692 results_.additionalResults["fundingLegFxRate" + resultSuffix + resultSuffix2 + "_" +
693 ore::data::to_string(valueDate)] = localFxFactor;
694 results_.additionalResults["fundingLegOISRate" + resultSuffix + resultSuffix2 + "_" +
695 ore::data::to_string(valueDate)] = irFixing;
696 results_.additionalResults["fundingLegDCF" + resultSuffix + resultSuffix2 + "_" +
697 ore::data::to_string(valueDate)] = dt;
698 localNotional *= localFxFactor;
699 accruedInterest += localNotional * (gearing * irFixing + spread) * dt;
700 results_.additionalResults["fundingLegAccruedInterest" + resultSuffix + resultSuffix2 +
701 "_" + ore::data::to_string(valueDate)] = accruedInterest;
702 }
703 }
704 fundingLegNotionalFactor = accruedInterest / localFundingLegNpv;
705 } else if (arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::DailyReset) {
706 QL_FAIL("daily reset funding legs support fixed rate, ibor and overnight indexed coupons only");
707 } else {
708 QL_FAIL("internal error: unknown notional type, contact dev");
709 }
710 } // loop over underlyings
711
712 DLOG("fundingLegNpv for funding leg #"
713 << (i + 1) << " is " << fundingMultiplier * localFundingLegNpv << " * " << fundingLegNotionalFactor
714 << " = " << fundingMultiplier * localFundingLegNpv * fundingLegNotionalFactor << " "
715 << arguments_.fundingCurrency_ << " (notional type of leg is '" << arguments_.fundingNotionalTypes_[i]
716 << "')");
717
718 localFundingLegNpv *= fundingLegNotionalFactor;
719
720 results_.additionalResults["fundingLegNpv" + resultSuffix] = fundingMultiplier * localFundingLegNpv;
721
722 // add funding leg cashflow to addtional results
723 cfResults.emplace_back();
724 cfResults.back().amount = fundingMultiplier * localFundingLegNpv;
725 cfResults.back().payDate = today;
726 cfResults.back().currency = arguments_.fundingCurrency_.code();
727 cfResults.back().legNumber = 3 + i;
728 cfResults.back().type = "AccruedFunding" + (nthCpn > 0 ? "_nth(" + std::to_string(nthCpn) + ")" : "");
729 cfResults.back().accrualStartDate = std::min(fundingStartDate, today);
730 cfResults.back().accrualEndDate = today;
731 cfResults.back().notional = arguments_.fundingNotionalTypes_[i] == TRS::FundingData::NotionalType::Fixed
732 ? fundingCouponNotional
733 : fundingLegNotionalFactor;
734
735 results_.additionalResults["fundingLegNotional" + resultSuffix] = cfResults.back().notional;
736
737 fundingLegNpv += localFundingLegNpv;
738 ++nthCpn;
739 } // loop over funding leg coupons (indexed by cpnNo)
740 } // loop over funding legs (indexed by i)
741
742 DLOG("total funding leg(s) npv is " << fundingMultiplier * fundingLegNpv);
743
744 results_.additionalResults["fundingLegNpv"] = fundingMultiplier * fundingLegNpv;
745 results_.additionalResults["fundingLegNpvCurrency"] = arguments_.fundingCurrency_.code();
746
747 // additional cashflow leg valuation (take the plain amount of future cashflows as if paid today)
748
749 Real additionalCashflowLegNpv = 0.0;
750 for (auto const& cf : arguments_.additionalCashflowLeg_) {
751 if (cf->date() > today) {
752 Real tmp = cf->amount() * (arguments_.additionalCashflowLegPayer_ ? -1.0 : 1.0);
753 additionalCashflowLegNpv += tmp;
754 // add additional cashflows to additional results
755 cfResults.emplace_back();
756 cfResults.back().amount = tmp;
757 cfResults.back().payDate = cf->date();
758 cfResults.back().currency = arguments_.additionalCashflowCurrency_.code();
759 cfResults.back().legNumber = 0;
760 cfResults.back().type = "AdditionalCashFlow";
761 }
762 }
763 DLOG("additionalCashflowLegNpv = " << additionalCashflowLegNpv << " " << arguments_.additionalCashflowCurrency_);
764 results_.additionalResults["additionalCashflowLegNpv"] = additionalCashflowLegNpv;
765 results_.additionalResults["additionalCashflowLegNpvCurrency"] = arguments_.additionalCashflowCurrency_.code();
766
767 // set npv and current notional, set additional results
768
769 Real fxAssetToPnlCcy = getFxConversionRate(today, arguments_.returnCurrency_, arguments_.fundingCurrency_, true);
770 Real fxAdditionalCashflowLegToPnlCcy =
771 getFxConversionRate(today, arguments_.additionalCashflowCurrency_, arguments_.fundingCurrency_, true);
772
773 results_.additionalResults["fxConversionAssetLegNpvToPnlCurrency"] = fxAssetToPnlCcy;
774 results_.additionalResults["fxConversionAdditionalCashflowLegNpvToPnlCurrency"] = fxAdditionalCashflowLegToPnlCcy;
775 results_.additionalResults["pnlCurrency"] = arguments_.fundingCurrency_.code();
776
777 results_.value = assetMultiplier * assetLegNpv * fxAssetToPnlCcy + fundingMultiplier * fundingLegNpv +
778 additionalCashflowLegNpv * fxAdditionalCashflowLegToPnlCcy;
779
780 Real currentNotional = 0.0;
781 for (Size j = 0; j < arguments_.underlying_.size(); ++j) {
782 // this is using the underlyingStartValue and fxConversionFactor that was populated during the
783 // valuation of the asset leg above in the last "nth current period" which contributed to this npv
784 if (underlyingStartValue[j] == Null<Real>()) {
786 arguments_.underlyingMultiplier_[j] * getUnderlyingFixing(j, today, true) *
787 getFxConversionRate(today, arguments_.initialPriceCurrency_, arguments_.returnCurrency_, true);
788 } else {
789 currentNotional += underlyingStartValue[j] * fxConversionFactor[j];
790 }
791 }
792
793 for (Size j = 0; j < arguments_.underlying_.size(); ++j) {
794 // the start fixing will refer to the last of the nth current return periods
795 std::string resultSuffix = arguments_.underlying_.size() == 1 ? "" : "_" + std::to_string(j);
796 Real startFixing = Null<Real>(), todaysFixing = Null<Real>();
797 try {
798 startFixing = getUnderlyingFixing(j, startDate, false);
799 } catch (...) {
800 }
801 try {
802 todaysFixing = getUnderlyingFixing(j, today, true);
803 } catch (...) {
804 }
805 results_.additionalResults["startFixing" + resultSuffix] = startFixing;
806 results_.additionalResults["todaysFixing" + resultSuffix] = todaysFixing;
807 }
808
809 for (auto const& d : arguments_.addFxIndices_) {
810 Real startFixing = Null<Real>(), todaysFixing = Null<Real>();
811 try {
812 startFixing = d.second->fixing(d.second->fixingCalendar().adjust(startDate, Preceding));
813 } catch (...) {
814 }
815 try {
816 todaysFixing = d.second->fixing(d.second->fixingCalendar().adjust(today, Preceding), true);
817 } catch (...) {
818 }
819 results_.additionalResults["startFxFixing(" + d.first + ")"] = startFixing;
820 results_.additionalResults["todaysFxFixing(" + d.first + ")"] = todaysFixing;
821 }
822
823 results_.additionalResults["currentNotional"] = currentNotional * fxAssetToPnlCcy;
824 results_.additionalResults["cashFlowResults"] = cfResults;
825
826 // propagate underlying additional results to trswrapper
827
828 for (Size i = 0; i < arguments_.underlying_.size(); ++i) {
829 for (auto const& [key, value] : arguments_.underlying_[i]->instrument()->additionalResults()) {
830 results_.additionalResults["und_ar_" + std::to_string(i + 1) + "_" + key] = value;
831 }
832 }
833
834 DLOG("TRSWrapperAccrualEngine: all done, total npv = " << results_.value << " "
835 << arguments_.fundingCurrency_.code());
836}
837
838} // namespace data
839} // namespace ore
const Instrument::results * results_
std::vector< TRS::FundingData::NotionalType > fundingNotionalTypes_
Definition: trswrapper.hpp:123
std::vector< QuantLib::Date > paymentSchedule_
Definition: trswrapper.hpp:121
std::vector< QuantLib::ext::shared_ptr< QuantLib::Index > > underlyingIndex_
Definition: trswrapper.hpp:114
std::map< std::string, QuantLib::ext::shared_ptr< QuantExt::FxIndex > > addFxIndices_
Definition: trswrapper.hpp:132
std::vector< QuantLib::Date > valuationSchedule_
Definition: trswrapper.hpp:121
QuantLib::Currency returnCurrency_
Definition: trswrapper.hpp:120
std::vector< QuantLib::Real > underlyingMultiplier_
Definition: trswrapper.hpp:115
std::vector< QuantLib::Leg > fundingLegs_
Definition: trswrapper.hpp:122
std::vector< QuantLib::ext::shared_ptr< ore::data::Trade > > underlying_
Definition: trswrapper.hpp:113
QuantLib::Currency fundingCurrency_
Definition: trswrapper.hpp:124
std::vector< QuantLib::Currency > assetCurrency_
Definition: trswrapper.hpp:119
QuantLib::Size fundingResetGracePeriod_
Definition: trswrapper.hpp:125
QuantLib::Currency initialPriceCurrency_
Definition: trswrapper.hpp:118
QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndexReturn_
Definition: trswrapper.hpp:131
QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndexAdditionalCashflows_
Definition: trswrapper.hpp:131
QuantLib::Currency additionalCashflowCurrency_
Definition: trswrapper.hpp:129
void validate() const override
Definition: trswrapper.cpp:164
std::vector< QuantLib::ext::shared_ptr< QuantExt::FxIndex > > fxIndexAsset_
Definition: trswrapper.hpp:130
QuantLib::Real getFxConversionRate(const QuantLib::Date &date, const QuantLib::Currency &source, const QuantLib::Currency &target, const bool enforceProjection) const
Definition: trswrapper.cpp:293
void calculate() const override
Definition: trswrapper.cpp:377
bool computeStartValue(std::vector< QuantLib::Real > &underlyingStartValue, std::vector< QuantLib::Real > &fxConversionFactor, QuantLib::Date &startDate, QuantLib::Date &endDate, bool &usingInitialPrice, const Size nth) const
Definition: trswrapper.cpp:174
Real getUnderlyingFixing(const Size i, const QuantLib::Date &date, const bool enforceProjection) const
Definition: trswrapper.cpp:358
const QuantLib::Currency additionalCashflowCurrency_
Definition: trswrapper.hpp:102
void fetchResults(const QuantLib::PricingEngine::results *) const override
Definition: trswrapper.cpp:172
std::vector< TRS::FundingData::NotionalType > fundingNotionalTypes_
Definition: trswrapper.hpp:96
std::vector< QuantLib::Date > paymentSchedule_
Definition: trswrapper.hpp:94
std::vector< QuantLib::ext::shared_ptr< QuantLib::Index > > underlyingIndex_
Definition: trswrapper.hpp:87
const QuantLib::Currency fundingCurrency_
Definition: trswrapper.hpp:97
const QuantLib::Currency returnCurrency_
Definition: trswrapper.hpp:93
std::map< std::string, QuantLib::ext::shared_ptr< QuantExt::FxIndex > > addFxIndices_
Definition: trswrapper.hpp:105
std::vector< QuantLib::Date > valuationSchedule_
Definition: trswrapper.hpp:94
bool isExpired() const override
Definition: trswrapper.cpp:134
const QuantLib::Currency initialPriceCurrency_
Definition: trswrapper.hpp:91
QuantLib::Real initialPrice_
Definition: trswrapper.hpp:90
std::vector< QuantLib::Real > underlyingMultiplier_
Definition: trswrapper.hpp:88
std::vector< QuantLib::Leg > fundingLegs_
Definition: trswrapper.hpp:95
TRSWrapper(const std::vector< QuantLib::ext::shared_ptr< ore::data::Trade > > &underlying, const std::vector< QuantLib::ext::shared_ptr< QuantLib::Index > > &underlyingIndex, const std::vector< QuantLib::Real > underlyingMultiplier, const bool includeUnderlyingCashflowsInReturn, const QuantLib::Real initialPrice, const QuantLib::Currency &initialPriceCurrency, const std::vector< QuantLib::Currency > &assetCurrency, const QuantLib::Currency &returnCurrency, const std::vector< QuantLib::Date > &valuationSchedule, const std::vector< QuantLib::Date > &paymentSchedule, const std::vector< QuantLib::Leg > &fundingLegs, const std::vector< TRS::FundingData::NotionalType > &fundingNotionalTypes, const QuantLib::Currency &fundingCurrency, const QuantLib::Size fundingResetGracePeriod, const bool paysAsset, const bool paysFunding, const QuantLib::Leg &additionalCashflowLeg, const bool additionalCashflowLegPayer, const QuantLib::Currency &additionalCashflowCurrency, const std::vector< QuantLib::ext::shared_ptr< QuantExt::FxIndex > > &fxIndexAsset, const QuantLib::ext::shared_ptr< QuantExt::FxIndex > &fxIndexReturn, const QuantLib::ext::shared_ptr< QuantExt::FxIndex > &fxIndexAdditionalCashflows, const std::map< std::string, QuantLib::ext::shared_ptr< QuantExt::FxIndex > > &addFxindices)
Definition: trswrapper.cpp:37
std::vector< QuantLib::ext::shared_ptr< ore::data::Trade > > underlying_
Definition: trswrapper.hpp:86
const QuantLib::Size fundingResetGracePeriod_
Definition: trswrapper.hpp:98
QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndexReturn_
Definition: trswrapper.hpp:104
QuantLib::ext::shared_ptr< QuantExt::FxIndex > fxIndexAdditionalCashflows_
Definition: trswrapper.hpp:104
QuantLib::Leg additionalCashflowLeg_
Definition: trswrapper.hpp:100
bool includeUnderlyingCashflowsInReturn_
Definition: trswrapper.hpp:89
void setupArguments(QuantLib::PricingEngine::arguments *) const override
Definition: trswrapper.cpp:136
std::vector< QuantLib::ext::shared_ptr< QuantExt::FxIndex > > fxIndexAsset_
Definition: trswrapper.hpp:103
const std::vector< QuantLib::Currency > assetCurrency_
Definition: trswrapper.hpp:92
SafeStack< ValueType > value
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
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)
Real currentNotional(const Leg &leg)
Definition: legdata.cpp:2435
std::string to_string(const LocationInfo &l)
Definition: ast.cpp:28
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Swap::arguments * arguments_
string conversion utilities
generic wrapper for trs (bond, convertible bond, equity, ...)