/src/quantlib/ql/pricingengines/swaption/basketgeneratingengine.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2013 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 | | |
20 | | /*! \file basketgeneratingengine.hpp |
21 | | \brief base class for pricing engines capable of |
22 | | generating a calibration basket |
23 | | */ |
24 | | |
25 | | #ifndef quantlib_basketgeneratingengine_hpp |
26 | | #define quantlib_basketgeneratingengine_hpp |
27 | | |
28 | | #include <ql/cashflows/fixedratecoupon.hpp> |
29 | | #include <ql/cashflows/iborcoupon.hpp> |
30 | | #include <ql/indexes/swapindex.hpp> |
31 | | #include <ql/instruments/vanillaswap.hpp> |
32 | | #include <ql/math/optimization/costfunction.hpp> |
33 | | #include <ql/models/shortrate/onefactormodels/gaussian1dmodel.hpp> |
34 | | #include <ql/qldefines.hpp> |
35 | | #include <ql/termstructures/volatility/swaption/swaptionvolstructure.hpp> |
36 | | #include <ql/termstructures/yieldtermstructure.hpp> |
37 | | #include <utility> |
38 | | |
39 | | namespace QuantLib { |
40 | | |
41 | | /* \warning the generated calibrating swaptions have a strike floored at |
42 | | 0.1bp (minus lognormal shift, if applicable), this is not true for atm |
43 | | swaptions where the strike is generated in the swaption helper. |
44 | | |
45 | | \warning the standardSwapBase index should have associated forward and |
46 | | discount curves. These curves are used for setup of the swaption helper. |
47 | | This means that the market price of the calibration instrument is calculated |
48 | | using these curves. Therefore the model price must be calculated using the |
49 | | same curves, otherwise the calibration gets incosistent, i.e. the pricing |
50 | | engine used for model calibration has to be capable of using the same curves |
51 | | as associated to the index. Also the volatility structure passed to construct |
52 | | the calibration helper should use curves that are consistent with the model |
53 | | calibration curve setup. Finally the discountCurve given in the constructor |
54 | | should be the same curve as the discounting curve of the swapIndex used to |
55 | | determine the calibration basket. */ |
56 | | |
57 | | class BasketGeneratingEngine { |
58 | | |
59 | | public: |
60 | | |
61 | | typedef enum CalibrationBasketType { |
62 | | Naive, |
63 | | MaturityStrikeByDeltaGamma |
64 | | } CalibrationBasketType; |
65 | | |
66 | 0 | virtual ~BasketGeneratingEngine() = default; |
67 | | |
68 | | std::vector<ext::shared_ptr<BlackCalibrationHelper>> |
69 | | calibrationBasket(const ext::shared_ptr<Exercise>& exercise, |
70 | | const ext::shared_ptr<SwapIndex>& standardSwapBase, |
71 | | const ext::shared_ptr<SwaptionVolatilityStructure>& swaptionVolatility, |
72 | | CalibrationBasketType basketType = MaturityStrikeByDeltaGamma) const; |
73 | | |
74 | | protected: |
75 | | BasketGeneratingEngine(const ext::shared_ptr<Gaussian1dModel>& model, |
76 | | Handle<Quote> oas, |
77 | | Handle<YieldTermStructure> discountCurve) |
78 | 0 | : onefactormodel_(model), oas_(std::move(oas)), discountCurve_(std::move(discountCurve)) {} |
79 | | |
80 | | BasketGeneratingEngine(Handle<Gaussian1dModel> model, |
81 | | Handle<Quote> oas, |
82 | | Handle<YieldTermStructure> discountCurve) |
83 | | : onefactormodel_(std::move(model)), oas_(std::move(oas)), |
84 | 0 | discountCurve_(std::move(discountCurve)) {} |
85 | | |
86 | | virtual Real underlyingNpv(const Date& expiry, Real y) const = 0; |
87 | | |
88 | | virtual Swap::Type underlyingType() const = 0; |
89 | | |
90 | | virtual const Date underlyingLastDate() const = 0; |
91 | | |
92 | | virtual const Array initialGuess(const Date &expiry) const = 0; // return (nominal, |
93 | | // maturity, rate) |
94 | | |
95 | | private: |
96 | | |
97 | | const Handle<Gaussian1dModel> onefactormodel_; |
98 | | const Handle<Quote> oas_; |
99 | | const Handle<YieldTermStructure> discountCurve_; |
100 | | |
101 | | class MatchHelper : public CostFunction { |
102 | | public: |
103 | | MatchHelper(const Swap::Type type, |
104 | | const Real npv, |
105 | | const Real delta, |
106 | | const Real gamma, |
107 | | ext::shared_ptr<Gaussian1dModel> model, |
108 | | ext::shared_ptr<SwapIndex> indexBase, |
109 | | const Date& expiry, |
110 | | const Real maxMaturity, |
111 | | const Real h) |
112 | 0 | : type_(type), mdl_(std::move(model)), indexBase_(std::move(indexBase)), |
113 | 0 | expiry_(expiry), maxMaturity_(maxMaturity), npv_(npv), delta_(delta), gamma_(gamma), |
114 | 0 | h_(h) {} |
115 | | |
116 | | Real NPV(const ext::shared_ptr<VanillaSwap>& swap, |
117 | | Real fixedRate, |
118 | | Real nominal, |
119 | | Real y, |
120 | 0 | int type) const { |
121 | 0 | Real npv = 0.0; |
122 | 0 | for (const auto& i : swap->fixedLeg()) { |
123 | 0 | ext::shared_ptr<FixedRateCoupon> c = |
124 | 0 | ext::dynamic_pointer_cast<FixedRateCoupon>(i); |
125 | 0 | npv -= |
126 | 0 | fixedRate * c->accrualPeriod() * nominal * |
127 | 0 | mdl_->zerobond(c->date(), expiry_, y, |
128 | 0 | indexBase_->discountingTermStructure()); |
129 | 0 | } |
130 | 0 | for (const auto& i : swap->floatingLeg()) { |
131 | 0 | ext::shared_ptr<IborCoupon> c = ext::dynamic_pointer_cast<IborCoupon>(i); |
132 | 0 | npv += |
133 | 0 | mdl_->forwardRate(c->fixingDate(), expiry_, y, |
134 | 0 | c->iborIndex()) * |
135 | 0 | c->accrualPeriod() * nominal * |
136 | 0 | mdl_->zerobond(c->date(), expiry_, y, |
137 | 0 | indexBase_->discountingTermStructure()); |
138 | 0 | } |
139 | 0 | return (Real)type * npv; |
140 | 0 | } |
141 | | |
142 | 0 | Real value(const Array& v) const override { |
143 | 0 | Array vals = values(v); |
144 | 0 | Real res = 0.0; |
145 | 0 | for (Real val : vals) { |
146 | 0 | res += val * val; |
147 | 0 | } |
148 | 0 | return std::sqrt(res / vals.size()); |
149 | 0 | } |
150 | | |
151 | 0 | Array values(const Array& v) const override { |
152 | | // transformations |
153 | 0 | int type = type_; // start with same type as non standard |
154 | | // underlying (1 means payer, -1 receiver) |
155 | 0 | Real nominal = std::fabs(v[0]); |
156 | 0 | if (v[0] < 0.0) |
157 | 0 | type *= -1; |
158 | 0 | Real maturity = std::min(std::fabs(v[1]), maxMaturity_); |
159 | |
|
160 | 0 | Real fixedRate = v[2]; // allow for negative rates explicitly |
161 | | // (though it might not be reasonable for calibration depending |
162 | | // on the model to calibrate and the market instrument quotation) |
163 | 0 | Size years = (Size)std::floor(maturity); |
164 | 0 | maturity -= (Real)years; |
165 | 0 | maturity *= 12.0; |
166 | 0 | Size months = (Size)std::floor(maturity); |
167 | 0 | Real alpha = 1.0 - (maturity - (Real)months); |
168 | 0 | if (years == 0 && months == 0) { |
169 | 0 | months = 1; // ensure a maturity of at least one month ... |
170 | 0 | alpha = 1.0; // ... but in this case only look at the lower |
171 | | // maturity swap |
172 | 0 | } |
173 | | // maturity -= (Real)months; maturity *= 365.25; |
174 | | // Size days = (Size)std::floor(maturity); |
175 | | // Real alpha = 1.0-(maturity-(Real)days); |
176 | | // generate swap |
177 | 0 | Period lowerPeriod = |
178 | 0 | years * Years + months * Months; //+days*Days; |
179 | 0 | Period upperPeriod = lowerPeriod + 1 * Months; // 1*Days; |
180 | 0 | ext::shared_ptr<SwapIndex> tmpIndexLower, tmpIndexUpper; |
181 | 0 | tmpIndexLower = indexBase_->clone(lowerPeriod); |
182 | 0 | tmpIndexUpper = indexBase_->clone(upperPeriod); |
183 | 0 | ext::shared_ptr<VanillaSwap> swapLower = |
184 | 0 | tmpIndexLower->underlyingSwap(expiry_); |
185 | 0 | ext::shared_ptr<VanillaSwap> swapUpper = |
186 | 0 | tmpIndexUpper->underlyingSwap(expiry_); |
187 | | // compute npv, delta, gamma |
188 | 0 | Real npvm = |
189 | 0 | alpha * NPV(swapLower, fixedRate, nominal, -h_, type) + |
190 | 0 | (1.0 - alpha) * |
191 | 0 | NPV(swapUpper, fixedRate, nominal, -h_, type); |
192 | 0 | Real npv = |
193 | 0 | alpha * NPV(swapLower, fixedRate, nominal, 0.0, type) + |
194 | 0 | (1.0 - alpha) * |
195 | 0 | NPV(swapUpper, fixedRate, nominal, 0.0, type); |
196 | 0 | Real npvu = |
197 | 0 | alpha * NPV(swapLower, fixedRate, nominal, h_, type) + |
198 | 0 | (1.0 - alpha) * |
199 | 0 | NPV(swapUpper, fixedRate, nominal, h_, type); |
200 | 0 | Real delta = (npvu - npvm) / (2.0 * h_); |
201 | 0 | Real gamma = (npvu - 2.0 * npv + npvm) / (h_ * h_); |
202 | | |
203 | | // debug output global standard underlying npv |
204 | | // Real xtmp = -5.0; |
205 | | // std::cout << "globalStandardNpv;"; |
206 | | // while (xtmp <= 5.0 + QL_EPSILON) { |
207 | | // std::cout << alpha *NPV(swapLower, fixedRate, nominal, xtmp, |
208 | | // type) + |
209 | | // (1.0 - alpha) * NPV(swapUpper, fixedRate, |
210 | | // nominal, xtmp, type) |
211 | | // << ";"; |
212 | | // xtmp += 0.1; |
213 | | // } |
214 | | // std::cout << std::endl; |
215 | | // end debug output |
216 | | |
217 | | // return target function values |
218 | 0 | Array res(3); |
219 | 0 | res[0] = (npv - npv_) / delta_; |
220 | 0 | res[1] = (delta - delta_) / delta_; |
221 | 0 | res[2] = (gamma - gamma_) / gamma_; |
222 | 0 | return res; |
223 | 0 | } |
224 | | |
225 | | const Swap::Type type_; |
226 | | const ext::shared_ptr<Gaussian1dModel> mdl_; |
227 | | const ext::shared_ptr<SwapIndex> indexBase_; |
228 | | const Date expiry_; |
229 | | const Real maxMaturity_; |
230 | | const Real npv_, delta_, gamma_, h_; |
231 | | }; |
232 | | }; |
233 | | } |
234 | | |
235 | | #endif |