QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
basketgeneratingengine.cpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013, 2015 Peter Caspers
5
6 This file is part of QuantLib, a free-software/open-source library
7 for financial quantitative analysts and developers - http://quantlib.org/
8
9 QuantLib is free software: you can redistribute it and/or modify it
10 under the terms of the QuantLib license. You should have received a
11 copy of the license along with this program; if not, please email
12 <quantlib-dev@lists.sf.net>. The license is also available online at
13 <http://quantlib.org/license.shtml>.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
27#include <cmath>
28
29using std::exp;
30using std::fabs;
31
32namespace QuantLib {
33
34 std::vector<ext::shared_ptr<BlackCalibrationHelper>>
36 const ext::shared_ptr<Exercise>& exercise,
37 const ext::shared_ptr<SwapIndex>& standardSwapBase,
38 const ext::shared_ptr<SwaptionVolatilityStructure>& swaptionVolatility,
39 const CalibrationBasketType basketType) const {
40
42 !standardSwapBase->forwardingTermStructure().empty(),
43 "standard swap base forwarding term structure must not be empty.");
45 !standardSwapBase->exogenousDiscount() ||
46 !standardSwapBase->discountingTermStructure().empty(),
47 "standard swap base discounting term structure must not be empty.");
48
49 std::vector<ext::shared_ptr<BlackCalibrationHelper> > result;
50
52 Size minIdxAlive = static_cast<Size>(
53 std::upper_bound(exercise->dates().begin(), exercise->dates().end(),
54 today) -
55 exercise->dates().begin());
56
57 ext::shared_ptr<RebatedExercise> rebEx =
58 ext::dynamic_pointer_cast<RebatedExercise>(exercise);
59
60 for (Size i = minIdxAlive; i < exercise->dates().size(); i++) {
61
62 Date expiry = exercise->date(i);
63 Real rebate = 0.0;
64 Date rebateDate = expiry;
65 if (rebEx != nullptr) {
66 rebate = rebEx->rebate(i);
67 rebateDate = rebEx->rebatePaymentDate(i);
68 }
69
70 ext::shared_ptr<SwaptionHelper> helper;
71
72 switch (basketType) {
73
74 case Naive: {
75 Real swapLength = swaptionVolatility->dayCounter().yearFraction(
76 standardSwapBase->valueDate(expiry), underlyingLastDate());
77 ext::shared_ptr<SmileSection> sec =
78 swaptionVolatility->smileSection(
79 expiry,
80 static_cast<Size>(std::lround(swapLength * 12.0)) * Months,
81 true);
82 Real atmStrike = sec->atmLevel();
83 Real atmVol;
84 if (atmStrike == Null<Real>())
85 atmVol = sec->volatility(0.03);
86 else
87 atmVol = sec->volatility(atmStrike);
88 Real shift = sec->shift();
89
90 helper = ext::make_shared<SwaptionHelper>(
91 expiry, underlyingLastDate(),
92 Handle<Quote>(ext::make_shared<SimpleQuote>(atmVol)),
93 standardSwapBase->iborIndex(),
94 standardSwapBase->fixedLegTenor(),
95 standardSwapBase->dayCounter(),
96 standardSwapBase->iborIndex()->dayCounter(),
97 standardSwapBase->exogenousDiscount()
98 ? standardSwapBase->discountingTermStructure()
99 : standardSwapBase->forwardingTermStructure(),
101 swaptionVolatility->volatilityType() ,shift);
102
103 break;
104 }
105
107
108 // determine the npv, first and second order derivatives at
109 // $y=0$ of the underlying swap
110
111 const Real h = 0.0001; // finite difference step in $y$, make
112 // this a parameter of the engine ?
113 Real zSpreadDsc =
114 oas_.empty() ? Real(1.0)
115 : exp(-oas_->value() *
116 onefactormodel_->termStructure()
117 ->dayCounter()
118 .yearFraction(expiry, rebateDate));
119
120 Real npvm = underlyingNpv(expiry, -h) +
121 rebate *
122 onefactormodel_->zerobond(rebateDate, expiry,
123 -h, discountCurve_) *
124 zSpreadDsc;
125 Real npv = underlyingNpv(expiry, 0.0) +
126 rebate * onefactormodel_->zerobond(
127 rebateDate, expiry, 0, discountCurve_) *
128 zSpreadDsc;
129 Real npvp = underlyingNpv(expiry, h) +
130 rebate *
131 onefactormodel_->zerobond(rebateDate, expiry, h,
133 zSpreadDsc;
134
135 Real delta = (npvp - npvm) / (2.0 * h);
136 Real gamma = (npvp - 2.0 * npv + npvm) / (h * h);
137
138 QL_REQUIRE(npv * npv + delta * delta + gamma * gamma > 0.0,
139 "(npv,delta,gamma) must have a positive norm");
140
141 // debug output
142 // std::cout << "EXOTIC npv " << npv << " delta " << delta
143 // << " gamma " << gamma << std::endl;
144 // Real xtmp = -5.0;
145 // std::cout
146 // << "********************************************EXERCISE "
147 // << expiry << " ******************" << std::endl;
148 // std::cout << "globalExoticNpv;";
149 // while (xtmp <= 5.0 + QL_EPSILON) {
150 // std::cout << underlyingNpv(expiry, xtmp) << ";";
151 // xtmp += 0.1;
152 // }
153 // std::cout << std::endl;
154 // end debug output
155
156 // play safe, we restrict the maximum maturity so to easily fit
157 // in the date class restriction
158 Real maxMaturity =
159 swaptionVolatility->dayCounter().yearFraction(
160 expiry, Date::maxDate() - 365);
161
162 ext::shared_ptr<MatchHelper> matchHelper_;
163 matchHelper_ = ext::make_shared<MatchHelper>(
164 underlyingType(), npv, delta, gamma, *onefactormodel_,
165 standardSwapBase, expiry, maxMaturity, h);
166
167 // Optimize
168 Array initial = initialGuess(expiry);
169 QL_REQUIRE(initial.size() == 3,
170 "initial guess must have size 3 (but is "
171 << initial.size() << ")");
172
173 EndCriteria ec(1000, 200, 1E-8, 1E-8, 1E-8); // make these
174 // criteria and the
175 // optimizer itself
176 // parameters of
177 // the method ?
178 Constraint constraint = NoConstraint();
179 Problem p(*matchHelper_, constraint, initial);
181
182 EndCriteria::Type ret = lm.minimize(p, ec);
184 ret != EndCriteria::Unknown &&
186 "optimizer returns error (" << ret << ")");
187 Array solution = p.currentValue();
188
189 Real maturity = fabs(solution[1]);
190
191 Size years = (Size)std::floor(maturity);
192 maturity -= (Real)years;
193 maturity *= 12.0;
194 Size months = (Size)std::floor(maturity + 0.5);
195 if (years == 0 && months == 0)
196 months = 1; // ensure a maturity of at least one months
197 // maturity -= (Real)months; maturity *= 365.25;
198 // Size days = (Size)std::floor(maturity);
199
200 Period matPeriod =
201 years * Years + months * Months; //+days*Days;
202
203 ext::shared_ptr<SmileSection> sec =
204 swaptionVolatility->smileSection(expiry, matPeriod, true);
205 Real shift = sec->shift();
206
207 // we have to floor the strike of the calibration instrument,
208 // see warning in the header
209 solution[2] = std::max(
210 solution[2], 0.00001 - shift); // floor at 0.1bp - shift
211
212 // also the calibrated nominal may be zero, so we floor it, too
213 solution[0] =
214 std::max(solution[0], 0.000001); // float at 0.01bp
215
216 Real vol = sec->volatility(solution[2]);
217
218 helper = ext::make_shared<SwaptionHelper>(
219 expiry, matPeriod,
220 Handle<Quote>(ext::make_shared<SimpleQuote>(
221 vol)),
222 standardSwapBase->iborIndex(),
223 standardSwapBase->fixedLegTenor(),
224 standardSwapBase->dayCounter(),
225 standardSwapBase->iborIndex()->dayCounter(),
226 standardSwapBase->exogenousDiscount()
227 ? standardSwapBase->discountingTermStructure()
228 : standardSwapBase->forwardingTermStructure(),
230 fabs(solution[0]), swaptionVolatility->volatilityType(), shift);
231 break;
232 }
233
234 default:
235 QL_FAIL("Calibration basket type not known (" << basketType
236 << ")");
237 }
238
239 result.push_back(helper);
240 }
241
242 return result;
243 }
244}
base class for pricing engines capable of generating a calibration basket
1-D array used in linear algebra.
Definition: array.hpp:52
Size size() const
dimension of the array
Definition: array.hpp:495
const Handle< YieldTermStructure > discountCurve_
virtual Real underlyingNpv(const Date &expiry, Real y) const =0
std::vector< ext::shared_ptr< BlackCalibrationHelper > > calibrationBasket(const ext::shared_ptr< Exercise > &exercise, const ext::shared_ptr< SwapIndex > &standardSwapBase, const ext::shared_ptr< SwaptionVolatilityStructure > &swaptionVolatility, CalibrationBasketType basketType=MaturityStrikeByDeltaGamma) const
virtual const Date underlyingLastDate() const =0
virtual const Array initialGuess(const Date &expiry) const =0
const Handle< Gaussian1dModel > onefactormodel_
virtual Swap::Type underlyingType() const =0
Base constraint class.
Definition: constraint.hpp:35
Concrete date class.
Definition: date.hpp:125
static Date maxDate()
latest allowed date
Definition: date.cpp:771
Criteria to end optimization process:
Definition: endcriteria.hpp:40
Shared handle to an observable.
Definition: handle.hpp:41
Levenberg-Marquardt optimization method.
EndCriteria::Type minimize(Problem &P, const EndCriteria &endCriteria) override
minimize the optimization problem P
No constraint.
Definition: constraint.hpp:79
template class providing a null value for a given type.
Definition: null.hpp:76
Constrained optimization problem.
Definition: problem.hpp:42
const Array & currentValue() const
current value of the local minimum
Definition: problem.hpp:81
DateProxy & evaluationDate()
the date at which pricing is to be performed.
Definition: settings.hpp:147
static Settings & instance()
access to the unique instance
Definition: singleton.hpp:104
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
Levenberg-Marquardt optimization method.
Definition: any.hpp:35
Real months(const Period &p)
Definition: period.cpp:296
Real years(const Period &p)
Definition: period.cpp:279
Option exercise with rebate payments.
simple quote class
Simplex optimization method.
Swaption calibration helper.
Swaption volatility cube.