20#include <ql/currencies/exchangeratemanager.hpp>
21#include <ql/math/functional.hpp>
22#include <ql/math/randomnumbers/haltonrsg.hpp>
23#include <ql/pricingengines/bond/bondfunctions.hpp>
24#include <ql/pricingengines/bond/discountingbondengine.hpp>
25#include <ql/quotes/derivedquote.hpp>
26#include <ql/termstructures/yield/bondhelpers.hpp>
27#include <ql/termstructures/yield/flatforward.hpp>
28#include <ql/termstructures/yield/nonlinearfittingmethods.hpp>
29#include <ql/termstructures/yield/oisratehelper.hpp>
30#include <ql/termstructures/yield/piecewiseyieldcurve.hpp>
31#include <ql/termstructures/yield/piecewisezerospreadedtermstructure.hpp>
32#include <ql/termstructures/yield/ratehelpers.hpp>
33#include <ql/termstructures/yield/overnightindexfutureratehelper.hpp>
34#include <ql/time/daycounters/actual360.hpp>
35#include <ql/time/daycounters/actualactual.hpp>
36#include <ql/time/imm.hpp>
38#include <ql/indexes/ibor/all.hpp>
39#include <ql/math/interpolations/convexmonotoneinterpolation.hpp>
40#include <ql/math/interpolations/mixedinterpolation.hpp>
82string yieldCurveKey(
const Currency& curveCcy,
const string& curveID,
const Date&) {
84 return tempSpec.name();
91template <
template <
class>
class CurveType>
92QuantLib::ext::shared_ptr<YieldTermStructure>
buildYieldCurve(
const vector<Date>& dates,
const vector<QuantLib::Real>& rates,
93 const DayCounter& dayCounter,
96 QuantLib::ext::shared_ptr<YieldTermStructure> yieldts;
97 switch (interpolationMethod) {
99 yieldts.reset(
new CurveType<QuantLib::Linear>(dates, rates, dayCounter, QuantLib::Linear()));
102 yieldts.reset(
new CurveType<QuantLib::LogLinear>(dates, rates, dayCounter, QuantLib::LogLinear()));
105 yieldts.reset(
new CurveType<QuantLib::Cubic>(dates, rates, dayCounter,
106 QuantLib::Cubic(CubicInterpolation::Kruger,
true)));
109 yieldts.reset(
new CurveType<QuantLib::Cubic>(dates, rates, dayCounter,
110 QuantLib::Cubic(CubicInterpolation::Kruger,
true,
111 CubicInterpolation::SecondDerivative, 0.0,
112 CubicInterpolation::FirstDerivative)));
116 new CurveType<QuantLib::ConvexMonotone>(dates, rates, dayCounter, Calendar(), {}, {}, QuantLib::ConvexMonotone()));
119 yieldts.reset(
new CurveType<QuantExt::Quadratic>(dates, rates, dayCounter,
QuantExt::Quadratic(1, 0, 1, 0, 1)));
126 yieldts.reset(
new CurveType<QuantLib::Cubic>(dates, rates, dayCounter, Cubic(CubicInterpolation::Parabolic)));
129 yieldts.reset(
new CurveType<QuantLib::Cubic>(dates, rates, dayCounter,
130 Cubic(CubicInterpolation::Spline,
false,
131 CubicInterpolation::SecondDerivative, 0.0,
132 CubicInterpolation::SecondDerivative, 0.0)));
136 new CurveType<DefaultLogMixedLinearCubic>(dates, rates, dayCounter, DefaultLogMixedLinearCubic(n)));
140 new CurveType<MonotonicLogMixedLinearCubic>(dates, rates, dayCounter, MonotonicLogMixedLinearCubic(n)));
144 new CurveType<KrugerLogMixedLinearCubic>(dates, rates, dayCounter, KrugerLogMixedLinearCubic(n)));
147 yieldts.reset(
new CurveType<LogMixedLinearCubic>(
148 dates, rates, dayCounter,
149 LogMixedLinearCubic(n, MixedInterpolation::ShareRanges, CubicInterpolation::Spline,
false,
150 CubicInterpolation::SecondDerivative, 0.0, CubicInterpolation::SecondDerivative,
155 QL_FAIL(
"Interpolation method '" << interpolationMethod <<
"' not recognised.");
160QuantLib::ext::shared_ptr<YieldTermStructure>
zerocurve(
const vector<Date>& dates,
const vector<Rate>& yields,
161 const DayCounter& dayCounter,
163 return buildYieldCurve<InterpolatedZeroCurve>(dates, yields, dayCounter, interpolationMethod, n);
166QuantLib::ext::shared_ptr<YieldTermStructure>
discountcurve(
const vector<Date>& dates,
const vector<DiscountFactor>& dfs,
167 const DayCounter& dayCounter,
169 return buildYieldCurve<InterpolatedDiscountCurve>(dates, dfs, dayCounter, interpolationMethod, n);
172QuantLib::ext::shared_ptr<YieldTermStructure>
forwardcurve(
const vector<Date>& dates,
const vector<Rate>& forwards,
173 const DayCounter& dayCounter,
175 return buildYieldCurve<InterpolatedForwardCurve>(dates, forwards, dayCounter, interpolationMethod, n);
183 else if (s ==
"LogLinear")
185 else if (s ==
"NaturalCubic")
187 else if (s ==
"FinancialCubic")
189 else if (s ==
"ConvexMonotone")
191 else if (s ==
"ExponentialSplines")
193 else if (s ==
"Quadratic")
195 else if (s ==
"LogQuadratic")
197 else if (s ==
"LogNaturalCubic")
199 else if (s ==
"LogFinancialCubic")
201 else if (s ==
"LogCubicSpline")
203 else if (s ==
"Hermite")
205 else if (s ==
"CubicSpline")
207 else if (s ==
"DefaultLogMixedLinearCubic")
209 else if (s ==
"MonotonicLogMixedLinearCubic")
211 else if (s ==
"KrugerLogMixedLinearCubic")
213 else if (s ==
"LogMixedLinearCubicNaturalSpline")
215 else if (s ==
"NelsonSiegel")
217 else if (s ==
"Svensson")
220 QL_FAIL(
"Yield curve interpolation method " << s <<
" not recognized");
226 else if (s ==
"Discount")
228 else if (s ==
"Forward")
231 QL_FAIL(
"Yield curve interpolation variable " << s <<
" not recognized");
236 return out <<
"Linear";
238 return out <<
"LogLinear";
240 return out <<
"NaturalCubic";
242 return out <<
"FinancialCubic";
244 return out <<
"ConvexMonotone";
246 return out <<
"ExponentialSplines";
248 return out <<
"Quadratic";
250 return out <<
"LogQuadratic";
252 return out <<
"LogNaturalCubic";
254 return out <<
"LogFinancialCubic";
256 return out <<
"LogCubicSpline";
258 return out <<
"Hermite";
260 return out <<
"CubicSpline";
262 return out <<
"DefaultLogMixedLinearCubic";
264 return out <<
"MonotonicLogMixedLinearCubic";
266 return out <<
"KrugerLogMixedLinearCubic";
268 return out <<
"LogMixedLinearCubicNaturalSpline";
270 return out <<
"NelsonSiegel";
272 return out <<
"Svensson";
274 QL_FAIL(
"Yield curve interpolation method " <<
static_cast<int>(m) <<
" not recognized");
278 const Loader& loader,
const map<
string, QuantLib::ext::shared_ptr<YieldCurve>>& requiredYieldCurves,
279 const map<
string, QuantLib::ext::shared_ptr<DefaultCurve>>& requiredDefaultCurves,
281 const QuantLib::ext::shared_ptr<ReferenceDataManager>& referenceData,
283 const bool buildCalibrationInfo,
const Market* market)
284 : asofDate_(asof), curveSpec_(curveSpec), loader_(loader), requiredYieldCurves_(requiredYieldCurves),
285 requiredDefaultCurves_(requiredDefaultCurves), fxTriangulation_(fxTriangulation), referenceData_(referenceData),
286 iborFallbackConfig_(iborFallbackConfig), preserveQuoteLinkage_(preserveQuoteLinkage),
287 buildCalibrationInfo_(buildCalibrationInfo), market_(market) {
292 QL_REQUIRE(
curveConfig_,
"No yield curve configuration found "
298 string discountCurveID =
curveConfig_->discountCurveID();
299 if (discountCurveID !=
curveConfig_->curveID() && !discountCurveID.empty()) {
301 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
306 QL_FAIL(
"The discount curve, " << discountCurveID
307 <<
", required in the building "
353 h_->enableExtrapolation();
374 }
catch (QuantLib::Error& e) {
376 << io::iso_date(asof) <<
": " << e.what());
377 }
catch (std::exception& e) {
380 QL_FAIL(
"unknown error");
384 h_->discount(QL_EPSILON);
389QuantLib::ext::shared_ptr<YieldTermStructure>
394 std::sort(instruments.begin(), instruments.end(), QuantLib::detail::BootstrapHelperSorter());
397 Real accuracy =
curveConfig_->bootstrapConfig().accuracy();
398 Real globalAccuracy =
curveConfig_->bootstrapConfig().globalAccuracy();
399 bool dontThrow =
curveConfig_->bootstrapConfig().dontThrow();
400 Size maxAttempts =
curveConfig_->bootstrapConfig().maxAttempts();
401 Real maxFactor =
curveConfig_->bootstrapConfig().maxFactor();
402 Real minFactor =
curveConfig_->bootstrapConfig().minFactor();
403 Size dontThrowSteps =
curveConfig_->bootstrapConfig().dontThrowSteps();
405 QuantLib::ext::shared_ptr<YieldTermStructure> yieldts;
410 typedef PiecewiseYieldCurve<ZeroYield, Linear, QuantExt::IterativeBootstrap> my_curve;
411 yieldts = QuantLib::ext::make_shared<my_curve>(
413 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
414 minFactor, dontThrowSteps));
417 typedef PiecewiseYieldCurve<ZeroYield, LogLinear, QuantExt::IterativeBootstrap> my_curve;
418 yieldts = QuantLib::ext::make_shared<my_curve>(
420 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
421 minFactor, dontThrowSteps));
424 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
425 yieldts = QuantLib::ext::make_shared<my_curve>(
427 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
428 minFactor, dontThrowSteps));
431 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
432 yieldts = QuantLib::ext::make_shared<my_curve>(
434 Cubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
435 CubicInterpolation::FirstDerivative),
436 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
437 minFactor, dontThrowSteps));
440 typedef PiecewiseYieldCurve<ZeroYield, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
441 yieldts = QuantLib::ext::make_shared<my_curve>(
443 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
444 minFactor, dontThrowSteps));
447 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
448 yieldts = QuantLib::ext::make_shared<my_curve>(
450 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
451 minFactor, dontThrowSteps));
454 typedef PiecewiseYieldCurve<ZeroYield, Cubic, QuantExt::IterativeBootstrap> my_curve;
455 yieldts = QuantLib::ext::make_shared<my_curve>(
457 Cubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
458 CubicInterpolation::SecondDerivative, 0.0),
459 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
463 typedef PiecewiseYieldCurve<ZeroYield, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
465 QuantLib::ext::make_shared<my_curve>(
467 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
468 minFactor, dontThrowSteps));
471 typedef PiecewiseYieldCurve<ZeroYield, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
472 yieldts = QuantLib::ext::make_shared<my_curve>(
474 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
475 minFactor, dontThrowSteps));
478 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
479 yieldts = QuantLib::ext::make_shared<my_curve>(
481 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
482 minFactor, dontThrowSteps));
485 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
486 yieldts = QuantLib::ext::make_shared<my_curve>(
488 LogCubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
489 CubicInterpolation::FirstDerivative),
490 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
494 typedef PiecewiseYieldCurve<ZeroYield, LogCubic, QuantExt::IterativeBootstrap> my_curve;
495 yieldts = QuantLib::ext::make_shared<my_curve>(
497 LogCubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
498 CubicInterpolation::SecondDerivative, 0.0),
499 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
503 typedef PiecewiseYieldCurve<ZeroYield, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
504 yieldts = QuantLib::ext::make_shared<my_curve>(
506 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
507 minFactor, dontThrowSteps));
510 typedef PiecewiseYieldCurve<ZeroYield, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
511 yieldts = QuantLib::ext::make_shared<my_curve>(
513 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
514 minFactor, dontThrowSteps));
517 typedef PiecewiseYieldCurve<ZeroYield, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
518 yieldts = QuantLib::ext::make_shared<my_curve>(
520 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
521 minFactor, dontThrowSteps));
524 typedef PiecewiseYieldCurve<ZeroYield, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
525 yieldts = QuantLib::ext::make_shared<my_curve>(
528 CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
529 CubicInterpolation::SecondDerivative, 0.0),
530 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
531 minFactor, dontThrowSteps));
540 typedef PiecewiseYieldCurve<Discount, Linear, QuantExt::IterativeBootstrap> my_curve;
541 yieldts = QuantLib::ext::make_shared<my_curve>(
543 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
544 minFactor, dontThrowSteps));
547 typedef PiecewiseYieldCurve<Discount, LogLinear, QuantExt::IterativeBootstrap> my_curve;
548 yieldts = QuantLib::ext::make_shared<my_curve>(
550 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
551 minFactor, dontThrowSteps));
554 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
555 yieldts = QuantLib::ext::make_shared<my_curve>(
557 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
558 minFactor, dontThrowSteps));
561 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
562 yieldts = QuantLib::ext::make_shared<my_curve>(
564 Cubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
565 CubicInterpolation::FirstDerivative),
566 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
567 minFactor, dontThrowSteps));
570 typedef PiecewiseYieldCurve<Discount, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
571 yieldts = QuantLib::ext::make_shared<my_curve>(
573 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
574 minFactor, dontThrowSteps));
577 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
578 yieldts = QuantLib::ext::make_shared<my_curve>(
580 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
581 minFactor, dontThrowSteps));
584 typedef PiecewiseYieldCurve<Discount, Cubic, QuantExt::IterativeBootstrap> my_curve;
585 yieldts = QuantLib::ext::make_shared<my_curve>(
587 Cubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
588 CubicInterpolation::SecondDerivative, 0.0),
589 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
590 minFactor, dontThrowSteps));
593 typedef PiecewiseYieldCurve<Discount, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
594 yieldts = QuantLib::ext::make_shared<my_curve>(
596 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
597 minFactor, dontThrowSteps));
600 typedef PiecewiseYieldCurve<Discount, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
601 yieldts = QuantLib::ext::make_shared<my_curve>(
603 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
604 minFactor, dontThrowSteps));
607 typedef PiecewiseYieldCurve<Discount, LogCubic, QuantExt::IterativeBootstrap> my_curve;
608 yieldts = QuantLib::ext::make_shared<my_curve>(
610 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
611 minFactor, dontThrowSteps));
614 typedef PiecewiseYieldCurve<Discount, LogCubic, QuantExt::IterativeBootstrap> my_curve;
615 yieldts = QuantLib::ext::make_shared<my_curve>(
617 QuantLib::LogCubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
618 CubicInterpolation::FirstDerivative),
619 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
623 typedef PiecewiseYieldCurve<Discount,LogCubic, QuantExt::IterativeBootstrap> my_curve;
624 yieldts = QuantLib::ext::make_shared<my_curve>(
626 LogCubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
627 CubicInterpolation::SecondDerivative, 0.0),
628 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
632 typedef PiecewiseYieldCurve<Discount, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
633 yieldts = QuantLib::ext::make_shared<my_curve>(
635 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
636 minFactor, dontThrowSteps));
639 typedef PiecewiseYieldCurve<Discount, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
640 yieldts = QuantLib::ext::make_shared<my_curve>(
642 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
643 minFactor, dontThrowSteps));
646 typedef PiecewiseYieldCurve<Discount, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
647 yieldts = QuantLib::ext::make_shared<my_curve>(
649 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
650 minFactor, dontThrowSteps));
653 typedef PiecewiseYieldCurve<Discount, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
654 yieldts = QuantLib::ext::make_shared<my_curve>(
657 CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
658 CubicInterpolation::SecondDerivative, 0.0),
659 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
660 minFactor, dontThrowSteps));
669 typedef PiecewiseYieldCurve<ForwardRate, Linear, QuantExt::IterativeBootstrap> my_curve;
670 yieldts = QuantLib::ext::make_shared<my_curve>(
672 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
673 minFactor, dontThrowSteps));
676 typedef PiecewiseYieldCurve<ForwardRate, LogLinear, QuantExt::IterativeBootstrap> my_curve;
677 yieldts = QuantLib::ext::make_shared<my_curve>(
679 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
680 minFactor, dontThrowSteps));
683 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
684 yieldts = QuantLib::ext::make_shared<my_curve>(
686 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
687 minFactor, dontThrowSteps));
690 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
691 yieldts = QuantLib::ext::make_shared<my_curve>(
693 Cubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
694 CubicInterpolation::FirstDerivative),
695 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
696 minFactor, dontThrowSteps));
699 typedef PiecewiseYieldCurve<ForwardRate, ConvexMonotone, QuantExt::IterativeBootstrap> my_curve;
700 yieldts = QuantLib::ext::make_shared<my_curve>(
702 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
703 minFactor, dontThrowSteps));
706 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
707 yieldts = QuantLib::ext::make_shared<my_curve>(
709 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
710 minFactor, dontThrowSteps));
713 typedef PiecewiseYieldCurve<ForwardRate, Cubic, QuantExt::IterativeBootstrap> my_curve;
714 yieldts = QuantLib::ext::make_shared<my_curve>(
716 Cubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
717 CubicInterpolation::SecondDerivative, 0.0),
718 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
719 minFactor, dontThrowSteps));
722 typedef PiecewiseYieldCurve<ForwardRate, QuantExt::Quadratic, QuantExt::IterativeBootstrap> my_curve;
723 yieldts = QuantLib::ext::make_shared<my_curve>(
725 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
726 minFactor, dontThrowSteps));
729 typedef PiecewiseYieldCurve<ForwardRate, QuantExt::LogQuadratic, QuantExt::IterativeBootstrap> my_curve;
730 yieldts = QuantLib::ext::make_shared<my_curve>(
732 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
733 minFactor, dontThrowSteps));
736 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
737 yieldts = QuantLib::ext::make_shared<my_curve>(
739 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
743 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
744 yieldts = QuantLib::ext::make_shared<my_curve>(
746 LogCubic(CubicInterpolation::Kruger,
true, CubicInterpolation::SecondDerivative, 0.0,
747 CubicInterpolation::FirstDerivative),
748 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
752 typedef PiecewiseYieldCurve<ForwardRate, LogCubic, QuantExt::IterativeBootstrap> my_curve;
753 yieldts = QuantLib::ext::make_shared<my_curve>(
755 LogCubic(CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
756 CubicInterpolation::SecondDerivative, 0.0),
757 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor, minFactor,
761 typedef PiecewiseYieldCurve<ForwardRate, DefaultLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
762 yieldts = QuantLib::ext::make_shared<my_curve>(
764 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
765 minFactor, dontThrowSteps));
768 typedef PiecewiseYieldCurve<ForwardRate, MonotonicLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
769 yieldts = QuantLib::ext::make_shared<my_curve>(
771 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
772 minFactor, dontThrowSteps));
775 typedef PiecewiseYieldCurve<ForwardRate, KrugerLogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
776 yieldts = QuantLib::ext::make_shared<my_curve>(
778 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
779 minFactor, dontThrowSteps));
782 typedef PiecewiseYieldCurve<ForwardRate, LogMixedLinearCubic, QuantExt::IterativeBootstrap> my_curve;
783 yieldts = QuantLib::ext::make_shared<my_curve>(
786 CubicInterpolation::Spline,
false, CubicInterpolation::SecondDerivative, 0.0,
787 CubicInterpolation::SecondDerivative, 0.0),
788 my_curve::bootstrap_type(accuracy, globalAccuracy, dontThrow, maxAttempts, maxFactor,
789 minFactor, dontThrowSteps));
796 QL_FAIL(
"Interpolation variable not recognised.");
808 vector<Date> dates(instruments.size() + 1,
asofDate_);
809 vector<Real> zeros(instruments.size() + 1, 0.0);
810 vector<Real> discounts(instruments.size() + 1, 1.0);
811 vector<Real> forwards(instruments.size() + 1, 0.0);
814 yieldts->enableExtrapolation();
816 for (Size i = 0; i < instruments.size(); i++) {
817 dates[i + 1] = instruments[i]->pillarDate();
818 zeros[i + 1] = yieldts->zeroRate(dates[i + 1],
zeroDayCounter_, Continuous);
819 discounts[i + 1] = yieldts->discount(dates[i + 1]);
820 forwards[i + 1] = yieldts->forwardRate(dates[i + 1], dates[i + 1],
zeroDayCounter_, Continuous);
823 forwards[0] = forwards[1];
831 QL_FAIL(
"Interpolation variable not recognised.");
836 calibrationInfo_ = QuantLib::ext::make_shared<PiecewiseYieldCurveCalibrationInfo>();
837 for (Size i = 0; i < instruments.size(); ++i) {
847 QL_REQUIRE(
curveSegments_.size() <= 1,
"More than one zero curve "
848 "segment not supported yet.");
851 const QuantLib::ext::shared_ptr<Conventions>& conventions = InstrumentConventions::instance().conventions();
854 vector<QuantLib::ext::shared_ptr<ZeroQuote>> zeroQuotes;
855 QuantLib::ext::shared_ptr<DirectYieldCurveSegment> zeroCurveSegment =
856 QuantLib::ext::dynamic_pointer_cast<DirectYieldCurveSegment>(
curveSegments_[0]);
857 auto zeroQuoteIDs = zeroCurveSegment->quotes();
859 for (Size i = 0; i < zeroQuoteIDs.size(); ++i) {
860 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(zeroQuoteIDs[i],
asofDate_);
863 "Market quote not of type zero.");
864 QuantLib::ext::shared_ptr<ZeroQuote> zeroQuote = QuantLib::ext::dynamic_pointer_cast<ZeroQuote>(marketQuote);
865 zeroQuotes.push_back(zeroQuote);
870 map<Date, Rate>
data;
871 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(
curveSegments_[0]->conventionsID());
872 QL_REQUIRE(convention,
"No conventions found with ID: " <<
curveSegments_[0]->conventionsID());
873 QL_REQUIRE(convention->type() ==
Convention::Type::Zero,
"Conventions ID does not give zero rate conventions.");
874 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention = QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
875 DayCounter quoteDayCounter = zeroConvention->dayCounter();
876 for (Size i = 0; i < zeroQuotes.size(); ++i) {
877 QL_REQUIRE(quoteDayCounter == zeroQuotes[i]->dayCounter(),
878 "The day counter should be the same between the conventions"
880 if (!zeroQuotes[i]->tenorBased()) {
881 data[zeroQuotes[i]->date()] = zeroQuotes[i]->quote()->value();
883 QL_REQUIRE(zeroConvention->tenorBased(),
"Using tenor based "
884 "zero rates without tenor based zero rate conventions.");
886 if (zeroConvention->spotLag() > 0) {
887 zeroDate = zeroConvention->spotCalendar().advance(zeroDate, zeroConvention->spotLag() * Days);
889 zeroDate = zeroConvention->tenorCalendar().advance(zeroDate, zeroQuotes[i]->tenor(),
890 zeroConvention->rollConvention(), zeroConvention->eom());
891 data[zeroDate] = zeroQuotes[i]->quote()->value();
895 QL_REQUIRE(
data.size() > 0,
"No market data found for curve spec " <<
curveSpec_.
name() <<
" with as of date "
900 Rate rate =
data.begin()->second;
903 <<
"date " << QuantLib::io::iso_date(
asofDate_) <<
", "
907 QL_REQUIRE(
data.size() > 1,
"The single zero rate quote provided "
908 "should be associated with a date greater than as of date.");
912 vector<Rate> zeroes, discounts;
913 dates.push_back(
data.begin()->first);
914 zeroes.push_back(
data.begin()->second);
915 discounts.push_back(1.0);
917 Compounding zeroCompounding = zeroConvention->compounding();
918 Frequency zeroCompoundingFreq = zeroConvention->compoundingFrequency();
919 map<Date, Rate>::iterator it;
920 for (it = ++
data.begin(); it !=
data.end(); ++it) {
921 dates.push_back(it->first);
922 InterestRate tempRate(it->second, quoteDayCounter, zeroCompounding, zeroCompoundingFreq);
923 Time t = quoteDayCounter.yearFraction(
asofDate_, it->first);
925 if (zeroCompounding == Continuous) {
926 zeroes.push_back(it->second);
928 zeroes.push_back(tempRate.equivalentRate(Continuous, NoFrequency, t));
930 discounts.push_back(tempRate.discountFactor(t));
931 DLOG(
"Add zero curve point for " <<
curveSpec_.
name() <<
": " << io::iso_date(dates.back()) <<
" " << fixed
932 << setprecision(4) << zeroes.back() <<
" / " << discounts.back());
935 QL_REQUIRE(dates.size() == zeroes.size(),
"Date and zero vectors differ in size.");
936 QL_REQUIRE(dates.size() == discounts.size(),
"Date and discount vectors differ in size.");
940 QuantLib::ext::shared_ptr<YieldTermStructure> tempCurve =
943 for (Size i = 0; i < dates.size(); ++i) {
944 Rate zero = tempCurve->zeroRate(dates[i],
zeroDayCounter_, Continuous);
945 zeroes.push_back(zero);
949 QuantLib::ext::shared_ptr<YieldTermStructure> tempCurve =
952 for (Size i = 0; i < dates.size(); ++i) {
953 DiscountFactor discount = tempCurve->discount(dates[i]);
954 discounts.push_back(discount);
958 QL_FAIL(
"Unknown yield curve interpolation variable.");
963 QL_REQUIRE(
curveSegments_.size() <= 1,
"More than one zero spreaded curve "
964 "segment not supported yet.");
966 "The curve segment is not of type Zero Spread.");
968 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
971 vector<QuantLib::ext::shared_ptr<ZeroQuote>> quotes;
972 QuantLib::ext::shared_ptr<ZeroSpreadedYieldCurveSegment> segment =
973 QuantLib::ext::dynamic_pointer_cast<ZeroSpreadedYieldCurveSegment>(
curveSegments_[0]);
974 auto quoteIDs = segment->quotes();
976 Date today = Settings::instance().evaluationDate();
978 vector<Handle<Quote>> quoteHandles;
979 for (Size i = 0; i < quoteIDs.size(); ++i) {
983 "Market quote not of type yield spread.");
984 QuantLib::ext::shared_ptr<ZeroQuote> zeroQuote = QuantLib::ext::dynamic_pointer_cast<ZeroQuote>(md);
985 quotes.push_back(zeroQuote);
986 dates.push_back(zeroQuote->tenorBased() ? today + zeroQuote->tenor() : zeroQuote->date());
987 quoteHandles.push_back(zeroQuote->quote());
991 QL_REQUIRE(!quotes.empty(),
992 "Cannot build curve with spec " <<
curveSpec_.
name() <<
" because there are no spread quotes");
994 string referenceCurveID = segment->referenceCurveID();
995 QuantLib::ext::shared_ptr<YieldCurve> referenceCurve;
996 if (referenceCurveID !=
curveConfig_->curveID() && !referenceCurveID.empty()) {
998 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
1001 referenceCurve = it->second;
1003 QL_FAIL(
"The reference curve, " << referenceCurveID
1004 <<
", required in the building "
1010 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1011 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
1012 QL_REQUIRE(convention->type() ==
Convention::Type::Zero,
"Conventions ID does not give zero rate conventions.");
1013 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention = QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
1014 DayCounter quoteDayCounter = zeroConvention->dayCounter();
1015 Compounding comp = zeroConvention->compounding();
1016 Frequency freq = zeroConvention->compoundingFrequency();
1018 p_ = QuantLib::ext::shared_ptr<YieldTermStructure>(
new PiecewiseZeroSpreadedTermStructure(
1019 referenceCurve->handle(), quoteHandles, dates, comp, freq, quoteDayCounter));
1024 "One segment required for weighted average curve, got " <<
curveSegments_.size());
1026 "The curve segment is not of type Weighted Average.");
1027 auto segment = QuantLib::ext::dynamic_pointer_cast<WeightedAverageYieldCurveSegment>(
curveSegments_[0]);
1028 QL_REQUIRE(segment !=
nullptr,
"expected WeightedAverageYieldCurveSegment, this is unexpected");
1031 QL_REQUIRE(it1 !=
requiredYieldCurves_.end(),
"Could not find reference curve1: " << segment->referenceCurveID1());
1032 QL_REQUIRE(it2 !=
requiredYieldCurves_.end(),
"Could not find reference curve2: " << segment->referenceCurveID2());
1033 p_ = QuantLib::ext::make_shared<WeightedYieldTermStructure>(it1->second->handle(), it2->second->handle(),
1034 segment->weight1(), segment->weight2());
1039 "One segment required for yield plus default curve, got " <<
curveSegments_.size());
1041 "The curve segment is not of type Yield Plus Default.");
1042 auto segment = QuantLib::ext::dynamic_pointer_cast<YieldPlusDefaultYieldCurveSegment>(
curveSegments_[0]);
1043 QL_REQUIRE(segment !=
nullptr,
"expected YieldPlusDefaultCurveSegment, this is unexpected");
1045 QL_REQUIRE(it !=
requiredYieldCurves_.end(),
"Could not find reference curve: " << segment->referenceCurveID());
1046 std::vector<Handle<DefaultProbabilityTermStructure>> defaultCurves;
1047 std::vector<Handle<Quote>> recRates;
1048 for (Size i = 0; i < segment->defaultCurveIDs().
size(); ++i) {
1051 "Could not find default curve: " << segment->defaultCurveIDs()[i]);
1052 defaultCurves.push_back(Handle<DefaultProbabilityTermStructure>(it->second->creditCurve()->curve()));
1053 recRates.push_back(Handle<Quote>(QuantLib::ext::make_shared<SimpleQuote>(it->second->recoveryRate())));
1055 p_ = QuantLib::ext::make_shared<YieldPlusDefaultYieldTermStructure>(it->second->handle(), defaultCurves, recRates,
1056 segment->weights());
1061 "One segment required for ibor fallback curve, got " <<
curveSegments_.size());
1063 "The curve segment is not of type Ibor Fallback");
1064 auto segment = QuantLib::ext::dynamic_pointer_cast<IborFallbackCurveSegment>(
curveSegments_[0]);
1065 QL_REQUIRE(segment !=
nullptr,
"expected IborFallbackCurve, internal error");
1067 QL_REQUIRE(it !=
requiredYieldCurves_.end(),
"Could not find rfr curve: '" << segment->rfrCurve() <<
"')");
1070 "buildIborFallbackCurve(): ibor index '"
1071 << segment->iborIndex()
1072 <<
"' must be specified in ibor fallback config, if RfrIndex or Spread is not specified in curve config");
1077 auto originalIndex =
parseIborIndex(segment->iborIndex(), dummyCurve);
1078 auto rfrIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(
parseIborIndex(rfrIndexName, it->second->handle()));
1079 QL_REQUIRE(rfrIndex,
"buidlIborFallbackCurve(): rfr index '"
1080 << rfrIndexName <<
"' could not be cast to OvernightIndex, is this index name correct?");
1081 DLOG(
"building ibor fallback curve for '" << segment->iborIndex() <<
"' with rfrIndex='" << rfrIndexName
1082 <<
"' and spread=" << spread);
1083 if (
auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(originalIndex)) {
1084 p_ = QuantLib::ext::make_shared<OvernightFallbackCurve>(on, rfrIndex, spread, Date::minDate());
1086 p_ = QuantLib::ext::make_shared<IborFallbackCurve>(originalIndex, rfrIndex, spread, Date::minDate());
1092 QL_REQUIRE(
curveSegments_.size() <= 1,
"More than one discount curve "
1093 "segment not supported yet.");
1095 "The curve segment is not of type Discount.");
1098 map<Date, DiscountFactor>
data;
1099 QuantLib::ext::shared_ptr<DirectYieldCurveSegment> discountCurveSegment =
1100 QuantLib::ext::dynamic_pointer_cast<DirectYieldCurveSegment>(
curveSegments_[0]);
1101 auto discountQuoteIDs = discountCurveSegment->quotes();
1103 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1104 QuantLib::ext::shared_ptr<Convention> convention;
1106 vector<string> quotes;
1107 quotes.reserve(discountQuoteIDs.size());
1109 std::transform(discountQuoteIDs.begin(), discountQuoteIDs.end(), std::back_inserter(quotes),
1110 [](
const std::pair<string, bool>& pair) {
1116 std::set<QuantLib::ext::shared_ptr<MarketDatum>> marketData;
1120 std::ostringstream ss;
1126 for (
const auto& marketQuote : marketData) {
1128 "Market quote not of type Discount.");
1129 QuantLib::ext::shared_ptr<DiscountQuote> discountQuote = QuantLib::ext::dynamic_pointer_cast<DiscountQuote>(marketQuote);
1133 vector<string>::const_iterator it = find(quotes.begin(), quotes.end(), discountQuote->name());
1134 if (it == quotes.end())
1138 if (discountQuote->date() != Date()) {
1140 data[discountQuote->date()] = discountQuote->quote()->value();
1142 }
else if (discountQuote->tenor() != Period()) {
1145 convention = conventions->get(discountCurveSegment->conventionsID());
1146 QuantLib::ext::shared_ptr<ZeroRateConvention> zeroConvention =
1147 QuantLib::ext::dynamic_pointer_cast<ZeroRateConvention>(convention);
1148 QL_REQUIRE(zeroConvention,
"could not cast to ZeroRateConvention");
1150 Calendar cal = zeroConvention->tenorCalendar();
1151 BusinessDayConvention rollConvention = zeroConvention->rollConvention();
1152 Date date = cal.adjust(cal.adjust(
asofDate_, rollConvention) + discountQuote->tenor(), rollConvention);
1153 DLOG(
"YieldCurve::buildDiscountCurve - tenor " << discountQuote->tenor() <<
" to date "
1154 << io::iso_date(date));
1155 data[date] = discountQuote->quote()->value();
1158 QL_FAIL(
"YieldCurve::buildDiscountCurve - neither date nor tenor recognised");
1163 QL_REQUIRE(
data.size() > 0,
"No market data found for curve spec " <<
curveSpec_.
name() <<
" with as of date "
1166 QL_REQUIRE(
data.size() == quotes.size(),
"Found " <<
data.size() <<
" quotes, but "
1168 <<
" quotes given in config " <<
curveConfig_->curveID());
1176 QL_REQUIRE(
data.size() > 1,
"The single discount quote provided "
1177 "should be associated with a date greater than as of date.");
1181 vector<DiscountFactor> discounts;
1182 map<Date, DiscountFactor>::iterator it;
1183 for (it =
data.begin(); it !=
data.end(); ++it) {
1184 dates.push_back(it->first);
1185 discounts.push_back(it->second);
1186 DLOG(
"Add discount curve point for " <<
curveSpec_.
name() <<
": " << io::iso_date(dates.back()) <<
" "
1187 << discounts.back());
1190 QL_REQUIRE(dates.size() == discounts.size(),
"Date and discount vectors differ in size.");
1192 QuantLib::ext::shared_ptr<YieldTermStructure> tempDiscCurve =
1199 vector<Rate> zeroes;
1200 for (Size i = 0; i < dates.size(); ++i) {
1201 Rate zero = tempDiscCurve->zeroRate(dates[i],
zeroDayCounter_, Continuous);
1202 zeroes.push_back(zero);
1206 QL_FAIL(
"Unknown yield curve interpolation variable.");
1212 QL_REQUIRE(!
curveSegments_.empty(),
"no curve segments defined.");
1216 DLOG(
"Building instrument sets for yield curve segments 0..." <<
curveSegments_.size() - 1);
1218 std::vector<vector<QuantLib::ext::shared_ptr<RateHelper>>> instrumentsPerSegment(
curveSegments_.size());
1259 QL_FAIL(
"Yield curve segment type not recognized.");
1267 for (
auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1268 if (std::next(it, 1) != instrumentsPerSegment[i].end() &&
1269 (*it)->pillarDate() == (*std::next(it, 1))->pillarDate()) {
1270 DLOG(
"Removing instrument with pillar date "
1271 << (*it)->pillarDate() <<
" in segment #" << i
1272 <<
" because the next instrument in the same segment has the same pillar date");
1273 it = instrumentsPerSegment[i].erase(it);
1281 std::vector<std::pair<Date, Date>> minMaxDatePerSegment(
curveSegments_.size(),
1282 std::make_pair(Date::maxDate(), Date::minDate()));
1284 if (!instrumentsPerSegment[i].empty()) {
1285 auto [minIt, maxIt] =
1286 std::minmax_element(instrumentsPerSegment[i].begin(), instrumentsPerSegment[i].end(),
1287 [](
const QuantLib::ext::shared_ptr<RateHelper>& h,
const QuantLib::ext::shared_ptr<RateHelper>& j) {
1288 return h->pillarDate() < h->pillarDate();
1290 minMaxDatePerSegment[i] = std::make_pair((*minIt)->pillarDate(), (*maxIt)->pillarDate());
1299 for (
auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1300 if ((*it)->pillarDate() > minMaxDatePerSegment[i + 1].first -
curveSegments_[i]->minDistance()) {
1301 DLOG(
"Removing instrument in segment #"
1302 << i <<
" (priority " <<
curveSegments_[i]->priority() <<
") because its pillar date "
1303 << (*it)->pillarDate() <<
" > " << minMaxDatePerSegment[i + 1].first
1304 <<
" (min pillar date in segment #" << (i + 1) <<
", priority "
1306 <<
" (min distance in segment #" << i <<
")");
1307 it = instrumentsPerSegment[i].erase(it);
1313 for (
auto it = instrumentsPerSegment[i].begin(); it != instrumentsPerSegment[i].end();) {
1314 if ((*it)->pillarDate() < minMaxDatePerSegment[i - 1].second +
curveSegments_[i - 1]->minDistance()) {
1315 DLOG(
"Removing instrument in segment #"
1316 << i <<
" (priority " <<
curveSegments_[i]->priority() <<
") because its pillar date "
1317 << (*it)->pillarDate() <<
" < " << minMaxDatePerSegment[i - 1].second
1318 <<
" (max pillar date in segment #" << (i - 1) <<
", priority "
1320 <<
" (min distance in segment #" << (i - 1) <<
")");
1321 it = instrumentsPerSegment[i].erase(it);
1331 for (Size i = 0; i <
curveConfig_->mixedInterpolationCutoff(); ++i)
1336 vector<QuantLib::ext::shared_ptr<RateHelper>> instruments;
1338 instruments.insert(instruments.end(), instrumentsPerSegment[i].begin(), instrumentsPerSegment[i].end());
1339 DLOG(
"Adding " << instrumentsPerSegment[i].
size() <<
" instruments for segment #" << i);
1344 DLOG(
"Bootstrapping with " << instruments.size() <<
" instruments");
1345 QL_REQUIRE(instruments.size() > 0,
1351 QL_REQUIRE(
curveSegments_.size() == 1,
"A discount ratio curve must contain exactly one segment");
1353 "The curve segment is not of type 'DiscountRatio'.");
1355 QuantLib::ext::shared_ptr<DiscountRatioYieldCurveSegment> segment =
1356 QuantLib::ext::dynamic_pointer_cast<DiscountRatioYieldCurveSegment>(
curveSegments_[0]);
1359 QuantLib::ext::shared_ptr<YieldCurve> baseCurve =
getYieldCurve(segment->baseCurveCurrency(), segment->baseCurveId());
1360 QL_REQUIRE(baseCurve,
"The base curve '" << segment->baseCurveId() <<
"' cannot be empty");
1362 QuantLib::ext::shared_ptr<YieldCurve> numCurve =
1363 getYieldCurve(segment->numeratorCurveCurrency(), segment->numeratorCurveId());
1364 QL_REQUIRE(numCurve,
"The numerator curve '" << segment->numeratorCurveId() <<
"' cannot be empty");
1366 QuantLib::ext::shared_ptr<YieldCurve> denCurve =
1367 getYieldCurve(segment->denominatorCurveCurrency(), segment->denominatorCurveId());
1368 QL_REQUIRE(denCurve,
"The denominator curve '" << segment->denominatorCurveId() <<
"' cannot be empty");
1370 p_ = QuantLib::ext::make_shared<DiscountRatioModifiedCurve>(baseCurve->handle(), numCurve->handle(), denCurve->handle());
1376 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::const_iterator it =
requiredYieldCurves_.find(idLookup);
1378 <<
"' required in the building of the curve '"
1387 QL_REQUIRE(
curveSegments_.size() == 1,
"FittedBond curve must contain exactly one segment.");
1389 "The curve segment is not of type 'FittedBond'.");
1391 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1393 QuantLib::ext::shared_ptr<FittedBondYieldCurveSegment> curveSegment =
1394 QuantLib::ext::dynamic_pointer_cast<FittedBondYieldCurveSegment>(
curveSegments_[0]);
1395 QL_REQUIRE(curveSegment !=
nullptr,
"could not cast to FittedBondYieldCurveSegment, this is unexpected");
1399 auto calInfo = QuantLib::ext::make_shared<FittedBondCurveCalibrationInfo>();
1407 auto quoteIDs = curveSegment->quotes();
1408 std::vector<QuantLib::ext::shared_ptr<QuantLib::Bond>> bonds;
1409 std::vector<QuantLib::ext::shared_ptr<BondHelper>> helpers;
1410 std::vector<Real> marketPrices, marketYields;
1411 std::vector<std::string> securityIDs;
1412 std::vector<Date> securityMaturityDates;
1413 Date lastMaturity = Date::minDate(), firstMaturity = Date::maxDate();
1418 auto engineData = QuantLib::ext::make_shared<EngineData>();
1419 engineData->model(
"Bond") =
"DiscountedCashflows";
1420 engineData->engine(
"Bond") =
"DiscountingRiskyBondEngine";
1421 engineData->engineParameters(
"Bond") = {{
"TimestepPeriod",
"6M"}};
1423 std::map<std::string, Handle<YieldTermStructure>> iborCurveMapping;
1424 for (
auto const& c : curveSegment->iborIndexCurves()) {
1426 auto key = yieldCurveKey(index->currency(), c.second,
asofDate_);
1428 QL_REQUIRE(y !=
requiredYieldCurves_.end(),
"required yield curve '" << key <<
"' for iborIndex '" << c.first
1429 <<
"' not provided for fitted bond curve");
1430 iborCurveMapping[c.first] = y->second->handle();
1433 auto engineFactory =
1434 QuantLib::ext::make_shared<EngineFactory>(engineData, QuantLib::ext::make_shared<FittedBondCurveHelperMarket>(iborCurveMapping),
1437 for (Size i = 0; i < quoteIDs.size(); ++i) {
1442 "Market quote not of type Bond / Price.");
1443 QuantLib::ext::shared_ptr<BondPriceQuote> bondQuote = QuantLib::ext::dynamic_pointer_cast<BondPriceQuote>(marketQuote);
1444 QL_REQUIRE(bondQuote,
"market quote has type bond quote, but can not be casted, this is unexpected.");
1445 auto m = [](Real x) {
return 100.0 * x; };
1446 Handle<Quote> rescaledBondQuote(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(bondQuote->quote(), m));
1447 string securityID = bondQuote->securityID();
1449 QL_REQUIRE(
referenceData_ !=
nullptr,
"reference data required to build fitted bond curve");
1450 auto res = BondFactory::instance().build(engineFactory,
referenceData_, securityID);
1451 auto qlInstr = res.bond;
1453 if (qlInstr->settlementDate() >
asofDate_ && QuantLib::BondFunctions::isTradable(*qlInstr)) {
1454 bonds.push_back(qlInstr);
1455 helpers.push_back(QuantLib::ext::make_shared<BondHelper>(rescaledBondQuote, qlInstr));
1456 Date thisMaturity = qlInstr->maturityDate();
1457 lastMaturity = std::max(lastMaturity, thisMaturity);
1458 firstMaturity = std::min(firstMaturity, thisMaturity);
1459 Real inflationFactor = res.inflationFactor();
1460 Real marketYield = qlInstr->yield(rescaledBondQuote->value() * inflationFactor,
1461 ActualActual(ActualActual::ISDA),
1462 Continuous, NoFrequency);
1463 DLOG(
"added bond " << securityID <<
", maturity = " << QuantLib::io::iso_date(thisMaturity)
1464 <<
", clean price = " << rescaledBondQuote->value() * inflationFactor
1465 <<
", yield (cont,act/act) = " << marketYield);
1466 marketPrices.push_back(bondQuote->quote()->value() * inflationFactor);
1467 securityIDs.push_back(securityID);
1468 marketYields.push_back(marketYield);
1469 securityMaturityDates.push_back(thisMaturity);
1471 DLOG(
"skipped bond " << securityID <<
" with settlement date "
1472 << QuantLib::io::iso_date(qlInstr->settlementDate()) <<
", isTradable = "
1473 << std::boolalpha << QuantLib::BondFunctions::isTradable(*qlInstr));
1478 calInfo->securities = securityIDs;
1479 calInfo->securityMaturityDates = securityMaturityDates;
1480 calInfo->marketPrices = marketPrices;
1481 calInfo->marketYields = marketYields;
1485 QL_REQUIRE(helpers.size() >= 1,
"no bonds for fitting bond curve");
1486 DLOG(
"Fitting bond curve with " << helpers.size() <<
" bonds.");
1488 Real minCutoffTime = 0.0, maxCutoffTime = QL_MAX_REAL;
1489 if (curveSegment->extrapolateFlat()) {
1492 DLOG(
"extrapolate flat outside " << minCutoffTime <<
"," << maxCutoffTime);
1495 QuantLib::ext::shared_ptr<FittedBondDiscountCurve::FittingMethod> method;
1498 method = QuantLib::ext::make_shared<ExponentialSplinesFitting>(
true, Array(), ext::shared_ptr<OptimizationMethod>(),
1499 Array(), minCutoffTime, maxCutoffTime);
1500 calInfo->fittingMethod =
"ExponentialSplines";
1503 method = QuantLib::ext::make_shared<NelsonSiegelFitting>(Array(), ext::shared_ptr<OptimizationMethod>(), Array(),
1504 minCutoffTime, maxCutoffTime);
1505 calInfo->fittingMethod =
"NelsonSiegel";
1508 method = QuantLib::ext::make_shared<SvenssonFitting>(Array(), ext::shared_ptr<OptimizationMethod>(), Array(),
1509 minCutoffTime, maxCutoffTime);
1510 calInfo->fittingMethod =
"Svensson";
1513 QL_FAIL(
"unknown fitting method");
1516 QuantLib::ext::shared_ptr<FittedBondDiscountCurve> tmp, current;
1517 Real minError = QL_MAX_REAL;
1518 HaltonRsg halton(method->size(), 42);
1522 trials =
curveConfig_->bootstrapConfig().maxAttempts();
1524 if (
curveConfig_->bootstrapConfig().maxAttempts() > 1) {
1525 WLOG(
"randomised optimisation seeds not implemented for given interpolation method");
1528 for (Size i = 0; i < trials; ++i) {
1536 Integer maxMaturity =
static_cast<Integer
>(
1537 std::distance(securityMaturityDates.begin(),
1538 std::max_element(securityMaturityDates.begin(), securityMaturityDates.end())));
1539 Integer minMaturity =
static_cast<Integer
>(
1540 std::distance(securityMaturityDates.begin(),
1541 std::min_element(securityMaturityDates.begin(), securityMaturityDates.end())));
1542 guess[0] = marketYields[maxMaturity];
1543 guess[1] = marketYields[minMaturity] - guess[0];
1546 DLOG(
"using smart NelsonSiegel guess for trial #" << (i + 1) <<
": " << guess);
1549 auto seq = halton.nextSequence();
1550 guess = Array(seq.value.begin(), seq.value.end());
1552 guess[0] = guess[0] * 0.10 - 0.05;
1553 guess[1] = guess[1] * 0.10 - 0.05;
1554 guess[2] = guess[2] * 0.10 - 0.05;
1555 guess[3] = guess[3] * 5.0;
1556 DLOG(
"using random NelsonSiegel guess for trial #" << (i + 1) <<
": " << guess);
1558 QL_FAIL(
"randomised optimisation seed not implemented");
1561 current = QuantLib::ext::make_shared<FittedBondDiscountCurve>(
asofDate_, helpers,
zeroDayCounter_, *method, 1.0e-10,
1563 Real cost = std::sqrt(current->fitResults().minimumCostValue());
1564 if (cost < minError) {
1568 DLOG(
"calibration trial #" << (i + 1) <<
" out of " << trials <<
": cost = " << cost
1569 <<
", best so far = " << minError);
1570 if (cost < curveConfig_->bootstrapConfig().accuracy()) {
1571 DLOG(
"reached desired accuracy (" <<
curveConfig_->bootstrapConfig().accuracy()
1572 <<
") - do not attempt more calibrations");
1576 QL_REQUIRE(tmp,
"no best solution found for fitted bond curve - this is unexpected.");
1578 if (Norm2(tmp->fitResults().solution()) < 1.0e-4) {
1579 WLOG(
"Fit solution is close to 0. The curve fitting should be reviewed.");
1582 DLOG(
"Fitted Bond Curve Summary:");
1583 DLOG(
" solution: " << tmp->fitResults().solution());
1584 DLOG(
" iterations: " << tmp->fitResults().numberOfIterations());
1585 DLOG(
" cost value: " << minError);
1587 std::vector<Real> modelPrices, modelYields;
1588 auto engine = QuantLib::ext::make_shared<DiscountingBondEngine>(Handle<YieldTermStructure>(tmp));
1589 for (Size i = 0; i < bonds.size(); ++i) {
1590 bonds[i]->setPricingEngine(engine);
1591 modelPrices.push_back(bonds[i]->cleanPrice() / 100.0);
1592 modelYields.push_back(bonds[i]->yield(bonds[i]->cleanPrice(), ActualActual(ActualActual::ISDA), Continuous, NoFrequency));
1593 DLOG(
"bond " << securityIDs[i] <<
", model clean price = " << modelPrices.back()
1594 <<
", yield (cont,actact) = " << modelYields.back() <<
", NPV = " << bonds[i]->NPV());
1597 Real tolerance =
curveConfig_->bootstrapConfig().globalAccuracy() == Null<Real>()
1600 QL_REQUIRE(
curveConfig_->bootstrapConfig().dontThrow() || minError < tolerance,
1601 "Fitted Bond Curve cost value (" << minError <<
") exceeds tolerance (" << tolerance <<
")");
1604 tmp->enableExtrapolation();
1608 Array solution = tmp->fitResults().solution();
1611 calInfo->modelPrices = modelPrices;
1612 calInfo->modelYields = modelYields;
1613 calInfo->tolerance = tolerance;
1614 calInfo->costValue = minError;
1615 calInfo->solution = std::vector<double>(solution.begin(), solution.end());
1616 calInfo->iterations =
static_cast<int>(tmp->fitResults().numberOfIterations());
1623 "One segment required for bond yield shifted curve, got " <<
curveSegments_.size());
1625 "The curve segment is not of type Bond Yield Shifted.");
1626 auto segment = QuantLib::ext::dynamic_pointer_cast<BondYieldShiftedYieldCurveSegment>(
curveSegments_[0]);
1627 QL_REQUIRE(segment !=
nullptr,
"expected BondYieldShiftedYieldCurveSegment, this is unexpected");
1629 QL_REQUIRE(it !=
requiredYieldCurves_.end(),
"Could not find reference curve: " << segment->referenceCurveID());
1632 auto quoteIDs = segment->quotes();
1633 QuantLib::ext::shared_ptr<QuantLib::Bond> bond;
1635 Date securityMaturityDate;
1636 Rate bondYield = Null<Real>();
1637 Real thisDuration = Null<Real>();
1639 auto engineData = QuantLib::ext::make_shared<EngineData>();
1640 engineData->model(
"Bond") =
"DiscountedCashflows";
1641 engineData->engine(
"Bond") =
"DiscountingRiskyBondEngine";
1642 engineData->engineParameters(
"Bond") = {{
"TimestepPeriod",
"3M"}};
1645 std::map<std::string, Handle<YieldTermStructure>> iborCurveMapping;
1646 for (
auto const& c : segment->iborIndexCurves()) {
1648 auto key = yieldCurveKey(index->currency(), c.second,
asofDate_);
1650 QL_REQUIRE(y !=
requiredYieldCurves_.end(),
"required ibor curve '" << key <<
"' for iborIndex '" << c.first
1651 <<
"' not provided");
1652 iborCurveMapping[c.first] = y->second->handle();
1655 auto engineFactory = QuantLib::ext::make_shared<EngineFactory>(engineData,
1656 QuantLib::ext::make_shared<FittedBondCurveHelperMarket>(iborCurveMapping),
1657 std::map<MarketContext, string>(),
1661 QL_REQUIRE(quoteIDs.size() > 0,
"at least one bond for shifting of the reference curve required.");
1663 std::vector<Real> bondYields, bondDurations;
1665 for (Size b = 0; b < quoteIDs.size(); ++b) {
1669 QL_REQUIRE(marketQuote !=
nullptr,
"no quotes for the bond " << quoteIDs[b].first <<
" found. this is unexpected");
1672 "Market quote not of type Bond / Price.");
1673 QuantLib::ext::shared_ptr<BondPriceQuote> bondQuote = QuantLib::ext::dynamic_pointer_cast<BondPriceQuote>(marketQuote);
1674 QL_REQUIRE(bondQuote,
"market quote has type bond quote, but can not be casted, this is unexpected.");
1675 auto m = [bondQuote](Real x) {
return x * 100.0; };
1676 Handle<Quote> rescaledBondQuote(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(bondQuote->quote(), m));
1678 securityID = bondQuote->securityID();
1679 QL_REQUIRE(
referenceData_ !=
nullptr,
"reference data required to build bond yield shifted curve");
1681 auto res = BondFactory::instance().build(engineFactory,
referenceData_, securityID);
1682 auto qlInstr = res.bond;
1683 auto inflationQuoteFactor = res.inflationFactor();
1686 if (qlInstr->settlementDate() >
asofDate_ && QuantLib::BondFunctions::isTradable(*qlInstr)) {
1688 Date thisMaturity = qlInstr->maturityDate();
1689 bondYield = qlInstr->yield(rescaledBondQuote->value() * inflationQuoteFactor,
1690 ActualActual(ActualActual::ISDA), Continuous, NoFrequency);
1692 thisDuration = QuantLib::BondFunctions::duration(*qlInstr,InterestRate(bondYield,ActualActual(ActualActual::ISDA),Continuous,NoFrequency)
1695 DLOG(
"found bond " << securityID <<
", maturity = " << QuantLib::io::iso_date(thisMaturity)
1696 <<
", clean price = " << rescaledBondQuote->value() * inflationQuoteFactor
1697 <<
", yield (cont,act/act) = " << bondYield
1698 <<
", duration = " << thisDuration);
1700 bondYields.push_back(bondYield);
1701 bondDurations.push_back(thisDuration);
1703 DLOG(
"calculated duration of the bond " << securityID <<
" is equal to " << thisDuration)
1707 DLOG(
"Skipping bond " << securityID
1708 <<
", with settlement date " << QuantLib::io::iso_date(qlInstr->settlementDate())
1709 <<
", isTradable = " << std::boolalpha << QuantLib::BondFunctions::isTradable(*qlInstr));
1714 p_ = QuantLib::ext::make_shared<BondYieldShiftedCurveTermStructure>(it->second->handle(), bondYields, bondDurations);
1719 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
1721 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
1724 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1725 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1726 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
1728 "Conventions ID does not give deposit rate conventions.");
1729 QuantLib::ext::shared_ptr<DepositConvention> depositConvention = QuantLib::ext::dynamic_pointer_cast<DepositConvention>(convention);
1731 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> depositSegment =
1732 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1733 auto depositQuoteIDs = depositSegment->quotes();
1735 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1736 "Deposit segment does not support pillar choice " << segment->pillarChoice());
1737 for (Size i = 0; i < depositQuoteIDs.size(); i++) {
1738 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(depositQuoteIDs[i],
asofDate_);
1742 QuantLib::ext::shared_ptr<MoneyMarketQuote> depositQuote;
1744 "Market quote not of type Deposit.");
1745 depositQuote = QuantLib::ext::dynamic_pointer_cast<MoneyMarketQuote>(marketQuote);
1748 QuantLib::ext::shared_ptr<RateHelper> depositHelper;
1749 Period depositTerm = depositQuote->term();
1750 Period fwdStart = depositQuote->fwdStart();
1751 Natural fwdStartDays =
static_cast<Natural
>(fwdStart.length());
1752 Handle<Quote> hQuote(depositQuote->quote());
1754 QL_REQUIRE(fwdStart.units() == Days,
"The forward start time unit for deposits "
1755 "must be expressed in days.");
1757 if (depositConvention->indexBased()) {
1760 string indexName = depositConvention->index();
1761 QuantLib::ext::shared_ptr<IborIndex> index;
1772 ss << indexName <<
"-" << io::short_period(depositTerm);
1773 indexName = ss.str();
1776 depositHelper = QuantLib::ext::make_shared<DepositRateHelper>(
1777 hQuote, depositTerm, fwdStartDays, index->fixingCalendar(), index->businessDayConvention(),
1778 index->endOfMonth(), index->dayCounter());
1780 depositHelper = QuantLib::ext::make_shared<DepositRateHelper>(
1781 hQuote, depositTerm, fwdStartDays, depositConvention->calendar(), depositConvention->convention(),
1782 depositConvention->eom(), depositConvention->dayCounter());
1784 instruments.push_back(depositHelper);
1790 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
1792 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
1795 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1796 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1797 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
1799 "Conventions ID does not give deposit rate conventions.");
1800 QuantLib::ext::shared_ptr<FutureConvention> futureConvention = QuantLib::ext::dynamic_pointer_cast<FutureConvention>(convention);
1802 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> futureSegment =
1803 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1804 auto futureQuoteIDs = futureSegment->quotes();
1806 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1807 "Future segment does not support pillar choice " << segment->pillarChoice());
1808 for (Size i = 0; i < futureQuoteIDs.size(); i++) {
1809 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(futureQuoteIDs[i],
asofDate_);
1814 if (
auto on = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(futureConvention->index())) {
1816 QuantLib::ext::shared_ptr<OIFutureQuote> futureQuote;
1818 "Market quote not of type Overnight Index Future.");
1819 futureQuote = QuantLib::ext::dynamic_pointer_cast<OIFutureQuote>(marketQuote);
1823 QL_REQUIRE(futureQuote->tenor().units() == Months || futureQuote->tenor().units() == Years,
1824 "Tenor of future quote (" << futureQuote->name()
1825 <<
") must be expressed in months or years");
1828 Date startDate, endDate;
1830 Date refEnd = Date(1, futureQuote->expiryMonth(), futureQuote->expiryYear());
1831 Date refStart = refEnd - futureQuote->tenor();
1832 startDate = IMM::nextDate(refStart,
false);
1833 endDate = IMM::nextDate(refEnd,
false);
1834 }
else if (futureConvention->dateGenerationRule() ==
1836 endDate = Date(1, futureQuote->expiryMonth(), futureQuote->expiryYear()) + 1 * Months;
1837 startDate = endDate - futureQuote->tenor();
1841 DLOG(
"Skipping the " << io::ordinal(i + 1) <<
" overnight index future instrument because its "
1842 <<
"end date, " << io::iso_date(endDate)
1843 <<
", is on or before the valuation date, " << io::iso_date(
asofDate_) <<
".");
1847 QuantLib::ext::shared_ptr<RateHelper> futureHelper = QuantLib::ext::make_shared<OvernightIndexFutureRateHelper>(
1848 futureQuote->quote(), startDate, endDate, on, Handle<Quote>(),
1849 futureConvention->overnightIndexFutureNettingType());
1850 instruments.push_back(futureHelper);
1852 TLOG(
"adding OI future helper: price=" << futureQuote->quote()->value() <<
" start=" << startDate
1853 <<
" end=" << endDate <<
" nettingType="
1854 << futureConvention->overnightIndexFutureNettingType());
1858 QuantLib::ext::shared_ptr<MMFutureQuote> futureQuote;
1860 "Market quote not of type Money Market Future.");
1861 futureQuote = QuantLib::ext::dynamic_pointer_cast<MMFutureQuote>(marketQuote);
1866 "For MM Futures only 'IMM' is allowed as the date generation rule, check the future convention '"
1867 << segment->conventionsID() <<
"'");
1868 Date refDate(1, futureQuote->expiryMonth(), futureQuote->expiryYear());
1869 Date immDate = IMM::nextDate(refDate,
false);
1872 DLOG(
"Skipping the " << io::ordinal(i + 1) <<
" money market future instrument because its "
1873 <<
"start date, " << io::iso_date(immDate)
1874 <<
", is before the valuation date, " << io::iso_date(
asofDate_) <<
".");
1878 QuantLib::ext::shared_ptr<RateHelper> futureHelper =
1879 QuantLib::ext::make_shared<FuturesRateHelper>(futureQuote->quote(), immDate, futureConvention->index());
1881 instruments.push_back(futureHelper);
1888 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
1890 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
1893 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1894 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1895 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
1896 QL_REQUIRE(convention->type() ==
Convention::Type::FRA,
"Conventions ID does not give FRA conventions.");
1897 QuantLib::ext::shared_ptr<FraConvention> fraConvention = QuantLib::ext::dynamic_pointer_cast<FraConvention>(convention);
1899 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> fraSegment =
1900 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1901 auto fraQuoteIDs = fraSegment->quotes();
1903 for (Size i = 0; i < fraQuoteIDs.size(); i++) {
1904 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(fraQuoteIDs[i],
asofDate_);
1910 "Market quote not of type FRA.");
1914 QuantLib::ext::shared_ptr<RateHelper> fraHelper;
1917 QuantLib::ext::shared_ptr<ImmFraQuote> immFraQuote;
1918 immFraQuote = QuantLib::ext::dynamic_pointer_cast<ImmFraQuote>(marketQuote);
1919 Size imm1 = immFraQuote->imm1();
1920 Size imm2 = immFraQuote->imm2();
1921 fraHelper = QuantLib::ext::make_shared<ImmFraRateHelper>(immFraQuote->quote(), imm1, imm2,
1922 fraConvention->index(), fraSegment->pillarChoice());
1924 QuantLib::ext::shared_ptr<FRAQuote> fraQuote;
1925 fraQuote = QuantLib::ext::dynamic_pointer_cast<FRAQuote>(marketQuote);
1926 Period periodToStart = fraQuote->fwdStart();
1927 fraHelper = QuantLib::ext::make_shared<FraRateHelper>(fraQuote->quote(), periodToStart, fraConvention->index(),
1928 fraSegment->pillarChoice());
1930 QL_FAIL(
"Market quote not of type FRA.");
1933 instruments.push_back(fraHelper);
1939 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
1941 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
1944 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
1945 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
1946 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
1947 QL_REQUIRE(convention->type() ==
Convention::Type::OIS,
"Conventions ID does not give OIS conventions.");
1948 QuantLib::ext::shared_ptr<OisConvention> oisConvention = QuantLib::ext::dynamic_pointer_cast<OisConvention>(convention);
1950 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> oisSegment =
1951 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
1954 string projectionCurveID = oisSegment->projectionCurveID();
1955 QuantLib::ext::shared_ptr<OvernightIndex> onIndex = oisConvention->index();
1956 if (projectionCurveID !=
curveConfig_->curveID() && !projectionCurveID.empty()) {
1958 QuantLib::ext::shared_ptr<YieldCurve> projectionCurve;
1959 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
1962 projectionCurve = it->second;
1964 QL_FAIL(
"The projection curve, " << projectionCurveID
1965 <<
", required in the building "
1969 onIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(onIndex->clone(projectionCurve->handle()));
1973 QuantLib::ext::shared_ptr<BRLCdi> brlCdiIndex = QuantLib::ext::dynamic_pointer_cast<BRLCdi>(onIndex);
1975 auto oisQuoteIDs = oisSegment->quotes();
1976 for (Size i = 0; i < oisQuoteIDs.size(); i++) {
1977 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(oisQuoteIDs[i],
asofDate_);
1981 QuantLib::ext::shared_ptr<SwapQuote> oisQuote;
1983 "Market quote (" << marketQuote->name() <<
") not of type swap.");
1984 oisQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
1987 Period oisTenor = oisQuote->term();
1988 QuantLib::ext::shared_ptr<RateHelper> oisHelper;
1990 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
1991 "OIS segment for BRL-CDI does not support pillar choice " << segment->pillarChoice());
1992 oisHelper = QuantLib::ext::make_shared<BRLCdiRateHelper>(
1993 oisTenor, oisQuote->quote(), brlCdiIndex,
1997 if (oisQuote->startDate() == Null<Date>() || oisQuote->maturityDate() == Null<Date>())
1998 oisHelper = QuantLib::ext::make_shared<QuantExt::OISRateHelper>(
1999 oisConvention->spotLag(), oisTenor, oisQuote->quote(), onIndex, oisConvention->fixedDayCounter(),
2000 oisConvention->fixedCalendar(), oisConvention->paymentLag(), oisConvention->eom(),
2001 oisConvention->fixedFrequency(), oisConvention->fixedConvention(),
2002 oisConvention->fixedPaymentConvention(), oisConvention->rule(),
2004 oisSegment->pillarChoice());
2006 oisHelper = QuantLib::ext::make_shared<QuantExt::DatedOISRateHelper>(oisQuote->startDate(),
2007 oisQuote->maturityDate(), oisQuote->quote(), onIndex, oisConvention->fixedDayCounter(),
2008 oisConvention->fixedCalendar(), oisConvention->paymentLag(),
2009 oisConvention->fixedFrequency(), oisConvention->fixedConvention(),
2010 oisConvention->fixedPaymentConvention(), oisConvention->rule(),
2012 oisSegment->pillarChoice());
2015 instruments.push_back(oisHelper);
2021 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2023 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2026 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2027 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2028 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2029 QL_REQUIRE(convention->type() ==
Convention::Type::Swap,
"Conventions ID does not give swap conventions.");
2030 QuantLib::ext::shared_ptr<IRSwapConvention> swapConvention = QuantLib::ext::dynamic_pointer_cast<IRSwapConvention>(convention);
2032 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> swapSegment =
2033 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
2034 if (swapSegment->projectionCurveID() !=
curveConfig_->curveID() && !swapSegment->projectionCurveID().empty()) {
2035 QL_FAIL(
"Solving for discount curve given the projection"
2036 " curve is not implemented yet");
2038 auto swapQuoteIDs = swapSegment->quotes();
2040 for (Size i = 0; i < swapQuoteIDs.size(); i++) {
2041 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(swapQuoteIDs[i],
asofDate_);
2045 QuantLib::ext::shared_ptr<SwapQuote> swapQuote;
2047 "Market quote not of type swap.");
2048 swapQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
2049 QL_REQUIRE(swapQuote->startDate() == Null<Date>(),
2050 "swap quote with fixed start date is not supported for ibor / subperiods swap instruments");
2052 Period swapTenor = swapQuote->term();
2053 QuantLib::ext::shared_ptr<RateHelper> swapHelper;
2054 if (swapConvention->hasSubPeriod()) {
2055 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2056 "Subperiod Swap segment does not support pillar choice " << segment->pillarChoice());
2057 swapHelper = QuantLib::ext::make_shared<SubPeriodsSwapHelper>(
2058 swapQuote->quote(), swapTenor, Period(swapConvention->fixedFrequency()),
2059 swapConvention->fixedCalendar(), swapConvention->fixedDayCounter(),
2060 swapConvention->fixedConvention(), Period(swapConvention->floatFrequency()),
2061 swapConvention->index(), swapConvention->index()->dayCounter(),
2063 swapConvention->subPeriodsCouponType());
2065 swapHelper = QuantLib::ext::make_shared<SwapRateHelper>(
2066 swapQuote->quote(), swapTenor, swapConvention->fixedCalendar(), swapConvention->fixedFrequency(),
2067 swapConvention->fixedConvention(), swapConvention->fixedDayCounter(), swapConvention->index(),
2069 Null<Natural>(), swapSegment->pillarChoice());
2072 instruments.push_back(swapHelper);
2078 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2080 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2083 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2084 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2085 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2087 "Conventions ID does not give average OIS conventions.");
2088 QuantLib::ext::shared_ptr<AverageOisConvention> averageOisConvention =
2089 QuantLib::ext::dynamic_pointer_cast<AverageOisConvention>(convention);
2091 QuantLib::ext::shared_ptr<AverageOISYieldCurveSegment> averageOisSegment =
2092 QuantLib::ext::dynamic_pointer_cast<AverageOISYieldCurveSegment>(segment);
2095 string projectionCurveID = averageOisSegment->projectionCurveID();
2096 QuantLib::ext::shared_ptr<OvernightIndex> onIndex = averageOisConvention->index();
2097 if (projectionCurveID !=
curveConfig_->curveID() && !projectionCurveID.empty()) {
2099 QuantLib::ext::shared_ptr<YieldCurve> projectionCurve;
2100 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2103 projectionCurve = it->second;
2105 QL_FAIL(
"The projection curve, " << projectionCurveID
2106 <<
", required in the building "
2110 onIndex = QuantLib::ext::dynamic_pointer_cast<OvernightIndex>(onIndex->clone(projectionCurve->handle()));
2113 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2114 "Average OIS segment does not support pillar choice " << segment->pillarChoice());
2115 auto averageOisQuoteIDs = averageOisSegment->quotes();
2116 for (Size i = 0; i < averageOisQuoteIDs.size(); i += 2) {
2118 QL_REQUIRE(i % 2 == 0,
"i is not even");
2122 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(averageOisQuoteIDs[i],
asofDate_);
2123 QuantLib::ext::shared_ptr<SwapQuote> swapQuote;
2126 "Market quote not of type swap.");
2127 swapQuote = QuantLib::ext::dynamic_pointer_cast<SwapQuote>(marketQuote);
2128 QL_REQUIRE(swapQuote->startDate() == Null<Date>(),
2129 "swap quote with fixed start date is not supported for average ois instrument");
2133 QuantLib::ext::shared_ptr<BasisSwapQuote> basisQuote;
2136 "Market quote not of type basis swap.");
2137 basisQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2140 Period AverageOisTenor = swapQuote->term();
2141 QL_REQUIRE(AverageOisTenor == basisQuote->maturity(),
2143 "and basis swap components of the Average OIS must "
2144 "have the same maturity.");
2146 swapQuote->quote(), averageOisConvention->spotLag() * Days, AverageOisTenor,
2147 averageOisConvention->fixedTenor(), averageOisConvention->fixedDayCounter(),
2148 averageOisConvention->fixedCalendar(), averageOisConvention->fixedConvention(),
2149 averageOisConvention->fixedPaymentConvention(), onIndex, averageOisConvention->onTenor(),
2150 basisQuote->quote(), averageOisConvention->rateCutoff(),
2153 instruments.push_back(averageOisHelper);
2160 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2162 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2165 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2166 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2167 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2169 "Conventions ID does not give tenor basis swap conventions.");
2170 QuantLib::ext::shared_ptr<TenorBasisSwapConvention> basisSwapConvention =
2171 QuantLib::ext::dynamic_pointer_cast<TenorBasisSwapConvention>(convention);
2173 QuantLib::ext::shared_ptr<TenorBasisYieldCurveSegment> basisSwapSegment =
2174 QuantLib::ext::dynamic_pointer_cast<TenorBasisYieldCurveSegment>(segment);
2177 string receiveCurveID = basisSwapSegment->receiveProjectionCurveID();
2178 QuantLib::ext::shared_ptr<IborIndex> receiveIndex = basisSwapConvention->receiveIndex();
2179 if (receiveCurveID !=
curveConfig_->curveID() && !receiveCurveID.empty()) {
2181 QuantLib::ext::shared_ptr<YieldCurve> shortCurve;
2182 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2185 shortCurve = it->second;
2187 QL_FAIL(
"The short side projection curve, " << receiveCurveID
2188 <<
", required in the building "
2192 receiveIndex = receiveIndex->clone(shortCurve->handle());
2196 string payCurveID = basisSwapSegment->payProjectionCurveID();
2197 QuantLib::ext::shared_ptr<IborIndex> payIndex = basisSwapConvention->payIndex();
2198 if (payCurveID !=
curveConfig_->curveID() && !payCurveID.empty()) {
2200 QuantLib::ext::shared_ptr<YieldCurve> longCurve;
2201 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2204 longCurve = it->second;
2206 QL_FAIL(
"The long side projection curve, " << payCurveID
2207 <<
", required in the building "
2211 payIndex = payIndex->clone(longCurve->handle());
2214 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2215 "Tenor basis swap segment does not support pillar choice " << segment->pillarChoice());
2216 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2217 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2218 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(basisSwapQuoteIDs[i],
asofDate_);
2222 QuantLib::ext::shared_ptr<BasisSwapQuote> basisSwapQuote;
2224 "Market quote not of type basis swap.");
2225 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2228 Period basisSwapTenor = basisSwapQuote->maturity();
2229 QuantLib::ext::shared_ptr<RateHelper> basisSwapHelper;
2230 bool telescopicValueDates =
true;
2231 basisSwapHelper.reset(
2234 basisSwapConvention->spreadOnRec(), basisSwapConvention->includeSpread(),
2235 basisSwapConvention->payFrequency(), basisSwapConvention->receiveFrequency(),
2236 telescopicValueDates, basisSwapConvention->subPeriodsCouponType()));
2238 instruments.push_back(basisSwapHelper);
2244 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2246 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2249 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2250 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2251 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2253 "Conventions ID does not give tenor basis two swap conventions.");
2254 QuantLib::ext::shared_ptr<TenorBasisTwoSwapConvention> basisSwapConvention =
2255 QuantLib::ext::dynamic_pointer_cast<TenorBasisTwoSwapConvention>(convention);
2257 QuantLib::ext::shared_ptr<TenorBasisYieldCurveSegment> basisSwapSegment =
2258 QuantLib::ext::dynamic_pointer_cast<TenorBasisYieldCurveSegment>(segment);
2261 string shortCurveID = basisSwapSegment->receiveProjectionCurveID();
2262 QuantLib::ext::shared_ptr<IborIndex> shortIndex = basisSwapConvention->shortIndex();
2263 if (shortCurveID !=
curveConfig_->curveID() && !shortCurveID.empty()) {
2265 QuantLib::ext::shared_ptr<YieldCurve> shortCurve;
2266 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2269 shortCurve = it->second;
2271 QL_FAIL(
"The short side projection curve, " << shortCurveID
2272 <<
", required in the building "
2276 shortIndex = shortIndex->clone(shortCurve->handle());
2280 string longCurveID = basisSwapSegment->payProjectionCurveID();
2281 QuantLib::ext::shared_ptr<IborIndex> longIndex = basisSwapConvention->longIndex();
2282 if (longCurveID !=
curveConfig_->curveID() && !longCurveID.empty()) {
2284 QuantLib::ext::shared_ptr<YieldCurve> longCurve;
2285 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2288 longCurve = it->second;
2290 QL_FAIL(
"The projection curve, " << longCurveID
2291 <<
", required in the building "
2295 longIndex = longIndex->clone(longCurve->handle());
2298 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2299 "Tenor basis two swap segment does not support pillar choice " << segment->pillarChoice());
2300 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2301 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2302 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(basisSwapQuoteIDs[i],
asofDate_);
2305 QuantLib::ext::shared_ptr<BasisSwapQuote> basisSwapQuote;
2308 "Market quote not of type basis swap.");
2309 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BasisSwapQuote>(marketQuote);
2312 Period basisSwapTenor = basisSwapQuote->maturity();
2314 basisSwapQuote->quote(), basisSwapTenor, basisSwapConvention->calendar(),
2315 basisSwapConvention->longFixedFrequency(), basisSwapConvention->longFixedConvention(),
2316 basisSwapConvention->longFixedDayCounter(), longIndex, basisSwapConvention->shortFixedFrequency(),
2317 basisSwapConvention->shortFixedConvention(), basisSwapConvention->shortFixedDayCounter(), shortIndex,
2318 basisSwapConvention->longMinusShort(),
2321 instruments.push_back(basisSwapHelper);
2327 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2329 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2332 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2333 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2334 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2336 "Conventions ID does not give bma basis swap conventions.");
2337 QuantLib::ext::shared_ptr<BMABasisSwapConvention> bmaBasisSwapConvention =
2338 QuantLib::ext::dynamic_pointer_cast<BMABasisSwapConvention>(convention);
2340 QuantLib::ext::shared_ptr<SimpleYieldCurveSegment> bmaBasisSwapSegment =
2341 QuantLib::ext::dynamic_pointer_cast<SimpleYieldCurveSegment>(segment);
2343 " did not successfully cast to a BMA basis swap yield curve segment!");
2346 QuantLib::ext::shared_ptr<BMAIndexWrapper> bmaIndex = bmaBasisSwapConvention->bmaIndex();
2347 bmaIndex = dynamic_pointer_cast<BMAIndexWrapper>(bmaIndex->clone(
handle()));
2350 string liborCurveID = bmaBasisSwapSegment->projectionCurveID();
2351 QuantLib::ext::shared_ptr<IborIndex> liborIndex = bmaBasisSwapConvention->liborIndex();
2353 QuantLib::ext::shared_ptr<YieldCurve> liborCurve;
2354 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2357 liborCurve = it->second;
2359 QL_FAIL(
"The libor side projection curve, " << liborCurveID
2360 <<
", required in the building "
2364 liborIndex = liborIndex->clone(liborCurve->handle());
2366 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2367 "BMA swap segment does not support pillar choice " << segment->pillarChoice());
2368 auto bmaBasisSwapQuoteIDs = bmaBasisSwapSegment->quotes();
2369 for (Size i = 0; i < bmaBasisSwapQuoteIDs.size(); i++) {
2370 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(bmaBasisSwapQuoteIDs[i],
asofDate_);
2374 QuantLib::ext::shared_ptr<BMASwapQuote> bmaBasisSwapQuote;
2376 "Market quote not of type bma swap.");
2378 bmaBasisSwapQuote = QuantLib::ext::dynamic_pointer_cast<BMASwapQuote>(marketQuote);
2381 QuantLib::ext::shared_ptr<RateHelper> bmaSwapHelper;
2382 bmaSwapHelper.reset(
new BMASwapRateHelper(bmaBasisSwapQuote->quote(), bmaBasisSwapQuote->maturity(),
2383 bmaIndex->fixingDays(), bmaIndex->fixingCalendar(),
2384 bmaBasisSwapQuote->term(), bmaIndex->businessDayConvention(),
2385 bmaIndex->dayCounter(), bmaIndex->bma(), liborIndex));
2386 instruments.push_back(bmaSwapHelper);
2392 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2394 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2397 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2398 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2399 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2400 QL_REQUIRE(convention->type() ==
Convention::Type::FX,
"Conventions ID does not give FX forward conventions.");
2402 QuantLib::ext::shared_ptr<FXConvention>
fxConvention = QuantLib::ext::dynamic_pointer_cast<FXConvention>(convention);
2404 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> fxForwardSegment =
2405 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2409 Currency knownCurrency;
2415 QL_FAIL(
"One of the currencies in the FX forward bootstrap "
2416 "instruments needs to match the yield curve currency.");
2419 string knownDiscountID = fxForwardSegment->foreignDiscountCurveID();
2420 Handle<YieldTermStructure> knownDiscountCurve;
2422 if (!knownDiscountID.empty()) {
2423 knownDiscountID = yieldCurveKey(knownCurrency, knownDiscountID,
asofDate_);
2426 knownDiscountCurve = it->second->handle();
2428 QL_FAIL(
"The foreign discount curve, " << knownDiscountID
2429 <<
", required in the building "
2436 DLOG(
"YieldCurve::addFXForwards No discount curve provided for building curve " <<
2437 curveSpec_.
name() <<
", looking up the inccy curve in the market.")
2443 string spotRateID = fxForwardSegment->spotRateID();
2444 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote =
getFxSpotQuote(spotRateID);
2447 Currency fxSpotSourceCcy =
parseCurrency(fxSpotQuote->unitCcy());
2448 Currency fxSpotTargetCcy =
parseCurrency(fxSpotQuote->ccy());
2450 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2451 "FX Forward segment does not support pillar choice " << segment->pillarChoice());
2452 DLOG(
"YieldCurve::addFXForwards(), create FX forward quotes and helpers");
2453 auto fxForwardQuoteIDs = fxForwardSegment->quotes();
2454 for (Size i = 0; i < fxForwardQuoteIDs.size(); i++) {
2455 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(fxForwardQuoteIDs[i],
asofDate_);
2459 QuantLib::ext::shared_ptr<FXForwardQuote> fxForwardQuote;
2460 Handle<Quote> spotFx;
2463 "Market quote not of type FX forward.");
2464 fxForwardQuote = QuantLib::ext::dynamic_pointer_cast<FXForwardQuote>(marketQuote);
2466 QL_REQUIRE(fxSpotQuote->unitCcy() == fxForwardQuote->unitCcy() &&
2467 fxSpotQuote->ccy() == fxForwardQuote->ccy(),
2468 "Currency mismatch between spot \"" << spotRateID <<
"\" and fwd \""
2469 << fxForwardQuoteIDs[i].first <<
"\"");
2473 Handle<Quote> qlFXForwardQuote;
2475 auto m = [f = fxSpotQuote->quote()->value()](Real x) {
return x - f; };
2477 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxForwardQuote->quote(), m));
2479 auto m = [p =
fxConvention->pointsFactor()](Real x) {
return x / p; };
2481 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxForwardQuote->quote(), m));
2492 Real tnSpread = Null<Real>();
2493 Real totalSpread = 0.0;
2496 spotFx = fxSpotQuote->quote();
2500 auto m = [f = qlFXForwardQuote->value()](Real x) {
return x - f; };
2501 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxSpotQuote->quote(), m));
2508 auto fxq = QuantLib::ext::dynamic_pointer_cast<FXForwardQuote>(q);
2509 if (fxq && fxSpotQuote->unitCcy() == fxq->unitCcy() && fxSpotQuote->ccy() == fxq->ccy() &&
2511 tnSpread = fxq->quote()->value() /
fxConvention->pointsFactor();
2516 if (tnSpread == Null<Real>()) {
2517 WLOG(
"YieldCurve::AddFxForwards cannot use ON rate, when SpotDays are 2 we also require the TN "
2521 totalSpread = tnSpread + qlFXForwardQuote->value();
2523 auto m2 = [totalSpread](Real x) {
return x - totalSpread; };
2524 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m2)>>(fxSpotQuote->quote(), m2));
2528 WLOG(
"YieldCurve::AddFxForwards cannot use ON rate, when SpotDays are " << spotDays <<
2529 ", only valid for SpotDays of 0, 1 or 2.");
2534 auto m = [f = qlFXForwardQuote->value()](Real x) {
return x - f; };
2535 spotFx = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxSpotQuote->quote(), m));
2537 spotFx = fxSpotQuote->quote();
2542 bool isFxBaseCurrencyCollateralCurrency = knownCurrency == fxSpotSourceCcy;
2544 QuantLib::ext::shared_ptr<RateHelper> fxForwardHelper(
new FxSwapRateHelper(
2545 qlFXForwardQuote, spotFx, fxForwardTenor, fxStartTenor.length(),
fxConvention->advanceCalendar(),
2547 knownDiscountCurve));
2549 instruments.push_back(fxForwardHelper);
2553 DLOG(
"YieldCurve::addFXForwards() done");
2557 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2559 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2562 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2563 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2564 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2566 "basis swap conventions.");
2567 QuantLib::ext::shared_ptr<CrossCcyBasisSwapConvention> basisSwapConvention =
2568 QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapConvention>(convention);
2571 bool onFlatSide = (
currency_ == basisSwapConvention->flatIndex()->currency());
2573 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> basisSwapSegment =
2574 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2577 string spotRateID = basisSwapSegment->spotRateID();
2578 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote =
getFxSpotQuote(spotRateID);
2581 Currency fxSpotSourceCcy =
parseCurrency(fxSpotQuote->unitCcy());
2582 Currency fxSpotTargetCcy =
parseCurrency(fxSpotQuote->ccy());
2585 string foreignDiscountID = basisSwapSegment->foreignDiscountCurveID();
2586 Currency foreignCcy = fxSpotSourceCcy ==
currency_ ? fxSpotTargetCcy : fxSpotSourceCcy;
2587 Handle<YieldTermStructure> foreignDiscountCurve;
2588 if (!foreignDiscountID.empty()) {
2589 foreignDiscountID = yieldCurveKey(foreignCcy, foreignDiscountID,
asofDate_);
2592 foreignDiscountCurve = it->second->handle();
2594 QL_FAIL(
"The foreign discount curve, " << foreignDiscountID
2595 <<
", required in the building "
2602 DLOG(
"YieldCurve::addCrossCcyBasisSwaps No discount curve provided for building curve "
2603 <<
curveSpec_.
name() <<
", looking up the inccy curve in the market.")
2609 string foreignProjectionCurveID = basisSwapSegment->foreignProjectionCurveID();
2610 QuantLib::ext::shared_ptr<IborIndex> foreignIndex =
2611 onFlatSide ? basisSwapConvention->spreadIndex() : basisSwapConvention->flatIndex();
2612 if (foreignProjectionCurveID.empty()) {
2613 foreignIndex = foreignIndex->clone(foreignDiscountCurve);
2615 foreignProjectionCurveID = yieldCurveKey(foreignCcy, foreignProjectionCurveID,
asofDate_);
2616 QuantLib::ext::shared_ptr<YieldCurve> foreignProjectionCurve;
2617 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2620 foreignProjectionCurve = it->second;
2622 QL_FAIL(
"The foreign projection curve, " << foreignProjectionCurveID
2623 <<
", required in the building "
2627 foreignIndex = foreignIndex->clone(foreignProjectionCurve->handle());
2631 string domesticProjectionCurveID = basisSwapSegment->domesticProjectionCurveID();
2632 QuantLib::ext::shared_ptr<IborIndex> domesticIndex =
2633 onFlatSide ? basisSwapConvention->flatIndex() : basisSwapConvention->spreadIndex();
2634 if (domesticProjectionCurveID !=
curveConfig_->curveID() && !domesticProjectionCurveID.empty()) {
2635 domesticProjectionCurveID = yieldCurveKey(
currency_, domesticProjectionCurveID,
asofDate_);
2636 QuantLib::ext::shared_ptr<YieldCurve> domesticProjectionCurve;
2637 map<string, QuantLib::ext::shared_ptr<YieldCurve>>::iterator it;
2640 domesticProjectionCurve = it->second;
2642 QL_FAIL(
"The domestic projection curve, " << domesticProjectionCurveID
2643 <<
", required in the"
2644 " building of the curve, "
2647 domesticIndex = domesticIndex->clone(domesticProjectionCurve->handle());
2651 RelinkableHandle<YieldTermStructure> flatDiscountCurve;
2652 RelinkableHandle<YieldTermStructure> spreadDiscountCurve;
2653 QuantLib::ext::shared_ptr<IborIndex> flatIndex;
2654 QuantLib::ext::shared_ptr<IborIndex> spreadIndex;
2659 spreadDiscountCurve.linkTo(*foreignDiscountCurve);
2660 flatIndex = domesticIndex;
2661 spreadIndex = foreignIndex;
2663 flatDiscountCurve.linkTo(*foreignDiscountCurve);
2667 flatIndex = foreignIndex;
2668 spreadIndex = domesticIndex;
2671 Period flatTenor = basisSwapConvention->flatTenor();
2672 Period spreadTenor = basisSwapConvention->spreadTenor();
2674 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2675 "XCcy basis segment does not support pillar choice " << segment->pillarChoice());
2676 auto basisSwapQuoteIDs = basisSwapSegment->quotes();
2677 for (Size i = 0; i < basisSwapQuoteIDs.size(); i++) {
2678 QuantLib::ext::shared_ptr<MarketDatum> marketQuote =
loader_.
get(basisSwapQuoteIDs[i],
asofDate_);
2682 QuantLib::ext::shared_ptr<CrossCcyBasisSwapQuote> basisSwapQuote;
2684 "Market quote not of type cross "
2685 "currency basis swap.");
2686 basisSwapQuote = QuantLib::ext::dynamic_pointer_cast<CrossCcyBasisSwapQuote>(marketQuote);
2689 Period basisSwapTenor = basisSwapQuote->maturity();
2690 bool isResettableSwap = basisSwapConvention->isResettable();
2691 if (!isResettableSwap) {
2692 instruments.push_back(QuantLib::ext::make_shared<CrossCcyBasisSwapHelper>(
2693 basisSwapQuote->quote(), fxSpotQuote->quote(), basisSwapConvention->settlementDays(),
2694 basisSwapConvention->settlementCalendar(), basisSwapTenor, basisSwapConvention->rollConvention(),
2695 flatIndex, spreadIndex, flatDiscountCurve, spreadDiscountCurve, basisSwapConvention->eom(),
2696 flatIndex->currency().code() != fxSpotQuote->unitCcy(), flatTenor, spreadTenor, 0.0, 1.0, 1.0,
2697 Calendar(), Calendar(), std::vector<Natural>(), std::vector<Calendar>(),
2698 basisSwapConvention->paymentLag(), basisSwapConvention->flatPaymentLag(),
2699 basisSwapConvention->includeSpread(), basisSwapConvention->lookback(),
2700 basisSwapConvention->fixingDays(), basisSwapConvention->rateCutoff(),
2701 basisSwapConvention->isAveraged(), basisSwapConvention->flatIncludeSpread(),
2702 basisSwapConvention->flatLookback(), basisSwapConvention->flatFixingDays(),
2703 basisSwapConvention->flatRateCutoff(), basisSwapConvention->flatIsAveraged(),
true));
2705 bool resetsOnFlatLeg = basisSwapConvention->flatIndexIsResettable();
2708 bool spreadOnForeignCcy = resetsOnFlatLeg ? true :
false;
2709 QuantLib::ext::shared_ptr<IborIndex> foreignIndex = resetsOnFlatLeg ? spreadIndex : flatIndex;
2710 Handle<YieldTermStructure> foreignDiscount = resetsOnFlatLeg ? spreadDiscountCurve : flatDiscountCurve;
2711 QuantLib::ext::shared_ptr<IborIndex> domesticIndex = resetsOnFlatLeg ? flatIndex : spreadIndex;
2712 Handle<YieldTermStructure> domesticDiscount = resetsOnFlatLeg ? flatDiscountCurve : spreadDiscountCurve;
2713 Handle<Quote> finalFxSpotQuote = fxSpotQuote->quote();
2715 if (foreignIndex->currency().code() != fxSpotQuote->unitCcy()) {
2716 auto m = [](Real x) {
return 1.0 / x; };
2718 Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxSpotQuote->quote(), m));
2720 Period foreignTenor = resetsOnFlatLeg ? spreadTenor : flatTenor;
2721 Period domesticTenor = resetsOnFlatLeg ? flatTenor : spreadTenor;
2724 instruments.push_back(QuantLib::ext::make_shared<CrossCcyBasisMtMResetSwapHelper>(
2725 basisSwapQuote->quote(), finalFxSpotQuote, basisSwapConvention->settlementDays(),
2726 basisSwapConvention->settlementCalendar(), basisSwapTenor, basisSwapConvention->rollConvention(),
2727 foreignIndex, domesticIndex, foreignDiscount, domesticDiscount, Handle<YieldTermStructure>(),
2728 Handle<YieldTermStructure>(), basisSwapConvention->eom(), spreadOnForeignCcy, foreignTenor,
2729 domesticTenor, basisSwapConvention->paymentLag(), basisSwapConvention->flatPaymentLag(),
2730 basisSwapConvention->includeSpread(), basisSwapConvention->lookback(),
2731 basisSwapConvention->fixingDays(), basisSwapConvention->rateCutoff(),
2732 basisSwapConvention->isAveraged(), basisSwapConvention->flatIncludeSpread(),
2733 basisSwapConvention->flatLookback(), basisSwapConvention->flatFixingDays(),
2734 basisSwapConvention->flatRateCutoff(), basisSwapConvention->flatIsAveraged(),
true));
2740 vector<QuantLib::ext::shared_ptr<RateHelper>>& instruments) {
2742 DLOG(
"Adding Segment " << segment->typeID() <<
" with conventions \"" << segment->conventionsID() <<
"\"");
2745 QuantLib::ext::shared_ptr<Conventions> conventions = InstrumentConventions::instance().conventions();
2746 QuantLib::ext::shared_ptr<Convention> convention = conventions->get(segment->conventionsID());
2747 QL_REQUIRE(convention,
"No conventions found with ID: " << segment->conventionsID());
2749 "Conventions ID does not give cross currency fix float swap conventions.");
2750 QuantLib::ext::shared_ptr<CrossCcyFixFloatSwapConvention> swapConvention =
2751 QuantLib::ext::dynamic_pointer_cast<CrossCcyFixFloatSwapConvention>(convention);
2753 QL_REQUIRE(swapConvention->fixedCurrency() ==
currency_,
2754 "The yield curve currency must "
2755 <<
"equal the cross currency fix float swap's fixed leg currency");
2758 QuantLib::ext::shared_ptr<CrossCcyYieldCurveSegment> swapSegment =
2759 QuantLib::ext::dynamic_pointer_cast<CrossCcyYieldCurveSegment>(segment);
2762 QuantLib::ext::shared_ptr<IborIndex> floatIndex = swapConvention->index();
2763 Currency floatLegCcy = floatIndex->currency();
2764 string foreignDiscountID = swapSegment->foreignDiscountCurveID();
2765 Handle<YieldTermStructure> floatLegDisc;
2767 QuantLib::ext::shared_ptr<YieldCurve> foreignDiscountCurve;
2768 if (!foreignDiscountID.empty()) {
2769 string floatLegDiscId = yieldCurveKey(floatLegCcy, foreignDiscountID,
asofDate_);
2772 floatLegDisc = it->second->handle();
2774 QL_FAIL(
"The foreign discount curve, " << floatLegDiscId
2775 <<
", required in the building "
2782 DLOG(
"YieldCurve::addCrossCcyFixFloatSwaps No discount curve provided for building curve "
2783 <<
curveSpec_.
name() <<
", looking up the inccy curve in the market.")
2788 string floatLegProjId = swapSegment->foreignProjectionCurveID();
2789 if (floatLegProjId.empty()) {
2790 floatIndex = floatIndex->clone(floatLegDisc);
2792 floatLegProjId = yieldCurveKey(floatLegCcy, floatLegProjId,
asofDate_);
2795 <<
" required in the building of curve "
2797 floatIndex = floatIndex->clone(it->second->handle());
2802 string fxSpotId = swapSegment->spotRateID();
2803 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotMd =
getFxSpotQuote(fxSpotId);
2806 Handle<Quote> fxSpotQuote;
2807 if (mdUnitCcy == floatLegCcy && mdCcy ==
currency_) {
2808 fxSpotQuote = fxSpotMd->quote();
2809 }
else if (mdUnitCcy ==
currency_ && mdCcy == floatLegCcy) {
2810 auto m=[](Real x) {
return 1.0/x;};
2811 fxSpotQuote = Handle<Quote>(QuantLib::ext::make_shared<DerivedQuote<
decltype(m)>>(fxSpotMd->quote(), m));
2813 QL_FAIL(
"The FX spot market quote " << mdUnitCcy <<
"/" << mdCcy <<
" cannot be used "
2818 QL_REQUIRE(segment->pillarChoice() == QuantLib::Pillar::LastRelevantDate,
2819 "XCcy fix-float basis segment does not support pillar choice " << segment->pillarChoice());
2820 auto quoteIds = swapSegment->quotes();
2821 for (Size i = 0; i < quoteIds.size(); i++) {
2828 QuantLib::ext::shared_ptr<CrossCcyFixFloatSwapQuote> swapQuote =
2829 QuantLib::ext::dynamic_pointer_cast<CrossCcyFixFloatSwapQuote>(marketQuote);
2830 QL_REQUIRE(swapQuote,
"Market quote should be of type 'CrossCcyFixFloatSwapQuote'");
2831 bool isResettableSwap = swapConvention->isResettable();
2832 QuantLib::ext::shared_ptr<RateHelper>
helper;
2833 if (!isResettableSwap) {
2835 helper = QuantLib::ext::make_shared<CrossCcyFixFloatSwapHelper>(
2836 swapQuote->quote(), fxSpotQuote, swapConvention->settlementDays(), swapConvention->settlementCalendar(),
2837 swapConvention->settlementConvention(), swapQuote->maturity(),
currency_,
2838 swapConvention->fixedFrequency(), swapConvention->fixedConvention(), swapConvention->fixedDayCounter(),
2839 floatIndex, floatLegDisc, Handle<Quote>(), swapConvention->eom());
2841 bool resetsOnFloatLeg = swapConvention->floatIndexIsResettable();
2842 helper = QuantLib::ext::make_shared<CrossCcyFixFloatMtMResetSwapHelper>(
2843 swapQuote->quote(), fxSpotQuote, swapConvention->settlementDays(), swapConvention->settlementCalendar(),
2844 swapConvention->settlementConvention(), swapQuote->maturity(),
currency_, swapConvention->fixedFrequency(),
2845 swapConvention->fixedConvention(), swapConvention->fixedDayCounter(), floatIndex,
2846 floatLegDisc, Handle<Quote>(), swapConvention->eom(), resetsOnFloatLeg);
2848 instruments.push_back(
helper);
2855 std::vector<string> tokens;
2856 split(tokens, spotId, boost::is_any_of(
"/"));
2858 QuantLib::ext::shared_ptr<FXSpotQuote> fxSpotQuote;
2859 if (tokens.size() == 4 && tokens[0] ==
"FX" && tokens[1] ==
"RATE") {
2861 QuantLib::ext::shared_ptr<MarketDatum> fxSpotMarketQuote =
loader_.
get(spotId,
asofDate_);
2863 if (fxSpotMarketQuote) {
2865 "Market quote not of type FX spot.");
2866 fxSpotQuote = QuantLib::ext::dynamic_pointer_cast<FXSpotQuote>(fxSpotMarketQuote);
2876 if (tokens.size() > 1 && tokens[0] ==
"FX") {
2877 if (tokens.size() == 3) {
2878 unitCcy = tokens[1];
2880 }
else if (tokens.size() == 4 && tokens[1] ==
"RATE") {
2881 unitCcy = tokens[2];
2884 QL_FAIL(
"Invalid FX spot ID " << spotId);
2886 }
else if (tokens.size() == 1 && spotId.size() == 6) {
2887 unitCcy = spotId.substr(0, 3);
2888 ccy = spotId.substr(3);
2890 QL_FAIL(
"Could not find quote for ID " << spotId <<
" with as of date " << io::iso_date(
asofDate_) <<
".");
Bond trade data model and serialization.
Container class for all Curve Configurations.
const std::string & curveConfigID() const
string name() const
returns the unique curve name
QuantLib::Handle< QuantLib::Quote > getQuote(const std::string &pair) const
const FallbackData & fallbackData(const string &iborIndex) const
bool isIndexReplaced(const string &iborIndex, const QuantLib::Date &asof=QuantLib::Date::maxDate()) const
Market data loader base class.
virtual std::vector< QuantLib::ext::shared_ptr< MarketDatum > > loadQuotes(const QuantLib::Date &) const =0
get all quotes, TODO change the return value to std::set
virtual QuantLib::ext::shared_ptr< MarketDatum > get(const std::string &name, const QuantLib::Date &d) const
get quote by its unique name, throws if not existent, override in derived classes for performance
virtual bool has(const std::string &name, const QuantLib::Date &d) const
Default implementation, returns false if get throws or returns a null pointer.
static const string inCcyConfiguration
InCcy configuration label.
Handle< YieldTermStructure > discountCurve(const string &ccy, const string &configuration=Market::defaultConfiguration) const
QuantLib::ext::shared_ptr< YieldTermStructure > p_
void addDeposits(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void buildBondYieldShiftedCurve()
Build a yield curve that uses QuantExt::bondYieldShiftedCurve.
const bool preserveQuoteLinkage_
void addCrossCcyBasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void buildDiscountRatioCurve()
Build a yield curve that uses QuantExt::DiscountRatioModifiedCurve.
void addTenorBasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
DayCounter zeroDayCounter_
void addOISs(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addFutures(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
map< string, QuantLib::ext::shared_ptr< DefaultCurve > > requiredDefaultCurves_
InterpolationVariable
Supported interpolation variables.
void addBMABasisSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void buildYieldPlusDefaultCurve()
Build a yield curve that uses QuantExt::YieldPlusDefaultYieldTermStructure.
void buildFittedBondCurve()
Build a yield curve that uses QuantLib::FittedBondCurve.
YieldCurve(Date asof, YieldCurveSpec curveSpec, const CurveConfigurations &curveConfigs, const Loader &loader, const map< string, QuantLib::ext::shared_ptr< YieldCurve > > &requiredYieldCurves=map< string, QuantLib::ext::shared_ptr< YieldCurve > >(), const map< string, QuantLib::ext::shared_ptr< DefaultCurve > > &requiredDefaultCurves=map< string, QuantLib::ext::shared_ptr< DefaultCurve > >(), const FXTriangulation &fxTriangulation=FXTriangulation(), const QuantLib::ext::shared_ptr< ReferenceDataManager > &referenceData=nullptr, const IborFallbackConfig &iborfallbackConfig=IborFallbackConfig::defaultConfig(), const bool preserveQuoteLinkage=false, const bool buildCalibrationInfo=true, const Market *market=nullptr)
Constructor.
void buildZeroSpreadedCurve()
RelinkableHandle< YieldTermStructure > h_
const QuantLib::ext::shared_ptr< ReferenceDataManager > referenceData_
void addFras(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
YieldCurveSpec curveSpec_
QuantLib::ext::shared_ptr< YieldCurveConfig > curveConfig_
const FXTriangulation & fxTriangulation_
void buildIborFallbackCurve()
Build a yield curve that uses QuantExt::IborFallbackCurve.
const Handle< YieldTermStructure > & handle() const
void buildBootstrappedCurve()
InterpolationMethod
Supported interpolation methods.
@ LogMixedLinearCubicNaturalSpline
@ DefaultLogMixedLinearCubic
@ KrugerLogMixedLinearCubic
@ MonotonicLogMixedLinearCubic
void addTenorBasisTwoSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void addFXForwards(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
Size mixedInterpolationSize_
InterpolationVariable interpolationVariable_
map< string, QuantLib::ext::shared_ptr< YieldCurve > > requiredYieldCurves_
void buildDiscountCurve()
InterpolationMethod interpolationMethod_
IborFallbackConfig iborFallbackConfig_
QuantLib::ext::shared_ptr< YieldCurveCalibrationInfo > calibrationInfo_
vector< QuantLib::ext::shared_ptr< YieldCurveSegment > > curveSegments_
void addCrossCcyFixFloatSwaps(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
void buildWeightedAverageCurve()
Build a yield curve that uses QuantExt::WeightedYieldTermStructure.
QuantLib::ext::shared_ptr< FXSpotQuote > getFxSpotQuote(string spotId)
QuantLib::ext::shared_ptr< YieldTermStructure > piecewisecurve(vector< QuantLib::ext::shared_ptr< RateHelper > > instruments)
QuantLib::ext::shared_ptr< YieldCurve > discountCurve_
QuantLib::ext::shared_ptr< YieldCurve > getYieldCurve(const std::string &ccy, const std::string &id) const
Return the yield curve with the given id from the requiredYieldCurves_ map.
bool buildCalibrationInfo_
void addAverageOISs(const QuantLib::ext::shared_ptr< YieldCurveSegment > &segment, vector< QuantLib::ext::shared_ptr< RateHelper > > &instruments)
const string & ccy() const
Wrapper class for building Default curves.
trade envelope data model and serialization
A market implementation providing curves for setting up bond rate helpers.
QuantLib::ext::shared_ptr< IborIndex > parseIborIndex(const string &s, const Handle< YieldTermStructure > &h)
Convert std::string to QuantLib::IborIndex.
bool isOvernightIndex(const string &indexName)
Return true if the indexName is that of an overnight index, otherwise false.
Currency parseCurrency(const string &s)
Convert text to QuantLib::Currency.
DayCounter parseDayCounter(const string &s)
Convert text to QuantLib::DayCounter.
Map text representations to QuantLib/QuantExt types.
Classes and functions for log message handling.
#define DLOG(text)
Logging Macro (Level = Debug)
#define WLOG(text)
Logging Macro (Level = Warning)
#define TLOG(text)
Logging Macro (Level = Data)
QuantLib::ext::shared_ptr< FXConvention > fxConvention
std::ostream & operator<<(std::ostream &out, EquityReturnType t)
QuantLib::ext::shared_ptr< YieldTermStructure > buildYieldCurve(const vector< Date > &dates, const vector< QuantLib::Real > &rates, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Templated function to build a YieldTermStructure and apply interpolation methods to it.
YieldCurve::InterpolationVariable parseYieldCurveInterpolationVariable(const string &s)
Helper function for parsing interpolation variable.
Size size(const ValueType &v)
bool matchFxFwdStringTerm(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const FXForwardQuote::FxFwdString &fxfwdString)
QuantLib::Period fxFwdQuoteStartTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term, const QuantLib::ext::shared_ptr< FXConvention > &fxConvention)
QuantLib::ext::shared_ptr< YieldTermStructure > discountcurve(const vector< Date > &dates, const vector< DiscountFactor > &dfs, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Discount Curve and apply interpolators.
YieldCurve::InterpolationMethod parseYieldCurveInterpolationMethod(const string &s)
Helper function for parsing interpolation method.
QuantLib::ext::shared_ptr< YieldTermStructure > forwardcurve(const vector< Date > &dates, const vector< Rate > &forwards, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Forward Curve and apply interpolators.
QuantLib::ext::shared_ptr< YieldTermStructure > zerocurve(const vector< Date > &dates, const vector< Rate > &yields, const DayCounter &dayCounter, YieldCurve::InterpolationMethod interpolationMethod, Size n)
Create a Interpolated Zero Curve and apply interpolators.
boost::optional< Wildcard > getUniqueWildcard(const C &c)
checks if at most one element in C has a wild card and returns it in this case
QuantLib::Period fxFwdQuoteTenor(const boost::variant< QuantLib::Period, FXForwardQuote::FxFwdString > &term)
Serializable Credit Default Swap.
Map text representations to QuantLib/QuantExt types.
QuantLib::BootstrapHelper< QuantLib::OptionletVolatilityStructure > helper
Reference data model and serialization.
static const std::vector< QuantLib::Period > defaultPeriods
vector< string > curveConfigs
string conversion utilities
Wrapper class for QuantLib term structures.