QuantLib: a free/open-source library for quantitative finance
Fully annotated sources - version 1.32
Loading...
Searching...
No Matches
swaptionpseudojacobian.cpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4
5Copyright (C) 2008 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
22
23#include <ql/models/marketmodels/pathwisegreeks/swaptionpseudojacobian.hpp>
24#include <ql/models/marketmodels/curvestates/lmmcurvestate.hpp>
25#include <ql/models/marketmodels/evolutiondescription.hpp>
26#include <ql/models/marketmodels/swapforwardmappings.hpp>
27#include <ql/pricingengines/blackformula.hpp>
28#include <ql/math/solvers1d/brent.hpp>
29
30
31namespace QuantLib
32{
33
35 const ext::shared_ptr<MarketModel>& inputModel, Size startIndex, Size endIndex) {
36 std::vector<Real> subRateTimes(inputModel->evolution().rateTimes().begin()+startIndex,
37 inputModel->evolution().rateTimes().begin()+endIndex+1);
38
39 std::vector<Real> subForwards(inputModel->initialRates().begin()+startIndex,inputModel->initialRates().begin()+endIndex);
40
41 LMMCurveState cs(subRateTimes);
42 cs.setOnForwardRates(subForwards);
43
44 Matrix zed(SwapForwardMappings::coterminalSwapZedMatrix(cs,inputModel->displacements()[0]));
45 Size factors = inputModel->numberOfFactors();
46
47
48 //first compute variance and implied vol
49
50 variance_=0.0;
51 Size index=0;
52
53 while (index < inputModel->evolution().numberOfSteps() && inputModel->evolution().firstAliveRate()[index] <= startIndex)
54 {
55 const Matrix& thisPseudo = inputModel->pseudoRoot(index);
56
57 Real thisVariance_ =0.0;
58 for (Size j=startIndex; j < endIndex; ++j)
59 for (Size k=startIndex; k < endIndex; ++k)
60 for (Size f=0; f < factors; ++f)
61 thisVariance_+= zed[0][j-startIndex]*thisPseudo[j][f]*thisPseudo[k][f]*zed[0][k-startIndex];
62
63 variance_ += thisVariance_;
64
65 ++index;
66 }
67
68 Size stopIndex = index;
69
70 expiry_ = subRateTimes[0];
71
73
74 Real scale = 0.5*(1.0/expiry_)/impliedVolatility_;
75
76 Size numberRates = inputModel->evolution().numberOfRates();
77
78 Matrix thisDerivative(numberRates, factors,0.0);
79 Matrix nullDerivative(numberRates, factors,0.0);
80
81 index =0;
82
83 while (index < stopIndex)
84 {
85 const Matrix& thisPseudo = inputModel->pseudoRoot(index);
86
87 for (Size rate=startIndex; rate<endIndex; ++rate)
88 {
89 Size zIndex = rate -startIndex;
90 for (Size f =0; f < factors; ++f)
91 {
92 Real sum=0.0;
93 for (Size rate2 = startIndex; rate2<endIndex; ++rate2)
94 {
95 Size zIndex2 = rate2-startIndex;
96 sum += zed[0][zIndex2] * thisPseudo[rate2][f];
97 }
98 sum *= 2.0*zed[0][zIndex];
99
100 thisDerivative[rate][f] =sum;
101
102 }
103 }
104
105 varianceDerivatives_.push_back(thisDerivative);
106
107 for ( Size rate=startIndex; rate<endIndex; ++rate)
108 for (Size f =0; f < factors; ++f)
109 thisDerivative[rate][f] *= scale;
110
111 volatilityDerivatives_.push_back(thisDerivative);
112
113 ++index;
114 }
115
116 for (; index < inputModel->evolution().numberOfSteps(); ++index)
117 {
118 varianceDerivatives_.push_back(nullDerivative);
119 volatilityDerivatives_.push_back(nullDerivative);
120
121 }
122
123
124
125
126
127 }
128
130 {
131 return varianceDerivatives_[i];
132 }
133
135 {
136 return volatilityDerivatives_[i];
137 }
138
140 {
141 return impliedVolatility_;
142 }
144 {
145 return variance_;
146 }
148 {
149 return expiry_;
150 }
151
152 namespace
153 {
154
155 // this class doesn't copy anything so fast to create and use
156 // but make sure everything it uses stays in scope...
157 class QuickCap
158 {
159 public:
160 QuickCap(Real Strike,
161 const std::vector<Real>& annuities,
162 const std::vector<Real>& currentRates,
163 const std::vector<Real>& expiries,
164 Real price);
165
166 Real operator()(Real volatility) const; // returns difference from input price
167
168 Real vega(Real volatility) const; // returns vol derivative
169
170
171
172 private:
173 Real strike_;
174 const std::vector<Real>& annuities_;
175 const std::vector<Real>& currentRates_;
176 const std::vector<Real>& expiries_;
177 Real price_;
178
179 };
180
181 QuickCap::QuickCap(Real Strike,
182 const std::vector<Real>& annuities,
183 const std::vector<Real>& currentRates,
184 const std::vector<Real>& expiries,
185 Real price)
186 :
187 strike_(Strike),
188 annuities_(annuities),
189 currentRates_(currentRates),
190 expiries_(expiries),
191 price_(price)
192 {
193 }
194
195 Real QuickCap::operator()(Real volatility) const
196 {
197 Real price =0.0;
198 for (Size i=0; i < annuities_.size(); ++i)
199 {
200 price += blackFormula(Option::Call,strike_,
201 currentRates_[i],
202 volatility*std::sqrt(expiries_[i]),
203 annuities_[i]);
204
205
206 }
207 return price-price_;
208 }
209
210 Real QuickCap::vega(Real volatility) const // returns vol derivative
211 {
212 Real vega =0.0;
213 for (Size i=0; i < annuities_.size(); ++i)
214 {
215
216
217 vega+= blackFormulaVolDerivative(strike_,currentRates_[i],
218
219 volatility*std::sqrt(expiries_[i]),
220 expiries_[i],
221 annuities_[i],
222 0.0);
223 }
224
225 return vega;
226 }
227
228
229
230 }
231
232 CapPseudoDerivative::CapPseudoDerivative(const ext::shared_ptr<MarketModel>& inputModel,
233 Real strike,
234 Size startIndex,
235 Size endIndex,
236 Real firstDF)
237 : firstDF_(firstDF) {
238 QL_REQUIRE(startIndex < endIndex, "for a cap pseudo derivative the start of the cap must be before the end");
239 QL_REQUIRE( endIndex <= inputModel->numberOfRates(), "for a cap pseudo derivative the end of the cap must before the end of the rates");
240
241 Size numberCaplets = endIndex-startIndex;
242 Size numberRates = inputModel->numberOfRates();
243 Size factors = inputModel->numberOfFactors();
244 LMMCurveState curve(inputModel->evolution().rateTimes());
245 curve.setOnForwardRates(inputModel->initialRates());
246
247 const Matrix& totalCovariance(inputModel->totalCovariance(inputModel->numberOfSteps()-1));
248
249 std::vector<Real> displacedImpliedVols(numberCaplets);
250 std::vector<Real> annuities(numberCaplets);
251 std::vector<Real> initialRates(numberCaplets);
252 std::vector<Real> expiries(numberCaplets);
253
254 Real capPrice =0.0;
255
256 Real guess=0.0;
257 Real minVol = 1e10;
258 Real maxVol =0.0;
259
260 for (Size j = startIndex; j < endIndex; ++j)
261 {
262 Size capletIndex = j - startIndex;
263 Time resetTime = inputModel->evolution().rateTimes()[j];
264 expiries[capletIndex] = resetTime;
265
266 Real sd = std::sqrt(totalCovariance[j][j]);
267 displacedImpliedVols[capletIndex] = std::sqrt(totalCovariance[j][j]/resetTime);
268
269 Real forward = inputModel->initialRates()[j];
270 initialRates[capletIndex] = forward;
271
272 Real annuity = curve.discountRatio(j+1,0)* inputModel->evolution().rateTaus()[j]*firstDF_;
273 annuities[capletIndex] = annuity;
274
275 Real displacement = inputModel->displacements()[j];
276
277 guess+= displacedImpliedVols[capletIndex]*(forward+displacement)/forward;
278 minVol =std::min(minVol, displacedImpliedVols[capletIndex]);
279 maxVol =std::max(maxVol, displacedImpliedVols[capletIndex]*(forward+displacement)/forward);
280
281
282 Real capletPrice = blackFormula(Option::Call,
283 strike,
284 forward,
285 sd,
286 annuity,
287 displacement
288 );
289
290 capPrice += capletPrice;
291
292 }
293
294 guess/=numberCaplets;
295
296
297 for (Size step =0; step < inputModel->evolution().numberOfSteps(); ++step)
298 {
299 Matrix thisDerivative(numberRates,factors,0.0);
300
301 for (Size rate =std::max(inputModel->evolution().firstAliveRate()[step],startIndex);
302 rate < endIndex; ++rate)
303 {
304 for (Size f=0; f < factors; ++f)
305 {
306 Real expiry = inputModel->evolution().rateTimes()[rate];
307 Real volDerivative = inputModel->pseudoRoot(step)[rate][f]
308 /(displacedImpliedVols[rate-startIndex]*expiry);
309 Real capletVega = blackFormulaVolDerivative(strike,inputModel->initialRates()[rate],
310 displacedImpliedVols[rate-startIndex]*std::sqrt(expiry),
311 expiry,
312 annuities[rate-startIndex],
313 inputModel->displacements()[rate]);
314
315 // note that the cap derivative is equal to one of the caplet ones so we lose a loop
316 thisDerivative[rate][f] = volDerivative*capletVega;
317 }
318 }
319
320 priceDerivatives_.push_back(thisDerivative);
321
322 }
323
324 QuickCap capPricer(strike, annuities, initialRates, expiries,capPrice);
325
326 Size maxEvaluations = 1000;
327 Real accuracy = 1E-6;
328
329 Brent solver;
330 solver.setMaxEvaluations(maxEvaluations);
331 impliedVolatility_ = solver.solve(capPricer,accuracy,guess,minVol*0.99,maxVol*1.01);
332
333
334
335 vega_ = capPricer.vega(impliedVolatility_);
336
337
338
339 for (Size step =0; step < inputModel->evolution().numberOfSteps(); ++step)
340 {
341 Matrix thisDerivative(numberRates,factors,0.0);
342
343 for (Size rate =std::max(inputModel->evolution().firstAliveRate()[step],startIndex);
344 rate < endIndex; ++rate)
345 {
346 for (Size f=0; f < factors; ++f)
347 {
348
349 thisDerivative[rate][f] = priceDerivatives_[step][rate][f]/vega_;
350 }
351 }
352
353 volatilityDerivatives_.push_back(thisDerivative);
354
355 }
356
357
358
359 }
360
361
363 {
364 return priceDerivatives_[i];
365 }
366
368 {
369 return volatilityDerivatives_[i];
370 }
371
372
373
375 {
376 return impliedVolatility_;
377 }
378
379
380
381
382}
Brent 1-D solver
Definition: brent.hpp:37
const Matrix & priceDerivative(Size i) const
const Matrix & volatilityDerivative(Size i) const
std::vector< Matrix > volatilityDerivatives_
CapPseudoDerivative(const ext::shared_ptr< MarketModel > &inputModel, Real strike, Size startIndex, Size endIndex, Real firstDF)
Curve state for Libor market models
Real discountRatio(Size i, Size j) const override
void setOnForwardRates(const std::vector< Rate > &fwdRates, Size firstValidIndex=0)
Matrix used in linear algebra.
Definition: matrix.hpp:41
void setMaxEvaluations(Size evaluations)
Definition: solver1d.hpp:238
Real solve(const F &f, Real accuracy, Real guess, Real step) const
Definition: solver1d.hpp:84
static Matrix coterminalSwapZedMatrix(const CurveState &cs, Spread displacement)
SwaptionPseudoDerivative(const ext::shared_ptr< MarketModel > &inputModel, Size startIndex, Size endIndex)
const Matrix & varianceDerivative(Size i) const
const Matrix & volatilityDerivative(Size i) const
Real Time
continuous quantity with 1-year units
Definition: types.hpp:62
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
Real blackFormulaVolDerivative(Rate strike, Rate forward, Real stdDev, Real expiry, Real discount, Real displacement)
Real blackFormula(Option::Type optionType, Real strike, Real forward, Real stdDev, Real discount, Real displacement)