55 {
56
57 DLOG(
"IndexCreditDefaultSwapOption::build() called for trade " <<
id());
58
59
63 QuantLib::ext::shared_ptr<ReferenceDataManager> refData = engineFactory->referenceData();
64 if (refData && refData->hasData("CreditIndex", entity)) {
65 auto refDatum = refData->getData("CreditIndex", entity);
66 QuantLib::ext::shared_ptr<CreditIndexReferenceDatum> creditIndexRefDatum =
67 QuantLib::ext::dynamic_pointer_cast<CreditIndexReferenceDatum>(refDatum);
69 if (creditIndexRefDatum->indexFamily() == "") {
70 ALOG(
"IndexFamily is blank in credit index reference data for entity " << entity);
71 }
72 } else {
73 ALOG(
"Credit index reference data missing for entity " << entity <<
", isdaSubProduct left blank");
74 }
75
77
78
79 const QuantLib::ext::shared_ptr<Market>& market = engineFactory->market();
80 Date asof = market->asofDate();
81 if (asof == Null<Date>() || asof == Date()) {
82 asof = Settings::instance().evaluationDate();
83 }
84
87 } else {
88 QL_REQUIRE(
tradeDate_ <= asof,
"Trade date (" << io::iso_date(
tradeDate_) <<
") should be on or "
89 << "before the valuation date (" << io::iso_date(asof) << ")");
90 }
91
94 } else {
97 << ") should be on or before the trade date ("
99 }
100
101
102
105 QL_REQUIRE(ntls.size() == 1, "IndexCreditDefaultSwapOption requires a single notional.");
110
111
112
113 QL_REQUIRE(legData.legType() == "Fixed", "Index CDS option " << id() << " requires fixed leg.");
114 auto fixedLegData = QuantLib::ext::dynamic_pointer_cast<FixedLegData>(legData.concreteLegData());
115 QL_REQUIRE(fixedLegData->rates().size() == 1, "Index CDS option " << id() << " requires single fixed rate.");
116 auto runningCoupon = fixedLegData->rates().front();
118
119
120
122 "invalid StrikeType (" <<
strikeType_ <<
"), expected 'Spread' or 'Price' or empty value");
126 }
else if (
strike_ == Null<Real>() &&
strikeType_ ==
"Spread" && upfrontFee == Null<Real>()) {
129 }
else if (
strike_ == Null<Real>() &&
strikeType_ ==
"Price" && upfrontFee == Null<Real>()) {
132 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"" && upfrontFee == Null<Real>()) {
135 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"Spread" && upfrontFee == Null<Real>()) {
138 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"Price" && upfrontFee == Null<Real>()) {
141 }
else if (
strike_ == Null<Real>() &&
strikeType_ ==
"" && upfrontFee != Null<Real>()) {
144 }
else if (
strike_ == Null<Real>() &&
strikeType_ ==
"Spread" && upfrontFee != Null<Real>()) {
148 } else {
149 QL_FAIL("StrikeType 'Spread' and non-zero upfront fee can not be combined.");
150 }
151 }
else if (
strike_ == Null<Real>() &&
strikeType_ ==
"Price" && upfrontFee != Null<Real>()) {
154 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"" && upfrontFee != Null<Real>()) {
158 } else {
159 QL_FAIL("Strike and non-zero upfront can not be combined.");
160 }
161 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"Spread" && upfrontFee != Null<Real>()) {
165 } else {
166 QL_FAIL("Strike and non-zero upfront can not be combined.");
167 }
168 }
else if (
strike_ != Null<Real>() &&
strikeType_ ==
"Price" && upfrontFee != Null<Real>()) {
172 } else {
173 QL_FAIL("Strike and non-zero upfront can not be combined.");
174 }
175 } else {
176 QL_FAIL("internal error, impossible branch in strike / strike type deduction.");
177 }
179
180
181 auto side = legData.isPayer() ? Protection::Side::Buyer : Protection::Side::Seller;
182
183
187 } else {
189 }
190
191
192 vector<string> constituentIds;
194 vector<Real> constituentNtls;
197 constituentIds.push_back(kv.first);
198 constituentNtls.push_back(kv.second);
199 }
200
201
202
204 Actual360 standardDayCounter;
205 DayCounter lastPeriodDayCounter = dc == standardDayCounter ? Actual360(true) : dc;
206
207
208 QL_REQUIRE(
option_.
style() ==
"European",
"IndexCreditDefaultSwapOption option style must"
210 QL_REQUIRE(
option_.
exerciseFees().empty(),
"IndexCreditDefaultSwapOption cannot handle exercise fees.");
211
212
214 QL_REQUIRE(exerciseDates.size() == 1, "IndexCreditDefaultSwapOption expects one exercise date"
215 << " but got " << exerciseDates.size() << " exercise dates.");
216 Date exerciseDate =
parseDate(exerciseDates.front());
217 QuantLib::ext::shared_ptr<Exercise> exercise = QuantLib::ext::make_shared<EuropeanExercise>(exerciseDate);
218
219 QL_REQUIRE(
parseDate(legData.schedule().rules().front().endDate()) > exerciseDate,
220 "IndexCreditDefaultSwapOption: ExerciseDate must be before EndDate");
221
222
223
224 if (legData.schedule().rules().size() == 1 && legData.schedule().dates().empty()) {
225
226
227
228 if (
parseDate(legData.schedule().rules().front().startDate()) < exerciseDate) {
229 legData.schedule().modifyRules().front().modifyStartDate() =
ore::data::to_string(exerciseDate);
230 }
231 }
232
233
236
237
238 QL_REQUIRE(!schedule.dates().empty(),
239 "IndexCreditDefaultSwapOption: underlying swap schedule does not contain any dates");
240 Date underlyingTradeDate =
242 Date underlyingProtectionStart;
245 } else if (legData.schedule().rules().size() == 1 && legData.schedule().dates().empty()) {
247 if (rule == DateGeneration::CDS || rule == DateGeneration::CDS2015) {
248 underlyingProtectionStart = std::max(exerciseDate, schedule.dates().front());
249 } else {
250 underlyingProtectionStart = schedule.dates().front();
251 }
252 } else {
253 underlyingProtectionStart = std::max(exerciseDate, schedule.dates().front());
254 }
255
256
257 auto iCdsOptionEngineBuilder = QuantLib::ext::dynamic_pointer_cast<IndexCreditDefaultSwapOptionEngineBuilder>(
258 engineFactory->builder("IndexCreditDefaultSwapOption"));
259 QL_REQUIRE(iCdsOptionEngineBuilder,
260 "IndexCreditDefaultSwapOption: internal error, expected IndexCreditDefaultSwapOptionEngineBuilder");
261 auto iCdsEngineBuilder = QuantLib::ext::dynamic_pointer_cast<IndexCreditDefaultSwapEngineBuilder>(
262 engineFactory->builder("IndexCreditDefaultSwap"));
263 QL_REQUIRE(iCdsEngineBuilder,
264 "IndexCreditDefaultSwap: internal error, expected IndexCreditDefaultSwapEngineBuilder");
265
266
267
268
269 auto cds = QuantLib::ext::make_shared<QuantExt::IndexCreditDefaultSwap>(
273
274
276 std::string overrideCurve = iCdsOptionEngineBuilder->engineParameter("Curve", {}, false, "Underlying");
277
279
281 StructuredTradeWarningMessage(
id(),
tradeType(),
"Could not imply Index CDS term.",
282 "Index CDS term could not be derived from start, end date, are these "
283 "dates correct (credit curve id is '" +
285 .log();
286 }
287
288
290 cds->setPricingEngine(iCdsEngineBuilder->engine(ccy,
creditCurveId, constituentIds, overrideCurve,
293
294
296
297
300
302 } else {
303
306 schedule.dates().back());
307 }
308
309
313
318
319
320
321 maturity_ = cds->coupons().back()->date();
322
323
324 legs_ = {cds->coupons()};
327
328
330 Real indicatorLongShort = positionType == Position::Long ? 1.0 : -1.0;
331
332
333 vector<QuantLib::ext::shared_ptr<Instrument>> additionalInstruments;
334 vector<Real> additionalMultipliers;
337 std::max(
maturity_,
addPremiums(additionalInstruments, additionalMultipliers, indicatorLongShort,
339
340
341
342
343
344
345 if (settleType == Settlement::Cash || exerciseDate <= Settings::instance().evaluationDate()) {
346 instrument_ = QuantLib::ext::make_shared<VanillaInstrument>(
option, indicatorLongShort, additionalInstruments,
347 additionalMultipliers);
348 } else {
349 bool isLong = positionType == Position::Long;
350 bool isPhysical = settleType == Settlement::Physical;
351 instrument_ = QuantLib::ext::make_shared<EuropeanOptionWrapper>(
option, isLong, exerciseDate, isPhysical, cds, 1.0, 1.0,
352 additionalInstruments, additionalMultipliers);
353 }
354
356}
const std::vector< BasketConstituent > & constituents() const
QuantLib::Real recoveryRate() const
QuantLib::Natural cashSettlementDays() const
const LegData & leg() const
bool settlesAccrual() const
const QuantLib::Date & tradeDate() const
PPT protectionPaymentTime() const
const string & creditCurveId() const
const Date & protectionStart() const
const BasketData & basket() const
const QuantLib::Date & indexStartDateHint() const
const std::string & strikeType() const
const ore::data::OptionData & option() const
QuantLib::Real effectiveStrike_
const QuantLib::Date & tradeDate() const
ore::data::OptionData option_
void fromBasket(const QuantLib::Date &asof, std::map< std::string, QuantLib::Real > &constituents)
Populate constituent notionals and curve IDs from basket data.
IndexCreditDefaultSwapData swap_
std::string effectiveStrikeType_
std::string creditCurveId() const
QuantLib::Date fepStartDate_
void fromReferenceData(const QuantLib::Date &asof, std::map< std::string, QuantLib::Real > &constituents, const QuantLib::ext::shared_ptr< ReferenceDataManager > &refData)
Populate constituent notionals and curve IDs from reference data.
CreditPortfolioSensitivityDecomposition sensitivityDecomposition_
QuantLib::Period effectiveIndexTerm_
QuantLib::Date tradeDate_
Notionals notionals_
Populated during trade building.
map< string, Real > constituents_
map of all the constituents to notionals
const vector< double > & notionals() const
const string & longShort() const
const string & style() const
const string & settlement() const
const PremiumData & premiumData() const
const vector< double > & exerciseFees() const
const vector< string > & exerciseDates() const
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)
QuantLib::ext::shared_ptr< InstrumentWrapper > instrument_
const string & tradeType() const
std::map< std::string, boost::any > additionalData_
DateGeneration::Rule parseDateGenerationRule(const string &s)
Convert text to QuantLib::DateGeneration::Rule.
CdsOption::StrikeType parseCdsOptionStrikeType(const string &s)
Date parseDate(const string &s)
Convert std::string to QuantLib::Date.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
Position::Type parsePositionType(const std::string &s)
Convert text to QuantLib::Position::Type.
BusinessDayConvention parseBusinessDayConvention(const string &s)
Convert text to QuantLib::BusinessDayConvention.
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
Settlement::Type parseSettlementType(const std::string &s)
Convert text to QuantLib::Settlement::Type.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
#define DLOG(text)
Logging Macro (Level = Debug)
#define ALOG(text)
Logging Macro (Level = Alert)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
QuantLib::Period implyIndexTerm(const Date &startDate, const Date &endDate)
std::string to_string(const LocationInfo &l)
std::pair< std::string, QuantLib::Period > splitCurveIdWithTenor(const std::string &creditCurveId)
Schedule makeSchedule(const ScheduleDates &data)
QuantLib::Real realisedFep
The realised front end protection amount, as of the valuation date, that would be due on option exerc...
QuantLib::Real tradeDate
Outstanding index notional on the trade date of the index CDS option.
QuantLib::Real full
Notional assuming no defaults i.e. an index factor of 1. Equal to notional on swap_.
QuantLib::Real valuationDate
Outstanding index notional on the valuation date of the index CDS option.