/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 | | } |