diff --git a/ql/termstructures/globalbootstrap.hpp b/ql/termstructures/globalbootstrap.hpp index 06b973a3b3..ceb1f393dd 100644 --- a/ql/termstructures/globalbootstrap.hpp +++ b/ql/termstructures/globalbootstrap.hpp @@ -56,9 +56,9 @@ template class GlobalBootstrap { The additional helpers are treated like the usual rate helpers, but no standard pillar dates are added for them. - WARNING: This class is known to work with Traits Discount, ZeroYield, Forward (i.e. the usual traits for IR curves - in QL), it might fail for other traits - check the usage of Traits::updateGuess(), Traits::guess(), - Traits::minValueAfter(), Traits::maxValueAfter() in this class against them. + WARNING: This class is known to work with Traits Discount, ZeroYield, Forward, i.e. the usual traits for IR curves + in QL. It requires Traits::minValueGlobal() and Traits::maxValueGlobal() to be implemented. Also, check the usage + of Traits::updateGuess(), Traits::guess() in this class. */ GlobalBootstrap(std::vector > additionalHelpers, std::function()> additionalDates, @@ -246,9 +246,8 @@ template void GlobalBootstrap::calculate() const { const Size numberBounds = ts_->times_.size() - 1; std::vector lowerBounds(numberBounds), upperBounds(numberBounds); for (Size i = 0; i < numberBounds; ++i) { - // just pass zero as the first alive helper, it's not used in the standard QL traits anyway - lowerBounds[i] = Traits::minValueAfter(i + 1, ts_, validCurve_, 0); - upperBounds[i] = Traits::maxValueAfter(i + 1, ts_, validCurve_, 0); + lowerBounds[i] = Traits::minValueGlobal(i + 1, ts_, validCurve_); + upperBounds[i] = Traits::maxValueGlobal(i + 1, ts_, validCurve_); } // setup cost function @@ -284,7 +283,9 @@ template void GlobalBootstrap::calculate() const { Array guess(numberBounds); for (Size i = 0; i < numberBounds; ++i) { // just pass zero as the first alive helper, it's not used in the standard QL traits anyway - guess[i] = transformInverse(Traits::guess(i + 1, ts_, validCurve_, 0), i); + // update ts_->data_ since Traits::guess() usually depends on previous values + Traits::updateGuess(ts_->data_, Traits::guess(i + 1, ts_, validCurve_, 0), i + 1); + guess[i] = transformInverse(ts_->data_[i + 1], i); } // setup problem diff --git a/ql/termstructures/yield/bootstraptraits.hpp b/ql/termstructures/yield/bootstraptraits.hpp index ba7e246d2b..02999a2d98 100644 --- a/ql/termstructures/yield/bootstraptraits.hpp +++ b/ql/termstructures/yield/bootstraptraits.hpp @@ -38,6 +38,7 @@ namespace QuantLib { namespace detail { const Real avgRate = 0.05; const Real maxRate = 1.0; + const Real maxDF = 10.0; } //! Discount-curve traits @@ -101,6 +102,18 @@ namespace QuantLib { return c->data()[i-1] * std::exp(detail::maxRate * dt); } + // possible constraints for global optimization + template + static Real minValueGlobal(Size i, const C* c, bool validData) + { + return 0; + } + template + static Real maxValueGlobal(Size i, const C* c, bool validData) + { + return detail::maxDF; + } + // root-finding update static void updateGuess(std::vector& data, Real discount, @@ -180,6 +193,18 @@ namespace QuantLib { return detail::maxRate; } + // possible constraints for global optimization + template + static Real minValueGlobal(Size i, const C* c, bool validData) + { + return -detail::maxRate; + } + template + static Real maxValueGlobal(Size i, const C* c, bool validData) + { + return detail::maxRate; + } + // root-finding update static void updateGuess(std::vector& data, Real rate, @@ -261,6 +286,18 @@ namespace QuantLib { return detail::maxRate; } + // possible constraints for global optimization + template + static Real minValueGlobal(Size i, const C* c, bool validData) + { + return -detail::maxRate; + } + template + static Real maxValueGlobal(Size i, const C* c, bool validData) + { + return detail::maxRate; + } + // root-finding update static void updateGuess(std::vector& data, Real forward, @@ -327,8 +364,7 @@ namespace QuantLib { // We choose as min a value very unlikely to be exceeded. result = -detail::maxRate; } - Real t = c->timeFromReference(c->dates()[i]); - return std::max(result, -1.0 / t + 1E-8); + return std::max(result, -1.0 / c->times()[i] + 1E-8); } template static Real maxValueAfter(Size, @@ -345,6 +381,18 @@ namespace QuantLib { return detail::maxRate; } + // possible constraints for global optimization + template + static Real minValueGlobal(Size i, const C* c, bool validData) + { + return std::max(-detail::maxRate, -1.0 / c->times()[i] + 1E-8); + } + template + static Real maxValueGlobal(Size i, const C* c, bool validData) + { + return detail::maxRate; + } + // root-finding update static void updateGuess(std::vector& data, Real rate,