35#include <ql/cashflows/simplecashflow.hpp>
36#include <ql/instruments/bond.hpp>
37#include <ql/instruments/bonds/zerocouponbond.hpp>
38#include <ql/quotes/simplequote.hpp>
39#include <ql/time/calendars/weekendsonly.hpp>
41#include <boost/lexical_cast.hpp>
42#include <boost/make_shared.hpp>
50void BondTRS::build(
const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
51 DLOG(
"BondTRS::build() called for trade " <<
id());
54 additionalData_[
"isdaAssetClass"] = string(
"Credit");
55 additionalData_[
"isdaBaseProduct"] = string(
"Total Return Swap");
56 additionalData_[
"isdaSubProduct"] = string(
"");
57 additionalData_[
"isdaTransaction"] = string(
"");
59 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
60 QuantLib::ext::shared_ptr<EngineBuilder> builder_trs = engineFactory->builder(
"BondTRS");
61 bondData_ = originalBondData_;
62 bondData_.populateFromBondReferenceData(engineFactory->referenceData());
67 auto configuration = builder_trs->configuration(MarketContext::pricing);
68 auto legBuilder = engineFactory->legBuilder(fundingLegData_.legType());
72 QL_REQUIRE(fundingLegData_.currency() != bondData_.currency() ||
fxIndex_.empty(),
73 "if funding leg ccy (" << fundingLegData_.currency() <<
") = bond ccy (" << bondData_.currency()
74 <<
"), no fx index must be given");
75 QL_REQUIRE(fundingLegData_.currency() == bondData_.currency() || !
fxIndex_.empty(),
76 "if funding leg ccy (" << fundingLegData_.currency() <<
") != bond ccy (" << bondData_.currency()
77 <<
"), a fx index must be given");
79 npvCurrency_ = fundingLegData_.currency();
80 notionalCurrency_ = bondData_.currency();
83 DLOG(
"build valuation and payment dates vectors");
85 Period observationLag = observationLag_.empty() ? 0 * Days :
parsePeriod(observationLag_);
86 Calendar observationCalendar =
parseCalendar(observationCalendar_);
87 BusinessDayConvention observationConvention =
93 BusinessDayConvention paymentConvention =
98 for (
auto const& d : schedule.dates()) {
99 valuationDates.push_back(observationCalendar.advance(d, -observationLag, observationConvention));
100 if (d != schedule.dates().front())
101 paymentDates.push_back(paymentCalendar.advance(d, plPeriod, paymentConvention));
107 "paymentDates size (" <<
paymentDates_.size() <<
") does no match valuatioDates size ("
113 DLOG(
"valuation schedule:");
117 DLOG(
"payment schedule:");
123 QuantLib::ext::shared_ptr<FxIndex>
fxIndex;
126 buildFxIndex(
fxIndex_, fundingLegData_.currency(), bondData_.currency(), engineFactory->market(),
127 engineFactory->configuration(MarketContext::pricing));
132 BondIndexBuilder bondIndexBuilder(bondData_, useDirtyPrices_,
false, NullCalendar(),
false, engineFactory);
137 if (effectiveInitialPrice != Null<Real>())
138 effectiveInitialPrice = effectiveInitialPrice / 100.0;
142 if (fundingLegData_.indexingFromAssetLeg()) {
143 DLOG(
"adding indexing information from trs leg to funding leg");
145 std::vector<string> stringValuationDates;
152 bondIndex->conditionalOnSurvival(), bondData_.bondNotional(), effectiveInitialPrice,
153 Null<Real>(), valuationSchedule, 0,
"",
"U",
false);
154 fundingLegData_.indexing().push_back(bondIndexing);
158 Indexing fxIndexing(
fxIndex_,
"",
false,
false,
false, 1.0, Null<Real>(), Null<Real>(), valuationSchedule,
160 fundingLegData_.indexing().push_back(fxIndexing);
164 fundingLegData_.notionals() = std::vector<Real>(1, 1.0);
165 fundingLegData_.notionalDates() = std::vector<std::string>();
168 fundingLegData_.indexingFromAssetLeg() =
false;
173 Leg
fundingLeg = legBuilder->buildLeg(fundingLegData_, engineFactory, requiredFixings_, configuration);
174 Leg fundingNotionalLeg;
175 if (fundingLegData_.notionalInitialExchange() || fundingLegData_.notionalFinalExchange() ||
176 fundingLegData_.notionalAmortizingExchange()) {
177 Natural fundingLegPayLag = 0;
180 fundingLegData_.notionalFinalExchange(), fundingLegData_.notionalAmortizingExchange(),
186 "funding leg and total return lag are both rec or both pay");
187 DLOG(
"Before bondTRS");
188 auto bondTRS = QuantLib::ext::make_shared<QuantExt::BondTRS>(
189 bondIndex, bondData_.bondNotional(), effectiveInitialPrice,
193 DLOG(
"After bondTRS");
194 QuantLib::ext::shared_ptr<BondTRSEngineBuilder> trsBondBuilder =
195 QuantLib::ext::dynamic_pointer_cast<BondTRSEngineBuilder>(builder_trs);
196 QL_REQUIRE(trsBondBuilder,
"No Builder found for BondTRS: " <<
id());
197 bondTRS->setPricingEngine(trsBondBuilder->engine(fundingLegData_.currency()));
198 setSensitivityTemplate(*trsBondBuilder);
201 maturity_ =
bondIndex->bond()->maturityDate();
202 notional_ =
bondIndex->bond()->notional() * bondData_.bondNotional();
211 addToRequiredFixings(bondTRS->returnLeg(), QuantLib::ext::make_shared<FixingDateGetter>(requiredFixings_));
217 for (
auto const& c :
bondIndex->bond()->cashflows()) {
218 requiredFixings_.addFixingDate(
fxIndex->fixingCalendar().adjust(c->date(), Preceding),
fxIndex_, c->date());
222 if (bondData_.isInflationLinked() && useDirtyPrices()) {
223 auto inflationIndices = extractAllInflationUnderlyingFromBond(
bondIndex->bond());
224 for (
const auto& cf : bondTRS->returnLeg()) {
225 auto tcf = QuantLib::ext::dynamic_pointer_cast<TRSCashFlow>(cf);
226 if (tcf !=
nullptr) {
227 for (
const auto& [key, index] : inflationIndices) {
228 auto [
name, interpolation, couponFrequency, observationLag] = key;
229 std::string oreName = IndexNameTranslator::instance().oreName(
name);
230 requiredFixings_.addZeroInflationFixingDate(
231 tcf->fixingStartDate() - observationLag, oreName,
false, index->frequency(),
232 index->availabilityLag(), interpolation, couponFrequency, Date::maxDate(),
false,
false);
240 Trade::fromXML(node);
241 XMLNode* bondTRSNode = XMLUtils::getChildNode(node,
"BondTRSData");
242 QL_REQUIRE(bondTRSNode,
"No BondTRSData Node");
243 originalBondData_.fromXML(XMLUtils::getChildNode(bondTRSNode,
"BondData"));
244 bondData_ = originalBondData_;
246 XMLNode* bondTRSDataNode = XMLUtils::getChildNode(bondTRSNode,
"TotalReturnData");
247 QL_REQUIRE(bondTRSDataNode,
"No bondTRSDataNode Node");
251 scheduleData_.fromXML(XMLUtils::getChildNode(bondTRSDataNode,
"ScheduleData"));
253 observationLag_ = XMLUtils::getChildValue(bondTRSDataNode,
"ObservationLag");
254 observationConvention_ = XMLUtils::getChildValue(bondTRSDataNode,
"ObservationConvention");
255 observationCalendar_ = XMLUtils::getChildValue(bondTRSDataNode,
"ObservationCalendar");
257 paymentLag_ = XMLUtils::getChildValue(bondTRSDataNode,
"PaymentLag");
258 paymentConvention_ = XMLUtils::getChildValue(bondTRSDataNode,
"PaymentConvention");
259 paymentCalendar_ = XMLUtils::getChildValue(bondTRSDataNode,
"PaymentCalendar");
260 paymentDates_ = XMLUtils::getChildrenValues(bondTRSDataNode,
"PaymentDates",
"PaymentDate");
263 if (
auto n = XMLUtils::getChildNode(bondTRSDataNode,
"InitialPrice"))
265 std::string priceType = XMLUtils::getChildValue(bondTRSDataNode,
"PriceType",
true);
266 if (priceType ==
"Dirty")
267 useDirtyPrices_ =
true;
268 else if (priceType ==
"Clean")
269 useDirtyPrices_ =
false;
271 QL_FAIL(
"PriceType (" << priceType <<
") must be Clean or Dirty");
274 XMLNode* fxt = XMLUtils::getChildNode(bondTRSDataNode,
"FXTerms");
276 fxIndex_ = XMLUtils::getChildValue(fxt,
"FXIndex",
true);
279 XMLUtils::getChildValueAsBool(bondTRSDataNode,
"PayBondCashFlowsImmediately",
false,
false);
281 XMLNode* bondTRSFundingNode = XMLUtils::getChildNode(bondTRSNode,
"FundingData");
282 XMLNode* fLegNode = XMLUtils::getChildNode(bondTRSFundingNode,
"LegData");
284 fundingLegData_.fromXML(fLegNode);
288 XMLNode* node = Trade::toXML(doc);
290 XMLUtils::appendNode(node, bondTRSNode);
291 XMLUtils::appendNode(bondTRSNode, originalBondData_.toXML(doc));
294 XMLUtils::appendNode(bondTRSNode, trsDataNode);
298 XMLUtils::addChild(doc, trsDataNode,
"InitialPrice",
initialPrice_);
299 XMLUtils::addChild(doc, trsDataNode,
"PriceType", useDirtyPrices_ ?
"Dirty" :
"Clean");
301 if (!observationLag_.empty())
302 XMLUtils::addChild(doc, trsDataNode,
"ObservationLag", observationLag_);
303 if (!observationConvention_.empty())
304 XMLUtils::addChild(doc, trsDataNode,
"ObservationConvention", observationConvention_);
305 if (!observationCalendar_.empty())
306 XMLUtils::addChild(doc, trsDataNode,
"ObservationCalendar", observationCalendar_);
308 if (!paymentLag_.empty())
309 XMLUtils::addChild(doc, trsDataNode,
"PaymentLag", paymentLag_);
310 if (!paymentConvention_.empty())
311 XMLUtils::addChild(doc, trsDataNode,
"PaymentConvention", paymentConvention_);
312 if (!paymentCalendar_.empty())
313 XMLUtils::addChild(doc, trsDataNode,
"PaymentCalendar", paymentCalendar_);
315 XMLUtils::addChildren(doc, trsDataNode,
"PaymentDates",
"PaymentDate",
paymentDates_);
319 XMLUtils::addChild(doc, fxNode,
"FXIndex",
fxIndex_);
320 XMLUtils::appendNode(trsDataNode, fxNode);
323 XMLUtils::appendNode(trsDataNode, scheduleData_.toXML(doc));
328 XMLUtils::appendNode(bondTRSNode, fundingDataNode);
329 XMLUtils::appendNode(fundingDataNode, fundingLegData_.toXML(doc));
333std::map<AssetClass, std::set<std::string>>
334BondTRS::underlyingIndices(
const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager)
const {
335 std::map<AssetClass, std::set<std::string>> result;
336 result[AssetClass::BOND] = {bondData_.securityId()};
Interface for building a bond index.
builder that returns an engine to price a bond instrument
bool payBondCashFlowsImmediately_
boost::shared_ptr< QuantExt::FxIndex > fxIndex_
const std::vector< Date > & valuationDates() const
const std::vector< Leg > & fundingLeg() const
const std::vector< Date > & paymentDates() const
std::vector< Date > paymentDates_
const boost::shared_ptr< QuantExt::FxIndex > & fxIndex() const
const boost::shared_ptr< QuantExt::BondIndex > & bondIndex() const
QuantLib::Real priceAdjustment(QuantLib::Real price)
QuantLib::ext::shared_ptr< QuantExt::BondIndex > bondIndex() const
void addRequiredFixings(RequiredFixings &requiredFixings, Leg leg={})
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Serializable object holding indexing data.
Serializable object holding leg data.
Serializable schedule data.
Serializable object holding schedule Dates data.
Vanilla Instrument Wrapper.
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Logic for calculating required fixing dates on legs.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
bool parseBool(const string &s)
Convert text to bool.
PaymentLag parsePaymentLag(const string &s)
Convert text to PaymentLag.
Real parseReal(const string &s)
Convert text to Real.
translates between QuantLib::Index::name() and ORE names
Map text representations to QuantLib/QuantExt types.
leg data model and serialization
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
void addToRequiredFixings(const QuantLib::Leg &leg, const QuantLib::ext::shared_ptr< FixingDateGetter > &fixingDateGetter)
std::string to_string(const LocationInfo &l)
boost::variant< QuantLib::Period, QuantLib::Natural > PaymentLag
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)
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)
Schedule makeSchedule(const ScheduleDates &data)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.