Hi!
I try to calculate IRR for a bond with
start date: 2022-01-03
maturity date: 2025-01-03
settlement date: 2022-11-04
coupon: 2% (annual)
frequency: semiannual (Frequency.P6M)
day count: act/365 (DayCounts.ACT_365L)
clean price: 97
Using yieldFromDirtyPrice, I’ve a irr of 0.0345149172.
Using MS XIRR I’ve a irr of 0.0347078830.
Discounting cashflow with MS XIRR I got, exactly, the dirty price (97.6794520548),
Using strata irr I got 97.7180266080.
this is my code
public static void test() {
LocalDate settlementDate = LocalDate.of(2022,11, 4);
LocalDate startDate = LocalDate.of(2022,1, 3);
LocalDate maturityDate = LocalDate.of(2025,1, 3);
double couponRate = 0.02;
BusinessDayAdjustment businessDayAdj = BusinessDayAdjustment.of(
BusinessDayConventions.NO_ADJUST, HolidayCalendarIds.NO_HOLIDAYS);
PeriodicSchedule accrualSchedule = PeriodicSchedule
.builder()
.startDate(startDate)
.endDate(maturityDate)
.lastRegularEndDate(maturityDate)
.businessDayAdjustment(businessDayAdj)
.frequency(Frequency.P6M)
.stubConvention(StubConvention.NONE)
.rollConvention(RollConventions.EOM)
.build();
FixedCouponBond fcb = FixedCouponBond
.builder()
.accrualSchedule(accrualSchedule)
.currency(Currency.EUR)
.securityId(SecurityId.of("CUSIP", "135087WL4"))
.notional(100.)
.fixedRate(couponRate)
.dayCount(DayCounts.ACT_365L)
.yieldConvention(FixedCouponBondYieldConvention.DE_BONDS)
.legalEntityId(LegalEntityId.of("LegalEntity", "DUMMY"))
.settlementDateOffset(DaysAdjustment.ofBusinessDays(3, HolidayCalendarIds.CATO))
.build();
ResolvedFixedCouponBond resolvedBond = fcb.resolve(ReferenceData.standard());
double cleanPrice = 97 / 100.;
double dirtyPrice = DiscountingFixedCouponBondProductPricer.DEFAULT.dirtyPriceFromCleanPrice(resolvedBond, settlementDate,cleanPrice);
double accrual = DiscountingFixedCouponBondProductPricer.DEFAULT.accruedInterest(resolvedBond, settlementDate);
double yield = DiscountingFixedCouponBondProductPricer.DEFAULT.yieldFromDirtyPrice(resolvedBond, settlementDate, dirtyPrice);
double calculatedDirty = DiscountingFixedCouponBondProductPricer.DEFAULT.dirtyPriceFromYield(resolvedBond, settlementDate, yield);
double macaulayDuration = DiscountingFixedCouponBondProductPricer.DEFAULT.macaulayDurationFromYield(resolvedBond, settlementDate, yield);
double modifiedDuration = DiscountingFixedCouponBondProductPricer.DEFAULT.modifiedDurationFromYield(resolvedBond, settlementDate, yield);
System.out.println("yield: " + yield);
System.out.println("dirty: " + dirtyPrice);
System.out.println("calculatedDirty: " + calculatedDirty);
System.out.println("macaulayDuration: " + macaulayDuration);
System.out.println("modifiedDuration: " + modifiedDuration);
System.out.println("accrual: " + accrual);
System.out.println("accrual days: " + DiscountingFixedCouponBondProductPricer.DEFAULT.accruedYearFraction(resolvedBond, settlementDate) * 365.);
}
What it’s wrong?