Yield / Duration diff on new issue gilts vs Bloomberg

If I look at the new UKT 0.875 2029 bond on Bloomberg and price it at par for settlement 2019-06-20 I am shown a yield of 0.875020 and a modified duration of 9.864 with 1 day accrued of 23.91 per 1m face.

When I perform the same calculation in Strata I see:

  • accrued = 23.907103825136616 (which gives dirty price 1.000023907103825)
  • yield = 0.008613234902641289 (via yieldFromDirtyPrice)
  • mod duration = 10.021424652709157 (via modifiedDurationFromYield)

I wanted to check whether anything like this had been raised before before I dig into this further.

Nothing like this has come up before I’m afraid. Not sure why a new issue would be any different…

It’s almost certainly the first short stub - we’ll come back when we’ve got an explanation of the diff, thx

So based on the official DMO closing data from Tradeweb (see https://www.dmo.gov.uk/data/treasury-bills/prices-and-yields/) UKT 0.875 2029 closed at 99.3 on the 19th with ytm = 0.946254 & mod dur = 9.858415

I believe the following test added to DiscountingFixedCouponBondProductPricerTest should pass but the yield is calculated as 0.931437

  public void uktNewIssue() {
    ResolvedFixedCouponBond bond = FixedCouponBond.builder()
            .securityId(SECURITY_ID)
            .dayCount(DayCounts.ACT_ACT_ICMA)
            .fixedRate(0.00875)
            .legalEntityId(ISSUER_ID)
            .currency(GBP)
            .notional(NOTIONAL)
            .accrualSchedule(PeriodicSchedule.of(LocalDate.of(2019, 6, 19), LocalDate.of(2029, 10, 22), Frequency.P6M,
                    BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, HolidayCalendarIds.GBLO),
                    StubConvention.SMART_INITIAL, false))
            .settlementDateOffset(DaysAdjustment.ofBusinessDays(1, HolidayCalendarIds.GBLO))
            .yieldConvention(FixedCouponBondYieldConvention.GB_BUMP_DMO)
            .exCouponPeriod(DaysAdjustment.ofCalendarDays(-8,
                    BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, HolidayCalendarIds.GBLO)))
            .build()
            .resolve(REF_DATA);
    LocalDate settlement = LocalDate.of(2019, 6, 20);
    double dirtyPrice = PRICER.dirtyPriceFromCleanPrice(bond, settlement, 0.993);
    assertEquals(dirtyPrice, 0.99302391, 1e-8);
    double yield = PRICER.yieldFromDirtyPrice(bond, settlement, dirtyPrice);
    assertEquals(yield, 0.00946254, 1e-8);
    double modDur = PRICER.modifiedDurationFromYield(bond, settlement, yield);
    assertEquals(modDur, 9.858415, EPS);
  }

Thanks for the test. We’re snowed under with other work needing quant time at the moment, so I don’t expect we’ll be able to resolve this quickly. If you end up finding the problem, I’ll happily review a PR!

I’ll let you know if we do manage to pinpoint what code needs to change - I doubt I will be able to submit a PR though.

FYI there seems to be the same issue with the UKT 0.625 2025: Tradeweb closing price of 100.166 for settlement 2019-07-08 has a dirty price of 100.174538 and a yield of 0.596405 where Strata calculates 0.589425