32#include <ql/cashflows/fixedratecoupon.hpp>
33#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
38std::map<std::string, Handle<YieldTermStructure>>
40 std::map<std::string, Handle<YieldTermStructure>> curves;
41 for (
auto const& ccy : rpa->legCurrencies()) {
47std::map<std::string, Handle<Quote>>
49 std::map<std::string, Handle<Quote>> fxSpots;
50 for (
auto const& ccy : rpa->legCurrencies()) {
56QuantLib::ext::shared_ptr<QuantLib::PricingEngine>
59 if (maxDiscretisationPoints == 0)
60 maxDiscretisationPoints = Null<Size>();
63 QuantLib::ext::shared_ptr<IborIndex> index;
64 auto qlInstr = QuantLib::ext::dynamic_pointer_cast<QuantExt::RiskParticipationAgreement>(rpa->instrument()->qlInstrument());
65 QL_REQUIRE(qlInstr !=
nullptr,
"RiskParticipationAgreementBlackEngineBuilder: internal error, could not "
66 "cast to RiskParticipationAgreement");
67 for (
auto const& l : qlInstr->underlying()) {
68 for (
auto const& c : l) {
69 if (
auto floatingCpn = QuantLib::ext::dynamic_pointer_cast<QuantLib::FloatingRateCoupon>(c)) {
71 index = QuantLib::ext::dynamic_pointer_cast<IborIndex>(floatingCpn->index());
76 auto key = index ==
nullptr ? rpa->npvCurrency() : IndexNameTranslator::instance().oreName(index->name());
77 return QuantLib::ext::make_shared<AnalyticBlackRiskParticipationAgreementEngine>(
79 market_->defaultCurve(rpa->creditCurveId(), config)->curve(),
80 market_->recoveryRate(rpa->creditCurveId(), config),
market_->swaptionVol(key, config),
84 modelParameter(
"Reversion", {IndexNameTranslator::instance().oreName(index->name()), rpa->npvCurrency()})),
86 maxDiscretisationPoints);
89QuantLib::ext::shared_ptr<QuantLib::PricingEngine>
92 if (maxDiscretisationPoints == 0)
93 maxDiscretisationPoints = Null<Size>();
96 for (
auto const& c : rpa->legCurrencies()) {
99 if (c != rpa->npvCurrency()) {
100 ccyPair = c + rpa->npvCurrency();
104 QL_REQUIRE(!ccyPair.empty(),
105 "RiskParticipationAgreementXCcyBlackEngineBuilder: no foreign currency found, this is unexpected");
106 return QuantLib::ext::make_shared<AnalyticXCcyBlackRiskParticipationAgreementEngine>(
108 market_->defaultCurve(rpa->creditCurveId(), config)->curve(),
109 market_->recoveryRate(rpa->creditCurveId(), config),
market_->fxVol(ccyPair, config),
111 maxDiscretisationPoints);
114QuantLib::ext::shared_ptr<QuantExt::LGM>
116 const std::vector<Date>& expiries,
const Date&
maturity,
117 const std::vector<Real>& strikes) {
121 DLOG(
"Get model data");
124 std::string referenceCalibrationGrid =
modelParameter(
"ReferenceCalibrationGrid", {},
false,
"");
128 QL_REQUIRE(sigma.size() == sigmaTimes.size() + 1,
"there must be n+1 volatilities (" << sigma.size()
129 <<
") for n volatility times ("
130 << sigmaTimes.size() <<
")");
134 bool continueOnCalibrationError =
globalParameters_.count(
"ContinueOnCalibrationError") > 0 &&
137 auto data = QuantLib::ext::make_shared<IrLgmData>();
140 std::vector<std::pair<CalibrationType, CalibrationStrategy>> validCalPairs = {
147 QL_REQUIRE(std::find(validCalPairs.begin(), validCalPairs.end(),
148 std::make_pair(calibration, calibrationStrategy)) != validCalPairs.end(),
149 "Calibration (" << calibration <<
") and CalibrationStrategy (" << calibrationStrategy
150 <<
") are not allowed in this combination");
154 Date today = Settings::instance().evaluationDate();
155 shiftHorizon = ActualActual(ActualActual::ISDA).yearFraction(today,
maturity) * shiftHorizon;
159 data->qualifier() = key;
160 data->calibrateH() =
false;
162 data->hValues() = {lambda};
163 data->reversionType() = reversionType;
164 data->calibrateA() =
false;
166 data->aValues() = sigma;
167 data->aTimes() = sigmaTimes;
169 data->calibrationType() = calibration;
170 data->shiftHorizon() = shiftHorizon;
175 DLOG(
"Build LgmData for co-terminal specification");
176 vector<string> expiryDates, termDates;
177 for (Size i = 0; i < expiries.size(); ++i) {
178 expiryDates.push_back(
to_string(expiries[i]));
181 data->optionExpiries() = expiryDates;
182 data->optionTerms() = termDates;
183 data->optionStrikes().resize(expiryDates.size(),
"ATM");
185 for (Size i = 0; i < expiryDates.size(); ++i) {
186 if (
strikes[i] != Null<Real>())
187 data->optionStrikes()[i] = std::to_string(
strikes[i]);
191 DLOG(
"Calibrate piecewise alpha");
193 data->calibrateH() =
false;
195 data->hValues() = {lambda};
196 data->calibrateA() =
true;
198 data->aValues() = {sigma};
200 DLOG(
"Calibrate constant sigma");
202 data->calibrateH() =
false;
204 data->hValues() = {lambda};
205 data->calibrateA() =
true;
207 data->aValues() = {sigma};
209 QL_FAIL(
"choice of calibration type invalid");
212 bool generateAdditionalResults =
false;
215 generateAdditionalResults =
parseBool(p->second);
219 DLOG(
"Build LGM model");
220 QuantLib::ext::shared_ptr<LgmBuilder> calib = QuantLib::ext::make_shared<LgmBuilder>(
222 referenceCalibrationGrid, generateAdditionalResults,
id);
225 QuantLib::ext::shared_ptr<QuantExt::LGM>
model;
228 model = calib->model();
230 DLOG(
"Skip calibration of model based on global parameters");
232 model = calib->model();
240QuantLib::ext::shared_ptr<QuantLib::PricingEngine>
243 DLOG(
"Get engine data");
250 if (maxDiscretisationPoints == 0)
251 maxDiscretisationPoints = Null<Size>();
255 auto qlInstr = QuantLib::ext::dynamic_pointer_cast<QuantExt::RiskParticipationAgreement>(rpa->instrument()->qlInstrument());
256 QL_REQUIRE(qlInstr !=
nullptr,
"RiskParticipationAgreementSwapLGMGridEngineBuilder: internal error, could not "
257 "cast to RiskParticipationAgreement");
259 std::vector<Date> expiries;
262 Date today = Settings::instance().evaluationDate();
263 Date calibrationMaturity = std::max(qlInstr->underlyingMaturity(), today);
266 QuantLib::ext::shared_ptr<IborIndex> index;
273 maxDiscretisationPoints);
274 for (Size i = 0; i < gridDates.size() - 1; ++i) {
275 Date mid = gridDates[i] + (gridDates[i + 1] - gridDates[i]) / 2;
278 if (mid > today && ((calibrationMaturity - mid) >= 90 || expiries.empty()))
279 expiries.push_back(mid);
282 std::vector<QuantLib::ext::shared_ptr<QuantLib::FixedRateCoupon>> fixedCpns;
283 std::vector<QuantLib::ext::shared_ptr<QuantLib::FloatingRateCoupon>> floatingCpns;
284 for (
auto const& l : qlInstr->underlying()) {
285 for (
auto const& c : l) {
286 if (
auto fixedCpn = QuantLib::ext::dynamic_pointer_cast<QuantLib::FixedRateCoupon>(c))
287 fixedCpns.push_back(fixedCpn);
288 if (
auto floatingCpn = QuantLib::ext::dynamic_pointer_cast<QuantLib::FloatingRateCoupon>(c)) {
289 floatingCpns.push_back(floatingCpn);
290 if (index ==
nullptr)
291 index = QuantLib::ext::dynamic_pointer_cast<IborIndex>(floatingCpn->index());
295 auto cpnLt = [](
const QuantLib::ext::shared_ptr<Coupon>& x,
const QuantLib::ext::shared_ptr<Coupon>& y) {
296 return x->accrualStartDate() < y->accrualStartDate();
298 std::sort(fixedCpns.begin(), fixedCpns.end(), cpnLt);
299 std::sort(floatingCpns.begin(), floatingCpns.end(), cpnLt);
301 auto accLt = [](
const QuantLib::ext::shared_ptr<Coupon>& x,
const Date& e) {
return x->accrualStartDate() < e; };
302 for (
auto const& expiry : expiries) {
304 auto firstFix = std::lower_bound(fixedCpns.begin(), fixedCpns.end(), expiry, accLt);
305 auto firstFloat = std::lower_bound(floatingCpns.begin(), floatingCpns.end(), expiry, accLt);
308 if (firstFix != fixedCpns.end() && firstFloat != floatingCpns.end())
309 strikes.push_back((*firstFix)->rate() - (*firstFloat)->spread());
311 strikes.push_back(Null<Real>());
316 DLOG(
"Building LGM Grid RPA engine for trade " <<
id);
317 QuantLib::ext::shared_ptr<QuantExt::LGM> lgm =
318 model(
id, index ==
nullptr ? rpa->npvCurrency() : IndexNameTranslator::instance().oreName(index->name()),
319 expiries, calibrationMaturity,
strikes);
321 Handle<DefaultProbabilityTermStructure> creditCurve =
324 return QuantLib::ext::make_shared<NumericLgmRiskParticipationAgreementEngine>(
325 rpa->npvCurrency(),
getDiscountCurves(rpa),
getFxSpots(rpa), lgm, sy, ny, sx, nx, creditCurve, recoveryRate,
326 maxGapDays, maxDiscretisationPoints);
329QuantLib::ext::shared_ptr<QuantLib::PricingEngine>
333 DLOG(
"Get engine data");
343 QL_REQUIRE(spacing != 0 * Days,
"RiskParticipationAgreementTLockLGMGridEngineBuilder: CalibrationInstrumentSpacing "
344 "is 0D, this is not allowed.");
350 QuantLib::ext::dynamic_pointer_cast<QuantExt::RiskParticipationAgreementTLock>(rpa->instrument()->qlInstrument());
351 QL_REQUIRE(qlInstr !=
nullptr,
"RiskParticipationAgreementTLockLGMGridEngineBuilder: internal error, could not "
352 "cast to RiskParticipationAgreementTLock");
354 QL_REQUIRE(qlInstr->bond() !=
nullptr,
355 "RiskParticipationAgreementTLockLGMGridEngineBuilder: internal error, bond is null");
357 std::vector<Date> expiries;
360 Date today = Settings::instance().evaluationDate();
361 Date calibrationMaturity = std::max(qlInstr->bond()->maturityDate(), today);
365 if (rpa->
protectionEnd() > today && qlInstr->terminationDate() > today) {
366 Date calibrationDate = today + spacing;
367 while (calibrationDate < qlInstr->terminationDate()) {
368 if (expiries.empty() || (calibrationMaturity - calibrationDate) >= 90)
369 expiries.push_back(calibrationDate);
370 calibrationDate += spacing;
372 expiries.push_back(qlInstr->terminationDate());
373 strikes.resize(expiries.size(), Null<Real>());
378 DLOG(
"Building LGM Grid RPA engine (tlock) for trade " <<
id);
379 QuantLib::ext::shared_ptr<QuantExt::LGM> lgm =
model(
id, rpa->npvCurrency(), expiries, calibrationMaturity,
strikes);
381 Handle<DefaultProbabilityTermStructure> creditCurve =
384 Handle<YieldTermStructure> treasuryCurve =
391 Handle<YieldTermStructure>(QuantLib::ext::make_shared<ZeroSpreadedTermStructure>(treasuryCurve, spread));
395 return QuantLib::ext::make_shared<NumericLgmRiskParticipationAgreementEngineTLock>(
396 rpa->npvCurrency(),
getDiscountCurves(rpa),
getFxSpots(rpa), lgm, sy, ny, sx, nx, treasuryCurve, creditCurve,
397 recoveryRate, timeStepsPerYear);
const Date & protectionEnd() const
const Date & protectionStart() const
QuantLib::ext::shared_ptr< Market > market_
const string & model() const
Return the model name.
std::string modelParameter(const std::string &p, const std::vector< std::string > &qualifiers={}, const bool mandatory=true, const std::string &defaultValue="") const
std::string engineParameter(const std::string &p, const std::vector< std::string > &qualifiers={}, const bool mandatory=true, const std::string &defaultValue="") const
const string & configuration(const MarketContext &key)
Return a configuration (or the default one if key not found)
set< std::pair< string, QuantLib::ext::shared_ptr< QuantExt::ModelBuilder > > > modelBuilders_
std::map< std::string, std::string > globalParameters_
static std::vector< Date > buildDiscretisationGrid(const Date &referenceDate, const Date &protectionStart, const Date &protectionEnd, const std::vector< Leg > &underlying, const Size maxGapDays=Null< Size >(), const Size maxDiscretisationPoints=Null< Size >())
QuantLib::ext::shared_ptr< QuantLib::PricingEngine > engineImpl(const std::string &id, RiskParticipationAgreement *rpa) override
std::map< std::string, Handle< Quote > > getFxSpots(RiskParticipationAgreement *rpa)
std::map< std::string, Handle< YieldTermStructure > > getDiscountCurves(RiskParticipationAgreement *rpa)
QuantLib::ext::shared_ptr< QuantLib::PricingEngine > engineImpl(const std::string &id, RiskParticipationAgreement *rpa) override
QuantLib::ext::shared_ptr< QuantLib::PricingEngine > engineImpl(const std::string &id, RiskParticipationAgreement *rpa) override
QuantLib::ext::shared_ptr< QuantLib::PricingEngine > engineImpl(const std::string &id, RiskParticipationAgreement *rpa) override
Period parsePeriod(const string &s)
Convert text to QuantLib::Period.
bool parseBool(const string &s)
Convert text to bool.
Real parseReal(const string &s)
Convert text to Real.
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
translates between QuantLib::Index::name() and ORE names
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
CalibrationType parseCalibrationType(const string &s)
Convert calibration type string into enumerated class value.
CalibrationStrategy parseCalibrationStrategy(const string &s)
Convert calibration strategy string into enumerated class value.
VolatilityType volatilityType(CapFloorVolatilityCurveConfig::VolatilityType type)
Imply QuantLib::VolatilityType from CapFloorVolatilityCurveConfig::VolatilityType.
std::string to_string(const LocationInfo &l)
LgmData::ReversionType parseReversionType(const string &s)
Enum parsers.
LgmData::VolatilityType parseVolatilityType(const string &s)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
string conversion utilities