Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | Static Private Attributes | List of all members
DefaultableEquityJumpDiffusionModel Class Reference

#include <qle/models/defaultableequityjumpdiffusionmodel.hpp>

+ Inheritance diagram for DefaultableEquityJumpDiffusionModel:
+ Collaboration diagram for DefaultableEquityJumpDiffusionModel:

Public Member Functions

 DefaultableEquityJumpDiffusionModel (const std::vector< Real > &stepTimes, const std::vector< Real > &h0, const std::vector< Real > &sigma, const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &equity, const Handle< QuantLib::DefaultProbabilityTermStructure > &creditCurve, const DayCounter &volDayCounter, const Real p=0.0, const Real eta=1.0, const bool adjustEquityForward=true)
 
const std::vector< Real > & stepTimes () const
 
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2equity () const
 
Real totalBlackVariance () const
 
const DayCounter & volDayCounter () const
 
Handle< QuantLib::DefaultProbabilityTermStructure > creditCurve () const
 
Real eta () const
 
Real p () const
 
bool adjustEquityForward () const
 
Real timeFromReference (const Date &d) const
 
const std::vector< Real > & h0 () const
 
const std::vector< Real > & sigma () const
 
Real h (const Real t, const Real S) const
 
Real h0 (const Real t) const
 
Real r (const Real t) const
 
Real q (const Real t) const
 
Real sigma (const Real t) const
 
Real dividendYield (const Real s, const Real t) const
 
void bootstrap (const Handle< QuantLib::BlackVolTermStructure > &volatility, const bool staticMesher, const Size timeStepsPerYear, const Size stateGridPoints=100, const Real mesherEpsilon=1E-4, const Real mesherScaling=1.5, const Real mesherConcentration=Null< Real >(), const DefaultableEquityJumpDiffusionModelBuilder::BootstrapMode bootstrapMode=DefaultableEquityJumpDiffusionModelBuilder::BootstrapMode::Alternating, const bool enforceFokkerPlanckBootstrap=false, const bool adjustEquityVolatility=true) const
 
void update () override
 

Private Member Functions

QuantLib::Size getTimeIndex (const Real t) const
 

Private Attributes

std::vector< Real > stepTimes_
 
std::vector< Real > h0_
 
std::vector< Real > sigma_
 
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2equity_
 
Handle< DefaultProbabilityTermStructure > creditCurve_
 
DayCounter volDayCounter_
 
Real p_
 
Real eta_
 
bool adjustEquityForward_
 
QuantLib::ext::shared_ptr< Fdm1dMeshermesher_
 
Real totalBlackVariance_ = 1.0
 

Static Private Attributes

static constexpr Real fh_ = 1E-4
 

Detailed Description

Definition at line 95 of file defaultableequityjumpdiffusionmodel.hpp.

Constructor & Destructor Documentation

◆ DefaultableEquityJumpDiffusionModel()

DefaultableEquityJumpDiffusionModel ( const std::vector< Real > &  stepTimes,
const std::vector< Real > &  h0,
const std::vector< Real > &  sigma,
const QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > &  equity,
const Handle< QuantLib::DefaultProbabilityTermStructure > &  creditCurve,
const DayCounter &  volDayCounter,
const Real  p = 0.0,
const Real  eta = 1.0,
const bool  adjustEquityForward = true 
)

Definition at line 150 of file defaultableequityjumpdiffusionmodel.cpp.

157 registerWith(equity);
158 registerWith(creditCurve);
159}
Handle< QuantLib::DefaultProbabilityTermStructure > creditCurve() const
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > equity_
QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > equity() const
+ Here is the call graph for this function:

Member Function Documentation

◆ stepTimes()

const std::vector< Real > & stepTimes ( ) const

Definition at line 163 of file defaultableequityjumpdiffusionmodel.cpp.

163{ return stepTimes_; }

◆ equity()

QuantLib::ext::shared_ptr< QuantExt::EquityIndex2 > equity ( ) const

Definition at line 165 of file defaultableequityjumpdiffusionmodel.cpp.

165{ return equity_; }
+ Here is the caller graph for this function:

◆ totalBlackVariance()

Real totalBlackVariance ( ) const

◆ volDayCounter()

const DayCounter & volDayCounter ( ) const

Definition at line 169 of file defaultableequityjumpdiffusionmodel.cpp.

169{ return volDayCounter_; }

◆ creditCurve()

Handle< DefaultProbabilityTermStructure > creditCurve ( ) const

Definition at line 171 of file defaultableequityjumpdiffusionmodel.cpp.

171 {
172 return creditCurve_;
173}
+ Here is the caller graph for this function:

◆ eta()

Real eta ( ) const

Definition at line 175 of file defaultableequityjumpdiffusionmodel.cpp.

175{ return eta_; }
+ Here is the caller graph for this function:

◆ p()

Real p ( ) const

Definition at line 177 of file defaultableequityjumpdiffusionmodel.cpp.

177{ return p_; }
+ Here is the caller graph for this function:

◆ adjustEquityForward()

bool adjustEquityForward ( ) const

Definition at line 179 of file defaultableequityjumpdiffusionmodel.cpp.

179{ return adjustEquityForward_; }

◆ timeFromReference()

Real timeFromReference ( const Date &  d) const

Definition at line 181 of file defaultableequityjumpdiffusionmodel.cpp.

181 {
182 return volDayCounter_.yearFraction(creditCurve_->referenceDate(), d);
183}

◆ h0() [1/2]

const std::vector< Real > & h0 ( ) const

Definition at line 185 of file defaultableequityjumpdiffusionmodel.cpp.

185{ return h0_; }

◆ sigma() [1/2]

const std::vector< Real > & sigma ( ) const

Definition at line 187 of file defaultableequityjumpdiffusionmodel.cpp.

187{ return sigma_; }

◆ h()

Real h ( const Real  t,
const Real  S 
) const

Definition at line 196 of file defaultableequityjumpdiffusionmodel.cpp.

196 {
197 return h0_[getTimeIndex(t)] * std::pow(equity_->equitySpot()->value() / S, p_);
198}
+ Here is the call graph for this function:

◆ h0() [2/2]

Real h0 ( const Real  t) const

◆ r()

Real r ( const Real  t) const

Definition at line 202 of file defaultableequityjumpdiffusionmodel.cpp.

202 {
203 if (t > fh_) {
204 return -std::log(equity_->equityForecastCurve()->discount(t + fh_) /
205 equity_->equityForecastCurve()->discount(t - fh_)) /
206 (2.0 * fh_);
207 } else {
208 return -std::log(equity_->equityForecastCurve()->discount(t + fh_) /
209 equity_->equityForecastCurve()->discount(t)) /
210 (fh_);
211 }
212}

◆ q()

Real q ( const Real  t) const

Definition at line 214 of file defaultableequityjumpdiffusionmodel.cpp.

214 {
215 if (t > fh_) {
216 return -std::log(equity_->equityDividendCurve()->discount(t + fh_) /
217 equity_->equityDividendCurve()->discount(t - fh_)) /
218 (2.0 * fh_);
219 } else {
220 return -std::log(equity_->equityDividendCurve()->discount(t + fh_) /
221 equity_->equityDividendCurve()->discount(t)) /
222 (fh_);
223 }
224}

◆ sigma() [2/2]

Real sigma ( const Real  t) const

Definition at line 200 of file defaultableequityjumpdiffusionmodel.cpp.

200{ return sigma_[getTimeIndex(t)]; }
+ Here is the call graph for this function:

◆ dividendYield()

Real dividendYield ( const Real  s,
const Real  t 
) const

Definition at line 226 of file defaultableequityjumpdiffusionmodel.cpp.

226 {
227 QL_REQUIRE(t > s || close_enough(s, t), "DefaultableEquityJumppDiffusionModel::dividendYield(): start time ("
228 << s << ") must be less or equal than end time (" << t << ")");
229 Real tmp = t;
230 if (close_enough(s, t)) {
231 tmp = s + fh_;
232 }
233 return -std::log(equity_->equityDividendCurve()->discount(tmp) / equity_->equityDividendCurve()->discount(s)) /
234 (tmp - s);
235}
Filter close_enough(const RandomVariable &x, const RandomVariable &y)
+ Here is the call graph for this function:

◆ bootstrap()

void bootstrap ( const Handle< QuantLib::BlackVolTermStructure > &  volatility,
const bool  staticMesher,
const Size  timeStepsPerYear,
const Size  stateGridPoints = 100,
const Real  mesherEpsilon = 1E-4,
const Real  mesherScaling = 1.5,
const Real  mesherConcentration = Null<Real>(),
const DefaultableEquityJumpDiffusionModelBuilder::BootstrapMode  bootstrapMode = DefaultableEquityJumpDiffusionModelBuilder::BootstrapMode::Alternating,
const bool  enforceFokkerPlanckBootstrap = false,
const bool  adjustEquityVolatility = true 
) const

Definition at line 237 of file defaultableequityjumpdiffusionmodel.cpp.

241 {
242
243 // set total black variance
244
245 Real forward = equity_->equitySpot()->value() * equity_->equityDividendCurve()->discount(stepTimes_.back()) /
246 equity_->equityForecastCurve()->discount(stepTimes_.back());
247 totalBlackVariance_ = volatility->blackVariance(stepTimes_.back(), forward);
248
249 // check validity of credit curve, otherwise we might divide by zero below
250
251 for (Size i = 0; i < stepTimes_.size(); ++i) {
252 QL_REQUIRE(!close_enough(creditCurve_->survivalProbability(stepTimes_[i]), 0.0),
253 "DefaultableEquityJumpDiffusionModel: creditCurve implies zero survival probability at t = "
254 << stepTimes_[i]
255 << ", this can not be handled. Check the credit curve / security spread provided in the market "
256 "data. If this happens during a spread imply, the target price might not be attainable even "
257 "for high spreads.");
258 }
259
260 if (close_enough(p_, 0.0) && !enforceFokkerPlanckBootstrap) {
261
262 // 1. case p = 0:
263
264 Real accumulatedVariance = 0.0;
265
266 for (Size i = 0; i < stepTimes_.size(); ++i) {
267
268 // 1.1 the stepwise model h is just the average hazard rate over each interval
269
270 h0_[i] = -std::log(creditCurve_->survivalProbability(stepTimes_[i]) /
271 (i == 0 ? 1.0 : creditCurve_->survivalProbability(stepTimes_[i - 1]))) /
272 (stepTimes_[i] - (i == 0 ? 0.0 : stepTimes_[i - 1]));
273
274 // 1.2 determine the implied equity vol in our model
275
276 Real impliedModelVol = 0.0;
277 Real forward = equity_->equitySpot()->value() / equity_->equityForecastCurve()->discount(stepTimes_[i]) *
278 equity_->equityDividendCurve()->discount(stepTimes_[i]);
279
280 if (!adjustEquityVolatility) {
281
282 // 1.2.1 if we do not adjust the equity vol, we just read it from the market surface
283
284 impliedModelVol = volatility->blackVol(stepTimes_[i], forward);
285
286 } else {
287
288 // 1.2.2 if we adjust the equity vol, we first compute the market atm option price
289
290 Real marketPrice = blackFormula(Option::Call, forward, forward,
291 std::sqrt(volatility->blackVariance(stepTimes_[i], forward)),
292 equity_->equityForecastCurve()->discount(stepTimes_[i]));
293
294 // 1.2.2 adjust the forward and the discount factor by the credit drift / jump intensity and back out
295 // the model implied vol using these and the market price computed above
296
297 // TODO a tacit assumption here is that a defaulted equity does not contribute signficantly to the ATM
298 // call option payoff, i.e. that eta is sufficiently close to 1, review this and compare to the "full"
299 // implementation via Fokker-Planck below
300
301 Real adjustedForward = adjustEquityForward_
302 ? forward / std::pow(creditCurve_->survivalProbability(stepTimes_[i]), eta_)
303 : forward;
304 try {
305 impliedModelVol =
306 blackFormulaImpliedStdDev(Option::Call, forward, adjustedForward, marketPrice,
307 equity_->equityForecastCurve()->discount(stepTimes_[i]) *
308 creditCurve_->survivalProbability(stepTimes_[i])) /
309 std::sqrt(stepTimes_[i]);
310 } catch (...) {
311 }
312 }
313
314 impliedModelVol = std::max(1E-4, impliedModelVol);
315
316 // 1.3 bootstrap the stepwise model sigma
317
318 sigma_[i] =
319 i == 0
320 ? impliedModelVol
321 : std::sqrt(std::max(impliedModelVol * impliedModelVol * stepTimes_[i] - accumulatedVariance, 0.0) /
322 (stepTimes_[i] - stepTimes_[i - 1]));
323
324 accumulatedVariance += sigma_[i] * sigma_[i] * (stepTimes_[i] - (i == 0 ? 0.0 : stepTimes_[i - 1]));
325 }
326
327 } else {
328
329 // 2. case p != 0 (or enforced Fokker-Planck method for bootstrap)
330
331 // 2.1 set up solver for the Fokker-Planck PDE
332
333 // 2.1.1 build mesher
334
335 Real spot = equity()->equitySpot()->value();
336 Real logSpot = std::log(spot);
337
338 if (mesher_ == nullptr || !staticMesher) {
339
340 TimeGrid tmpGrid(stepTimes_.begin(), stepTimes_.end(),
341 std::max<Size>(std::lround(timeStepsPerYear * stepTimes_.back() + 0.5), 1));
342
343 Real mi = spot;
344 Real ma = spot;
345
346 Real forward = spot;
347 for (Size i = 1; i < tmpGrid.size(); ++i) {
348 forward = equity()->equitySpot()->value() * equity()->equityDividendCurve()->discount(tmpGrid[i]) /
349 equity()->equityForecastCurve()->discount(tmpGrid[i]) /
350 std::pow(creditCurve()->survivalProbability(tmpGrid[i]), eta());
351 mi = std::min(mi, forward);
352 ma = std::max(ma, forward);
353 }
354
355 Real sigmaSqrtT = std::max(1E-4, std::sqrt(volatility->blackVariance(tmpGrid.back(), forward)));
356 Real normInvEps = InverseCumulativeNormal()(1.0 - mesherEpsilon);
357 Real xMin = std::log(mi) - sigmaSqrtT * normInvEps * mesherScaling;
358 Real xMax = std::log(ma) + sigmaSqrtT * normInvEps * mesherScaling;
359
360 if (mesherConcentration != Null<Real>()) {
361 mesher_ = QuantLib::ext::make_shared<Concentrating1dMesher>(xMin, xMax, stateGridPoints,
362 std::make_pair(logSpot, mesherConcentration), true);
363 } else {
364 mesher_ = QuantLib::ext::make_shared<Uniform1dMesher>(xMin, xMax, stateGridPoints);
365 }
366 }
367
368 // 2.1.2 build operator
369
370 auto fdmOp = QuantLib::ext::make_shared<FdmDefaultableEquityJumpDiffusionFokkerPlanckOp>(
371 stepTimes_.back(), QuantLib::ext::make_shared<FdmMesherComposite>(mesher_), shared_from_this());
372
373 // 2.1.3 build solver
374
375 // TODO which schema / how many damping steps should we take? For the moment we follow the recommendation from
376 // the Andersen paper and use Crank-Nicholson after a "few" Rannacher steps (i.e. implicit Euler)
377 // TrBDF2 seems to be a specialised scheme for initial Dirac conditons though. Some research required...
378
379 auto solver = QuantLib::ext::make_shared<FdmBackwardSolver>(
380 fdmOp, std::vector<QuantLib::ext::shared_ptr<BoundaryCondition<FdmLinearOp>>>(), nullptr, FdmSchemeDesc::Douglas());
381
382 constexpr Size dampingSteps = 5;
383
384 // 2.2 boostrap h0 and sigma functions
385
386 // 2.2.1 set integration length dy for each grid point (= center of integration interval) and initial condition
387
388 Array p(mesher_->size(), 0.0), dy(mesher_->size(), 0.0);
389
390 for (Size i = 0; i < mesher_->size(); ++i) {
391 if (i > 0) {
392 dy[i] += 0.5 * mesher_->dminus(i);
393 } else {
394 dy[i] += 0.5 * mesher_->dminus(i + 1);
395 }
396 if (i < mesher_->size() - 1) {
397 dy[i] += 0.5 * mesher_->dplus(i);
398 } else {
399 dy[i] += 0.5 * mesher_->dplus(i - 1);
400 }
401 }
402
403 for (Size i = 0; i < mesher_->size(); ++i) {
404 if (i > 0) {
405 if ((logSpot > mesher_->location(i - 1) || close_enough(logSpot, mesher_->location(i - 1))) &&
406 (logSpot < mesher_->location(i) && !close_enough(logSpot, mesher_->location(i)))) {
407 Real alpha = (mesher_->location(i) - logSpot) / mesher_->dplus(i - 1);
408 p[i - 1] = alpha / dy[i - 1];
409 p[i] = (1 - alpha) / dy[i];
410 }
411 }
412 }
413
414 Array guess(2);
415
416 // bookkeeping to maange optimization guesses (see below)
417 constexpr Real thresholdSuccessfulOptimization = 1E-5;
418 Real lastOptimizationError = 0.0;
419 Array lastValidGuess;
420
421 for (Size i = 0; i < stepTimes_.size(); ++i) {
422
423 // 2.2.2 we roll from timestep i-1 (t=0 for i=0) to i and calibrate (h0, sigma) to the market
424
425 Real marketDefaultableBond = creditCurve_->survivalProbability(stepTimes_[i]) *
426 equity_->equityForecastCurve()->discount(stepTimes_[i]);
427 Real forward = equity_->equitySpot()->value() / equity_->equityForecastCurve()->discount(stepTimes_[i]) *
428 equity_->equityDividendCurve()->discount(stepTimes_[i]);
429 Real marketEquityOption = blackFormula(Option::Call, forward, forward,
430 std::sqrt(volatility->blackVariance(stepTimes_[i], forward)),
431 equity_->equityForecastCurve()->discount(stepTimes_[i]));
432
433 struct TargetFunction : public QuantLib::CostFunction {
434 static Real hToOpt(const Real x) { return std::log(std::max(x, 1E-6)); }
435 static Real sigmaToOpt(const Real x) { return std::log(std::max(x, 1E-6)); }
436 static Real hToReal(const Real x) { return std::exp(x); }
437 static Real sigmaToReal(const Real x) { return std::exp(x); }
438
439 enum class Mode { h0, sigma, both };
440 TargetFunction(const Mode mode, const Real strike, const Real marketEquityOption,
441 const Real marketDefaultableBond, Real& h0, Real& sigma, const Array& p,
442 const std::vector<Real>& locations, const Array& dy,
443 const QuantLib::ext::shared_ptr<FdmBackwardSolver>& solver, const Real t_from, const Real t_to,
444 const Size steps, const Size dampingSteps)
445 : mode_(mode), strike_(strike), marketEquityOption_(marketEquityOption),
446 marketDefaultableBond_(marketDefaultableBond), h0_(h0), sigma_(sigma), locations_(locations),
447 dy_(dy), p_(p), solver_(solver), t_from_(t_from), t_to_(t_to), steps_(steps),
448 dampingSteps_(dampingSteps) {}
449
450 Array values(const Array& x) const override {
451
452 // 2.2.2.0 set trial values from optimiser for h0 and sigma, we square the values to ensure
453 // positivity, this transformation is reverted when setting the guess and reading the solution
454
455 if (mode_ == Mode::h0) {
456 h0_ = hToReal(x[0]);
457 } else if (mode_ == Mode::sigma) {
458 sigma_ = sigmaToReal(x[0]);
459 } else {
460 h0_ = hToReal(x[0]);
461 sigma_ = sigmaToReal(x[1]);
462 }
463
464 // 2.2.2.1 roll density back (in "time to maturity", not in calendar time, which rolls forward)
465
466 Array pTmp = p_;
467 solver_->rollback(pTmp, t_from_, t_to_, steps_, dampingSteps_);
468
469 // 2.2.2.2 compute model defaultable zero bond and equity call option
470
471 Real defaultableBond = 0.0;
472 if (mode_ == Mode::h0 || mode_ == Mode::both) {
473 for (Size i = 0; i < pTmp.size(); ++i) {
474 defaultableBond += pTmp[i] * dy_[i];
475 }
476 }
477
478 Real equityOption = 0.0;
479 if (mode_ == Mode::sigma || mode_ == Mode::both) {
480 bool knockInLocation = true;
481 for (Size i = 0; i < pTmp.size(); ++i) {
482 if (locations_[i] > std::log(strike_) && !close_enough(locations_[i], std::log(strike_))) {
483 Real dy = dy_[i];
484 if (knockInLocation) {
485 // TODO there are more sophisticated corrections (reference in the Andersen paper?)
486 dy = (locations_[i] - std::log(strike_));
487 if (i < pTmp.size())
488 dy += 0.5 * (locations_[i + 1] - locations_[i]);
489 else
490 dy += 0.5 * (locations_[i] - locations_[i - 1]);
491 knockInLocation = false;
492 }
493 equityOption += pTmp[i] * dy * (std::exp(locations_[i]) - strike_);
494 }
495 }
496 }
497
498 if (mode_ == Mode::h0) {
499 Array result(1);
500 result[0] = (defaultableBond - marketDefaultableBond_) / marketDefaultableBond_;
501 return result;
502 } else if (mode_ == Mode::sigma) {
503 Array result(1);
504 result[0] = (equityOption - marketEquityOption_) / marketEquityOption_;
505 return result;
506 } else {
507 Array result(2);
508 result[0] = (defaultableBond - marketDefaultableBond_) / marketDefaultableBond_;
509 result[1] = (equityOption - marketEquityOption_) / marketEquityOption_;
510 return result;
511 }
512 }
513 const Mode mode_;
514 const Real strike_, marketEquityOption_, marketDefaultableBond_;
515 Real &h0_, &sigma_;
516 const std::vector<Real>& locations_;
517 const Array &dy_, &p_;
518 const QuantLib::ext::shared_ptr<FdmBackwardSolver> solver_;
519 const Real t_from_, t_to_;
520 const Size steps_, dampingSteps_;
521 };
522
523 /* 2.2.2.3 The first guess (i=0) are parameters computed with p = 0 as above.
524 A subsequent guess (i>0) is the last solution that resulted in an
525 error below a given threshold (or the guess for i=0 if that is the
526 only available guess). */
527
528 if (i == 0) {
529 guess[0] = -std::log(creditCurve_->survivalProbability(stepTimes_[i]) /
530 (i == 0 ? 1.0 : creditCurve_->survivalProbability(stepTimes_[i - 1]))) /
531 (stepTimes_[i] - (i == 0 ? 0.0 : stepTimes_[i - 1]));
532 guess[1] = std::sqrt(volatility->blackVariance(stepTimes_[i], forward) /
533 (stepTimes_[i] - (i == 0 ? 0.0 : stepTimes_[i - 1])));
534 lastValidGuess = guess;
535 } else {
536 if (lastOptimizationError < thresholdSuccessfulOptimization) {
537 guess[0] = h0_[i - 1];
538 guess[1] = sigma_[i - 1];
539 lastValidGuess = guess;
540 } else {
541 guess = lastValidGuess;
542 }
543 }
544
545 // 2.2.2.4 transform the guess
546
547 guess[0] = TargetFunction::hToOpt(guess[0]);
548 guess[1] = TargetFunction::sigmaToOpt(guess[1]);
549
550 // 2.2.2.5 run the optimzation for the current time step and set the model parameters to the found solution
551
552 Real t_from = stepTimes_.back() - (i == 0 ? 0.0 : stepTimes_[i - 1]);
553 Real t_to = stepTimes_.back() - stepTimes_[i];
554 Size steps = static_cast<Size>(0.5 + (t_from - t_to) * static_cast<Real>(timeStepsPerYear));
555
556 NoConstraint noConstraint;
557 LevenbergMarquardt lm;
558 EndCriteria endCriteria(100, 10, 1E-8, 1E-8, 1E-8);
560 // simultaneous optimization of (h0,sigma)
561 TargetFunction targetFunction(TargetFunction::Mode::both, forward, marketEquityOption,
562 marketDefaultableBond, h0_[i], sigma_[i], p, mesher_->locations(), dy,
563 solver, t_from, t_to, steps, i == 0 ? dampingSteps : 0);
564 Problem problem(targetFunction, noConstraint, guess);
565 lm.minimize(problem, endCriteria);
566 h0_[i] = TargetFunction::hToReal(problem.currentValue()[0]);
567 sigma_[i] = TargetFunction::sigmaToReal(problem.currentValue()[1]);
568 lastOptimizationError = problem.functionValue();
569 } else {
570 // alternating optimization of h0 and sigma
571 TargetFunction target_function_h0(TargetFunction::Mode::h0, forward, marketEquityOption,
572 marketDefaultableBond, h0_[i], sigma_[i], p, mesher_->locations(), dy,
573 solver, t_from, t_to, steps, i == 0 ? dampingSteps : 0);
574 TargetFunction target_function_sigma(TargetFunction::Mode::sigma, forward, marketEquityOption,
575 marketDefaultableBond, h0_[i], sigma_[i], p, mesher_->locations(),
576 dy, solver, t_from, t_to, steps, i == 0 ? dampingSteps : 0);
577 Real current0 = guess[0], current1 = guess[1];
578 Real delta0 = 0.0, delta1 = 0.0;
579 Real functionValue0 = 0.0, functionValue1 = 0.0;
580 Size iteration = 0;
581 constexpr Real tol_x = 1E-8;
582 do {
583 // optimize h0
584 Problem p0(target_function_h0, noConstraint, Array(1, current0));
585 lm.minimize(p0, endCriteria);
586 h0_[i] = TargetFunction::hToReal(p0.currentValue()[0]);
587 delta0 = std::abs(h0_[i] - TargetFunction::hToReal(current0));
588 current0 = p0.currentValue()[0];
589 functionValue0 = p0.functionValue();
590 // optimize sigma
591 Problem p1(target_function_sigma, noConstraint, Array(1, current1));
592 lm.minimize(p1, endCriteria);
593 sigma_[i] = TargetFunction::sigmaToReal(p1.currentValue()[0]);
594 delta1 = std::abs(sigma_[i] - TargetFunction::sigmaToReal(current1));
595 current1 = p1.currentValue()[0];
596 functionValue1 = p1.functionValue();
597 } while (iteration++ < 50 && (delta0 > tol_x || delta1 > tol_x));
598 lastOptimizationError =
599 std::sqrt(0.5 * (functionValue0 * functionValue0 + functionValue1 * functionValue1));
600 }
601
602 // 2.2.2.6 we still have to do the actual roll back with the solution we have found
603
604 solver->rollback(p, t_from, t_to, steps, i == 0 ? dampingSteps : 0);
605
606 } // bootstrap over step times
607 } // case p!= 0
608}
std::vector< Size > steps
+ Here is the call graph for this function:

◆ update()

void update ( )
override

Definition at line 161 of file defaultableequityjumpdiffusionmodel.cpp.

161{ notifyObservers(); }

◆ getTimeIndex()

Size getTimeIndex ( const Real  t) const
private

Definition at line 189 of file defaultableequityjumpdiffusionmodel.cpp.

189 {
190 Size m = std::distance(stepTimes_.begin(),
191 std::lower_bound(stepTimes_.begin(), stepTimes_.end(), t,
192 [](Real x, Real y) { return x < y && !close_enough(x, y); }));
193 return std::min(m, stepTimes_.size() - 1);
194}
+ Here is the caller graph for this function:

Member Data Documentation

◆ stepTimes_

std::vector<Real> stepTimes_
private

Definition at line 168 of file defaultableequityjumpdiffusionmodel.hpp.

◆ h0_

std::vector<Real> h0_
mutableprivate

Definition at line 169 of file defaultableequityjumpdiffusionmodel.hpp.

◆ sigma_

std::vector<Real> sigma_
private

Definition at line 169 of file defaultableequityjumpdiffusionmodel.hpp.

◆ equity_

QuantLib::ext::shared_ptr<QuantExt::EquityIndex2> equity_
private

Definition at line 170 of file defaultableequityjumpdiffusionmodel.hpp.

◆ creditCurve_

Handle<DefaultProbabilityTermStructure> creditCurve_
private

Definition at line 171 of file defaultableequityjumpdiffusionmodel.hpp.

◆ volDayCounter_

DayCounter volDayCounter_
private

Definition at line 172 of file defaultableequityjumpdiffusionmodel.hpp.

◆ p_

Real p_
private

Definition at line 173 of file defaultableequityjumpdiffusionmodel.hpp.

◆ eta_

Real eta_
private

Definition at line 173 of file defaultableequityjumpdiffusionmodel.hpp.

◆ adjustEquityForward_

bool adjustEquityForward_
private

Definition at line 174 of file defaultableequityjumpdiffusionmodel.hpp.

◆ mesher_

QuantLib::ext::shared_ptr<Fdm1dMesher> mesher_
mutableprivate

Definition at line 177 of file defaultableequityjumpdiffusionmodel.hpp.

◆ totalBlackVariance_

Real totalBlackVariance_ = 1.0
mutableprivate

Definition at line 180 of file defaultableequityjumpdiffusionmodel.hpp.

◆ fh_

constexpr Real fh_ = 1E-4
staticconstexprprivate

Definition at line 183 of file defaultableequityjumpdiffusionmodel.hpp.