Coverage Report

Created: 2025-08-05 06:45

/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