Skip to content

Commit

Permalink
Allow constraints in FittedBondDiscountCurve::FittingMethod (lballabi…
Browse files Browse the repository at this point in the history
  • Loading branch information
klin333 committed Aug 19, 2024
1 parent c0fac24 commit 7d4de77
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
11 changes: 8 additions & 3 deletions ql/termstructures/yield/fittedbonddiscountcurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,11 @@ namespace QuantLib {
ext::shared_ptr<OptimizationMethod> optimizationMethod,
Array l2,
const Real minCutoffTime,
const Real maxCutoffTime)
const Real maxCutoffTime,
ext::shared_ptr<Constraint> constraint)
: constrainAtZero_(constrainAtZero), weights_(weights), l2_(std::move(l2)),
calculateWeights_(weights.empty()), optimizationMethod_(std::move(optimizationMethod)),
constraint_(std::move(constraint)),
minCutoffTime_(minCutoffTime), maxCutoffTime_(maxCutoffTime) {}

void FittedBondDiscountCurve::FittingMethod::init() {
Expand Down Expand Up @@ -188,7 +190,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);
Expand Down Expand Up @@ -221,7 +222,11 @@ namespace QuantLib {
if(!optimization){
optimization = ext::make_shared<Simplex>(curve_->simplexLambda_);
}
Problem problem(costFunction, constraint, x);
ext::shared_ptr<Constraint> constraint = constraint_;
if (!constraint) {
constraint = ext::make_shared<NoConstraint>();
}
Problem problem(costFunction, *constraint, x);

Real rootEpsilon = curve_->accuracy_;
Real functionEpsilon = curve_->accuracy_;
Expand Down
13 changes: 12 additions & 1 deletion ql/termstructures/yield/fittedbonddiscountcurve.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <ql/patterns/lazyobject.hpp>
#include <ql/math/array.hpp>
#include <ql/utilities/clone.hpp>
#include <ql/math/optimization/constraint.hpp>

namespace QuantLib {

Expand Down Expand Up @@ -209,6 +210,8 @@ namespace QuantLib {
Array l2() const;
//! return optimization method being used
ext::shared_ptr<OptimizationMethod> optimizationMethod() const;
//! return optimization contraint
ext::shared_ptr<Constraint> constraint() const;
//! open discountFunction to public
DiscountFactor discount(const Array& x, Time t) const;
protected:
Expand All @@ -219,7 +222,8 @@ namespace QuantLib {
ext::shared_ptr<OptimizationMethod>(),
Array l2 = Array(),
Real minCutoffTime = 0.0,
Real maxCutoffTime = QL_MAX_REAL);
Real maxCutoffTime = QL_MAX_REAL,
ext::shared_ptr<Constraint> constraint = ext::shared_ptr<Constraint>());
//! rerun every time instruments/referenceDate changes
virtual void init();
//! discount function called by FittedBondDiscountCurve
Expand Down Expand Up @@ -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> optimizationMethod_;
// optimization constraint, if none provided use NoConstraint
ext::shared_ptr<Constraint> constraint_;
// flat extrapolation of instantaneous forward before / after cutoff
Real minCutoffTime_, maxCutoffTime_;
};
Expand Down Expand Up @@ -329,6 +335,11 @@ namespace QuantLib {
return optimizationMethod_;
}

inline ext::shared_ptr<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
Expand Down
57 changes: 57 additions & 0 deletions test-suite/fittedbonddiscountcurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,63 @@ BOOST_AUTO_TEST_CASE(testGuessSize) {
ExpectedErrorMessage("wrong size for guess"));
}




BOOST_AUTO_TEST_CASE(testConstraint) {

BOOST_TEST_MESSAGE("Testing that fitted bond curves check the guess size when given...");

class FlatZero : public FittedBondDiscountCurve::FittingMethod {
public:
FlatZero(bool forcePositive)
: FittedBondDiscountCurve::FittingMethod(true, // constrainAtZero
Array(), // weights
ext::shared_ptr<OptimizationMethod>(),
Array(), // l2
0.0, // minCutoffTime
QL_MAX_REAL, //maxCutoffTime
forcePositive ?
ext::shared_ptr<Constraint>(ext::make_shared<PositiveConstraint>()) :
ext::shared_ptr<Constraint>(ext::make_shared<NoConstraint>())){};

std::unique_ptr<FittedBondDiscountCurve::FittingMethod> clone() const override {
return std::unique_ptr<FittedBondDiscountCurve::FittingMethod>(new FlatZero(*this));
}

private:
Size size() const override { return 1; }

DiscountFactor discountFunction(const Array& x, Time t) const override {
Real zeroRate = x[0];
DiscountFactor d = std::exp(-zeroRate * t);
return d;
}
};

Date today = Settings::instance().evaluationDate();
auto bond1 = ext::make_shared<ZeroCouponBond>(3, TARGET(), 100.0, today + Period(1, Years));
auto bond2 = ext::make_shared<ZeroCouponBond>(3, TARGET(), 100.0, today + Period(2, Years));

std::vector<ext::shared_ptr<BondHelper>> helpers(2);
helpers[0] = ext::make_shared<BondHelper>(makeQuoteHandle(101.0), bond1);
helpers[1] = ext::make_shared<BondHelper>(makeQuoteHandle(102.0), bond2);

Real accuracy = 1e-10; // default value
Size maxIterations = 10000; // default value
Array guess = {0.01}; // something positive so that initial value is in feasible region

FlatZero unconstrainedMethod(false);
FittedBondDiscountCurve unconstrainedCurve(0, TARGET(), helpers, Actual365Fixed(), unconstrainedMethod,
accuracy, maxIterations, guess);
BOOST_CHECK_LT(unconstrainedCurve.fitResults().solution()[0], 0.0);

FlatZero positiveMethod(true);
FittedBondDiscountCurve positiveCurve(0, TARGET(), helpers, Actual365Fixed(), positiveMethod,
accuracy, maxIterations, guess);
BOOST_CHECK_GT(positiveCurve.fitResults().solution()[0], 0.0);
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 7d4de77

Please sign in to comment.