62 {
63
64 DLOG(
"Swaption::build() for " <<
id());
65
66
67
72
73
74
76
79 }
80
81
82
86
87
88
89 DLOG(
"Swaption::build() for " <<
id() <<
": build exercise");
90
92
98
100
101 Date today = Settings::instance().evaluationDate();
102
103
104
107 maturity_ = std::max(today, exerciseDate);
108
110
111
112
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);
124 }
125 } else if (exerciseDate <= c->date()) {
126 legs_.back().push_back(c);
128 }
129 }
130 }
131
132 } else {
133
134
135
137 legs_.push_back(Leg());
142 }
143 }
144
145
146
148 legs_.push_back(Leg());
153 }
154
155
156
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.");
174 return;
175 }
176
177
178
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.");
202 return;
203 }
204
205
206
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);
217 }
218 } else if (firstExerciseDate <= c->date()) {
219 legs_.back().push_back(c);
220 }
221 }
222 }
223
224
225
228 else
230
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");
236
237 std::vector<QuantLib::Currency> ccys;
240 auto swaption =
243
244 std::string builderType;
245 std::vector<std::string> builderPrecheckMessages;
246
248 QuantExt::BlackMultiLegOptionEngineBase::instrumentIsHandled(*swaption, builderPrecheckMessages)) {
249 builderType = "EuropeanSwaption";
250 } else {
251 QL_REQUIRE(
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";
259 }
260
261 DLOG(
"Getting builder for '" << builderType <<
"', got " << builderPrecheckMessages.size()
262 << " builder precheck messages:");
263 for (auto const& m : builderPrecheckMessages) {
265 }
266
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");
269
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");
272
273
274
275 QuantLib::ext::shared_ptr<InterestRateIndex> index;
276
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() <<
"'");
283 index = tmp;
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() <<
"'");
290 index = tmp;
291 }
292 }
293 }
294 }
295 }
296
297 if (index == nullptr) {
298 DLOG(
"no ibor, ois, bma/sifma, cms index found, use ccy key to look up vol");
299 }
300
301
302
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() <<
"'");
321 index = tmp;
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() <<
"'");
328 index = tmp;
329 }
330 }
331 }
332 }
333 }
334
335 if(firstFixedRate == Null<Real>())
336 firstFixedRate = lastFixedRate;
337 if(firstFloatSpread == Null<Real>())
338 firstFloatSpread = lastFloatSpread;
339
340 if (firstFixedRate != Null<Real>()) {
342 if (firstFloatSpread != Null<Real>()) {
343 strikes[i] -= firstFloatSpread;
344 }
345 }
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)) << ")");
351 }
352
353
354
355 cpu_timer timer;
356
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));
361 timer.stop();
362 DLOG(
"Swaption model calibration time: " << timer.format(default_places,
"%w") <<
" s");
363 swaption->setPricingEngine(swaptionEngine);
365
366
367
368 auto swapEngine =
370 envelope().additionalField(
"security_spread",
false));
371
372 std::vector<QuantLib::ext::shared_ptr<Instrument>> underlyingSwaps =
374
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,
381
382 instrument_ = QuantLib::ext::make_shared<BermudanOptionWrapper>(
384 settlementType_ == Settlement::Physical ?
true :
false, underlyingSwaps, 1.0, 1.0, additionalInstruments,
385 additionalMultipliers);
386
388
389 DLOG(
"Building Swaption done");
390}
const string & settlementMethod() const
const string & longShort() const
const string & style() const
const string & settlement() const
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_
QuantLib::ext::shared_ptr< ore::data::Swap > underlying_
Exercise::Type exerciseType_
Settlement::Method settlementMethod_
Settlement::Type settlementType_
Position::Type positionType_
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
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)
RequiredFixings requiredFixings_
const Envelope & envelope() const
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
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.
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
Size size(const ValueType &v)