1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2007 Ferdinando Ametrano
5  Copyright (C) 2007 Mark Joshi
6 
7  This file is part of QuantLib, a free-software/open-source library
8  for financial quantitative analysts and developers - http://quantlib.org/
9 
10  QuantLib is free software: you can redistribute it and/or modify it
11  under the terms of the QuantLib license.  You should have received a
12  copy 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 
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the license for more details.
19 */
20 
21 #include <ql/models/marketmodels/models/ctsmmcapletcalibration.hpp>
22 #include <ql/models/marketmodels/models/piecewiseconstantvariance.hpp>
23 #include <ql/models/marketmodels/models/pseudorootfacade.hpp>
24 #include <ql/models/marketmodels/models/cotswaptofwdadapter.hpp>
25 #include <ql/models/marketmodels/swapforwardmappings.hpp>
26 #include <ql/models/marketmodels/marketmodel.hpp>
27 #include <ql/math/matrixutilities/pseudosqrt.hpp>
28 #include <ql/math/comparison.hpp>
29 #include <ql/utilities/dataformatters.hpp>
30 
31 namespace QuantLib {
32 
~CTSMMCapletCalibration()33     CTSMMCapletCalibration::~CTSMMCapletCalibration() {}
34 
CTSMMCapletCalibration(const EvolutionDescription & evolution,const ext::shared_ptr<PiecewiseConstantCorrelation> & corr,const std::vector<ext::shared_ptr<PiecewiseConstantVariance>> & displacedSwapVariances,const std::vector<Volatility> & mktCapletVols,const ext::shared_ptr<CurveState> & cs,Spread displacement)35     CTSMMCapletCalibration::CTSMMCapletCalibration(
36                             const EvolutionDescription& evolution,
37                             const ext::shared_ptr<PiecewiseConstantCorrelation>& corr,
38                             const std::vector<ext::shared_ptr<
39                                         PiecewiseConstantVariance> >&
40                                                 displacedSwapVariances,
41                             const std::vector<Volatility>& mktCapletVols,
42                             const ext::shared_ptr<CurveState>& cs,
43                             Spread displacement)
44     : evolution_(evolution),  corr_(corr),
45       displacedSwapVariances_(displacedSwapVariances),
46       mktCapletVols_(mktCapletVols),
47       mdlCapletVols_(evolution_.numberOfRates()),
48       mktSwaptionVols_(evolution_.numberOfRates()),
49       mdlSwaptionVols_(evolution_.numberOfRates()),
50       cs_(cs), displacement_(displacement),
51       numberOfRates_(evolution_.numberOfRates())
52     {
53         performChecks(evolution_, *corr_, displacedSwapVariances_,
54                       mktCapletVols_, *cs_);
55 
56 
57 
58     }
59 
60     const std::vector<Volatility>&
timeDependentUnCalibratedSwaptionVols(Size i) const61     CTSMMCapletCalibration::timeDependentUnCalibratedSwaptionVols(Size i) const
62     {
63         QL_REQUIRE(i<numberOfRates_,
64                    "index (" << i << ") must less than number of rates (" <<
65                    numberOfRates_ << ")");
66         return displacedSwapVariances_[i]->volatilities();
67     }
68 
69     const std::vector<Volatility>&
timeDependentCalibratedSwaptionVols(Size i) const70     CTSMMCapletCalibration::timeDependentCalibratedSwaptionVols(Size i) const
71     {
72         QL_REQUIRE(i<numberOfRates_,
73                    "index (" << i << ") must less than number of rates (" <<
74                    numberOfRates_ << ")");
75         return timeDependentCalibratedSwaptionVols_[i];
76     }
77 
performChecks(const EvolutionDescription & evolution,const PiecewiseConstantCorrelation & corr,const std::vector<ext::shared_ptr<PiecewiseConstantVariance>> & displacedSwapVariances,const std::vector<Volatility> & mktCapletVols,const CurveState & cs)78     void CTSMMCapletCalibration::performChecks(
79                     const EvolutionDescription& evolution,
80                     const PiecewiseConstantCorrelation&  corr,
81                     const std::vector<ext::shared_ptr<
82                                 PiecewiseConstantVariance> >&
83                                             displacedSwapVariances,
84                     const std::vector<Volatility>& mktCapletVols,
85                     const CurveState& cs)
86     {
87         const std::vector<Time>& evolutionTimes = evolution.evolutionTimes();
88         QL_REQUIRE(evolutionTimes==corr.times(),
89                    "evolutionTimes "
90                    << io::sequence(evolutionTimes)
91                    << " not equal to correlation times "
92                    << io::sequence(corr.times()));
93 
94         const std::vector<Time>& rateTimes = evolution.rateTimes();
95         QL_REQUIRE(rateTimes==cs.rateTimes(),
96                    "mismatch between EvolutionDescription and "
97                    "CurveState rate times");
98 
99         Size numberOfRates = evolution.numberOfRates();
100         QL_REQUIRE(numberOfRates==displacedSwapVariances.size(),
101                    "mismatch between EvolutionDescription number of rates ("
102                    << numberOfRates << ") and displacedSwapVariances size ("
103                    << displacedSwapVariances.size() << ")");
104         QL_REQUIRE(numberOfRates==corr.numberOfRates(),
105                    "mismatch between EvolutionDescription number of rates ("
106                    << numberOfRates << ") and corr number of rates ("
107                    << corr.numberOfRates() << ")");
108         QL_REQUIRE(numberOfRates==mktCapletVols.size(),
109                    "mismatch between EvolutionDescription number of rates ("
110                    << numberOfRates << ") and mktCapletVols size ("
111                    << mktCapletVols.size() << ")");
112         QL_REQUIRE(numberOfRates==cs.numberOfRates(),
113                    "mismatch between EvolutionDescription number of rates ("
114                    << numberOfRates << ") and CurveState  number of rates ("
115                    << cs.numberOfRates() << ")");
116 
117         std::vector<Time> temp(rateTimes.begin(), rateTimes.end()-1);
118         QL_REQUIRE(temp==evolutionTimes,
119                    "mismatch between evolutionTimes and rateTimes");
120 
121         Volatility lastSwaptionVol =
122             displacedSwapVariances.back()->totalVolatility(numberOfRates-1);
123         QL_REQUIRE(close(lastSwaptionVol, mktCapletVols[numberOfRates-1]),
124                    "last caplet vol (" << std::setprecision(16) <<
125                    mktCapletVols[numberOfRates-1] <<
126                    ") must be equal to last swaption vol (" <<
127                    lastSwaptionVol << "); discrepancy is " <<
128                    lastSwaptionVol-mktCapletVols[numberOfRates-1]);
129     }
130 
calibrate(Natural numberOfFactors,Natural maxIterations,Real capletVolTolerance,Natural innerSolvingMaxIterations,Real innerSolvingTolerance)131     bool CTSMMCapletCalibration::calibrate(Natural numberOfFactors,
132 
133                                            Natural maxIterations,
134                                            Real capletVolTolerance,
135 
136                                            Natural innerSolvingMaxIterations,
137                                            Real innerSolvingTolerance) {
138         // initialize results
139         calibrated_ = false;
140         failures_ = 987654321; // a positive large number
141         deformationSize_ = 987654321;
142         capletRmsError_ = swaptionRmsError_ = 987654321;
143         capletMaxError_ = swaptionMaxError_ = 987654321;
144 
145         // initialize working variables
146         usedCapletVols_ = mktCapletVols_;
147 
148         for (Size i=0; i<numberOfRates_; ++i)
149             mktSwaptionVols_[i]=displacedSwapVariances_[i]->totalVolatility(i);
150 
151         std::vector<Spread> displacements(numberOfRates_,
152                                           displacement_);
153         const std::vector<Time>& rateTimes = evolution_.rateTimes();
154         Natural iterations = 0;
155 
156         // calibration loop
157         do {
158             failures_ = calibrationImpl_(numberOfFactors,
159                                          innerSolvingMaxIterations,
160                                          innerSolvingTolerance);
161 
162             ext::shared_ptr<MarketModel> ctsmm(new
163                 PseudoRootFacade(swapCovariancePseudoRoots_,
164                                  rateTimes,
165                                  cs_->coterminalSwapRates(),
166                                  displacements));
167             const Matrix& swaptionTotCovariance =
168                 ctsmm->totalCovariance(numberOfRates_-1);
169 
170             CotSwapToFwdAdapter flmm(ctsmm);
171             const Matrix& capletTotCovariance =
172                 flmm.totalCovariance(numberOfRates_-1);
173 
174             // check fit
175             capletRmsError_ = swaptionRmsError_ = 0.0;
176             capletMaxError_ = swaptionMaxError_ = -1.0;
177 
178             for (Size i=0; i<numberOfRates_; ++i) {
179                 mdlSwaptionVols_[i] = std::sqrt(swaptionTotCovariance[i][i]/rateTimes[i]);
180                 Real swaptionError = std::fabs(mktSwaptionVols_[i]-mdlSwaptionVols_[i]);
181                 swaptionRmsError_ += swaptionError*swaptionError;
182                 swaptionMaxError_ = std::max(swaptionMaxError_, swaptionError);
183 
184                 mdlCapletVols_[i] = std::sqrt(capletTotCovariance[i][i]/rateTimes[i]);
185                 Real capletError = std::fabs(mktCapletVols_[i]-mdlCapletVols_[i]);
186                 capletRmsError_ += capletError*capletError;
187                 capletMaxError_ = std::max(capletMaxError_, capletError);
188 
189                 if (i < numberOfRates_-1)
190                     usedCapletVols_[i] *= mktCapletVols_[i]/mdlCapletVols_[i];
191             }
192             swaptionRmsError_ = std::sqrt(swaptionRmsError_/numberOfRates_);
193             capletRmsError_ = std::sqrt(capletRmsError_/numberOfRates_);
194             ++iterations;
195         } while (iterations<maxIterations &&
196                  capletRmsError_>capletVolTolerance);
197 
198          ext::shared_ptr<MarketModel> ctsmm(new
199                 PseudoRootFacade(swapCovariancePseudoRoots_,
200                                  rateTimes,
201                                  cs_->coterminalSwapRates(),
202                                  displacements));
203 
204          timeDependentCalibratedSwaptionVols_.clear();
205          for (Size i=0; i<numberOfRates_; ++i)
206              timeDependentCalibratedSwaptionVols_.push_back(
207                 ctsmm->timeDependentVolatility(i));
208 
209         // calculate deformationSize_ ??
210         calibrated_ = true;
211         return failures_==0;
212     }
213 
214 }
215