Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
bondindex.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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
19#include <ql/cashflows/cpicoupon.hpp>
20#include <ql/settings.hpp>
24
25#include <boost/make_shared.hpp>
26
27namespace QuantExt {
28
29BondIndex::BondIndex(const std::string& securityName, const bool dirty, const bool relative,
30 const Calendar& fixingCalendar, const QuantLib::ext::shared_ptr<QuantLib::Bond>& bond,
31 const Handle<YieldTermStructure>& discountCurve,
32 const Handle<DefaultProbabilityTermStructure>& defaultCurve, const Handle<Quote>& recoveryRate,
33 const Handle<Quote>& securitySpread, const Handle<YieldTermStructure>& incomeCurve,
34 const bool conditionalOnSurvival, const Date& issueDate, const PriceQuoteMethod priceQuoteMethod,
35 const double priceQuoteBaseValue, const bool isInflationLinked, const double bidAskAdjustment,
36 const bool bondIssueDateFallback)
37 : securityName_(securityName), dirty_(dirty), relative_(relative), fixingCalendar_(fixingCalendar), bond_(bond),
38 discountCurve_(discountCurve), defaultCurve_(defaultCurve), recoveryRate_(recoveryRate),
39 securitySpread_(securitySpread), incomeCurve_(incomeCurve), conditionalOnSurvival_(conditionalOnSurvival),
40 issueDate_(issueDate), priceQuoteMethod_(priceQuoteMethod), priceQuoteBaseValue_(priceQuoteBaseValue),
41 isInflationLinked_(isInflationLinked), bidAskAdjustment_(bidAskAdjustment),
42 bondIssueDateFallback_(bondIssueDateFallback) {
43
44 registerWith(Settings::instance().evaluationDate());
45 registerWith(IndexManager::instance().notifier(BondIndex::name()));
46 registerWith(bond_);
47 registerWith(discountCurve_);
48 registerWith(defaultCurve_);
49 registerWith(recoveryRate_);
50 registerWith(securitySpread_);
51 registerWith(incomeCurve_);
52
53 vanillaBondEngine_ = QuantLib::ext::make_shared<DiscountingRiskyBondEngine>(discountCurve, defaultCurve, recoveryRate,
54 securitySpread, 6 * Months, boost::none);
55}
56
57std::string BondIndex::name() const { return "BOND-" + securityName_; }
58
59Calendar BondIndex::fixingCalendar() const { return fixingCalendar_; }
60
61bool BondIndex::isValidFixingDate(const Date& d) const { return fixingCalendar().isBusinessDay(d); }
62
63void BondIndex::update() { notifyObservers(); }
64
65Real BondIndex::fixing(const Date& fixingDate, bool forecastTodaysFixing) const {
66 //! this logic is the same as in InterestRateIndex
67 QL_REQUIRE(isValidFixingDate(fixingDate), "Fixing date " << fixingDate << " is not valid for '" << name() << "'");
68 Date today = Settings::instance().evaluationDate();
69 if (fixingDate > today || (fixingDate == today && forecastTodaysFixing))
70 return forecastFixing(fixingDate);
72 if (fixingDate < today || Settings::instance().enforcesTodaysHistoricFixings()) {
73 // must have been fixed
74 // do not catch exceptions
75 Rate result = pastFixing(fixingDate);
76 QL_REQUIRE(result != Null<Real>(), "Missing " << name() << " fixing for " << fixingDate);
77 return result * adj;
78 }
79 try {
80 // might have been fixed
81 Rate result = pastFixing(fixingDate);
82 if (result != Null<Real>())
83 return result * adj;
84 else
85 ; // fall through and forecast
86 } catch (Error&) {
87 ; // fall through and forecast
88 }
89 return forecastFixing(fixingDate);
90}
91
92Rate BondIndex::forecastFixing(const Date& fixingDate) const {
93 Date today = Settings::instance().evaluationDate();
94 QL_REQUIRE(fixingDate >= today,
95 "BondIndex::forecastFixing(): fixingDate (" << fixingDate << ") must be >= today (" << today << ")");
96 QL_REQUIRE(bond_, "BondIndex::forecastFixing(): bond required");
97
98 // on today, try to get the dirty absolute price from the bond itself
99
100 Real price = Null<Real>();
101 if (fixingDate == today) {
102 try {
103 price = bond_->settlementValue();
104 } catch (...) {
105 }
106 }
107
108 // for future dates or if the above did not work, assume that the bond can be priced by
109 // simply discounting its cashflows
110
111 if (price == Null<Real>()) {
112 auto res = vanillaBondEngine_->calculateNpv(bond_->settlementDate(fixingDate),
113 bond_->settlementDate(fixingDate), bond_->cashflows(), boost::none,
115 price = res.npv;
116 }
117
118 price += bidAskAdjustment_ * bond_->notional(fixingDate);
119
120 if (!dirty_) {
121 price -= bond_->accruedAmount(fixingDate) / 100.0 * bond_->notional(fixingDate);
122 }
123
124 if (relative_) {
125 if (close_enough(bond_->notional(fixingDate), 0.0))
126 price = 0.0;
127 else
128 price /= bond_->notional(fixingDate);
129 }
130
131 return price;
132}
133
134Real BondIndex::pastFixing(const Date& fixingDate) const {
135 QL_REQUIRE(isValidFixingDate(fixingDate), fixingDate << " is not a valid fixing date for '" << name() << "'");
136
137 Date fd = (bondIssueDateFallback_ && fixingDate < issueDate_) ? issueDate_ : fixingDate;
138
139 Real price = timeSeries()[fd] + bidAskAdjustment_;
140 if (price == Null<Real>())
141 return price;
142 if (dirty_) {
143 QL_REQUIRE(bond_, "BondIndex::pastFixing(): bond required for dirty prices");
144 price += bond_->accruedAmount(fd) / 100.0;
145 }
146
147 if (isInflationLinked_) {
149 }
150
151 if (!relative_) {
152 QL_REQUIRE(bond_, "BondIndex::pastFixing(): bond required for absolute prices");
153 price *= bond_->notional(fd);
154 }
155 return price;
156}
157
158BondFuturesIndex::BondFuturesIndex(const QuantLib::Date& expiryDate, const std::string& securityName, const bool dirty,
159 const bool relative, const Calendar& fixingCalendar,
160 const QuantLib::ext::shared_ptr<QuantLib::Bond>& bond,
161 const Handle<YieldTermStructure>& discountCurve,
162 const Handle<DefaultProbabilityTermStructure>& defaultCurve,
163 const Handle<Quote>& recoveryRate, const Handle<Quote>& securitySpread,
164 const Handle<YieldTermStructure>& incomeCurve, const bool conditionalOnSurvival,
165 const Date& issueDate, const PriceQuoteMethod priceQuoteMethod, const double priceQuoteBaseValue)
166 : BondIndex(securityName, dirty, relative, fixingCalendar, bond, discountCurve, defaultCurve, recoveryRate,
167 securitySpread, incomeCurve, conditionalOnSurvival, issueDate, priceQuoteMethod, priceQuoteBaseValue),
168 expiryDate_(expiryDate) {}
169
170std::string BondFuturesIndex::name() const {
171 if (name_ == "") {
172 std::ostringstream o;
173 o << "BOND-" << securityName() << "-" << QuantLib::io::iso_date(expiryDate_);
174 name_ = o.str();
175 // Remove the "-dd" portion from the expiry date
176 name_.erase(name_.length() - 3);
177 }
178
179 return name_;
180}
181
182Rate BondFuturesIndex::forecastFixing(const Date& fixingDate) const {
183 Date today = Settings::instance().evaluationDate();
184 QL_REQUIRE(fixingDate >= today, "BondFuturesIndex::forecastFixing(): fixingDate ("
185 << fixingDate << ") must be >= today (" << today << ")");
186 QL_REQUIRE(bond_, "BondFuturesIndex::forecastFixing(): bond required");
187
188 auto bondNpvResults = vanillaBondEngine_->calculateNpv(bond()->settlementDate(expiryDate_),
189 bond()->settlementDate(expiryDate_), bond()->cashflows(),
190 boost::none, incomeCurve(), conditionalOnSurvival(), false);
191 Real price = bondNpvResults.npv;
192
193 if (!dirty()) {
194 price -= bond()->accruedAmount(expiryDate_) / 100.0 * bond()->notional(expiryDate_);
195 }
196
197 if (relative()) {
198 if (close_enough(bond()->notional(expiryDate_), 0.0))
199 price = 0.0;
200 else
201 price /= bond()->notional(expiryDate_);
202 }
203
204 return price;
205}
206
207Date ConstantMaturityBondIndex::maturityDate(const Date& valueDate) const {
208 // same as IborIndex
209 return fixingCalendar().advance(valueDate, tenor_, convention_, endOfMonth_);
210}
211
212Rate ConstantMaturityBondIndex::forecastFixing(const Date& fixingDate) const {
213 QL_REQUIRE(bond_, "cannot forecast ConstantMaturityBondIndex fixing, because underlying bond not set");
214 QL_REQUIRE(fixingDate == bondStartDate_, "bond yield fixing only available at bond start date, "
215 << io::iso_date(fixingDate) << " != " << io::iso_date(bondStartDate_));
216 return bond_->yield(dayCounter_, compounding_, frequency_, accuracy_, maxEvaluations_, guess_, priceType_);
217}
218
219} // namespace QuantExt
bond index class representing historical and forward bond prices
std::string name() const override
Definition: bondindex.cpp:170
Rate forecastFixing(const Date &fixingDate) const override
Definition: bondindex.cpp:182
BondFuturesIndex(const QuantLib::Date &expiryDate, const std::string &securityName, const bool dirty=false, const bool relative=true, const Calendar &fixingCalendar=NullCalendar(), const QuantLib::ext::shared_ptr< QuantLib::Bond > &bond=nullptr, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Handle< DefaultProbabilityTermStructure > &defaultCurve=Handle< DefaultProbabilityTermStructure >(), const Handle< Quote > &recoveryRate=Handle< Quote >(), const Handle< Quote > &securitySpread=Handle< Quote >(), const Handle< YieldTermStructure > &incomeCurve=Handle< YieldTermStructure >(), const bool conditionalOnSurvival=true, const Date &issueDate=Date(), const PriceQuoteMethod priceQuoteMethod=PriceQuoteMethod::PercentageOfPar, const double priceQuoteBaseValue=1.0)
Definition: bondindex.cpp:158
bool dirty() const
Definition: bondindex.hpp:123
BondIndex(const std::string &securityName, const bool dirty=false, const bool relative=true, const Calendar &fixingCalendar=NullCalendar(), const QuantLib::ext::shared_ptr< QuantLib::Bond > &bond=nullptr, const Handle< YieldTermStructure > &discountCurve=Handle< YieldTermStructure >(), const Handle< DefaultProbabilityTermStructure > &defaultCurve=Handle< DefaultProbabilityTermStructure >(), const Handle< Quote > &recoveryRate=Handle< Quote >(), const Handle< Quote > &securitySpread=Handle< Quote >(), const Handle< YieldTermStructure > &incomeCurve=Handle< YieldTermStructure >(), const bool conditionalOnSurvival=true, const Date &issueDate=Date(), const PriceQuoteMethod priceQuoteMethod=PriceQuoteMethod::PercentageOfPar, const double priceQuoteBaseValue=1.0, const bool isInflationLinked=false, const double bidAskAdjustment=0.0, const bool bondIssueDateFallback=false)
Definition: bondindex.cpp:29
const std::string & securityName() const
Definition: bondindex.hpp:122
virtual Rate forecastFixing(const Date &fixingDate) const
Definition: bondindex.cpp:92
Handle< YieldTermStructure > discountCurve_
Definition: bondindex.hpp:142
Handle< Quote > recoveryRate() const
Definition: bondindex.hpp:128
double priceQuoteBaseValue_
Definition: bondindex.hpp:150
Handle< YieldTermStructure > incomeCurve_
Definition: bondindex.hpp:146
void update() override
Definition: bondindex.cpp:63
std::string securityName_
Definition: bondindex.hpp:138
Calendar fixingCalendar() const override
Definition: bondindex.cpp:59
Handle< YieldTermStructure > discountCurve() const
Definition: bondindex.hpp:126
bool conditionalOnSurvival() const
Definition: bondindex.hpp:131
Handle< DefaultProbabilityTermStructure > defaultCurve() const
Definition: bondindex.hpp:127
Handle< YieldTermStructure > incomeCurve() const
Definition: bondindex.hpp:130
PriceQuoteMethod priceQuoteMethod_
Definition: bondindex.hpp:149
Rate pastFixing(const Date &fixingDate) const
Definition: bondindex.cpp:134
std::string name() const override
Definition: bondindex.cpp:57
Handle< Quote > securitySpread_
Definition: bondindex.hpp:145
Handle< Quote > securitySpread() const
Definition: bondindex.hpp:129
bool relative() const
Definition: bondindex.hpp:124
QuantLib::ext::shared_ptr< QuantLib::Bond > bond() const
Definition: bondindex.hpp:125
Handle< DefaultProbabilityTermStructure > defaultCurve_
Definition: bondindex.hpp:143
bool isValidFixingDate(const Date &fixingDate) const override
Definition: bondindex.cpp:61
QuantLib::ext::shared_ptr< DiscountingRiskyBondEngine > vanillaBondEngine_
Definition: bondindex.hpp:153
QuantLib::ext::shared_ptr< QuantLib::Bond > bond_
Definition: bondindex.hpp:141
Calendar fixingCalendar_
Definition: bondindex.hpp:140
Handle< Quote > recoveryRate_
Definition: bondindex.hpp:144
Real fixing(const Date &fixingDate, bool forecastTodaysFixing=false) const override
Definition: bondindex.cpp:65
Date maturityDate(const Date &valueDate) const override
Definition: bondindex.cpp:207
BusinessDayConvention convention_
Definition: bondindex.hpp:251
ext::shared_ptr< Bond > bond_
Definition: bondindex.hpp:253
Rate forecastFixing(const Date &fixingDate) const override
Definition: bondindex.cpp:212
const Bond & bond_
some inflation related utilities.
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
Real inflationLinkedBondQuoteFactor(const QuantLib::ext::shared_ptr< QuantLib::Bond > &bond)
Definition: inflation.cpp:83