Cannot match yield for a GOC BOND with BBG


#1

I have a security with:
issue date: 2018 August 22
Maturity date: 2028 December 15
Coupon: 2.650

private static final DiscountingFixedCouponBondProductPricer PRICER = DiscountingFixedCouponBondProductPricer.DEFAULT;
private static final ResolvedFixedCouponBond _13509PGS6 = FixedCouponBond.builder()
	      .securityId(SecurityId.of(StandardId.of("CUSIP", "13509PGS6")))
	      .dayCount(DAY_COUNT)
	      .fixedRate(2.650 * 0.01)
	      .legalEntityId(ISSUER_ID)
	      .currency(Currency.CAD)
	      .notional(NOTIONAL)
	      .accrualSchedule(PeriodicSchedule.builder()
	          .startDate(LocalDate.of(2018, Month.AUGUST, 22))
	          .endDate(LocalDate.of(2028, Month.DECEMBER, 15))
	          .frequency(Frequency.P6M)
	          .businessDayAdjustment(BUSINESS_ADJUST) // BusinessDayConventions.FOLLOWING on US calendar
	          .stubConvention(StubConvention.SHORT_INITIAL)
	          .build())
	      .settlementDateOffset(SETTLEMENT_OFFSET)
	      .yieldConvention(YIELD_CONVENTION)
	      .build()
	      .resolve(REF_DATA);

for a settlement of November 5th, 2018, I expect a yield of 2.894 (BBG) but I get 2.872 for a price of 97.878.

	LocalDate settlementDate = LocalDate.of(2018, 11, 5);
	double dirtyPrice = PRICER.dirtyPriceFromCleanPrice(_13509PGS6, settlementDate, cleanPrice/100);
	double yield = PRICER.yieldFromDirtyPrice(_13509PGS6, settlementDate, dirtyPrice)*100;

First coupon is March 15, 2018.

Whan am I missing? If I adjust the start date to be First coupon minus 6 months, I get close to BBG up to 4th decimal place - but it doesn’t really make sense since the start date would be prior to the issue date - would it?
Out of ideas - :thinking:


#2

Can’t get it to work for these securities having Short First Coupon…
Any help would be really appreciated
Thanks


#3

Got the right result by modifying this:

  private double factorToNextCoupon(ResolvedFixedCouponBond bond, LocalDate settlementDate) {
if (bond.getPeriodicPayments().get(0).getStartDate().isAfter(settlementDate)) {
  return 0d;
}
double retVal;
int couponIndex = couponIndex(bond.getPeriodicPayments(), settlementDate);
double factorSpot = accruedYearFraction(bond, settlementDate);
double factorPeriod = bond.getPeriodicPayments().get(couponIndex).getYearFraction();
LocalDate firstCouponDate = bond.getPeriodicPayments().get(0).getUnadjustedEndDate(); //first coupon period
LocalDate startQuasiPeriod = firstCouponDate.minusMonths(bond.getFrequency().get(ChronoUnit.MONTHS)); 

ScheduleInfo scheduleInfo = new ScheduleInfo() {
	@Override
	public LocalDate getStartDate() {
		// TODO Auto-generated method stub
		return startQuasiPeriod;
	}

	@Override
	public LocalDate getEndDate() {
		// TODO Auto-generated method stub
		return firstCouponDate;
	}

	@Override
	public LocalDate getPeriodEndDate(LocalDate date) {
		// TODO Auto-generated method stub
		return firstCouponDate;
	}

	@Override
	public Frequency getFrequency() {
		// TODO Auto-generated method stub
		return bond.getFrequency();
	}

	@Override
	public boolean isEndOfMonthConvention() {
		// TODO Auto-generated method stub
		return false;
	}
	
};

double quasiPeriodYearFraction = bond.getDayCount().relativeYearFraction(startQuasiPeriod, firstCouponDate, scheduleInfo); 

if (factorSpot < quasiPeriodYearFraction) {
	retVal = (factorPeriod - factorSpot) / quasiPeriodYearFraction;
}else{
	retVal = (factorPeriod - factorSpot) / factorPeriod;
}
return retVal; 

}


#4

Formally Strata does not support the price-yield formula for the Canadian bonds. Could you confirm that one of the formulas in Strata exactly matches the one you would like to use, in particular for the bond with an irregular coupon period?