IRS CAD (insert Term here) vs 3M CDOR

For a given effective date, tenor, and notional I need to calculate the delta (DV01) sensitivity of 1 basis point to the (3mo) curve.

I have the price contributions (composites) and the CDOR (Canadian Dollar Offered Rate) daily rates.
I’ve read the blog posts on starata and multi-curves (calibration, interpolation, etc), also the SwapPricingExample.

I found the CDOR indices defined in com.opengamma.strata.basics.index.IborIndices (Thank you).

What’s the simplest way to do this?

I understand the discount curve (in this case) is the difference between the “tenor” swap curve and the 3mo interpolated to 30yr curve. What data should I feed to … what? (I mean DiscountingSwapTradePricer, MarketQuoteSensitivityCalculator)

Please bare with me - just a regular developer here , no quant, not much swaps knowledge either (coming from the equities realm)

Thank you!

StandardFixedIborSwapConventions and FixedIborSwapConventions are both final.
Through which mechanism would I be able to add say “CAD-FIXED-3M-CDOR-3M”?

I got to a point where my newly defined CAD_FIXED_3M_CDOR_3M is not recognized since not being defined in the above.

See this documentation about adding an extended enum. Basically, you need to add a config file that points at your additional class.

To calculate PV01 in DiscountingSwapTradePricer you call presentValueSensitivity. This gets you the sensitivity to the zero rates (assuming your curve contains zero rates). To convert that sensitivity to par rate sensitivity you need to use MarketQuoteSensitivityCalculator (pass the result of presentValueSensitivity to the calculator).

I used the SwapPricingWithCalibrationExample source, removed the fixing part, and replaced FixedIborSwapConventions.USD_FIXED_6M_LIBOR_3M with my own definition of CAD_FIXED_6M_CDOR_3M and got pretty close to the expected result seen in a vendor terminal.

SwapTradeCalculations does wonders :slight_smile:
Here’s my shortest way to calculate this:

		ReferenceData REF_DATA = ReferenceData.standard();
		Map<CurveGroupName, CurveGroupDefinition> defns = 
				RatesCalibrationCsvLoader.load(
						GROUPS_RESOURCE, 
						SETTINGS_RESOURCE, 
						CALIBRATION_RESOURCE);
		ResolvedSwapTrade swap = 
				CAD_FIXED_6M_CDOR_3M.createTrade(
						VALUATION_DATE, 
						SWAP_PERIOD_TO_START, 
						Tenor.of(Period.ofYears(3)),
						BuySell.BUY, 
						SWAP_NOTIONAL, 
						SWAP_COUPON, 
						REF_DATA)
				.resolve(REF_DATA);

		CalibrationMeasures CALIBRATION_MEASURES = CalibrationMeasures.PAR_SPREAD;
		
		CurveCalibrator CALIBRATOR = CurveCalibrator.of(1e-9, 1e-9, 100, CALIBRATION_MEASURES);

		ImmutableMap<QuoteId, Double> MAP_MQ = QuotesCsvLoader.load(VALUATION_DATE, QUOTES_RESOURCE);

		ImmutableMarketData MARKET_QUOTES = ImmutableMarketData.builder(VALUATION_DATE).values(MAP_MQ).build();

		ImmutableRatesProvider multicurve = CALIBRATOR.calibrate(defns.get(CURVE_GROUP_NAME), MARKET_QUOTES,REF_DATA);
		
		DiscountingSwapTradePricer PRICER_SWAP = DiscountingSwapTradePricer.DEFAULT;
		
		SwapTradeCalculations swapTradeCalc = new SwapTradeCalculations(PRICER_SWAP);
		
		System.out.println("DV01 = "+swapTradeCalc.pv01MarketQuoteSum(swap, multicurve));

CalibrationMeasures.PAR_SPREAD is the only type that works for me.

If I use MARKET_QUOTE I get a yData containing NaN exception
If I use PRESENT_VALUE I get Market Quote sensitivity requires Jacobian calibration information exception.

Also If I define in my calibration file the 1M and 2M CDOR values, I get a BaseNewtonVectorRootFinder - Failed to converge in backtracking, even after a Jacobian recalculation exception.

files below
groups

Group Name,Curve Type,Reference,Curve Name
IRS-VS-3M-CDOR,Discount,CAD,CAD-CURVE
IRS-VS-3M-CDOR,Forward,CAD-CDOR-3M,CAD-CURVE

settings

Curve Name,Value Type,Day Count,Interpolator,Left Extrapolator,Right Extrapolator
CAD-CURVE,Zero,Act/365F,LogNaturalSplineDiscountFactor,Interpolator,LogLinear

calibrations

Curve Name,Label,Symbology,Ticker,Field Name,Type,Convention,Time,Date
#CAD-CURVE,CAD-CDOR-1M,OG-Ticker,CAD-CDOR-1M,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,1M,
#CAD-CURVE,CAD-CDOR-2M,OG-Ticker,CAD-CDOR-2M,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,2M,
CAD-CURVE,CAD-CDOR-3M,OG-Ticker,CAD-CDOR-3M,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,3M,
CAD-CURVE,CAD-CDOR-6M,OG-Ticker,CAD-CDOR-6M,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,6M,
CAD-CURVE,CAD-CDOR-1Y,OG-Ticker,CAD-CDOR-1Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,1Y,
CAD-CURVE,DLR-CMP-2Y,OG-Ticker,DLR-CMP-2Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,2Y,
CAD-CURVE,DLR-CMP-3Y,OG-Ticker,DLR-CMP-3Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,3Y,
CAD-CURVE,DLR-CMP-4Y,OG-Ticker,DLR-CMP-4Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,4Y,
CAD-CURVE,DLR-CMP-5Y,OG-Ticker,DLR-CMP-5Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,5Y,
CAD-CURVE,DLR-CMP-6Y,OG-Ticker,DLR-CMP-6Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,6Y,
CAD-CURVE,DLR-CMP-7Y,OG-Ticker,DLR-CMP-7Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,7Y,
CAD-CURVE,DLR-CMP-8Y,OG-Ticker,DLR-CMP-8Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,8Y,
CAD-CURVE,DLR-CMP-9Y,OG-Ticker,DLR-CMP-9Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,9Y,
CAD-CURVE,DLR-CMP-10Y,OG-Ticker,DLR-CMP-10Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,10Y,
CAD-CURVE,DLR-CMP-12Y,OG-Ticker,DLR-CMP-12Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,12Y,
CAD-CURVE,DLR-CMP-15Y,OG-Ticker,DLR-CMP-15Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,15Y,
CAD-CURVE,DLR-CMP-20Y,OG-Ticker,DLR-CMP-20Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,20Y,
CAD-CURVE,DLR-CMP-25Y,OG-Ticker,DLR-CMP-25Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,25Y,
CAD-CURVE,DLR-CMP-30Y,OG-Ticker,DLR-CMP-30Y,MarketValue,IRS,CAD-FIXED-6M-CDOR-3M,30Y,

quotes

Valuation Date,Symbology,Ticker,Field Name,Value
2018-03-19,OG-Ticker,CAD-CDOR-1M,MarketValue,0.01595
2018-03-19,OG-Ticker,CAD-CDOR-2M,MarketValue,0.0164
2018-03-19,OG-Ticker,CAD-CDOR-3M,MarketValue,0.016975
2018-03-19,OG-Ticker,CAD-CDOR-6M,MarketValue,0.0184875
2018-03-19,OG-Ticker,CAD-CDOR-1Y,MarketValue,0.0205625
2018-03-19,OG-Ticker,DLR-CMP-2Y,MarketValue,0.02148
2018-03-19,OG-Ticker,DLR-CMP-3Y,MarketValue,0.02280
2018-03-19,OG-Ticker,DLR-CMP-4Y,MarketValue,0.03366
2018-03-19,OG-Ticker,DLR-CMP-5Y,MarketValue,0.02419
2018-03-19,OG-Ticker,DLR-CMP-6Y,MarketValue,0.02458
2018-03-19,OG-Ticker,DLR-CMP-7Y,MarketValue,0.02496
2018-03-19,OG-Ticker,DLR-CMP-8Y,MarketValue,0.02533
2018-03-19,OG-Ticker,DLR-CMP-9Y,MarketValue,0.02569
2018-03-19,OG-Ticker,DLR-CMP-10Y,MarketValue,0.02601
2018-03-19,OG-Ticker,DLR-CMP-12Y,MarketValue,0.02654
2018-03-19,OG-Ticker,DLR-CMP-15Y,MarketValue,0.02713
2018-03-19,OG-Ticker,DLR-CMP-20Y,MarketValue,0.02764
2018-03-19,OG-Ticker,DLR-CMP-25Y,MarketValue,0.02755
2018-03-19,OG-Ticker,DLR-CMP-30Y,MarketValue,0.02733

The backtracking error is because the root finder has nothing that constrains the 1M or 2M point.

What you typically need to do is to use the IborFixingDeposit class for the 1M and 2M points. Instead of Type=IRS, you use Type=FIX in the calibrations file:

CAD-CURVE,CAD-CDOR-1M-FIX,OG-Ticker,CAD-CDOR-1M,MarketValue,IRS,CAD-CDOR-3M,1M,
CAD-CURVE,CAD-CDOR-2M-FIX,OG-Ticker,CAD-CDOR-2M,MarketValue,IRS,CAD-CDOR-3M,2M,

If you look in calibrations.csv in strata-examples, you will see an example of the FIX type that is used to lock the first point on the USD-LIBOR-3M curve.

Your case is slightly different as you want to lock two points on the curve, at 1M and 2M. Note that I believe the convention column refers to CAD-CDOR-3M to match the rest of the points on the curve.

Thanks Stephen

you mean

CAD-CURVE,CAD-CDOR-1M-FIX,OG-Ticker,CAD-CDOR-1M,MarketValue,FIX,CAD-CDOR-3M,1M,
CAD-CURVE,CAD-CDOR-2M-FIX,OG-Ticker,CAD-CDOR-2M,MarketValue,FIX,CAD-CDOR-3M,2M,

In this case I get same dates as resolved dates for the 1M and 2M …

Curve node dates clash, node 'CAD-CDOR-1M-FIX' and 'CAD-CDOR-2M-FIX' resolved to dates '2018-06-19' and '2018-06-19' respectively

Ah yes, I see now that our code ignores the “Time” column. This means FIX can only be added once for the spot observation of CAD-CDOR-3M. I’ll need to get our quants to look at this case.

“The backtracking error is because the root finder has nothing that constrains the 1M or 2M point.”

How come the 1M and 2M points have to be constrained? Couldn’t the root finder simply find the best solution given that these points are “free”?

How can we know which points must be constrained? Is it every month?

hi @vst ,

Would you mind sharing how you replaced FixedIborSwapConventions.USD_FIXED_6M_LIBOR_3M with your own definition of CAD_FIXED_6M_CDOR_3M

Running into the same issue where I still am unable to recognise my new AUD swap conventions.

Thanks vm

In my project in:
src/opengamma/strata/config/library I defined FixedOvernightSwapConvention.ini
having

[providers]
com.mycompany.swaps.IRSSwapsConvention = constants

in
src/mycompany/swaps I defined IRSSwapsConvention.java
having

public static final FixedIborSwapConvention CAD_FIXED_6M_CDOR_3M =
	      ImmutableFixedIborSwapConvention.of(
	          "CAD-FIXED-6M-CDOR-3M",
	          FixedRateSwapLegConvention.of(CAD, ACT_365F, P6M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, CANADA_HOLIDAYS)),
	          IborRateSwapLegConvention.of(IborIndices.CAD_CDOR_3M));

Hope it helps

1 Like