/src/quantlib/ql/models/volatility/garch.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) 2006 Joseph Wang |
5 | | Copyright (C) 2012 Liquidnet Holdings, Inc. |
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 | | <https://www.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 | | /*! \file garch.hpp |
22 | | \brief GARCH volatility model |
23 | | */ |
24 | | |
25 | | #ifndef quantlib_garch_volatility_model_hpp |
26 | | #define quantlib_garch_volatility_model_hpp |
27 | | |
28 | | #include <ql/volatilitymodel.hpp> |
29 | | #include <ql/math/optimization/problem.hpp> |
30 | | #include <ql/math/optimization/constraint.hpp> |
31 | | #include <vector> |
32 | | |
33 | | namespace QuantLib { |
34 | | |
35 | | //! GARCH volatility model |
36 | | /*! Volatilities are assumed to be expressed on an annual basis. |
37 | | */ |
38 | | class Garch11 : public VolatilityCompositor { |
39 | | public: |
40 | | typedef TimeSeries<Volatility> time_series; |
41 | | |
42 | | enum Mode { |
43 | | MomentMatchingGuess, /*!< The initial guess is a moment |
44 | | matching estimates for |
45 | | mean(r2), acf(0), and acf(1). */ |
46 | | GammaGuess, /*!< The initial guess is an |
47 | | estimate of gamma based on the |
48 | | property: |
49 | | acf(i+1) = gamma*acf(i) for i > 1. */ |
50 | | BestOfTwo, /*!< The best of the two above modes */ |
51 | | DoubleOptimization /*!< Double optimization */ |
52 | | }; |
53 | | |
54 | | //! \name Constructors |
55 | | //@{ |
56 | | Garch11(Real a, Real b, Real vl) |
57 | | : alpha_(a), beta_(b), gamma_(1 - a - b), |
58 | 0 | vl_(vl), logLikelihood_(0), mode_(BestOfTwo) {} |
59 | | |
60 | | Garch11(const time_series& qs, Mode mode = BestOfTwo) |
61 | 0 | : alpha_(0), beta_(0), vl_(0), logLikelihood_(0), mode_(mode) { |
62 | 0 | calibrate(qs); |
63 | 0 | }; |
64 | | //@} |
65 | | |
66 | | //! \name Inspectors |
67 | | //@{ |
68 | 0 | Real alpha() const { return alpha_; } |
69 | 0 | Real beta() const { return beta_; } |
70 | 0 | Real omega() const { return vl_ * gamma_; } |
71 | 0 | Real ltVol() const { return vl_; } |
72 | 0 | Real logLikelihood() const { return logLikelihood_; } |
73 | 0 | Mode mode() const { return mode_; } |
74 | | //@} |
75 | | |
76 | | //! \name VolatilityCompositor interface |
77 | | //@{ |
78 | 0 | time_series calculate(const time_series& quoteSeries) override { |
79 | 0 | return calculate(quoteSeries, alpha(), beta(), omega()); |
80 | 0 | } |
81 | 0 | void calibrate(const time_series& quoteSeries) override { |
82 | 0 | const auto values = quoteSeries.values(); |
83 | 0 | calibrate(values.cbegin(), values.cend()); |
84 | 0 | } |
85 | | //@} |
86 | | |
87 | | //! \name Additional interface |
88 | | //@{ |
89 | | static time_series calculate(const time_series& quoteSeries, |
90 | | Real alpha, Real beta, Real omega); |
91 | | |
92 | | void calibrate(const time_series& quoteSeries, |
93 | | OptimizationMethod& method, |
94 | 0 | const EndCriteria& endCriteria) { |
95 | 0 | const auto values = quoteSeries.values(); |
96 | 0 | calibrate(values.cbegin(), values.cend(), |
97 | 0 | method, endCriteria); |
98 | 0 | } |
99 | | |
100 | | void calibrate(const time_series& quoteSeries, |
101 | | OptimizationMethod& method, |
102 | | const EndCriteria& endCriteria, |
103 | 0 | const Array& initialGuess) { |
104 | 0 | const auto values = quoteSeries.values(); |
105 | 0 | calibrate(values.cbegin(), values.cend(), |
106 | 0 | method, endCriteria, initialGuess); |
107 | 0 | } |
108 | | |
109 | | template <typename ForwardIterator> |
110 | 0 | void calibrate(ForwardIterator begin, ForwardIterator end) { |
111 | 0 | std::vector<Volatility> r2; |
112 | 0 | Real mean_r2 = to_r2(begin, end, r2); |
113 | 0 | ext::shared_ptr<Problem> p = |
114 | 0 | calibrate_r2(mode_, r2, mean_r2, alpha_, beta_, vl_); |
115 | 0 | gamma_ = 1 - alpha_ - beta_; |
116 | 0 | vl_ /= gamma_; |
117 | 0 | logLikelihood_ = p ? -p->functionValue() : |
118 | 0 | -costFunction(begin, end); |
119 | 0 | } |
120 | | |
121 | | template <typename ForwardIterator> |
122 | | void calibrate(ForwardIterator begin, ForwardIterator end, |
123 | | OptimizationMethod& method, |
124 | 0 | EndCriteria endCriteria) { |
125 | 0 | std::vector<Volatility> r2; |
126 | 0 | Real mean_r2 = to_r2(begin, end, r2); |
127 | 0 | ext::shared_ptr<Problem> p = |
128 | 0 | calibrate_r2(mode_, r2, mean_r2, method, |
129 | 0 | endCriteria, alpha_, beta_, vl_); |
130 | 0 | gamma_ = 1 - alpha_ - beta_; |
131 | 0 | vl_ /= gamma_; |
132 | 0 | logLikelihood_ = p ? -p->functionValue() : |
133 | 0 | -costFunction(begin, end); |
134 | 0 | } |
135 | | |
136 | | template <typename ForwardIterator> |
137 | | void calibrate(ForwardIterator begin, ForwardIterator end, |
138 | | OptimizationMethod& method, |
139 | | EndCriteria endCriteria, |
140 | 0 | const Array& initialGuess) { |
141 | 0 | std::vector<Volatility> r2; |
142 | 0 | to_r2(begin, end, r2); |
143 | 0 | ext::shared_ptr<Problem> p = |
144 | 0 | calibrate_r2(r2, method, endCriteria, initialGuess, |
145 | 0 | alpha_, beta_, vl_); |
146 | 0 | gamma_ = 1 - alpha_ - beta_; |
147 | 0 | vl_ /= gamma_; |
148 | 0 | logLikelihood_ = p ? -p->functionValue() : |
149 | 0 | -costFunction(begin, end); |
150 | 0 | } |
151 | | |
152 | 0 | Real forecast(Real r, Real sigma2) const { |
153 | 0 | return gamma_* vl_ + alpha_ * r * r + beta_ * sigma2; |
154 | 0 | } |
155 | | |
156 | | // a helper for calculation of r^2 and <r^2> |
157 | | template <typename InputIterator> |
158 | | static Real to_r2(InputIterator begin, InputIterator end, |
159 | 0 | std::vector<Volatility>& r2) { |
160 | 0 | Real u2(0.0), mean_r2(0.0), w(1.0); |
161 | 0 | for (; begin != end; ++begin) { |
162 | 0 | u2 = *begin; u2 *= u2; |
163 | 0 | mean_r2 = (1.0 - w) * mean_r2 + w * u2; |
164 | 0 | r2.push_back(u2); |
165 | 0 | w /= (w + 1.0); |
166 | 0 | } |
167 | 0 | return mean_r2; |
168 | 0 | } |
169 | | |
170 | | /*! calibrates GARCH for r^2 */ |
171 | | static ext::shared_ptr<Problem> calibrate_r2( |
172 | | Mode mode, |
173 | | const std::vector<Volatility>& r2, |
174 | | Real mean_r2, |
175 | | Real& alpha, |
176 | | Real& beta, |
177 | | Real& omega); |
178 | | |
179 | | /*! calibrates GARCH for r^2 with user-defined optimization |
180 | | method and end criteria */ |
181 | | static ext::shared_ptr<Problem> calibrate_r2( |
182 | | Mode mode, |
183 | | const std::vector<Volatility>& r2, |
184 | | Real mean_r2, |
185 | | OptimizationMethod& method, |
186 | | const EndCriteria& endCriteria, |
187 | | Real& alpha, |
188 | | Real& beta, |
189 | | Real& omega); |
190 | | |
191 | | /*! calibrates GARCH for r^2 with user-defined optimization |
192 | | method, end criteria and initial guess */ |
193 | | static ext::shared_ptr<Problem> calibrate_r2( |
194 | | const std::vector<Volatility>& r2, |
195 | | Real mean_r2, |
196 | | OptimizationMethod& method, |
197 | | const EndCriteria& endCriteria, |
198 | | const Array& initialGuess, |
199 | | Real& alpha, |
200 | | Real& beta, |
201 | | Real& omega); |
202 | | |
203 | | /*! calibrates GARCH for r^2 with user-defined optimization |
204 | | method, end criteria and initial guess */ |
205 | | static ext::shared_ptr<Problem> calibrate_r2( |
206 | | const std::vector<Volatility> &r2, |
207 | | OptimizationMethod& method, |
208 | | const EndCriteria& endCriteria, |
209 | | const Array& initialGuess, |
210 | | Real& alpha, |
211 | | Real& beta, |
212 | | Real& omega); |
213 | | |
214 | | /*! calibrates GARCH for r^2 with user-defined optimization |
215 | | method, end criteria, constraints and initial guess */ |
216 | | static ext::shared_ptr<Problem> calibrate_r2( |
217 | | const std::vector<Volatility>& r2, |
218 | | Real mean_r2, |
219 | | OptimizationMethod& method, |
220 | | Constraint& constraints, |
221 | | const EndCriteria& endCriteria, |
222 | | const Array& initialGuess, |
223 | | Real& alpha, |
224 | | Real& beta, |
225 | | Real& omega); |
226 | | |
227 | | static ext::shared_ptr<Problem> calibrate_r2( |
228 | | const std::vector<Volatility> &r2, |
229 | | OptimizationMethod& method, |
230 | | Constraint& constraints, |
231 | | const EndCriteria& endCriteria, |
232 | | const Array& initialGuess, |
233 | | Real& alpha, |
234 | | Real& beta, |
235 | | Real& omega); |
236 | | |
237 | | template<class InputIterator> |
238 | | static Real costFunction(InputIterator begin, InputIterator end, |
239 | 0 | Real alpha, Real beta, Real omega) { |
240 | 0 | Real retval(0.0); |
241 | 0 | Real u2(0.0), sigma2(0.0); |
242 | 0 | Size N = 0; |
243 | 0 | for (; begin != end; ++begin, ++N) { |
244 | 0 | sigma2 = omega + alpha * u2 + beta * sigma2; |
245 | 0 | u2 = *begin; u2 *= u2; |
246 | 0 | retval += std::log(sigma2) + u2 / sigma2; |
247 | 0 | } |
248 | 0 | return N > 0 ? Real(retval / (2*N)) : 0.0; |
249 | 0 | } |
250 | | //@} |
251 | | private: |
252 | | Real alpha_, beta_, gamma_, vl_; |
253 | | Real logLikelihood_; |
254 | | Mode mode_; |
255 | | |
256 | | template<class InputIterator> |
257 | 0 | Real costFunction(InputIterator begin, InputIterator end) const { |
258 | 0 | return costFunction(begin, end, alpha(), beta(), omega()); |
259 | 0 | } |
260 | | }; |
261 | | |
262 | | } |
263 | | |
264 | | |
265 | | #endif |