QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
lognormalfwdrateeulerconstrained.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4Copyright (C) 2006 Ferdinando Ametrano
5Copyright (C) 2006 Mark Joshi
6
7This file is part of QuantLib, a free-software/open-source library
8for financial quantitative analysts and developers - http://quantlib.org/
9
10QuantLib is free software: you can redistribute it and/or modify it
11under the terms of the QuantLib license. You should have received a
12copy of the license along with this program; if not, please email
13<quantlib-dev@lists.sf.net>. The license is also available online at
14<http://quantlib.org/license.shtml>.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the license for more details.
19*/
20
21#include <ql/models/marketmodels/evolvers/lognormalfwdrateeulerconstrained.hpp>
22#include <ql/models/marketmodels/marketmodel.hpp>
23#include <ql/models/marketmodels/evolutiondescription.hpp>
24#include <ql/models/marketmodels/browniangenerator.hpp>
25#include <ql/models/marketmodels/driftcomputation/lmmdriftcalculator.hpp>
26#include <ql/math/distributions/normaldistribution.hpp>
27
28namespace QuantLib {
29
30
32 const ext::shared_ptr<MarketModel>& marketModel,
33 const BrownianGeneratorFactory& factory,
34 const std::vector<Size>& numeraires,
35 Size initialStep)
36 : marketModel_(marketModel),
37 numeraires_(numeraires),
38 initialStep_(initialStep),
39 numberOfRates_(marketModel->numberOfRates()),
40 numberOfFactors_(marketModel_->numberOfFactors()),
41 curveState_(marketModel->evolution().rateTimes()),
42 forwards_(marketModel->initialRates()),
43 displacements_(marketModel->displacements()),
44 logForwards_(numberOfRates_), initialLogForwards_(numberOfRates_),
45 drifts1_(numberOfRates_), initialDrifts_(numberOfRates_),
46 brownians_(numberOfFactors_), correlatedBrownians_(numberOfRates_),
47 alive_(marketModel->evolution().firstAliveRate())
48 {
49 checkCompatibility(marketModel->evolution(), numeraires);
50
51 Size steps = marketModel->evolution().numberOfSteps();
52
55
56 calculators_.reserve(steps);
57 variances_.reserve(steps);
58 fixedDrifts_.reserve(steps);
59 for (Size j=0; j<steps; ++j) {
60 const Matrix& A = marketModel_->pseudoRoot(j);
61 calculators_.emplace_back(A, displacements_, marketModel->evolution().rateTaus(),
62 numeraires[j], alive_[j]);
63 std::vector<Real> fixed(numberOfRates_);
64 std::vector<Real> variances(numberOfRates_);
65 for (Size k=0; k<numberOfRates_; ++k) {
66 Real variance =
67 std::inner_product(A.row_begin(k), A.row_end(k),
68 A.row_begin(k), Real(0.0));
69 variances[k] = variance;
70 fixed[k] = -0.5*variance;
71 }
72 variances_.push_back(variances);
73 fixedDrifts_.push_back(fixed);
74 }
75
76 setForwards(marketModel_->initialRates());
77 }
78
79 const std::vector<Size>& LogNormalFwdRateEulerConstrained::numeraires() const {
80 return numeraires_;
81 }
82
83 void LogNormalFwdRateEulerConstrained::setForwards(const std::vector<Real>& forwards)
84 {
85 QL_REQUIRE(forwards.size()==numberOfRates_,
86 "mismatch between forwards and rateTimes");
87 for (Size i=0; i<numberOfRates_; ++i)
88 initialLogForwards_[i] = std::log(forwards[i] +
90 calculators_[initialStep_].compute(forwards, initialDrifts_);
91 }
92
95 }
96
98 const std::vector<Size>& startIndexOfSwapRate,
99 const std::vector<Size>& endIndexOfSwapRate)
100 {
101 QL_REQUIRE(startIndexOfSwapRate.size() == numeraires_.size(),
102 "Size mismatch in constraint specification.");
103 QL_REQUIRE(endIndexOfSwapRate.size() == numeraires_.size(), "Size mismatch in constraint specification.");
104
105 startIndexOfSwapRate_=startIndexOfSwapRate;
106 endIndexOfSwapRate_ = endIndexOfSwapRate;
107
108 covariances_.clear();
109 covariances_.reserve(startIndexOfSwapRate_.size());
110
111 std::vector<Real> covariances(numberOfRates_);
112
113 for (Size i=0; i < startIndexOfSwapRate_.size(); ++i) {
114 QL_REQUIRE(startIndexOfSwapRate_[i]+1 == endIndexOfSwapRate_[i],
115 "constrained euler currently only implemented for forward rates");
116
117 const Matrix& A = marketModel_->pseudoRoot(currentStep_);
118
119 for (Size j=0; j < numberOfRates_; ++j) {
120 Real cov=0.0;
121 for (Size k=0; k < numberOfFactors_; ++k)
122 cov += A[startIndexOfSwapRate_[i]][k]*A[j][k];
123 covariances[j] = cov;
124
125 }
126 covariances_.push_back(covariances);
127 }
128
129 }
130
132 const std::vector<Rate>& rateConstraints,
133 const std::valarray<bool>& isConstraintActive)
134 {
135 QL_REQUIRE(rateConstraints.size() == numeraires_.size(),
136 "wrong number of constraints specified");
137
138 QL_REQUIRE(isConstraintActive.size() == numeraires_.size(),
139 "wrong number of isConstraintActive specified");
140
141 rateConstraints_=rateConstraints;
142 isConstraintActive_.resize(isConstraintActive.size());
143 isConstraintActive_ = isConstraintActive;
144
145 for (unsigned long i=0; i < rateConstraints_.size(); i++)
147 }
148
149
152 std::copy(initialLogForwards_.begin(), initialLogForwards_.end(),
153 logForwards_.begin());
154 return generator_->nextPath();
155 }
156
158 {
159 // we're going from T1 to T2
160
161 // a) compute drifts D1 at T1;
164 } else {
165 std::copy(initialDrifts_.begin(), initialDrifts_.end(),
166 drifts1_.begin());
167 }
168
169 // b) evolve forwards up to T2 using D1;
170 Real weight = generator_->nextStep(brownians_);
171 const Matrix& A = marketModel_->pseudoRoot(currentStep_);
172 const std::vector<Real>& fixedDrift = fixedDrifts_[currentStep_];
173
174 Size alive = alive_[currentStep_];
175 for (Size i=alive; i<numberOfRates_; i++) {
176 logForwards_[i] += drifts1_[i] + fixedDrift[i];
177 logForwards_[i] +=
178 std::inner_product(A.row_begin(i), A.row_end(i),
179 brownians_.begin(), Real(0.0));
180 }
181
182 // check constraint active
185
186 // compute error
187 Real requiredShift = rateConstraints_[currentStep_] - logForwards_[index];
188
189 Real multiplier = requiredShift/variances_[currentStep_][index];
190
191 // now shift each rate by multiplier * weighting of index rate
192 // across the step
193 for (Size i=alive; i<numberOfRates_; i++) {
194 // we only need a small part of cov matrix
195 logForwards_[i] += multiplier*covariances_[currentStep_][i];
196 }
197
198 // now we need to calculate the LR shift, we have moved Gaussian Z_k by multiplier * a_{index,k}
199 // divide original density by density of shifted normal
200 Real weightsEffect = 1.0;
201
203 for (Size k=0; k < numberOfFactors_; k++) {
204 Real shift = multiplier * A[index][k];
205 Real originalDensity = phi.derivative(brownians_[k]+shift);
206 // the density of the draw after changes in original measure
207 Real newDensity = phi.derivative(brownians_[k]);
208 // the density of the draw after changes in new measure, shifts cancel
209 weightsEffect*= originalDensity/newDensity;
210 }
211
212 weight *= weightsEffect;
213 }
214
215 for (Size i=alive; i<numberOfRates_; i++)
216 forwards_[i] = std::exp(logForwards_[i]) - displacements_[i];
217
218 // c) update curve state
220
221 ++currentStep_;
222
223 return weight;
224 }
225
227 return currentStep_;
228 }
229
231 return curveState_;
232 }
233
234}
virtual ext::shared_ptr< BrownianGenerator > create(Size factors, Size steps) const =0
Cumulative normal distribution function.
Curve state for market-model simulations
Definition: curvestate.hpp:41
virtual const std::vector< Rate > & forwardRates() const =0
void setOnForwardRates(const std::vector< Rate > &fwdRates, Size firstValidIndex=0)
void setForwards(const std::vector< Real > &forwards)
LogNormalFwdRateEulerConstrained(const ext::shared_ptr< MarketModel > &, const BrownianGeneratorFactory &, const std::vector< Size > &numeraires, Size initialStep=0)
void setConstraintType(const std::vector< Size > &startIndexOfSwapRate, const std::vector< Size > &endIndexOfSwapRate) override
call once
void setThisConstraint(const std::vector< Rate > &rateConstraints, const std::valarray< bool > &isConstraintActive) override
call before each path
const std::vector< Size > & numeraires() const override
Matrix used in linear algebra.
Definition: matrix.hpp:41
const_row_iterator row_begin(Size i) const
Definition: matrix.hpp:360
const_row_iterator row_end(Size i) const
Definition: matrix.hpp:378
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Definition: any.hpp:35
void checkCompatibility(const EvolutionDescription &evolution, const std::vector< Size > &numeraires)