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
31namespace QuantLib {
32
33 class CmsCoupon;
34 class YieldTermStructure;
35 class Quote;
36
37 class VanillaOptionPricer {
38 public:
39 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 /*! \deprecated Renamed to MarketQuotedOptionPricer.
65 Deprecated in version 1.31.
66 */
67 [[deprecated("Renamed to MarketQuotedOptionPricer")]]
68 typedef MarketQuotedOptionPricer BlackVanillaOptionPricer;
69
70 class GFunction {
71 public:
72 virtual ~GFunction() = default;
73 virtual Real operator()(Real x) = 0;
74 virtual Real firstDerivative(Real x) = 0;
75 virtual Real secondDerivative(Real x) = 0;
76 };
77
78 class GFunctionFactory {
79 public:
80 enum YieldCurveModel { Standard,
81 ExactYield,
82 ParallelShifts,
83 NonParallelShifts
84 };
85
86 GFunctionFactory() = delete;
87
88 static ext::shared_ptr<GFunction>
89 newGFunctionStandard(Size q,
90 Real delta,
91 Size swapLength);
92 static ext::shared_ptr<GFunction>
93 newGFunctionExactYield(const CmsCoupon& coupon);
94 static ext::shared_ptr<GFunction>
95 newGFunctionWithShifts(const CmsCoupon& coupon,
96 const Handle<Quote>& meanReversion);
97 private:
98 class GFunctionStandard : public GFunction {
99 public:
100 GFunctionStandard(Size q,
101 Real delta,
102 Size swapLength)
103 : q_(q), delta_(delta), swapLength_(swapLength) {}
104 Real operator()(Real x) override;
105 Real firstDerivative(Real x) override;
106 Real secondDerivative(Real x) override;
107
108 protected:
109 /* number of period per year */
110 const int q_;
111 /* fraction of a period between the swap start date and
112 the pay date */
113 Real delta_;
114 /* length of swap*/
115 Size swapLength_;
116 };
117
118 class GFunctionExactYield : public GFunction {
119 public:
120 GFunctionExactYield(const CmsCoupon& coupon);
121 Real operator()(Real x) override;
122 Real firstDerivative(Real x) override;
123 Real secondDerivative(Real x) override;
124
125 protected:
126 /* fraction of a period between the swap start date and
127 the pay date */
128 Real delta_;
129 /* accruals fraction*/
130 std::vector<Time> accruals_;
131 };
132
133 class GFunctionWithShifts : public GFunction {
134
135 Time swapStartTime_;
136
137 Time shapedPaymentTime_;
138 std::vector<Time> shapedSwapPaymentTimes_;
139
140 std::vector<Time> accruals_;
141 std::vector<Real> swapPaymentDiscounts_;
142 Real discountAtStart_, discountRatio_;
143
144 Real swapRateValue_;
145 Handle<Quote> meanReversion_;
146
147 Real calibratedShift_ = 0.03, tmpRs_ = 10000000.0;
148 const Real accuracy_ = 1.0e-14;
149
150 //* function describing the non-parallel shape of the curve shift*/
151 Real shapeOfShift(Real s) const;
152 //* calibration of shift*/
153 Real calibrationOfShift(Real Rs);
154 Real functionZ(Real x);
155 Real derRs_derX(Real x);
156 Real derZ_derX(Real x);
157 Real der2Rs_derX2(Real x);
158 Real der2Z_derX2(Real x);
159
160 class ObjectiveFunction {
161 const GFunctionWithShifts& o_;
162 Real Rs_;
163 mutable Real derivative_;
164 public:
165 virtual ~ObjectiveFunction() = default;
166 ObjectiveFunction(const GFunctionWithShifts& o, const Real Rs) : o_(o), Rs_(Rs) {}
167 virtual Real operator()(const Real& x) const;
168 Real derivative(const Real& x) const;
169 void setSwapRateValue(Real x);
170 const GFunctionWithShifts& gFunctionWithShifts() const { return o_; }
171 };
172
173 ext::shared_ptr<ObjectiveFunction> objectiveFunction_;
174 public:
175 GFunctionWithShifts(const CmsCoupon& coupon, Handle<Quote> meanReversion);
176 Real operator()(Real x) override;
177 Real firstDerivative(Real x) override;
178 Real secondDerivative(Real x) override;
179 };
180
181 };
182
183 inline std::ostream& operator<<(std::ostream& out,
184 GFunctionFactory::YieldCurveModel type) {
185 switch (type) {
186 case GFunctionFactory::Standard:
187 return out << "Standard";
188 case GFunctionFactory::ExactYield:
189 return out << "ExactYield";
190 case GFunctionFactory::ParallelShifts:
191 return out << "ParallelShifts";
192 case GFunctionFactory::NonParallelShifts:
193 return out << "NonParallelShifts";
194 default:
195 QL_FAIL("unknown option type");
196 }
197 }
198
199 //! CMS-coupon pricer
200 /*! Base class for the pricing of a CMS coupon via static replication
201 as in Hagan's "Conundrums..." article
202 */
203 class HaganPricer: public CmsCouponPricer, public MeanRevertingPricer {
204 public:
205 /* */
206 Real swapletPrice() const override = 0;
207 Rate swapletRate() const override;
208 Real capletPrice(Rate effectiveCap) const override;
209 Rate capletRate(Rate effectiveCap) const override;
210 Real floorletPrice(Rate effectiveFloor) const override;
211 Rate floorletRate(Rate effectiveFloor) const override;
212 /* */
213 Real meanReversion() const override;
214 void setMeanReversion(const Handle<Quote>& meanReversion) override {
215 unregisterWith(h: meanReversion_);
216 meanReversion_ = meanReversion;
217 registerWith(h: meanReversion_);
218 update();
219 };
220
221 protected:
222 HaganPricer(const Handle<SwaptionVolatilityStructure>& swaptionVol,
223 GFunctionFactory::YieldCurveModel modelOfYieldCurve,
224 Handle<Quote> meanReversion);
225 void initialize(const FloatingRateCoupon& coupon) override;
226
227 virtual Real optionletPrice(Option::Type optionType,
228 Real strike) const = 0;
229
230 ext::shared_ptr<YieldTermStructure> rateCurve_;
231 GFunctionFactory::YieldCurveModel modelOfYieldCurve_;
232 ext::shared_ptr<GFunction> gFunction_;
233 const CmsCoupon* coupon_;
234 Date paymentDate_, fixingDate_;
235 Rate swapRateValue_;
236 DiscountFactor discount_;
237 Real annuity_;
238 Real gearing_;
239 Spread spread_;
240 Real spreadLegValue_;
241 Rate cutoffForCaplet_ = 2, cutoffForFloorlet_ = 0;
242 Handle<Quote> meanReversion_;
243 Period swapTenor_;
244 ext::shared_ptr<VanillaOptionPricer> vanillaOptionPricer_;
245 };
246
247
248 //! CMS-coupon pricer
249 /*! Prices a cms coupon via static replication as in Hagan's
250 "Conundrums..." article via numerical integration based on
251 prices of vanilla swaptions
252 */
253 class NumericHaganPricer : public HaganPricer {
254 public:
255 NumericHaganPricer(
256 const Handle<SwaptionVolatilityStructure>& swaptionVol,
257 GFunctionFactory::YieldCurveModel modelOfYieldCurve,
258 const Handle<Quote>& meanReversion,
259 Rate lowerLimit = 0.0,
260 Rate upperLimit = 1.0,
261 Real precision = 1.0e-6,
262 Real hardUpperLimit = QL_MAX_REAL);
263
264 Real upperLimit() const { return upperLimit_; }
265 Real lowerLimit() const { return lowerLimit_; }
266 Real stdDeviations() const { return stdDeviationsForUpperLimit_; }
267
268 // private:
269 class Function {
270 public:
271 /*! \deprecated Use `auto` or `decltype` instead.
272 Deprecated in version 1.29.
273 */
274 QL_DEPRECATED
275 typedef Real argument_type;
276
277 /*! \deprecated Use `auto` or `decltype` instead.
278 Deprecated in version 1.29.
279 */
280 QL_DEPRECATED
281 typedef Real result_type;
282 virtual ~Function() = default;
283 virtual Real operator()(Real x) const = 0;
284 };
285
286 class ConundrumIntegrand : public Function {
287 friend class NumericHaganPricer;
288 public:
289 ConundrumIntegrand(ext::shared_ptr<VanillaOptionPricer> o,
290 const ext::shared_ptr<YieldTermStructure>& rateCurve,
291 ext::shared_ptr<GFunction> gFunction,
292 Date fixingDate,
293 Date paymentDate,
294 Real annuity,
295 Real forwardValue,
296 Real strike,
297 Option::Type optionType);
298 Real operator()(Real x) const override;
299
300 protected:
301 Real functionF(Real x) const;
302 Real firstDerivativeOfF(Real x) const;
303 Real secondDerivativeOfF(Real x) const;
304
305 Real strike() const;
306 Real annuity() const;
307 Date fixingDate() const;
308 void setStrike(Real strike);
309
310 const ext::shared_ptr<VanillaOptionPricer> vanillaOptionPricer_;
311 const Real forwardValue_, annuity_;
312 const Date fixingDate_, paymentDate_;
313 Real strike_;
314 const Option::Type optionType_;
315 ext::shared_ptr<GFunction> gFunction_;
316 };
317
318 Real integrate(Real a,
319 Real b,
320 const ConundrumIntegrand& Integrand) const;
321 Real optionletPrice(Option::Type optionType, Rate strike) const override;
322 Real swapletPrice() const override;
323 Real resetUpperLimit(Real stdDeviationsForUpperLimit) const;
324 Real resetLowerLimit(Real stdDeviationsForLowerLimit) const;
325 Real refineIntegration(Real integralValue, const ConundrumIntegrand& integrand) const;
326
327 mutable Real lowerLimit_, stdDeviationsForLowerLimit_, upperLimit_, stdDeviationsForUpperLimit_;
328 const Real requiredStdDeviations_ = 8, precision_,
329 refiningIntegrationTolerance_ = .0001;
330 const Real hardUpperLimit_;
331 };
332
333 //! CMS-coupon pricer
334 class AnalyticHaganPricer : public HaganPricer {
335 public:
336 AnalyticHaganPricer(
337 const Handle<SwaptionVolatilityStructure>& swaptionVol,
338 GFunctionFactory::YieldCurveModel modelOfYieldCurve,
339 const Handle<Quote>& meanReversion);
340 protected:
341 Real optionletPrice(Option::Type optionType, Real strike) const override;
342 Real swapletPrice() const override;
343 };
344
345}
346
347
348#endif
349

source code of quantlib/ql/cashflows/conundrumpricer.hpp