diff --git a/ql/termstructures/yield/fittedbonddiscountcurve.cpp b/ql/termstructures/yield/fittedbonddiscountcurve.cpp index d7f466137a5..2d0aa4b279f 100644 --- a/ql/termstructures/yield/fittedbonddiscountcurve.cpp +++ b/ql/termstructures/yield/fittedbonddiscountcurve.cpp @@ -130,10 +130,15 @@ namespace QuantLib { ext::shared_ptr optimizationMethod, Array l2, const Real minCutoffTime, - const Real maxCutoffTime) + const Real maxCutoffTime, + Constraint constraint) : constrainAtZero_(constrainAtZero), weights_(weights), l2_(std::move(l2)), calculateWeights_(weights.empty()), optimizationMethod_(std::move(optimizationMethod)), - minCutoffTime_(minCutoffTime), maxCutoffTime_(maxCutoffTime) {} + constraint_(std::move(constraint)), + minCutoffTime_(minCutoffTime), maxCutoffTime_(maxCutoffTime) { + if (constraint_.empty()) + constraint_ = NoConstraint(); + } void FittedBondDiscountCurve::FittingMethod::init() { // yield conventions @@ -188,7 +193,6 @@ namespace QuantLib { void FittedBondDiscountCurve::FittingMethod::calculate() { FittingCost& costFunction = *costFunction_; - Constraint constraint = NoConstraint(); // start with the guess solution, if it exists Array x(size(), 0.0); @@ -221,7 +225,7 @@ namespace QuantLib { if(!optimization){ optimization = ext::make_shared(curve_->simplexLambda_); } - Problem problem(costFunction, constraint, x); + Problem problem(costFunction, constraint_, x); Real rootEpsilon = curve_->accuracy_; Real functionEpsilon = curve_->accuracy_; diff --git a/ql/termstructures/yield/fittedbonddiscountcurve.hpp b/ql/termstructures/yield/fittedbonddiscountcurve.hpp index dd601d0868a..6db9eba8d43 100644 --- a/ql/termstructures/yield/fittedbonddiscountcurve.hpp +++ b/ql/termstructures/yield/fittedbonddiscountcurve.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace QuantLib { @@ -209,6 +210,8 @@ namespace QuantLib { Array l2() const; //! return optimization method being used ext::shared_ptr optimizationMethod() const; + //! return optimization contraint + const Constraint& constraint() const; //! open discountFunction to public DiscountFactor discount(const Array& x, Time t) const; protected: @@ -219,7 +222,8 @@ namespace QuantLib { ext::shared_ptr(), Array l2 = Array(), Real minCutoffTime = 0.0, - Real maxCutoffTime = QL_MAX_REAL); + Real maxCutoffTime = QL_MAX_REAL, + Constraint constraint = NoConstraint()); //! rerun every time instruments/referenceDate changes virtual void init(); //! discount function called by FittedBondDiscountCurve @@ -257,6 +261,8 @@ namespace QuantLib { EndCriteria::Type errorCode_ = EndCriteria::None; // optimization method to be used, if none provided use Simplex ext::shared_ptr optimizationMethod_; + // optimization constraint, if none provided use NoConstraint + Constraint constraint_; // flat extrapolation of instantaneous forward before / after cutoff Real minCutoffTime_, maxCutoffTime_; }; @@ -329,6 +335,10 @@ namespace QuantLib { return optimizationMethod_; } + inline const Constraint& FittedBondDiscountCurve::FittingMethod::constraint() const { + return constraint_; + } + inline DiscountFactor FittedBondDiscountCurve::FittingMethod::discount(const Array& x, Time t) const { if (t < minCutoffTime_) { // flat fwd extrapolation before min cutoff time diff --git a/ql/termstructures/yield/nonlinearfittingmethods.cpp b/ql/termstructures/yield/nonlinearfittingmethods.cpp index f9f1b217cc9..dcaebe093c6 100644 --- a/ql/termstructures/yield/nonlinearfittingmethods.cpp +++ b/ql/termstructures/yield/nonlinearfittingmethods.cpp @@ -33,39 +33,37 @@ namespace QuantLib { const Real minCutoffTime, const Real maxCutoffTime, const Size numCoeffs, - const Real fixedKappa) - : FittedBondDiscountCurve::FittingMethod( - constrainAtZero, weights, optimizationMethod, l2, minCutoffTime, maxCutoffTime), - numCoeffs_(numCoeffs), fixedKappa_(fixedKappa) - { + const Real fixedKappa, + Constraint constraint) + : FittedBondDiscountCurve::FittingMethod(constrainAtZero, weights, optimizationMethod, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)), + numCoeffs_(numCoeffs), fixedKappa_(fixedKappa) { QL_REQUIRE(ExponentialSplinesFitting::size() > 0, "At least 1 unconstrained coefficient required"); } - ExponentialSplinesFitting::ExponentialSplinesFitting(bool constrainAtZero, + ExponentialSplinesFitting::ExponentialSplinesFitting( + bool constrainAtZero, const Array& weights, const Array& l2, const Real minCutoffTime, const Real maxCutoffTime, - const Size numCoeffs, const Real fixedKappa) - : FittedBondDiscountCurve::FittingMethod(constrainAtZero, weights, ext::shared_ptr(), l2, - minCutoffTime, maxCutoffTime), - numCoeffs_(numCoeffs),fixedKappa_(fixedKappa) - { - QL_REQUIRE(ExponentialSplinesFitting::size() > 0, "At least 1 unconstrained coefficient required"); - } + const Size numCoeffs, const Real fixedKappa, + Constraint constraint) + : ExponentialSplinesFitting(constrainAtZero, weights, {}, l2, + minCutoffTime, maxCutoffTime, + numCoeffs, fixedKappa, std::move(constraint)) {} - ExponentialSplinesFitting::ExponentialSplinesFitting(bool constrainAtZero, - const Size numCoeffs, - const Real fixedKappa, - const Array& weights ) - : FittedBondDiscountCurve::FittingMethod(constrainAtZero, weights, ext::shared_ptr(), Array(),0.0,QL_MAX_REAL), - numCoeffs_(numCoeffs), fixedKappa_(fixedKappa) - { - QL_REQUIRE(ExponentialSplinesFitting::size() > 0, "At least 1 unconstrained coefficient required"); - } + ExponentialSplinesFitting::ExponentialSplinesFitting( + bool constrainAtZero, + const Size numCoeffs, + const Real fixedKappa, + const Array& weights, + Constraint constraint) + : ExponentialSplinesFitting(constrainAtZero, weights, {}, Array(), + 0.0, QL_MAX_REAL, + numCoeffs, fixedKappa, std::move(constraint)) {} std::unique_ptr ExponentialSplinesFitting::clone() const { - return std::unique_ptr( - new ExponentialSplinesFitting(*this)); + return std::make_unique(*this); } Size ExponentialSplinesFitting::size() const { @@ -107,20 +105,23 @@ namespace QuantLib { const ext::shared_ptr& optimizationMethod, const Array& l2, const Real minCutoffTime, - const Real maxCutoffTime) - : FittedBondDiscountCurve::FittingMethod( - true, weights, optimizationMethod, l2, minCutoffTime, maxCutoffTime) {} + const Real maxCutoffTime, + Constraint constraint) + : FittedBondDiscountCurve::FittingMethod(true, weights, optimizationMethod, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)) {} - NelsonSiegelFitting::NelsonSiegelFitting(const Array& weights, - const Array& l2, - const Real minCutoffTime, const Real maxCutoffTime) - : FittedBondDiscountCurve::FittingMethod(true, weights, ext::shared_ptr(), l2, - minCutoffTime, maxCutoffTime) {} + NelsonSiegelFitting::NelsonSiegelFitting( + const Array& weights, + const Array& l2, + const Real minCutoffTime, + const Real maxCutoffTime, + Constraint constraint) + : NelsonSiegelFitting(weights, {}, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)) {} std::unique_ptr NelsonSiegelFitting::clone() const { - return std::unique_ptr( - new NelsonSiegelFitting(*this)); + return std::make_unique(*this); } Size NelsonSiegelFitting::size() const { @@ -143,19 +144,22 @@ namespace QuantLib { const ext::shared_ptr& optimizationMethod, const Array& l2, const Real minCutoffTime, - const Real maxCutoffTime) - : FittedBondDiscountCurve::FittingMethod( - true, weights, optimizationMethod, l2, minCutoffTime, maxCutoffTime) {} + const Real maxCutoffTime, + Constraint constraint) + : FittedBondDiscountCurve::FittingMethod(true, weights, optimizationMethod, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)) {} SvenssonFitting::SvenssonFitting(const Array& weights, - const Array& l2, const Real minCutoffTime, const Real maxCutoffTime) - : FittedBondDiscountCurve::FittingMethod(true, weights, ext::shared_ptr(), l2, - minCutoffTime, maxCutoffTime) {} + const Array& l2, + const Real minCutoffTime, + const Real maxCutoffTime, + Constraint constraint) + : SvenssonFitting(weights, {}, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)) {} std::unique_ptr SvenssonFitting::clone() const { - return std::unique_ptr( - new SvenssonFitting(*this)); + return std::make_unique(*this); } Size SvenssonFitting::size() const { @@ -184,9 +188,10 @@ namespace QuantLib { const ext::shared_ptr& optimizationMethod, const Array& l2, const Real minCutoffTime, - const Real maxCutoffTime) - : FittedBondDiscountCurve::FittingMethod( - constrainAtZero, weights, optimizationMethod, l2, minCutoffTime, maxCutoffTime), + const Real maxCutoffTime, + Constraint constraint) + : FittedBondDiscountCurve::FittingMethod(constrainAtZero, weights, optimizationMethod, l2, + minCutoffTime, maxCutoffTime, std::move(constraint)), splines_(3, knots.size() - 5, knots) { QL_REQUIRE(knots.size() >= 8, @@ -208,34 +213,16 @@ namespace QuantLib { } } - CubicBSplinesFitting::CubicBSplinesFitting(const std::vector