/src/quantlib/ql/cashflows/conundrumpricer.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | Copyright (C) 2006 Giorgio Facchinetti |
3 | | Copyright (C) 2006 Mario Pucci |
4 | | Copyright (C) 2023 Andre Miemiec |
5 | | |
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 | | |
17 | | This program is distributed in the hope that it will be useful, but |
18 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
19 | | or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ |
20 | | |
21 | | /*! \file conundrumpricer.hpp |
22 | | \brief CMS-coupon pricer |
23 | | */ |
24 | | |
25 | | #ifndef quantlib_conundrum_pricer_hpp |
26 | | #define quantlib_conundrum_pricer_hpp |
27 | | |
28 | | #include <ql/cashflows/couponpricer.hpp> |
29 | | #include <ql/instruments/payoffs.hpp> |
30 | | |
31 | | namespace QuantLib { |
32 | | |
33 | | class CmsCoupon; |
34 | | class YieldTermStructure; |
35 | | class Quote; |
36 | | |
37 | | class VanillaOptionPricer { |
38 | | public: |
39 | 0 | virtual ~VanillaOptionPricer() = default; |
40 | | virtual Real operator()(Real strike, |
41 | | Option::Type optionType, |
42 | | Real deflator) const = 0; |
43 | | }; |
44 | | |
45 | | class MarketQuotedOptionPricer : public VanillaOptionPricer { |
46 | | public: |
47 | | MarketQuotedOptionPricer( |
48 | | Rate forwardValue, |
49 | | Date expiryDate, |
50 | | const Period& swapTenor, |
51 | | const ext::shared_ptr<SwaptionVolatilityStructure>& |
52 | | volatilityStructure); |
53 | | |
54 | | Real operator()(Real strike, Option::Type optionType, Real deflator) const override; |
55 | | |
56 | | private: |
57 | | Rate forwardValue_; |
58 | | Date expiryDate_; |
59 | | Period swapTenor_; |
60 | | ext::shared_ptr<SwaptionVolatilityStructure> volatilityStructure_; |
61 | | ext::shared_ptr<SmileSection> smile_; |
62 | | }; |
63 | | |
64 | | class GFunction { |
65 | | public: |
66 | 0 | virtual ~GFunction() = default; |
67 | | virtual Real operator()(Real x) = 0; |
68 | | virtual Real firstDerivative(Real x) = 0; |
69 | | virtual Real secondDerivative(Real x) = 0; |
70 | | }; |
71 | | |
72 | | class GFunctionFactory { |
73 | | public: |
74 | | enum YieldCurveModel { Standard, |
75 | | ExactYield, |
76 | | ParallelShifts, |
77 | | NonParallelShifts |
78 | | }; |
79 | | |
80 | | GFunctionFactory() = delete; |
81 | | |
82 | | static ext::shared_ptr<GFunction> |
83 | | newGFunctionStandard(Size q, |
84 | | Real delta, |
85 | | Size swapLength); |
86 | | static ext::shared_ptr<GFunction> |
87 | | newGFunctionExactYield(const CmsCoupon& coupon); |
88 | | static ext::shared_ptr<GFunction> |
89 | | newGFunctionWithShifts(const CmsCoupon& coupon, |
90 | | const Handle<Quote>& meanReversion); |
91 | | private: |
92 | | class GFunctionStandard : public GFunction { |
93 | | public: |
94 | | GFunctionStandard(Size q, |
95 | | Real delta, |
96 | | Size swapLength) |
97 | 0 | : q_(q), delta_(delta), swapLength_(swapLength) {} |
98 | | Real operator()(Real x) override; |
99 | | Real firstDerivative(Real x) override; |
100 | | Real secondDerivative(Real x) override; |
101 | | |
102 | | protected: |
103 | | /* number of period per year */ |
104 | | const int q_; |
105 | | /* fraction of a period between the swap start date and |
106 | | the pay date */ |
107 | | Real delta_; |
108 | | /* length of swap*/ |
109 | | Size swapLength_; |
110 | | }; |
111 | | |
112 | | class GFunctionExactYield : public GFunction { |
113 | | public: |
114 | | GFunctionExactYield(const CmsCoupon& coupon); |
115 | | Real operator()(Real x) override; |
116 | | Real firstDerivative(Real x) override; |
117 | | Real secondDerivative(Real x) override; |
118 | | |
119 | | protected: |
120 | | /* fraction of a period between the swap start date and |
121 | | the pay date */ |
122 | | Real delta_; |
123 | | /* accruals fraction*/ |
124 | | std::vector<Time> accruals_; |
125 | | }; |
126 | | |
127 | | class GFunctionWithShifts : public GFunction { |
128 | | |
129 | | Time swapStartTime_; |
130 | | |
131 | | Time shapedPaymentTime_; |
132 | | std::vector<Time> shapedSwapPaymentTimes_; |
133 | | |
134 | | std::vector<Time> accruals_; |
135 | | std::vector<Real> swapPaymentDiscounts_; |
136 | | Real discountAtStart_, discountRatio_; |
137 | | |
138 | | Real swapRateValue_; |
139 | | Handle<Quote> meanReversion_; |
140 | | |
141 | | Real calibratedShift_ = 0.03, tmpRs_ = 10000000.0; |
142 | | const Real accuracy_ = 1.0e-14; |
143 | | |
144 | | //* function describing the non-parallel shape of the curve shift*/ |
145 | | Real shapeOfShift(Real s) const; |
146 | | //* calibration of shift*/ |
147 | | Real calibrationOfShift(Real Rs); |
148 | | Real functionZ(Real x); |
149 | | Real derRs_derX(Real x); |
150 | | Real derZ_derX(Real x); |
151 | | Real der2Rs_derX2(Real x); |
152 | | Real der2Z_derX2(Real x); |
153 | | |
154 | | class ObjectiveFunction { |
155 | | const GFunctionWithShifts& o_; |
156 | | Real Rs_; |
157 | | mutable Real derivative_; |
158 | | public: |
159 | 0 | virtual ~ObjectiveFunction() = default; |
160 | 0 | ObjectiveFunction(const GFunctionWithShifts& o, const Real Rs) : o_(o), Rs_(Rs) {} |
161 | | virtual Real operator()(const Real& x) const; |
162 | | Real derivative(const Real& x) const; |
163 | | void setSwapRateValue(Real x); |
164 | 0 | const GFunctionWithShifts& gFunctionWithShifts() const { return o_; } |
165 | | }; |
166 | | |
167 | | ext::shared_ptr<ObjectiveFunction> objectiveFunction_; |
168 | | public: |
169 | | GFunctionWithShifts(const CmsCoupon& coupon, Handle<Quote> meanReversion); |
170 | | Real operator()(Real x) override; |
171 | | Real firstDerivative(Real x) override; |
172 | | Real secondDerivative(Real x) override; |
173 | | }; |
174 | | |
175 | | }; |
176 | | |
177 | | inline std::ostream& operator<<(std::ostream& out, |
178 | 0 | GFunctionFactory::YieldCurveModel type) { |
179 | 0 | switch (type) { |
180 | 0 | case GFunctionFactory::Standard: |
181 | 0 | return out << "Standard"; |
182 | 0 | case GFunctionFactory::ExactYield: |
183 | 0 | return out << "ExactYield"; |
184 | 0 | case GFunctionFactory::ParallelShifts: |
185 | 0 | return out << "ParallelShifts"; |
186 | 0 | case GFunctionFactory::NonParallelShifts: |
187 | 0 | return out << "NonParallelShifts"; |
188 | 0 | default: |
189 | 0 | QL_FAIL("unknown option type"); |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | | //! CMS-coupon pricer |
194 | | /*! Base class for the pricing of a CMS coupon via static replication |
195 | | as in Hagan's "Conundrums..." article |
196 | | */ |
197 | | class HaganPricer: public CmsCouponPricer, public MeanRevertingPricer { |
198 | | public: |
199 | | /* */ |
200 | | Real swapletPrice() const override = 0; |
201 | | Rate swapletRate() const override; |
202 | | Real capletPrice(Rate effectiveCap) const override; |
203 | | Rate capletRate(Rate effectiveCap) const override; |
204 | | Real floorletPrice(Rate effectiveFloor) const override; |
205 | | Rate floorletRate(Rate effectiveFloor) const override; |
206 | | /* */ |
207 | | Real meanReversion() const override; |
208 | 0 | void setMeanReversion(const Handle<Quote>& meanReversion) override { |
209 | 0 | unregisterWith(meanReversion_); |
210 | 0 | meanReversion_ = meanReversion; |
211 | 0 | registerWith(meanReversion_); |
212 | 0 | update(); |
213 | 0 | }; |
214 | | |
215 | | protected: |
216 | | HaganPricer(const Handle<SwaptionVolatilityStructure>& swaptionVol, |
217 | | GFunctionFactory::YieldCurveModel modelOfYieldCurve, |
218 | | Handle<Quote> meanReversion); |
219 | | void initialize(const FloatingRateCoupon& coupon) override; |
220 | | |
221 | | virtual Real optionletPrice(Option::Type optionType, |
222 | | Real strike) const = 0; |
223 | | |
224 | | ext::shared_ptr<YieldTermStructure> rateCurve_; |
225 | | GFunctionFactory::YieldCurveModel modelOfYieldCurve_; |
226 | | ext::shared_ptr<GFunction> gFunction_; |
227 | | const CmsCoupon* coupon_; |
228 | | Date paymentDate_, fixingDate_; |
229 | | Rate swapRateValue_; |
230 | | DiscountFactor discount_; |
231 | | Real annuity_; |
232 | | Real gearing_; |
233 | | Spread spread_; |
234 | | Real spreadLegValue_; |
235 | | Rate cutoffForCaplet_ = 2, cutoffForFloorlet_ = 0; |
236 | | Handle<Quote> meanReversion_; |
237 | | Period swapTenor_; |
238 | | ext::shared_ptr<VanillaOptionPricer> vanillaOptionPricer_; |
239 | | }; |
240 | | |
241 | | |
242 | | //! CMS-coupon pricer |
243 | | /*! Prices a cms coupon via static replication as in Hagan's |
244 | | "Conundrums..." article via numerical integration based on |
245 | | prices of vanilla swaptions |
246 | | */ |
247 | | class NumericHaganPricer : public HaganPricer { |
248 | | public: |
249 | | NumericHaganPricer( |
250 | | const Handle<SwaptionVolatilityStructure>& swaptionVol, |
251 | | GFunctionFactory::YieldCurveModel modelOfYieldCurve, |
252 | | const Handle<Quote>& meanReversion, |
253 | | Rate lowerLimit = 0.0, |
254 | | Rate upperLimit = 1.0, |
255 | | Real precision = 1.0e-6, |
256 | | Real hardUpperLimit = QL_MAX_REAL); |
257 | | |
258 | 0 | Real upperLimit() const { return upperLimit_; } |
259 | 0 | Real lowerLimit() const { return lowerLimit_; } |
260 | 0 | Real stdDeviations() const { return stdDeviationsForUpperLimit_; } |
261 | | |
262 | | // private: |
263 | | class Function { |
264 | | public: |
265 | 0 | virtual ~Function() = default; |
266 | | virtual Real operator()(Real x) const = 0; |
267 | | }; |
268 | | |
269 | | class ConundrumIntegrand : public Function { |
270 | | friend class NumericHaganPricer; |
271 | | public: |
272 | | ConundrumIntegrand(ext::shared_ptr<VanillaOptionPricer> o, |
273 | | const ext::shared_ptr<YieldTermStructure>& rateCurve, |
274 | | ext::shared_ptr<GFunction> gFunction, |
275 | | Date fixingDate, |
276 | | Date paymentDate, |
277 | | Real annuity, |
278 | | Real forwardValue, |
279 | | Real strike, |
280 | | Option::Type optionType); |
281 | | Real operator()(Real x) const override; |
282 | | |
283 | | protected: |
284 | | Real functionF(Real x) const; |
285 | | Real firstDerivativeOfF(Real x) const; |
286 | | Real secondDerivativeOfF(Real x) const; |
287 | | |
288 | | Real strike() const; |
289 | | Real annuity() const; |
290 | | Date fixingDate() const; |
291 | | void setStrike(Real strike); |
292 | | |
293 | | const ext::shared_ptr<VanillaOptionPricer> vanillaOptionPricer_; |
294 | | const Real forwardValue_, annuity_; |
295 | | const Date fixingDate_, paymentDate_; |
296 | | Real strike_; |
297 | | const Option::Type optionType_; |
298 | | ext::shared_ptr<GFunction> gFunction_; |
299 | | }; |
300 | | |
301 | | Real integrate(Real a, |
302 | | Real b, |
303 | | const ConundrumIntegrand& Integrand) const; |
304 | | Real optionletPrice(Option::Type optionType, Rate strike) const override; |
305 | | Real swapletPrice() const override; |
306 | | Real resetUpperLimit(Real stdDeviationsForUpperLimit) const; |
307 | | Real resetLowerLimit(Real stdDeviationsForLowerLimit) const; |
308 | | Real refineIntegration(Real integralValue, const ConundrumIntegrand& integrand) const; |
309 | | |
310 | | mutable Real lowerLimit_, stdDeviationsForLowerLimit_, upperLimit_, stdDeviationsForUpperLimit_; |
311 | | const Real requiredStdDeviations_ = 8, precision_, |
312 | | refiningIntegrationTolerance_ = .0001; |
313 | | const Real hardUpperLimit_; |
314 | | }; |
315 | | |
316 | | //! CMS-coupon pricer |
317 | | class AnalyticHaganPricer : public HaganPricer { |
318 | | public: |
319 | | AnalyticHaganPricer( |
320 | | const Handle<SwaptionVolatilityStructure>& swaptionVol, |
321 | | GFunctionFactory::YieldCurveModel modelOfYieldCurve, |
322 | | const Handle<Quote>& meanReversion); |
323 | | protected: |
324 | | Real optionletPrice(Option::Type optionType, Real strike) const override; |
325 | | Real swapletPrice() const override; |
326 | | }; |
327 | | |
328 | | } |
329 | | |
330 | | |
331 | | #endif |