|
| 1 | +/* |
| 2 | + Copyright (C) 2018 Quaternion Risk Management Ltd |
| 3 | + All rights reserved. |
| 4 | +
|
| 5 | + This file is part of ORE, a free-software/open-source library |
| 6 | + for transparent pricing and risk analysis - http://opensourcerisk.org |
| 7 | +
|
| 8 | + ORE is free software: you can redistribute it and/or modify it |
| 9 | + under the terms of the Modified BSD License. You should have received a |
| 10 | + copy of the license along with this program. |
| 11 | + The license is also available online at <http://opensourcerisk.org> |
| 12 | +
|
| 13 | + This program is distributed on the basis that it will form a useful |
| 14 | + contribution to risk analytics and model standardisation, but WITHOUT |
| 15 | + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 16 | + FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. |
| 17 | +*/ |
| 18 | + |
| 19 | +#include <ored/portfolio/builders/formulabasedcoupon.hpp> |
| 20 | +#include <qle/cashflows/mcgaussianformulabasedcouponpricer.hpp> |
| 21 | + |
| 22 | +#include <ql/math/matrixutilities/pseudosqrt.hpp> |
| 23 | + |
| 24 | +#include <boost/algorithm/string.hpp> |
| 25 | +#include <boost/make_shared.hpp> |
| 26 | + |
| 27 | +#include <ored/configuration/correlationcurveconfig.hpp> |
| 28 | + |
| 29 | +#include <ored/utilities/indexparser.hpp> |
| 30 | +#include <ored/utilities/parsers.hpp> |
| 31 | + |
| 32 | +#include <boost/algorithm/string.hpp> |
| 33 | + |
| 34 | +#include <qle/termstructures/flatcorrelation.hpp> |
| 35 | + |
| 36 | +namespace ore { |
| 37 | +namespace data { |
| 38 | + |
| 39 | +boost::shared_ptr<FloatingRateCouponPricer> FormulaBasedCouponPricerBuilder::engineImpl( |
| 40 | + const std::string& paymentCcy, |
| 41 | + const std::map<std::string, boost::shared_ptr<QuantLib::IborCouponPricer>>& iborPricers, |
| 42 | + const std::map<std::string, boost::shared_ptr<QuantLib::CmsCouponPricer>>& cmsPricers, |
| 43 | + const std::map<std::string, boost::shared_ptr<InterestRateIndex>>& indexMaps) { |
| 44 | + |
| 45 | + // MC parameters |
| 46 | + auto samples = parseInteger(engineParameters_.at("Samples")); |
| 47 | + auto seed = parseInteger(engineParameters_.at("Seed")); |
| 48 | + auto useSobol = parseBool(engineParameters_.at("Sobol")); |
| 49 | + SalvagingAlgorithm::Type salvaging = parseBool(engineParameters_.at("SalvageCorrelationMatrix")) |
| 50 | + ? SalvagingAlgorithm::Spectral |
| 51 | + : SalvagingAlgorithm::None; |
| 52 | + |
| 53 | + // build fx vol map |
| 54 | + std::map<std::string, Handle<BlackVolTermStructure>> fxVols; |
| 55 | + for (auto const& i : indexMaps) { |
| 56 | + std::string indexCcy = i.second->currency().code(); |
| 57 | + if (indexCcy != paymentCcy) { |
| 58 | + fxVols[indexCcy] = (market_->fxVol(paymentCcy + indexCcy, configuration(MarketContext::pricing))); |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + // build correlation map (index-index or index-FX) |
| 63 | + // Index/Index correlation |
| 64 | + std::map<std::pair<std::string, std::string>, Handle<QuantExt::CorrelationTermStructure>> correlation; |
| 65 | + std::string fxSource = modelParameters_.at("FXSource"); |
| 66 | + std::string index1, index2, indexQL1, indexQL2; |
| 67 | + |
| 68 | + for (auto it1 = indexMaps.begin(); it1 != std::prev(indexMaps.end(), 1); it1++) { |
| 69 | + index1 = it1->first; |
| 70 | + indexQL1 = it1->second->name(); |
| 71 | + for (auto it2 = std::next(it1, 1); it2 != indexMaps.end(); it2++) { |
| 72 | + index2 = it2->first; |
| 73 | + indexQL2 = it2->second->name(); |
| 74 | + QuantLib::Handle<QuantExt::CorrelationTermStructure> corrCurve( |
| 75 | + boost::make_shared<FlatCorrelation>(0, NullCalendar(), 0.0, Actual365Fixed())); |
| 76 | + try { |
| 77 | + corrCurve = market_->correlationCurve(index1, index2, configuration(MarketContext::pricing)); |
| 78 | + } catch (...) { |
| 79 | + WLOG("no correlation curve found for " << index1 << ", " << index2 |
| 80 | + << " found, fall back to zero correlation."); |
| 81 | + } |
| 82 | + correlation[std::make_pair(indexQL1, indexQL2)] = corrCurve; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + std::string index, indexQL, indexCcy, fxIndex; |
| 87 | + for (auto const& it : indexMaps) { |
| 88 | + index = it.first; |
| 89 | + indexQL = it.second->name(); |
| 90 | + std::vector<std::string> result; |
| 91 | + boost::split(result, index, boost::is_any_of("-")); |
| 92 | + indexCcy = result[0]; |
| 93 | + if (indexCcy != paymentCcy) { |
| 94 | + fxIndex = "FX-" + fxSource + "-" + indexCcy + "-" + paymentCcy; |
| 95 | + QuantLib::Handle<QuantExt::CorrelationTermStructure> corrCurve( |
| 96 | + boost::make_shared<FlatCorrelation>(0, NullCalendar(), 0.0, Actual365Fixed())); |
| 97 | + try { |
| 98 | + corrCurve = market_->correlationCurve(index, fxIndex, configuration(MarketContext::pricing)); |
| 99 | + } catch (...) { |
| 100 | + WLOG("no correlation curve found for " << index << ", " << fxIndex |
| 101 | + << " found, fall back to zero correlation."); |
| 102 | + } |
| 103 | + correlation[std::make_pair(indexQL, "FX")] = corrCurve; |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + auto discount = market_->discountCurve(paymentCcy, configuration(MarketContext::pricing)); |
| 108 | + return boost::make_shared<QuantExt::MCGaussianFormulaBasedCouponPricer>( |
| 109 | + paymentCcy, iborPricers, cmsPricers, fxVols, correlation, discount, samples, seed, useSobol, salvaging); |
| 110 | +} |
| 111 | + |
| 112 | +} // namespace data |
| 113 | +} // namespace ore |
0 commit comments