Skip to content

Commit dd7e99f

Browse files
pcaspersjenkins
authored andcommitted
Merge remote-tracking branch 'origin/master' into seb_fwdBond
1 parent 90ab329 commit dd7e99f

7 files changed

Lines changed: 58 additions & 11 deletions

File tree

Docs/UserGuide/tradedata/bondForward_refdata.tex

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ \subsubsection{Bond Forward / T-Lock / J-Lock (using ref. data)}
4545
true). Exactly one of the fields Amount, LockRate must be given. In case the LockRate is given, the Settlement
4646
must be set to Cash. If Settlement is not given, it defaults to Cash in this case. \\
4747
Allowable values: Any non-negative real number. The LockRate is expressed in decimal form, eg 0.05 is a rate of 5\%
48+
\item dv01 [Optional]: When the LockRate is given, it is possible to implement a contractual DV01 instead of deriving it from the bond price. \\
49+
Allowable values: Any positive real number. E.G If the dPdY is given then dv01=10000*dPdY/N.
4850
\item LockRateDayCounter [Optional]: The day counter w.r.t. which the lock rate is expressed. Optional, defaults to A360. \\
4951
Allowable values: see table \ref{tab:daycount}
5052
\item SettlementDirty [Optional]: A flag that determines whether the settlement amount {({\tt Amount})} reflects
@@ -110,3 +112,23 @@ \subsubsection{Bond Forward / T-Lock / J-Lock (using ref. data)}
110112
\caption{Forward Bond Date (T-Lock)}
111113
\label{lst:forward_bond_refdata_tlock}
112114
\end{listing}
115+
116+
\begin{listing}[H]
117+
\begin{minted}[fontsize=\small]{xml}
118+
<ForwardBondData>
119+
<BondData>
120+
<SecurityId>ISIN:XS1234567890</SecurityId>
121+
<BondNotional>100000</BondNotional>
122+
</BondData>
123+
<SettlementData>
124+
<ForwardMaturityDate>20160808</ForwardMaturityDate>
125+
<ForwardSettlementDate>20160810</ForwardSettlementDate>
126+
<LockRate>0.02365</LockRate>
127+
<dv01>0.8</dv01>
128+
</SettlementData>
129+
<LongInForward>true</LongInForward>
130+
</ForwardBondData>
131+
\end{minted}
132+
\caption{Forward Bond Date (T-Lock) with DV01}
133+
\label{lst:forward_bond_refdata_tlock_dv01}
134+
\end{listing}

OREData/ored/portfolio/forwardbond.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void ForwardBond::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
7575
}
7676
Real amount = amount_.empty() ? Null<Real>() : parseReal(amount_);
7777
Real lockRate = lockRate_.empty() ? Null<Real>() : parseReal(lockRate_);
78+
Real dv01 = dv01_.empty() ? Null<Real>() : parseReal(dv01_);
7879
DayCounter lockRateDayCounter = lockRateDayCounter_.empty() ? Actual360() : parseDayCounter(lockRateDayCounter_);
7980
bool settlementDirty = settlementDirty_.empty() ? true : parseBool(settlementDirty_);
8081
Real compensationPayment = parseReal(compensationPayment_);
@@ -84,6 +85,7 @@ void ForwardBond::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
8485
QL_REQUIRE((amount == Null<Real>() && lockRate != Null<Real>()) ||
8586
(amount != Null<Real>() && lockRate == Null<Real>()),
8687
"ForwardBond: exactly one of Amount of LockRate must be given");
88+
QL_REQUIRE(dv01 >= 0.0, "negative DV01 given");
8789
QL_REQUIRE(compensationPaymentDate <= fwdMaturityDate, "Premium cannot be paid after forward contract maturity");
8890

8991
if (lockRate != Null<Real>())
@@ -138,7 +140,7 @@ void ForwardBond::build(const boost::shared_ptr<EngineFactory>& engineFactory) {
138140
: boost::make_shared<QuantExt::ForwardBond>(bond, lockRate, lockRateDayCounter, longInForward,
139141
fwdMaturityDate, fwdSettlementDate, isPhysicallySettled,
140142
settlementDirty, compensationPayment,
141-
compensationPaymentDate, bondData_.bondNotional());
143+
compensationPaymentDate, bondData_.bondNotional(), dv01);
142144

143145
boost::shared_ptr<fwdBondEngineBuilder> fwdBondBuilder =
144146
boost::dynamic_pointer_cast<fwdBondEngineBuilder>(builder_fwd);
@@ -177,6 +179,7 @@ void ForwardBond::fromXML(XMLNode* node) {
177179
lockRate_ = XMLUtils::getChildValue(fwdSettlementNode, "LockRate", false);
178180
lockRateDayCounter_ = XMLUtils::getChildValue(fwdSettlementNode, "LockRateDayCounter", false);
179181
settlementDirty_ = XMLUtils::getChildValue(fwdSettlementNode, "SettlementDirty", false);
182+
dv01_ = XMLUtils::getChildValue(fwdSettlementNode, "dv01", false);
180183

181184
XMLNode* fwdPremiumNode = XMLUtils::getChildNode(fwdBondNode, "PremiumData");
182185
if (fwdPremiumNode) {
@@ -207,6 +210,8 @@ XMLNode* ForwardBond::toXML(XMLDocument& doc) {
207210
XMLUtils::addChild(doc, fwdSettlementNode, "Amount", amount_);
208211
if (!lockRate_.empty())
209212
XMLUtils::addChild(doc, fwdSettlementNode, "LockRate", lockRate_);
213+
if (!dv01_.empty())
214+
XMLUtils::addChild(doc, fwdSettlementNode, "dv01", dv01_);
210215
if (!lockRateDayCounter_.empty())
211216
XMLUtils::addChild(doc, fwdSettlementNode, "LockRateDayCounter", lockRateDayCounter_);
212217
if (!settlementDirty_.empty())

OREData/ored/portfolio/forwardbond.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ class ForwardBond : public Trade {
3636
//! Constructor taking an envelope and bond data
3737
ForwardBond(Envelope env, const BondData& bondData, string fwdMaturityDate, string fwdSettlementDate,
3838
string settlement, string amount, string lockRate, string lockRateDayCounter, string settlementDirty,
39-
string compensationPayment, string compensationPaymentDate, string longInForward)
39+
string compensationPayment, string compensationPaymentDate, string longInForward, string dv01 = string())
4040
: Trade("ForwardBond", env), originalBondData_(bondData), bondData_(bondData),
4141
fwdMaturityDate_(fwdMaturityDate), fwdSettlementDate_(fwdSettlementDate), settlement_(settlement),
4242
amount_(amount), lockRate_(lockRate), lockRateDayCounter_(lockRateDayCounter),
4343
settlementDirty_(settlementDirty), compensationPayment_(compensationPayment),
44-
compensationPaymentDate_(compensationPaymentDate), longInForward_(longInForward) {}
44+
compensationPaymentDate_(compensationPaymentDate), longInForward_(longInForward), dv01_(dv01) {}
4545

4646
virtual void build(const boost::shared_ptr<EngineFactory>&) override;
4747

@@ -65,6 +65,7 @@ class ForwardBond : public Trade {
6565
const string& compensationPayment() const { return compensationPayment_; }
6666
const string& compensationPaymentDate() const { return compensationPaymentDate_; }
6767
const string& longInForward() const { return longInForward_; }
68+
const string& dv01() const { return dv01_; }
6869

6970
protected:
7071
BondData originalBondData_, bondData_;
@@ -80,6 +81,7 @@ class ForwardBond : public Trade {
8081
string compensationPayment_;
8182
string compensationPaymentDate_;
8283
string longInForward_;
84+
string dv01_;
8385
};
8486
} // namespace data
8587
} // namespace ore

QuantExt/qle/instruments/forwardbond.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,18 @@ ForwardBond::ForwardBond(const boost::shared_ptr<Bond>& underlying, const boost:
3030
: underlying_(underlying), payoff_(payoff), lockRate_(Null<Real>()), fwdMaturityDate_(fwdMaturityDate),
3131
fwdSettlementDate_(fwdSettlementDate), isPhysicallySettled_(isPhysicallySettled),
3232
settlementDirty_(settlementDirty), compensationPayment_(compensationPayment),
33-
compensationPaymentDate_(compensationPaymentDate), bondNotional_(bondNotional) {}
33+
compensationPaymentDate_(compensationPaymentDate), bondNotional_(bondNotional), dv01_(Null<Real>()) {}
3434

35-
ForwardBond::ForwardBond(const boost::shared_ptr<Bond>& underlying, const Real lockRate,
35+
ForwardBond::ForwardBond(const boost::shared_ptr<Bond>& underlying, const Real lockRate,
3636
const DayCounter& lockRateDayCounter, const bool longInForward, const Date& fwdMaturityDate,
3737
const Date& fwdSettlementDate, const bool isPhysicallySettled, const bool settlementDirty,
38-
const Real compensationPayment, const Date compensationPaymentDate, const Real bondNotional)
38+
const Real compensationPayment, const Date compensationPaymentDate,
39+
const Real bondNotional,const Real dv01)
3940
: underlying_(underlying), payoff_(nullptr), lockRate_(lockRate), lockRateDayCounter_(lockRateDayCounter),
4041
longInForward_(longInForward), fwdMaturityDate_(fwdMaturityDate), fwdSettlementDate_(fwdSettlementDate),
4142
isPhysicallySettled_(isPhysicallySettled), settlementDirty_(settlementDirty),
4243
compensationPayment_(compensationPayment), compensationPaymentDate_(compensationPaymentDate),
43-
bondNotional_(bondNotional) {}
44+
bondNotional_(bondNotional), dv01_(dv01) {}
4445

4546
bool ForwardBond::isExpired() const { return detail::simple_event(fwdMaturityDate_).hasOccurred(); }
4647

@@ -59,6 +60,7 @@ void ForwardBond::setupArguments(PricingEngine::arguments* args) const {
5960
arguments->compensationPayment = compensationPayment_;
6061
arguments->compensationPaymentDate = compensationPaymentDate_;
6162
arguments->bondNotional = bondNotional_;
63+
arguments->dv01 = dv01_;
6264
}
6365

6466
void ForwardBond::results::reset() {

QuantExt/qle/instruments/forwardbond.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ class ForwardBond : public Instrument {
5252
ForwardBond(const boost::shared_ptr<QuantLib::Bond>& underlying, const Real lockRate,
5353
const DayCounter& lockRateDayCounter, const bool longInForward, const Date& fwdMaturityDate,
5454
const Date& fwdSettlementDate, const bool isPhysicallySettled, const bool settlementDirty,
55-
const Real compensationPayment, const Date compensationPaymentDate, const Real bondNotional = 1.0);
55+
const Real compensationPayment, const Date compensationPaymentDate, const Real bondNotional = 1.0,
56+
const Real dv01 = Null<Real>());
5657

5758
//! \name Instrument interface
5859
//@{
@@ -79,6 +80,7 @@ class ForwardBond : public Instrument {
7980
Real compensationPayment_;
8081
Date compensationPaymentDate_;
8182
Real bondNotional_;
83+
Real dv01_;
8284
mutable Real underlyingIncome_;
8385
mutable Real underlyingSpotValue_;
8486
mutable Real forwardValue_;
@@ -99,6 +101,7 @@ class ForwardBond::arguments : public virtual PricingEngine::arguments {
99101
Real compensationPayment;
100102
Date compensationPaymentDate;
101103
Real bondNotional;
104+
Real dv01;
102105
void validate() const override;
103106
};
104107

QuantExt/qle/pricingengines/discountingforwardbondengine.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,17 +329,29 @@ boost::tuple<Real, Real> DiscountingForwardBondEngine::calculateForwardContractP
329329
Real price = forwardBondValue / arguments_.bondNotional / bd->notional(bondSettlementDate) * 100.0;
330330
Real yield = BondFunctions::yield(*bd, price, arguments_.lockRateDayCounter, Compounded, Semiannual,
331331
bondSettlementDate, 1E-10, 100, 0.05, Bond::Price::Dirty);
332-
Real dv01 = price / 100.0 *
333-
BondFunctions::duration(*bd, yield, arguments_.lockRateDayCounter, Compounded, Semiannual,
334-
Duration::Modified, bondSettlementDate);
332+
Real dv01;
333+
if (arguments_.dv01 != Null<Real>()) {
334+
335+
dv01 = arguments_.dv01;
336+
337+
} else {
338+
339+
dv01 = price / 100.0 *
340+
BondFunctions::duration(*bd, yield, arguments_.lockRateDayCounter, Compounded, Semiannual,
341+
Duration::Modified, bondSettlementDate);
342+
}
343+
335344
QL_REQUIRE(arguments_.longInForward, "DiscountingForwardBondEngine: internal error, longInForward must be "
336345
"populated if payoff is specified via lock-rate");
337346
Real multiplier = (*arguments_.longInForward) ? 1.0 : -1.0;
338347
forwardContractForwardValue = multiplier * (yield - arguments_.lockRate) * dv01 * arguments_.bondNotional *
339348
bd->notional(bondSettlementDate);
349+
340350
effectivePayoff = boost::make_shared<ForwardBondTypePayoff>(
341351
(*arguments_.longInForward) ? Position::Long : Position::Short,
342352
arguments_.lockRate * dv01 * arguments_.bondNotional * bd->notional(bondSettlementDate));
353+
354+
343355
} else {
344356
QL_FAIL("DiscountingForwardBondEngine: internal error, no payoff and no lock rate given, expected exactly one "
345357
"of them to be populated.");

xsd/instruments.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@
321321
<xs:element type="xs:string" name="Settlement" minOccurs="0"/>
322322
<xs:element type="xs:float" name="Amount" minOccurs="0"/>
323323
<xs:element type="xs:float" name="LockRate" minOccurs="0"/>
324+
<xs:element type="xs:float" name="dv01" minOccurs="0"/>
324325
<xs:element type="xs:string" name="LockRateDayCounter" minOccurs="0"/>
325326
<xs:element type="xs:string" name="SettlementDirty" minOccurs="0"/>
326327
</xs:all>

0 commit comments

Comments
 (0)