Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Types | Private Member Functions | Private Attributes | List of all members
IterativeBootstrap< Curve > Class Template Reference

#include <qle/termstructures/iterativebootstrap.hpp>

+ Inheritance diagram for IterativeBootstrap< Curve >:
+ Collaboration diagram for IterativeBootstrap< Curve >:

Public Member Functions

 IterativeBootstrap (QuantLib::Real accuracy=QuantLib::Null< QuantLib::Real >(), QuantLib::Real globalAccuracy=QuantLib::Null< QuantLib::Real >(), bool dontThrow=false, QuantLib::Size maxAttempts=1, QuantLib::Real maxFactor=2.0, QuantLib::Real minFactor=2.0, QuantLib::Size dontThrowSteps=10)
 
void setup (Curve *ts)
 
void calculate () const
 

Private Types

typedef Curve::traits_type Traits
 
typedef Curve::interpolator_type Interpolator
 

Private Member Functions

void initialize () const
 

Private Attributes

Curve * ts_
 
QuantLib::Size n_
 
QuantLib::Brent firstSolver_
 
QuantLib::FiniteDifferenceNewtonSafe solver_
 
bool initialized_
 
bool validCurve_
 
bool loopRequired_
 
QuantLib::Size firstAliveHelper_
 
QuantLib::Size alive_
 
std::vector< QuantLib::Real > previousData_
 
std::vector< QuantLib::ext::shared_ptr< QuantLib::BootstrapError< Curve > > > errors_
 
QuantLib::Real accuracy_
 
QuantLib::Real globalAccuracy_
 
bool dontThrow_
 
QuantLib::Size maxAttempts_
 
QuantLib::Real maxFactor_
 
QuantLib::Real minFactor_
 
QuantLib::Size dontThrowSteps_
 

Detailed Description

template<class Curve>
class QuantExt::IterativeBootstrap< Curve >

Straight copy of QuantLib::IterativeBootstrap with the following modifications

Definition at line 77 of file iterativebootstrap.hpp.

Member Typedef Documentation

◆ Traits

typedef Curve::traits_type Traits
private

Definition at line 78 of file iterativebootstrap.hpp.

◆ Interpolator

typedef Curve::interpolator_type Interpolator
private

Definition at line 79 of file iterativebootstrap.hpp.

Constructor & Destructor Documentation

◆ IterativeBootstrap()

IterativeBootstrap ( QuantLib::Real  accuracy = QuantLib::Null<QuantLib::Real>(),
QuantLib::Real  globalAccuracy = QuantLib::Null<QuantLib::Real>(),
bool  dontThrow = false,
QuantLib::Size  maxAttempts = 1,
QuantLib::Real  maxFactor = 2.0,
QuantLib::Real  minFactor = 2.0,
QuantLib::Size  dontThrowSteps = 10 
)

Constructor

Parameters
accuracyAccuracy for the bootstrap. If Null<Real>(), its value is taken from the termstructure's accuracy.
globalAccuracyAccuracy for the global bootstrap stopping criterion. If it is set to Null<Real>(), its value is taken from the termstructure's accuracy.
dontThrowIf set to true, the bootstrap doesn't throw and returns a fall back result
maxAttemptsNumber of attempts on each iteration. A number greater than implies retries.
maxFactorFactor for max value retry on each iteration if there is a failure.
minFactorFactor for min value retry on each iteration if there is a failure.
dontThrowStepsIf dontThrow is true, this gives the number of steps to use when searching for a fallback curve pillar value that gives the minimum bootstrap helper error.

Definition at line 123 of file iterativebootstrap.hpp.

126 : ts_(0), n_(0), initialized_(false), validCurve_(false), loopRequired_(Interpolator::global),
127 firstAliveHelper_(0), alive_(0), accuracy_(accuracy), globalAccuracy_(globalAccuracy), dontThrow_(dontThrow),
128 maxAttempts_(maxAttempts), maxFactor_(maxFactor), minFactor_(minFactor), dontThrowSteps_(dontThrowSteps) {}

Member Function Documentation

◆ setup()

void setup ( Curve *  ts)

Definition at line 130 of file iterativebootstrap.hpp.

130 {
131 ts_ = ts;
132 n_ = ts_->instruments_.size();
133 QL_REQUIRE(n_ > 0, "no bootstrap helpers given");
134 for (QuantLib::Size j = 0; j < n_; ++j)
135 ts_->registerWith(ts_->instruments_[j]);
136}

◆ calculate()

void calculate

Definition at line 207 of file iterativebootstrap.hpp.

207 {
208
209 // we might have to call initialize even if the curve is initialized
210 // and not moving, just because helpers might be date relative and change
211 // with evaluation date change.
212 // anyway it makes little sense to use date relative helpers with a
213 // non-moving curve if the evaluation date changes
214 if (!initialized_ || ts_->moving_)
215 initialize();
216
217 // setup helpers
218 for (QuantLib::Size j = firstAliveHelper_; j < n_; ++j) {
219 const QuantLib::ext::shared_ptr<typename Traits::helper>& helper = ts_->instruments_[j];
220
221 // check for valid quote
222 QL_REQUIRE(helper->quote()->isValid(), QuantLib::io::ordinal(j + 1)
223 << " instrument (maturity: " << helper->maturityDate()
224 << ", pillar: " << helper->pillarDate() << ") has an invalid quote");
225
226 // don't try this at home!
227 // This call creates helpers, and removes "const".
228 // There is a significant interaction with observability.
229 helper->setTermStructure(const_cast<Curve*>(ts_));
230 }
231
232 const std::vector<QuantLib::Time>& times = ts_->times_;
233 const std::vector<QuantLib::Real>& data = ts_->data_;
234 QuantLib::Real accuracy = accuracy_ != QuantLib::Null<QuantLib::Real>() ? accuracy_ : ts_->accuracy_;
235 QuantLib::Real globalAccuracy = globalAccuracy_ == QuantLib::Null<QuantLib::Real>() ? accuracy : globalAccuracy_;
236
237 QuantLib::Size maxIterations = Traits::maxIterations() - 1;
238
239 // there might be a valid curve state to use as guess
240 bool validData = validCurve_;
241
242 for (QuantLib::Size iteration = 0;; ++iteration) {
243 previousData_ = ts_->data_;
244
245 std::vector<QuantLib::Real> minValues(alive_, QuantLib::Null<QuantLib::Real>());
246 std::vector<QuantLib::Real> maxValues(alive_, QuantLib::Null<QuantLib::Real>());
247 std::vector<QuantLib::Size> attempts(alive_, 1);
248
249 for (QuantLib::Size i = 1; i <= alive_; ++i) {
250
251 // bracket root and calculate guess
252 if (minValues[i - 1] == QuantLib::Null<QuantLib::Real>()) {
253 minValues[i - 1] = Traits::minValueAfter(i, ts_, validData, firstAliveHelper_);
254 } else {
255 minValues[i - 1] =
256 minValues[i - 1] < 0.0 ? minFactor_ * minValues[i - 1] : minValues[i - 1] / minFactor_;
257 }
258 if (maxValues[i - 1] == QuantLib::Null<QuantLib::Real>()) {
259 maxValues[i - 1] = Traits::maxValueAfter(i, ts_, validData, firstAliveHelper_);
260 } else {
261 maxValues[i - 1] =
262 maxValues[i - 1] > 0.0 ? maxFactor_ * maxValues[i - 1] : maxValues[i - 1] / maxFactor_;
263 }
264 QuantLib::Real guess = Traits::guess(i, ts_, validData, firstAliveHelper_);
265
266 // adjust guess if needed
267 if (guess >= maxValues[i - 1])
268 guess = maxValues[i - 1] - (maxValues[i - 1] - minValues[i - 1]) / 5.0;
269 else if (guess <= minValues[i - 1])
270 guess = minValues[i - 1] + (maxValues[i - 1] - minValues[i - 1]) / 5.0;
271
272 // extend interpolation if needed
273 if (!validData) {
274 try { // extend interpolation a point at a time
275 // including the pillar to be bootstrapped
276 ts_->interpolation_ =
277 ts_->interpolator_.interpolate(times.begin(), times.begin() + i + 1, data.begin());
278 } catch (...) {
279 if (!Interpolator::global)
280 throw; // no chance to fix it in a later iteration
281
282 // otherwise use Linear while the target
283 // interpolation is not usable yet
284 ts_->interpolation_ =
285 QuantLib::Linear().interpolate(times.begin(), times.begin() + i + 1, data.begin());
286 }
287 ts_->interpolation_.update();
288 }
289
290 try {
291 if (validData)
292 solver_.solve(*errors_[i], accuracy, guess, minValues[i - 1], maxValues[i - 1]);
293 else
294 firstSolver_.solve(*errors_[i], accuracy, guess, minValues[i - 1], maxValues[i - 1]);
295 } catch (std::exception& e) {
296 if (validCurve_) {
297 // the previous curve state might have been a
298 // bad guess, so we retry without using it.
299 // This would be tricky to do here (we're
300 // inside multiple nested for loops, we need
301 // to re-initialize...), so we invalidate the
302 // curve, make a recursive call and then exit.
303 validCurve_ = initialized_ = false;
304 calculate();
305 return;
306 }
307
308 // If we have more attempts left on this iteration, try again. Note that the max and min
309 // bounds will be widened on the retry.
310 if (attempts[i - 1] < maxAttempts_) {
311 attempts[i - 1]++;
312 i--;
313 continue;
314 }
315
316 if (dontThrow_) {
317 // Use the fallback value
318 ts_->data_[i] =
319 detail::dontThrowFallback(*errors_[i], minValues[i - 1], maxValues[i - 1], dontThrowSteps_);
320
321 // Remember to update the interpolation. If we don't and we are on the last "i", we will still
322 // have the last attempted value in the solver being used in ts_->interpolation_.
323 ts_->interpolation_.update();
324 } else {
325 QL_FAIL(QuantLib::io::ordinal(iteration + 1)
326 << " iteration: failed "
327 "at "
328 << QuantLib::io::ordinal(i)
329 << " alive instrument, "
330 "pillar "
331 << errors_[i]->helper()->pillarDate() << ", maturity "
332 << errors_[i]->helper()->maturityDate() << ", reference date " << ts_->dates_[0] << ": "
333 << e.what());
334 }
335 }
336 }
337
338 if (!loopRequired_)
339 break;
340
341 // exit condition
342 QuantLib::Real change = std::fabs(data[1] - previousData_[1]);
343 for (QuantLib::Size i = 2; i <= alive_; ++i)
344 change = std::max(change, std::fabs(data[i] - previousData_[i]));
345
346 if (change <= globalAccuracy || change <= accuracy)
347 break;
348
349 // If we hit the max number of iterations and dontThrow is true, just use what we have
350 if (iteration == maxIterations) {
351 if (dontThrow_) {
352 break;
353 } else {
354 QL_FAIL("convergence not reached after " << iteration << " iterations; last improvement " << change
355 << ", required accuracy "
356 << std::max(globalAccuracy, accuracy));
357 }
358 }
359
360 validData = true;
361 }
362
363 validCurve_ = true;
364}
QuantLib::FiniteDifferenceNewtonSafe solver_
std::vector< QuantLib::Real > previousData_
std::vector< QuantLib::ext::shared_ptr< QuantLib::BootstrapError< Curve > > > errors_
QuantLib::Real dontThrowFallback(const QuantLib::BootstrapError< Curve > &error, QuantLib::Real xMin, QuantLib::Real xMax, QuantLib::Size steps)
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
+ Here is the call graph for this function:

◆ initialize()

void initialize
private

Definition at line 138 of file iterativebootstrap.hpp.

138 {
139
140 // ensure helpers are sorted
141 std::sort(ts_->instruments_.begin(), ts_->instruments_.end(), QuantLib::detail::BootstrapHelperSorter());
142
143 // skip expired helpers
144 QuantLib::Date firstDate = Traits::initialDate(ts_);
145 QL_REQUIRE(ts_->instruments_[n_ - 1]->pillarDate() > firstDate, "all instruments expired");
147 while (ts_->instruments_[firstAliveHelper_]->pillarDate() <= firstDate)
150 QL_REQUIRE(alive_ >= Interpolator::requiredPoints - 1,
151 "not enough alive instruments: " << alive_ << " provided, " << Interpolator::requiredPoints - 1
152 << " required");
153
154 // calculate dates and times, create errors_
155 std::vector<QuantLib::Date>& dates = ts_->dates_;
156 std::vector<QuantLib::Time>& times = ts_->times_;
157 dates.resize(alive_ + 1);
158 times.resize(alive_ + 1);
159 errors_.resize(alive_ + 1);
160 dates[0] = firstDate;
161 times[0] = ts_->timeFromReference(dates[0]);
162
163 QuantLib::Date latestRelevantDate, maxDate = firstDate;
164
165 // pillar counter: i
166 // helper counter: j
167 for (QuantLib::Size i = 1, j = firstAliveHelper_; j < n_; ++i, ++j) {
168
169 const QuantLib::ext::shared_ptr<typename Traits::helper>& helper = ts_->instruments_[j];
170 dates[i] = helper->pillarDate();
171 times[i] = ts_->timeFromReference(dates[i]);
172
173 // check for duplicated pillars
174 QL_REQUIRE(dates[i - 1] != dates[i], "more than one instrument with pillar " << dates[i]);
175
176 latestRelevantDate = helper->latestRelevantDate();
177 // check that the helper is really extending the curve, i.e. that
178 // pillar-sorted helpers are also sorted by latestRelevantDate
179 QL_REQUIRE(latestRelevantDate > maxDate, QuantLib::io::ordinal(j + 1)
180 << " instrument (pillar: " << dates[i]
181 << ") has latestRelevantDate (" << latestRelevantDate
182 << ") before or equal to "
183 "previous instrument's latestRelevantDate ("
184 << maxDate << ")");
185 maxDate = latestRelevantDate;
186
187 // when a pillar date is different from the last relevant date the
188 // convergence loop is required even if the Interpolator is local
189 if (dates[i] != latestRelevantDate)
190 loopRequired_ = true;
191
192 errors_[i] = QuantLib::ext::make_shared<QuantLib::BootstrapError<Curve> >(ts_, helper, i);
193 }
194 ts_->maxDate_ = maxDate;
195
196 // set initial guess only if the current curve cannot be used as guess
197 if (!validCurve_ || ts_->data_.size() != alive_ + 1) {
198 // ts_->data_[0] is the only relevant item,
199 // but reasonable numbers might be needed for the whole data vector
200 // because, e.g., of interpolation's early checks
201 ts_->data_ = std::vector<QuantLib::Real>(alive_ + 1, Traits::initialValue(ts_));
202 previousData_.resize(alive_ + 1);
203 }
204 initialized_ = true;
205}

Member Data Documentation

◆ ts_

Curve* ts_
private

Definition at line 105 of file iterativebootstrap.hpp.

◆ n_

QuantLib::Size n_
private

Definition at line 106 of file iterativebootstrap.hpp.

◆ firstSolver_

QuantLib::Brent firstSolver_
private

Definition at line 107 of file iterativebootstrap.hpp.

◆ solver_

QuantLib::FiniteDifferenceNewtonSafe solver_
private

Definition at line 108 of file iterativebootstrap.hpp.

◆ initialized_

bool initialized_
mutableprivate

Definition at line 109 of file iterativebootstrap.hpp.

◆ validCurve_

bool validCurve_
private

Definition at line 109 of file iterativebootstrap.hpp.

◆ loopRequired_

bool loopRequired_
private

Definition at line 109 of file iterativebootstrap.hpp.

◆ firstAliveHelper_

QuantLib::Size firstAliveHelper_
mutableprivate

Definition at line 110 of file iterativebootstrap.hpp.

◆ alive_

QuantLib::Size alive_
private

Definition at line 110 of file iterativebootstrap.hpp.

◆ previousData_

std::vector<QuantLib::Real> previousData_
mutableprivate

Definition at line 111 of file iterativebootstrap.hpp.

◆ errors_

std::vector<QuantLib::ext::shared_ptr<QuantLib::BootstrapError<Curve> > > errors_
mutableprivate

Definition at line 112 of file iterativebootstrap.hpp.

◆ accuracy_

QuantLib::Real accuracy_
private

Definition at line 113 of file iterativebootstrap.hpp.

◆ globalAccuracy_

QuantLib::Real globalAccuracy_
private

Definition at line 114 of file iterativebootstrap.hpp.

◆ dontThrow_

bool dontThrow_
private

Definition at line 115 of file iterativebootstrap.hpp.

◆ maxAttempts_

QuantLib::Size maxAttempts_
private

Definition at line 116 of file iterativebootstrap.hpp.

◆ maxFactor_

QuantLib::Real maxFactor_
private

Definition at line 117 of file iterativebootstrap.hpp.

◆ minFactor_

QuantLib::Real minFactor_
private

Definition at line 118 of file iterativebootstrap.hpp.

◆ dontThrowSteps_

QuantLib::Size dontThrowSteps_
private

Definition at line 119 of file iterativebootstrap.hpp.