-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Feature: Fast Valuation of Seasoned OIS Swaps #2213
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
base: master
Are you sure you want to change the base?
Feature: Fast Valuation of Seasoned OIS Swaps #2213
Conversation
…ating the compoun factor
Rate OvernightIndex::compoundedFixings(const Date& fromFixingDate, const Date& toFixingDate) { | ||
calculate(); | ||
auto yearFraction = dayCounter_.yearFraction(fromFixingDate, toFixingDate); | ||
auto compIndexEnd = compoundIndex_[toFixingDate]; | ||
auto compIndexStart = compoundIndex_[fromFixingDate]; | ||
|
||
if (compIndexStart == Null<Real>() || compIndexEnd == Null<Real>()) | ||
return Null<Real>(); | ||
|
||
return (compoundIndex_[toFixingDate] / compoundIndex_[fromFixingDate] - 1) / yearFraction; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this belongs into the index. It should be in the coupon or the coupon pricer—especially because the way the composition is done doesn't depend only on the start and end date, but also on the lookback days and whether or not one must apply the observation shift, which are parameters of the coupon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, the compounded index should be linked to the Overnight Index itself, unless we are using the same CompoundedOvernightIndexPricer within the same Leg
. I don’t see any performance improvements from having a different instance of the CompoundedOvernightIndexPricer
for each coupon, especially if each has an associated compoundedIndex attribute; each pricer is going to recalculate those compounded fixings in the past, not leveraging the compounded index.
Aren't the lookback days and the observation shift logics that concern the Coupon itself? I feel like they shouldn't concern the compounded index. I don't really see why the compounded index should have taken into account that logic, since we could have coupons on the same Overnight index with different lookback days, and so on.
Another practical way to store the compoundedIndex could be by utilizing a sort of IndexManager
, similar to what you have implemented with the standard fixings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lookback days and the observation shift concern the Coupon, and they have an effect on the compounding. As an example, let's consider a coupon starting today, Monday May 12th, with lookback days = 2, so we have for instance these initial compounding dates:
date | fixing date |
---|---|
Monday May 12th | Thursday May 8th |
Tuesday May 13th | Friday May 9th |
Wednesday May 14th | Monday May 12th |
Thursday May 15th | Tuesday May 13th |
Friday May 16th | Wednesday May 14th |
Monday May 19th | Thursday May 15th |
If the observation shift is set to false, the coupon dates in the first column determine the compounding days; so for instance, the index fixing for Friday May 9th is compounded for 1 day (May 13th to May 14th) and the fixing for Wednesday May 14th is compounded for 3 days (May 16th to May 19th). If the observation shift is set to true, it's the fixing dates in the second column that determine the compounding days, so the index fixing for Friday May 9th is compounded for 3 days and the fixing for Wednesday May 14th is compounded for 1 day. A different number of lookback days would give you other results.
The index alone can't know this. It can only give you single fixings. It's the coupon that should manage this calculation.
--
About having different instances of the coupon pricer: yes, the cache should be shared between pricers, like the IndexManager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you're saying, and I agree that it’s ultimately the coupon that should handle the compounding, not the compounded index itself. The compounded index can give us the individual fixings (since that’s what it essentially stores), but the logic for compounding over a period is typically managed within the coupon itself.
How would you suggest to tackle this problem then? I was thinking to resister and additional index in in the IndexManager
(with the name "<Overnight_index> Comp"), and store the compounded index there since now if I feel like it's the natural place to store it. But again the problems will come from the fact that we might have non-contiguous fixing (calendar-wise I mean), so we could have the comp index for a period (like from the 1st of Janurary to the 31st of Janurary) but then let's say we are missing some fixings (first week of February) and we have the fixing after those. How should we deal with that situation?
My idea is to not store anything and then fallback on normal fixing (stored in the normal index).
Example of CompIndex in IndexManager
(assuming that the available fixings start from the 1st of January 2025)
Name: "Estr Comp"
Date | CompIndexValue |
---|---|
02-01-2025 | 1.0000 |
03-01-2025 | 1.000081 |
06-01-2025 | 1.000324 |
07-01-2025 | 1.000405 |
08-01-2025 | 1.000487 |
09-01-2025 | 1.000568 |
10-01-2025 | ... |
return compIndexEnd / compIndexStart; | ||
} | ||
|
||
void OvernightIndex::performCalculations() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure LazyObject is the right mechanism for this. This calculation will be executed again and again every time the index (or the pricer, if you move the calculation there) receives a notification; for instance, when the forecast curve changes, even though it has no effect on the stored past prices on which this calculation depends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the calculation be triggered also when the forecast curve changes as well? Not just when I call the addFixing
or addFixings
? It's there where I set calculated_ = false
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see, because you've removed the part in update
where the lazy object sets calculated_
to false. Hmm, yes, it would possibly work, but I'm not sure if I'm comfortable with changing the way the lazy object works. Also, you might add a fixing through a different instance of the index, and this instance would still have calculated_
set to false and ignore the new fixing.
.from(fixingDates.front()) | ||
.to(lastFixingDate) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using performCalculations(), which has no arguments, forced you to calculate compounded values for the whole history, but that might be unnecessary. If possible, I'd calculate the series of compounded values only on the requested range, extending it as needed with each call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's inefficient. Ideally, assuming that one should add fixings from the last fixing day that we have in history in the compounded index, the optimization that can be put in place could be to compute the compounded index from the last past fixing date to the new past date of the next fixing.
Added a compoundIndex attribute in the
OvernightIndex
to keep track of the past fixings and speed up the calculation of compounded fixings for Seasoned OIS Swap as described in #1653.Changes in the PR include:
OvernightIndex
Lazy, so the compounded index is calculated on demand.OvernightIndex
class, with new methodscompoundedFixings
andcompoundedFactor
. These methods leverage historical fixings to calculate rates and factors efficiently.averageRate
code inCompoundingOvernightIndexedCouponPricer
by extracting logic for handling past, today, and future fixings into separate private methods (handlePastFixings, handleTodayFixing, handleFutureFixings) to improve code readability and maintainability.