Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
bondoption.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
21
22#include <boost/lexical_cast.hpp>
33#include <ql/cashflows/simplecashflow.hpp>
34#include <ql/errors.hpp>
35#include <ql/exercise.hpp>
36#include <ql/instruments/bond.hpp>
37#include <ql/instruments/bonds/zerocouponbond.hpp>
38#include <ql/instruments/callabilityschedule.hpp>
39#include <ql/instruments/compositeinstrument.hpp>
40#include <ql/instruments/vanillaoption.hpp>
41#include <ql/termstructures/volatility/swaption/swaptionvolstructure.hpp>
42
43using namespace QuantLib;
44using namespace QuantExt;
45
46namespace ore {
47namespace data {
48
49void BondOption::build(const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
50 DLOG("Building Bond Option: " << id());
51
52 // ISDA taxonomy
53 additionalData_["isdaAssetClass"] = string("Interest Rate");
54 additionalData_["isdaBaseProduct"] = string("Option");
55 additionalData_["isdaSubProduct"] = string("Debt Option");
56 additionalData_["isdaTransaction"] = string("");
57
58 const QuantLib::ext::shared_ptr<Market> market = engineFactory->market();
59 QuantLib::ext::shared_ptr<EngineBuilder> builder = engineFactory->builder("BondOption");
60 bondData_ = originalBondData_;
61 bondData_.populateFromBondReferenceData(engineFactory->referenceData());
62
63 Calendar calendar = parseCalendar(bondData_.calendar());
64 QuantLib::ext::shared_ptr<QuantExt::BondOption> bondoption;
65
66 // FIXME this won't work for zero bonds (but their implementation is incomplete anyhow, see bond.cpp)
67 underlying_ = QuantLib::ext::make_shared<ore::data::Bond>(Envelope(), bondData_);
68
69 underlying_->build(engineFactory);
70
71 legs_ = underlying_->legs();
72 legCurrencies_ = underlying_->legCurrencies();
73 legPayers_ = std::vector<bool>(legs_.size(), false); // always receive (long option view)
74 npvCurrency_ = underlying_->bondData().currency();
75 notional_ = underlying_->notional() * bondData_.bondNotional();
76 notionalCurrency_ = underlying_->bondData().currency();
77 maturity_ = std::max(optionData_.premiumData().latestPremiumDate(), underlying_->maturity());
78
79 auto qlBondInstr = QuantLib::ext::dynamic_pointer_cast<QuantLib::Bond>(underlying_->instrument()->qlInstrument());
80 QL_REQUIRE(qlBondInstr, "BondOption::build(): could not cast to QuantLib::Bond");
81 for (auto const p : underlying_->legPayers()) {
82 QL_REQUIRE(!p, "BondOption::build(): underlying leg must be receiver");
83 }
84
85 boost::variant<QuantLib::Bond::Price, QuantLib::InterestRate> callabilityPrice;
86 if (strike_.type() == TradeStrike::Type::Price) {
87 if (priceType_ == "Dirty") {
88 callabilityPrice = QuantLib::Bond::Price(strike_.value(), QuantLib::Bond::Price::Dirty);
89 } else if (priceType_ == "Clean") {
90 callabilityPrice = QuantLib::Bond::Price(strike_.value(), QuantLib::Bond::Price::Clean);
91 } else {
92 QL_FAIL("BondOption::build(): price type \"" << priceType_ << "\" not recognised.");
93 }
94 } else {
95 // strike is quoted as a yield
96 DayCounter dayCounter = Actual365Fixed();
97 Frequency freq = Annual;
98 // attempt to get the daycounter and frequency from the bond
99 if (bondData_.coupons().size() > 0) {
100 auto cn = bondData_.coupons().front();
101 const string& dc = cn.dayCounter();
102 if (!dc.empty())
103 dayCounter = parseDayCounter(dc);
104 if (cn.schedule().rules().size() > 0)
105 freq = parsePeriod(cn.schedule().rules().front().tenor()).frequency();
106 }
107 callabilityPrice = QuantLib::InterestRate(strike_.value(), dayCounter, strike_.compounding(), freq);
108 }
109
110 Callability::Type callabilityType =
111 parseOptionType(optionData_.callPut()) == Option::Call ? Callability::Call : Callability::Put;
112
113 QL_REQUIRE(optionData_.exerciseDates().size() == 1,
114 "BondOption::build(): exactly one option date required, found " << optionData_.exerciseDates().size());
115 Date exerciseDate = parseDate(optionData_.exerciseDates().back());
116 QuantLib::ext::shared_ptr<Callability> callability;
117 callability.reset(new Callability(callabilityPrice, callabilityType, exerciseDate));
118 CallabilitySchedule callabilitySchedule = std::vector<QuantLib::ext::shared_ptr<Callability>>(1, callability);
119
120 bondoption.reset(new QuantExt::BondOption(qlBondInstr, callabilitySchedule, knocksOut_));
121
122 Currency currency = parseCurrency(underlying_->bondData().currency());
123
124 QuantLib::ext::shared_ptr<BondOptionEngineBuilder> bondOptionBuilder =
125 QuantLib::ext::dynamic_pointer_cast<BondOptionEngineBuilder>(builder);
126 QL_REQUIRE(bondOptionBuilder, "No Builder found for bondOption: " << id());
127
128 QuantLib::ext::shared_ptr<BlackBondOptionEngine> blackEngine = QuantLib::ext::dynamic_pointer_cast<BlackBondOptionEngine>(
129 bondOptionBuilder->engine(id(), currency, bondData_.creditCurveId(), bondData_.hasCreditRisk(),
130 bondData_.securityId(), bondData_.referenceCurveId(), bondData_.volatilityCurveId()));
131 bondoption->setPricingEngine(blackEngine);
132 setSensitivityTemplate(*bondOptionBuilder);
133
134 Real multiplier =
135 bondData_.bondNotional() * (parsePositionType(optionData_.longShort()) == Position::Long ? 1.0 : -1.0);
136
137 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
138 std::vector<Real> additionalMultipliers;
139 addPremiums(additionalInstruments, additionalMultipliers, multiplier, optionData_.premiumData(),
140 multiplier > 0.0 ? -1.0 : 1.0, currency, engineFactory,
141 bondOptionBuilder->configuration(MarketContext::pricing));
142
143 instrument_.reset(new VanillaInstrument(bondoption, multiplier, additionalInstruments, additionalMultipliers));
144
145 // the required fixings are (at most) those of the underlying
146 requiredFixings_ = underlying_->requiredFixings();
147}
148
149void BondOption::fromXML(XMLNode* node) {
150 Trade::fromXML(node);
151
152 XMLNode* bondOptionNode = XMLUtils::getChildNode(node, "BondOptionData");
153 QL_REQUIRE(bondOptionNode, "No BondOptionData Node");
154 optionData_.fromXML(XMLUtils::getChildNode(bondOptionNode, "OptionData"));
155 strike_.fromXML(bondOptionNode, true, true);
156 redemption_ = XMLUtils::getChildValueAsDouble(bondOptionNode, "Redemption", false, 100.0);
157 // don't need PriceType id a yield strike is provided
158 if (strike_.type() == TradeStrike::Type::Price)
159 priceType_ = XMLUtils::getChildValue(bondOptionNode, "PriceType", true);
160 if (auto n = XMLUtils::getChildNode(bondOptionNode, "KnocksOut"))
161 knocksOut_ = parseBool(XMLUtils::getNodeValue(n));
162 else
163 knocksOut_ = false;
164
165 originalBondData_.fromXML(XMLUtils::getChildNode(bondOptionNode, "BondData"));
166 bondData_ = originalBondData_;
167}
168
169XMLNode* BondOption::toXML(XMLDocument& doc) const {
170 XMLNode* node = Trade::toXML(doc);
171
172 XMLNode* bondOptionNode = doc.allocNode("BondOptionData");
173 XMLUtils::appendNode(node, bondOptionNode);
174 XMLUtils::appendNode(bondOptionNode, optionData_.toXML(doc));
175 XMLUtils::appendNode(bondOptionNode, strike_.toXML(doc));
176 XMLUtils::addChild(doc, bondOptionNode, "Redemption", redemption_);
177 if (!priceType_.empty())
178 XMLUtils::addChild(doc, bondOptionNode, "PriceType", priceType_);
179 XMLUtils::addChild(doc, bondOptionNode, "KnocksOut", knocksOut_);
180
181 XMLUtils::appendNode(bondOptionNode, originalBondData_.toXML(doc));
182 return node;
183}
184
185std::map<AssetClass, std::set<std::string>>
186BondOption::underlyingIndices(const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceDataManager) const {
187 std::map<AssetClass, std::set<std::string>> result;
188 result[AssetClass::BOND] = {bondData_.securityId()};
189 return result;
190}
191} // namespace data
192} // namespace ore
Bond trade data model and serialization.
bond option data model and serialization
bond utilities
builder that returns an engine to price a bond instrument
Engine builder for bond option.
const CallabilitySchedule & callability() const
const boost::shared_ptr< QuantLib::Bond > underlying_
virtual void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Definition: bondoption.cpp:49
Serializable object holding generic trade data, reporting dimensions.
Definition: envelope.hpp:51
Vanilla Instrument Wrapper.
Small XML Document wrapper class.
Definition: xmlutils.hpp:65
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
Definition: xmlutils.cpp:132
Pricing Engine Factory.
Logic for calculating required fixing dates on legs.
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
Definition: parsers.cpp:157
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Definition: parsers.cpp:51
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Definition: parsers.cpp:290
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Definition: parsers.cpp:404
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Definition: parsers.cpp:171
bool parseBool(const string &s)
Convert text to bool.
Definition: parsers.cpp:144
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Definition: parsers.cpp:209
Option::Type parseOptionType(const std::string &s)
Convert text to QuantLib::Option::Type.
Definition: parsers.cpp:481
Map text representations to QuantLib/QuantExt types.
leg data model and serialization
Classes and functions for log message handling.
@ data
Definition: log.hpp:77
#define DLOG(text)
Logging Macro (Level = Debug)
Definition: log.hpp:554
Calendar calendar
Definition: utilities.cpp:441
Serializable Credit Default Swap.
Definition: namespaces.docs:23
Map text representations to QuantLib/QuantExt types.
Swap trade data model and serialization.