QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
capletcoterminalmaxhomogeneity.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4Copyright (C) 2007 Ferdinando Ametrano
5Copyright (C) 2007 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
27#include <ql/math/quadratic.hpp>
28
29namespace QuantLib {
30
31 namespace {
32
33 bool singleRateClosestPointFinder(
34 Size capletNumber,
35 const std::vector<Volatility>& homogeneousSolution,
36 const std::vector<Volatility>& previousRateSolution,
37 Real capletVariance,
38 const std::vector<Real>& correlations,
39 Real w0,
40 Real w1,
41 Real capletSwaptionPriority,
42 Size maxIterations,
43 Real tolerance,
44 std::vector<Volatility>& solution,
45 Real finalWeight,
46 Real& swaptionError,
47 Real& capletError)
48 {
49 if (capletNumber ==0) // there only is one point so to go through everything would be silly
50 {
51 Real previousSwapVariance = previousRateSolution[0] *previousRateSolution[0];
52 Real thisSwapVariance = homogeneousSolution[0] *homogeneousSolution[0]
53 + homogeneousSolution[1] *homogeneousSolution[1];
54 Real crossTerm = 2*w0*w1*correlations[0]*previousRateSolution[0];
55 Real constantTerm = w0*w0* previousSwapVariance - capletVariance;
56 Real theta = w1*w1;
57
58 quadratic q(theta,crossTerm, constantTerm);
59 Real volminus, volplus;
60 bool capSuccess = q.roots(volminus,volplus);
61 Real residual = thisSwapVariance - volminus*volminus;
62 bool swapSuccess = residual >=0;
63 bool success = capSuccess && swapSuccess;
64
65 if (success)
66 {
67 solution[0] = volminus;
68 solution[1] = std::sqrt(residual);
69 swaptionError= 0.0;
70 capletError =0.0;
71 return success;
72 }
73
74 bool prioritizeCaplet = capletSwaptionPriority <0.5;
75
76 if (capSuccess && prioritizeCaplet)
77 {
78 solution[0] = volminus;
79 solution[1] = 0; // residual is negative or we'd have totally succeeded
80 swaptionError = std::sqrt(thisSwapVariance)-volminus;
81 capletError =0.0;
82 return success;
83 }
84
85 if (capSuccess && !prioritizeCaplet)
86 {
87 solution[0] = std::sqrt(thisSwapVariance);
88 solution[1] = 0.0;
89 swaptionError=0.0;
90 capletError= std::sqrt(q(solution[0])+capletVariance) - std::sqrt(capletVariance);
91 return success;
92 }
93
94
95 // ok caplets have failed
96 if (swapSuccess)
97 {
98 solution[0] = volminus;
99 solution[1] = std::sqrt(residual);
100 swaptionError= 0.0;
101 capletError= std::sqrt(q(solution[0])+capletVariance) - std::sqrt(capletVariance);
102 return success;
103 }
104
105 // ok caplets have failed and swaps fail with optimal caplet solution
106
107 if (prioritizeCaplet)
108 {
109 solution[0] = volminus;
110 solution[1] = 0; // residual is negative or we'd have totally succeeded
111 swaptionError = std::sqrt(thisSwapVariance)-volminus;
112 capletError =0.0;
113
114 }
115 else
116 {
117 solution[0] = std::sqrt(thisSwapVariance);
118 solution[1] = 0.0;
119 swaptionError=0.0;
120 capletError= std::sqrt(q(solution[0])+capletVariance) - std::sqrt(capletVariance);
121
122
123 }
124
125
126 return success;
127 }
128
129 // first get in correct format
130 Real previousSwapVariance=0.0;
131 Real thisSwapVariance =0.0;
132 {
133 Size i=0;
134 for (; i<capletNumber+1; ++i) {
135 previousSwapVariance += previousRateSolution[i] *
136 previousRateSolution[i];
137 thisSwapVariance += homogeneousSolution[i] *
138 homogeneousSolution[i];
139 }
140 thisSwapVariance+= homogeneousSolution[i]*homogeneousSolution[i];
141 }
142
143 Real theta = w1*w1;
144 std::vector<Real> b(capletNumber+1);
145 Array cylinderCentre(capletNumber+1);
146 Array targetArray(capletNumber+2);
147 Array targetArrayRestricted(capletNumber+1);
148
149
150 Real bsq = 0.0;
151 for (Size i=0; i<capletNumber+1; ++i) {
152 b[i] = 2*w0*w1*correlations[i]*previousRateSolution[i]/theta;
153 cylinderCentre[i] = -0.5*b[i];
154 targetArray[i] = homogeneousSolution[i];
155 targetArrayRestricted[i] = targetArray[i];
156 bsq+=b[i]*b[i];
157 }
158 targetArray[capletNumber+1] = homogeneousSolution[capletNumber+1];
159
160 Real A = previousSwapVariance*w0*w0/theta;
161 Real constQuadraticTerm = A - 0.25*bsq;
162 Real S2 = capletVariance/theta - constQuadraticTerm;
163
164 // if S2 < 0, there are no solutions so we take the best we can.
165 Real S = S2 > 0 ? Real(std::sqrt(S2)) : 0;
166
167 Real R = std::sqrt(thisSwapVariance);
168
169 BasisIncompleteOrdered basis(capletNumber+1);
170 basis.addVector(cylinderCentre);
171 basis.addVector(targetArrayRestricted);
172 for (Size i=0; i<capletNumber+1; ++i) {
173 Array ei(capletNumber+1,0.0);
174 ei[i]=1.0;
175 basis.addVector(ei);
176 }
177
178 Matrix orthTransformationRestricted(basis.getBasisAsRowsInMatrix());
179 Matrix orthTransformation(capletNumber+2, capletNumber+2, 0.0);
180
181 orthTransformation[capletNumber+1][capletNumber+1]=1.0;
182 for (Size k=0; k<capletNumber+1; ++k)
183 for (Size l=0; l<capletNumber+1; ++l)
184 orthTransformation[k][l]=orthTransformationRestricted[k][l];
185
186 Array movedCentre = orthTransformationRestricted*cylinderCentre;
187 Real alpha = movedCentre[0];
188 Array movedTarget = orthTransformation*targetArray;
189
190 Real Z1=0.0, Z2=0.0, Z3=0.0;
191
192 SphereCylinderOptimizer optimizer(R, S, alpha, movedTarget[0], movedTarget[1],movedTarget[movedTarget.size()-1],finalWeight);
193
194 bool success = false;
195
196 if (!optimizer.isIntersectionNonEmpty())
197 {
198 Z1 = R*capletSwaptionPriority+(1-capletSwaptionPriority)*(alpha-S);
199 Z2 = 0.0;
200 Z3 = 0.0;
201 swaptionError =Z1-R;
202 capletError = (alpha-S)-Z1;
203 }
204 else
205 {
206 success = true;
207 capletError =0.0;
208 swaptionError =0.0;
209
210 if (maxIterations > 0.0)
211 {
212 optimizer.findClosest(maxIterations,
213 tolerance,
214 Z1,
215 Z2,
216 Z3);
217 }
218 else
219 optimizer.findByProjection(
220 Z1,
221 Z2,
222 Z3);
223 }
224
225 Array rotatedSolution(capletNumber+2,0.0);
226 rotatedSolution[0] = Z1;
227 rotatedSolution[1] = Z2;
228 rotatedSolution[capletNumber+1] = Z3;
229
230 Array arraySolution(transpose(orthTransformation) *
231 rotatedSolution);
232 {
233 Size i=0;
234 for (; i < arraySolution.size(); ++i)
235 solution[i]=arraySolution[i];
236 for (; i < solution.size(); ++i)
237 solution[i]=0.0;
238 }
239
240 return success;
241
242 }
243
244 }
245
247 const EvolutionDescription& evolution,
248 const ext::shared_ptr<PiecewiseConstantCorrelation>& corr,
249 const std::vector<ext::shared_ptr<
251 displacedSwapVariances,
252 const std::vector<Volatility>& mktCapletVols,
253 const ext::shared_ptr<CurveState>& cs,
254 Spread displacement,
255 Real caplet0Swaption1Priority)
256 : CTSMMCapletCalibration(evolution, corr, displacedSwapVariances,
257 mktCapletVols, cs, displacement),
258 caplet0Swaption1Priority_(caplet0Swaption1Priority) {
259
260 QL_REQUIRE(caplet0Swaption1Priority>=0.0 &&
261 caplet0Swaption1Priority<=1.0,
262 "caplet0Swaption1Priority (" << caplet0Swaption1Priority <<
263 ") must be in [0.0, 1.0]");
264 }
265
266 // the actual calibration function, this is a static class member
268 const EvolutionDescription& evolution,
270 const std::vector<ext::shared_ptr<
271 PiecewiseConstantVariance> >& displacedSwapVariances,
272 const std::vector<Volatility>& capletVols,
273 const CurveState& cs,
274 const Spread displacement,
275 Real caplet0Swaption1Priority,
276 const Size numberOfFactors,
277 Size maxIterations,
278 Real tolerance,
279 Real& deformationSize, // ret value
280 Real& totalSwaptionError, // ret value
281 std::vector<Matrix>& swapCovariancePseudoRoots)
282 {
283
285 displacedSwapVariances, capletVols, cs);
286
287 Size numberOfSteps = evolution.numberOfSteps();
288 Size numberOfRates = evolution.numberOfRates();
289 const std::vector<Time>& rateTimes = evolution.rateTimes();
290
291 QL_REQUIRE(numberOfFactors<=numberOfRates,
292 "number of factors (" << numberOfFactors <<
293 ") cannot be greater than numberOfRates (" <<
294 numberOfRates << ")");
295 QL_REQUIRE(numberOfFactors>0,
296 "number of factors (" << numberOfFactors <<
297 ") must be greater than zero");
298
299
301
302 totalSwaptionError = 0.0;
303 deformationSize = 0.0;
304
305 // factor reduction
306 std::vector<Matrix> corrPseudo(corr.times().size());
307 for (Size i=0; i<corrPseudo.size(); ++i)
308 corrPseudo[i] = rankReducedSqrt(corr.correlation(i),
309 numberOfFactors, 1.0,
311
312 // get Zinverse, we can get wj later
313 Matrix zedMatrix =
315 Matrix invertedZedMatrix = inverse(zedMatrix);
316
317 // vectors for the new vol of all swap rates
318 std::vector<std::vector<Volatility> > newVols;
319 std::vector<Volatility> theseNewVols(numberOfRates);
320 std::vector<Volatility> firstRateVols(numberOfRates);
321 firstRateVols[0] = std::sqrt(displacedSwapVariances[0]->variances()[0]);
322 std::vector<Volatility> secondRateVols(numberOfRates);
323 std::vector<Real> correlations(numberOfRates);
324 newVols.push_back(firstRateVols);
325
326 // final caplet and swaption are the same, so we skip that case
327 for (Size i=0; i<numberOfRates-1; ++i)
328 {
329 // final weight dont do anything when i < 2
330 Real thisFinalWeight = i > 1 ? (i-1)/2.0 : 1.0;
331 // we will calibrate caplet on forward rate i,
332 // we will do this by modifying the vol of swap rate i+1
333 const std::vector<Real>& var =
334 displacedSwapVariances[i+1]->variances();
335
336 for (Size j =0; j < i+2; ++j)
337 secondRateVols[j] = std::sqrt(var[j]);
338
339 for (Size k=0; k < i+1; k++) {
340 Real correlation=0.0;
341 for (Size l=0; l < numberOfFactors; ++l) {
342 Real term1 = corrPseudo[k][i][l];
343 Real term2 = corrPseudo[k][i+1][l];
344 correlation += term1*term2;
345 }
346 correlations[k] = correlation;
347 }
348
349 Real w0 = invertedZedMatrix[i][i];
350 Real w1 = invertedZedMatrix[i][i+1];
351 // w0 adjustment
352 for (Size k = i+2; k <invertedZedMatrix.columns(); ++k)
353 w0+= invertedZedMatrix[i][k];
354
355 Real targetCapletVariance= capletVols[i]*capletVols[i]*rateTimes[i];
356
357 Real thisCapletError;
358 Real thisSwaptionError;
359
360 bool success = singleRateClosestPointFinder(
361 i, secondRateVols, firstRateVols, targetCapletVariance, correlations,
362 w0, w1, caplet0Swaption1Priority,maxIterations, tolerance,
363 theseNewVols, thisFinalWeight ,thisSwaptionError, thisCapletError);
364
365 totalSwaptionError+= thisSwaptionError*thisSwaptionError;
366
367 if (!success)
368 ++failures;
369
370 for (Size j=0; j < i+2; ++j)
371 deformationSize += (theseNewVols[i]-secondRateVols[i])*(theseNewVols[i]-secondRateVols[i]);
372
373 newVols.push_back(theseNewVols);
374 firstRateVols = theseNewVols;
375 }
376
377 swapCovariancePseudoRoots.resize(numberOfSteps);
378 for (Size k=0; k<numberOfSteps; ++k) {
379 swapCovariancePseudoRoots[k] = corrPseudo[k];
380 for (Size j=0; j<numberOfRates; ++j) {
381 Real coeff =newVols[j][k];
382 for (Size i=0; i<numberOfFactors; ++i)
383 swapCovariancePseudoRoots[k][j][i]*=coeff;
384 }
385 QL_ENSURE(swapCovariancePseudoRoots[k].rows()==numberOfRates,
386 "step " << k << " abcd vol wrong number of rows: " <<
387 swapCovariancePseudoRoots[k].rows() <<
388 " instead of " << numberOfRates);
389 QL_ENSURE(swapCovariancePseudoRoots[k].columns()==numberOfFactors,
390 "step " << k << " abcd vol wrong number of columns: " <<
391 swapCovariancePseudoRoots[k].columns() <<
392 " instead of " << numberOfFactors);
393 }
394
395 return failures;
396 }
397
399 Natural numberOfFactors,
400 Natural maxIterations,
401 Real tolerance) {
402
404 *corr_,
406 // not mktCapletVols_ but...
408 *cs_,
410
412
413 numberOfFactors,
414 maxIterations,
415 tolerance,
416
419
421 }
422
423}
ext::shared_ptr< PiecewiseConstantCorrelation > corr_
ext::shared_ptr< CurveState > cs_
static void performChecks(const EvolutionDescription &evolution, const PiecewiseConstantCorrelation &corr, const std::vector< ext::shared_ptr< PiecewiseConstantVariance > > &displacedSwapVariances, const std::vector< Volatility > &mktCapletVols, const CurveState &cs)
std::vector< ext::shared_ptr< PiecewiseConstantVariance > > displacedSwapVariances_
std::vector< Volatility > usedCapletVols_
std::vector< Matrix > swapCovariancePseudoRoots_
CTSMMCapletMaxHomogeneityCalibration(const EvolutionDescription &evolution, const ext::shared_ptr< PiecewiseConstantCorrelation > &corr, const std::vector< ext::shared_ptr< PiecewiseConstantVariance > > &displacedSwapVariances, const std::vector< Volatility > &capletVols, const ext::shared_ptr< CurveState > &cs, Spread displacement, Real caplet0Swaption1Priority=1.0)
static Natural capletMaxHomogeneityCalibration(const EvolutionDescription &evolution, const PiecewiseConstantCorrelation &corr, const std::vector< ext::shared_ptr< PiecewiseConstantVariance > > &displacedSwapVariances, const std::vector< Volatility > &capletVols, const CurveState &cs, Spread displacement, Real caplet0Swaption1Priority, Size numberOfFactors, Size maxIterations, Real tolerance, Real &deformationSize, Real &totalSwaptionError, std::vector< Matrix > &swapCovariancePseudoRoots)
Natural calibrationImpl_(Natural numberOfFactors, Natural maxIterations, Real tolerance) override
Curve state for market-model simulations
Definition: curvestate.hpp:41
Market-model evolution description.
const std::vector< Time > & rateTimes() const
Matrix used in linear algebra.
Definition: matrix.hpp:41
Size columns() const
Definition: matrix.hpp:508
virtual const Matrix & correlation(Size i) const
virtual const std::vector< Time > & times() const =0
static Matrix coterminalSwapZedMatrix(const CurveState &cs, Spread displacement)
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
Definition: errors.hpp:130
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
ext::function< Real(Real)> b
QL_REAL Real
real number
Definition: types.hpp:50
unsigned QL_INTEGER Natural
positive integer
Definition: types.hpp:43
Real Spread
spreads on interest rates
Definition: types.hpp:74
std::size_t Size
size of a container
Definition: types.hpp:58
Real theta
Definition: any.hpp:35
Matrix rankReducedSqrt(const Matrix &matrix, Size maxRank, Real componentRetainedPercentage, SalvagingAlgorithm::Type sa)
Definition: pseudosqrt.cpp:427
Matrix transpose(const Matrix &m)
Definition: matrix.hpp:700
Matrix inverse(const Matrix &m)
Definition: matrix.cpp:44
ext::shared_ptr< YieldTermStructure > q
pseudo square root of a real symmetric matrix
quadratic formula
Real alpha
Definition: sabr.cpp:200
Find closest point of the intersection of a sphere and cylinder to a given point.
Utility functions for mapping between swap rate and forward rate.