32#include <ql/cashflows/simplecashflow.hpp>
33#include <ql/instruments/bond.hpp>
34#include <ql/instruments/bonds/zerocouponbond.hpp>
35#include <ql/quotes/simplequote.hpp>
36#include <ql/time/calendars/weekendsonly.hpp>
37#include <ql/time/daycounters/actual360.hpp>
39#include <boost/lexical_cast.hpp>
40#include <boost/make_shared.hpp>
49 DLOG(
"ForwardBond::build() called for trade " <<
id());
52 additionalData_[
"isdaAssetClass"] = string(
"Interest Rate");
53 additionalData_[
"isdaBaseProduct"] = string(
"Forward");
54 additionalData_[
"isdaSubProduct"] = string(
"Debt");
55 additionalData_[
"isdaTransaction"] = string(
"");
57 additionalData_[
"currency"] = currency_;
59 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
61 QuantLib::ext::shared_ptr<EngineBuilder> builder_fwd = engineFactory->builder(
"ForwardBond");
62 QuantLib::ext::shared_ptr<EngineBuilder> builder_bd = engineFactory->builder(
"Bond");
64 bondData_ = originalBondData_;
65 bondData_.populateFromBondReferenceData(engineFactory->referenceData());
67 npvCurrency_ = currency_ = bondData_.coupons().front().currency();
68 notionalCurrency_ = currency_;
70 QL_REQUIRE(!bondData_.referenceCurveId().empty(),
"reference curve id required");
71 QL_REQUIRE(!bondData_.settlementDays().empty(),
"settlement days required");
73 Date issueDate =
parseDate(bondData_.issueDate());
75 Natural settlementDays = boost::lexical_cast<Natural>(bondData_.settlementDays());
79 bool isPhysicallySettled;
80 if (settlement_ ==
"Physical" || settlement_.empty())
81 isPhysicallySettled =
true;
82 else if (settlement_ ==
"Cash")
83 isPhysicallySettled =
false;
85 QL_FAIL(
"ForwardBond: invalid settlement '" << settlement_ <<
"', expected Cash or Physical");
96 QL_REQUIRE((amount == Null<Real>() && lockRate != Null<Real>()) ||
97 (amount != Null<Real>() && lockRate == Null<Real>()),
98 "ForwardBond: exactly one of Amount of LockRate must be given");
99 QL_REQUIRE(dv01 >= 0.0,
"negative DV01 given");
100 QL_REQUIRE(compensationPaymentDate <= fwdMaturityDate,
"Premium cannot be paid after forward contract maturity");
102 if (lockRate != Null<Real>())
103 isPhysicallySettled =
false;
105 QL_REQUIRE(!bondData_.coupons().empty(),
"ForwardBond: No LegData given. If you want to represent a zero bond, "
106 "set it up as a coupon bond with zero fixed rate");
108 bool firstLegIsPayer = bondData_.coupons()[0].isPayer();
109 QL_REQUIRE(firstLegIsPayer ==
false,
"ForwardBond: The underlying bond must be entered with a receiver leg. Use "
110 "LongInBond to specify pay direction of forward payoff");
111 QL_REQUIRE(compensationPayment > 0.0 ||
close_enough(compensationPayment, 0.0),
112 "ForwardBond: Negative compensation payments ("
113 << compensationPayment
114 <<
") are not allowed. Notice that we will ensure that a positive compensation amount will be paid "
115 "by the party being long in the forward contract.");
117 QuantLib::ext::shared_ptr<Payoff> payoff;
118 if (amount != Null<Real>()) {
119 payoff = longInForward ? QuantLib::ext::make_shared<QuantExt::ForwardBondTypePayoff>(Position::Long, amount)
120 : QuantLib::ext::make_shared<QuantExt::ForwardBondTypePayoff>(Position::Short, amount);
122 compensationPayment = longInForward ? compensationPayment : -compensationPayment;
124 std::vector<Leg> separateLegs;
125 for (Size i = 0; i < bondData_.coupons().
size(); ++i) {
127 auto configuration = builder_bd->configuration(MarketContext::pricing);
128 auto legBuilder = engineFactory->legBuilder(bondData_.coupons()[i].legType());
129 leg = legBuilder->buildLeg(bondData_.coupons()[i], engineFactory, requiredFixings_, configuration);
130 separateLegs.push_back(leg);
133 auto bond = QuantLib::ext::make_shared<QuantLib::Bond>(settlementDays,
calendar, issueDate, leg);
137 legCurrencies_ = {npvCurrency_};
138 legPayers_ = {firstLegIsPayer};
140 maturity_ = bond->cashflows().back()->date();
141 notional_ =
currentNotional(bond->cashflows()) * bondData_.bondNotional();
144 QuantLib::ext::shared_ptr<QuantLib::Instrument> fwdBond =
145 payoff ? QuantLib::ext::make_shared<QuantExt::ForwardBond>(bond, payoff, fwdMaturityDate, fwdSettlementDate,
146 isPhysicallySettled, settlementDirty, compensationPayment,
147 compensationPaymentDate, bondData_.bondNotional())
148 : QuantLib::ext::make_shared<QuantExt::ForwardBond>(bond, lockRate, lockRateDayCounter, longInForward,
149 fwdMaturityDate, fwdSettlementDate, isPhysicallySettled,
150 settlementDirty, compensationPayment,
151 compensationPaymentDate, bondData_.bondNotional(), dv01);
153 QuantLib::ext::shared_ptr<fwdBondEngineBuilder> fwdBondBuilder =
154 QuantLib::ext::dynamic_pointer_cast<fwdBondEngineBuilder>(builder_fwd);
155 QL_REQUIRE(fwdBondBuilder,
"ForwardBond::build(): could not cast builder: " <<
id());
157 fwdBond->setPricingEngine(fwdBondBuilder->engine(
id(), currency, bondData_.creditCurveId(),
158 bondData_.hasCreditRisk(), bondData_.securityId(),
159 bondData_.referenceCurveId(), bondData_.incomeCurveId()));
160 setSensitivityTemplate(*fwdBondBuilder);
163 additionalData_[
"currentNotional"] =
currentNotional(bond->cashflows()) * bondData_.bondNotional();
164 additionalData_[
"originalNotional"] =
originalNotional(bond->cashflows()) * bondData_.bondNotional();
168 Trade::fromXML(node);
169 XMLNode* fwdBondNode = XMLUtils::getChildNode(node,
"ForwardBondData");
170 QL_REQUIRE(fwdBondNode,
"No ForwardBondData Node");
171 originalBondData_.fromXML(XMLUtils::getChildNode(fwdBondNode,
"BondData"));
172 bondData_ = originalBondData_;
174 XMLNode* fwdSettlementNode = XMLUtils::getChildNode(fwdBondNode,
"SettlementData");
175 QL_REQUIRE(fwdSettlementNode,
"No fwdSettlementNode Node");
177 fwdMaturityDate_ = XMLUtils::getChildValue(fwdSettlementNode,
"ForwardMaturityDate",
true);
178 fwdSettlementDate_ = XMLUtils::getChildValue(fwdSettlementNode,
"ForwardSettlementDate",
false);
179 settlement_ = XMLUtils::getChildValue(fwdSettlementNode,
"Settlement",
false);
180 amount_ = XMLUtils::getChildValue(fwdSettlementNode,
"Amount",
false);
181 lockRate_ = XMLUtils::getChildValue(fwdSettlementNode,
"LockRate",
false);
182 lockRateDayCounter_ = XMLUtils::getChildValue(fwdSettlementNode,
"LockRateDayCounter",
false);
183 settlementDirty_ = XMLUtils::getChildValue(fwdSettlementNode,
"SettlementDirty",
false);
184 dv01_ = XMLUtils::getChildValue(fwdSettlementNode,
"dv01",
false);
186 XMLNode* fwdPremiumNode = XMLUtils::getChildNode(fwdBondNode,
"PremiumData");
187 if (fwdPremiumNode) {
195 longInForward_ = XMLUtils::getChildValue(fwdBondNode,
"LongInForward",
true);
199 XMLNode* node = Trade::toXML(doc);
201 XMLUtils::appendNode(node, fwdBondNode);
202 XMLUtils::appendNode(fwdBondNode, originalBondData_.toXML(doc));
205 XMLUtils::appendNode(fwdBondNode, fwdSettlementNode);
206 XMLUtils::addChild(doc, fwdSettlementNode,
"ForwardMaturityDate",
fwdMaturityDate_);
208 XMLUtils::addChild(doc, fwdSettlementNode,
"ForwardSettlementDate",
fwdSettlementDate_);
209 if (!settlement_.empty())
210 XMLUtils::addChild(doc, fwdSettlementNode,
"Settlement", settlement_);
212 XMLUtils::addChild(doc, fwdSettlementNode,
"Amount",
amount_);
214 XMLUtils::addChild(doc, fwdSettlementNode,
"LockRate",
lockRate_);
216 XMLUtils::addChild(doc, fwdSettlementNode,
"dv01",
dv01_);
220 XMLUtils::addChild(doc, fwdSettlementNode,
"SettlementDirty",
settlementDirty_);
223 XMLUtils::appendNode(fwdBondNode, fwdPremiumNode);
227 XMLUtils::addChild(doc, fwdBondNode,
"LongInForward",
longInForward_);
232std::map<AssetClass, std::set<std::string>>
233ForwardBond::underlyingIndices(
const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager)
const {
234 std::map<AssetClass, std::set<std::string>> result;
235 result[AssetClass::BOND] = {bondData_.securityId()};
builder that returns an engine to price a bond instrument
Engine builder for forward bonds.
DayCounter lockRateDayCounter_
Date compensationPaymentDate_
boost::optional< bool > longInForward_
Real compensationPayment_
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
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.
bool parseBool(const string &s)
Convert text to bool.
Real parseReal(const string &s)
Convert text to Real.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
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)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real currentNotional(const Leg &leg)
Size size(const ValueType &v)
Real originalNotional(const Leg &leg)
Leg joinLegs(const std::vector< Leg > &legs)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
Swap trade data model and serialization.