417 {
418 DLOG(
"ConvertibleBond::build() called for trade " <<
id());
419
420
421
426
427 auto builder = QuantLib::ext::dynamic_pointer_cast<ConvertibleBondEngineBuilder>(engineFactory->builder("ConvertibleBond"));
428 QL_REQUIRE(builder, "ConvertibleBond::build(): could not cast to ConvertibleBondBuilder, this is unexpected");
429
432
433
434
436 underlyingBond.build(engineFactory);
438 auto qlUnderlyingBond = QuantLib::ext::dynamic_pointer_cast<QuantLib::Bond>(underlyingBond.instrument()->qlInstrument());
439 QL_REQUIRE(qlUnderlyingBond,
440 "ConvertibleBond::build(): internal error, could not cast underlying bond to QuantLib::Bond");
441 auto qlUnderlyingBondCoupons = qlUnderlyingBond->cashflows();
442 qlUnderlyingBondCoupons.erase(
443 std::remove_if(qlUnderlyingBondCoupons.begin(), qlUnderlyingBondCoupons.end(),
444 [](QuantLib::ext::shared_ptr<CashFlow> c) { return QuantLib::ext::dynamic_pointer_cast<Coupon>(c) == nullptr; }),
445 qlUnderlyingBondCoupons.end());
446
447
448
449 QuantLib::ext::shared_ptr<EngineBuilder> vanillaBuilder = engineFactory->builder("Bond");
450 QL_REQUIRE(builder, "ConvertibleBond::build(): internal error, vanilla builder is null");
451 std::string openEndDateStr = vanillaBuilder->modelParameter("OpenEndDateReplacement", {}, false, "");
453
454
455
456 bool isPerpetual = false;
458 for (auto const& r : d.schedule().rules()) {
459 isPerpetual = isPerpetual || r.endDate().empty();
460 }
461 }
462
463 DLOG(
"isPerpetual=" << std::boolalpha << isPerpetual <<
", openEndDateReplacement=" << openEndDateReplacement);
464
465
466
467 auto config = builder->configuration(MarketContext::pricing);
468
469 QuantLib::ext::shared_ptr<EquityIndex2> equity;
472 }
473
476 "ConvertibleBondEngineBuilder::build(): exactly one of equity underlying or fixed amount conversion "
477 "must be specified");
478
479 QuantLib::ext::shared_ptr<FxIndex> fx;
480 if (equity != nullptr && !equity->currency().empty()) {
483 "ConvertibleBondEngineBuilder::build(): FXIndex required in conversion data, since eq ccy ("
485 << ")");
487 engineFactory->market(), config);
488 }
492 "ConvertibleBondEngineBuilder::build(): FXIndex required in conversion data, since fixed amount "
493 "conversion ccy ("
498 config);
499 }
500 }
501
502
503
504 if (fx != nullptr) {
505
506 Date d0 = qlUnderlyingBond->startDate();
507 Date d1 = qlUnderlyingBond->maturityDate();
508
509
510 if (equity != nullptr) {
511 auto div = equity->dividendFixings();
512 for (auto const& d : div) {
513 if (d.exDate >= d0) {
516 }
517 }
518 }
519
520 Date today = Settings::instance().evaluationDate();
521 d0 = std::min(d0, today);
522
523
524
525 for (Date d = d0; d <= d1; ++d) {
527 Date::maxDate(), false, false);
528 }
529 }
530
531
532
534
535
536
537 ConvertibleBond2::ExchangeableData exchangeableData = buildExchangeableData(
data_.
conversionData());
538 std::vector<ConvertibleBond2::CallabilityData> callData =
539 buildCallabilityData(
data_.
callData(), openEndDateReplacement);
540 ConvertibleBond2::MakeWholeData makeWholeCrIncreaseData = buildMakeWholeData(
data_.
callData());
541 std::vector<ConvertibleBond2::CallabilityData> putData =
542 buildCallabilityData(
data_.
putData(), openEndDateReplacement);
543
544
545 std::vector<ConvertibleBond2::ConversionRatioData> conversionRatioData =
547 : buildConversionFixedAmountData(
data_.conversionData());
548 std::vector<ConvertibleBond2::ConversionData> conversionData = buildConversionData(
550 std::vector<ConvertibleBond2::MandatoryConversionData> mandatoryConversionData =
552 std::vector<ConvertibleBond2::ConversionResetData> conversionResetData = buildConversionResetData(
554 std::vector<ConvertibleBond2::DividendProtectionData> dividendProtectionData =
557
558
559
560
561 Date lastDate = qlUnderlyingBond->maturityDate();
562 if (!dividendProtectionData.empty()) {
563 lastDate = std::max(lastDate, dividendProtectionData.back().protectionDate);
564 }
565
567 auto qlConvertible = QuantLib::ext::make_shared<ConvertibleBond2>(
568 qlUnderlyingBond->settlementDays(), qlUnderlyingBond->calendar(), qlUnderlyingBond->issueDate(),
569 qlUnderlyingBondCoupons, exchangeableData, callData, makeWholeCrIncreaseData, putData, conversionRatioData,
570 conversionData, mandatoryConversionData, conversionResetData, dividendProtectionData,
572 qlConvertible->setPricingEngine(builder->engine(
577
578
579
580 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(qlConvertible, multiplier);
582 maturity_ = qlUnderlyingBond->maturityDate();
583 notional_ = qlUnderlyingBond->notional();
584 legs_ = {qlUnderlyingBond->cashflows()};
587}
const string & securityId() const
bool hasCreditRisk() const
const string & currency() const
const std::vector< LegData > & coupons() const
const string & referenceCurveId() const
const string & calendar() const
const string & creditCurveId() const
Real bondNotional() const
const std::string & equityCreditCurve() const
const std::string & currency() const
const std::string fxIndex() const
const ore::data::EquityUnderlying equityUnderlying() const
const ExchangeableData & exchangeableData() const
const FixedAmountConversionData & fixedAmountConversionData() const
const ore::data::BondData & bondData() const
const CallabilityData & putData() const
const CallabilityData & callData() const
const DividendProtectionData & dividendProtectionData() const
const ConversionData & conversionData() const
std::string detachable() const
void populateFromBondReferenceData(const QuantLib::ext::shared_ptr< ore::data::ReferenceDataManager > &referenceData)
const std::string & name() const override
void addData(const RequiredFixings &requiredFixings)
void addFixingDate(const QuantLib::Date &fixingDate, const std::string &indexName, const QuantLib::Date &payDate=Date::maxDate(), const bool alwaysAddIfPaysOnSettlement=false, const bool mandatoryFixing=true)
std::vector< bool > legPayers_
std::vector< string > legCurrencies_
std::vector< QuantLib::Leg > legs_
void setSensitivityTemplate(const EngineBuilder &builder)
RequiredFixings requiredFixings_
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
std::map< std::string, boost::any > additionalData_
Calendar parseCalendar(const string &s)
Convert text to QuantLib::Calendar.
bool parseBool(const string &s)
Convert text to bool.
#define DLOG(text)
Logging Macro (Level = Debug)
Date getOpenEndDateReplacement(const std::string &replacementPeriodStr, const Calendar &calendar)
QuantLib::ext::shared_ptr< QuantExt::FxIndex > buildFxIndex(const string &fxIndex, const string &domestic, const string &foreign, const QuantLib::ext::shared_ptr< Market > &market, const string &configuration, bool useXbsCurves)