I am trying to fit a EUR curve based on the following instruments:-
- EONIA quotes
- 1m vs 6m basis quotes
- 3m (outright) quotes
- 6m (outright) quotes
- 6m vs 12m quotes
(1) , (3) & (4) are simply outright quotes and I fit that (using a python optimiser) by modelling them as :-
- EONIA is modelled as a Quantlib OvernightIndexedSwap object
- 3m & 6m Swaps are modelled as VanillaSwap object
I am having trouble fitting the basis quotes.
1m vs 6m basis quotes
The quotes are as follows:-
6m vs 12m basis quotes
The quotes are as follows:-
The attached code is what I use to model these basis swaps (basically I model them as 2 VanillaSwaps - long the long term Euribor and short the short term Euribor)
My question is regarding which leg to use a Swap1 vs Swap2.
My understanding is , the spread is added to the libor leg of the short tenor.
So for example, for modelling 1m vs 6m, I create VanillaSwap1 object (for the 1m Euribor leg) and add the spread to the floating leg. I then create VanillaSwap2 for the long tenor (i.e. 6m Euribor)
Similarly, for modelling 6m vs 12m basis,:- I create VanillSwap1 object (for the 6m Euribor leg) and add the spread to the floating leg. I then create VanillaSwap2 for the long tenor (i.e. 12m Euribor).
However, I am getting negative fitted zero rate (after the optimisation process) for the 6m vs 12m. NOTE:I get the correct zero spread rate which matches the market but the sign is -ve
For the 1m vs 6m basis, I correctly fit the zero rate spreads to the market
Am I doing something wrong here?
self.z_leg1_forcurve = curves[self.leg1_forcurve] self.z_leg2_forcurve = curves[self.leg2_forcurve] self.z_discurve_1 = curves[self.leg1_discurve] self.z_discurve_2 = curves[self.leg2_discurve] # set the base curve IborIndex self.IBOR_Index1 = ql.IborIndex( 'IborIndex1', ql.Period(self.leg1_frequency), self.settle_days, self.currency, self.calendar, ql.ModifiedFollowing, False, self.day_count, self.z_leg1_forcurve.QLZeroCurve # Zero curve for the forecasting curve ) # set the spread curve IborIndex self.IBOR_Index2 = ql.IborIndex( 'IborIndex2', ql.Period(self.leg2_frequency), self.settle_days, self.currency, self.calendar, ql.ModifiedFollowing, False, self.day_count, self.z_leg2_forcurve.QLZeroCurve # Zero curve for the forecasting curve ) # create a payment schedule for leg_1 schedule1 = ql.Schedule( self.start_date, self.end_date, ql.Period(self.leg1_frequency), self.calendar, ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Backward, False ) # create a payment schedule for leg_2 schedule2 = ql.Schedule( self.start_date, self.end_date, ql.Period(self.leg2_frequency), self.calendar, ql.ModifiedFollowing, ql.ModifiedFollowing, ql.DateGeneration.Backward, False ) # Swap1 is the short tenor (to which we add the spread quote) self.QL_Swap1 = ql.VanillaSwap( ql.VanillaSwap.Payer, self.notional, # nominal schedule1, # fixed leg schedule 0.0, # fixed rate self.day_count, # fixed leg day_count schedule1, # float leg schedule self.IBOR_Index1, # libor index self.quote, # spread (added to leg1 ALWAYS) self.day_count # float leg day_count ) # Swap2 is the long tenor self.QL_Swap2 = ql.VanillaSwap( ql.VanillaSwap.Payer, self.notional, # nominal schedule2, # fixed schedule 0.0, # fixedRate self.day_count, # fixed leg DayCount schedule2, # float schedule self.IBOR_Index2, # liborIndex 0.0, # spread self.day_count # float leg day_count ) # discount the base curve with it's own discounting_curve engine = ql.DiscountingSwapEngine(self.z_discurve_1.QLZeroCurve) self.QL_Swap1.setPricingEngine(engine) # discount the spread curve with it's own discounting_curve engine2 = ql.DiscountingSwapEngine(self.z_discurve_2.QLZeroCurve) self.QL_Swap2.setPricingEngine(engine2) ```