Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
localvol.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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
20
22
23#include <ql/exercise.hpp>
24#include <ql/math/comparison.hpp>
25#include <ql/math/matrixutilities/pseudosqrt.hpp>
26#include <ql/quotes/simplequote.hpp>
27
28namespace ore {
29namespace data {
30
31using namespace QuantLib;
32using namespace QuantExt;
33
34LocalVol::LocalVol(const Size paths, const std::string& currency, const Handle<YieldTermStructure>& curve,
35 const std::string& index, const std::string& indexCurrency,
36 const Handle<BlackScholesModelWrapper>& model, const McParams& mcParams,
37 const std::set<Date>& simulationDates, const IborFallbackConfig& iborFallbackConfig)
38 : LocalVol(paths, {currency}, {curve}, {}, {}, {}, {index}, {indexCurrency}, model, {}, mcParams, simulationDates,
39 iborFallbackConfig) {}
40
42 const Size paths, const std::vector<std::string>& currencies, const std::vector<Handle<YieldTermStructure>>& curves,
43 const std::vector<Handle<Quote>>& fxSpots,
44 const std::vector<std::pair<std::string, QuantLib::ext::shared_ptr<InterestRateIndex>>>& irIndices,
45 const std::vector<std::pair<std::string, QuantLib::ext::shared_ptr<ZeroInflationIndex>>>& infIndices,
46 const std::vector<std::string>& indices, const std::vector<std::string>& indexCurrencies,
47 const Handle<BlackScholesModelWrapper>& model,
48 const std::map<std::pair<std::string, std::string>, Handle<QuantExt::CorrelationTermStructure>>& correlations,
49 const McParams& mcParams, const std::set<Date>& simulationDates, const IborFallbackConfig& iborFallbackConfig)
50 : BlackScholesBase(paths, currencies, curves, fxSpots, irIndices, infIndices, indices, indexCurrencies, model,
51 correlations, mcParams, simulationDates, iborFallbackConfig) {}
52
54
56
57 // nothing to do if we do not have any indices
58
59 if (indices_.empty())
60 return;
61
62 // init underlying path where we map a date to a randomvariable representing the path values
63
64 for (auto const& d : effectiveSimulationDates_) {
65 underlyingPaths_[d] = std::vector<RandomVariable>(model_->processes().size(), RandomVariable(size(), 0.0));
66 if (trainingSamples() != Null<Size>())
68 std::vector<RandomVariable>(model_->processes().size(), RandomVariable(trainingSamples(), 0.0));
69 }
70
71 // compile the correlation matrix
72
73 Matrix correlation = getCorrelation();
74
75 // set reference date values, if there are no future simulation dates we are done
76
77 for (Size l = 0; l < indices_.size(); ++l) {
78 underlyingPaths_[*effectiveSimulationDates_.begin()][l].setAll(model_->processes()[l]->x0());
79 if (trainingSamples() != Null<Size>()) {
80 underlyingPathsTraining_[*effectiveSimulationDates_.begin()][l].setAll(model_->processes()[l]->x0());
81 }
82 }
83
84 if (effectiveSimulationDates_.size() == 1)
85 return;
86
87 // compute the sqrt correlation
88
89 Matrix sqrtCorr = pseudoSqrt(correlation, SalvagingAlgorithm::Spectral);
90
91 // precompute the deterministic part of the drift on each time step
92
93 std::vector<Array> deterministicDrift(timeGrid_.size() - 1, Array(indices_.size(), 0.0));
94
95 for (Size i = 0; i < timeGrid_.size() - 1; ++i) {
96 for (Size j = 0; j < indices_.size(); ++j) {
97 Real t0 = timeGrid_[i];
98 Real t1 = timeGrid_[i + 1];
99 deterministicDrift[i][j] = -std::log(model_->processes()[j]->riskFreeRate()->discount(t1) /
100 model_->processes()[j]->dividendYield()->discount(t1) /
101 (model_->processes()[j]->riskFreeRate()->discount(t0) /
102 model_->processes()[j]->dividendYield()->discount(t0)));
103 }
104 }
105
106 // precompute index for drift adjustment for eq / com indices that are not in base ccy
107
108 std::vector<Size> eqComIdx(indices_.size());
109 for (Size j = 0; j < indices_.size(); ++j) {
110 Size idx = Null<Size>();
111 if (!indices_[j].isFx()) {
112 // do we have an fx index with the desired currency?
113 for (Size jj = 0; jj < indices_.size(); ++jj) {
114 if (indices_[jj].isFx()) {
116 idx = jj;
117 }
118 }
119 }
120 eqComIdx[j] = idx;
121 }
122
123 // precompute some time related quantities
124
125 std::vector<Real> t(timeGrid_.size() - 1), dt(timeGrid_.size() - 1), sqrtdt(timeGrid_.size() - 1);
126 for (Size i = 0; i < timeGrid_.size() - 1; ++i) {
127 t[i] = timeGrid_[i];
128 dt[i] = timeGrid_[i + 1] - timeGrid_[i];
129 sqrtdt[i] = std::sqrt(dt[i]);
130 }
131
132 // evolve the process using correlated normal variates and set the underlying path values
133
138 correlation, sqrtCorr, deterministicDrift, eqComIdx, t, dt, sqrtdt);
139
140 if (trainingSamples() != Null<Size>()) {
143 timeGrid_.size() - 1, mcParams_.trainingSeed,
145 correlation, sqrtCorr, deterministicDrift, eqComIdx, t, dt, sqrtdt);
146 }
147
148} // initPaths()
149
150void LocalVol::populatePathValues(const Size nSamples, std::map<Date, std::vector<RandomVariable>>& paths,
151 const QuantLib::ext::shared_ptr<MultiPathVariateGeneratorBase>& gen,
152 const Matrix& correlation, const Matrix& sqrtCorr,
153 const std::vector<Array>& deterministicDrift, const std::vector<Size>& eqComIdx,
154 const std::vector<Real>& t, const std::vector<Real>& dt,
155 const std::vector<Real>& sqrtdt) const {
156
157 Array stateDiff(indices_.size()), logState(indices_.size()), logState0(indices_.size());
158 for (Size j = 0; j < indices_.size(); ++j) {
159 logState0[j] = std::log(model_->processes()[j]->x0());
160 }
161
162 std::vector<std::vector<RandomVariable*>> rvs(indices_.size(),
163 std::vector<RandomVariable*>(effectiveSimulationDates_.size() - 1));
164 auto date = effectiveSimulationDates_.begin();
165 for (Size i = 0; i < effectiveSimulationDates_.size() - 1; ++i) {
166 ++date;
167 for (Size j = 0; j < indices_.size(); ++j) {
168 rvs[j][i] = &paths[*date][j];
169 rvs[j][i]->expand();
170 }
171 }
172
173 for (Size path = 0; path < size(); ++path) {
174 auto p = gen->next();
175 logState = logState0;
176 std::size_t date = 0;
177 auto pos = positionInTimeGrid_.begin();
178 ++pos;
179 // evolve the process on the refined time grid
180 for (Size i = 0; i < timeGrid_.size() - 1; ++i) {
181 for (Size j = 0; j < indices_.size(); ++j) {
182 // localVol might throw / return nan, inf, handle these cases here
183 // by setting the local vol to zero
184 Real volj = 0.0;
185 try {
186 volj = model_->processes()[j]->localVolatility()->localVol(t[i], std::exp(logState[j]));
187 } catch (...) {
188 }
189 if (!std::isfinite(volj))
190 volj = 0.0;
191 Real dw = 0;
192 for (Size k = 0; k < indices_.size(); ++k) {
193 dw += sqrtCorr[j][k] * p.value[i][k];
194 }
195 stateDiff[j] = volj * dw * sqrtdt[i] - 0.5 * volj * volj * dt[i];
196 // drift adjustment for eq / com indices that are not in base ccy
197 if (eqComIdx[j] != Null<Size>()) {
198 Real volIdx = model_->processes()[eqComIdx[j]]->localVolatility()->localVol(
199 t[i], std::exp(logState[eqComIdx[j]]));
200 stateDiff[j] -= correlation[eqComIdx[j]][j] * volIdx * volj * dt[i];
201 }
202 }
203 // update state with stateDiff from above and deterministic part of the drift
204 logState += stateDiff + deterministicDrift[i];
205 // on the effective simulation dates populate the underlying paths
206 if (i + 1 == *pos) {
207 for (Size j = 0; j < indices_.size(); ++j)
208 rvs[j][date]->data()[path] = std::exp(logState[j]);
209 ++date;
210 ++pos;
211 }
212 }
213 }
214} // populatePathValues()
215
216RandomVariable LocalVol::getFutureBarrierProb(const std::string& index, const Date& obsdate1, const Date& obsdate2,
217 const RandomVariable& barrier, const bool above) const {
218 QL_FAIL("getFutureBarrierProb not implemented by LocalVol");
219}
220
221} // namespace data
222} // namespace ore
void performCalculations() const override
Size size() const override
std::map< Date, std::vector< RandomVariable > > underlyingPathsTraining_
std::map< Date, std::vector< RandomVariable > > underlyingPaths_
std::set< Date > effectiveSimulationDates_
const Handle< BlackScholesModelWrapper > model_
Size trainingSamples() const override
std::vector< Size > positionInTimeGrid_
void performCalculations() const override
Definition: localvol.cpp:53
RandomVariable getFutureBarrierProb(const std::string &index, const Date &obsdate1, const Date &obsdate2, const RandomVariable &barrier, const bool above) const override
Definition: localvol.cpp:216
void populatePathValues(const Size nSamples, std::map< Date, std::vector< RandomVariable > > &paths, const QuantLib::ext::shared_ptr< MultiPathVariateGeneratorBase > &gen, const Matrix &correlation, const Matrix &sqrtCorr, const std::vector< Array > &deterministicDrift, const std::vector< Size > &eqComIdx, const std::vector< Real > &t, const std::vector< Real > &dt, const std::vector< Real > &sqrtdt) const
Definition: localvol.cpp:150
LocalVol(const Size paths, const std::vector< std::string > &currencies, const std::vector< Handle< YieldTermStructure > > &curves, const std::vector< Handle< Quote > > &fxSpots, const std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< InterestRateIndex > > > &irIndices, const std::vector< std::pair< std::string, QuantLib::ext::shared_ptr< ZeroInflationIndex > > > &infIndices, const std::vector< std::string > &indices, const std::vector< std::string > &indexCurrencies, const Handle< BlackScholesModelWrapper > &model, const std::map< std::pair< std::string, std::string >, Handle< QuantExt::CorrelationTermStructure > > &correlations, const McParams &mcparams, const std::set< Date > &simulationDates, const IborFallbackConfig &iborFallbackConfig=IborFallbackConfig::defaultConfig())
Definition: localvol.cpp:41
std::vector< IndexInfo > indices_
Definition: modelimpl.hpp:114
Real dt(const Date &d1, const Date &d2) const override
Definition: modelimpl.hpp:73
const std::vector< std::string > indexCurrencies_
Definition: modelimpl.hpp:108
local vol model for n underlyings (fx, equity or commodity)
@ data
Definition: log.hpp:77
boost::shared_ptr< MultiPathVariateGeneratorBase > makeMultiPathVariateGenerator(const SequenceType s, const Size dimension, const Size timeSteps, const BigNatural seed, const SobolBrownianGenerator::Ordering ordering, const SobolRsg::DirectionIntegers directionIntegers)
Serializable Credit Default Swap.
Definition: namespaces.docs:23
QuantExt::SequenceType sequenceType
Definition: model.hpp:54
QuantLib::SobolBrownianGenerator::Ordering sobolOrdering
Definition: model.hpp:59
QuantExt::SequenceType trainingSequenceType
Definition: model.hpp:55
QuantLib::SobolRsg::DirectionIntegers sobolDirectionIntegers
Definition: model.hpp:60