Coverage Report

Created: 2026-09-28 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/termstructures/volatility/interpolatedsmilesection.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2006 Ferdinando Ametrano
5
 Copyright (C) 2006 François du Vignaud
6
 Copyright (C) 2015 Peter Caspers
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <https://www.quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
/*! \file interpolatedsmilesection.hpp
23
    \brief Interpolated smile section class
24
*/
25
26
#ifndef quantlib_interpolated_smile_section_hpp
27
#define quantlib_interpolated_smile_section_hpp
28
29
#include <ql/math/interpolations/linearinterpolation.hpp>
30
#include <ql/patterns/lazyobject.hpp>
31
#include <ql/quotes/simplequote.hpp>
32
#include <ql/termstructure.hpp>
33
#include <ql/termstructures/volatility/smilesection.hpp>
34
#include <ql/time/daycounters/actual365fixed.hpp>
35
#include <utility>
36
37
namespace QuantLib {
38
39
    template<class Interpolator>
40
    class InterpolatedSmileSection : public SmileSection,
41
                                     public LazyObject {
42
      public:
43
        InterpolatedSmileSection(Time expiryTime,
44
                                 std::vector<Rate> strikes,
45
                                 const std::vector<Handle<Quote> >& stdDevHandles,
46
                                 Handle<Quote> atmLevel,
47
                                 const Interpolator& interpolator = Interpolator(),
48
                                 const DayCounter& dc = Actual365Fixed(),
49
                                 VolatilityType type = ShiftedLognormal,
50
                                 Real shift = 0.0,
51
                                 bool flatStrikeExtrapolation = false);
52
        InterpolatedSmileSection(Time expiryTime,
53
                                 std::vector<Rate> strikes,
54
                                 const std::vector<Real>& stdDevs,
55
                                 Real atmLevel,
56
                                 const Interpolator& interpolator = Interpolator(),
57
                                 const DayCounter& dc = Actual365Fixed(),
58
                                 VolatilityType type = ShiftedLognormal,
59
                                 Real shift = 0.0,
60
                                 bool flatStrikeExtrapolation = false);
61
        InterpolatedSmileSection(const Date& d,
62
                                 std::vector<Rate> strikes,
63
                                 const std::vector<Handle<Quote> >& stdDevHandles,
64
                                 Handle<Quote> atmLevel,
65
                                 const DayCounter& dc = Actual365Fixed(),
66
                                 const Interpolator& interpolator = Interpolator(),
67
                                 const Date& referenceDate = Date(),
68
                                 VolatilityType type = ShiftedLognormal,
69
                                 Real shift = 0.0,
70
                                 bool flatStrikeExtrapolation = false);
71
        InterpolatedSmileSection(const Date& d,
72
                                 std::vector<Rate> strikes,
73
                                 const std::vector<Real>& stdDevs,
74
                                 Real atmLevel,
75
                                 const DayCounter& dc = Actual365Fixed(),
76
                                 const Interpolator& interpolator = Interpolator(),
77
                                 const Date& referenceDate = Date(),
78
                                 VolatilityType type = ShiftedLognormal,
79
                                 Real shift = 0.0,
80
                                 bool flatStrikeExtrapolation = false);
81
82
        void performCalculations() const override;
83
        Real varianceImpl(Rate strike) const override;
84
        Volatility volatilityImpl(Rate strike) const override;
85
0
        Real minStrike() const override { return strikes_.front(); }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::minStrike() const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::minStrike() const
86
0
        Real maxStrike() const override { return strikes_.back(); }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::maxStrike() const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::maxStrike() const
87
0
        Real atmLevel() const override { return atmLevel_->value(); }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::atmLevel() const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::atmLevel() const
88
        void update() override;
89
90
      private:
91
        void checkStrikes();
92
93
        Real exerciseTimeSquareRoot_;
94
        std::vector<Rate> strikes_;
95
        std::vector<Handle<Quote> > stdDevHandles_;
96
        Handle<Quote> atmLevel_;
97
        mutable std::vector<Volatility> vols_;
98
        mutable Interpolation interpolation_;
99
        bool flatStrikeExtrapolation_;
100
    };
101
102
103
    template <class Interpolator>
104
    InterpolatedSmileSection<Interpolator>::InterpolatedSmileSection(
105
        Time timeToExpiry,
106
        std::vector<Rate> strikes,
107
        const std::vector<Handle<Quote> >& stdDevHandles,
108
        Handle<Quote> atmLevel,
109
        const Interpolator& interpolator,
110
        const DayCounter& dc,
111
        const VolatilityType type,
112
        const Real shift,
113
        bool flatStrikeExtrapolation
114
    )
115
    : SmileSection(timeToExpiry, dc, type, shift),
116
      exerciseTimeSquareRoot_(std::sqrt(exerciseTime())), strikes_(std::move(strikes)),
117
      stdDevHandles_(stdDevHandles), atmLevel_(std::move(atmLevel)), vols_(stdDevHandles.size()),
118
      flatStrikeExtrapolation_(flatStrikeExtrapolation) {
119
        for (auto& stdDevHandle : stdDevHandles_)
120
            LazyObject::registerWith(stdDevHandle);
121
        LazyObject::registerWith(atmLevel_);
122
123
        checkStrikes();
124
        interpolation_ = detail::interpolateWithoutUpdate(
125
            interpolator, strikes_.begin(), strikes_.end(), vols_.begin());
126
    }
127
128
    template <class Interpolator>
129
    InterpolatedSmileSection<Interpolator>::InterpolatedSmileSection(
130
        Time timeToExpiry,
131
        std::vector<Rate> strikes,
132
        const std::vector<Real>& stdDevs,
133
        Real atmLevel,
134
        const Interpolator& interpolator,
135
        const DayCounter& dc,
136
        const VolatilityType type,
137
        const Real shift,
138
        bool flatStrikeExtrapolation
139
    )
140
0
    : SmileSection(timeToExpiry, dc, type, shift),
141
0
      exerciseTimeSquareRoot_(std::sqrt(exerciseTime())), strikes_(std::move(strikes)),
142
0
      stdDevHandles_(stdDevs.size()), vols_(stdDevs.size()),
143
0
      flatStrikeExtrapolation_(flatStrikeExtrapolation) {
144
        // fill dummy handles to allow generic handle-based
145
        // computations later on
146
0
        for (Size i=0; i<stdDevs.size(); ++i)
147
0
            stdDevHandles_[i] = Handle<Quote>(ext::make_shared<SimpleQuote>(stdDevs[i]));
148
0
        atmLevel_ = Handle<Quote>(ext::make_shared<SimpleQuote>(atmLevel));
149
        
150
0
        checkStrikes();
151
0
        interpolation_ = detail::interpolateWithoutUpdate(
152
0
            interpolator, strikes_.begin(), strikes_.end(), vols_.begin());
153
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::InterpolatedSmileSection(double, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> > const&, double, QuantLib::Linear const&, QuantLib::DayCounter const&, QuantLib::VolatilityType, double, bool)
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::InterpolatedSmileSection(double, std::__1::vector<double, std::__1::allocator<double> >, std::__1::vector<double, std::__1::allocator<double> > const&, double, QuantLib::Cubic const&, QuantLib::DayCounter const&, QuantLib::VolatilityType, double, bool)
154
155
    template <class Interpolator>
156
    InterpolatedSmileSection<Interpolator>::InterpolatedSmileSection(
157
        const Date& d,
158
        std::vector<Rate> strikes,
159
        const std::vector<Handle<Quote> >& stdDevHandles,
160
        Handle<Quote> atmLevel,
161
        const DayCounter& dc,
162
        const Interpolator& interpolator,
163
        const Date& referenceDate,
164
        const VolatilityType type,
165
        const Real shift,
166
        bool flatStrikeExtrapolation
167
    )
168
    : SmileSection(d, dc, referenceDate, type, shift),
169
      exerciseTimeSquareRoot_(std::sqrt(exerciseTime())), strikes_(std::move(strikes)),
170
      stdDevHandles_(stdDevHandles), atmLevel_(std::move(atmLevel)), vols_(stdDevHandles.size()),
171
      flatStrikeExtrapolation_(flatStrikeExtrapolation) {
172
        for (auto& stdDevHandle : stdDevHandles_)
173
            LazyObject::registerWith(stdDevHandle);
174
        LazyObject::registerWith(atmLevel_);
175
        
176
        checkStrikes();
177
        interpolation_ = detail::interpolateWithoutUpdate(
178
            interpolator, strikes_.begin(), strikes_.end(), vols_.begin());
179
    }
180
181
    template <class Interpolator>
182
    InterpolatedSmileSection<Interpolator>::InterpolatedSmileSection(
183
        const Date& d,
184
        std::vector<Rate> strikes,
185
        const std::vector<Real>& stdDevs,
186
        Real atmLevel,
187
        const DayCounter& dc,
188
        const Interpolator& interpolator,
189
        const Date& referenceDate,
190
        const VolatilityType type,
191
        const Real shift,
192
        bool flatStrikeExtrapolation
193
    )
194
0
    : SmileSection(d, dc, referenceDate, type, shift),
195
0
      exerciseTimeSquareRoot_(std::sqrt(exerciseTime())), strikes_(std::move(strikes)),
196
0
      stdDevHandles_(stdDevs.size()), vols_(stdDevs.size()),
197
0
      flatStrikeExtrapolation_(flatStrikeExtrapolation) {
198
        //fill dummy handles to allow generic handle-based
199
        // computations later on
200
0
        for (Size i=0; i<stdDevs.size(); ++i)
201
0
            stdDevHandles_[i] = Handle<Quote>(ext::make_shared<SimpleQuote>(stdDevs[i]));
202
0
        atmLevel_ = Handle<Quote>(ext::make_shared<SimpleQuote>(atmLevel));
203
        
204
0
        checkStrikes();
205
0
        interpolation_ = detail::interpolateWithoutUpdate(
206
0
            interpolator, strikes_.begin(), strikes_.end(), vols_.begin());
207
0
    }
208
209
210
    template <class Interpolator>
211
    inline void InterpolatedSmileSection<Interpolator>::performCalculations()
212
0
                                                                      const {
213
0
        for (Size i=0; i<stdDevHandles_.size(); ++i)
214
0
            vols_[i] = stdDevHandles_[i]->value()/exerciseTimeSquareRoot_;
215
0
        interpolation_.update();
216
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::performCalculations() const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::performCalculations() const
217
218
    #ifndef __DOXYGEN__
219
    template <class Interpolator>
220
0
    Real InterpolatedSmileSection<Interpolator>::varianceImpl(Real strike) const {
221
0
        Real v = volatilityImpl(strike);
222
0
        return v * v * exerciseTime();
223
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::varianceImpl(double) const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::varianceImpl(double) const
224
225
    template <class Interpolator>
226
0
    Real InterpolatedSmileSection<Interpolator>::volatilityImpl(Real strike) const {
227
0
        calculate();
228
        
229
0
        if (flatStrikeExtrapolation_) {
230
0
            if (strike < minStrike()) {
231
0
                return interpolation_(minStrike(), true);                
232
0
            } else if (strike > maxStrike()) {
233
0
                return interpolation_(maxStrike(), true);
234
0
            }
235
0
        }
236
237
0
        return std::max(interpolation_(strike, true), 0.0);
238
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::volatilityImpl(double) const
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::volatilityImpl(double) const
239
240
    template <class Interpolator>
241
0
    void InterpolatedSmileSection<Interpolator>::update() {
242
0
        LazyObject::update();
243
0
        SmileSection::update();
244
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::update()
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::update()
245
    #endif
246
247
    template <class Interpolator>
248
0
    void InterpolatedSmileSection<Interpolator>::checkStrikes() {
249
        QL_REQUIRE(std::is_sorted(strikes_.begin(), strikes_.end()), 
250
0
                    "Strikes have to be sorted in ascending order");
251
0
    }
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Linear>::checkStrikes()
Unexecuted instantiation: QuantLib::InterpolatedSmileSection<QuantLib::Cubic>::checkStrikes()
252
253
}
254
255
#endif