27#ifndef quantlib_iterative_bootstrap_hpp
28#define quantlib_iterative_bootstrap_hpp
45 template <
class Curve>
49 QL_REQUIRE(xMin < xMax,
"Expected xMin to be less than xMax");
53 Real absError = std::abs(error(xMin));
54 Real minError = absError;
57 Real stepSize = (xMax - xMin) / steps;
58 for (
Size i = 0; i < steps; i++) {
62 absError = std::abs(error(xMin));
65 if (absError < minError) {
77 template <
class Curve>
79 typedef typename Curve::traits_type
Traits;
100 Real minFactor = 2.0,
101 bool dontThrow =
false,
102 Size dontThrowSteps = 10,
122 mutable std::vector<ext::shared_ptr<BootstrapError<Curve> > >
errors_;
128 template <
class Curve>
138 : accuracy_(accuracy), minValue_(minValue), maxValue_(maxValue), maxAttempts_(maxAttempts),
139 maxFactor_(maxFactor), minFactor_(minFactor), dontThrow_(dontThrow),
140 dontThrowSteps_(dontThrowSteps), ts_(nullptr), loopRequired_(
Interpolator::global) {
147 template <
class Curve>
150 n_ = ts_->instruments_.size();
151 QL_REQUIRE(n_ > 0,
"no bootstrap helpers given");
152 for (
Size j=0; j<n_; ++j)
153 ts_->registerWithObservables(ts_->instruments_[j]);
159 template <
class Curve>
162 std::sort(ts_->instruments_.begin(), ts_->instruments_.end(),
165 Date firstDate = Traits::initialDate(ts_);
166 QL_REQUIRE(ts_->instruments_[n_-1]->pillarDate()>firstDate,
167 "all instruments expired");
168 firstAliveHelper_ = 0;
169 while (ts_->instruments_[firstAliveHelper_]->pillarDate() <= firstDate)
171 alive_ = n_-firstAliveHelper_;
172 Size nodes = alive_+1;
173 QL_REQUIRE(nodes >= Interpolator::requiredPoints,
174 "not enough alive instruments: " << alive_ <<
175 " provided, " << Interpolator::requiredPoints-1 <<
179 std::vector<Date>& dates = ts_->dates_;
180 std::vector<Time>& times = ts_->times_;
181 dates.resize(alive_+1);
182 times.resize(alive_+1);
183 errors_.resize(alive_+1);
184 dates[0] = firstDate;
185 times[0] = ts_->timeFromReference(dates[0]);
187 Date latestRelevantDate, maxDate = firstDate;
190 for (
Size i=1, j=firstAliveHelper_; j<n_; ++i, ++j) {
191 const ext::shared_ptr<typename Traits::helper>& helper =
192 ts_->instruments_[j];
193 dates[i] = helper->pillarDate();
194 times[i] = ts_->timeFromReference(dates[i]);
197 "more than one instrument with pillar " << dates[i]);
199 latestRelevantDate = helper->latestRelevantDate();
204 dates[i] <<
") has latestRelevantDate (" <<
205 latestRelevantDate <<
") before or equal to "
206 "previous instrument's latestRelevantDate (" <<
208 maxDate = latestRelevantDate;
212 if (dates[i] != latestRelevantDate)
213 loopRequired_ =
true;
215 errors_[i] = ext::shared_ptr<BootstrapError<Curve> >(
new
218 ts_->maxDate_ = maxDate;
221 if (!validCurve_ || ts_->data_.size()!=alive_+1) {
225 ts_->data_ = std::vector<Real>(alive_+1, Traits::initialValue(ts_));
226 previousData_.resize(alive_+1);
232 template <
class Curve>
240 if (!initialized_ || ts_->moving_)
244 for (
Size j=firstAliveHelper_; j<n_; ++j) {
245 const ext::shared_ptr<typename Traits::helper>& helper =
246 ts_->instruments_[j];
250 helper->maturityDate() <<
", pillar: " <<
251 helper->pillarDate() <<
") has an invalid quote");
255 helper->setTermStructure(
const_cast<Curve*
>(ts_));
258 const std::vector<Time>& times = ts_->times_;
259 const std::vector<Real>& data = ts_->data_;
260 Real accuracy = accuracy_ !=
Null<Real>() ? accuracy_ : ts_->accuracy_;
262 Size maxIterations = Traits::maxIterations()-1;
265 bool validData = validCurve_;
267 for (
Size iteration=0; ; ++iteration) {
268 previousData_ = ts_->data_;
271 std::vector<Real> minValues(alive_+1,
Null<Real>());
272 std::vector<Real> maxValues(alive_+1,
Null<Real>());
273 std::vector<Size> attempts(alive_+1, 1);
275 for (
Size i=1; i<=alive_; ++i) {
278 Real& min = minValues[i];
279 Real& max = maxValues[i];
285 min = (minValue_ !=
Null<Real>() ? minValue_ :
286 Traits::minValueAfter(i, ts_, validData, firstAliveHelper_));
287 max = (maxValue_ !=
Null<Real>() ? maxValue_ :
288 Traits::maxValueAfter(i, ts_, validData, firstAliveHelper_));
292 min = (min < 0.0 ?
Real(min * minFactor_) :
Real(min / minFactor_));
294 max = (max > 0.0 ?
Real(max * maxFactor_) :
Real(max / maxFactor_));
296 Real guess = Traits::guess(i, ts_, validData, firstAliveHelper_);
300 guess = max - (max - min) / 5.0;
301 else if (guess <= min)
302 guess = min + (max - min) / 5.0;
308 ts_->interpolation_ = ts_->interpolator_.interpolate(
309 times.begin(), times.begin()+i+1, data.begin());
311 if (!Interpolator::global)
317 times.begin(), times.begin()+i+1, data.begin());
319 ts_->interpolation_.
update();
324 solver_.solve(*errors_[i], accuracy, guess, min, max);
326 firstSolver_.solve(*errors_[i], accuracy, guess, min, max);
327 }
catch (std::exception &e) {
335 validCurve_ = initialized_ =
false;
342 if (attempts[i] < maxAttempts_) {
354 ts_->interpolation_.update();
358 "pillar " << errors_[i]->helper()->pillarDate() <<
359 ", maturity " << errors_[i]->helper()->maturityDate() <<
360 ", reference date " << ts_->dates_[0] <<
370 Real change = std::fabs(data[1]-previousData_[1]);
371 for (
Size i=2; i<=alive_; ++i)
372 change = std::max(change, std::fabs(data[i]-previousData_[i]));
373 if (change<=accuracy)
377 if (iteration == maxIterations) {
381 QL_FAIL(
"convergence not reached after " << iteration <<
382 " iterations; last improvement " << change <<
383 ", required accuracy " << accuracy);
base helper class used for bootstrapping
safe Newton 1-D solver with finite difference derivatives
Universal piecewise-term-structure boostrapper.
std::vector< Real > previousData_
std::vector< ext::shared_ptr< BootstrapError< Curve > > > errors_
Curve::interpolator_type Interpolator
Curve::traits_type Traits
IterativeBootstrap(Real accuracy=Null< Real >(), Real minValue=Null< Real >(), Real maxValue=Null< Real >(), Size maxAttempts=1, Real maxFactor=2.0, Real minFactor=2.0, bool dontThrow=false, Size dontThrowSteps=10, Size maxEvaluations=MAX_FUNCTION_EVALUATIONS)
FiniteDifferenceNewtonSafe solver_
Linear-interpolation factory and traits
Interpolation interpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin) const
template class providing a null value for a given type.
void setMaxEvaluations(Size evaluations)
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Safe (bracketed) Newton 1-D solver with finite difference derivatives.
detail::ordinal_holder ordinal(Size)
outputs naturals as 1st, 2nd, 3rd...
std::size_t Size
size of a container
linear interpolation between discrete points
Real dontThrowFallback(const BootstrapError< Curve > &error, Real xMin, Real xMax, Size steps)
#define MAX_FUNCTION_EVALUATIONS