IborFutureCurveNode vs IborFixingDepositCurveNode

According to Bloomberg the INT_RATE_FUT_END_DT value for EDGF17 is 2017-04-18 and EDG17 is 2017-05-17 however the following test case seems to suggest that Strata thinks the second date is 2017-05-15 which leads to the situation where you cannot fit a USD 3M curve as of 2017-02-09 with both 3M LIBOR and EDG17 in the curve.

@Test
public void testCurveNodes() {
    final LocalDate valuationDate = LocalDate.of(2017, 2, 9);
    final ReferenceData referenceData = ReferenceData.standard();

    final IborFixingDepositCurveNode fixing = IborFixingDepositCurveNode.of(
            IborFixingDepositTemplate.of(IborIndices.USD_LIBOR_3M),
            QuoteId.of(StandardId.of("Bloomberg-Ticker", "US0003 Index"), FieldName.of("VALUE"))
    );
    final IborFutureCurveNode edf7 = IborFutureCurveNode.of(
            IborFutureTemplate.of(YearMonth.of(2017, 1), ImmutableIborFutureConvention.of(IborIndices.USD_LIBOR_3M, DateSequences.MONTHLY_IMM)),
            QuoteId.of(StandardId.of("Bloomberg-Ticker", "EDF17 Index"), FieldName.of("MID"))
    );
    final IborFutureCurveNode edg7 = IborFutureCurveNode.of(
            IborFutureTemplate.of(YearMonth.of(2017, 2), ImmutableIborFutureConvention.of(IborIndices.USD_LIBOR_3M, DateSequences.MONTHLY_IMM)),
            QuoteId.of(StandardId.of("Bloomberg-Ticker", "EDG17 Index"), FieldName.of("MID"))
    );

    assertEquals(LocalDate.of(2017, 5, 15), fixing.date(valuationDate, referenceData));
    assertEquals(LocalDate.of(2017, 4, 18), edf7.date(valuationDate, referenceData));
    assertEquals(LocalDate.of(2017, 5, 17), edg7.date(valuationDate, referenceData));
}

Is this expected behavior? e.g.
fixing.date(LocalDate.of(2017, 2, 15), referenceData) returns 2017-05-17
but
IborIndices.USD_LIBOR_3M.calculateMaturityFromEffective(LocalDate.of(2017, 2, 15), referenceData) returns 2017-05-15

When two nodes result in the same date it is possible to drop one of them automatically. Use CurveNodeDateOrder.of(1, CurveNodeClashAction.DROP_OTHER) on the node you want keep.

The IborFixingDepositCurveNode starts at 2017-02-09. Add 2 days and adjust over a weekend to get the effective date of 2017-02-13. Add three months to get 2017-05-13, and adjust that over a weekend to get 2017-05-15.

The IborFutureCurveNode starts at 3rd Wednesday 2017-02-15, and adds three months to get 2017-05-15.

I don’t see how the code would result in 2017-05-17.

Hi Stephen,

According to Bloomberg the dates for each future are as follows

           INT_RATE_FUT_START_DT  INT_RATE_FUT_END_DT
    EDF17  18/01/2017             18/04/2017
    EDG17  15/02/2017             17/05/2017
    EDH17  15/03/2017             21/06/2017
    EDJ17  18/04/2017             19/07/2017
    EDK17  17/05/2017             16/08/2017
    EDM17  21/06/2017             20/09/2017
    EDN17  19/07/2017             18/10/2017
    EDQ17  16/08/2017             15/11/2017
    EDU17  20/09/2017             20/12/2017
    EDV17  18/10/2017             17/01/2018
    EDX17  15/11/2017             21/02/2018
    EDZ17  20/12/2017             21/03/2018
    EDF18  17/01/2018             18/04/2018
    EDG18  21/02/2018             16/05/2018
    EDH18  21/03/2018             20/06/2018
    EDJ18  18/04/2018             18/07/2018
    EDK18  16/05/2018             15/08/2018
    EDM18  20/06/2018             19/09/2018
    EDN18  18/07/2018             17/10/2018
    EDQ18  15/08/2018             21/11/2018
    EDU18  19/09/2018             19/12/2018
    EDV18  17/10/2018             16/01/2019
    EDX18  21/11/2018             20/02/2019
    EDZ18  19/12/2018             20/03/2019

I am querying with Bloomberg what the end dates actually represent, it seems that all except EDF17 are just set to the IMM date 3m forward.

I spent some time thinking about this, my understanding of a curve clash is when you have two nodes which should tell you the same thing (but due to liquidity or fixing lag or whatever may not so it’s safest to drop one). The way I think about the front eurodollar future and the 3m libor fixing is that they are telling me the same thing 2 days prior to the IMM date, and for GBP on the IMM date due to T+2 vs T+0 settlement convention.

2017-02-09 is the Thursday before the IMM date so I don’t see why there should be a curve clash then - I would expect one on 2017-02-13.

I guess my follow up question is whether you agree with that premise around clashes, and if so how can it be
resolved?

As can be seen in my last reply, the date chosen for the curve is the END date, not the effective date, (see CurveNodeDate.calculate). Both the input dates result in 2017-05-15.

To avoid date clashes, simply create one of the two nodes (typically the future) with the action that is to occur if it results in a clash. This is achieved by passing in CurveNodeDateOrder via the builder of the curve node with CurveNodeClashAction.DROP_OTHER or CurveNodeClashAction.DROP_THIS.

I understand what the code is doing, I just think it’s wrong… For the record, Strata cannot fit a USD LIBOR 3M curve with the front future EDG17 on the curve for valuation date 2017-02-09 when that future’s last trading date is 2017-02-13. Typically trading desks would expect the future to drop out on 2017-02-10.
This may not have come up before as it’s not one of the IMM contracts and 2017-02-09 is the only day this occurs in the 18months I am testing.