54#include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp>
55#include <ql/termstructures/yield/zerospreadedtermstructure.hpp>
57#include <boost/lexical_cast.hpp>
64QuantLib::Handle<QuantExt::CorrelationTermStructure>
66 if (index1 == index2) {
70 return Handle<QuantExt::CorrelationTermStructure>(
71 QuantLib::ext::make_shared<FlatCorrelation>(0, NullCalendar(), 1.0, ActualActual(ActualActual::ISDA)));
77QuantLib::ext::shared_ptr<ScriptedInstrument::engine>
79 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceData,
82 const std::vector<ScriptedTradeEventData>& events = scriptedTrade.
events();
83 const std::vector<ScriptedTradeValueTypeData>& numbers = scriptedTrade.
numbers();
84 const std::vector<ScriptedTradeValueTypeData>& indices = scriptedTrade.
indices();
85 const std::vector<ScriptedTradeValueTypeData>& currencies = scriptedTrade.
currencies();
86 const std::vector<ScriptedTradeValueTypeData>& daycounters = scriptedTrade.
daycounters();
88 LOG(
"Building engine for scripted trade " <<
id);
101 std::string productTag =
getScript(scriptedTrade, ScriptLibraryStorage::instance().get(),
"",
false).first;
111 std::string purpose =
"";
118 getScript(scriptedTrade, ScriptLibraryStorage::instance().get(), purpose,
true).second;
124 DLOG(
"retrieved ast from cache");
134 events, numbers, indices, currencies, daycounters);
138 DLOG(
"Built initial context:");
148 DLOG(
"Run static analyser on script");
183 Handle<YieldTermStructure> yts =
184 externalDiscountCurve.empty() || c !=
baseCcy_
187 if (!externalSecuritySpread.empty() && c ==
baseCcy_)
188 yts = Handle<YieldTermStructure>(QuantLib::ext::make_shared<ZeroSpreadedTermStructure>(
191 DLOG(
"curve for " << c <<
" added.");
196 for (Size i = 1; i <
modelCcys_.size(); ++i) {
231 "model/engine = GaussianCam/MC required to build an amc model, got " <<
modelParam_ <<
"/"
255 <<
"' not recognised, expected BlackScholes/[MC|FD], LocalVolDupire/MC, "
256 "LocalVolAndreasenHuge/MC, GaussianCam/MC");
259 QL_REQUIRE(
model_ !=
nullptr ||
modelCG_ !=
nullptr,
"internal error: both model_ and modelCG_ are null");
307 DLOG(
"condExpMdlStates = " << boost::algorithm::join(
script.conditionalExpectationModelStates(),
","));
308 }
else if (
modelParam_ ==
"LocalVolAndreasenHuge") {
314 bool generateAdditionalResults =
false;
317 generateAdditionalResults =
parseBool(p->second);
320 QuantLib::ext::shared_ptr<ScriptedInstrument::engine>
engine;
322 engine = QuantLib::ext::make_shared<ScriptedInstrumentPricingEngine>(
324 std::set<std::string>(
script.stickyCloseOutStates().begin(),
script.stickyCloseOutStates().end()),
328 std::string runType = rt !=
globalParameters_.end() ? rt->second :
"<<no run type set>>";
329 bool useCachedSensis =
useAd_ && (runType ==
"SensitivityDelta");
331 if (
useAd_ && !useCachedSensis) {
332 WLOG(
"Will not apply AD although useAD is configured, because runType ("
333 << runType <<
") does not match SensitivitiyDelta");
336 WLOG(
"Will not use exxternal compute deivce although useExternalComputeDevice is configured, because we "
337 "are either applying AD ("
338 << std::boolalpha << useCachedSensis <<
") or we are generating add results ("
339 << generateAdditionalResults <<
"), both of which do not support external devices at the moment.");
341 engine = QuantLib::ext::make_shared<ScriptedInstrumentPricingEngineCG>(
345 if (useExternalDev) {
352 <<
", generateAdditionalResults = " << generateAdditionalResults);
380 const QuantLib::ext::shared_ptr<ore::data::ReferenceDataManager>& referenceData) {
381 DLOG(
"Extract indices from script:");
386 }
else if (ind.
isIr()) {
388 }
else if (ind.
isInf()) {
390 }
else if (ind.
isFx()) {
392 if (ind.
fx()->sourceCurrency() != ind.
fx()->targetCurrency())
394 }
else if (ind.
isComm()) {
399 QL_FAIL(
"unexpected index type for '" << ind.
name() <<
"'");
405 QL_REQUIRE(ind.
isIr(),
"expected IR (ON) index for " << ind.
name());
412 std::set<std::string> names;
413 std::set<IndexInfo> commIndices, eqIndices, fxIndices, irIndices, infIndices;
415 for (
auto const& i : indices) {
417 names.insert(i.values().begin(), i.values().end());
419 names.insert(i.value());
423 for (
auto const& n : names) {
426 fxIndices.insert(ind);
428 eqIndices.insert(ind);
430 commIndices.insert(ind);
432 irIndices.insert(ind);
433 else if (ind.
isInf())
434 infIndices.insert(ind);
438 if (!commIndices.empty()) {
442 }
else if (!eqIndices.empty()) {
446 }
else if (!fxIndices.empty()) {
450 for (
auto const& i : fxIndices) {
451 std::string f = i.fx()->sourceCurrency().code();
452 std::string d = i.fx()->targetCurrency().code();
460 }
else if (!irIndices.empty() || !infIndices.empty()) {
468 if ((
int)!eqIndices.empty() + (
int)!fxIndices.empty() + (
int)!commIndices.empty() > 1) {
532 }
else if (
modelParam_ ==
"LocalVolAndreasenHuge") {
575 DLOG(
"model calibration is disalbed in global pricing engine parameters");
587 DLOG(
"Populate fixing map");
592 std::map<std::string, std::set<std::pair<Date, bool>>> indexFixings;
595 for (
auto const& d :
fixings) {
596 indexFixings[
name].insert(std::make_pair(d,
true));
601 for (
auto const& d :
fixings) {
602 indexFixings[
name].insert(std::make_pair(d,
false));
610 std::map<std::string, Size> stats;
611 for (
auto const& [d, _] :
fixings) {
612 auto idx = i.
comm(d);
613 std::string
name = idx->name();
614 fixings_[
name].insert(idx->fixingCalendar().adjust(d, Preceding));
617 for (
auto const& s : stats) {
618 DLOG(
"added " << s.second <<
" fixings for '" << s.first <<
"' (from eval op, prob fcts)");
627 Size nIbor = 0, nRfr = 0;
629 d = i.
index()->fixingCalendar().adjust(d, Preceding);
631 auto fd = i.
irIborFallback(iborFallbackConfig)->onCoupon(d)->fixingDates();
639 DLOG(
"added " << nIbor <<
" Ibor and " << nRfr <<
" Rfr fixings for ibor fallback '" << i.
name()
640 <<
"' (from eval op, prob fcts)");
642 Size nOis = 0, nRfr = 0;
644 d = i.
index()->fixingCalendar().adjust(d, Preceding);
653 DLOG(
"added " << nOis <<
" OIS and " << nRfr <<
" Rfr fallback fixings for OIS fallback '" << i.
name()
654 <<
"' (from eval op, prob fcts)");
658 for (
const auto& [d, prob] :
fixings) {
659 fixings_[i.
name()].insert((prob ? imkt : i).index()->fixingCalendar().adjust(d, Preceding));
661 DLOG(
"added " <<
fixings.size() <<
" fixings for '" << i.
name() <<
"' (from eval op, prob fcts)");
669 "FWD[COMP|AVG]() only supports IR ON indices, got '" << f.first <<
"' during fixing map population");
670 fixings_[f.first].insert(f.second.begin(), f.second.end());
671 DLOG(
"added " << f.second.size() <<
" fixings for '" << f.first <<
"' (from FWD[COMP|AVG]())");
676 DLOG(
"Extract pay ccys and determine the model's base ccy");
679 DLOG(
"got pay currency " << c.first);
684 std::set<std::string> baseCcyCandidates;
688 std::string ccy = i.fx()->targetCurrency().code();
689 baseCcyCandidates.insert(ccy);
690 DLOG(
"add base ccy candidate " << ccy <<
" from " << i);
694 if (baseCcyCandidates.empty()) {
696 baseCcyCandidates.insert(p);
697 DLOG(
"add base ccy candidate " << p <<
" from pay ccys");
705 baseCcy_ = *baseCcyCandidates.begin();
711 << (
amcCam_ !=
nullptr ?
"(this choice might be overwritten below for AMC builders)" :
""));
715 QL_REQUIRE(e.
isEq(),
"ScriptedTradeEngineBuilder::getEqCcy(): expected eq index, got " << e.
name());
718 QL_REQUIRE(!tmp.empty(),
"ScriptedTradeEngineBuilder: Cannot find currency for equity '"
719 << e.
eq()->name() <<
"'. Check if equity is present in curveconfig.");
724 QL_REQUIRE(e.
isComm(),
"ScriptedTradeEngineBuilder::getCommCcy(): expected comm index, got " << e.
name());
727 QL_REQUIRE(!tmp.empty(),
"ScriptedTradeEngineBuilder: Cannot find currency for commodity '"
728 << e.
commName() <<
"'. Check if Commodity is present in curveconfig.");
733 std::set<std::string> tmpCcys;
736 DLOG(
"Compile the model currencies list");
743 std::string f = i.fx()->sourceCurrency().code();
744 std::string d = i.fx()->targetCurrency().code();
753 tmpCcys.insert(i.ir()->currency().code());
756 tmpCcys.insert(i.inf()->currency().code());
781 std::string newBaseCcy_ =
amcCam_->ir(0)->currency().code();
783 DLOG(
"base ccy and AMC model base ccy are identical (" <<
baseCcy_ <<
")");
785 if (tmpCcys.size() > 1) {
786 DLOG(
"base ccy " <<
baseCcy_ <<
" is overwritten with AMC model base ccy " << newBaseCcy_
787 <<
", since more than one ccy is needed in the final model.");
790 DLOG(
"base ccy " <<
baseCcy_ <<
" is kept although AMC model base ccy is different (" << newBaseCcy_
791 <<
"), because it is a single currency model");
798 for (
auto const& c : tmpCcys)
804 DLOG(
"model ccy " << c <<
" added");
821 std::set<std::string> coveredCcys;
824 std::string targetCcy = i.fx()->targetCurrency().code();
825 std::string sourceCcy = i.fx()->sourceCurrency().code();
827 std::find(coveredCcys.begin(), coveredCcys.end(), sourceCcy) == coveredCcys.end()) {
830 coveredCcys.insert(sourceCcy);
834 std::find(coveredCcys.begin(), coveredCcys.end(), targetCcy) == coveredCcys.end()) {
837 coveredCcys.insert(targetCcy);
844 for (Size i = 1; i <
modelCcys_.size(); ++i) {
845 if (std::find(coveredCcys.begin(), coveredCcys.end(),
modelCcys_[i]) == coveredCcys.end()) {
849 DLOG(
"added model index " <<
modelIndices_.back() <<
" (since fullDynamicFx = true)");
861 DLOG(
"added model ir index " << i.name());
867 DLOG(
"added model inf index " << i.name());
874 DLOG(
"skipping correlation setup because we are using zero volatility");
879 std::set<std::pair<std::string, std::string>> tmp;
888 tmp.insert(std::make_pair(m,
"COMM-" + ind.
commName()));
891 tmp.insert(std::make_pair(m, m));
899 tmp.insert(std::make_pair(irIdx.first, irIdx.first));
904 tmp.insert(std::make_pair(infIdx.first, ind.
infName()));
908 DLOG(
"adding correlations for indices:");
909 for (
auto const& n : tmp)
910 DLOG(
"model index '" << n.first <<
"' lookup name '" << n.second <<
"'");
912 std::vector<std::pair<std::string, std::string>> corrModelIndices(tmp.begin(), tmp.end());
914 for (Size i = 0; i < corrModelIndices.size(); ++i) {
915 for (Size j = 0; j < i; ++j) {
917 correlations_[std::make_pair(corrModelIndices[i].first, corrModelIndices[j].first)] =
919 DLOG(
"added correlation for " << corrModelIndices[j].second <<
" ~ " << corrModelIndices[i].second);
920 }
catch (
const std::exception& e) {
921 WLOG(
"no correlation provided for " << corrModelIndices[j].second <<
" ~ " << corrModelIndices[i].second
922 <<
"(" << e.what() <<
")");
931 for (
auto const& d : s.second)
936 for (
auto const& d : s.second)
939 for (
auto const& d : s.second)
942 for (
auto const& d : s.second)
945 for (
auto const& d : s.second)
951 Handle<BlackVolTermStructure> vol;
953 vol = Handle<BlackVolTermStructure>(
954 QuantLib::ext::make_shared<BlackConstantVol>(0, NullCalendar(), 0.0, ActualActual(ActualActual::ISDA)));
955 DLOG(
"using zero volatility processes");
960 std::string
name = ind.
eq()->name();
966 processes_.push_back(QuantLib::ext::make_shared<GeneralizedBlackScholesProcess>(spot, div, fc, vol));
967 DLOG(
"added process for equity " <<
name);
968 }
else if (ind.
isComm()) {
970 auto spot = Handle<Quote>(QuantLib::ext::make_shared<DerivedPriceQuote>(
974 auto div = Handle<YieldTermStructure>(QuantLib::ext::make_shared<PriceTermStructureAdapter>(*priceCurve, *fc));
975 div->enableExtrapolation();
978 processes_.push_back(QuantLib::ext::make_shared<GeneralizedBlackScholesProcess>(spot, div, fc, vol));
979 DLOG(
"added process for commodity " <<
name);
980 }
else if (ind.
isFx()) {
981 std::string targetCcy = ind.
fx()->targetCurrency().code();
982 std::string sourceCcy = ind.
fx()->sourceCurrency().code();
988 processes_.push_back(QuantLib::ext::make_shared<GeneralizedBlackScholesProcess>(spot, div, fc, vol));
989 DLOG(
"added process for fx " << sourceCcy <<
"-" << targetCcy);
991 QL_FAIL(
"unexpected model index " << ind);
998 DLOG(
"skipping IR reversion setup because we are using zero volatility");
1002 std::set<std::string> irCcys;
1004 irCcys.insert(i.ir()->currency().code());
1009 for (
auto const& ccy : irCcys) {
1013 QL_REQUIRE(!revStr.empty(),
"Did not find reversion for "
1015 <<
", need IrReversion_CCY or IrReversion parameter in pricing engine config.");
1022QuantLib::ext::shared_ptr<ZeroInflationIndex>
1023getInfMarketIndex(
const std::string&
name,
1024 const std::vector<std::pair<std::string, QuantLib::ext::shared_ptr<ZeroInflationIndex>>>& indices) {
1025 for (
auto const& i : indices) {
1026 if (i.first ==
name)
1029 QL_FAIL(
"ScriptedTradeEngineBuilder::compileSimulationAndAddDates(): did not find zero inflation index '"
1030 <<
name <<
"' in model indices, this is unexpected");
1035 DLOG(
"compile simulation and additional dates...");
1047 QuantLib::ext::shared_ptr<ZeroInflationIndex> marketIndex = getInfMarketIndex(info.
name(),
modelInfIndices_);
1049 for (
auto const& d : s.second) {
1050 auto lim = inflationPeriod(d, info.
inf()->frequency());
1052 QL_DEPRECATED_DISABLE_WARNING
1054 if (info.
inf()->interpolated())
1056 QL_DEPRECATED_ENABLE_WARNING
1062 DLOG(
"added " << s.second.size() <<
" simulation dates for '" << s.first <<
"' (from eval op obs dates)");
1070 addDates_.insert(s.second.begin(), s.second.end());
1071 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first <<
"' (from eval op fwd dates)");
1079 std::string payCcy = s.first;
1084 return ind.isFx() && ind.fx()->sourceCurrency().code() == payCcy;
1087 DLOG(
"added " << s.second.size() <<
" simulation dates for '" << payCcy <<
"' (from pay() obs dates)");
1089 addDates_.insert(s.second.begin(), s.second.end());
1090 DLOG(
"added " << s.second.size() <<
" additional dates for '" << payCcy <<
"' (from pay() obs dates)");
1095 DLOG(
"added " <<
staticAnalyser_->regressionDates().size() <<
" simulation dates (from npv() regression dates)");
1098 addDates_.insert(s.second.begin(), s.second.end());
1099 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first <<
"' (from pay() pay dates)");
1107 DLOG(
"added " << s.second.size() <<
" simulation dates for '" << s.first
1108 <<
"' (from discount() obs dates)");
1110 addDates_.insert(s.second.begin(), s.second.end());
1111 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first
1112 <<
"' (from discount() obs dates)");
1114 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first <<
"' (from discount() obs dates)");
1118 addDates_.insert(s.second.begin(), s.second.end());
1119 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first <<
"' (from discount() pay dates)");
1127 DLOG(
"added " << s.second.size() <<
" simulation dates for '" << s.first
1128 <<
"' (from fwd[Comp|Avg]() obs dates)");
1130 addDates_.insert(s.second.begin(), s.second.end());
1131 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first
1132 <<
"' (from fwd[Comp|Avg]() obs dates)");
1137 addDates_.insert(s.second.begin(), s.second.end());
1138 DLOG(
"added " << s.second.size() <<
" additional dates for '" << s.first
1139 <<
"' (from fwd[Comp|Avg]() start/end dates)");
1146std::map<std::string, std::vector<Real>> filterBlackScholesCalibrationStrikes(
1147 const std::map<std::string, std::vector<Real>>& strikes,
const std::vector<std::string>& modelIndices,
1148 const std::vector<QuantLib::ext::shared_ptr<GeneralizedBlackScholesProcess>>& processes,
const Real T) {
1149 QL_REQUIRE(modelIndices.size() == processes.size(),
"filterBlackScholesCalibrationStrikes: processes size ("
1150 << processes.size() <<
") must match modelIndices size ("
1151 << modelIndices.size() <<
")");
1152 std::map<std::string, std::vector<Real>> result;
1154 DLOG(
"excluding all calibration strikes, because last relevant time is not positive (" << T <<
")");
1157 const Real normInvEps = 2.0 * InverseCumulativeNormal()(1 - 1E-6);
1158 for (
auto const& ks : strikes) {
1159 auto m = std::find(modelIndices.begin(), modelIndices.end(), ks.first);
1160 if (m != modelIndices.end()) {
1161 Size index = std::distance(modelIndices.begin(), m);
1162 Real atmf = processes[index]->x0() / processes[index]->riskFreeRate()->discount(T) *
1163 processes[index]->dividendYield()->discount(T);
1165 std::max(processes[index]->blackVolatility()->blackVol(T, atmf), 0.1) * std::sqrt(std::max(T, 1.0));
1166 Real xmin = std::exp(std::log(atmf) - normInvEps * sigmaSqrtT);
1167 Real xmax = std::exp(std::log(atmf) + normInvEps * sigmaSqrtT);
1168 for (
auto const k : ks.second) {
1169 if (k < xmin || k > xmax) {
1170 DLOG(
"excluding calibration strike (" << k <<
") for index '" << modelIndices[index]
1171 <<
"', bounds = [" << xmin <<
"," << xmax <<
"]");
1173 result[ks.first].push_back(k);
1177 result[ks.first] = ks.second;
1184std::vector<std::vector<Real>> getCalibrationStrikesVector(
const std::map<std::string, std::vector<Real>>& strikes,
1185 const std::vector<std::string>& modelIndices) {
1186 std::vector<std::vector<Real>> result;
1187 for (
auto const& m : modelIndices) {
1190 result.push_back(s->second);
1192 result.push_back({});
1204 auto builder = QuantLib::ext::make_shared<BlackScholesModelBuilder>(
1208 modelCG_ = QuantLib::ext::make_shared<BlackScholesCG>(
1225 auto builder = QuantLib::ext::make_shared<BlackScholesModelBuilder>(
1227 getCalibrationStrikesVector(filteredStrikes,
modelIndices_));
1228 model_ = QuantLib::ext::make_shared<FdBlackScholesBase>(
1243 QL_FAIL(
"local vol model type " <<
modelParam_ <<
" not recognised.");
1256std::string getFirstIrIndexOrCcy(
const std::string& ccy,
const std::set<IndexInfo> irIndices) {
1257 for (
auto const& index : irIndices) {
1258 if (index.isIrSwap() && index.irSwap()->iborIndex()->currency().code() == ccy)
1259 return IndexNameTranslator::instance().oreName(index.irSwap()->iborIndex()->name());
1260 if (index.isIrIbor() && index.irIbor()->currency().code() == ccy)
1261 return index.name();
1268 const std::vector<std::string>& conditionalExpectationModelStates) {
1284 std::map<std::pair<std::string, std::string>,
1285 std::tuple<Handle<QuantExt::CorrelationTermStructure>, Period, Period>>
1292 if (firstEntry.first == secondEntry.first)
1294 auto e = tmpCorrelations.find(std::make_pair(firstEntry.first, secondEntry.first));
1295 if (e == tmpCorrelations.end() ||
1296 (firstEntry.second > std::get<1>(e->second) && secondEntry.second > std::get<2>(e->second))) {
1297 tmpCorrelations[std::make_pair(firstEntry.first, secondEntry.first)] =
1298 std::make_tuple(c.second, firstEntry.second, secondEntry.second);
1302 map<CorrelationKey, Handle<Quote>> camCorrelations;
1303 for (
auto const& c : tmpCorrelations) {
1309 if (f_1.
type == CrossAssetModel::AssetType::INF)
1311 if (f_2.
type == CrossAssetModel::AssetType::INF)
1314 auto q = Handle<Quote>(QuantLib::ext::make_shared<CorrelationValue>(std::get<0>(c.second), 0.0));
1315 camCorrelations[std::make_pair(f_1, f_2)] = q;
1316 DLOG(
"added correlation for " << c.first.first <<
"/" << c.first.second <<
": " << q->value());
1321 std::set<CorrelationFactor> allCorrRiskFactors;
1330 allCorrRiskFactors.insert({CrossAssetModel::AssetType::IR, ccy, 0});
1332 for (
auto const& c1 : allCorrRiskFactors) {
1333 for (
auto const& c2 : allCorrRiskFactors) {
1335 Size nf_1 = c1.type == CrossAssetModel::AssetType::INF &&
infModelType_ ==
"JY" ? 2 : 1;
1336 Size nf_2 = c2.type == CrossAssetModel::AssetType::INF &&
infModelType_ ==
"JY" ? 2 : 1;
1337 for (Size k = 0; k < nf_1; ++k) {
1338 for (Size l = 0; l < nf_2; ++l) {
1348 std::set<std::string> lookupnames1, lookupnames2;
1349 lookupnames1.insert(s_1);
1350 lookupnames2.insert(s_2);
1352 lookupnames1.insert(s_1.substr(0, s_1.size() - 2));
1354 lookupnames2.insert(s_2.substr(0, s_2.size() - 2));
1355 for (
auto const& l1 : lookupnames1) {
1356 for (
auto const& l2 : lookupnames2) {
1361 !overwrite.empty()) {
1362 camCorrelations[std::make_pair(f_1, f_2)] =
1363 Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(
parseReal(overwrite)));
1376 std::vector<QuantLib::ext::shared_ptr<IrModelData>> irConfigs;
1377 std::vector<QuantLib::ext::shared_ptr<InflationModelData>> infConfigs;
1378 std::vector<QuantLib::ext::shared_ptr<FxBsData>> fxConfigs;
1379 std::vector<QuantLib::ext::shared_ptr<EqBsData>> eqConfigs;
1380 std::vector<QuantLib::ext::shared_ptr<CommoditySchwartzData>> comConfigs;
1385 std::vector<Date> calibrationDates;
1386 std::vector<std::string> calibrationExpiries, calibrationTerms;
1390 calibrationDates.push_back(d);
1398 std::vector<Real> calibrationTimes;
1399 for (Size i = 0; i + 1 < calibrationDates.size(); ++i) {
1400 calibrationTimes.push_back(
modelCurves_.front()->timeFromReference(calibrationDates[i]));
1404 for (Size i = 0; i <
modelCcys_.size(); ++i) {
1405 auto config = QuantLib::ext::make_shared<IrLgmData>();
1409 config->calibrateH() =
false;
1411 config->hTimes() = std::vector<Real>();
1412 config->shiftHorizon() =
1414 config->scaling() = 1.0;
1421 [&ccy](
const std::pair<std::string, QuantLib::ext::shared_ptr<InterestRateIndex>>& index) {
1422 return index.second->currency().code() == ccy;
1425 DLOG(
"set up zero vol IrLgmData for currency '" <<
modelCcys_[i] <<
"'");
1428 config->hValues() = {0.0};
1429 config->calibrateA() =
false;
1431 config->aTimes() = std::vector<Real>();
1432 config->aValues() = {0.0};
1439 config->hValues() = {rev->second};
1440 config->calibrateA() =
true;
1442 config->aTimes() = calibrationTimes;
1443 config->aValues() = std::vector<Real>(calibrationTimes.size() + 1, 0.0030);
1444 config->optionExpiries() = calibrationExpiries;
1445 config->optionTerms() = calibrationTerms;
1446 config->optionStrikes() =
1447 std::vector<std::string>(calibrationExpiries.size(),
"ATM");
1449 irConfigs.push_back(config);
1454 QuantLib::ext::shared_ptr<InflationModelData> config;
1457 config = QuantLib::ext::make_shared<InfDkData>(
1465 QuantLib::ext::shared_ptr<BaseStrike> calibrationStrike;
1468 calibrationStrike = QuantLib::ext::make_shared<AbsoluteStrike>(k->second.front());
1470 calibrationStrike = QuantLib::ext::make_shared<AtmStrike>(QuantLib::DeltaVolQuote::AtmType::AtmFwd);
1472 std::vector<QuantLib::ext::shared_ptr<CalibrationInstrument>> calInstr;
1473 for (
auto const& d : calibrationDates)
1475 QuantLib::ext::make_shared<CpiCapFloor>(QuantLib::CapFloor::Type::Floor, d, calibrationStrike));
1483 config = QuantLib::ext::make_shared<InfDkData>(
1500 ReversionParameter realRateRev = QuantLib::ext::static_pointer_cast<LgmData>(irConfigs[ccyIndex])->reversionParameter();
1501 VolatilityParameter realRateVol = QuantLib::ext::static_pointer_cast<LgmData>(irConfigs[ccyIndex])->volatilityParameter();
1504 Real realRateToNominalRateRatio =
parseReal(
1508 "ScriptedTrade::buildGaussianCam(): internal error, inflation index currency "
1509 <<
modelInfIndices_[i].second->currency().code() <<
" not found in model ccy list.");
1510 realRateVol.
mult(realRateToNominalRateRatio);
1511 config = QuantLib::ext::make_shared<InfJyData>(
1514 realRateRev, realRateVol,
1524 realRateToNominalRateRatio);
1526 QL_FAIL(
"invalid infModelType '" <<
infModelType_ <<
"', expected DK or JY");
1529 infConfigs.push_back(config);
1533 for (Size i = 1; i <
modelCcys_.size(); ++i) {
1534 auto config = QuantLib::ext::make_shared<FxBsData>();
1539 bool haveFxIndex =
false;
1545 DLOG(
"set up zero vol FxBsData for currency '" <<
modelCcys_[i] <<
"'");
1548 config->calibrateSigma() =
false;
1550 config->sigmaTimes() = std::vector<Real>();
1551 config->sigmaValues() = {0.0};
1556 config->calibrateSigma() =
true;
1558 config->sigmaTimes() = calibrationTimes;
1559 config->sigmaValues() = std::vector<Real>(calibrationTimes.size() + 1, 0.10);
1560 config->optionExpiries() = calibrationExpiries;
1561 config->optionStrikes() =
1562 std::vector<std::string>(calibrationExpiries.size(),
"ATMF");
1564 fxConfigs.push_back(config);
1569 auto config = QuantLib::ext::make_shared<EqBsData>();
1571 config->eqName() = eq.eq()->name();
1573 DLOG(
"set up zero vol EqBsData for underlying " << eq.eq()->name());
1576 config->calibrateSigma() =
false;
1578 config->sigmaTimes() = std::vector<Real>();
1579 config->sigmaValues() = {0.0};
1581 DLOG(
"set up EqBsData for underlying '" << eq.eq()->name() <<
"'");
1584 config->calibrateSigma() =
true;
1586 config->sigmaTimes() = calibrationTimes;
1587 config->sigmaValues() = std::vector<Real>(calibrationTimes.size() + 1, 0.10);
1588 config->optionExpiries() = calibrationExpiries;
1589 config->optionStrikes() =
1590 std::vector<std::string>(calibrationExpiries.size(),
"ATMF");
1592 eqConfigs.push_back(config);
1596 std::vector<QuantLib::ext::shared_ptr<CrLgmData>> crLgmConfigs;
1597 std::vector<QuantLib::ext::shared_ptr<CrCirData>> crCirConfigs;
1601 auto config = QuantLib::ext::make_shared<CommoditySchwartzData>();
1603 config->name() = comm.commName();
1606 config->calibrateSigma() =
false;
1608 config->sigmaValue() = 0.0;
1611 config->calibrateSigma() =
true;
1613 config->sigmaValue() = 0.10;
1614 config->optionExpiries() = calibrationExpiries;
1615 config->optionStrikes() =
1616 std::vector<std::string>(calibrationExpiries.size(),
"ATMF");
1618 comConfigs.push_back(config);
1623 auto discretization =
useCg_ ? CrossAssetModel::Discretization::Euler : CrossAssetModel::Discretization::Exact;
1624 auto camBuilder = QuantLib::ext::make_shared<CrossAssetModelBuilder>(
1626 QuantLib::ext::make_shared<CrossAssetModelData>(irConfigs, fxConfigs, eqConfigs, infConfigs, crLgmConfigs, crCirConfigs,
1629 configurationInCcy, configurationXois, configurationXois, configurationInCcy, configurationInCcy,
1631 SalvagingAlgorithm::Spectral,
id);
1635 modelCG_ = QuantLib::ext::make_shared<GaussianCamCG>(
1638 camBuilder->model()->discretization() == CrossAssetModel::Discretization::Exact ? 0 :
timeStepsPerYear_,
1639 iborFallbackConfig, std::vector<Size>(), conditionalExpectationModelStates);
1641 model_ = QuantLib::ext::make_shared<GaussianCam>(
1644 camBuilder->model()->discretization() == CrossAssetModel::Discretization::Exact ? 0 :
timeStepsPerYear_,
1645 iborFallbackConfig, std::vector<Size>(), conditionalExpectationModelStates);
1655 std::vector<Date> calibrationDates;
1656 std::vector<std::string> calibrationExpiries, calibrationTerms;
1660 calibrationDates.push_back(d);
1668 std::vector<Real> calibrationTimes;
1669 for (Size i = 0; i + 1 < calibrationDates.size(); ++i) {
1670 calibrationTimes.push_back(
modelCurves_.front()->timeFromReference(calibrationDates[i]));
1674 std::string calibrationStrike =
"ATM";
1679 if(!f->second.empty()) {
1680 calibrationStrike = boost::lexical_cast<std::string>(f->second.front());
1688 "ScriptedTradeEngineBuilder::buildFdGaussianCam(): only one ccy is supported, got "
1691 auto config = QuantLib::ext::make_shared<IrLgmData>();
1695 config->calibrateH() =
false;
1697 config->hTimes() = std::vector<Real>();
1698 config->shiftHorizon() =
1700 config->scaling() = 1.0;
1703 DLOG(
"set up zero vol IrLgmData for currency '" <<
modelCcys_.front() <<
"'");
1706 config->hValues() = {0.0};
1707 config->calibrateA() =
false;
1709 config->aTimes() = std::vector<Real>();
1710 config->aValues() = {0.0};
1712 DLOG(
"set up IrLgmData for currency '" <<
modelCcys_.front() <<
"'");
1716 config->hValues() = {rev->second};
1717 config->calibrateA() =
true;
1719 config->aTimes() = calibrationTimes;
1720 config->aValues() = std::vector<Real>(calibrationTimes.size() + 1, 0.0030);
1721 config->optionExpiries() = calibrationExpiries;
1722 config->optionTerms() = calibrationTerms;
1723 config->optionStrikes() = std::vector<std::string>(calibrationExpiries.size(), calibrationStrike);
1729 auto camBuilder = QuantLib::ext::make_shared<CrossAssetModelBuilder>(
1731 QuantLib::ext::make_shared<CrossAssetModelData>(
1732 std::vector<QuantLib::ext::shared_ptr<IrModelData>>{config}, std::vector<QuantLib::ext::shared_ptr<FxBsData>>{},
1733 std::vector<QuantLib::ext::shared_ptr<EqBsData>>{}, std::vector<QuantLib::ext::shared_ptr<InflationModelData>>{},
1734 std::vector<QuantLib::ext::shared_ptr<CrLgmData>>{}, std::vector<QuantLib::ext::shared_ptr<CrCirData>>{},
1735 std::vector<QuantLib::ext::shared_ptr<CommoditySchwartzData>>{}, 0,
1736 std::map<CorrelationKey, QuantLib::Handle<QuantLib::Quote>>{},
bootstrapTolerance_,
"LGM",
1737 CrossAssetModel::Discretization::Exact),
1738 configurationInCcy, configurationXois, configurationXois, configurationInCcy, configurationInCcy,
1740 SalvagingAlgorithm::Spectral,
id);
1750 const std::vector<std::string>& conditionalExpectationModelStates) {
1752 QL_REQUIRE(
useCg_,
"building gaussian cam from external amc cg model, useCg must be set to true in this case.");
1758 const std::vector<std::string>& conditionalExpectationModelStates) {
1760 QL_REQUIRE(!
useCg_,
"building gaussian cam from external amc cam, useCg must be set to false in this case.");
1762 std::vector<std::pair<CrossAssetModel::AssetType, Size>> selectedComponents;
1765 for (Size i = 0; i <
modelCcys_.size(); ++i) {
1766 selectedComponents.push_back(
1772 selectedComponents.push_back(std::make_pair(CrossAssetModel::AssetType::INF,
1777 for (Size i = 1; i <
modelCcys_.size(); ++i) {
1778 selectedComponents.push_back(
1784 selectedComponents.push_back(std::make_pair(CrossAssetModel::AssetType::EQ,
amcCam_->eqIndex(eq.eq()->name())));
1788 QL_REQUIRE(
commIndices_.empty(),
"GaussianCam model does not support commodity underlyings currently");
1790 std::vector<Size> projectedStateProcessIndices;
1791 Handle<CrossAssetModel> projectedModel(
1796 modelCG_ = QuantLib::ext::make_shared<GaussianCamCG>(
1799 projectedModel->discretization() == CrossAssetModel::Discretization::Exact ? 0 :
timeStepsPerYear_,
1800 iborFallbackConfig, projectedStateProcessIndices, conditionalExpectationModelStates);
1802 model_ = QuantLib::ext::make_shared<GaussianCam>(
1805 projectedModel->discretization() == CrossAssetModel::Discretization::Exact ? 0 :
timeStepsPerYear_,
1806 iborFallbackConfig, projectedStateProcessIndices, conditionalExpectationModelStates);
1809 DLOG(
"built GuassianCam model as projection of xva evolution model");
1810 for (
auto const& p : projectedStateProcessIndices)
1811 DLOG(
" got projected state process index: " << p);
1817 DLOG(
"adding amc date grid (" <<
amcGrid_.size() <<
") to context as _AMC_SimDates");
1818 std::vector<ValueType> tmp;
1821 context->arrays[
"_AMC_SimDates"] = tmp;
1825 const QuantLib::ext::shared_ptr<Context>& context) {
black scholes model for n underlyings (fx, equity or commodity)
black scholes model for n underlyings (fx, equity or commodity)
builder for an array of black scholes processes
QuantLib::ext::shared_ptr< Market > market_
const string & engine() const
Return the engine 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_
string additionalField(const std::string &name, const bool mandatory=true, const std::string &defaultValue=std::string()) const
const FallbackData & fallbackData(const string &iborIndex) const
QuantLib::ext::shared_ptr< Index > index(const Date &obsDate=Date()) const
std::string infName() const
QuantLib::ext::shared_ptr< ZeroInflationIndex > inf() const
QuantLib::ext::shared_ptr< EquityIndex2 > eq() const
QuantLib::ext::shared_ptr< FallbackIborIndex > irIborFallback(const IborFallbackConfig &iborFallbackConfig, const Date &asof=QuantLib::Date::maxDate()) const
QuantLib::ext::shared_ptr< QuantExt::CommodityIndex > comm(const Date &obsDate=Date()) const
QuantLib::ext::shared_ptr< FxIndex > fx() const
QuantLib::ext::shared_ptr< FallbackOvernightIndex > irOvernightFallback(const IborFallbackConfig &iborFallbackConfig, const Date &asof=QuantLib::Date::maxDate()) const
std::string commName() const
@ Hagan
Parametrize LGM H(t) as H(t) = int_0^t h(s) ds with constant or piecewise h(s)
@ Hagan
Parametrize volatility as Hagan alpha(t)
void setCalibrate(const bool b)
std::set< Date > simulationDates_
std::map< std::string, Real > irReversions_
QuantLib::ext::shared_ptr< StaticAnalyser > staticAnalyser_
std::string referenceCalibrationGrid_
void buildLocalVol(const std::string &id, const IborFallbackConfig &iborFallbackConfig)
std::string infModelType_
std::vector< std::string > modelIndices_
void buildFdGaussianCam(const std::string &id, const IborFallbackConfig &iborFallbackConfig)
void compileSimulationAndAddDates()
void buildAMCCGModel(const std::string &id, const IborFallbackConfig &iborFallbackConfig, const std::vector< std::string > &conditionalExpectationModelStates)
Model::McParams mcParams_
void compileModelCcyList()
virtual void setupBlackScholesProcesses()
void buildFdBlackScholes(const std::string &id, const IborFallbackConfig &iborFallbackConfig)
QuantLib::Date lastRelevantDate_
Size mesherMaxConcentratingPoints_
std::set< std::string > payCcys_
void extractIndices(const QuantLib::ext::shared_ptr< ore::data::ReferenceDataManager > &referenceData=nullptr)
std::string gridCoarsening_
std::vector< std::string > modelIndicesCurrencies_
std::string externalComputeDevice_
const std::map< std::string, std::set< Date > > & fixings() const
bool useExternalComputeDevice_
std::vector< Real > calibrationMoneyness_
std::set< IndexInfo > irIndices_
std::map< std::pair< std::string, std::string >, Handle< QuantExt::CorrelationTermStructure > > correlations_
std::set< IndexInfo > eqIndices_
std::vector< Handle< Quote > > modelFxSpots_
std::map< std::string, std::set< Date > > fixings_
std::string scheduleProductClass_
const QuantLib::ext::shared_ptr< QuantExt::CrossAssetModel > amcCam_
bool continueOnCalibrationError_
bool useDoublePrecisionForExternalCalculation_
Real mesherConcentration_
const QuantLib::ext::shared_ptr< ore::data::ModelCG > amcCgModel_
bool includePastCashflows_
void populateModelParameters()
QuantLib::ext::shared_ptr< Model > model_
void buildGaussianCam(const std::string &id, const IborFallbackConfig &iborFallbackConfig, const std::vector< std::string > &conditionalExpectationModelStates)
std::vector< std::string > modelCcys_
std::set< Date > addDates_
void setLastRelevantDate()
void buildGaussianCamAMC(const std::string &id, const IborFallbackConfig &iborFallbackConfig, const std::vector< std::string > &conditionalExpectationModelStates)
const std::vector< Date > amcGrid_
void setupCalibrationStrikes(const ScriptedTradeScriptData &script, const QuantLib::ext::shared_ptr< Context > &context)
QuantLib::ext::shared_ptr< ModelCG > modelCG_
bool externalDeviceCompatibilityMode_
void addAmcGridToContext(QuantLib::ext::shared_ptr< Context > &context) const
std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< ZeroInflationIndex > > > modelInfIndices_
std::set< IndexInfo > fxIndices_
std::set< IndexInfo > commIndices_
std::set< IndexInfo > infIndices_
void buildBlackScholes(const std::string &id, const IborFallbackConfig &iborFallbackConfig)
std::string sensitivityTemplate_
std::string assetClassReplacement_
std::string getCommCcy(const IndexInfo &e)
std::string resolvedProductTag_
std::map< std::string, std::vector< Real > > calibrationStrikes_
std::string simmProductClass_
std::vector< Handle< YieldTermStructure > > modelCurves_
std::string baseCcyParam_
void compileModelIndexLists()
void populateFixingsMap(const IborFallbackConfig &iborFallbackConfig)
std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< InterestRateIndex > > > modelIrIndices_
void deriveProductClass(const std::vector< ScriptedTradeValueTypeData > &indices)
std::map< std::string, ASTNodePtr > astCache_
virtual QuantLib::Handle< QuantExt::CorrelationTermStructure > correlationCurve(const std::string &index1, const std::string &index2)
std::string getEqCcy(const IndexInfo &e)
std::vector< QuantLib::ext::shared_ptr< GeneralizedBlackScholesProcess > > processes_
const std::vector< ScriptedTradeValueTypeData > & indices() const
const std::vector< ScriptedTradeValueTypeData > & daycounters() const
const std::vector< ScriptedTradeValueTypeData > & numbers() const
const std::vector< ScriptedTradeValueTypeData > & currencies() const
const std::vector< ScriptedTradeEventData > & events() const
const Envelope & envelope() const
script engine context holding variable names and values
black scholes fd model base class for n underlyings (fx, equity or commodity)
fd gaussian cross asset model for single underlying ir model
gaussian cross asset model for ir, fx, eq, com
SequenceType parseSequenceType(const std::string &s)
Convert string to sequence type.
QuantLib::LsmBasisSystem::PolynomialType parsePolynomType(const std::string &s)
Convert text to QuantLib::LsmBasisSystem::PolynomialType.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
bool parseBool(const string &s)
Convert text to bool.
SobolRsg::DirectionIntegers parseSobolRsgDirectionIntegers(const std::string &s)
Convert text to QuantLib::SobolRsg::DirectionIntegers.
Real parseRealOrNull(const string &s)
Convert text to Real, empty string to Null<Real>()
bool isPseudoCurrency(const string &code)
check for pseudo currency = precious metal or crypto currency */
Real parseReal(const string &s)
Convert text to Real.
SobolBrownianGenerator::Ordering parseSobolBrownianGeneratorOrdering(const std::string &s)
Convert text to QuantLib::SobolBrownianGenerator::Ordering.
Integer parseInteger(const string &s)
Convert text to QuantLib::Integer.
translates between QuantLib::Index::name() and ORE names
IR component data for the cross asset model.
local vol model for n underlyings (fx, equity or commodity)
builder for an array of local vol processes
Classes and functions for log message handling.
#define LOG(text)
Logging Macro (Level = Notice)
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
#define DLOGGERSTREAM(text)
Classes for representing a strike using various conventions.
market data related utilties
class for holding details of a zero coupon CPI cap floor calibration instrument.
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
boost::shared_ptr< CrossAssetModel > getProjectedCrossAssetModel(const boost::shared_ptr< CrossAssetModel > &model, const std::vector< std::pair< CrossAssetModel::AssetType, Size > > &selectedComponents, std::vector< Size > &projectedStateProcessIndices)
CorrelationFactor parseCorrelationFactor(const string &name, const char separator)
ASTNodePtr parseScript(const std::string &code)
Handle< YieldTermStructure > indexOrYieldCurve(const QuantLib::ext::shared_ptr< Market > &market, const std::string &name, const std::string &configuration)
void addNewSchedulesToContext(QuantLib::ext::shared_ptr< Context > context, const std::vector< ScriptedTradeScriptData::NewScheduleData > &newSchedules)
std::string to_string(const LocationInfo &l)
std::map< std::string, std::vector< Real > > getCalibrationStrikes(const std::vector< ScriptedTradeScriptData::CalibrationData > &calibrationSpec, const QuantLib::ext::shared_ptr< Context > &context)
void checkDuplicateName(const QuantLib::ext::shared_ptr< Context > context, const std::string &name)
Size getInflationSimulationLag(const QuantLib::ext::shared_ptr< ZeroInflationIndex > &index)
std::pair< std::string, ScriptedTradeScriptData > getScript(const ScriptedTrade &scriptedTrade, const ScriptLibraryData &scriptLibrary, const std::string &purpose, const bool fallBackOnEmptyPurpose)
std::pair< std::string, Period > convertIndexToCamCorrelationEntry(const std::string &i)
QuantLib::ext::shared_ptr< Context > makeContext(Size nPaths, const std::string &gridCoarsening, const std::vector< std::string > &schedulesEligibleForCoarsening, const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceData, const std::vector< ScriptedTradeEventData > &events, const std::vector< ScriptedTradeValueTypeData > &numbers, const std::vector< ScriptedTradeValueTypeData > &indices, const std::vector< ScriptedTradeValueTypeData > ¤cies, const std::vector< ScriptedTradeValueTypeData > &daycounters)
Serializable Credit Default Swap.
Reference data model and serialization.
trade schedule data model and serialization
scripted instrument pricing engine
scripted instrument pricing engine using a cg model
QuantExt::CrossAssetModel::AssetType type
bool externalDeviceCompatibilityMode
QuantExt::SequenceType sequenceType
QuantLib::SobolBrownianGenerator::Ordering sobolOrdering
QuantExt::SequenceType trainingSequenceType
QuantLib::SobolRsg::DirectionIntegers sobolDirectionIntegers
QuantLib::Real regressionVarianceCutoff
QuantLib::LsmBasisSystem::PolynomialType polynomType
string conversion utilities