Skip to content
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

allow swaptions to take OvernightIndexedSwap #1593

Merged
merged 14 commits into from Mar 28, 2024

Conversation

thrasibule
Copy link
Contributor

closes #1588 I don't want to take any credit this for this code. This is cherry picked from https://github.com/OpenSourceRisk/QuantLib. @pcaspers mentionned before that he would be willing to contribute this to QuantLib, see #1379 (comment)

@pcaspers
Copy link
Contributor

pcaspers commented Feb 8, 2023

I have no objections doing this. Quite the contrary, it helps reducing the diff between our fork and the official repo!

@lballabio lballabio added this to the Release 1.30 milestone Feb 8, 2023
@coveralls
Copy link

coveralls commented Feb 8, 2023

Coverage Status

coverage: 72.497% (+0.07%) from 72.426%
when pulling 9b4efa3 on thrasibule:ois_swaption2
into c6492d0 on lballabio:master.

@@ -72,6 +72,7 @@ namespace QuantLib {
}

void OvernightIndexedSwap::initialize(const Schedule& schedule) {
schedule_ = schedule;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be assigned in the constructor?

Regardless of where it is assigned, it should be passed by value and moved into the member variable in order to avoid a copy.

@@ -97,10 +102,13 @@ namespace QuantLib {
Settlement::Method settlementMethod() const {
return settlementMethod_;
}
Swap::Type type() const { return swap_->type(); }
Swap::Type type() const { return swap_ ? swap_->type() : swapOis_->type(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If swapOis_ is assumed to be non-null when swap_ is null then this should probably be asserted in the constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is implicitly enforced by the signature. One can never pass both a vanillaswap and a overnightindexedswap to the constructor.

VanillaSwap::arguments::validate();
QL_REQUIRE(swap, "vanilla swap not set");
}
if (swapOis) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean else if?

const Leg& fixedLeg = swap.fixedLeg();
auto swap = arguments_.swap;
auto swapOis = arguments_.swapOis;
QL_REQUIRE(swap || swapOis,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean QL_REQUIRE((swap || swapOis) && !(swap && swapOis)?

@ralfkonrad
Copy link
Contributor

Hi @thrasibule,

IMHO this PR looks a little bit like this anti-pattern:

We are now having both swap_ and swapOis_ in Swaption and later on having (a lot of) switches to decide if the underlying swap is a VanillaSwap or an OvernightIndexedSwap.

E.g. what about the other pricing engines in ql/pricingengines/swaption? Do they still work as designed if you pass in an OvernightIndexedSwap?

@pcaspers: I guess in ORE you don't care about the other engines aka don't use them?

Wouldn't it be better to derive an OvernightIndexedSwaption from Swaption and do the needed adjustments aka switch- and if -statements there?

Regards Ralf

@lballabio
Copy link
Owner

Yes, I was thinking about reworking this somehow. I'll give it a go.

@pcaspers
Copy link
Contributor

pcaspers commented Feb 9, 2023

Yes - the goal in ORE was to get it working with as little effort as possible.

@lballabio
Copy link
Owner

I think I'd duplicate the class so that we have a Swaption and an OvernightIndexedSwaption. Same for the Black engine. We can find later ways to factor out common code (templates, maybe? Types are different).

Also, I don't think any of the other engines (besides the Black engine in this PR) will work with an OI swaption — they all use arguments_.swap one way or the other. I think this also prevents the swaption helper from working with OI, as it can calculate the Black price but not the model price. @pcaspers, did you modify those as well in ORE?

@pcaspers
Copy link
Contributor

Yes we have adapted those as well

@pcaspers
Copy link
Contributor

The danger here being that a partial migration and / or refactoring will cause conflicts in our codebase. Not sure if this is the right way forward?

@lballabio
Copy link
Owner

Hmm. Yes, we probably need to look at those as well. Do you have additional engines in QuantExt too?

@tomwhoiscontrary
Copy link
Contributor

Another road here would be to revisit the idea of a base type for interest rate swaps (#662). I agree that it seems janky to have two fields for the different types of swaps as in the original implementation, but it seems just as janky to have two classes of swaption which ultimately differ only in the underlying index!

@pcaspers
Copy link
Contributor

Hmm. Yes, we probably need to look at those as well. Do you have additional engines in QuantExt too?

yes - also updates for CMS pricers (not sure at the moment if they are affected too)

@ralfkonrad
Copy link
Contributor

@pcaspers: I'm not sure I understood all of your answers concerning what has been adopted in ORE correctly. E.g. which of the engines in ql/pricingengines/swaption will currently work with the approach discussed here?

You have the BlackSwaptionEngine adjusted. But what about the others? I don't see adjustment for the FdHullWhiteSwaptionEngine, the TreeSwaptionEngine (incl. the DiscretizedSwaption).

I would expect changes for them as well to handle e.g. a Bermudan swaption which is between two call dates. The current running OIS coupon cannot be priced correctly with their current implementation, can they?!

Or have I overlooked something?

@lballabio
Copy link
Owner

Another road here would be to revisit the idea of a base type for interest rate swaps (#662). I agree that it seems janky to have two fields for the different types of swaps as in the original implementation, but it seems just as janky to have two classes of swaption which ultimately differ only in the underlying index!

Yes, I'm liking this solution better than any of the alternatives

@pcaspers
Copy link
Contributor

@pcaspers: I'm not sure I understood all of your answers concerning what has been adopted in ORE correctly. E.g. which of the engines in ql/pricingengines/swaption will currently work with the approach discussed here?

You have the BlackSwaptionEngine adjusted. But what about the others? I don't see adjustment for the FdHullWhiteSwaptionEngine, the TreeSwaptionEngine (incl. the DiscretizedSwaption).

I would expect changes for them as well to handle e.g. a Bermudan swaption which is between two call dates. The current running OIS coupon cannot be priced correctly with their current implementation, can they?!

Or have I overlooked something?

No you haven't overlooked anything. We don't use FdHullWhiteSwaptionEngine or TreeSwaptionEngine in ORE, therefore I didn't adjust those. But we have other engines (not part of QuantLib) that handle Swaptions on OIS Swaps.

@lballabio lballabio removed this from the Release 1.30 milestone Mar 25, 2023
@github-actions
Copy link
Contributor

This PR was automatically marked as stale because it has been open 60 days with no activity. Remove stale label or comment, or this will be closed in two weeks.

@lballabio
Copy link
Owner

@pcaspers: I'm not sure I understood all of your answers concerning what has been adopted in ORE correctly. E.g. which of the engines in ql/pricingengines/swaption will currently work with the approach discussed here?
You have the BlackSwaptionEngine adjusted. But what about the others? I don't see adjustment for the FdHullWhiteSwaptionEngine, the TreeSwaptionEngine (incl. the DiscretizedSwaption).
I would expect changes for them as well to handle e.g. a Bermudan swaption which is between two call dates. The current running OIS coupon cannot be priced correctly with their current implementation, can they?!
Or have I overlooked something?

No you haven't overlooked anything. We don't use FdHullWhiteSwaptionEngine or TreeSwaptionEngine in ORE, therefore I didn't adjust those. But we have other engines (not part of QuantLib) that handle Swaptions on OIS Swaps.

@pcaspers: I'm having another look at this.

So if I get this correctly:
(a) the part of this PR that modifies the swaption itself and the Black engine can be used to price European swaptions given a vol surface built from quoted volatilities;
(b) but the part that modifies the swaption helpers can't be used until we have an engine that works with OIS swaptions (either the existing JamshidianSwaptionEngine, TreeSwaptionEngine etc or some new one from ORE) and thus can be used during calibration.

Is that right?

@pcaspers
Copy link
Contributor

pcaspers commented Aug 3, 2023

@lballabio yes that sounds right.

@lballabio
Copy link
Owner

@pcaspers this can probably be simplified using #1789 which is now merged—do you want to try it in ORE first?

@pcaspers
Copy link
Contributor

@lballabio that would be nice. However since we have a release end of September I am going to look into this in October or possibly even later. I.e. I don't want to hold things up!

@lballabio
Copy link
Owner

Sure!

@pcaspers
Copy link
Contributor

pcaspers commented Feb 5, 2024

So in ORE we are moving in a slightly different direction now: In general we need to support swaptions with European, Bermudan, American exercise right on overnight, Ibor, BMA/SIFMA, Subperiod coupons. For Bermudan / American swaptions we are using the MultiLegOption instrument

https://github.com/OpenSourceRisk/Engine/blob/master/QuantExt/qle/instruments/multilegoption.hpp

for a while now already, in conjunction with numerical integration / finite-difference and MC engines. Only the European case still used QuantLib::Swaption and NonStandardSwaption and the corresponding Black pricing engine. I am now working on adapting the Black engine to MultiLegOption and generalizing it to the remaining coupon types, so that all cases can be uniformly represented by MultiLegOption and our existing numerical engines can also be applied to the European case. SwaptionHelper is still on Swaption and the QL Black engine. We might move to the new Black engine there too.

Long story short, this development here has no high priority for us at the moment. Of course I'd be happy to migrate our approach to QuantLib, but I appreciate that this would be too disruptive (correct me if I am wrong!), so that we'll probably just keep the variants in parallel.

@thrasibule
Copy link
Contributor Author

What do you think of the current PR? This is a natural extension of ##1789. I don't think it breaks anything, and it allows to price OIS european swaptions using the Black engine, which is better than the status quo.

@lballabio
Copy link
Owner

I still have to find some time to look at the new changes, but yes, I'd try to get it into next release.

Real shift = 0.0);
Real shift = 0.0,
Natural settlementDays = Null<Size>(),
RateAveraging::Type averagingMethod = RateAveraging::Compound);
Copy link
Owner

@lballabio lballabio Feb 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that we want to pass the averaging method yet—the engines we can use with the swaption helper (Jamshidian etc) don't manage OIS yet and are going to treat the swaps as vanilla during calibration. This might be ok if the averaging method is compounding, because of the telescopic property, but not for arithmetic averaging. I wouldn't add the parameter yet and would hard-code the method instead.

@ralfkonrad
Copy link
Contributor

I'm not fully convinced by the approach yet.

  1. In SwaptionHelper we start already to distinguish between VanillaSwap and OvernightIndexedSwap. This will in the long run be spread into other parts of the library like engines as well, I guess. The idea of c++ and OOP is to get rid of these if and switch statements by using a clean class hierarchy.
  2. Pricing engine like the TreeSwaptionEngine will probably fail or at least give wrong results if we pass an OIS swap into it. We might make them fail fast by checking for a VanillaSwap but then see remark 1 above.
  3. The G2SwaptionEngine might except an OIS swap but there is no corresponding test case to check the result of these engines. As far as I can see only the BlackSwaptionEngine is currently tested.

I am still in favor of doing it the hard but consistent way to have a class likeOISSwaption with its own engines etc. and avoiding code duplication by using templates and/or an abstract base class like FixedVsFloatingSwaption.

@thrasibule
Copy link
Contributor Author

SwaptionHelper is a little awkward. Maybe it makes sense to have a separate OISSwaptionHelper class, where we can pass the averagingmethod there. Other than that I don't see why we need to create a new instrument class just because a particular engine doesn't give the right results. BlackSwaptionEngine doesn't give the right result with Bermudan exercise for instance.

@lballabio
Copy link
Owner

A separate OISSwaptionHelper class might be a good idea. Existing engines not working with OIS are not a problem but they should probably raise an exception if passed an OIS swaption. What do you think?

@lballabio lballabio added this to the Release 1.34 milestone Mar 5, 2024
@lballabio
Copy link
Owner

I started separating SwaptionHelper and OISSwaptionHelper but when I got halfway I realized that the switch was now isolated in a small method makeSwap. I might stop here. What do you think?

@thrasibule
Copy link
Contributor Author

This definitely less invasive. I've done the whole hierarchy here: thrasibule@038a30b (with almost the same makeSwap method). The only advantage is if we want to pass additional parameters to overnightindexed swaption like averaging method.

@lballabio lballabio merged commit 9ff0542 into lballabio:master Mar 28, 2024
51 checks passed
Repository owner deleted a comment from FinancialEngineerLab Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RFR/SOFR Swaptions
7 participants