-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix lower/upper bounds for global bootstrap #2120
Fix lower/upper bounds for global bootstrap #2120
Conversation
Currently global bootstrap uses minValueAfter/maxValueAfter methods from Traits to come up with lower/upper bounds. This is problematic. These methods depend on the previous point in the curve. In the iterative bootstrap these methods are called after the previous point is already known exactly. However, in the global bootstrap all points are still filled with Traits::initialValue. This makes the bounds too tight and leads to bad results for curves with higher interest rates. Instead add separate minValueGlobal/maxValueGlobal methods that do not rely on previous data.
3d38f49
to
c987e2d
Compare
CC @pcaspers as the original author of the code |
It seems like calling |
It wouldn't for the Discount trait, which is the most commonly used one AFAIK. It uses the previous point when
We'd need to introduce a new flag like return c->data()[i-1] == 1.0 ? maxDF : c->data()[i-1] * std::exp(detail::maxRate * dt); or to just change the code to return constants (0 and maxDF) even for the iterative bootstrap. We rarely use iterative bootstrap, so I don't know how valuable this calculation is for its performance. All of this seems less clean than new methods, especially since the comment says pretty explicitly // possible constraints based on previous values For the global bootstrap I need methods that do not depend on previous values. However, let me know what your preference is. |
I see, thanks. I missed the difference in the discount traits. |
Thank you. I do agree that this causes a bit of duplication. Also, C++ doesn't have a nice way to make an alias when the logic is the same (e.g. |
Also, use exp instead of atan transformation for discount factors. This is an improvement on lballabio#2120 based on these observations: * Rates-based traits don't need any constraints in the optimization, so we don't need any transformation with them. This is achieved with identity transformation in their traits. * Discount factors are only bounded on one side (have to be positive), so instead of estimating a max value to use atan, we can simply use exp. This is faster and uses fewer magic numbers. Another issue with atan is that changes the gradients too much when the value is far from the middle of the range. This pushes optimization away from the correct solution when rates are low. This makes it hard to find value of maxDF that works for both very low and very high rates.
Also, use exp instead of atan transformation for discount factors. This is an improvement on lballabio#2120 based on these observations: * Rates-based traits don't need any constraints in the optimization, so we don't need any transformation with them. This removes unnecessary computations. * Discount factors are only bounded on one side (have to be positive), so instead of estimating a max value to use atan, we can simply use exp. This is faster and uses fewer magic numbers. Another issue with atan is that it changes the gradients too much when the value is far from the middle of the range. This pushes optimization away from the correct solution when rates are low. This makes it hard to find value of maxDF that works for both very low and very high rates.
Also, use exp instead of atan transformation for discount factors. This is an improvement on lballabio#2120 based on these observations: * Rates-based traits don't need any constraints in the optimization, so we don't need any transformation with them. This removes unnecessary computations. * Discount factors are only bounded on one side (have to be positive), so instead of estimating a max value to use atan, we can simply use exp. This is faster and uses fewer magic numbers. Another issue with atan is that it changes the gradients too much when the value is far from the middle of the range. This pushes optimization away from the correct solution when rates are low. This makes it hard to find value of maxDF that works for both very low and very high rates.
Currently global bootstrap uses minValueAfter/maxValueAfter methods from Traits to come up with lower/upper bounds. This is problematic. These methods depend on the previous point in the curve. In the iterative bootstrap these methods are called after the previous point is already known exactly. However, in the global bootstrap all points are still filled with Traits::initialValue. This makes the bounds too tight and leads to bad results for curves with higher interest rates.
Instead add separate minValueGlobal/maxValueGlobal methods that do not rely on previous data.