|
20 | 20 | #include <ored/scripting/models/blackscholes.hpp> |
21 | 21 | #include <ored/scripting/models/blackscholescg.hpp> |
22 | 22 | #include <ored/scripting/models/fdblackscholesbase.hpp> |
| 23 | +#include <ored/scripting/models/fdgaussiancam.hpp> |
23 | 24 | #include <ored/scripting/models/gaussiancam.hpp> |
24 | 25 | #include <ored/scripting/models/gaussiancamcg.hpp> |
25 | 26 | #include <ored/scripting/models/localvol.hpp> |
|
51 | 52 |
|
52 | 53 | #include <ql/termstructures/volatility/equityfx/blackconstantvol.hpp> |
53 | 54 |
|
| 55 | +#include <boost/lexical_cast.hpp> |
| 56 | + |
54 | 57 | namespace ore { |
55 | 58 | namespace data { |
56 | 59 |
|
@@ -233,6 +236,8 @@ ScriptedTradeEngineBuilder::engine(const std::string& id, const ScriptedTrade& s |
233 | 236 | } else { |
234 | 237 | buildGaussianCam(id, iborFallbackConfig, script.conditionalExpectationModelStates()); |
235 | 238 | } |
| 239 | + } else if (modelParam_ == "GaussianCam" && engineParam_ == "FD") { |
| 240 | + buildFdGaussianCam(id, iborFallbackConfig); |
236 | 241 | } else { |
237 | 242 | QL_FAIL("model '" << modelParam_ << "' / engine '" << engineParam_ |
238 | 243 | << "' not recognised, expected BlackScholes/[MC|FD], LocalVolDupire/MC, " |
@@ -1511,6 +1516,104 @@ void ScriptedTradeEngineBuilder::buildGaussianCam(const std::string& id, const I |
1511 | 1516 | modelBuilders_.insert(std::make_pair(id, camBuilder)); |
1512 | 1517 | } |
1513 | 1518 |
|
| 1519 | +void ScriptedTradeEngineBuilder::buildFdGaussianCam(const std::string& id, |
| 1520 | + const IborFallbackConfig& iborFallbackConfig) { |
| 1521 | + |
| 1522 | + Date referenceDate = modelCurves_.front()->referenceDate(); |
| 1523 | + std::vector<Date> calibrationDates; |
| 1524 | + std::vector<std::string> calibrationExpiries, calibrationTerms; |
| 1525 | + |
| 1526 | + for (auto const& d : simulationDates_) { |
| 1527 | + if (d > referenceDate) { |
| 1528 | + calibrationDates.push_back(d); |
| 1529 | + calibrationExpiries.push_back(ore::data::to_string(d)); |
| 1530 | + // make sure the underlying swap has at least 1M to run, QL will throw otherwise during calibration |
| 1531 | + calibrationTerms.push_back(ore::data::to_string(std::max(d + 1 * Months, lastRelevantDate_))); |
| 1532 | + } |
| 1533 | + } |
| 1534 | + |
| 1535 | + // calibration times (need one less than calibration dates) |
| 1536 | + std::vector<Real> calibrationTimes; |
| 1537 | + for (Size i = 0; i + 1 < calibrationDates.size(); ++i) { |
| 1538 | + calibrationTimes.push_back(modelCurves_.front()->timeFromReference(calibrationDates[i])); |
| 1539 | + } |
| 1540 | + |
| 1541 | + // determine calibration strike |
| 1542 | + std::string calibrationStrike = "ATM"; |
| 1543 | + if(calibration_ == "Deal") { |
| 1544 | + // first model index found in calibration strike spec and first specified strike therein is used |
| 1545 | + for (auto const& m : modelIrIndices_) { |
| 1546 | + if (auto f = calibrationStrikes_.find(m.first); f != calibrationStrikes_.end()) { |
| 1547 | + if(!f->second.empty()) { |
| 1548 | + calibrationStrike = boost::lexical_cast<std::string>(f->second.front()); |
| 1549 | + } |
| 1550 | + } |
| 1551 | + } |
| 1552 | + } |
| 1553 | + |
| 1554 | + // IR config |
| 1555 | + QL_REQUIRE(modelCcys_.size() == 1, |
| 1556 | + "ScriptedTradeEngineBuilder::buildFdGaussianCam(): only one ccy is supported, got " |
| 1557 | + << modelCcys_.size()); |
| 1558 | + |
| 1559 | + auto config = boost::make_shared<IrLgmData>(); |
| 1560 | + config->qualifier() = getFirstIrIndexOrCcy(modelCcys_.front(), irIndices_); |
| 1561 | + config->reversionType() = LgmData::ReversionType::HullWhite; |
| 1562 | + config->volatilityType() = LgmData::VolatilityType::Hagan; |
| 1563 | + config->calibrateH() = false; |
| 1564 | + config->hParamType() = ParamType::Constant; |
| 1565 | + config->hTimes() = std::vector<Real>(); |
| 1566 | + config->shiftHorizon() = |
| 1567 | + modelCurves_.front()->timeFromReference(lastRelevantDate_) * 0.5; // TODO hardcode 0.5 here? |
| 1568 | + config->scaling() = 1.0; |
| 1569 | + std::string ccy = modelCcys_.front(); |
| 1570 | + if (zeroVolatility_ ) { |
| 1571 | + DLOG("set up zero vol IrLgmData for currency '" << modelCcys_.front() << "'"); |
| 1572 | + // zero vol |
| 1573 | + config->calibrationType() = CalibrationType::None; |
| 1574 | + config->hValues() = {0.0}; |
| 1575 | + config->calibrateA() = false; |
| 1576 | + config->aParamType() = ParamType::Constant; |
| 1577 | + config->aTimes() = std::vector<Real>(); |
| 1578 | + config->aValues() = {0.0}; |
| 1579 | + } else { |
| 1580 | + DLOG("set up IrLgmData for currency '" << modelCcys_.front() << "'"); |
| 1581 | + auto rev = irReversions_.find(modelCcys_.front()); |
| 1582 | + QL_REQUIRE(rev != irReversions_.end(), "reversion for ccy " << modelCcys_.front() << " not found"); |
| 1583 | + config->calibrationType() = CalibrationType::Bootstrap; |
| 1584 | + config->hValues() = {rev->second}; |
| 1585 | + config->calibrateA() = true; |
| 1586 | + config->aParamType() = ParamType::Piecewise; |
| 1587 | + config->aTimes() = calibrationTimes; |
| 1588 | + config->aValues() = std::vector<Real>(calibrationTimes.size() + 1, 0.0030); // start value for optimiser |
| 1589 | + config->optionExpiries() = calibrationExpiries; |
| 1590 | + config->optionTerms() = calibrationTerms; |
| 1591 | + config->optionStrikes() = std::vector<std::string>(calibrationExpiries.size(), calibrationStrike); |
| 1592 | + } |
| 1593 | + |
| 1594 | + std::string configurationInCcy = configuration(MarketContext::irCalibration); |
| 1595 | + std::string configurationXois = configuration(MarketContext::pricing); |
| 1596 | + |
| 1597 | + auto camBuilder = boost::make_shared<CrossAssetModelBuilder>( |
| 1598 | + market_, |
| 1599 | + boost::make_shared<CrossAssetModelData>( |
| 1600 | + std::vector<boost::shared_ptr<IrModelData>>{config}, std::vector<boost::shared_ptr<FxBsData>>{}, |
| 1601 | + std::vector<boost::shared_ptr<EqBsData>>{}, std::vector<boost::shared_ptr<InflationModelData>>{}, |
| 1602 | + std::vector<boost::shared_ptr<CrLgmData>>{}, std::vector<boost::shared_ptr<CrCirData>>{}, |
| 1603 | + std::vector<boost::shared_ptr<CommoditySchwartzData>>{}, 0, |
| 1604 | + std::map<CorrelationKey, QuantLib::Handle<QuantLib::Quote>>{}, bootstrapTolerance_, "LGM", |
| 1605 | + CrossAssetModel::Discretization::Exact), |
| 1606 | + configurationInCcy, configurationXois, configurationXois, configurationInCcy, configurationInCcy, |
| 1607 | + configurationXois, !calibrate_ || zeroVolatility_, continueOnCalibrationError_, referenceCalibrationGrid_, |
| 1608 | + SalvagingAlgorithm::Spectral, id); |
| 1609 | + |
| 1610 | + model_ = boost::make_shared<FdGaussianCam>(camBuilder->model(), modelCcys_.front(), modelCurves_.front(), |
| 1611 | + modelIrIndices_, simulationDates_, modelSize_, timeStepsPerYear_, |
| 1612 | + mesherEpsilon_, iborFallbackConfig); |
| 1613 | + |
| 1614 | + modelBuilders_.insert(std::make_pair(id, camBuilder)); |
| 1615 | +} |
| 1616 | + |
1514 | 1617 | void ScriptedTradeEngineBuilder::buildAMCCGModel(const std::string& id, const IborFallbackConfig& iborFallbackConfig, |
1515 | 1618 | const std::vector<std::string>& conditionalExpectationModelStates) { |
1516 | 1619 | // nothing to build really, the resulting model is exactly the input model |
|
0 commit comments