/src/quantlib/ql/cashflows/lineartsrpricer.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) 2014, 2016 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 | | |
16 | | This program is distributed in the hope that it will be useful, but |
17 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
18 | | or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ |
19 | | |
20 | | /*! \file lineartsrpricer.hpp |
21 | | \brief linear terminal swap rate model for cms coupon pricing |
22 | | */ |
23 | | |
24 | | #ifndef quantlib_lineartsr_pricer_hpp |
25 | | #define quantlib_lineartsr_pricer_hpp |
26 | | |
27 | | #include <ql/termstructures/volatility/smilesection.hpp> |
28 | | #include <ql/cashflows/couponpricer.hpp> |
29 | | #include <ql/instruments/payoffs.hpp> |
30 | | #include <ql/indexes/swapindex.hpp> |
31 | | #include <ql/instruments/fixedvsfloatingswap.hpp> |
32 | | #include <ql/math/integrals/integral.hpp> |
33 | | |
34 | | namespace QuantLib { |
35 | | |
36 | | class CmsCoupon; |
37 | | class YieldTermStructure; |
38 | | |
39 | | //! CMS-coupon pricer |
40 | | /*! Prices a cms coupon using a linear terminal swap rate model |
41 | | The slope parameter is linked to a gaussian short rate model. |
42 | | Reference: Andersen, Piterbarg, Interest Rate Modeling, 16.3.2 |
43 | | |
44 | | The cut off point for integration can be set |
45 | | - by explicitly specifying the lower and upper bound |
46 | | - by defining the lower and upper bound to be the strike where |
47 | | a vanilla swaption has 1% or less vega of the atm swaption |
48 | | - by defining the lower and upper bound to be the strike where |
49 | | undeflated (!) payer resp. receiver prices are below a given |
50 | | threshold |
51 | | - by specificying a number of standard deviations to cover |
52 | | using a Black Scholes process with an atm volatility as |
53 | | a benchmark |
54 | | In every case the lower and upper bound are applied though. |
55 | | In case the smile section is shifted lognormal, the specified |
56 | | lower and upper bound are applied to strike + shift so that |
57 | | e.g. a zero lower bound always refers to the lower bound of |
58 | | the rates in the shifted lognormal model. |
59 | | Note that for normal volatility input the lower rate bound |
60 | | is adjusted to min(-upperBound, lowerBound), except the bounds |
61 | | are set explicitly. |
62 | | */ |
63 | | |
64 | | class LinearTsrPricer : public CmsCouponPricer, public MeanRevertingPricer { |
65 | | |
66 | | private: |
67 | | static const Real defaultLowerBound, |
68 | | defaultUpperBound; |
69 | | |
70 | | public: |
71 | | |
72 | | struct Settings { |
73 | | |
74 | 0 | Settings() : lowerRateBound_(defaultLowerBound), upperRateBound_(defaultUpperBound) {} |
75 | | |
76 | | Settings &withRateBound(const Real lowerRateBound = defaultLowerBound, |
77 | 0 | const Real upperRateBound = defaultUpperBound) { |
78 | 0 | strategy_ = RateBound; |
79 | 0 | lowerRateBound_ = lowerRateBound; |
80 | 0 | upperRateBound_ = upperRateBound; |
81 | 0 | defaultBounds_ = false; |
82 | 0 | return *this; |
83 | 0 | } |
84 | | |
85 | 0 | Settings &withVegaRatio(const Real vegaRatio = 0.01) { |
86 | 0 | strategy_ = VegaRatio; |
87 | 0 | vegaRatio_ = vegaRatio; |
88 | 0 | lowerRateBound_ = defaultLowerBound; |
89 | 0 | upperRateBound_ = defaultUpperBound; |
90 | 0 | defaultBounds_ = true; |
91 | 0 | return *this; |
92 | 0 | } |
93 | | |
94 | | Settings &withVegaRatio(const Real vegaRatio, |
95 | | const Real lowerRateBound, |
96 | 0 | const Real upperRateBound) { |
97 | 0 | strategy_ = VegaRatio; |
98 | 0 | vegaRatio_ = vegaRatio; |
99 | 0 | lowerRateBound_ = lowerRateBound; |
100 | 0 | upperRateBound_ = upperRateBound; |
101 | 0 | defaultBounds_ = false; |
102 | 0 | return *this; |
103 | 0 | } |
104 | | |
105 | 0 | Settings &withPriceThreshold(const Real priceThreshold = 1.0E-8) { |
106 | 0 | strategy_ = PriceThreshold; |
107 | 0 | priceThreshold_ = priceThreshold; |
108 | 0 | lowerRateBound_ = defaultLowerBound; |
109 | 0 | upperRateBound_ = defaultUpperBound; |
110 | 0 | defaultBounds_ = true; |
111 | 0 | return *this; |
112 | 0 | } |
113 | | |
114 | | Settings &withPriceThreshold(const Real priceThreshold, |
115 | | const Real lowerRateBound, |
116 | 0 | const Real upperRateBound) { |
117 | 0 | strategy_ = PriceThreshold; |
118 | 0 | priceThreshold_ = priceThreshold; |
119 | 0 | lowerRateBound_ = lowerRateBound; |
120 | 0 | upperRateBound_ = upperRateBound; |
121 | 0 | defaultBounds_ = false; |
122 | 0 | return *this; |
123 | 0 | } |
124 | | |
125 | 0 | Settings &withBSStdDevs(const Real stdDevs = 3.0) { |
126 | 0 | strategy_ = BSStdDevs; |
127 | 0 | stdDevs_ = stdDevs; |
128 | 0 | lowerRateBound_ = defaultLowerBound; |
129 | 0 | upperRateBound_ = defaultUpperBound; |
130 | 0 | defaultBounds_ = true; |
131 | 0 | return *this; |
132 | 0 | } |
133 | | |
134 | | Settings &withBSStdDevs(const Real stdDevs, |
135 | | const Real lowerRateBound, |
136 | 0 | const Real upperRateBound) { |
137 | 0 | strategy_ = BSStdDevs; |
138 | 0 | stdDevs_ = stdDevs; |
139 | 0 | lowerRateBound_ = lowerRateBound; |
140 | 0 | upperRateBound_ = upperRateBound; |
141 | 0 | defaultBounds_ = false; |
142 | 0 | return *this; |
143 | 0 | } |
144 | | |
145 | | enum Strategy { |
146 | | RateBound, |
147 | | VegaRatio, |
148 | | PriceThreshold, |
149 | | BSStdDevs |
150 | | }; |
151 | | |
152 | | Strategy strategy_ = RateBound; |
153 | | Real vegaRatio_ = 0.01; |
154 | | Real priceThreshold_ = 1.0E-8; |
155 | | Real stdDevs_ = 3.0; |
156 | | Real lowerRateBound_, upperRateBound_; |
157 | | bool defaultBounds_ = true; |
158 | | }; |
159 | | |
160 | | |
161 | | LinearTsrPricer( |
162 | | const Handle<SwaptionVolatilityStructure>& swaptionVol, |
163 | | Handle<Quote> meanReversion, |
164 | | Handle<YieldTermStructure> couponDiscountCurve = Handle<YieldTermStructure>(), |
165 | | const Settings& settings = Settings(), |
166 | | ext::shared_ptr<Integrator> integrator = ext::shared_ptr<Integrator>()); |
167 | | |
168 | | /* */ |
169 | | Real swapletPrice() const override; |
170 | | Rate swapletRate() const override; |
171 | | Real capletPrice(Rate effectiveCap) const override; |
172 | | Rate capletRate(Rate effectiveCap) const override; |
173 | | Real floorletPrice(Rate effectiveFloor) const override; |
174 | | Rate floorletRate(Rate effectiveFloor) const override; |
175 | | /* */ |
176 | | Real meanReversion() const override; |
177 | 0 | void setMeanReversion(const Handle<Quote>& meanReversion) override { |
178 | 0 | unregisterWith(meanReversion_); |
179 | 0 | meanReversion_ = meanReversion; |
180 | 0 | registerWith(meanReversion_); |
181 | 0 | update(); |
182 | 0 | } |
183 | | |
184 | | |
185 | | private: |
186 | | |
187 | | Real GsrG(const Date &d) const; |
188 | | Real singularTerms(Option::Type type, Real strike) const; |
189 | | Real integrand(Real strike) const; |
190 | | Real a_, b_; |
191 | | |
192 | | class integrand_f; |
193 | | |
194 | | class VegaRatioHelper { |
195 | | public: |
196 | | VegaRatioHelper(const SmileSection *section, const Real targetVega) |
197 | 0 | : section_(section), targetVega_(targetVega) {} |
198 | 0 | Real operator()(Real strike) const { |
199 | 0 | return section_->vega(strike) - targetVega_; |
200 | 0 | }; |
201 | | const SmileSection *section_; |
202 | | const Real targetVega_; |
203 | | }; |
204 | | |
205 | | class PriceHelper { |
206 | | public: |
207 | | PriceHelper(const SmileSection *section, const Option::Type type, |
208 | | const Real targetPrice) |
209 | 0 | : section_(section), targetPrice_(targetPrice), type_(type) {} |
210 | 0 | Real operator()(Real strike) const { |
211 | 0 | return section_->optionPrice(strike, type_) - targetPrice_; |
212 | 0 | }; |
213 | | const SmileSection *section_; |
214 | | const Real targetPrice_; |
215 | | const Option::Type type_; |
216 | | }; |
217 | | |
218 | | void initialize(const FloatingRateCoupon& coupon) override; |
219 | | Real optionletPrice(Option::Type optionType, Real strike) const; |
220 | | Real strikeFromVegaRatio(Real ratio, Option::Type optionType, |
221 | | Real referenceStrike) const; |
222 | | Real strikeFromPrice(Real price, Option::Type optionType, |
223 | | Real referenceStrike) const; |
224 | | |
225 | | Handle<Quote> meanReversion_; |
226 | | |
227 | | Handle<YieldTermStructure> forwardCurve_, discountCurve_; |
228 | | Handle<YieldTermStructure> couponDiscountCurve_; |
229 | | |
230 | | const CmsCoupon *coupon_; |
231 | | |
232 | | Date today_, paymentDate_, fixingDate_; |
233 | | |
234 | | Real gearing_, spread_; |
235 | | |
236 | | Period swapTenor_; |
237 | | Real spreadLegValue_, swapRateValue_, couponDiscountRatio_, discountCurvePaymentDiscount_, |
238 | | annuity_; |
239 | | |
240 | | ext::shared_ptr<SwapIndex> swapIndex_; |
241 | | ext::shared_ptr<FixedVsFloatingSwap> swap_; |
242 | | ext::shared_ptr<SmileSection> smileSection_; |
243 | | |
244 | | Settings settings_; |
245 | | DayCounter volDayCounter_; |
246 | | ext::shared_ptr<Integrator> integrator_; |
247 | | |
248 | | Real adjustedLowerBound_, adjustedUpperBound_; |
249 | | }; |
250 | | } |
251 | | |
252 | | #endif |