Fixbond yield calculation

Hello,

The root finding fails in the following yield calculation:

import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.StandardId;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.Payment;
import com.opengamma.strata.basics.date.*;
import com.opengamma.strata.basics.schedule.*;
import com.opengamma.strata.pricer.bond.DiscountingFixedCouponBondProductPricer;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.bond.FixedCouponBond;
import com.opengamma.strata.product.bond.FixedCouponBondYieldConvention;
import com.opengamma.strata.product.bond.ResolvedFixedCouponBond;

import java.time.LocalDate;
import java.util.HashMap;

import static com.opengamma.strata.product.SecurityId.of;
import static com.opengamma.strata.product.bond.FixedCouponBondYieldConvention.DE_BONDS;


public class Example {

    
    public static final void bondYield(){

        // set up the bond
        SecurityId wkn = SecurityId.of(StandardId.of("UTF-8","111111"));
        StandardId legalEntityID = StandardId.of("UTF-8","Borrowers United");
        // build the periodic schedule of bond payments
        LocalDate startDate = LocalDate.of(2015,10,13);
        LocalDate endDate = LocalDate.of(2020,10,13);
        HolidayCalendar holCal = HolidayCalendars.SAT_SUN;
        BusinessDayConvention bdc = BusinessDayConventions.FOLLOWING;
        BusinessDayAdjustment bdAdj = BusinessDayAdjustment.of(bdc,holCal.getId());
        Frequency frequency = Frequency.P12M;
        StubConvention stubConvention = StubConvention.NONE;
        RollConvention rollConvention = RollConventions.DAY_13;
        PeriodicSchedule accrualSchedule = PeriodicSchedule.builder()
                .startDate(startDate)
                .endDate(endDate)
                .businessDayAdjustment(bdAdj)
                .frequency(frequency)
                .stubConvention(stubConvention)
                .rollConvention(rollConvention)
                .build();

        // days adjustment for settlement date offset
        DaysAdjustment settlementDateOffset = DaysAdjustment.ofBusinessDays(2,holCal.getId());

        // get a bond builder
        FixedCouponBond.Builder bondBuilder = FixedCouponBond.builder();
        // set the bond attributes
        bondBuilder.securityId(wkn)
                   .legalEntityId(legalEntityID)
                   .yieldConvention(FixedCouponBondYieldConvention.DE_BONDS)
                   .accrualSchedule(accrualSchedule)
                   .fixedRate(0.01)
                   .notional(100.0)
                   .settlementDateOffset(settlementDateOffset)
                   .dayCount(DayCounts.ACT_ACT_ICMA)
                   .currency(Currency.EUR)
        ;
        FixedCouponBond theBond = bondBuilder.build();

        // Turn the bond into a resolved bond via the required ReferenceData.
        ReferenceData refDataStandard = ReferenceData.standard();
        ResolvedFixedCouponBond resolvedBond = theBond.resolve(refDataStandard);

        // get the bond pricer
        DiscountingFixedCouponBondProductPricer pricer = DiscountingFixedCouponBondProductPricer.DEFAULT;
       
        // yield from dirty price of 98 at settlement date 2016-01-01
        LocalDate settlementDate = LocalDate.of(2016,1,1);
        Double dirtyPrice = 98.0;
        Double yield = pricer.yieldFromDirtyPrice(resolvedBond,settlementDate,dirtyPrice);
        String msg = "Yield at dirty price of "+dirtyPrice+" settled on "+settlementDate+" is: "+yield;
        System.out.println(msg);
    }

}

Hi,
Have you tried with :

Double dirtyPrice = 0.98;

Best.

OK. Thanks this works.

Yes, as per the docs, we use decimal prices:

* <h4>Price</h4>
* Strata uses <i>decimal prices</i> for bonds in the trade model, pricers and market data.
* For example, a price of 99.32% is represented in Strata by 0.9932.

Thanks for the beautiful library.
It’s a pleasure to use.

I ran into another problem with the root finder. it is supposed to be a zero coupon bond.
Is it OK if I post such code here?

import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.StandardId;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.currency.Payment;
import com.opengamma.strata.basics.date.*;
import com.opengamma.strata.basics.schedule.*;
import com.opengamma.strata.pricer.bond.DiscountingFixedCouponBondProductPricer;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.bond.FixedCouponBond;
import com.opengamma.strata.product.bond.FixedCouponBondYieldConvention;
import com.opengamma.strata.product.bond.ResolvedFixedCouponBond;

import java.time.LocalDate;
import java.util.HashMap;

import static com.opengamma.strata.product.SecurityId.of;
import static com.opengamma.strata.product.bond.FixedCouponBondYieldConvention.DE_BONDS;

/**
 * Created by vagrant on 15.02.17.
 */
public class Examples {

    public static final void yieldExample(){

        SecurityId wkn = SecurityId.of(StandardId.of("UTF-8","111111"));
        StandardId legalEntityID = StandardId.of("UTF-8","Borrowers United");

        LocalDate startDate = LocalDate.of(2016,6,21);
        LocalDate endDate = LocalDate.of(2017,4,7);
        HolidayCalendar holCal = HolidayCalendars.SAT_SUN;
        BusinessDayConvention bdc = BusinessDayConventions.FOLLOWING;
        BusinessDayAdjustment bdAdj = BusinessDayAdjustment.of(bdc,holCal.getId());
        Frequency frequency = Frequency.TERM;
        StubConvention stubConvention = StubConvention.NONE;
        RollConvention rollConvention = RollConventions.NONE;
        PeriodicSchedule accrualSchedule = PeriodicSchedule.builder()
                .startDate(startDate)
                .endDate(endDate)
                .businessDayAdjustment(bdAdj)
                .frequency(frequency)
                .stubConvention(stubConvention)
                .rollConvention(rollConvention)
                .build();


        DaysAdjustment settlementDateOffset = DaysAdjustment.ofBusinessDays(2,holCal.getId());

        FixedCouponBond.Builder bondBuilder = FixedCouponBond.builder();
        bondBuilder.securityId(wkn)
                   .legalEntityId(legalEntityID)
                   .yieldConvention(FixedCouponBondYieldConvention.DE_BONDS)
                   .accrualSchedule(accrualSchedule)
                   .fixedRate(0.01)
                   .notional(1.0)
                   .settlementDateOffset(settlementDateOffset)
                   .dayCount(DayCounts.ACT_ACT_ICMA)
                   .currency(Currency.EUR)
        ;
        FixedCouponBond theBond = bondBuilder.build();
        ReferenceData refDataStandard = ReferenceData.standard();
        ResolvedFixedCouponBond resolvedBond = theBond.resolve(refDataStandard);

        DiscountingFixedCouponBondProductPricer pricer = DiscountingFixedCouponBondProductPricer.DEFAULT;

        LocalDate settlementDate = LocalDate.of(2016,10,21);
        Double dirtyPrice = 0.98;
        Double yield = pricer.yieldFromDirtyPrice(resolvedBond,settlementDate,dirtyPrice);
        String msg = "Yield at dirty price of "+dirtyPrice+" settled on "+settlementDate+" is: "+yield;
        System.out.println(msg);
    }


}

From my experience DayCounts.ACT_ACT_ICMA is incompatible with Frequency.TERM but the problem persists with other day counts.

After reading the Opengamma document on bond pricing it seems to me that no root bracketing is needed, if the yield is computed for a settlement date in the last period.
In case of yield conventions US_STRRET or DE_BONDS the same is true if the settlement date is in the second to last period.
In this case simple algebraic equations have to be solved yielding exact solutions.

As of now, Strata does not properly support zero coupon bonds, as they have subtly different conventions and rules. As might be imagined, you may be able to tweak FixedCouponBond to come close, see also this thread.

We do not currently have Zero Coupon bonds on our roadmap, but feel free to contact us directly if it is of commercial interest.