24#ifndef quantlib_global_bootstrap_hpp
25#define quantlib_global_bootstrap_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);
87 std::vector<ext::shared_ptr<typename Traits::helper> > additionalHelpers,
88 ext::function<std::vector<Date>()> additionalDates,
89 ext::function<
Array()> additionalErrors,
91: ts_(nullptr), accuracy_(accuracy), additionalHelpers_(
std::move(additionalHelpers)),
92 additionalDates_(
std::move(additionalDates)), additionalErrors_(
std::move(additionalErrors)) {}
96 for (
Size j = 0; j < ts_->instruments_.size(); ++j)
97 ts_->registerWithObservables(ts_->instruments_[j]);
98 for (
Size j = 0; j < additionalHelpers_.size(); ++j)
99 ts_->registerWithObservables(additionalHelpers_[j]);
112 const Date firstDate = Traits::initialDate(ts_);
115 if (!ts_->instruments_.empty()) {
116 while (firstHelper_ < ts_->instruments_.size() && ts_->instruments_[firstHelper_]->pillarDate() <= firstDate)
119 numberHelpers_ = ts_->instruments_.size() - firstHelper_;
122 firstAdditionalHelper_ = 0;
123 if (!additionalHelpers_.empty()) {
124 while (firstAdditionalHelper_ < additionalHelpers_.size() &&
125 additionalHelpers_[firstAdditionalHelper_]->pillarDate() <= firstDate)
126 ++firstAdditionalHelper_;
128 numberAdditionalHelpers_ = additionalHelpers_.size() - firstAdditionalHelper_;
131 std::vector<Date> additionalDates;
132 if (additionalDates_)
133 additionalDates = additionalDates_();
134 if (!additionalDates.empty()) {
135 additionalDates.erase(
136 std::remove_if(additionalDates.begin(), additionalDates.end(),
137 [=](
const Date& date) { return date <= firstDate; }),
138 additionalDates.end()
141 const Size numberAdditionalDates = additionalDates.size();
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 dates.insert(dates.end(), additionalDates.begin(), additionalDates.end());
158 std::sort(dates.begin(), dates.end());
159 auto it = std::unique(dates.begin(), dates.end());
160 QL_REQUIRE(it == dates.end(),
"duplicate dates among alive instruments and additional dates");
164 for (
auto& date : dates)
165 times.push_back(ts_->timeFromReference(date));
168 Date maxDate = dates.back();
169 for (
Size j = 0; j < numberHelpers_; ++j) {
170 maxDate = std::max(ts_->instruments_[firstHelper_ + j]->latestRelevantDate(), maxDate);
172 ts_->maxDate_ = maxDate;
175 if (!validCurve_ || ts_->data_.size() != dates.size()) {
179 ts_->data_ = std::vector<Real>(dates.size(), Traits::initialValue(ts_));
191 if (!initialized_ || ts_->moving_)
195 for (
Size j = 0; j < numberHelpers_; ++j) {
196 const ext::shared_ptr<typename Traits::helper> &helper = ts_->instruments_[firstHelper_ + j];
199 <<
" instrument (maturity: " << helper->maturityDate()
200 <<
", pillar: " << helper->pillarDate() <<
") has an invalid quote");
204 helper->setTermStructure(
const_cast<Curve *
>(ts_));
208 for (
Size j = 0; j < numberAdditionalHelpers_; ++j) {
209 const ext::shared_ptr<typename Traits::helper> &helper = additionalHelpers_[firstAdditionalHelper_ + j];
211 <<
" additional instrument (maturity: " << helper->maturityDate()
212 <<
") has an invalid quote");
213 helper->setTermStructure(
const_cast<Curve *
>(ts_));
216 Real accuracy = accuracy_ !=
Null<Real>() ? accuracy_ : ts_->accuracy_;
219 Real optEps = accuracy;
225 ts_->interpolation_ =
226 ts_->interpolator_.interpolate(ts_->times_.begin(), ts_->times_.end(), ts_->data_.begin());
230 const Size numberBounds = ts_->times_.size() - 1;
231 std::vector<Real> lowerBounds(numberBounds), upperBounds(numberBounds);
232 for (
Size i = 0; i < numberBounds; ++i) {
234 lowerBounds[i] = Traits::minValueAfter(i + 1, ts_, validCurve_, 0);
235 upperBounds[i] = Traits::maxValueAfter(i + 1, ts_, validCurve_, 0);
241 TargetFunction(
const Size firstHelper,
242 const Size numberHelpers,
243 ext::function<
Array()> additionalErrors,
245 std::vector<Real> lowerBounds,
246 std::vector<Real> upperBounds)
247 : firstHelper_(firstHelper), numberHelpers_(numberHelpers),
248 additionalErrors_(std::move(additionalErrors)), ts_(ts),
249 lowerBounds_(std::move(lowerBounds)), upperBounds_(std::move(upperBounds)) {}
251 Real transformDirect(
const Real x,
const Size i)
const {
252 return (std::atan(x) +
M_PI_2) /
M_PI * (upperBounds_[i] - lowerBounds_[i]) + lowerBounds_[i];
256 return std::tan((
y - lowerBounds_[i]) *
M_PI / (upperBounds_[i] - lowerBounds_[i]) -
M_PI_2);
259 Real value(
const Array& x)
const override {
261 std::transform(
v.begin(),
v.end(),
v.begin(), [](
Real x) ->
Real { return x*x; });
262 return std::sqrt(std::accumulate(
v.begin(),
v.end(),
Real(0.0)) /
static_cast<Real>(
v.size()));
266 for (
Size i = 0; i < x.
size(); ++i) {
267 Traits::updateGuess(ts_->data_, transformDirect(x[i], i), i + 1);
269 ts_->interpolation_.update();
270 std::vector<Real> result(numberHelpers_);
271 for (
Size i = 0; i < numberHelpers_; ++i) {
272 result[i] = ts_->instruments_[firstHelper_ + i]->quote()->value() -
273 ts_->instruments_[firstHelper_ + i]->impliedQuote();
275 if (additionalErrors_) {
276 Array tmp = additionalErrors_();
277 result.resize(numberHelpers_ + tmp.
size());
278 for (
Size i = 0; i < tmp.
size(); ++i) {
279 result[numberHelpers_ + i] = tmp[i];
282 return Array(result.begin(), result.end());
286 Size firstHelper_, numberHelpers_;
287 ext::function<
Array()> additionalErrors_;
289 const std::vector<Real> lowerBounds_, upperBounds_;
291 TargetFunction cost(firstHelper_, numberHelpers_, additionalErrors_, ts_, lowerBounds, upperBounds);
294 Array guess(numberBounds);
295 for (
Size i = 0; i < numberBounds; ++i) {
297 guess[i] = cost.transformInverse(Traits::guess(i + 1, ts_, validCurve_, 0), i);
302 Problem problem(cost, noConstraint, guess);
312 "global bootstrap failed, error is " << finalTargetError <<
", accuracy is " << accuracy);
base helper class used for bootstrapping
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 numberAdditionalHelpers_
ext::function< Array()> additionalErrors_
ext::function< std::vector< Date >()> additionalDates_
GlobalBootstrap(Real accuracy=Null< Real >())
Curve::interpolator_type Interpolator
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
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Maps function, bind and cref to either the boost or std implementation.
detail::ordinal_holder ordinal(Size)
outputs naturals as 1st, 2nd, 3rd...
std::size_t Size
size of a container
Levenberg-Marquardt optimization method.
linear interpolation between discrete points
ext::shared_ptr< BlackVolTermStructure > v