Discount curve extrapolation with flat spread w.r.t. existing projection curve

The tutorial class has OIS rates up to 5Y and swap rates up to 30Y. As I understand, ON rates will be flat extrapolated beyond 5Y point. I tried a few ways of adding a line
final GeneratorYDCurve genAddExistFwd3 = new GeneratorCurveAddYieldExisiting(genIntLin, false, CURVE_NAME_FWD3_GBP);
in additional units to achieve outcome similar to figure 5.3 in @marc-opengamma book, such that ON rates are extrapolated with flat spread w.r.t. CURVE_NAME_FWD3_GBP curve, but with no success.
If you would be so kind to provide proposition of changes needed to the static block in lines 136-149, Any hints will be very much appreciated.


Dear OpenGamma Community,

For those, who would be interested in the solution, there should be only 1 unit:
private static final int NB_UNITS[] = new int[] {1};
//Additive generator:
final GeneratorYDCurve genAddExistFwd = new GeneratorCurveAddYieldExisiting(genIntLin, false, CURVE_NAME_FWD3_GBP);
//used in the unit:
GENERATORS_UNITS[0][0] = new GeneratorYDCurve[] {genIntLin, genAddExistFwd};
// and now important order of curves in the unit - first the curve that is known:

The problem I am facing is building s set of curves {DSC, FWD1M, FWD3M, FWD6M}, where only one is constructed by interpolation, for simplicity using:
final GeneratorYDCurve genIntLin = new GeneratorCurveYieldInterpolated(MATURITY_CALCULATOR, INTERPOLATOR_LINEAR);
and all the others are constructed as a spread. w.r.t. the curve with neighbouring period of the underlying index.
E.g. assuming, that FWD3M is generated by genIntLin, I would like to have generators:
final GeneratorYDCurve genIntCCS = CurveCalibrationConventionDataSets.generatorYDMatCcs();
final GeneratorYDCurve genAddExistFwd1M = new GeneratorCurveAddYieldExisiting(genIntCCS, false, FWD1M); //generator for the DSC curve
final GeneratorYDCurve genAddExistFwd3M = new GeneratorCurveAddYieldExisiting(genIntCCS, false, FWD3M); //generator for the FWD1M and FWD6M curves

If I put this kind of set up to one unit, it does not converge.

I am not interested in a set up like:
GENERATORS_UNITS[0][0] = new GeneratorYDCurve[] {genIntLin, genAddExistFwd3M, genAddExistFwd3M, genAddExistFwd3M};
NAMES_UNITS[0][0] = new String[] {FWD3M, DSC, FWD1M, FWD6M};

The reason for this kind of set up I am asking is that I found, that it is the only way to have meaningful forward basis between all curves. Other set up (like the one unwanted above) usually produces some poor effects in forward basis purely related to interpolation scheme, while it can be avoided by building up basis spreads one on top of the other.
Any hint how to create a working unit with such construction would be very appreciated.

To make it even more difficult, I could imagine that even I would like to have FWD3M as my “root” curve, there may be data valid only out to 30Y, while there are quotes for FWD6M available out to 50Y, so I would like to extrapolate it based on the flat spread w.r.t. FWD6M curve - as I understand I have a problem of entanglement, as construction of FWD6M curve requires a FWD3M curve and vice versa.

Thank you in advance for your support.


Dear Slusek,

The Figure 5.5 of my book what created using the code in the class “MulticurveBuildingDiscountingDiscountUSDSpreadTest” and more precisely the block 6 of curves.

The relevant lines of code are:

DEFINITIONS_UNITS[6][0] = new InstrumentDefinition<?>[][] {DEFINITIONS_FWD3_USD_3, DEFINITIONS_DSC_USD };
GeneratorYDCurve genAddExistFwd3 = new GeneratorCurveAddYieldExisiting(genIntLin, false, CURVE_NAME_FWD3_USD);
GENERATORS_UNITS[6][0] = new GeneratorYDCurve[] {genIntLin, genAddExistFwd3 };

This is similar to the part you are not interested in :frowning:

The curve generator add a linearly interpolated spread on top of the existing LIBOR3M curve. Note also that the discounting curve depends on the LIBOR curve through the spread and the LIBOR curve on the discounting by the discounting part. The two curve have to be calibrated simultaneously (not consecutively). Also in the list of curves, the LIBOR3M has to come first, if not the curve generator does not have the base curve when constructing the discounting curve as a spread.

In don’t understand exactly what you are trying to do with the 4 curves. Is is correct to say you want the 1M to be a spread to the 3M and the DSC to be a spread to 1M (and thus DSC to be a spread on a spread on 3M)?

Currently there is a limitation on the way the sensitivities are computed, the spread curves on existing curves can only be one level deep. It is not possible at this stage to have a base curve calibrated, construct another curve as a spread on that curve and then a third curve constructed as a spread on the second one. To have you example working, you would need to have curves only one level high when you “pile” the curves.

The limitation is indicated as a comment in the code but is missing in the Java doc. (see class ParameterSensitivityMulticurveUnderlyingMatrixCalculator). I will make the Java doc more explicit on this limitation.



Hi Marc,

Thank you very much for your comment. The reason I wanted to have this kind of setup was just to have one complete bundle of curves, which move all together. I have experienced nice properties of a setup, where all the basis spreads are defined as a spread between two consecutive tenors of the underlying index. At least there is smaller impact on the forward basis. It is in your book and long in other papers, (e.g. Bianchetti, Marco, Two Curves, One Price: Pricing & Hedging Interest Rate Derivatives Decoupling Forwarding and Discounting Yield Curves (November 14, 2008). Available at SSRN: or, that when interpolation is done directly on rates on each curve, then in forward rates the basis curve may behave badly.

If I want to have a set up of curves in EUR as I described, that everything is on a basis spread, wouldn’t it work if I create some iterative procedure? I know it is in contrary to your assumption, but that is what makes me feel would be a solution for my approach. I was thinking about applying a procedure as you are using for XCcy curve in MulticurveBuildingDiscountingDiscountXCcyCollatTest.
So would it work to create first discounting and 3M curve, where discounting is done as a spread on top of the 3M curve, then in the next step using those curves to construct the 1M curve using the dsc and 3M curve as knownData and a generate the curve as a spread to dsc curve and then the same for 6M, where it would be built as a spread to existing 3M.

The thing that I am curious is the case of AUD curve. in the test cases all the projection curves are build by genIntLin generators. As I understand from the book, the 6M curve should be modeled as a spread to 3M up to 3Y, beyond the 3M curve should be modeled as a spread to 6M. I guess something similar should be in case of EUR market, that there should be a switch between which curve is modeled as “rates curve” and which as a “spread curve”.

Best regards,

Hi Marc,

One more example came to my mind why one would want to build curves in iterative manner. Let’s suppose you have IRS data indexed to 6M up to 50Y, indexed to 3M up to 20Y and indexed to 1M up to 10Y. As I understand, in order to have a setup within one Unit, we would have to have all the spreads fixed to 6M curve, so in that situation the 1M6M spread would be fixed as on the 10Y tenor, while if we first have constructed a 3M6M spread and than in the second iteration we would build 1M3M spread, than the 1M6M spread would be fixed on the 20Y tenor. That could give us more flexibility if we knew, the 3M6M spread is significantly tightening on a 10Yx20Y period. I know it is just about guessing what is more correct, since we don’t have an instrument to hedge that risk, but I think that would make us less prone to overstating the forward 1M6M basis in the periods beyond 10Y.