Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/termstructures/volatility/equityfx/fixedlocalvolsurface.cpp
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) 2015 Johannes Göttker-Schnetmann
5
 Copyright (C) 2015 Klaus Spanderen
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
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
#include <ql/math/interpolations/linearinterpolation.hpp>
22
#include <ql/termstructures/volatility/equityfx/fixedlocalvolsurface.hpp>
23
#include <ql/time/calendars/nullcalendar.hpp>
24
#include <ql/time/daycounters/yearfractiontodate.hpp>
25
#include <utility>
26
27
28
namespace QuantLib {
29
30
    FixedLocalVolSurface::FixedLocalVolSurface(const Date& referenceDate,
31
                                               const std::vector<Date>& dates,
32
                                               const std::vector<Real>& strikes,
33
                                               ext::shared_ptr<Matrix> localVolMatrix,
34
                                               const DayCounter& dayCounter,
35
                                               Extrapolation lowerExtrapolation,
36
                                               Extrapolation upperExtrapolation)
37
0
    : LocalVolTermStructure(referenceDate, NullCalendar(), Following, dayCounter),
38
0
      maxDate_(dates.back()), localVolMatrix_(std::move(localVolMatrix)),
39
0
      strikes_(dates.size(), ext::make_shared<std::vector<Real> >(strikes)),
40
0
      localVolInterpol_(dates.size()), lowerExtrapolation_(lowerExtrapolation),
41
0
      upperExtrapolation_(upperExtrapolation) {
42
43
0
        QL_REQUIRE(dates[0]>=referenceDate,
44
0
                   "cannot have dates[0] < referenceDate");
45
46
0
        times_ = std::vector<Time>(dates.size());
47
0
        for (Size j=0; j<times_.size(); j++)
48
0
            times_[j] = timeFromReference(dates[j]);
49
50
0
        checkSurface();
51
0
        setInterpolation<Linear>();
52
0
    }
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<QuantLib::Date, std::__1::allocator<QuantLib::Date> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
53
54
    FixedLocalVolSurface::FixedLocalVolSurface(const Date& referenceDate,
55
                                               const std::vector<Time>& times,
56
                                               const std::vector<Real>& strikes,
57
                                               ext::shared_ptr<Matrix> localVolMatrix,
58
                                               const DayCounter& dayCounter,
59
                                               Extrapolation lowerExtrapolation,
60
                                               Extrapolation upperExtrapolation)
61
0
    : LocalVolTermStructure(referenceDate, NullCalendar(), Following, dayCounter),
62
0
      maxDate_(yearFractionToDate(dayCounter, referenceDate, times.back())), times_(times),
63
0
      localVolMatrix_(std::move(localVolMatrix)),
64
0
      strikes_(times.size(), ext::make_shared<std::vector<Real> >(strikes)),
65
0
      localVolInterpol_(times.size()), lowerExtrapolation_(lowerExtrapolation),
66
0
      upperExtrapolation_(upperExtrapolation) {
67
68
0
        QL_REQUIRE(times_[0]>=0, "cannot have times[0] < 0");
69
70
0
        checkSurface();
71
0
        setInterpolation<Linear>();
72
0
    }
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
73
74
    FixedLocalVolSurface::FixedLocalVolSurface(
75
        const Date& referenceDate,
76
        const std::vector<Time>& times,
77
        const std::vector<ext::shared_ptr<std::vector<Real> > >& strikes,
78
        ext::shared_ptr<Matrix> localVolMatrix,
79
        const DayCounter& dayCounter,
80
        Extrapolation lowerExtrapolation,
81
        Extrapolation upperExtrapolation)
82
0
    : LocalVolTermStructure(referenceDate, NullCalendar(), Following, dayCounter),
83
0
      maxDate_(yearFractionToDate(dayCounter, referenceDate, times.back())), times_(times),
84
0
      localVolMatrix_(std::move(localVolMatrix)), strikes_(strikes),
85
0
      localVolInterpol_(times.size()), lowerExtrapolation_(lowerExtrapolation),
86
0
      upperExtrapolation_(upperExtrapolation) {
87
88
0
        QL_REQUIRE(times_[0]>=0, "cannot have times[0] < 0");
89
0
        QL_REQUIRE(times.size() == strikes.size(),
90
0
             "need strikes for every time step");
91
0
        checkSurface();
92
0
        setInterpolation<Linear>();
93
0
    }
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<boost::shared_ptr<std::__1::vector<double, std::__1::allocator<double> > >, std::__1::allocator<boost::shared_ptr<std::__1::vector<double, std::__1::allocator<double> > > > > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
Unexecuted instantiation: QuantLib::FixedLocalVolSurface::FixedLocalVolSurface(QuantLib::Date const&, std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<boost::shared_ptr<std::__1::vector<double, std::__1::allocator<double> > >, std::__1::allocator<boost::shared_ptr<std::__1::vector<double, std::__1::allocator<double> > > > > const&, boost::shared_ptr<QuantLib::Matrix>, QuantLib::DayCounter const&, QuantLib::FixedLocalVolSurface::Extrapolation, QuantLib::FixedLocalVolSurface::Extrapolation)
94
95
96
0
    void FixedLocalVolSurface::checkSurface() {
97
0
        QL_REQUIRE(times_.size()==localVolMatrix_->columns(),
98
0
                   "mismatch between date vector and vol matrix colums");
99
0
        for (const auto& strike : strikes_) {
100
0
            QL_REQUIRE(strike->size() == localVolMatrix_->rows(),
101
0
                       "mismatch between money-strike vector and "
102
0
                       "vol matrix rows");
103
0
        }
104
105
0
        for (Size j=1; j<times_.size(); j++) {
106
0
            QL_REQUIRE(times_[j]>times_[j-1],
107
0
                       "dates must be sorted unique!");
108
0
        }
109
110
0
        for (const auto& strike : strikes_)
111
0
            for (Size j = 1; j < strike->size(); j++) {
112
0
                QL_REQUIRE((*strike)[j] >= (*strike)[j - 1], "strikes must be sorted");
113
0
            }
114
0
    }
115
116
0
    Date FixedLocalVolSurface::maxDate() const {
117
0
        return maxDate_;
118
0
    }
119
0
    Time FixedLocalVolSurface::maxTime() const {
120
0
        return times_.back();
121
0
    }
122
0
    Real FixedLocalVolSurface::minStrike() const {
123
0
        return strikes_.back()->front();
124
0
    }
125
0
    Real FixedLocalVolSurface::maxStrike() const {
126
0
        return strikes_.back()->back();
127
0
    }
128
129
0
    Volatility FixedLocalVolSurface::localVolImpl(Time t, Real strike) const {
130
0
        t = std::min(times_.back(), std::max(t, times_.front()));
131
132
0
        const Size idx = std::distance(times_.begin(),
133
0
            std::lower_bound(times_.begin(), times_.end(), t));
134
135
0
        if (close_enough(t, times_[idx])) {
136
0
            if (strikes_[idx]->front() < strikes_[idx]->back())
137
0
                return localVolInterpol_[idx](strike, true);
138
0
            else
139
0
                return (*localVolMatrix_)[localVolMatrix_->rows()/2][idx];
140
0
        }
141
0
        else {
142
0
            Real earlierStrike = strike, laterStrike = strike;
143
0
            if (lowerExtrapolation_ == ConstantExtrapolation) {
144
0
                if (strike < strikes_[idx-1]->front())
145
0
                    earlierStrike = strikes_[idx-1]->front();
146
0
                if (strike < strikes_[idx]->front())
147
0
                    laterStrike = strikes_[idx]->front();
148
0
            }
149
150
0
            if (upperExtrapolation_ == ConstantExtrapolation) {
151
0
                if (strike > strikes_[idx-1]->back())
152
0
                    earlierStrike = strikes_[idx-1]->back();
153
0
                if (strike > strikes_[idx]->back())
154
0
                    laterStrike = strikes_[idx]->back();
155
0
            }
156
157
0
            const Real earlyVol =
158
0
                (strikes_[idx-1]->front() < strikes_[idx-1]->back())
159
0
                ? localVolInterpol_[idx-1](earlierStrike, true)
160
0
                : (*localVolMatrix_)[localVolMatrix_->rows()/2][idx-1];
161
0
            const Real laterVol = localVolInterpol_[idx](laterStrike, true);
162
163
0
            return earlyVol
164
0
                    + (laterVol-earlyVol)/(times_[idx]-times_[idx-1])
165
0
                      *(t-times_[idx-1]);
166
0
        }
167
0
    }
168
169
}