1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2013, 2015 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 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the license for more details.
18*/
19
20#include <ql/models/shortrate/onefactormodels/gsr.hpp>
21#include <ql/quotes/simplequote.hpp>
22#include <utility>
23
24namespace QuantLib {
25
26 Gsr::Gsr(const Handle<YieldTermStructure>& termStructure,
27 std::vector<Date> volstepdates,
28 const std::vector<Real>& volatilities,
29 const Real reversion,
30 const Real T)
31 : Gaussian1dModel(termStructure), CalibratedModel(2), reversion_(arguments_[0]),
32 sigma_(arguments_[1]), volstepdates_(std::move(volstepdates)) {
33
34 QL_REQUIRE(!termStructure.empty(), "yield term structure handle is empty");
35
36 volatilities_.resize(new_size: volatilities.size());
37 for (Size i = 0; i < volatilities.size(); ++i)
38 volatilities_[i] = Handle<Quote>(ext::make_shared<SimpleQuote>(args: volatilities[i]));
39 reversions_.resize(new_size: 1);
40 reversions_[0] = Handle<Quote>(ext::make_shared<SimpleQuote>(args: reversion));
41
42 initialize(T);
43 }
44
45 Gsr::Gsr(const Handle<YieldTermStructure>& termStructure,
46 std::vector<Date> volstepdates,
47 const std::vector<Real>& volatilities,
48 const std::vector<Real>& reversions,
49 const Real T)
50 : Gaussian1dModel(termStructure), CalibratedModel(2), reversion_(arguments_[0]),
51 sigma_(arguments_[1]), volstepdates_(std::move(volstepdates)) {
52
53 QL_REQUIRE(!termStructure.empty(), "yield term structure handle is empty");
54
55 volatilities_.resize(new_size: volatilities.size());
56 for (Size i = 0; i < volatilities.size(); ++i)
57 volatilities_[i] = Handle<Quote>(ext::make_shared<SimpleQuote>(args: volatilities[i]));
58 reversions_.resize(new_size: reversions.size());
59 for (Size i = 0; i < reversions.size(); ++i)
60 reversions_[i] = Handle<Quote>(ext::make_shared<SimpleQuote>(args: reversions[i]));
61
62 initialize(T);
63 }
64
65 Gsr::Gsr(const Handle<YieldTermStructure>& termStructure,
66 std::vector<Date> volstepdates,
67 std::vector<Handle<Quote> > volatilities,
68 const Handle<Quote>& reversion,
69 const Real T)
70 : Gaussian1dModel(termStructure), CalibratedModel(2), reversion_(arguments_[0]),
71 sigma_(arguments_[1]), volatilities_(std::move(volatilities)),
72 reversions_(std::vector<Handle<Quote> >(1, reversion)),
73 volstepdates_(std::move(volstepdates)) {
74
75 QL_REQUIRE(!termStructure.empty(), "yield term structure handle is empty");
76 initialize(T);
77 }
78
79 Gsr::Gsr(const Handle<YieldTermStructure>& termStructure,
80 std::vector<Date> volstepdates,
81 std::vector<Handle<Quote> > volatilities,
82 std::vector<Handle<Quote> > reversions,
83 const Real T)
84 : Gaussian1dModel(termStructure), CalibratedModel(2), reversion_(arguments_[0]),
85 sigma_(arguments_[1]), volatilities_(std::move(volatilities)),
86 reversions_(std::move(reversions)), volstepdates_(std::move(volstepdates)) {
87
88 QL_REQUIRE(!termStructure.empty(), "yield term structure handle is empty");
89 initialize(T);
90 }
91
92void Gsr::update() {
93 if (stateProcess_ != nullptr)
94 ext::static_pointer_cast<GsrProcess>(r: stateProcess_)->flushCache();
95 LazyObject::update();
96}
97
98void Gsr::updateTimes() const {
99 volsteptimes_.clear();
100 int j = 0;
101 for (auto i = volstepdates_.begin(); i != volstepdates_.end(); ++i, ++j) {
102 volsteptimes_.push_back(x: termStructure()->timeFromReference(d: *i));
103 volsteptimesArray_[j] = volsteptimes_[j];
104 if (j == 0)
105 QL_REQUIRE(volsteptimes_[0] > 0.0, "volsteptimes must be positive ("
106 << volsteptimes_[0] << ")");
107 else
108 QL_REQUIRE(volsteptimes_[j] > volsteptimes_[j - 1],
109 "volsteptimes must be strictly increasing ("
110 << volsteptimes_[j - 1] << "@" << (j - 1) << ", "
111 << volsteptimes_[j] << "@" << j << ")");
112 }
113 if (stateProcess_ != nullptr)
114 ext::static_pointer_cast<GsrProcess>(r: stateProcess_)->flushCache();
115}
116
117void Gsr::updateVolatility() {
118 for (Size i = 0; i < sigma_.size(); i++) {
119 sigma_.setParam(i, x: volatilities_[i]->value());
120 }
121 update();
122}
123
124void Gsr::updateReversion() {
125 for (Size i = 0; i < reversion_.size(); i++) {
126 reversion_.setParam(i, x: reversions_[i]->value());
127 }
128 update();
129}
130
131void Gsr::initialize(Real T) {
132
133 volsteptimesArray_ = Array(volstepdates_.size());
134
135 updateTimes();
136
137 QL_REQUIRE(volatilities_.size() == volsteptimes_.size() + 1,
138 "there must be n+1 volatilities ("
139 << volatilities_.size() << ") for n volatility step times ("
140 << volsteptimes_.size() << ")");
141
142 QL_REQUIRE(reversions_.size() == 1 ||
143 reversions_.size() == volsteptimes_.size() + 1,
144 "there must be 1 or n+1 reversions ("
145 << reversions_.size() << ") for n volatility step times ("
146 << volsteptimes_.size() << ")");
147 if (reversions_.size() == 1) {
148 reversion_ = ConstantParameter(reversions_[0]->value(), NoConstraint());
149 } else {
150 reversion_ = PiecewiseConstantParameter(volsteptimes_, NoConstraint());
151 for (Size i = 0; i < reversion_.size(); i++) {
152 reversion_.setParam(i, x: reversions_[i]->value());
153 }
154 }
155
156 // sigma_ =
157 // PiecewiseConstantParameter(volsteptimes_,PositiveConstraint());
158 sigma_ = PiecewiseConstantParameter(volsteptimes_, NoConstraint());
159 for (Size i = 0; i < sigma_.size(); i++) {
160 sigma_.setParam(i, x: volatilities_[i]->value());
161 }
162
163 stateProcess_ = ext::make_shared<GsrProcess>(
164 args&: volsteptimesArray_, args: sigma_.params(), args: reversion_.params(), args&: T);
165
166 registerWith(h: termStructure());
167
168 registerWith(h: stateProcess_);
169
170 volatilityObserver_ = ext::make_shared<VolatilityObserver>(args: this);
171 reversionObserver_ = ext::make_shared<ReversionObserver>(args: this);
172
173 for (auto& reversion : reversions_)
174 reversionObserver_->registerWith(h: reversion);
175
176 for (auto& volatilitie : volatilities_)
177 volatilityObserver_->registerWith(h: volatilitie);
178}
179
180Real Gsr::zerobondImpl(const Time T, const Time t, const Real y,
181 const Handle<YieldTermStructure> &yts) const {
182
183 calculate();
184
185 if (t == 0.0)
186 return yts.empty() ? this->termStructure()->discount(t: T, extrapolate: true)
187 : yts->discount(t: T, extrapolate: true);
188
189 ext::shared_ptr<GsrProcess> p =
190 ext::dynamic_pointer_cast<GsrProcess>(r: stateProcess_);
191
192 Real x = y * stateProcess_->stdDeviation(t0: 0.0, x0: 0.0, dt: t) +
193 stateProcess_->expectation(t0: 0.0, x0: 0.0, dt: t);
194 Real gtT = p->G(t, T, x);
195
196 Real d = yts.empty()
197 ? termStructure()->discount(t: T, extrapolate: true) /
198 termStructure()->discount(t, extrapolate: true)
199 : yts->discount(t: T, extrapolate: true) / yts->discount(t, extrapolate: true);
200
201 return d * exp(x: -x * gtT - 0.5 * p->y(t) * gtT * gtT);
202}
203
204Real Gsr::numeraireImpl(const Time t, const Real y,
205 const Handle<YieldTermStructure> &yts) const {
206
207 calculate();
208
209 ext::shared_ptr<GsrProcess> p =
210 ext::dynamic_pointer_cast<GsrProcess>(r: stateProcess_);
211
212 if (t == 0)
213 return yts.empty()
214 ? this->termStructure()->discount(t: p->getForwardMeasureTime(),
215 extrapolate: true)
216 : yts->discount(t: p->getForwardMeasureTime());
217 return zerobond(T: p->getForwardMeasureTime(), t, y, yts);
218}
219}
220

source code of quantlib/ql/models/shortrate/onefactormodels/gsr.cpp