25#ifndef quantlib_global_bootstrap_hpp
26#define quantlib_global_bootstrap_hpp
28#include <ql/functional.hpp>
29#include <ql/math/interpolations/linearinterpolation.hpp>
30#include <ql/math/optimization/levenbergmarquardt.hpp>
31#include <ql/termstructures/bootstraperror.hpp>
32#include <ql/termstructures/bootstraphelper.hpp>
33#include <ql/utilities/dataformatters.hpp>
40 typedef typename Curve::traits_type
Traits;
61 GlobalBootstrap(std::vector<ext::shared_ptr<typename Traits::helper> > additionalHelpers,
62 ext::function<std::vector<Date>()> additionalDates,
63 ext::function<
Array()> additionalErrors,
65 void setup(Curve *ts);
89 std::vector<ext::shared_ptr<typename Traits::helper> > additionalHelpers,
90 ext::function<std::vector<Date>()> additionalDates,
91 ext::function<
Array()> additionalErrors,
93: ts_(nullptr), accuracy_(accuracy), additionalHelpers_(
std::move(additionalHelpers)),
94 additionalDates_(
std::move(additionalDates)), additionalErrors_(
std::move(additionalErrors)) {}
98 for (
Size j = 0; j < ts_->instruments_.size(); ++j)
99 ts_->registerWithObservables(ts_->instruments_[j]);
100 for (
Size j = 0; j < additionalHelpers_.size(); ++j)
101 ts_->registerWithObservables(additionalHelpers_[j]);
114 Date firstDate = Traits::initialDate(ts_);
117 if (!ts_->instruments_.empty()) {
118 while (firstHelper_ < ts_->instruments_.size() && ts_->instruments_[firstHelper_]->pillarDate() <= firstDate)
121 numberHelpers_ = ts_->instruments_.size() - firstHelper_;
124 firstAdditionalHelper_ = 0;
125 if (!additionalHelpers_.empty()) {
126 while (firstAdditionalHelper_ < additionalHelpers_.size() &&
127 additionalHelpers_[firstAdditionalHelper_]->pillarDate() <= firstDate)
128 ++firstAdditionalHelper_;
130 numberAdditionalHelpers_ = additionalHelpers_.size() - firstAdditionalHelper_;
133 std::vector<Date> additionalDates;
134 if (additionalDates_)
135 additionalDates = additionalDates_();
136 firstAdditionalDate_ = 0;
137 if (!additionalDates.empty()) {
138 while (firstAdditionalDate_ < additionalDates.size() && additionalDates[firstAdditionalDate_] <= firstDate)
139 ++firstAdditionalDate_;
141 numberAdditionalDates_ = additionalDates.size() - firstAdditionalDate_;
143 QL_REQUIRE(numberHelpers_ + numberAdditionalDates_ >= Interpolator::requiredPoints - 1,
144 "not enough alive instruments (" << numberHelpers_ <<
") + additional dates (" << numberAdditionalDates_
145 <<
") = " << numberHelpers_ + numberAdditionalDates_ <<
" provided, "
146 << Interpolator::requiredPoints - 1 <<
" required");
149 std::vector<Date> &dates = ts_->dates_;
150 std::vector<Time> × = ts_->times_;
154 dates.push_back(firstDate);
155 for (
Size j = 0; j < numberHelpers_; ++j)
156 dates.push_back(ts_->instruments_[firstHelper_ + j]->pillarDate());
157 for (
Size j = firstAdditionalDate_; j < numberAdditionalDates_; ++j)
158 dates.push_back(additionalDates[firstAdditionalDate_ + j]);
159 std::sort(dates.begin(), dates.end());
160 auto it = std::unique(dates.begin(), dates.end());
161 QL_REQUIRE(it == dates.end(),
"duplicate dates among alive instruments and additional dates");
165 for (
auto& date : dates)
166 times.push_back(ts_->timeFromReference(date));
169 Date maxDate = firstDate;
170 for (
Size j = 0; j < numberHelpers_; ++j) {
171 maxDate = std::max(ts_->instruments_[firstHelper_ + j]->latestRelevantDate(), maxDate);
173 for (
Size j = 0; j < numberAdditionalDates_; ++j) {
174 maxDate = std::max(additionalDates[firstAdditionalDate_ + j], maxDate);
176 ts_->maxDate_ = maxDate;
179 if (!validCurve_ || ts_->data_.size() != dates.size()) {
183 ts_->data_ = std::vector<Real>(dates.size(), Traits::initialValue(ts_));
195 if (!initialized_ || ts_->moving_)
199 for (
Size j = 0; j < numberHelpers_; ++j) {
200 const ext::shared_ptr<typename Traits::helper> &helper = ts_->instruments_[firstHelper_ + j];
202 QL_REQUIRE(helper->quote()->isValid(),
io::ordinal(j + 1)
203 <<
" instrument (maturity: " << helper->maturityDate()
204 <<
", pillar: " << helper->pillarDate() <<
") has an invalid quote");
208 helper->setTermStructure(
const_cast<Curve *
>(ts_));
212 for (
Size j = 0; j < numberAdditionalHelpers_; ++j) {
213 const ext::shared_ptr<typename Traits::helper> &helper = additionalHelpers_[firstAdditionalHelper_ + j];
214 QL_REQUIRE(helper->quote()->isValid(),
io::ordinal(j + 1)
215 <<
" additional instrument (maturity: " << helper->maturityDate()
216 <<
") has an invalid quote");
217 helper->setTermStructure(
const_cast<Curve *
>(ts_));
220 Real accuracy = accuracy_ !=
Null<Real>() ? accuracy_ : ts_->accuracy_;
223 Real optEps = accuracy;
229 ts_->interpolation_ =
230 ts_->interpolator_.interpolate(ts_->times_.begin(), ts_->times_.end(), ts_->data_.begin());
234 std::vector<Real> lowerBounds(numberHelpers_ + numberAdditionalDates_),
235 upperBounds(numberHelpers_ + numberAdditionalDates_);
236 for (
Size i = 0; i < numberHelpers_ + numberAdditionalDates_; ++i) {
238 lowerBounds[i] = Traits::minValueAfter(i + 1, ts_, validCurve_, 0);
239 upperBounds[i] = Traits::maxValueAfter(i + 1, ts_, validCurve_, 0);
245 TargetFunction(
const Size firstHelper,
246 const Size numberHelpers,
247 ext::function<
Array()> additionalErrors,
249 std::vector<Real> lowerBounds,
250 std::vector<Real> upperBounds)
251 : firstHelper_(firstHelper), numberHelpers_(numberHelpers),
252 additionalErrors_(std::move(additionalErrors)), ts_(ts),
253 lowerBounds_(std::move(lowerBounds)), upperBounds_(std::move(upperBounds)) {}
255 Real transformDirect(
const Real x,
const Size i)
const {
256 return (std::atan(x) + M_PI_2) / M_PI * (upperBounds_[i] - lowerBounds_[i]) + lowerBounds_[i];
259 Real transformInverse(
const Real y,
const Size i)
const {
260 return std::tan((y - lowerBounds_[i]) * M_PI / (upperBounds_[i] - lowerBounds_[i]) - M_PI_2);
263 Real value(
const Array& x)
const override {
265 std::transform(v.begin(), v.end(), v.begin(), [](
Real x) ->
Real { return x*x; });
266 return std::sqrt(std::accumulate(v.begin(), v.end(),
Real(0.0)) /
static_cast<Real>(v.size()));
270 for (
Size i = 0; i < x.
size(); ++i) {
271 Traits::updateGuess(ts_->data_, transformDirect(x[i], i), i + 1);
273 ts_->interpolation_.update();
274 std::vector<Real> result(numberHelpers_);
275 for (
Size i = 0; i < numberHelpers_; ++i) {
276 result[i] = ts_->instruments_[firstHelper_ + i]->quote()->value() -
277 ts_->instruments_[firstHelper_ + i]->impliedQuote();
279 if (additionalErrors_) {
280 Array tmp = additionalErrors_();
281 result.resize(numberHelpers_ + tmp.
size());
282 for (
Size i = 0; i < tmp.
size(); ++i) {
283 result[numberHelpers_ + i] = tmp[i];
286 return Array(result.begin(), result.end());
290 Size firstHelper_, numberHelpers_;
291 ext::function<
Array()> additionalErrors_;
293 const std::vector<Real> lowerBounds_, upperBounds_;
295 TargetFunction cost(firstHelper_, numberHelpers_, additionalErrors_, ts_, lowerBounds, upperBounds);
298 Array guess(numberHelpers_ + numberAdditionalDates_);
299 for (
Size i = 0; i < guess.
size(); ++i) {
301 guess[i] = cost.transformInverse(Traits::guess(i + 1, ts_, validCurve_, 0), i);
306 Problem problem(cost, noConstraint, guess);
315 QL_REQUIRE(finalTargetError <= accuracy,
316 "global bootstrap failed, error is " << finalTargetError <<
", accuracy is " << accuracy);
1-D array used in linear algebra.
Size size() const
dimension of the array
Cost function abstract class for optimization problem.
Criteria to end optimization process:
Global boostrapper, with additional restrictions.
Size numberAdditionalDates_
Size numberAdditionalHelpers_
ext::function< Array()> additionalErrors_
ext::function< std::vector< Date >()> additionalDates_
GlobalBootstrap(Real accuracy=Null< Real >())
Size firstAdditionalDate_
Curve::interpolator_type Interpolator
std::vector< Real > lowerBounds_
std::vector< Real > upperBounds_
Curve::traits_type Traits
Size firstAdditionalHelper_
std::vector< ext::shared_ptr< typename Traits::helper > > additionalHelpers_
Levenberg-Marquardt optimization method.
EndCriteria::Type minimize(Problem &P, const EndCriteria &endCriteria) override
minimize the optimization problem P
template class providing a null value for a given type.
Constrained optimization problem.
const Array & currentValue() const
current value of the local minimum
detail::ordinal_holder ordinal(Size)
outputs naturals as 1st, 2nd, 3rd...
std::size_t Size
size of a container