Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Classes | Public Member Functions | Private Member Functions | List of all members
ParSensitivityInstrumentBuilder Class Reference

#include <orea/engine/parsensitivityinstrumentbuilder.hpp>

+ Collaboration diagram for ParSensitivityInstrumentBuilder:

Classes

struct  Instruments
 

Public Member Functions

 ParSensitivityInstrumentBuilder ()=default
 
void createParInstruments (ParSensitivityInstrumentBuilder::Instruments &instruments, const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > &simMarketParams, const ore::analytics::SensitivityScenarioData &sensitivityData, const std::set< ore::analytics::RiskFactorKey::KeyType > &typesDisabled={}, const std::set< ore::analytics::RiskFactorKey::KeyType > &parTypes={}, const std::set< ore::analytics::RiskFactorKey > &relevantRiskFactors={}, const bool continueOnError=false, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration, const QuantLib::ext::shared_ptr< ore::analytics::Market > &simMarket=nullptr) const
 Create par QuantLib::Instruments. More...
 

Private Member Functions

std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeDeposit (const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Deposit for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeFRA (const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create FRA for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeSwap (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Swap for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeOIS (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create OIS Swap for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeTenorBasisSwap (const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string receiveIndexName, std::string payIndexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Basis Swap for implying par rate sensitivity from zero rate sensitivity. More...
 
QuantLib::ext::shared_ptr< QuantLib::CapFloor > makeCapFloor (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, QuantLib::Period term, double strike, bool generatePillar, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Cap/Floor QuantLib::Instrument for implying flat vol sensitivity from optionlet vol sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeCrossCcyBasisSwap (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string baseCcy, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Cross Ccy Basis Swap for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeFxForward (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string baseCcy, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create FX Forwrad for implying par rate sensitivity from zero rate sensitivity. More...
 
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeCDS (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string name, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create CDS for implying par rate sensitivity from Hazard Rate sensitivity. More...
 
QuantLib::ext::shared_ptr< QuantLib::Instrument > makeZeroInflationSwap (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string indexName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create Zero Swap for implying par rate sensitivity from zero rate sensitivity. More...
 
QuantLib::ext::shared_ptr< QuantLib::Instrument > makeYoyInflationSwap (const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string indexName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, bool fromZero, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create YoY Swap for implying par rate sensitivity from yoy rate sensitivity. More...
 
void makeYoYCapFloor (ParSensitivityInstrumentBuilder::Instruments &instruments, const QuantLib::ext::shared_ptr< Market > &market, std::string indexName, QuantLib::Period term, double strike, const QuantLib::ext::shared_ptr< ore::data::Convention > &convention, bool singleCurve, bool fromZero, const std::string &expDiscountCurve, const ore::analytics::RiskFactorKey &key, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
 Create YoY Cap/Floor for implying rate rate sensitivity from yoy optionlet vol sensitivity. More...
 

Detailed Description

Definition at line 37 of file parsensitivityinstrumentbuilder.hpp.

Constructor & Destructor Documentation

◆ ParSensitivityInstrumentBuilder()

Member Function Documentation

◆ createParInstruments()

void createParInstruments ( ParSensitivityInstrumentBuilder::Instruments instruments,
const QuantLib::Date &  asof,
const QuantLib::ext::shared_ptr< ore::analytics::ScenarioSimMarketParameters > &  simMarketParams,
const ore::analytics::SensitivityScenarioData sensitivityData,
const std::set< ore::analytics::RiskFactorKey::KeyType > &  typesDisabled = {},
const std::set< ore::analytics::RiskFactorKey::KeyType > &  parTypes = {},
const std::set< ore::analytics::RiskFactorKey > &  relevantRiskFactors = {},
const bool  continueOnError = false,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration,
const QuantLib::ext::shared_ptr< ore::analytics::Market > &  simMarket = nullptr 
) const

Create par QuantLib::Instruments.

Definition at line 86 of file parsensitivityinstrumentbuilder.cpp.

94 {
95
96 QL_REQUIRE(typesDisabled != parTypes, "At least one par risk factor type must be enabled "
97 << "for a valid ParSensitivityAnalysis.");
98
99 // this is called twice, first (dry run) with simMarket = nullptr to
100 // - do pillar adjustments and
101 // - populate the par helper dependencies
102 // and second with simMarket != null to
103 // - create the final par instruments linked to the sim market
104
105 bool dryRun = simMarket == nullptr;
106 if (dryRun) {
107 Settings::instance().evaluationDate() = asof;
108 }
109
110 LOG("Build par instruments...");
111 auto& parHelpers_ = instruments.parHelpers_;
112 auto& parCaps_ = instruments.parCaps_;
113 auto& parYoYCaps_ = instruments.parYoYCaps_;
114 auto& parHelperDependencies_ = instruments.parHelperDependencies_;
115 auto& yieldCurvePillars_ = instruments.yieldCurvePillars_;
116 auto& parCapsYts_ = instruments.parCapsYts_;
117 auto& parCapsVts_ = instruments.parCapsVts_;
118 auto& capFloorPillars_ = instruments.capFloorPillars_;
119 auto& cdsPillars_ = instruments.cdsPillars_;
120 auto& yoyCapFloorPillars_ = instruments.yoyCapFloorPillars_;
121 auto& zeroInflationPillars_ = instruments.zeroInflationPillars_;
122
123 parHelpers_.clear();
124 parCaps_.clear();
125 parYoYCaps_.clear();
126
127 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
128 QL_REQUIRE(conventions != nullptr, "conventions are empty");
129
130 // Discount curve instruments
131 if (typesDisabled.count(RiskFactorKey::KeyType::DiscountCurve) == 0) {
132
133 LOG("ParSensitivityAnalysis: Discount curve par instruments");
134 for (auto c : sensitivityData.discountCurveShiftData()) {
135 string ccy = c.first;
136 QL_REQUIRE(simMarket || yieldCurvePillars_.find(ccy) == yieldCurvePillars_.end(),
137 "duplicate entry in yieldCurvePillars '" << ccy << "'");
139 *QuantLib::ext::dynamic_pointer_cast<SensitivityScenarioData::CurveShiftParData>(c.second);
140 LOG("ParSensitivityAnalysis: Discount curve ccy=" << ccy);
141 Size n_ten = data.shiftTenors.size();
142 QL_REQUIRE(data.parInstruments.size() == n_ten,
143 "number of tenors does not match number of discount curve par instruments, "
144 << data.parInstruments.size() << " vs. " << n_ten << " ccy=" << ccy
145 << ", check sensitivity configuration.");
146 for (Size j = 0; j < n_ten; ++j) {
148 if (!dryRun && !relevantRiskFactors.empty() &&
149 relevantRiskFactors.find(key) == relevantRiskFactors.end())
150 continue;
151 Period term = data.shiftTenors[j];
152 string instType = data.parInstruments[j];
153 bool singleCurve = data.parInstrumentSingleCurve;
154 string indexName = ""; // if empty, it will be picked from conventions
155 string yieldCurveName = ""; // ignored, if empty
156 string equityForecastCurveName = ""; // ignored, if empty
157 std::pair<QuantLib::ext::shared_ptr<Instrument>, Date> ret;
158 bool recognised = true, skipped = false;
159 try {
160 map<string, string> conventionsMap = data.parInstrumentConventions;
161 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
162 "conventions not found for ccy " << ccy << " and instrument type " << instType);
163 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
164 QL_REQUIRE(convention != nullptr, "convention is empty");
165 if (instType == "IRS")
166 ret = makeSwap(simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
167 convention, singleCurve, parHelperDependencies_[key],
168 instruments.removeTodaysFixingIndices_, data.discountCurve, marketConfiguration);
169 else if (instType == "DEP")
170 ret = makeDeposit(asof, simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName,
171 term, convention, marketConfiguration);
172 else if (instType == "FRA")
173 ret = makeFRA(asof, simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
174 convention, marketConfiguration);
175 else if (instType == "OIS")
176 ret = makeOIS(simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
177 convention, singleCurve, parHelperDependencies_[key],
178 instruments.removeTodaysFixingIndices_, data.discountCurve, marketConfiguration);
179 else if (instType == "XBS") {
180 string otherCurrency =
181 data.otherCurrency.empty() ? simMarketParams->baseCcy() : data.otherCurrency;
182 ret = makeCrossCcyBasisSwap(simMarket, otherCurrency, ccy, term, convention,
183 parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
184 marketConfiguration);
185 } else if (instType == "FXF")
186 ret = makeFxForward(simMarket, simMarketParams->baseCcy(), ccy, term, convention,
187 parHelperDependencies_[key], marketConfiguration);
188 else if (instType == "TBS")
189 ret = makeTenorBasisSwap(asof, simMarket, ccy, "", "", "", "", term, convention, singleCurve,
190 parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
191 data.discountCurve, marketConfiguration);
192 else
193 recognised = false;
194 } catch (const std::exception& e) {
195 skipped = true;
196 if (continueOnError) {
197 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
198 "Skipping par instrument for discount curve " + ccy, e.what())
199 .log();
200 } else {
201 QL_FAIL(e.what());
202 }
203 }
204 if (!recognised)
205 QL_FAIL("Instrument type " << instType << " for par sensitivity conversion not recognised");
206 if (!skipped) {
207 parHelpers_[key] = ret.first;
208 if (!simMarket) {
209 yieldCurvePillars_[ccy].push_back((ret.second - asof) * Days);
210 }
211 DLOG("Par instrument for discount curve, ccy " << ccy << " tenor " << j << ", type " << instType
212 << " built.");
213 }
214 }
215 }
216 }
217
218 if (typesDisabled.count(RiskFactorKey::KeyType::YieldCurve) == 0) {
219
220 LOG("ParSensitivityAnalysis: Yield curve par instruments");
221 // Yield curve instruments
222 QL_REQUIRE(simMarketParams->yieldCurveNames().size() == simMarketParams->yieldCurveCurrencies().size(),
223 "vector size mismatch in sim market parameters yield curve names/currencies");
224 for (auto y : sensitivityData.yieldCurveShiftData()) {
225 string curveName = y.first;
226 QL_REQUIRE(simMarket || yieldCurvePillars_.find(curveName) == yieldCurvePillars_.end(),
227 "duplicate entry in yieldCurvePillars '" << curveName << "'");
228 string equityForecastCurveName = ""; // ignored, if empty
229 string ccy = "";
230 for (Size j = 0; j < simMarketParams->yieldCurveNames().size(); ++j) {
231 if (curveName == simMarketParams->yieldCurveNames()[j])
232 ccy = simMarketParams->yieldCurveCurrencies().at(curveName);
233 }
234 LOG("ParSensitivityAnalysis: yield curve name " << curveName);
235 QL_REQUIRE(ccy != "", "yield curve currency not found for yield curve " << curveName);
237 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CurveShiftParData>(y.second);
238 Size n_ten = data.shiftTenors.size();
239 QL_REQUIRE(data.parInstruments.size() == n_ten,
240 "number of tenors does not match number of yield curve par instruments");
241 for (Size j = 0; j < n_ten; ++j) {
243 if (!dryRun && !relevantRiskFactors.empty() &&
244 relevantRiskFactors.find(key) == relevantRiskFactors.end())
245 continue;
246 Period term = data.shiftTenors[j];
247 string instType = data.parInstruments[j];
248 bool singleCurve = data.parInstrumentSingleCurve;
249 std::pair<QuantLib::ext::shared_ptr<Instrument>, Date> ret;
250 bool recognised = true, skipped = false;
251 try {
252 map<string, string> conventionsMap = data.parInstrumentConventions;
253 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
254 "conventions not found for ccy " << ccy << " and instrument type " << instType);
255 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
256
257 if (instType == "IRS")
258 ret = makeSwap(simMarket, ccy, "", curveName, equityForecastCurveName, term, convention,
259 singleCurve, parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
260 data.discountCurve, marketConfiguration);
261 else if (instType == "DEP")
262 ret = makeDeposit(asof, simMarket, ccy, "", curveName, equityForecastCurveName, term,
263 convention, marketConfiguration);
264 else if (instType == "FRA")
265 ret = makeFRA(asof, simMarket, ccy, "", curveName, equityForecastCurveName, term, convention,
266 marketConfiguration);
267 else if (instType == "OIS")
268 ret = makeOIS(simMarket, ccy, "", curveName, equityForecastCurveName, term, convention,
269 singleCurve, parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
270 data.discountCurve, marketConfiguration);
271 else if (instType == "TBS")
272 ret = makeTenorBasisSwap(asof, simMarket, ccy, "", "", curveName, "", term, convention,
273 singleCurve, parHelperDependencies_[key],
274 instruments.removeTodaysFixingIndices_, data.discountCurve,
275 marketConfiguration);
276 else if (instType == "XBS") {
277 string otherCurrency =
278 data.otherCurrency.empty() ? simMarketParams->baseCcy() : data.otherCurrency;
279 ret = makeCrossCcyBasisSwap(simMarket, otherCurrency, ccy, term, convention,
280 parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
281 marketConfiguration);
282 } else
283 recognised = false;
284 } catch (const std::exception& e) {
285 skipped = true;
286 if (continueOnError) {
287 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
288 "Skipping par instrument for " + curveName, e.what())
289 .log();
290 } else {
291 QL_FAIL(e.what());
292 }
293 }
294 if (!recognised)
295 QL_FAIL("Instrument type " << instType << " for par sensitivity conversion unexpected");
296 if (!skipped) {
297 parHelpers_[key] = ret.first;
298 if (!simMarket) {
299 yieldCurvePillars_[curveName].push_back((ret.second - asof) * Days);
300 }
301 DLOG("Par instrument for yield curve, ccy " << ccy << " tenor " << j << ", type " << instType
302 << " built.");
303 }
304 }
305 }
306 }
307
308 if (typesDisabled.count(RiskFactorKey::KeyType::IndexCurve) == 0) {
309
310 LOG("ParSensitivityAnalysis: Index curve par instruments");
311 // Index curve instruments
312 for (auto index : sensitivityData.indexCurveShiftData()) {
313 string indexName = index.first;
314 QL_REQUIRE(simMarket || yieldCurvePillars_.find(indexName) == yieldCurvePillars_.end(),
315 "duplicate entry in yieldCurvePillars '" << indexName << "'");
317 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CurveShiftParData>(index.second);
318 Size n_ten = data.shiftTenors.size();
319 QL_REQUIRE(data.parInstruments.size() == n_ten,
320 indexName << " number of tenors " << n_ten << "does not match number of index curve par instruments"
321 << data.parInstruments.size());
322 vector<string> tokens;
323 boost::split(tokens, indexName, boost::is_any_of("-"));
324 QL_REQUIRE(tokens.size() >= 2, "index name " << indexName << " unexpected");
325 string ccy = tokens[0];
326 QL_REQUIRE(ccy.length() == 3, "currency token not recognised");
327 for (Size j = 0; j < n_ten; ++j) {
329 if (!dryRun && !relevantRiskFactors.empty() &&
330 relevantRiskFactors.find(key) == relevantRiskFactors.end())
331 continue;
332 Period term = data.shiftTenors[j];
333 string instType = data.parInstruments[j];
334 bool singleCurve = data.parInstrumentSingleCurve;
335 string yieldCurveName = "";
336 string equityForecastCurveName = ""; // ignored, if empty
337 std::pair<QuantLib::ext::shared_ptr<Instrument>, Date> ret;
338 bool recognised = true, skipped = false;
339 try {
340 map<string, string> conventionsMap = data.parInstrumentConventions;
341 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
342 "conventions not found for ccy " << ccy << " and instrument type " << instType);
343 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
344
345 if (instType == "IRS")
346 ret = makeSwap(simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
347 convention, singleCurve, parHelperDependencies_[key],
348 instruments.removeTodaysFixingIndices_, data.discountCurve, marketConfiguration);
349 else if (instType == "DEP")
350 ret = makeDeposit(asof, simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName,
351 term, convention, marketConfiguration);
352 else if (instType == "FRA")
353 ret = makeFRA(asof, simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
354 convention, marketConfiguration);
355 else if (instType == "OIS")
356 ret = makeOIS(simMarket, ccy, indexName, yieldCurveName, equityForecastCurveName, term,
357 convention, singleCurve, parHelperDependencies_[key],
358 instruments.removeTodaysFixingIndices_, data.discountCurve, marketConfiguration);
359 else if (instType == "TBS")
360 ret = makeTenorBasisSwap(asof, simMarket, ccy, "", "", "", "", term, convention, singleCurve,
361 parHelperDependencies_[key], instruments.removeTodaysFixingIndices_,
362 data.discountCurve, marketConfiguration);
363 else
364 recognised = false;
365 } catch (const std::exception& e) {
366 skipped = true;
367 if (continueOnError) {
368 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
369 "Skipping par instrument for index curve " + indexName,
370 e.what())
371 .log();
372 } else {
373 QL_FAIL(e.what());
374 }
375 }
376 if (!recognised)
377 QL_FAIL("Instrument type " << instType << " for par sensitivity conversion not recognised");
378 if (!skipped) {
379 parHelpers_[key] = ret.first;
380 if (!simMarket) {
381 yieldCurvePillars_[indexName].push_back((ret.second - asof) * Days);
382 }
383 DLOG("Par instrument for index " << indexName << " ccy " << ccy << " tenor " << j << " built.");
384 }
385 }
386 }
387 }
388
389 if (typesDisabled.count(RiskFactorKey::KeyType::OptionletVolatility) == 0) {
390
391 // Caps/Floors
392 LOG("ParSensitivityAnalysis: Cap/Floor par instruments");
393
394 for (auto c : sensitivityData.capFloorVolShiftData()) {
395 string key = c.first;
396 auto datap = QuantLib::ext::dynamic_pointer_cast<SensitivityScenarioData::CapFloorVolShiftParData>(c.second);
397 string expDiscountCurve = datap ? datap->discountCurve : "";
399 string indexName = data.indexName;
400 string ccy = parseIborIndex(indexName)->currency().code();
401 Handle<YieldTermStructure> yts;
402 Handle<OptionletVolatilityStructure> ovs;
403 Size n_strikes = data.shiftStrikes.size();
404 Size n_expiries = data.shiftExpiries.size();
405
406 // Determine if the cap floor is ATM
407 bool isAtm = data.shiftStrikes.size() == 1 && data.shiftStrikes[0] == 0.0 && data.isRelative;
408
409 for (Size j = 0; j < n_strikes; ++j) {
410 Real strike = data.shiftStrikes[j];
411 for (Size k = 0; k < n_expiries; ++k) {
412 RiskFactorKey rfkey(RiskFactorKey::KeyType::OptionletVolatility, key, k * n_strikes + j);
413 if (!dryRun && !relevantRiskFactors.empty() &&
414 relevantRiskFactors.find(rfkey) == relevantRiskFactors.end())
415 continue;
416 try {
417 if (simMarket != nullptr) {
418 yts = expDiscountCurve.empty() ? simMarket->discountCurve(ccy, marketConfiguration)
419 : simMarket->iborIndex(expDiscountCurve, marketConfiguration)
420 ->forwardingTermStructure();
421 ovs = simMarket->capFloorVol(key, marketConfiguration);
422 }
423 Period term = data.shiftExpiries[k];
424 auto tmp = makeCapFloor(simMarket, ccy, indexName, term, strike, isAtm,
425 parHelperDependencies_[rfkey], expDiscountCurve, marketConfiguration);
426 parCaps_[rfkey] = tmp;
427 parCapsYts_[rfkey] = yts;
428 parCapsVts_[rfkey] = ovs;
429 if (j == 0)
430 capFloorPillars_[key].push_back(term);
431 DLOG("Par cap/floor for key " << rfkey << " strike " << j << " tenor " << k << " built.");
432 } catch (const std::exception& e) {
433 if (continueOnError) {
434 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
435 "Skipping par cap/floor for key " + key, e.what())
436 .log();
437 } else {
438 QL_FAIL(e.what());
439 }
440 }
441 }
442 }
443 }
444 }
445
446 if (typesDisabled.count(RiskFactorKey::KeyType::SurvivalProbability) == 0) {
447
448 // CDS Instruments
449 LOG("ParSensitivityAnalysis: CDS par instruments");
450 for (auto c : sensitivityData.creditCurveShiftData()) {
451 string name = c.first;
452 string ccy = sensitivityData.creditCcys().at(name);
453 auto itr = sensitivityData.creditCurveShiftData().find(name);
454 QL_REQUIRE(itr != sensitivityData.creditCurveShiftData().end(),
455 "creditCurveShiftData not found for " << name);
457 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CurveShiftParData>(c.second);
458 Size n_expiries = data.shiftTenors.size();
459 for (Size k = 0; k < n_expiries; ++k) {
460 string instType = data.parInstruments[k];
462 if (!dryRun && !relevantRiskFactors.empty() &&
463 relevantRiskFactors.find(key) == relevantRiskFactors.end())
464 continue;
465 Period term = data.shiftTenors[k];
466 std::pair<QuantLib::ext::shared_ptr<Instrument>, Date> ret;
467 bool skipped = false;
468 try {
469 map<string, string> conventionsMap = data.parInstrumentConventions;
470 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
471 "conventions not found for name " << name << " and instrument type " << instType);
472 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
473
474 ret = makeCDS(simMarket, name, ccy, term, convention, parHelperDependencies_[key],
475 data.discountCurve, marketConfiguration);
476 } catch (const std::exception& e) {
477 skipped = true;
478 if (continueOnError) {
479 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
480 "Skipping par instrument for cds " + name, e.what())
481 .log();
482 } else {
483 QL_FAIL(e.what());
484 }
485 }
486 if (!skipped) {
487 parHelpers_[key] = ret.first;
488 if (!simMarket) {
489 cdsPillars_[name].push_back((ret.second - asof) * Days);
490 }
491 DLOG("Par CDS for name " << name << " tenor " << k << " built.");
492 }
493 }
494 }
495 }
496
497 if (typesDisabled.count(RiskFactorKey::KeyType::ZeroInflationCurve) == 0) {
498
499 LOG("ParSensitivityAnalysis: ZCI curve par instruments");
500 // Zero Inflation Curve instruments
501 for (auto z : sensitivityData.zeroInflationCurveShiftData()) {
502 string indexName = z.first;
504 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CurveShiftParData>(z.second);
505 Size n_ten = data.shiftTenors.size();
506 for (Size j = 0; j < n_ten; ++j) {
508 if (!dryRun && !relevantRiskFactors.empty() &&
509 relevantRiskFactors.find(key) == relevantRiskFactors.end())
510 continue;
511 Period term = data.shiftTenors[j];
512 string instType = data.parInstruments[j];
513 bool singleCurve = data.parInstrumentSingleCurve;
514 try {
515 map<string, string> conventionsMap = data.parInstrumentConventions;
516 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
517 "conventions not found for zero inflation curve " << indexName << " and instrument type "
518 << instType);
519 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
520
521 auto tmp =
522 makeZeroInflationSwap(simMarket, indexName, term, convention, singleCurve,
523 parHelperDependencies_[key], data.discountCurve, marketConfiguration);
524 auto helper = QuantLib::ext::dynamic_pointer_cast<ZeroCouponInflationSwap>(tmp);
525 QuantLib::ext::shared_ptr<IndexedCashFlow> lastCoupon =
526 QuantLib::ext::dynamic_pointer_cast<IndexedCashFlow>(helper->inflationLeg().back());
527 Date latestRelevantDate = std::max(helper->maturityDate(), lastCoupon->fixingDate());
528 zeroInflationPillars_[indexName].push_back((latestRelevantDate - asof) * Days);
529
530 parHelpers_[key] = tmp;
531 DLOG("Par instrument for zero inflation index " << indexName << " tenor " << j << " built.");
532 } catch (const std::exception& e) {
533 if (continueOnError) {
534 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
535 "Skipping par instrument for zero inflation index " + indexName,
536 e.what())
537 .log();
538 } else {
539 QL_FAIL(e.what());
540 }
541 }
542 }
543 }
544 }
545
546 if (typesDisabled.count(RiskFactorKey::KeyType::YoYInflationCurve) == 0) {
547
548 // YoY Inflation Curve instruments
549 LOG("ParSensitivityAnalysis: YOYI curve par instruments");
550 for (auto y : sensitivityData.yoyInflationCurveShiftData()) {
551 string indexName = y.first;
553 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CurveShiftParData>(y.second);
554 Size n_ten = data.shiftTenors.size();
555 for (Size j = 0; j < n_ten; ++j) {
556 Period term = data.shiftTenors[j];
557 string instType = data.parInstruments[j];
558 bool singleCurve = data.parInstrumentSingleCurve;
559
561 bool recognised = true;
562 try {
563 map<string, string> conventionsMap = data.parInstrumentConventions;
564 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
565 "conventions not found for zero inflation curve " << indexName << " and instrument type "
566 << instType);
567 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
568
569 if (instType == "ZIS") {
570 auto tmp =
571 makeYoyInflationSwap(simMarket, indexName, term, convention, singleCurve, true,
572 parHelperDependencies_[key], data.discountCurve, marketConfiguration);
573 auto helper = dynamic_pointer_cast<YearOnYearInflationSwap>(tmp);
574 // set pillar date
575 QuantLib::ext::shared_ptr<YoYInflationCoupon> lastCoupon =
576 QuantLib::ext::dynamic_pointer_cast<YoYInflationCoupon>(helper->yoyLeg().back());
577 Date latestRelevantDate = std::max(helper->maturityDate(), lastCoupon->fixingDate());
578 instruments.yoyInflationPillars_[indexName].push_back((latestRelevantDate - asof) * Days);
579 parHelpers_[key] = tmp;
580 } else if (instType == "YYS") {
581 auto tmp =
582 makeYoyInflationSwap(simMarket, indexName, term, convention, singleCurve, false,
583 parHelperDependencies_[key], data.discountCurve, marketConfiguration);
584 auto helper = dynamic_pointer_cast<YearOnYearInflationSwap>(tmp);
585 // set pillar date
586 QuantLib::ext::shared_ptr<YoYInflationCoupon> lastCoupon =
587 QuantLib::ext::dynamic_pointer_cast<YoYInflationCoupon>(helper->yoyLeg().back());
588 Date latestRelevantDate = std::max(helper->maturityDate(), lastCoupon->fixingDate());
589 instruments.yoyInflationPillars_[indexName].push_back((latestRelevantDate - asof) * Days);
590 parHelpers_[key] = tmp;
591 } else
592 recognised = false;
593 } catch (const std::exception& e) {
594 if (continueOnError) {
595 StructuredAnalyticsErrorMessage("Par sensitivity conversion",
596 "Skipping par instrument for yoy index " + indexName, e.what())
597 .log();
598 } else {
599 QL_FAIL(e.what());
600 }
601 }
602 if (!recognised)
603 QL_FAIL("Instrument type " << instType << " for par sensitivity conversion not recognised");
604 DLOG("Par instrument for yoy inflation index " << indexName << " tenor " << j << " built.");
605 }
606 }
607 }
608
609 if (typesDisabled.count(RiskFactorKey::KeyType::YoYInflationCapFloorVolatility) == 0) {
610
611 // YY Caps/Floors
612 LOG("ParSensitivityAnalysis: YOYI Cap/Floor par instruments");
613 for (auto y : sensitivityData.yoyInflationCapFloorVolShiftData()) {
614 string indexName = y.first;
616 *QuantLib::ext::static_pointer_cast<SensitivityScenarioData::CapFloorVolShiftParData>(y.second);
617 Size n_strikes = data.shiftStrikes.size();
618 Size n_expiries = data.shiftExpiries.size();
619 bool singleCurve = data.parInstrumentSingleCurve;
620 for (Size j = 0; j < n_strikes; ++j) {
621 Real strike = data.shiftStrikes[j];
622 pair<string, Size> key(indexName, j);
623 for (Size k = 0; k < n_expiries; ++k) {
625 k * n_strikes + j);
626
627 bool recognised = true;
628 string instType;
629 try {
630 instType = data.parInstruments[j];
631 map<string, string> conventionsMap = data.parInstrumentConventions;
632 QL_REQUIRE(conventionsMap.find(instType) != conventionsMap.end(),
633 "conventions not found for zero inflation curve "
634 << indexName << " and instrument type " << instType);
635 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(conventionsMap[instType]);
636 Period term = data.shiftExpiries[k];
637 if (instType == "ZIS") {
638 makeYoYCapFloor(instruments, simMarket, indexName, term, strike, convention, singleCurve,
639 true, data.discountCurve, key, marketConfiguration);
640 } else if (instType == "YYS") {
641 makeYoYCapFloor(instruments, simMarket, indexName, term, strike, convention, singleCurve,
642 false, data.discountCurve, key, marketConfiguration);
643 } else
644 recognised = false;
645 if (j == 0)
646 yoyCapFloorPillars_[indexName].push_back(term);
647 } catch (const std::exception& e) {
648 if (continueOnError) {
650 "Par sensitivity conversion",
651 "Skipping par instrument for yoy cap floor index " + indexName, e.what())
652 .log();
653 } else {
654 QL_FAIL(e.what());
655 }
656 }
657 if (!recognised)
658 QL_FAIL("Instrument type " << instType << " for par sensitivity conversion not recognised");
659 DLOG("Par yoy cap/floor for index " << indexName << " strike " << j << " tenor " << k << " built.");
660 }
661 }
662 }
663 }
664
665 LOG("Par instrument building done, got " << parHelpers_.size() + parCaps_.size() + parYoYCaps_.size()
666 << " instruments");
667} // createParInstruments
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeSwap(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Swap for implying par rate sensitivity from zero rate sensitivity.
QuantLib::ext::shared_ptr< QuantLib::CapFloor > makeCapFloor(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, QuantLib::Period term, double strike, bool generatePillar, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Cap/Floor QuantLib::Instrument for implying flat vol sensitivity from optionlet vol sensitivit...
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeTenorBasisSwap(const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string receiveIndexName, std::string payIndexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Basis Swap for implying par rate sensitivity from zero rate sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeCrossCcyBasisSwap(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string baseCcy, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Cross Ccy Basis Swap for implying par rate sensitivity from zero rate sensitivity.
void makeYoYCapFloor(ParSensitivityInstrumentBuilder::Instruments &instruments, const QuantLib::ext::shared_ptr< Market > &market, std::string indexName, QuantLib::Period term, double strike, const QuantLib::ext::shared_ptr< ore::data::Convention > &convention, bool singleCurve, bool fromZero, const std::string &expDiscountCurve, const ore::analytics::RiskFactorKey &key, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create YoY Cap/Floor for implying rate rate sensitivity from yoy optionlet vol sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeDeposit(const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Deposit for implying par rate sensitivity from zero rate sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeFRA(const QuantLib::Date &asof, const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create FRA for implying par rate sensitivity from zero rate sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeOIS(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string ccy, std::string indexName, std::string yieldCurveName, std::string equityForecastCurveName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, std::set< std::string > &removeTodaysFixingIndices, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create OIS Swap for implying par rate sensitivity from zero rate sensitivity.
QuantLib::ext::shared_ptr< QuantLib::Instrument > makeYoyInflationSwap(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string indexName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, bool fromZero, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create YoY Swap for implying par rate sensitivity from yoy rate sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeFxForward(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string baseCcy, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create FX Forwrad for implying par rate sensitivity from zero rate sensitivity.
std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeCDS(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string name, std::string ccy, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create CDS for implying par rate sensitivity from Hazard Rate sensitivity.
QuantLib::ext::shared_ptr< QuantLib::Instrument > makeZeroInflationSwap(const QuantLib::ext::shared_ptr< ore::data::Market > &market, std::string indexName, QuantLib::Period term, const QuantLib::ext::shared_ptr< ore::data::Convention > &conventions, bool singleCurve, std::set< ore::analytics::RiskFactorKey > &parHelperDependencies, const std::string &expDiscountCurve="", const std::string &marketConfiguration=ore::data::Market::defaultConfiguration) const
Create Zero Swap for implying par rate sensitivity from zero rate sensitivity.
Data types stored in the scenario class.
Definition: scenario.hpp:48
const map< string, QuantLib::ext::shared_ptr< CapFloorVolShiftData > > & yoyInflationCapFloorVolShiftData() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & indexCurveShiftData() const
const map< string, QuantLib::ext::shared_ptr< CapFloorVolShiftData > > & capFloorVolShiftData() const
const map< string, string > & creditCcys() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & discountCurveShiftData() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & zeroInflationCurveShiftData() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & creditCurveShiftData() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & yoyInflationCurveShiftData() const
const map< string, QuantLib::ext::shared_ptr< CurveShiftData > > & yieldCurveShiftData() const
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h=Handle< YieldTermStructure >())
data
#define LOG(text)
#define DLOG(text)
Size size(const ValueType &v)
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
std::map< std::string, std::vector< QuantLib::Period > > zeroInflationPillars_
std::map< ore::analytics::RiskFactorKey, QuantLib::ext::shared_ptr< QuantLib::Instrument > > parHelpers_
par helpers (all except cap/floors)
std::map< ore::analytics::RiskFactorKey, std::set< ore::analytics::RiskFactorKey > > parHelperDependencies_
list of (raw) risk factors on which a par helper depends
std::map< std::string, std::vector< QuantLib::Period > > yieldCurvePillars_
par QuantLib::Instrument pillars
std::map< ore::analytics::RiskFactorKey, QuantLib::Handle< QuantLib::YieldTermStructure > > parCapsYts_
std::map< ore::analytics::RiskFactorKey, QuantLib::ext::shared_ptr< QuantLib::CapFloor > > parCaps_
par helpers: IR cap / floors
std::map< ore::analytics::RiskFactorKey, QuantLib::Handle< QuantLib::OptionletVolatilityStructure > > parCapsVts_
std::map< ore::analytics::RiskFactorKey, QuantLib::ext::shared_ptr< QuantLib::YoYInflationCapFloor > > parYoYCaps_
std::map< std::string, std::vector< QuantLib::Period > > yoyCapFloorPillars_
std::map< std::string, std::vector< QuantLib::Period > > capFloorPillars_
std::map< std::string, std::vector< QuantLib::Period > > cdsPillars_
std::map< std::string, std::vector< QuantLib::Period > > yoyInflationPillars_
Date asof(14, Jun, 2018)
string name
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeDeposit()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeDeposit ( const QuantLib::Date &  asof,
const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  indexName,
std::string  yieldCurveName,
std::string  equityForecastCurveName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Deposit for implying par rate sensitivity from zero rate sensitivity.

Definition at line 792 of file parsensitivityinstrumentbuilder.cpp.

795 {
796
797 // Curve priorities, use in the following order if ccy/indexName/yieldCurveName strings are not blank
798 // Single curve setting only
799 // - discounts: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
800 // - forwards: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
801 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
802 QuantLib::ext::shared_ptr<DepositConvention> conv = QuantLib::ext::dynamic_pointer_cast<DepositConvention>(convention);
803 QL_REQUIRE(conv, "convention not recognised, expected DepositConvention");
804 QuantLib::ext::shared_ptr<IborIndex> index;
805 if (indexName == "" && conv->indexBased()) {
806 // At this point, we may have an overnight index or an ibor index
807 if (isOvernightIndex(conv->index())) {
808 index = parseIborIndex(conv->index());
809 } else {
810 index = parseIborIndex(conv->index() + "-" + to_string(term));
811 }
812 } else if (indexName != "") {
813 if (market != nullptr) {
814 index = market->iborIndex(indexName, marketConfiguration).currentLink();
815 } else {
816 index = parseIborIndex(indexName);
817 }
818 }
819 QuantLib::ext::shared_ptr<Deposit> helper;
820 if (index != nullptr) {
821 helper = QuantLib::ext::make_shared<Deposit>(1.0, 0.0, term, index->fixingDays(), index->fixingCalendar(),
822 index->businessDayConvention(), index->endOfMonth(), index->dayCounter(),
823 asof, true, 0 * Days);
824 } else {
825 QL_REQUIRE(!conv->indexBased(), "expected non-index-based deposit convention");
826 helper = QuantLib::ext::make_shared<Deposit>(1.0, 0.0, term, conv->settlementDays(), conv->calendar(),
827 conv->convention(), conv->eom(), conv->dayCounter(), asof, true, 0 * Days);
828 }
829 RelinkableHandle<YieldTermStructure> engineYts;
830 QuantLib::ext::shared_ptr<PricingEngine> depositEngine = QuantLib::ext::make_shared<DepositEngine>(engineYts);
831 helper->setPricingEngine(depositEngine);
832 if (market != nullptr) {
833 if (indexName != "")
834 engineYts.linkTo(*index->forwardingTermStructure());
835 else if (yieldCurveName != "")
836 engineYts.linkTo(*market->yieldCurve(yieldCurveName, marketConfiguration));
837 else if (equityForecastCurveName != "")
838 engineYts.linkTo(*market->equityForecastCurve(equityForecastCurveName, marketConfiguration));
839 else if (ccy != "")
840 engineYts.linkTo(*market->discountCurve(ccy, marketConfiguration));
841 else
842 QL_FAIL("Yield term structure not found for deposit (ccy=" << ccy << ")");
843 }
844 // set pillar date
845 Date latestRelevantDate = helper->maturityDate();
846 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, latestRelevantDate);
847}
bool isOvernightIndex(const std::string &indexName)
std::string to_string(const LocationInfo &l)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeFRA()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeFRA ( const QuantLib::Date &  asof,
const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  indexName,
std::string  yieldCurveName,
std::string  equityForecastCurveName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create FRA for implying par rate sensitivity from zero rate sensitivity.

Definition at line 849 of file parsensitivityinstrumentbuilder.cpp.

852 {
853 // Curve priorities, use in the following order if ccy/indexName/yieldCurveName strings are not blank
854 // - discounts: discountCurve(ccy) -> yieldCurve(yieldCurveName) -> iborIndex(indexName)
855 // - forwards: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
856 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
857 QuantLib::ext::shared_ptr<FraConvention> conv = QuantLib::ext::dynamic_pointer_cast<FraConvention>(convention);
858 QL_REQUIRE(conv, "convention not recognised, expected FraConvention");
859 string name = indexName != "" ? indexName : conv->indexName();
860 QuantLib::ext::shared_ptr<IborIndex> index;
861 if (market != nullptr) {
862 index = *market->iborIndex(name, marketConfiguration);
863 if (indexName == "") {
864 if (yieldCurveName != "")
865 index = market->iborIndex(name)->clone(market->yieldCurve(yieldCurveName, marketConfiguration));
866 else if (equityForecastCurveName != "")
867 index = market->iborIndex(name)->clone(
868 market->equityForecastCurve(equityForecastCurveName, marketConfiguration));
869 else if (ccy != "")
870 index = market->iborIndex(name)->clone(market->discountCurve(ccy, marketConfiguration));
871 else
872 QL_FAIL("index curve not identified for FRA (ccy=" << ccy << ")");
873 }
874 } else {
875 index = parseIborIndex(name);
876 }
877 QuantLib::ext::shared_ptr<IborIndex> fraConvIdx =
878 ore::data::parseIborIndex(conv->indexName(), index->forwardingTermStructure()); // used for setting up the FRA
879 if (fraConvIdx->tenor() != index->tenor()) {
880 WLOG("FRA building - mismatch between input index (" << indexName << ") and conventions (" << conv->indexName()
881 << ") - using conventions");
882 }
883 QL_REQUIRE((term.units() == Months) || (term.units() == Years), "term unit must be Months or Years");
884 QL_REQUIRE(fraConvIdx->tenor().units() == Months, "index tenor unit must be Months (" << fraConvIdx->tenor() << ")("
885 << term << ")(" << indexName
886 << ")(" << name << ")");
887 QL_REQUIRE(term > fraConvIdx->tenor(), "term must be larger than index tenor");
888 Period startTerm = term - fraConvIdx->tenor(); // the input term refers to the end of the FRA accrual period
889 Calendar fraCal = fraConvIdx->fixingCalendar();
890 Date asofadj = fraCal.adjust(asof); // same as in FraRateHelper
891 Date todaySpot = fraConvIdx->valueDate(asofadj);
892 Date valueDate =
893 fraCal.advance(todaySpot, startTerm, fraConvIdx->businessDayConvention(), fraConvIdx->endOfMonth());
894 Date maturityDate = fraConvIdx->maturityDate(valueDate);
895 Handle<YieldTermStructure> ytsTmp;
896 if (market != nullptr) {
897 if (ccy != "")
898 ytsTmp = market->discountCurve(ccy, marketConfiguration);
899 else if (yieldCurveName != "")
900 ytsTmp = market->yieldCurve(yieldCurveName, marketConfiguration);
901 else if (equityForecastCurveName != "")
902 ytsTmp = market->equityForecastCurve(equityForecastCurveName, marketConfiguration);
903 else
904 ytsTmp = index->forwardingTermStructure();
905 } else {
906 // FRA instrument requires non-empty curves for its construction below
907 ytsTmp = Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.00, Actual365Fixed()));
908 fraConvIdx = fraConvIdx->clone(ytsTmp);
909 }
910 auto helper =
911 QuantLib::ext::make_shared<QuantLib::ForwardRateAgreement>(fraConvIdx, valueDate, Position::Long, 0.0, 1.0, ytsTmp);
912 // set pillar date
913 // yieldCurvePillars_[indexName == "" ? ccy : indexName].push_back((maturityDate - asof) *
914 // Days);
915 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, maturityDate);
916}
#define WLOG(text)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeSwap()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeSwap ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  indexName,
std::string  yieldCurveName,
std::string  equityForecastCurveName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
bool  singleCurve,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
std::set< std::string > &  removeTodaysFixingIndices,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Swap for implying par rate sensitivity from zero rate sensitivity.

Definition at line 669 of file parsensitivityinstrumentbuilder.cpp.

673 {
674 // Curve priorities, use in the following order if ccy/indexName/yieldCurveName strings are not blank
675 // 1) singleCurve = false
676 // - discounts: discountCurve(ccy) -> yieldCurve(yieldCurveName)
677 // - forwards: iborIndex(indexName) -> iborIndex(conventions index name)
678 // 2) singleCurve = true
679 // - discounts: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
680 // - forwards: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
681 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
682 QuantLib::ext::shared_ptr<IRSwapConvention> conv = QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(convention);
683 QL_REQUIRE(conv, "convention not recognised, expected IRSwapConvention");
684 string name = indexName != "" ? indexName : conv->indexName();
685 QuantLib::ext::shared_ptr<IborIndex> index;
686 Handle<YieldTermStructure> discountCurve;
687 if (market == nullptr) {
688 index = parseIborIndex(name);
689 } else {
690 if (!expDiscountCurve.empty()) {
691 // Look up the explicit discount curve in the market
692 QuantLib::ext::shared_ptr<IborIndex> dummyIndex;
693 if (tryParseIborIndex(expDiscountCurve, dummyIndex)) {
694 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
695 discountCurve = discountIndex->forwardingTermStructure();
696 } else {
697 discountCurve = market->yieldCurve(expDiscountCurve, marketConfiguration);
698 }
699 } else if (ccy != "")
700 discountCurve = market->discountCurve(ccy, marketConfiguration);
701 else if (yieldCurveName != "")
702 discountCurve = market->yieldCurve(yieldCurveName, marketConfiguration);
703 else if (equityForecastCurveName != "")
704 discountCurve = market->equityForecastCurve(equityForecastCurveName, marketConfiguration);
705
706 index = *market->iborIndex(name, marketConfiguration);
707
708 if (singleCurve) {
709 if (indexName != "")
710 discountCurve = index->forwardingTermStructure();
711 else if (yieldCurveName != "") {
712 index = index->clone(market->yieldCurve(yieldCurveName, marketConfiguration));
713 discountCurve = market->yieldCurve(yieldCurveName, marketConfiguration);
714 } else if (ccy != "")
715 index = index->clone(market->discountCurve(ccy, marketConfiguration));
716 else if (equityForecastCurveName != "") {
717 index = index->clone(market->equityForecastCurve(equityForecastCurveName, marketConfiguration));
718 discountCurve = market->equityForecastCurve(equityForecastCurveName, marketConfiguration);
719 } else
720 QL_FAIL("Discount curve undetermined for Swap (ccy=" << ccy << ")");
721 }
722 }
723
724 if (!singleCurve)
725 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, name, 0);
726
727 QuantLib::ext::shared_ptr<Swap> helper;
728 Date latestRelevantDate;
729
730 auto bmaIndex = QuantLib::ext::dynamic_pointer_cast<QuantExt::BMAIndexWrapper>(index);
731 if (bmaIndex) {
732 // FIXME do we want to remove today's historic fixing from the index as we do for the Ibor case?
733 helper = QuantLib::ext::shared_ptr<FixedBMASwap>(
734 MakeFixedBMASwap(term, bmaIndex->bma(), 0.0, 0 * Days).withBMALegTenor(3 * Months));
735 // need to do very little with the factory, as the market conventions are default
736 // should maybe discount with Libor, as this is how we assume the quotes come in.
737 QuantLib::ext::shared_ptr<AverageBMACoupon> lastCoupon =
738 QuantLib::ext::dynamic_pointer_cast<AverageBMACoupon>(helper->leg(1).back());
739 latestRelevantDate = std::max(helper->maturityDate(), lastCoupon->fixingDates().end()[-2]);
740 } else if (conv->hasSubPeriod()) {
741 removeTodaysFixingIndices.insert(index->name());
742 auto subPeriodSwap = QuantLib::ext::shared_ptr<SubPeriodsSwap>(
743 MakeSubPeriodsSwap(term, index, 0.0, Period(conv->floatFrequency()), 0 * Days)
744 .withSettlementDays(index->fixingDays())
745 .withFixedLegDayCount(conv->fixedDayCounter())
746 .withFixedLegTenor(Period(conv->fixedFrequency()))
747 .withFixedLegConvention(conv->fixedConvention())
748 .withFixedLegCalendar(conv->fixedCalendar())
749 .withSubCouponsType(conv->subPeriodsCouponType()));
750
751 latestRelevantDate = subPeriodSwap->maturityDate();
752 QuantLib::ext::shared_ptr<FloatingRateCoupon> lastCoupon =
753 QuantLib::ext::dynamic_pointer_cast<FloatingRateCoupon>(subPeriodSwap->floatLeg().back());
754 helper = subPeriodSwap;
755 if (IborCoupon::Settings::instance().usingAtParCoupons()) {
756 /* Subperiods coupons do not have a par approximation either... */
757 if (QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(lastCoupon)) {
758 Date fixingValueDate = index->valueDate(lastCoupon->fixingDate());
759 Date endValueDate = index->maturityDate(fixingValueDate);
760 latestRelevantDate = std::max(latestRelevantDate, endValueDate);
761 }
762 } else {
763 /* May need to adjust latestRelevantDate if you are projecting libor based
764 on tenor length rather than from accrual date to accrual date. */
765 Date fixingValueDate = index->valueDate(lastCoupon->fixingDate());
766 Date endValueDate = index->maturityDate(fixingValueDate);
767 latestRelevantDate = std::max(latestRelevantDate, endValueDate);
768 }
769 } else {
770 removeTodaysFixingIndices.insert(index->name());
771 helper = QuantLib::ext::shared_ptr<VanillaSwap>(MakeVanillaSwap(term, index, 0.0, 0 * Days)
772 .withSettlementDays(index->fixingDays())
773 .withFixedLegDayCount(conv->fixedDayCounter())
774 .withFixedLegTenor(Period(conv->fixedFrequency()))
775 .withFixedLegConvention(conv->fixedConvention())
776 .withFixedLegTerminationDateConvention(conv->fixedConvention())
777 .withFixedLegCalendar(conv->fixedCalendar())
778 .withFloatingLegCalendar(conv->fixedCalendar()));
779 QuantLib::ext::shared_ptr<IborCoupon> lastCoupon = QuantLib::ext::dynamic_pointer_cast<IborCoupon>(helper->leg(1).back());
780 latestRelevantDate = std::max(helper->maturityDate(), lastCoupon->fixingEndDate());
781 }
782
783 if (market) {
784 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
785 helper->setPricingEngine(swapEngine);
786 }
787
788 // set pillar date
789 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, latestRelevantDate);
790}
MakeFixedBMASwap & withBMALegTenor(const Period &tenor)
MakeSubPeriodsSwap & withFixedLegTenor(const Period &t)
MakeSubPeriodsSwap & withSettlementDays(Natural settlementDays)
MakeSubPeriodsSwap & withFixedLegConvention(BusinessDayConvention bdc)
MakeSubPeriodsSwap & withSubCouponsType(const QuantExt::SubPeriodsCoupon1::Type &st)
MakeSubPeriodsSwap & withFixedLegDayCount(const DayCounter &dc)
MakeSubPeriodsSwap & withFixedLegCalendar(const Calendar &cal)
bool tryParseIborIndex(const string &s, QuantLib::ext::shared_ptr< IborIndex > &index)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeOIS()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeOIS ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  indexName,
std::string  yieldCurveName,
std::string  equityForecastCurveName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
bool  singleCurve,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
std::set< std::string > &  removeTodaysFixingIndices,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create OIS Swap for implying par rate sensitivity from zero rate sensitivity.

Definition at line 918 of file parsensitivityinstrumentbuilder.cpp.

922 {
923 // Curve priorities, use in the following order if ccy/indexName/yieldCurveName strings are not blank
924 // 1) singleCurve = false
925 // - discounts: discountCurve(ccy) -> yieldCurve(yieldCurveName)
926 // - forwards: iborIndex(indexName) -> iborIndex(conventions index name)
927 // 2) singleCurve = true
928 // - discounts: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
929 // - forwards: iborIndex(indexName) -> yieldCurve(yieldCurveName) -> discountCurve(ccy)
930 QuantLib::ext::shared_ptr<OisConvention> conv = QuantLib::ext::dynamic_pointer_cast<OisConvention>(convention);
931 QL_REQUIRE(conv, "convention not recognised, expected OisConvention");
932 QuantLib::ext::shared_ptr<IborIndex> index = parseIborIndex(conv->indexName());
933 if (market == nullptr) {
934 if (!expDiscountCurve.empty())
935 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, expDiscountCurve, 0);
936 else
937 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy);
938 if (!singleCurve)
939 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve,
940 indexName != "" ? indexName : conv->indexName(), 0);
941 }
942 QuantLib::ext::shared_ptr<OvernightIndex> overnightIndexTmp = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index);
943 QL_REQUIRE(overnightIndexTmp,
944 "ParSensitivityAnalysis::makeOIS(): expected OIS index, got \"" << conv->indexName() << "\"");
945 // makeOIS below requires non-empty ts
946 Handle<YieldTermStructure> indexTs =
947 Handle<YieldTermStructure>(QuantLib::ext::make_shared<FlatForward>(0, NullCalendar(), 0.00, Actual365Fixed()));
948 if (market != nullptr) {
949 if (singleCurve) {
950 if (indexName != "") {
951 indexTs = market->iborIndex(indexName, marketConfiguration).currentLink()->forwardingTermStructure();
952 } else if (yieldCurveName != "") {
953 indexTs = market->yieldCurve(yieldCurveName, marketConfiguration);
954 } else if (equityForecastCurveName != "") {
955 indexTs = market->equityForecastCurve(equityForecastCurveName, marketConfiguration);
956 } else if (ccy != "") {
957 indexTs = market->discountCurve(ccy, marketConfiguration);
958 } else {
959 QL_FAIL("Index curve not identified in ParSensitivityAnalysis::makeOIS");
960 }
961 } else {
962 indexTs = market->iborIndex(indexName != "" ? indexName : conv->indexName(), marketConfiguration)
963 .currentLink()
964 ->forwardingTermStructure();
965 }
966 }
967 QuantLib::ext::shared_ptr<OvernightIndex> overnightIndex =
968 QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(overnightIndexTmp->clone(indexTs));
969 removeTodaysFixingIndices.insert(overnightIndex->name());
970 QuantLib::ext::shared_ptr<OvernightIndexedSwap> helper =
971 MakeOIS(term, overnightIndex, Null<Rate>(), 0 * Days).withTelescopicValueDates(true);
972
973 if (market != nullptr) {
974 RelinkableHandle<YieldTermStructure> engineYts;
975 if (singleCurve) {
976 if (indexName != "")
977 engineYts.linkTo(*indexTs);
978 else if (yieldCurveName != "")
979 engineYts.linkTo(*market->yieldCurve(yieldCurveName, marketConfiguration));
980 else if (equityForecastCurveName != "")
981 engineYts.linkTo(*market->equityForecastCurve(equityForecastCurveName, marketConfiguration));
982 else if (ccy != "")
983 engineYts.linkTo(*market->discountCurve(ccy, marketConfiguration));
984 else
985 QL_FAIL("discount curve not identified in ParSensitivityAnalysis::makeOIS, single curve (ccy=" << ccy
986 << ")");
987 } else {
988 if (!expDiscountCurve.empty()) {
989 // Look up the explicit discount curve in the market
990 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
991 engineYts.linkTo(*discountIndex->forwardingTermStructure());
992 } else if (ccy != "")
993 engineYts.linkTo(*market->discountCurve(ccy, marketConfiguration));
994 else if (yieldCurveName != "")
995 engineYts.linkTo(*market->yieldCurve(yieldCurveName, marketConfiguration));
996 else if (equityForecastCurveName != "")
997 engineYts.linkTo(*market->equityForecastCurve(equityForecastCurveName, marketConfiguration));
998 else
999 QL_FAIL("discount curve not identified in ParSensitivityAnalysis::makeOIS, multi curve (ccy=" << ccy
1000 << ")");
1001 }
1002 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(engineYts);
1003 helper->setPricingEngine(swapEngine);
1004 }
1005
1006 // set pillar date
1007 Date latestRelevantDate = helper->maturityDate();
1008 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, latestRelevantDate);
1009}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeTenorBasisSwap()

std::pair< QuantLib::ext::shared_ptr< QuantLib::Instrument >, Date > makeTenorBasisSwap ( const QuantLib::Date &  asof,
const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  receiveIndexName,
std::string  payIndexName,
std::string  yieldCurveName,
std::string  equityForecastCurveName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
const bool  singleCurve,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
std::set< std::string > &  removeTodaysFixingIndices,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Basis Swap for implying par rate sensitivity from zero rate sensitivity.

Definition at line 1011 of file parsensitivityinstrumentbuilder.cpp.

1016 {
1017
1018 QuantLib::ext::shared_ptr<TenorBasisSwapConvention> conv =
1019 QuantLib::ext::dynamic_pointer_cast<TenorBasisSwapConvention>(convention);
1020 QL_REQUIRE(conv, "convention not recognised, expected TenorBasisSwapConvention");
1021 Handle<YieldTermStructure> discountCurve, receiveIndexCurve, payIndexCurve;
1022 QuantLib::ext::shared_ptr<IborIndex> payIndex = parseIborIndex(conv->payIndexName());
1023 QuantLib::ext::shared_ptr<IborIndex> receiveIndex = parseIborIndex(conv->receiveIndexName());
1024 QuantLib::ext::shared_ptr<OvernightIndex> receiveIndexOn = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(receiveIndex);
1025 QuantLib::ext::shared_ptr<OvernightIndex> payIndexOn = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(payIndex);
1026
1027 if (market != nullptr) {
1028 if (!expDiscountCurve.empty()) {
1029 // Look up the explicit discount curve in the market
1030 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
1031 discountCurve = discountIndex->forwardingTermStructure();
1032 } else if (ccy != "")
1033 discountCurve = market->discountCurve(ccy, marketConfiguration);
1034 else if (yieldCurveName != "")
1035 discountCurve = market->yieldCurve(yieldCurveName, marketConfiguration);
1036 else if (equityForecastCurveName != "")
1037 discountCurve = market->equityForecastCurve(equityForecastCurveName, marketConfiguration);
1038 else {
1039 QL_FAIL("tenor basis swap discount curve undetermined");
1040 }
1041 if (singleCurve)
1042 receiveIndexCurve = discountCurve;
1043 else
1044 receiveIndexCurve = market
1045 ->iborIndex(receiveIndexName != "" ? receiveIndexName : conv->receiveIndexName(),
1046 marketConfiguration)
1047 ->forwardingTermStructure();
1048 payIndexCurve = market->iborIndex(payIndexName != "" ? payIndexName : conv->payIndexName(), marketConfiguration)
1049 ->forwardingTermStructure();
1050 }
1051 payIndex = payIndex->clone(payIndexCurve);
1052 receiveIndex = receiveIndex->clone(receiveIndexCurve);
1053
1054 QuantLib::ext::shared_ptr<Libor> payIndexAsLibor = QuantLib::ext::dynamic_pointer_cast<Libor>(payIndex);
1055 QuantLib::ext::shared_ptr<Libor> receiveIndexAsLibor = QuantLib::ext::dynamic_pointer_cast<Libor>(receiveIndex);
1056 Calendar payIndexCalendar =
1057 payIndexAsLibor != nullptr ? payIndexAsLibor->jointCalendar() : payIndex->fixingCalendar();
1058 Calendar receiveIndexCalendar =
1059 receiveIndexAsLibor != nullptr ? receiveIndexAsLibor->jointCalendar() : receiveIndex->fixingCalendar();
1060 removeTodaysFixingIndices.insert(receiveIndex->name());
1061 removeTodaysFixingIndices.insert(payIndex->name());
1062
1063 Date settlementDate = payIndexCalendar.advance(payIndexCalendar.adjust(asof), payIndex->fixingDays() * Days);
1064
1065 bool telescopicValueDates = true;
1066 QuantLib::ext::shared_ptr<Swap> helper = QuantLib::ext::make_shared<TenorBasisSwap>(
1067 settlementDate, 1.0, term, payIndex, 0.0, conv->payFrequency(), receiveIndex, 0.0, conv->receiveFrequency(),
1068 DateGeneration::Backward, conv->includeSpread(), conv->spreadOnRec(), conv->subPeriodsCouponType(),
1069 telescopicValueDates);
1070
1071 QuantLib::ext::shared_ptr<IborCoupon> lastCoupon1 =
1072 QuantLib::ext::dynamic_pointer_cast<IborCoupon>(QuantLib::ext::static_pointer_cast<TenorBasisSwap>(helper)->payLeg().back());
1073 Date maxDate2;
1074 QuantLib::ext::shared_ptr<IborCoupon> lastCoupon2 =
1075 QuantLib::ext::dynamic_pointer_cast<IborCoupon>(QuantLib::ext::static_pointer_cast<TenorBasisSwap>(helper)->recLeg().back());
1076 if (lastCoupon2 != nullptr)
1077 maxDate2 = lastCoupon2->fixingEndDate();
1078 else {
1079 QuantLib::ext::shared_ptr<QuantExt::SubPeriodsCoupon1> lastCoupon2;
1080 if (conv->spreadOnRec())
1081 lastCoupon2 = QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(
1082 QuantLib::ext::static_pointer_cast<TenorBasisSwap>(helper)->payLeg().back());
1083 else
1084 lastCoupon2 = QuantLib::ext::dynamic_pointer_cast<QuantExt::SubPeriodsCoupon1>(
1085 QuantLib::ext::static_pointer_cast<TenorBasisSwap>(helper)->recLeg().back());
1086 maxDate2 = receiveIndexCalendar.advance(lastCoupon2->valueDates().back(), conv->receiveFrequency());
1087 }
1088 Date latestRelevantDate = std::max(helper->maturityDate(), std::max(lastCoupon1->fixingEndDate(), maxDate2));
1089
1090 if (market != nullptr) {
1091 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
1092 helper->setPricingEngine(swapEngine);
1093 } else {
1094 if (!singleCurve) {
1095 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, receiveIndexName, 0);
1096 }
1097 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, payIndexName, 0);
1098 if (!expDiscountCurve.empty())
1099 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, expDiscountCurve, 0);
1100 else
1101 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy);
1102 }
1103
1104 // latest date and return result
1105 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, latestRelevantDate);
1106}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeCapFloor()

QuantLib::ext::shared_ptr< CapFloor > makeCapFloor ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  ccy,
std::string  indexName,
QuantLib::Period  term,
double  strike,
bool  generatePillar,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Cap/Floor QuantLib::Instrument for implying flat vol sensitivity from optionlet vol sensitivity.

Definition at line 1108 of file parsensitivityinstrumentbuilder.cpp.

1111 {
1112
1113 QuantLib::ext::shared_ptr<CapFloor> inst;
1114 auto conventions = InstrumentConventions::instance().conventions();
1115
1116 if (!market) {
1117 // No market so just return a dummy cap
1118 QuantLib::ext::shared_ptr<IborIndex> index = parseIborIndex(indexName);
1119 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index) == nullptr,
1120 "ParSensitivityAnalysis::makeCapFloor(): OIS indices are not yet supported for par conversion");
1121 inst = MakeCapFloor(CapFloor::Cap, term, index, 0.03);
1122 } else {
1123
1124 QuantLib::ext::shared_ptr<IborIndex> index = *market->iborIndex(indexName, marketConfiguration);
1125 QL_REQUIRE(QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(index) == nullptr,
1126 "ParSensitivityAnalysis::makeCapFloor(): OIS indices are not yet supported for par conversion");
1127 QL_REQUIRE(index, "Index not found with name " << indexName);
1128 Handle<YieldTermStructure> discount;
1129 if (expDiscountCurve.empty())
1130 discount = market->discountCurve(ccy, marketConfiguration);
1131 else
1132 discount = market->iborIndex(expDiscountCurve, marketConfiguration)->forwardingTermStructure();
1133 QL_REQUIRE(!discount.empty(), "Discount curve not found for cap floor index " << indexName);
1134
1135 // Create a dummy cap just to get the ATM rate
1136 // Note this construction excludes the first caplet which is what we want
1137 inst = MakeCapFloor(CapFloor::Cap, term, index, 0.03);
1138 Rate atmRate = inst->atmRate(**discount);
1139 // bool isAtm = strike == Null<Real>();
1140 // strike = isAtm ? atmRate : strike;
1141 strike = strike == Null<Real>() ? atmRate : strike;
1142 CapFloor::Type type = strike >= atmRate ? CapFloor::Cap : CapFloor::Floor;
1143
1144 // Create the actual cap or floor instrument that we will use
1145 if (isAtm) {
1146 inst = MakeCapFloor(type, term, index, atmRate);
1147 } else {
1148 inst = MakeCapFloor(type, term, index, strike);
1149 }
1150 Handle<OptionletVolatilityStructure> ovs = market->capFloorVol(indexName, marketConfiguration);
1151 QL_REQUIRE(!ovs.empty(), "Optionlet volatility structure not found for index " << indexName);
1152 QL_REQUIRE(ovs->volatilityType() == ShiftedLognormal || ovs->volatilityType() == Normal,
1153 "Optionlet volatility type " << ovs->volatilityType() << " not covered");
1154 QuantLib::ext::shared_ptr<PricingEngine> engine;
1155 if (ovs->volatilityType() == ShiftedLognormal) {
1156 engine = QuantLib::ext::make_shared<BlackCapFloorEngine>(discount, ovs, ovs->displacement());
1157 } else {
1158 engine = QuantLib::ext::make_shared<BachelierCapFloorEngine>(discount, ovs);
1159 }
1160 inst->setPricingEngine(engine);
1161 }
1162 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy);
1163 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, indexName);
1164 // set pillar date
1165 // if (generatePillar) {
1166 // capFloorPillars_[ccy].push_back(term /*(end - asof) * Days*/);
1167 // }
1168
1169 QL_REQUIRE(inst, "empty cap/floor par instrument pointer");
1170 return inst;
1171}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeCrossCcyBasisSwap()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeCrossCcyBasisSwap ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  baseCcy,
std::string  ccy,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
std::set< std::string > &  removeTodaysFixingIndices,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Cross Ccy Basis Swap for implying par rate sensitivity from zero rate sensitivity.

Definition at line 1173 of file parsensitivityinstrumentbuilder.cpp.

1176 {
1177
1178 auto conventions = InstrumentConventions::instance().conventions();
1179 QuantLib::ext::shared_ptr<CrossCcyBasisSwapConvention> conv =
1180 QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapConvention>(convention);
1181 QL_REQUIRE(conv, "convention not recognised, expected CrossCcyBasisSwapConvention");
1182 QL_REQUIRE(baseCcy == conv->flatIndex()->currency().code() || baseCcy == conv->spreadIndex()->currency().code(),
1183 "base currency " << baseCcy << " not covered by convention " << conv->id());
1184 QL_REQUIRE(ccy == conv->flatIndex()->currency().code() || ccy == conv->spreadIndex()->currency().code(),
1185 "currency " << ccy << " not covered by convention " << conv->id());
1186 string baseIndexName, indexName;
1187 Period baseIndexTenor, indexTenor;
1188 if (baseCcy == conv->flatIndex()->currency().code()) {
1189 baseIndexName = conv->flatIndexName();
1190 baseIndexTenor = conv->flatTenor();
1191 indexName = conv->spreadIndexName();
1192 indexTenor = conv->spreadTenor();
1193 } else {
1194 baseIndexName = conv->spreadIndexName();
1195 baseIndexTenor = conv->spreadTenor();
1196 indexName = conv->flatIndexName();
1197 indexTenor = conv->flatTenor();
1198 }
1199 Currency baseCurrency = parseCurrency(baseCcy);
1200 Currency currency = parseCurrency(ccy);
1201 Handle<IborIndex> baseIndex, index;
1202 if (market != nullptr) {
1203 baseIndex = market->iborIndex(baseIndexName, marketConfiguration);
1204 index = market->iborIndex(indexName, marketConfiguration);
1205 } else {
1206 baseIndex = Handle<IborIndex>(parseIborIndex(baseIndexName));
1207 index = Handle<IborIndex>(parseIborIndex(indexName));
1208 }
1209 Date today = Settings::instance().evaluationDate();
1210
1211 // For now, to mimic the xccy helper behaviour in the case that today is settlementCalendar holiday
1212 today = conv->settlementCalendar().adjust(today);
1213
1214 Date start = conv->settlementCalendar().advance(today, conv->settlementDays() * Days, conv->rollConvention());
1215 Date end = conv->settlementCalendar().advance(start, term, conv->rollConvention());
1216 Schedule baseSchedule = MakeSchedule()
1217 .from(start)
1218 .to(end)
1219 .withTenor(baseIndexTenor)
1220 .withCalendar(conv->settlementCalendar())
1221 .withConvention(conv->rollConvention())
1222 .endOfMonth(conv->eom());
1223 Schedule schedule = MakeSchedule()
1224 .from(start)
1225 .to(end)
1226 .withTenor(indexTenor)
1227 .withCalendar(conv->settlementCalendar())
1228 .withConvention(conv->rollConvention())
1229 .endOfMonth(conv->eom());
1230 Real baseNotional = 1.0;
1231 // the fx spot is not needed in the dry run
1232 Handle<Quote> fxSpot =
1233 market != nullptr
1234 // use instantaneous fx rate
1235 ? market->fxRate(ccy + baseCcy, marketConfiguration)
1236 : Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0)); // multiplicative conversion into base ccy
1237 Real notional = 1.0 / fxSpot->value();
1238
1239 RelinkableHandle<YieldTermStructure> baseDiscountCurve;
1240 RelinkableHandle<YieldTermStructure> discountCurve;
1241 QuantLib::ext::shared_ptr<FxIndex> fxIndex =
1242 QuantLib::ext::make_shared<FxIndex>("dummy", conv->settlementDays(), currency, baseCurrency, conv->settlementCalendar(),
1243 fxSpot, discountCurve, baseDiscountCurve);
1244 auto m = [](Real x) { return 1.0 / x; };
1245 QuantLib::ext::shared_ptr<FxIndex> reversedFxIndex = QuantLib::ext::make_shared<FxIndex>(
1246 "dummyRev", conv->settlementDays(), baseCurrency, currency, conv->settlementCalendar(),
1247 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<decltype(m)>>(fxSpot, m)), baseDiscountCurve, discountCurve);
1248
1249 // LOG("Make Cross Ccy Swap for base ccy " << baseCcy << " currency " << ccy);
1250 // Set up first leg as spread leg, second as flat leg
1251 removeTodaysFixingIndices.insert(baseIndex->name());
1252 removeTodaysFixingIndices.insert(index->name());
1253 QuantLib::ext::shared_ptr<CrossCcySwap> helper;
1254 bool telescopicValueDates = true; // same as in the yield curve building
1255
1256 if (baseCcy == conv->spreadIndex()->currency().code()) { // base ccy index is spread index
1257 if (conv->isResettable() && conv->flatIndexIsResettable()) { // i.e. flat index leg is resettable
1258 DLOG("create resettable xccy par instrument (1), convention " << conv->id());
1259 helper = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
1260 baseNotional, baseCurrency, baseSchedule, *baseIndex, 0.0, // spread index leg => use fairForeignSpread
1261 currency, schedule, *index, 0.0, reversedFxIndex, true, // resettable flat index leg
1262 conv->paymentLag(), conv->flatPaymentLag(), conv->includeSpread(), conv->lookback(), conv->fixingDays(),
1263 conv->rateCutoff(), conv->isAveraged(), conv->flatIncludeSpread(), conv->flatLookback(),
1264 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), telescopicValueDates,
1265 true); // fair spread leg is foreign
1266 } else if (conv->isResettable() && !conv->flatIndexIsResettable()) { // i.e. spread index leg is resettable
1267 DLOG("create resettable xccy par instrument (2), convention " << conv->id());
1268 helper = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
1269 notional, currency, schedule, *index, 0.0, // flat index leg
1270 baseCurrency, baseSchedule, *baseIndex, 0.0, fxIndex,
1271 true, // resettable spread index leg => use fairDomesticSpread
1272 conv->flatPaymentLag(), conv->paymentLag(), conv->flatIncludeSpread(), conv->flatLookback(),
1273 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), conv->includeSpread(),
1274 conv->lookback(), conv->fixingDays(), conv->rateCutoff(), conv->isAveraged(), telescopicValueDates,
1275 false); // fair spread leg is domestic
1276 } else { // not resettable
1277 DLOG("create non-resettable xccy par instrument (3), convention " << conv->id());
1278 helper = QuantLib::ext::make_shared<CrossCcyBasisSwap>(
1279 baseNotional, baseCurrency, baseSchedule, *baseIndex, 0.0, 1.0, // spread index leg => use fairPaySpread
1280 notional, currency, schedule, *index, 0.0, 1.0, // flat index leg
1281 conv->paymentLag(), conv->flatPaymentLag(), conv->includeSpread(), conv->lookback(), conv->fixingDays(),
1282 conv->rateCutoff(), conv->isAveraged(), conv->flatIncludeSpread(), conv->flatLookback(),
1283 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), telescopicValueDates);
1284 }
1285 } else { // base ccy index is flat index
1286 if (conv->isResettable() && conv->flatIndexIsResettable()) {
1287 DLOG("create resettable xccy par instrument (4), convention " << conv->id());
1288 // second leg is resettable, so the second leg is the base currency leg
1289 helper = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
1290 notional, currency, schedule, *index, 0.0, // spread index leg => use fairForeignSpread
1291 baseCurrency, baseSchedule, *baseIndex, 0.0, fxIndex, true, // resettable flat index leg
1292 conv->paymentLag(), conv->flatPaymentLag(), conv->includeSpread(), conv->lookback(), conv->fixingDays(),
1293 conv->rateCutoff(), conv->isAveraged(), conv->flatIncludeSpread(), conv->flatLookback(),
1294 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), telescopicValueDates,
1295 true); // fair spread leg is foreign
1296 } else if (conv->isResettable() && !conv->flatIndexIsResettable()) {
1297 DLOG("create resettable xccy par instrument (5), convention " << conv->id());
1298 // second leg is resettable, so the second leg is the non-base non-flat spread leg
1299 helper = QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwap>(
1300 baseNotional, baseCurrency, baseSchedule, *baseIndex, 0.0, // flat index leg
1301 currency, schedule, *index, 0.0, reversedFxIndex,
1302 true, // resettable spread index leg => use fairDomesticSpread
1303 conv->flatPaymentLag(), conv->paymentLag(), conv->flatIncludeSpread(), conv->flatLookback(),
1304 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), conv->includeSpread(),
1305 conv->lookback(), conv->fixingDays(), conv->rateCutoff(), conv->isAveraged(), telescopicValueDates,
1306 false); // fair spread leg is domestic
1307 } else { // not resettable
1308 DLOG("create non-resettable xccy par instrument (6), convention " << conv->id());
1309 helper = QuantLib::ext::make_shared<CrossCcyBasisSwap>(
1310 notional, currency, schedule, *index, 0.0, 1.0, // spread index leg => use fairPaySpread
1311 baseNotional, baseCurrency, baseSchedule, *baseIndex, 0.0, 1.0, // flat index leg
1312 conv->paymentLag(), conv->flatPaymentLag(), conv->includeSpread(), conv->lookback(), conv->fixingDays(),
1313 conv->rateCutoff(), conv->isAveraged(), conv->flatIncludeSpread(), conv->flatLookback(),
1314 conv->flatFixingDays(), conv->flatRateCutoff(), conv->flatIsAveraged(), telescopicValueDates);
1315 }
1316 }
1317
1318 bool isBaseDiscount = true;
1319 bool isNonBaseDiscount = true;
1320 if (market != nullptr) {
1321 baseDiscountCurve.linkTo(xccyYieldCurve(market, baseCcy, isBaseDiscount, marketConfiguration).currentLink());
1322 discountCurve.linkTo(xccyYieldCurve(market, ccy, isNonBaseDiscount, marketConfiguration).currentLink());
1323 QuantLib::ext::shared_ptr<PricingEngine> swapEngine =
1324 QuantLib::ext::make_shared<CrossCcySwapEngine>(baseCurrency, baseDiscountCurve, currency, discountCurve, fxSpot);
1325 helper->setPricingEngine(swapEngine);
1326 }
1327
1328 if (isBaseDiscount)
1329 parHelperDependencies_.emplace(RiskFactorKey::KeyType::YieldCurve, baseCcy, 0);
1330 else
1331 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, baseCcy, 0);
1332
1333 if (isNonBaseDiscount)
1334 parHelperDependencies_.emplace(RiskFactorKey::KeyType::YieldCurve, ccy, 0);
1335 else
1336 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy, 0);
1337
1338 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, baseIndexName, 0);
1339 parHelperDependencies_.emplace(RiskFactorKey::KeyType::IndexCurve, indexName, 0);
1340
1341 // set pillar date
1342 Date latestRelevantDate = helper->maturityDate();
1343 if (auto i = QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwap>(helper)) {
1344 QuantLib::ext::shared_ptr<IborCoupon> lastCoupon0 =
1345 QuantLib::ext::dynamic_pointer_cast<IborCoupon>(helper->leg(0)[helper->leg(0).size() - 2]);
1346 QuantLib::ext::shared_ptr<IborCoupon> lastCoupon1 =
1347 QuantLib::ext::dynamic_pointer_cast<IborCoupon>(helper->leg(1)[helper->leg(1).size() - 2]);
1348 if (lastCoupon0 != nullptr)
1349 latestRelevantDate = std::max(latestRelevantDate, lastCoupon0->fixingEndDate());
1350 if (lastCoupon1 != nullptr)
1351 latestRelevantDate = std::max(latestRelevantDate, lastCoupon1->fixingEndDate());
1352 // yieldCurvePillars_[ccy].push_back((latestRelevantDate - asof) * Days);
1353 }
1354
1355 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, latestRelevantDate);
1356}
Currency parseCurrency(const string &s)
Handle< YieldTermStructure > xccyYieldCurve(const QuantLib::ext::shared_ptr< Market > &market, const string &ccyCode, const string &configuration)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeFxForward()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeFxForward ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  baseCcy,
std::string  ccy,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create FX Forwrad for implying par rate sensitivity from zero rate sensitivity.

Definition at line 1359 of file parsensitivityinstrumentbuilder.cpp.

1362 {
1363
1364 QuantLib::ext::shared_ptr<FXConvention> conv = QuantLib::ext::dynamic_pointer_cast<FXConvention>(convention);
1365 QL_REQUIRE(conv, "convention not recognised, expected FXConvention");
1366 QL_REQUIRE(baseCcy == conv->sourceCurrency().code() || baseCcy == conv->targetCurrency().code(),
1367 "base currency " << baseCcy << " not covered by convention " << conv->id());
1368 QL_REQUIRE(ccy == conv->sourceCurrency().code() || ccy == conv->targetCurrency().code(),
1369 "currency " << ccy << " not covered by convention " << conv->id());
1370 Currency baseCurrency = parseCurrency(baseCcy);
1371 Currency currency = parseCurrency(ccy);
1372 Date today = Settings::instance().evaluationDate();
1373 Date spot = conv->advanceCalendar().advance(today, conv->spotDays() * Days);
1374 Date maturity = conv->advanceCalendar().advance(spot, term);
1375 Real baseNotional = 1.0;
1376 Handle<Quote> fxSpot =
1377 market != nullptr
1378 ? market->fxRate(ccy + baseCcy, marketConfiguration)
1379 : Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(1.0)); // multiplicative conversion into base ccy
1380 Real notional = 1.0 / fxSpot->value();
1381 QuantLib::ext::shared_ptr<FxForward> helper =
1382 QuantLib::ext::make_shared<FxForward>(baseNotional, baseCurrency, notional, currency, maturity, true);
1383
1384 bool isBaseDiscount = true;
1385 bool isNonBaseDiscount = true;
1386 if (market != nullptr) {
1387 Handle<YieldTermStructure> baseDiscountCurve =
1388 xccyYieldCurve(market, baseCcy, isBaseDiscount, marketConfiguration);
1389 Handle<YieldTermStructure> discountCurve = xccyYieldCurve(market, ccy, isNonBaseDiscount, marketConfiguration);
1390 QuantLib::ext::shared_ptr<PricingEngine> engine = QuantLib::ext::make_shared<DiscountingFxForwardEngine>(
1391 baseCurrency, baseDiscountCurve, currency, discountCurve, fxSpot);
1392 helper->setPricingEngine(engine);
1393 }
1394
1395 if (isBaseDiscount)
1396 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, baseCcy, 0);
1397 else
1398 parHelperDependencies_.emplace(RiskFactorKey::KeyType::YieldCurve, baseCcy, 0);
1399
1400 if (isNonBaseDiscount)
1401 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy, 0);
1402 else
1403 parHelperDependencies_.emplace(RiskFactorKey::KeyType::YieldCurve, ccy, 0);
1404
1405 // set pillar date
1406 // yieldCurvePillars_[ccy].push_back((maturity - asof) * Days);
1407 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, maturity);
1408}
Time maturity
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeCDS()

std::pair< QuantLib::ext::shared_ptr< Instrument >, Date > makeCDS ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  name,
std::string  ccy,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create CDS for implying par rate sensitivity from Hazard Rate sensitivity.

Definition at line 1411 of file parsensitivityinstrumentbuilder.cpp.

1414 {
1415
1416 QuantLib::ext::shared_ptr<CdsConvention> conv = QuantLib::ext::dynamic_pointer_cast<CdsConvention>(convention);
1417 QL_REQUIRE(conv, "convention not recognised, expected CdsConvention");
1418
1419 QuantLib::ext::shared_ptr<QuantExt::CreditDefaultSwap> helper = MakeCreditDefaultSwap(term, 0.1)
1420 .withNominal(1)
1421 .withCouponTenor(Period(conv->frequency()))
1422 .withDayCounter(conv->dayCounter())
1423 .withDateGenerationRule(conv->rule())
1424 .withSettlesAccrual(conv->settlesAccrual())
1425 .withPaysAtDefaultTime(conv->paysAtDefaultTime())
1426 // .withPaysAtDefaultTime(conv->rebatesAccrual()) // FIXME: missing in conventions
1427 ;
1428
1429 if (market != nullptr) {
1430 Handle<YieldTermStructure> yts;
1431 if (!expDiscountCurve.empty()) {
1432 // Look up the explicit discount curve in the market
1433 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
1434 yts = discountIndex->forwardingTermStructure();
1435 } else {
1436 yts = market->discountCurve(ccy, marketConfiguration);
1437 }
1438
1439 Handle<DefaultProbabilityTermStructure> dpts = market->defaultCurve(name, marketConfiguration)->curve();
1440 Handle<Quote> recovery = market->recoveryRate(name, marketConfiguration);
1441
1442 QuantLib::ext::shared_ptr<PricingEngine> cdsEngine =
1443 QuantLib::ext::make_shared<QuantExt::MidPointCdsEngine>(dpts, recovery->value(), yts);
1444 helper->setPricingEngine(cdsEngine);
1445 }
1446
1447 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy, 0);
1448
1449 // set pillar date
1450 // Date maturity = helper->maturity();
1451 Date maturity = conv->calendar().adjust(helper->maturity(), conv->paymentConvention());
1452 // cdsPillars_[name].push_back((maturity - asof) * Days);
1453 return std::pair<QuantLib::ext::shared_ptr<Instrument>, Date>(helper, maturity);
1454}
MakeCreditDefaultSwap & withPaysAtDefaultTime(bool)
MakeCreditDefaultSwap & withCouponTenor(Period)
MakeCreditDefaultSwap & withNominal(Real)
MakeCreditDefaultSwap & withDayCounter(const DayCounter &)
MakeCreditDefaultSwap & withDateGenerationRule(DateGeneration::Rule rule)
MakeCreditDefaultSwap & withSettlesAccrual(bool)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeZeroInflationSwap()

QuantLib::ext::shared_ptr< Instrument > makeZeroInflationSwap ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  indexName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
bool  singleCurve,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create Zero Swap for implying par rate sensitivity from zero rate sensitivity.

Definition at line 1456 of file parsensitivityinstrumentbuilder.cpp.

1460 {
1461
1462 QuantLib::ext::shared_ptr<InflationSwapConvention> conv = QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(convention);
1463 QL_REQUIRE(conv, "convention not recognised, expected InflationSwapConvention");
1464 string name = indexName != "" ? indexName : conv->indexName();
1465 QuantLib::ext::shared_ptr<ZeroInflationIndex> index = conv->index();
1466 Currency currency = index->currency();
1467 string ccy = currency.code();
1468 Handle<YieldTermStructure> discountCurve;
1469 if (market != nullptr) {
1470 // Get the inflation index
1471 index = *market->zeroInflationIndex(name, marketConfiguration);
1472
1473 // Get the discount curve
1474 if (!expDiscountCurve.empty()) {
1475 // Look up the explicit discount curve in the market
1476 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
1477 discountCurve = discountIndex->forwardingTermStructure();
1478 } else {
1479 // Take the default discount curve for the inflation currency from the market
1480 discountCurve = market->discountCurve(ccy, marketConfiguration);
1481 }
1482 }
1483
1484 // Potentially use conventions here to get an updated start date e.g. AU CPI conventions with a publication roll.
1485 Date start = Settings::instance().evaluationDate();
1486 start = getInflationSwapStart(start, *conv);
1487 Date end = start + term;
1488 QuantLib::ext::shared_ptr<ZeroCouponInflationSwap> helper(new ZeroCouponInflationSwap(
1489 ZeroCouponInflationSwap::Payer, 1.0, start, end, conv->infCalendar(), conv->infConvention(), conv->dayCounter(),
1490 0.0, index, conv->observationLag(), CPI::AsIndex));
1491
1492 if (market != nullptr) {
1493 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
1494 helper->setPricingEngine(swapEngine);
1495 }
1496
1497 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy, 0);
1498
1499 // set pillar date
1500 return helper;
1501}
QuantLib::Date getInflationSwapStart(const Date &asof, const InflationSwapConvention &convention)
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeYoyInflationSwap()

QuantLib::ext::shared_ptr< Instrument > makeYoyInflationSwap ( const QuantLib::ext::shared_ptr< ore::data::Market > &  market,
std::string  indexName,
QuantLib::Period  term,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  conventions,
bool  singleCurve,
bool  fromZero,
std::set< ore::analytics::RiskFactorKey > &  parHelperDependencies,
const std::string &  expDiscountCurve = "",
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create YoY Swap for implying par rate sensitivity from yoy rate sensitivity.

Definition at line 1503 of file parsensitivityinstrumentbuilder.cpp.

1507 {
1508
1509 QuantLib::ext::shared_ptr<InflationSwapConvention> conv = QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(convention);
1510 QL_REQUIRE(conv, "convention not recognised, expected InflationSwapConvention");
1511 string name = indexName != "" ? indexName : conv->indexName();
1512
1513 QuantLib::ext::shared_ptr<ZeroInflationIndex> zeroIndex = conv->index();
1514 QuantLib::ext::shared_ptr<YoYInflationIndex> index =
1515 QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(zeroIndex, conv->interpolated());
1516
1517 // Potentially use conventions here to get an updated start date e.g. AU CPI conventions with a publication roll.
1518 Date start = Settings::instance().evaluationDate();
1519 start = getInflationSwapStart(start, *conv);
1520 Date end = start + term;
1521 Period tenor(1, Years);
1522 Schedule fixSchedule = MakeSchedule()
1523 .from(start)
1524 .to(end)
1525 .withTenor(tenor)
1526 .withCalendar(conv->fixCalendar())
1527 .withConvention(conv->fixConvention());
1528 Schedule yoySchedule = MakeSchedule()
1529 .from(start)
1530 .to(end)
1531 .withTenor(tenor)
1532 .withCalendar(conv->infCalendar())
1533 .withConvention(conv->infConvention());
1534
1535 Currency currency = index->currency();
1536 string ccy = currency.code();
1537 Handle<YieldTermStructure> discountCurve;
1538 if (market != nullptr) {
1539
1540 // Get the inflation index
1541 if (fromZero) {
1542 zeroIndex = *market->zeroInflationIndex(name, marketConfiguration);
1543 index = QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(zeroIndex, false);
1544 } else {
1545 index = *market->yoyInflationIndex(name, marketConfiguration);
1546 }
1547
1548 // Get the discount curve
1549 if (!expDiscountCurve.empty()) {
1550 // Look up the explicit discount curve in the market
1551 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
1552 discountCurve = discountIndex->forwardingTermStructure();
1553 } else {
1554 // Take the default discount curve for the inflation currency from the market
1555 discountCurve = market->discountCurve(ccy, marketConfiguration);
1556 }
1557 }
1558
1559 QuantLib::ext::shared_ptr<YearOnYearInflationSwap> helper(new YearOnYearInflationSwap(
1560 YearOnYearInflationSwap::Payer, 1.0, fixSchedule, 0.0, conv->dayCounter(), yoySchedule, index,
1561 conv->observationLag(), 0.0, conv->dayCounter(), conv->infCalendar()));
1562
1563 QuantLib::ext::shared_ptr<InflationCouponPricer> yoyCpnPricer = QuantLib::ext::make_shared<YoYInflationCouponPricer>(discountCurve);
1564 for (auto& c : helper->yoyLeg()) {
1565 auto cpn = QuantLib::ext::dynamic_pointer_cast<YoYInflationCoupon>(c);
1566 QL_REQUIRE(cpn, "yoy inflation coupon expected, could not cast");
1567 cpn->setPricer(yoyCpnPricer);
1568 }
1569 parHelperDependencies_.emplace(RiskFactorKey::KeyType::DiscountCurve, ccy, 0);
1570
1571 if (fromZero) {
1572 parHelperDependencies_.emplace(RiskFactorKey::KeyType::ZeroInflationCurve, ccy, 0);
1573 }
1574
1575 if (market != nullptr) {
1576 QuantLib::ext::shared_ptr<PricingEngine> swapEngine = QuantLib::ext::make_shared<DiscountingSwapEngine>(discountCurve);
1577 helper->setPricingEngine(swapEngine);
1578 }
1579 return helper;
1580}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ makeYoYCapFloor()

void makeYoYCapFloor ( ParSensitivityInstrumentBuilder::Instruments instruments,
const QuantLib::ext::shared_ptr< Market > &  market,
std::string  indexName,
QuantLib::Period  term,
double  strike,
const QuantLib::ext::shared_ptr< ore::data::Convention > &  convention,
bool  singleCurve,
bool  fromZero,
const std::string &  expDiscountCurve,
const ore::analytics::RiskFactorKey key,
const std::string &  marketConfiguration = ore::data::Market::defaultConfiguration 
) const
private

Create YoY Cap/Floor for implying rate rate sensitivity from yoy optionlet vol sensitivity.

Definition at line 1582 of file parsensitivityinstrumentbuilder.cpp.

1588 {
1589
1590 QuantLib::ext::shared_ptr<InflationSwapConvention> conv = QuantLib::ext::dynamic_pointer_cast<InflationSwapConvention>(convention);
1591 QL_REQUIRE(conv, "convention not recognised, expected InflationSwapConvention");
1592 string name = indexName != "" ? indexName : conv->indexName();
1593
1594 QuantLib::ext::shared_ptr<ZeroInflationIndex> zeroIndex = conv->index();
1595 QuantLib::ext::shared_ptr<YoYInflationIndex> index =
1596 QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(zeroIndex, conv->interpolated());
1597
1598 Date start = Settings::instance().evaluationDate();
1599 Date end = start + term;
1600 Period tenor(1, Years);
1601 Schedule yoySchedule = MakeSchedule()
1602 .from(start)
1603 .to(end)
1604 .withTenor(tenor)
1605 .withCalendar(conv->infCalendar())
1606 .withConvention(conv->infConvention());
1607
1608 Currency currency = index->currency();
1609 string ccy = currency.code();
1610 Handle<YieldTermStructure> discountCurve;
1611 if (market != nullptr) {
1612
1613 // Get the inflation index
1614 if (fromZero) {
1615 zeroIndex = *market->zeroInflationIndex(name, marketConfiguration);
1616 index = QuantLib::ext::make_shared<QuantExt::YoYInflationIndexWrapper>(zeroIndex, conv->interpolated());
1617 } else {
1618 index = *market->yoyInflationIndex(name, marketConfiguration);
1619 }
1620
1621 // Get the discount curve
1622 if (!expDiscountCurve.empty()) {
1623 // Look up the explicit discount curve in the market
1624 auto discountIndex = market->iborIndex(expDiscountCurve, marketConfiguration);
1625 discountCurve = discountIndex->forwardingTermStructure();
1626 } else {
1627 // Take the default discount curve for the inflation currency from the market
1628 discountCurve = market->discountCurve(ccy, marketConfiguration);
1629 }
1630 }
1631
1632 // build the leg data and instrument
1633 Leg yoyLeg = yoyInflationLeg(yoySchedule, yoySchedule.calendar(), index, conv->observationLag())
1634 .withNotionals(1.0)
1635 .withPaymentDayCounter(conv->dayCounter())
1636 .withRateCurve(discountCurve);
1637
1638 if (market == nullptr)
1639 return;
1640
1641 auto ovs = market->yoyCapFloorVol(name, marketConfiguration);
1642 QuantLib::ext::shared_ptr<PricingEngine> engine;
1643 if (ovs->volatilityType() == ShiftedLognormal) {
1644 if (close_enough(ovs->displacement(), 0.0)) {
1645 engine = QuantLib::ext::make_shared<QuantExt::YoYInflationBlackCapFloorEngine>(index, ovs, discountCurve);
1646 } else {
1647 engine =
1648 QuantLib::ext::make_shared<QuantExt::YoYInflationUnitDisplacedBlackCapFloorEngine>(index, ovs, discountCurve);
1649 }
1650 } else if (ovs->volatilityType() == Normal) {
1651 engine = QuantLib::ext::make_shared<QuantExt::YoYInflationBachelierCapFloorEngine>(index, ovs, discountCurve);
1652 } else {
1653 QL_FAIL("ParSensitivityAnalysis::makeYoYCapFloor(): volatility type " << ovs->volatilityType()
1654 << " not handled for index " << name);
1655 }
1656
1657 QuantLib::ext::shared_ptr<YoYInflationCapFloor> atmHelper = QuantLib::ext::make_shared<YoYInflationCapFloor>(
1658 YoYInflationCapFloor::Cap, yoyLeg, std::vector<Real>(yoyLeg.size(), strike));
1659 Rate atmRate = atmHelper->atmRate(**discountCurve);
1660 strike = strike == Null<Real>() ? atmRate : strike;
1661 YoYInflationCapFloor::Type type = strike >= atmRate ? YoYInflationCapFloor::Cap : YoYInflationCapFloor::Floor;
1662 auto helper = QuantLib::ext::make_shared<YoYInflationCapFloor>(type, yoyLeg, std::vector<Real>(yoyLeg.size(), strike));
1663 helper->setPricingEngine(engine);
1664
1665 instruments.parYoYCaps_[key] = helper;
1666 instruments.parYoYCapsYts_[key] = discountCurve;
1667 instruments.parYoYCapsIndex_[key] = Handle<YoYInflationIndex>(index);
1668 instruments.parYoYCapsVts_[key] = ovs;
1669}
yoyInflationLeg & withRateCurve(const Handle< YieldTermStructure > &rateCurve)
yoyInflationLeg & withNotionals(Real notional)
yoyInflationLeg & withPaymentDayCounter(const DayCounter &)
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
std::map< ore::analytics::RiskFactorKey, QuantLib::Handle< QuantExt::YoYOptionletVolatilitySurface > > parYoYCapsVts_
std::map< ore::analytics::RiskFactorKey, QuantLib::Handle< QuantLib::YieldTermStructure > > parYoYCapsYts_
par helpers: YoY cap / floors
std::map< ore::analytics::RiskFactorKey, QuantLib::Handle< QuantLib::YoYInflationIndex > > parYoYCapsIndex_
+ Here is the call graph for this function:
+ Here is the caller graph for this function: