-
Notifications
You must be signed in to change notification settings - Fork 2.1k
QL-ORE ON coupons alignment #2297
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
QL-ORE ON coupons alignment #2297
Conversation
|
@lballabio I actually need help with the test |
|
Not a lot of time now unfortunately, but I would try checking that we're not accessing some vector out of its bounds and getting garbage numbers. |
|
I pushed a fix for the failing tests—a couple of bools were left uninitialized. I still have to do a proper review... |
|
Thank you @lballabio! I didn't have much time to debug the tests lately |
|
Apologies for the long delay. One thing: currently the pricers are defined this way: classDiagram
class FloatingRateCouponPricer
class CompoundingOvernightIndexedCouponPricer
class ArithmeticAveragedOvernightIndexedCouponPricer
class CappedFlooredOvernightIndexedCouponPricer
class BlackOvernightIndexedCouponPricer
class BlackAverageONIndexedCouponPricer
FloatingRateCouponPricer <|-- CompoundingOvernightIndexedCouponPricer
FloatingRateCouponPricer <|-- ArithmeticAveragedOvernightIndexedCouponPricer
FloatingRateCouponPricer <|-- CappedFlooredOvernightIndexedCouponPricer
CappedFlooredOvernightIndexedCouponPricer <|-- BlackOvernightIndexedCouponPricer
CappedFlooredOvernightIndexedCouponPricer <|-- BlackAverageONIndexedCouponPricer
Instead, I would try to turn it into classDiagram
class FloatingRateCouponPricer
class CompoundingOvernightIndexedCouponPricer
class ArithmeticAveragedOvernightIndexedCouponPricer
class BlackOvernightIndexedCouponPricer
class BlackAverageONIndexedCouponPricer
FloatingRateCouponPricer <|-- CompoundingOvernightIndexedCouponPricer
FloatingRateCouponPricer <|-- ArithmeticAveragedOvernightIndexedCouponPricer
CompoundingOvernightIndexedCouponPricer <|-- BlackOvernightIndexedCouponPricer
ArithmeticAveragedOvernightIndexedCouponPricer <|-- BlackAverageONIndexedCouponPricer
or maybe, if we need to share something between compounded and averaged, something like classDiagram
class FloatingRateCouponPricer
class OvernightIndexedCouponPricer
class CompoundingOvernightIndexedCouponPricer
class ArithmeticAveragedOvernightIndexedCouponPricer
class BlackOvernightIndexedCouponPricer
class BlackAverageONIndexedCouponPricer
FloatingRateCouponPricer <|-- OvernightIndexedCouponPricer
OvernightIndexedCouponPricer <|-- CompoundingOvernightIndexedCouponPricer
OvernightIndexedCouponPricer <|-- ArithmeticAveragedOvernightIndexedCouponPricer
CompoundingOvernightIndexedCouponPricer <|-- BlackOvernightIndexedCouponPricer
ArithmeticAveragedOvernightIndexedCouponPricer <|-- BlackAverageONIndexedCouponPricer
What do you think? |
|
2nd and 3rd case make more sense to me. I would opt for the 3rd case. One question: is |
|
The interface is already declared in FloatingRateCouponPricer. The base class might perhaps store the volatility term structure, but otherwise there's not a lot in common, which is why the existing pricers don't have a common base. |
|
Got it. So the |
|
One problem that I have noticed @lballabio: If |
|
I think you can copy the approach in |
|
@lballabio don't know is it better to set if (lookbackDays != 0) { //by default lookbackDays is 2147483647
BusinessDayConvention bdc = lookbackDays > 0 ? Preceding : Following;
valueStart = overnightIndex->fixingCalendar().advance(valueStart, -lookbackDays, Days, bdc); //error is throw in here: QuantLib::Error: Date's serial number (366) outside allowed range [367-109574]
valueEnd = overnightIndex->fixingCalendar().advance(valueEnd, -lookbackDays, Days, bdc);
} |
|
Hi Paolo, I'm not sure I understand the question. Right now you have |
|
I was just wondering whether to set |
|
I fixed the issues you guys pointed out. Whenever you have time to review it @lballabio @pcaspers |
|
Thanks, I'm looking at it now so hopefully it goes into 1.41. |
| OvernightLeg& withOvernightIndexedCouponPricer(const ext::shared_ptr<FloatingRateCouponPricer>& couponPricer); | ||
| OvernightLeg& withCapFlooredOvernightIndexedCouponPricer( | ||
| const ext::shared_ptr<OvernightIndexedCouponPricer>& couponPricer); |
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.
@pcaspers as I see it, there's no reason to have two different methods to pass two different pricers; the Black pricer can manage coupons both with and without caps/floors. Do you have any use cases that say otherwise?
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.
@lballabio no, you are right, we don't need both methods
|
Hmm, there seems to be a problem that didn't surface until I tried to use just one pricer for both capped and non-capped coupons. If one sets a Black coupon pricer to an OvernightIndexedCoupon (not the capped one), this triggers an infinite recursion. |
|
You can leave it to me if you want, just give me a couple of days |
|
Sure, thanks. |
|
I figured out what the error is due to: in ORE the effectiveIndexFixing_ = coupon_->underlying()->effectiveIndexFixing();but since now that we also need to be able to price an thus leading to that infinite recursion. auto [swapletRate, effectiveSpread, effectiveIndexFixing] = compute(coupon_->accrualEndDate()); |
|
Sounds good - did you try that? |
|
Yeah, it worked. This is the code that I've added: auto [swapletRate, effectiveSpread, effectiveIndexFixing] = CompoundingOvernightIndexedCouponPricer::compute(coupon_->accrualEndDate());
swapletRate_ = swapletRate;
effectiveSpread_ = effectiveSpread;
effectiveIndexFixing_ = effectiveIndexFixing;Are we sure that we want to trigger the |
|
makes sense to me, we need these results for the underlying coupon, so why not set them here |
With the check in setCouponPricer, the call
OvernightLeg(...)
.withCouponPricer(arithmeticPricer)
.withAveragingMethod(RateAveraging::Simple)
would fail.
|
Thanks! Another thing turned up: I added a few more checks in the tests, and one of them fails because setting a Black arithmetic-averaging pricer to a vanilla coupon results in a rate = 0 being returned. I'm pushing it so you can have a look. |
| vanillaCoupon->setPricer(pricer); | ||
|
|
||
| Rate rate = vanillaCoupon->rate(); | ||
| Rate expectedRate = 0.039765917; |
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.
Is this rate supposed to be the same as in the Compounding averaging case? I get a different value with the ArithmeticAveragedOvernightIndexedCouponPricer
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 think we need to call the ArithmeticAveragedOvernightIndexedCouponPricer::swaplet() method in the BlackAveragingOvernightIndexedCouponPricer::initialize method, just like we did with the BlackCompoundingOvernightIndexedCouponPricer case since aslo in the ORE code the swapletRate_ was set to
swapletRate_ = coupon_->underlying()->rate();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.
No, it's not supposed to be the same.
|
Great, thanks. Thanks to you both for the effort on this one! |
This PR tries to be an alignment for the difference of the overnight coupons and ON coupons pricers in QuantLib and ORE.
Changes to note for ORE (@pcaspers ):
OvernightIndexedCouponPricercode is in theovernightindexedcouponpricer.hppfile not in theovernightindexedcoupon.hppfile anymore.rateCutoffin ORE islockoutDaysin QuantLibfixingDaysin ORE islookbackDaysin QuantLibAverageONIndexedCouponin QuantLib the averaging method is passed as a argument in theOvernightIndexedCouponand it is an enum type:OvernightIndexedCouponPricerspricing logic haven't been changes since I haven't noticed substantial differences (apart from the rateCutoff and fixingDays naming conventions). The only thing that I'm unsure of is the following line. I haven't seen such thing in QuantLib.Changes to note in QL (@lballabio ):
CappedFlooredOvernightIndexedCouponclass underovernigthindexcoupon.hpp(imported from ORE)BlackOvernightIndexedCouponPricerandBlackAverageONIndexedCouponPricerfor pricing capped / floored compounded ON coupons (imported from ORE)OvernightLegclass (includeSpread,withCaps,withFloors,withNakedOption, ...) imported from OREincludeSpread,rateComputationStartDate,rateComputationEndDatearguments to theOvernightIndexedCouponconstructor (missing args from ORE)