19#include <ql/cashflows/coupon.hpp>
20#include <ql/cashflows/simplecashflow.hpp>
21#include <ql/exercise.hpp>
22#include <ql/instruments/compositeinstrument.hpp>
23#include <ql/instruments/swaption.hpp>
24#include <ql/time/daycounters/actualactual.hpp>
28#include <qle/pricingengines/blackmultilegoptionengine.hpp>
39#include <boost/algorithm/string/case_conv.hpp>
40#include <boost/timer/timer.hpp>
44using boost::timer::cpu_timer;
45using boost::timer::default_places;
47using std::lower_bound;
54QuantLib::Settlement::Method defaultSettlementMethod(
const QuantLib::Settlement::Type t) {
55 if (t == QuantLib::Settlement::Physical)
56 return QuantLib::Settlement::PhysicalOTC;
58 return QuantLib::Settlement::ParYieldCurve;
62void Swaption::build(
const QuantLib::ext::shared_ptr<EngineFactory>& engineFactory) {
64 DLOG(
"Swaption::build() for " <<
id());
89 DLOG(
"Swaption::build() for " <<
id() <<
": build exercise");
101 Date today = Settings::instance().evaluationDate();
107 maturity_ = std::max(today, exerciseDate);
114 legs_.push_back(Leg());
118 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c)) {
119 if (exerciseDate <= cpn->accrualStartDate()) {
120 legs_.back().push_back(c);
125 }
else if (exerciseDate <= c->date()) {
126 legs_.back().push_back(c);
137 legs_.push_back(Leg());
148 legs_.push_back(Leg());
157 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
158 std::vector<Real> additionalMultipliers;
159 Date lastPremiumDate =
addPremiums(additionalInstruments, additionalMultipliers, Position::Long ? 1.0 : -1.0,
163 auto builder = QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(engineFactory->builder(
"Swap"));
164 QL_REQUIRE(builder,
"could not get swap builder to build exercised swaption instrument.");
165 auto swap = QuantLib::ext::make_shared<QuantLib::Swap>(
legs_,
legPayers_);
167 envelope().additionalField(
"discount_curve",
false),
168 envelope().additionalField(
"security_spread",
false)));
171 additionalInstruments, additionalMultipliers);
173 DLOG(
"Building exercised swaption done.");
181 legs_ = {{QuantLib::ext::make_shared<QuantLib::SimpleCashFlow>(0.0, today)}};
185 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
186 std::vector<Real> additionalMultipliers;
187 Date lastPremiumDate =
addPremiums(additionalInstruments, additionalMultipliers, Position::Long ? 1.0 : -1.0,
191 auto builder = QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(engineFactory->builder(
"Swap"));
192 QL_REQUIRE(builder,
"could not get swap builder to build expired swaption instrument.");
193 auto swap = QuantLib::ext::make_shared<QuantLib::Swap>(
legs_,
legPayers_);
195 envelope().additionalField(
"discount_curve",
false),
196 envelope().additionalField(
"security_spread",
false)));
198 additionalInstruments, additionalMultipliers);
201 DLOG(
"Building (non-exercised) swaption without alive exercise dates done.");
212 legs_.push_back(Leg());
213 for (
auto const& c : l) {
214 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c)) {
215 if (firstExerciseDate <= cpn->accrualStartDate()) {
216 legs_.back().push_back(c);
218 }
else if (firstExerciseDate <= c->date()) {
219 legs_.back().push_back(c);
233 WLOG(
"Cash-settled Bermudan/American Swaption (id = "
234 <<
id() <<
") with ParYieldCurve settlement method not supported by Lgm engine. "
235 <<
"Approximate pricing using CollateralizedCashPrice pricing methodology");
237 std::vector<QuantLib::Currency> ccys;
244 std::string builderType;
245 std::vector<std::string> builderPrecheckMessages;
248 QuantExt::BlackMultiLegOptionEngineBase::instrumentIsHandled(*swaption, builderPrecheckMessages)) {
249 builderType =
"EuropeanSwaption";
252 QuantExt::NumericLgmMultiLegOptionEngineBase::instrumentIsHandled(*swaption, builderPrecheckMessages),
253 "Swaption::build(): instrument is not handled by the available engines: " +
254 boost::join(builderPrecheckMessages,
", "));
256 builderType =
"BermudanSwaption";
258 builderType =
"AmericanSwaption";
261 DLOG(
"Getting builder for '" << builderType <<
"', got " << builderPrecheckMessages.size()
262 <<
" builder precheck messages:");
263 for (
auto const& m : builderPrecheckMessages) {
267 auto swaptionBuilder = QuantLib::ext::dynamic_pointer_cast<SwaptionEngineBuilder>(engineFactory->builder(builderType));
268 QL_REQUIRE(swaptionBuilder,
"Swaption::build(): internal error: could not cast to SwaptionEngineBuilder");
270 auto swapBuilder = QuantLib::ext::dynamic_pointer_cast<SwapEngineBuilderBase>(engineFactory->builder(
"Swap"));
271 QL_REQUIRE(swapBuilder,
"Swaption::build(): internal error: could not cast to SwapEngineBuilder");
275 QuantLib::ext::shared_ptr<InterestRateIndex> index;
278 for (
auto const& c : l) {
279 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(c)) {
280 if (index ==
nullptr) {
281 if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<IborIndex>(cpn->index())) {
282 DLOG(
"found ibor / ois index '" << tmp->name() <<
"'");
284 }
else if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<SwapIndex>(cpn->index())) {
285 DLOG(
"found cms index " << tmp->name() <<
", use key '" << tmp->iborIndex()->name()
286 <<
"' to look up vol");
287 index = tmp->iborIndex();
288 }
else if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<BMAIndex>(cpn->index())) {
289 DLOG(
"found bma/sifma index '" << tmp->name() <<
"'");
297 if (index ==
nullptr) {
298 DLOG(
"no ibor, ois, bma/sifma, cms index found, use ccy key to look up vol");
305 Real firstFixedRate = Null<Real>(), lastFixedRate = Null<Real>();
306 Real firstFloatSpread = Null<Real>(), lastFloatSpread = Null<Real>();
308 for (
auto const& c : l) {
309 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<FixedRateCoupon>(c)) {
310 if (cpn->accrualStartDate() >=
exerciseBuilder_->noticeDates()[i] && firstFixedRate == Null<Real>())
311 firstFixedRate = cpn->rate();
312 lastFixedRate = cpn->rate();
313 }
else if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(c)) {
315 firstFloatSpread == Null<Real>())
316 firstFloatSpread = cpn->spread();
317 lastFloatSpread = cpn->spread();
318 if (index ==
nullptr) {
319 if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<IborIndex>(cpn->index())) {
320 DLOG(
"found ibor / ois index '" << tmp->name() <<
"'");
322 }
else if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<SwapIndex>(cpn->index())) {
323 DLOG(
"found cms index " << tmp->name() <<
", use key '" << tmp->iborIndex()->name()
324 <<
"' to look up vol");
325 index = tmp->iborIndex();
326 }
else if (
auto tmp = QuantLib::ext::dynamic_pointer_cast<BMAIndex>(cpn->index())) {
327 DLOG(
"found bma/sifma index '" << tmp->name() <<
"'");
335 if(firstFixedRate == Null<Real>())
336 firstFixedRate = lastFixedRate;
337 if(firstFloatSpread == Null<Real>())
338 firstFloatSpread = lastFloatSpread;
340 if (firstFixedRate != Null<Real>()) {
342 if (firstFloatSpread != Null<Real>()) {
343 strikes[i] -= firstFloatSpread;
346 DLOG(
"calibration strike for ex date "
348 << (
strikes[i] == Null<Real>() ?
"ATMF" : std::to_string(
strikes[i])) <<
" (fixed rate "
349 << (firstFixedRate == Null<Real>() ?
"NA" : std::to_string(firstFixedRate)) <<
", spread "
350 << (firstFloatSpread == Null<Real>() ?
"NA" : std::to_string(firstFloatSpread)) <<
")");
357 auto swaptionEngine = swaptionBuilder->engine(
358 id(), index ==
nullptr ?
npvCurrency_ : IndexNameTranslator::instance().oreName(index->name()),
360 envelope().additionalField(
"discount_curve",
false),
envelope().additionalField(
"security_spread",
false));
362 DLOG(
"Swaption model calibration time: " << timer.format(default_places,
"%w") <<
" s");
363 swaption->setPricingEngine(swaptionEngine);
370 envelope().additionalField(
"security_spread",
false));
372 std::vector<QuantLib::ext::shared_ptr<Instrument>> underlyingSwaps =
375 std::vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
376 std::vector<Real> additionalMultipliers;
377 Real multiplier =
positionType_ == Position::Long ? 1.0 : -1.0;
378 Date lastPremiumDate =
addPremiums(additionalInstruments, additionalMultipliers, Position::Long ? 1.0 : -1.0,
382 instrument_ = QuantLib::ext::make_shared<BermudanOptionWrapper>(
384 settlementType_ == Settlement::Physical ?
true :
false, underlyingSwaps, 1.0, 1.0, additionalInstruments,
385 additionalMultipliers);
389 DLOG(
"Building Swaption done");
392std::vector<QuantLib::ext::shared_ptr<Instrument>>
394 const std::vector<Date>& exerciseDates) {
395 std::vector<QuantLib::ext::shared_ptr<Instrument>> swaps;
396 for (Size i = 0; i < exerciseDates.size(); ++i) {
398 std::vector<bool> payer =
underlying_->legPayers();
399 for (Size j = 0; j <
legs.size(); ++j) {
400 Date ed = exerciseDates[i];
401 auto it = std::lower_bound(
legs[j].begin(),
legs[j].end(), exerciseDates[i],
402 [&ed](
const QuantLib::ext::shared_ptr<CashFlow>& c,
const Date& d) {
403 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(c)) {
404 return cpn->accrualStartDate() < ed;
406 return c->date() < ed;
409 if (it !=
legs[j].begin())
413 auto newSwap = QuantLib::ext::make_shared<QuantLib::Swap>(
legs, payer);
414 if (swapEngine !=
nullptr) {
415 newSwap->setPricingEngine(swapEngine);
417 swaps.push_back(newSwap);
418 for (
auto const& l :
legs) {
420 WLOG(
"Added empty leg to underlying swap for exercise " << QuantLib::io::iso_date(exerciseDates[i])
424 if (
auto cpn = QuantLib::ext::dynamic_pointer_cast<Coupon>(l.front())) {
425 d = cpn->accrualStartDate();
427 d = l.front()->date();
429 DLOG(
"Added leg with start date " << QuantLib::io::iso_date(d) <<
" for exercise "
430 << QuantLib::io::iso_date(exerciseDates[i]));
449 Date asof = Settings::instance().evaluationDate();
450 for (Size i = 0; i < std::min(
legData_.size(),
legs_.size()); ++i) {
455 for (Size j = 0; j <
legs_[i].size(); ++j) {
456 QuantLib::ext::shared_ptr<CashFlow> flow =
legs_[i][j];
458 if (flow->date() > asof) {
461 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(flow);
465 QuantLib::ext::shared_ptr<FloatingRateCoupon> frc = QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(flow);
475 QuantLib::ext::shared_ptr<Coupon> coupon = QuantLib::ext::dynamic_pointer_cast<Coupon>(
legs_[i][0]);
477 additionalData_[
"originalNotional[" + legID +
"]"] = coupon->nominal();
489 for (Size i = 0; i < nodes.size(); i++) {
502 for (Size i = 0; i <
legData_.size(); i++)
508map<AssetClass, set<string>>
510 map<AssetClass, set<string>> result;
511 if (
auto s =
envelope().additionalField(
"security_spread",
false); !s.empty())
Engine builder for Swaps.
Serializable object holding generic trade data, reporting dimensions.
Serializable object holding leg data.
virtual void fromXML(XMLNode *node) override
const string & settlementMethod() const
const string & longShort() const
const string & style() const
const string & settlement() const
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
const PremiumData & premiumData() const
void addData(const RequiredFixings &requiredFixings)
std::vector< QuantLib::ext::shared_ptr< Instrument > > buildUnderlyingSwaps(const QuantLib::ext::shared_ptr< PricingEngine > &, const std::vector< Date > &)
build underlying swaps for exposure simulation
QuantLib::ext::shared_ptr< ExerciseBuilder > exerciseBuilder_
vector< LegData > legData_
QuantLib::Real notional() const override
Return the current notional in npvCurrency. See individual sub-classes for the precise definition.
virtual void fromXML(XMLNode *node) override
virtual XMLNode * toXML(XMLDocument &doc) const override
std::map< AssetClass, std::set< std::string > > underlyingIndices(const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceDataManager=nullptr) const override
QuantLib::ext::shared_ptr< ore::data::Swap > underlying_
Exercise::Type exerciseType_
Settlement::Method settlementMethod_
Settlement::Type settlementType_
void build(const QuantLib::ext::shared_ptr< EngineFactory > &) override
Position::Type positionType_
const std::map< std::string, boost::any > & additionalData() const override
returns all additional data returned by the trade once built
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
const std::vector< QuantLib::Leg > & legs() const
std::vector< QuantLib::Leg > legs_
virtual void fromXML(XMLNode *node) override
Date addPremiums(std::vector< QuantLib::ext::shared_ptr< Instrument > > &instruments, std::vector< Real > &multipliers, const Real tradeMultiplier, const PremiumData &premiumData, const Real premiumMultiplier, const Currency &tradeCurrency, const QuantLib::ext::shared_ptr< EngineFactory > &factory, const string &configuration)
void setSensitivityTemplate(const EngineBuilder &builder)
virtual XMLNode * toXML(XMLDocument &doc) const override
RequiredFixings requiredFixings_
const Envelope & envelope() const
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
Small XML Document wrapper class.
XMLNode * allocNode(const string &nodeName)
util functions that wrap rapidxml
static vector< XMLNode * > getChildrenNodes(XMLNode *node, const string &name)
Returns all the children with a given name.
static XMLNode * getChildNode(XMLNode *n, const string &name="")
static void appendNode(XMLNode *parent, XMLNode *child)
Exercise::Type parseExerciseType(const std::string &s)
Convert text to QuantLib::Exercise::Type.
Settlement::Method parseSettlementMethod(const std::string &s)
Convert text to QuantLib::Settlement::Method.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
translates between QuantLib::Index::name() and ORE names
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
Real currentNotional(const Leg &leg)
Size size(const ValueType &v)
std::string to_string(const LocationInfo &l)
Serializable Credit Default Swap.
Wrapper for option instruments, tracks whether option has been exercised or not.
Swaption data model and serialization.
string conversion utilities