/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate.bond.provider; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.util.Set; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZonedDateTime; import org.threeten.bp.temporal.JulianFields; import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition; import com.opengamma.analytics.financial.instrument.payment.CouponFixedDefinition; import com.opengamma.analytics.financial.interestrate.annuity.derivative.AnnuityCouponFixed; import com.opengamma.analytics.financial.interestrate.annuity.derivative.AnnuityPaymentFixed; import com.opengamma.analytics.financial.interestrate.bond.calculator.CleanPriceFromYieldCalculator; import com.opengamma.analytics.financial.interestrate.bond.calculator.DirtyPriceFromYieldCalculator; import com.opengamma.analytics.financial.interestrate.bond.calculator.MacaulayDurationFromYieldCalculator; import com.opengamma.analytics.financial.interestrate.bond.calculator.ModifiedDurationFromCleanPriceCalculator; import com.opengamma.analytics.financial.interestrate.bond.calculator.ModifiedDurationFromYieldCalculator; import com.opengamma.analytics.financial.interestrate.bond.calculator.YieldFromCleanPriceCalculator; import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedSecurity; import com.opengamma.analytics.financial.legalentity.CreditRating; import com.opengamma.analytics.financial.legalentity.LegalEntity; import com.opengamma.analytics.financial.legalentity.LegalEntityFilter; import com.opengamma.analytics.financial.legalentity.LegalEntityShortName; import com.opengamma.analytics.financial.legalentity.Region; import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve; import com.opengamma.analytics.financial.model.interestrate.curve.YieldPeriodicCurve; import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.CleanPriceFromCurvesCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.ConvexityFromCurvesCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.DirtyPriceFromCurvesCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.MacaulayDurationFromCurvesCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.ModifiedDurationFromCurvesCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.PresentValueIssuerCalculator; import com.opengamma.analytics.financial.provider.calculator.issuer.YieldFromCurvesCalculator; import com.opengamma.analytics.financial.provider.description.IssuerProviderDiscountDataSets; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderInterface; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderIssuerDecoratedSpreadContinuous; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderIssuerDecoratedSpreadPeriodic; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscountingDecoratedIssuer; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity; import com.opengamma.analytics.financial.schedule.ScheduleCalculator; import com.opengamma.analytics.financial.util.AssertSensitivityObjects; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.util.time.TimeCalculator; import com.opengamma.financial.convention.businessday.BusinessDayConvention; import com.opengamma.financial.convention.businessday.BusinessDayConventions; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.financial.convention.calendar.MondayToFridayCalendar; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCounts; import com.opengamma.financial.convention.yield.YieldConvention; import com.opengamma.financial.convention.yield.YieldConventionFactory; import com.opengamma.util.i18n.Country; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; import com.opengamma.util.tuple.Pairs; /** * Tests related to the discounting method for bond security. */ @Test(groups = TestGroup.UNIT) public class BondSecurityDiscountingMethodTest { /** Curves for a specific issuer name */ private static final IssuerProviderDiscount ISSUER_SPECIFIC_MULTICURVES = IssuerProviderDiscountDataSets.getIssuerSpecificProvider(); /** Curves for a specific country */ private static final IssuerProviderDiscount COUNTRY_SPECIFIC_MULTICURVES = IssuerProviderDiscountDataSets.getCountrySpecificProvider(); /** Curves for a specific currency */ private static final IssuerProviderDiscount CURRENCY_SPECIFIC_MULTICURVES = IssuerProviderDiscountDataSets.getCurrencySpecificProvider(); /** Curves for a specific rating */ private static final IssuerProviderDiscount COUNTRY_RATING_SPECIFIC_MULTICURVES = IssuerProviderDiscountDataSets.getCountryRatingSpecificProvider(); /** The issuer names from the provider */ private static final String[] ISSUER_NAMES = IssuerProviderDiscountDataSets.getIssuerNames(); // T 4 5/8 11/15/16 - ISIN - US912828FY19 /** The issuer name */ private static final String ISSUER_NAME = ISSUER_NAMES[0]; /** The credit ratings */ private static final Set<CreditRating> CREDIT_RATINGS = IssuerProviderDiscountDataSets.getIssuers()[0].getCreditRatings(); /** The legal entity */ private static final LegalEntity ISSUER = new LegalEntity(null, ISSUER_NAME, CREDIT_RATINGS, null, Region.of("United States", Country.US, Currency.USD)); private static final Currency CUR = Currency.USD; private static final Calendar CALENDAR = new MondayToFridayCalendar("A"); private static final Period PAYMENT_TENOR_FIXED = Period.ofMonths(6); private static final int COUPON_PER_YEAR = 2; private static final DayCount DAY_COUNT_FIXED = DayCounts.ACT_ACT_ICMA; private static final BusinessDayConvention BUSINESS_DAY_FIXED = BusinessDayConventions.FOLLOWING; private static final boolean IS_EOM_FIXED = false; private static final Period BOND_TENOR_FIXED = Period.ofYears(10); private static final int SETTLEMENT_DAYS = 3; private static final ZonedDateTime START_ACCRUAL_DATE_FIXED = DateUtils.getUTCDate(2006, 11, 15); private static final ZonedDateTime MATURITY_DATE_FIXED = START_ACCRUAL_DATE_FIXED.plus(BOND_TENOR_FIXED); private static final double RATE_FIXED = 0.04625; private static final double NOTIONAL = 100; private static final YieldConvention YIELD_CONVENTION_FIXED = YieldConventionFactory.INSTANCE.getYieldConvention("STREET CONVENTION"); /** Bond security definition with an entity containing only a short name */ private static final BondFixedSecurityDefinition BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY = BondFixedSecurityDefinition.from(CUR, MATURITY_DATE_FIXED, START_ACCRUAL_DATE_FIXED, PAYMENT_TENOR_FIXED, RATE_FIXED, SETTLEMENT_DAYS, NOTIONAL, CALENDAR, DAY_COUNT_FIXED, BUSINESS_DAY_FIXED, YIELD_CONVENTION_FIXED, IS_EOM_FIXED, ISSUER_NAME, "RepoType"); /** Bond security definition with a full legal entity */ private static final BondFixedSecurityDefinition BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY = BondFixedSecurityDefinition.from(CUR, MATURITY_DATE_FIXED, START_ACCRUAL_DATE_FIXED, PAYMENT_TENOR_FIXED, RATE_FIXED, SETTLEMENT_DAYS, NOTIONAL, CALENDAR, DAY_COUNT_FIXED, BUSINESS_DAY_FIXED, YIELD_CONVENTION_FIXED, IS_EOM_FIXED, ISSUER, "RepoType"); // To derivatives // Spot: middle coupon /** A reference date in between coupons */ private static final ZonedDateTime REFERENCE_DATE_1 = DateUtils.getUTCDate(2011, 8, 18); /** The first spot date */ private static final ZonedDateTime SPOT_1 = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE_1, SETTLEMENT_DAYS, CALENDAR); /** The time to the first reference date */ private static final double REFERENCE_TIME_1 = TimeCalculator.getTimeBetween(REFERENCE_DATE_1, SPOT_1); /** Bond security with no entity created on the first reference date */ private static final BondFixedSecurity BOND_FIXED_SECURITY_NO_ENTITY_1 = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.toDerivative(REFERENCE_DATE_1); /** Bond security with full entity created on the first reference date */ private static final BondFixedSecurity BOND_FIXED_SECURITY_FULL_ENTITY_1 = BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.toDerivative(REFERENCE_DATE_1); // Spot: on coupon date private static final ZonedDateTime REFERENCE_DATE_2 = DateUtils.getUTCDate(2012, 1, 10); private static final ZonedDateTime SPOT_2 = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE_2, SETTLEMENT_DAYS, CALENDAR); private static final double REFERENCE_TIME_2 = TimeCalculator.getTimeBetween(REFERENCE_DATE_2, SPOT_2); private static final BondFixedSecurity BOND_FIXED_SECURITY_2 = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.toDerivative(REFERENCE_DATE_2); // Calculators private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance(); private static final PresentValueIssuerCalculator PVIC = PresentValueIssuerCalculator.getInstance(); private static final BondSecurityDiscountingMethod METHOD_BOND_SECURITY = BondSecurityDiscountingMethod.getInstance(); private static final YieldFromCurvesCalculator YFCC = YieldFromCurvesCalculator.getInstance(); private static final YieldFromCleanPriceCalculator YFPC = YieldFromCleanPriceCalculator.getInstance(); private static final ModifiedDurationFromCurvesCalculator MDFC = ModifiedDurationFromCurvesCalculator.getInstance(); private static final ModifiedDurationFromCleanPriceCalculator MDFP = ModifiedDurationFromCleanPriceCalculator.getInstance(); private static final ModifiedDurationFromYieldCalculator MDFY = ModifiedDurationFromYieldCalculator.getInstance(); private static final MacaulayDurationFromCurvesCalculator McDFC = MacaulayDurationFromCurvesCalculator.getInstance(); private static final MacaulayDurationFromYieldCalculator McDFY = MacaulayDurationFromYieldCalculator.getInstance(); private static final DirtyPriceFromYieldCalculator DPFY = DirtyPriceFromYieldCalculator.getInstance(); private static final DirtyPriceFromCurvesCalculator DPFC = DirtyPriceFromCurvesCalculator.getInstance(); private static final ConvexityFromCurvesCalculator CFC = ConvexityFromCurvesCalculator.getInstance(); private static final CleanPriceFromYieldCalculator CPFY = CleanPriceFromYieldCalculator.getInstance(); private static final CleanPriceFromCurvesCalculator CPFC = CleanPriceFromCurvesCalculator.getInstance(); private static final double TOLERANCE_PV = 1.0E-8; private static final double TOLERANCE_PV_DELTA = 1.0E-4; private static final double TOLERANCE_PRICE = 1.0E-8; private static final double TOLERANCE_YIELD = 1.0E-8; private static final double TOLERANCE_CONV = 1.0E-8; private static final double TOLERANCE_CONV_FD = 1.0E-5; /** * Tests the present value of a bond at a time in between coupons. The legal entity contains only the short name * and the curve bundle contains issuer-specific curves. */ @Test public void presentValueFixedMiddleIssuer() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getNominal().toDerivative(REFERENCE_DATE_1); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_1); coupon = coupon.trimBefore(REFERENCE_TIME_1); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(ISSUER_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } /** * Tests the present value of a bond at a time in between coupons. The legal entity contains only the short name * and the curve bundle contains issuer-specific curves. */ @Test public void presentValueFixedMiddleShortName() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getNominal().toDerivative(REFERENCE_DATE_1); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_1); coupon = coupon.trimBefore(REFERENCE_TIME_1); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(ISSUER_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } /** * Tests the present value of a bond at a time in between coupons. The curve bundle contains country-specific curves. */ @Test public void presentValueFixedMiddleCountry() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getNominal().toDerivative(REFERENCE_DATE_1); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_1); coupon = coupon.trimBefore(REFERENCE_TIME_1); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(COUNTRY_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, COUNTRY_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } /** * Tests the present value of a bond at a time in between coupons. The curve bundle contains currency-specific curves. */ @Test public void presentValueFixedMiddleCurrency() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getNominal().toDerivative(REFERENCE_DATE_1); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_1); coupon = coupon.trimBefore(REFERENCE_TIME_1); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(CURRENCY_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, CURRENCY_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } /** * Tests the present value of a bond at a time in between coupons. The curve bundle contains currency-specific curves. */ @Test public void presentValueFixedMiddleCountryRating() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getNominal().toDerivative(REFERENCE_DATE_1); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_FULL_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_1); coupon = coupon.trimBefore(REFERENCE_TIME_1); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(COUNTRY_RATING_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, COUNTRY_RATING_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } @Test public void presentValueFixedOnCoupon() { final AnnuityPaymentFixed nominal = (AnnuityPaymentFixed) BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getNominal().toDerivative(REFERENCE_DATE_2); AnnuityCouponFixed coupon = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.getCoupons().toDerivative(REFERENCE_DATE_2); coupon = coupon.trimBefore(REFERENCE_TIME_2); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(ISSUER_SPECIFIC_MULTICURVES, CUR, ISSUER); final MultipleCurrencyAmount pvNominal = nominal.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pvCoupon = coupon.accept(PVDC, multicurvesDecorated); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_2, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvNominal.getAmount(CUR) + pvCoupon.getAmount(CUR), pv.getAmount(CUR), TOLERANCE_PV); } @Test public void presentValueFixedMethodVsCalculator() { final MultipleCurrencyAmount pvMethod = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final MultipleCurrencyAmount pvCalculator = BOND_FIXED_SECURITY_NO_ENTITY_1.accept(PVIC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value Method vs Calculator", pvMethod.getAmount(CUR), pvCalculator.getAmount(CUR), TOLERANCE_PV); } @Test /** * Tests the present value from curves and a z-spread. */ public void presentValueFromZSpread() { final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); double zSpread = 0.0; MultipleCurrencyAmount pvZ = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); assertEquals("Fixed coupon bond security: present value from z-spread", pv.getAmount(CUR), pvZ.getAmount(CUR), TOLERANCE_PV); IssuerProviderInterface issuerShifted = new IssuerProviderIssuerDecoratedSpreadContinuous( ISSUER_SPECIFIC_MULTICURVES, BOND_FIXED_SECURITY_NO_ENTITY_1.getIssuerEntity(), zSpread); MultipleCurrencyAmount pvZExpected = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, issuerShifted); assertEquals("Fixed coupon bond security: present value from z-spread", pvZExpected.getAmount(CUR), pvZ.getAmount(CUR), TOLERANCE_PV); zSpread = 0.0010; // 10bps issuerShifted = new IssuerProviderIssuerDecoratedSpreadContinuous(ISSUER_SPECIFIC_MULTICURVES, BOND_FIXED_SECURITY_NO_ENTITY_1.getIssuerEntity(), zSpread); pvZ = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); pvZExpected = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, issuerShifted); assertEquals("Fixed coupon bond security: present value from z-spread", pvZExpected.getAmount(CUR), pvZ.getAmount(CUR), TOLERANCE_PV); } @Test /** * Tests the present value z-spread sensitivity. */ public void presentValueZSpreadSensitivity() { final double zSpread = 0.0050; // 50bps final double shift = 1.0E-5; final double pvzs = METHOD_BOND_SECURITY.presentValueZSpreadSensitivity(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); final MultipleCurrencyAmount pvZUp = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread + shift); final MultipleCurrencyAmount pvZDown = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread - shift); assertEquals("Fixed coupon bond security: present value z-spread sensitivity", (pvZUp.getAmount(CUR) - pvZDown.getAmount(CUR)) / (2 * shift), pvzs, TOLERANCE_PV_DELTA); } @Test /** * Tests the bond security present value from clean price. */ public void presentValueFromCleanPrice() { final double cleanPrice = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final MultipleCurrencyAmount pvClean = METHOD_BOND_SECURITY.presentValueFromCleanPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider(), cleanPrice); final MultipleCurrencyAmount pvCleanExpected = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: present value", pvCleanExpected.getAmount(CUR), pvClean.getAmount(CUR), TOLERANCE_PV); } @Test /** * Tests the z-spread computation from the present value. */ public void zSpreadFromPresentValue() { final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double zSpread = METHOD_BOND_SECURITY.zSpreadFromCurvesAndPV(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, pv); assertEquals("Fixed coupon bond security: present value from z-spread", 0.0, zSpread, TOLERANCE_PV); final double zSpreadExpected = 0.0025; // 25bps final MultipleCurrencyAmount pvZSpread = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpreadExpected); final double zSpread2 = METHOD_BOND_SECURITY.zSpreadFromCurvesAndPV(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, pvZSpread); assertEquals("Fixed coupon bond security: present value from z-spread", zSpreadExpected, zSpread2, TOLERANCE_PV); final double zSpreadExpected3 = 0.0250; // 2.50% final MultipleCurrencyAmount pvZSpread3 = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpreadExpected3); final double zSpread3 = METHOD_BOND_SECURITY.zSpreadFromCurvesAndPV(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, pvZSpread3); assertEquals("Fixed coupon bond security: present value from z-spread", zSpreadExpected3, zSpread3, TOLERANCE_PV); } @Test /** * Tests the z-spread sensitivity computation from the present value. */ public void zSpreadSensitivityFromPresentValue() { final double zSpread = 0.0025; // 25bps final MultipleCurrencyAmount pvZSpread = METHOD_BOND_SECURITY.presentValueFromZSpread(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); final double zsComputed = METHOD_BOND_SECURITY.presentValueZSpreadSensitivityFromCurvesAndPV(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, pvZSpread); final double zsExpected = METHOD_BOND_SECURITY.presentValueZSpreadSensitivity(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); assertEquals("Fixed coupon bond security: z-spread sensitivity", zsExpected, zsComputed, TOLERANCE_PV); } @Test /** * Tests the z-spread computation from the clean price. */ public void zSpreadFromCleanPrice() { final double zSpreadExpected = 0.0025; // 25bps final IssuerProviderInterface issuerShifted = new IssuerProviderIssuerDecoratedSpreadContinuous( ISSUER_SPECIFIC_MULTICURVES, BOND_FIXED_SECURITY_NO_ENTITY_1.getIssuerEntity(), zSpreadExpected); final double cleanZSpread = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, issuerShifted); final double zSpread = METHOD_BOND_SECURITY.zSpreadFromCurvesAndClean(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, cleanZSpread); assertEquals("Fixed coupon bond security: present value from z-spread", zSpreadExpected, zSpread, TOLERANCE_PV); } @Test /** * Tests the z-spread sensitivity computation from the present value. */ public void zSpreadSensitivityFromCleanPrice() { final double zSpread = 0.0025; // 25bps final IssuerProviderInterface issuerShifted = new IssuerProviderIssuerDecoratedSpreadContinuous( ISSUER_SPECIFIC_MULTICURVES, BOND_FIXED_SECURITY_NO_ENTITY_1.getIssuerEntity(), zSpread); final double cleanZSpread = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, issuerShifted); final double zsComputed = METHOD_BOND_SECURITY.presentValueZSpreadSensitivityFromCurvesAndClean(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, cleanZSpread); final double zsExpected = METHOD_BOND_SECURITY.presentValueZSpreadSensitivity(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES, zSpread); assertEquals("Fixed coupon bond security: z-spread sensitivity", zsExpected, zsComputed, TOLERANCE_PV); } @Test public void dirtyPriceFixed() { final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getDiscountFactor(CUR, REFERENCE_TIME_1); final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: dirty price from curves", pv.getAmount(CUR) / df / BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getNotional(), dirty); assertTrue("Fixed coupon bond security: dirty price is relative price", (0.50 < dirty) & (dirty < 2.0)); } @Test public void cleanPriceFixed() { final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double clean = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: clean price from curves", dirty - BOND_FIXED_SECURITY_NO_ENTITY_1.getAccruedInterest() / BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getNotional(), clean); } @Test public void cleanAndDirtyPriceFixed() { final double cleanPrice = 0.90; final double accruedInterest = BOND_FIXED_SECURITY_NO_ENTITY_1.getAccruedInterest() / BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getNotional(); assertEquals("Fixed coupon bond security", cleanPrice + accruedInterest, METHOD_BOND_SECURITY.dirtyPriceFromCleanPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, cleanPrice)); final double dirtyPrice = 0.95; assertEquals("Fixed coupon bond security", dirtyPrice - accruedInterest, METHOD_BOND_SECURITY.cleanPriceFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice)); assertEquals("Fixed coupon bond security", cleanPrice, METHOD_BOND_SECURITY.cleanPriceFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, METHOD_BOND_SECURITY.dirtyPriceFromCleanPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, cleanPrice))); } @Test public void dirtyPriceFromYieldUSStreet() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double dirtyPriceExpected = 1.04173525; // To be check with another source. assertEquals("Fixed coupon bond security: dirty price from yield", dirtyPriceExpected, dirtyPrice, TOLERANCE_PRICE); } @Test public void cleanPriceFromYieldUSStreet() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double cleanPriceExpected = METHOD_BOND_SECURITY.cleanPriceFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double cleanPrice = METHOD_BOND_SECURITY.cleanPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); assertEquals("Fixed coupon bond security: dirty price from yield", cleanPriceExpected, cleanPrice, TOLERANCE_PRICE); } @Test public void dirtyPriceFromYieldUSStreetLastPeriod() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2016, 6, 3); // In last period final BondFixedSecurity bondSecurity = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.toDerivative(referenceDate); final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(bondSecurity, yield); final double dirtyPriceExpected = (1 + RATE_FIXED / COUPON_PER_YEAR) / (1 + bondSecurity.getFactorToNextCoupon() * yield / COUPON_PER_YEAR); assertEquals("Fixed coupon bond security: dirty price from yield US Street - last period", dirtyPriceExpected, dirtyPrice, TOLERANCE_PRICE); } @Test public void yieldFromDirtyPriceUSStreet() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double yieldComputed = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); assertEquals("Fixed coupon bond security: yield from dirty price", yield, yieldComputed, TOLERANCE_YIELD); } @Test public void yieldFromCurvesUSStreet() { final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double yieldExpected = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double yieldComputed = METHOD_BOND_SECURITY.yieldFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: yield from dirty price", yieldExpected, yieldComputed, TOLERANCE_YIELD); } @Test public void yieldFromCleanPriceUSStreet() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double cleanPrice = METHOD_BOND_SECURITY.cleanPriceFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double yieldComputed = METHOD_BOND_SECURITY.yieldFromCleanPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, cleanPrice); assertEquals("Fixed coupon bond security: yield from clean price", yield, yieldComputed, TOLERANCE_YIELD); final double cleanPrice2 = METHOD_BOND_SECURITY.cleanPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yieldComputed); assertEquals("Fixed coupon bond security: yield from clean price", cleanPrice, cleanPrice2, TOLERANCE_YIELD); } @Test public void modifiedDurationFromYieldUSStreet() { final double yield = 0.04; final double modifiedDuration = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double modifiedDurationExpected = 4.566199225; // To be check with another source. assertEquals("Fixed coupon bond security: modified duration from yield US Street - hard coded value", modifiedDurationExpected, modifiedDuration, TOLERANCE_PRICE); final double shift = 1.0E-6; final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double dirtyP = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield + shift); final double dirtyM = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield - shift); final double modifiedDurationFD = -(dirtyP - dirtyM) / (2 * shift) / dirty; assertEquals("Fixed coupon bond security: modified duration from yield US Street - finite difference", modifiedDurationFD, modifiedDuration, TOLERANCE_PRICE); } @Test public void modifiedDurationFromCurvesUSStreet() { final double yield = METHOD_BOND_SECURITY.yieldFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double modifiedDurationExpected = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double modifiedDuration = METHOD_BOND_SECURITY.modifiedDurationFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: modified duration from curves US Street", modifiedDurationExpected, modifiedDuration, TOLERANCE_PRICE); } @Test public void modifiedDurationFromDirtyPriceUSStreet() { final double dirtyPrice = 0.95; final double yield = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double modifiedDurationExpected = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double modifiedDuration = METHOD_BOND_SECURITY.modifiedDurationFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); assertEquals("Fixed coupon bond security: modified duration from curves US Street", modifiedDurationExpected, modifiedDuration, TOLERANCE_PRICE); } @Test public void modifiedDurationFromYieldUSStreetLastPeriod() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2016, 6, 3); // In last period final BondFixedSecurity bondSecurity = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.toDerivative(referenceDate); final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.modifiedDurationFromYield(bondSecurity, yield); final double dirtyPriceExpected = bondSecurity.getFactorToNextCoupon() / COUPON_PER_YEAR / (1 + bondSecurity.getFactorToNextCoupon() * yield / COUPON_PER_YEAR); assertEquals("Fixed coupon bond security: modified duration from yield US Street - last period", dirtyPriceExpected, dirtyPrice, TOLERANCE_PRICE); } @Test /** * Tests Macauley duration vs a hard coded value (US Street convention). */ public void macauleyDurationFromYieldUSStreet() { final double yield = 0.04; final double mc = METHOD_BOND_SECURITY.macaulayDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double mcExpected = 4.851906106 / dirty; assertEquals("Fixed coupon bond security: Macauley duration from yield US Street: harcoded value", mcExpected, mc, 1E-8); final double md = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); assertEquals("Fixed coupon bond security: Macauley duration from yield US Street: vs modified duration", md * (1 + yield / COUPON_PER_YEAR), mc, 1E-8); } @Test /** * Tests Macauley duration from the curves (US Street convention). */ public void macauleyDurationFromCurvesUSStreet() { final double yield = METHOD_BOND_SECURITY.yieldFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double macauleyDurationExpected = METHOD_BOND_SECURITY.macaulayDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double macauleyDuration = METHOD_BOND_SECURITY.macaulayDurationFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: Macauley duration from curves US Street", macauleyDurationExpected, macauleyDuration, 1E-8); } @Test /** * Tests Macauley duration from a dirty price (US Street convention). */ public void macauleyDurationFromDirtyPriceUSStreet() { final double dirtyPrice = 0.95; final double yield = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double macauleyDurationExpected = METHOD_BOND_SECURITY.macaulayDurationFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double macauleyDuration = METHOD_BOND_SECURITY.macaulayDurationFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); assertEquals("Fixed coupon bond security: Macauley duration from curves US Street", macauleyDurationExpected, macauleyDuration, 1E-8); } @Test /** * Tests convexity vs a hard coded value (US Street convention). */ public void convexityDurationFromYieldUSStreet() { final double yield = 0.04; final double cv = METHOD_BOND_SECURITY.convexityFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double cvExpected = 25.75957016 / dirty; assertEquals("Fixed coupon bond security: Macauley duration from yield US Street: harcoded value", cvExpected, cv, TOLERANCE_CONV); final double shift = 1.0E-5; final double dirtyP = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield + shift); final double dirtyM = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield - shift); final double cvFD = (dirtyP + dirtyM - 2 * dirty) / (shift * shift) / dirty; assertEquals("Fixed coupon bond security: modified duration from yield US Street - finite difference", cvFD, cv, TOLERANCE_CONV_FD); } @Test /** * Tests convexity from the curves (US Street convention). */ public void convexityFromCurvesUSStreet() { final double yield = METHOD_BOND_SECURITY.yieldFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double convexityExpected = METHOD_BOND_SECURITY.convexityFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double convexity = METHOD_BOND_SECURITY.convexityFromCurves(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: convexity from curves US Street", convexityExpected, convexity, 1E-8); } @Test /** * Tests convexity from a dirty price (US Street convention). */ public void convexityFromDirtyPriceUSStreet() { final double dirtyPrice = 0.95; final double yield = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); final double convexityExpected = METHOD_BOND_SECURITY.convexityFromYield(BOND_FIXED_SECURITY_NO_ENTITY_1, yield); final double convexity = METHOD_BOND_SECURITY.convexityFromDirtyPrice(BOND_FIXED_SECURITY_NO_ENTITY_1, dirtyPrice); assertEquals("Fixed coupon bond security: convexity from curves US Street", convexityExpected, convexity, 1E-8); } @Test public void dirtyPriceCurveSensitivity() { MulticurveSensitivity sensi = METHOD_BOND_SECURITY.dirtyPriceCurveSensitivity(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES).cleaned(); sensi = sensi.cleaned(); final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_NO_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); final double dfSettle = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getDiscountFactor(CUR, BOND_FIXED_SECURITY_NO_ENTITY_1.getSettlementTime()); final String DSC_CURVE_NAME = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getName(CUR); final String ISS_CURVE_NAME = ISSUER_SPECIFIC_MULTICURVES.getName(BOND_FIXED_SECURITY_NO_ENTITY_1.getIssuerEntity()); assertEquals("Fixed coupon bond security: dirty price curve sensitivity: risk-less curve", BOND_FIXED_SECURITY_NO_ENTITY_1.getSettlementTime(), sensi.getYieldDiscountingSensitivities().get(DSC_CURVE_NAME) .get(0).first, TOLERANCE_PV_DELTA); assertEquals("Fixed coupon bond security: dirty price curve sensitivity: risk-less curve", BOND_FIXED_SECURITY_NO_ENTITY_1.getSettlementTime() / dfSettle * pv.getAmount(CUR) / NOTIONAL, sensi .getYieldDiscountingSensitivities().get(DSC_CURVE_NAME).get(0).second, TOLERANCE_PV_DELTA); final double dfCpn0 = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getDiscountFactor(BOND_FIXED_SECURITY_NO_ENTITY_1.getCurrency(), BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getPaymentTime()); assertEquals("Fixed coupon bond security: dirty price curve sensitivity: repo curve", BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getPaymentTime(), sensi .getYieldDiscountingSensitivities() .get(ISS_CURVE_NAME).get(0).first, TOLERANCE_PV_DELTA); assertEquals("Fixed coupon bond security: dirty price curve sensitivity: repo curve", -BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getPaymentTime() * BOND_FIXED_SECURITY_NO_ENTITY_1.getCoupon().getNthPayment(0).getAmount() * dfCpn0 / dfSettle / NOTIONAL, sensi.getYieldDiscountingSensitivities().get(ISS_CURVE_NAME).get(0).second, TOLERANCE_PV_DELTA); } @Test /** * Tests that the clean price for consecutive dates in the future are relatively smooth (no jump die to miscalculated accrued or missing coupon). */ public void cleanPriceSmoothness() { final int nbDateForward = 150; final ZonedDateTime[] forwardDate = new ZonedDateTime[nbDateForward]; forwardDate[0] = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE_2, SETTLEMENT_DAYS, CALENDAR); //Spot final long[] jumpDays = new long[nbDateForward - 1]; for (int loopdate = 1; loopdate < nbDateForward; loopdate++) { forwardDate[loopdate] = ScheduleCalculator.getAdjustedDate(forwardDate[loopdate - 1], 1, CALENDAR); jumpDays[loopdate - 1] = forwardDate[loopdate].getLong(JulianFields.MODIFIED_JULIAN_DAY) - forwardDate[loopdate - 1].getLong(JulianFields.MODIFIED_JULIAN_DAY); } final double[] cleanPriceForward = new double[nbDateForward]; for (int loopdate = 0; loopdate < nbDateForward; loopdate++) { final BondFixedSecurity bondForward = BOND_FIXED_SECURITY_DEFINITION_NO_ENTITY.toDerivative(REFERENCE_DATE_2, forwardDate[loopdate]); cleanPriceForward[loopdate] = METHOD_BOND_SECURITY.cleanPriceFromCurves(bondForward, ISSUER_SPECIFIC_MULTICURVES); } //Test note: 0.03425 is roughly the difference between the coupon and the risk/free rate. The clean price is decreasing naturally by this amount divided by (roughly) 365 every day. //Test note: On the coupon date there is a jump in the clean price: If the coupon is included the clean price due to coupon is 0.04625/2*exp(-t*0.0100)*exp(t*0.0120) - 0.04625/2 = 1.59276E-05; // if the coupon is not included the impact is 0 (t=?). The clean price is thus expected to jump by the above amount when the settlement is on the coupon date 15-May-2012. final double couponJump = 1.59276E-05; for (int loopdate = 1; loopdate < nbDateForward; loopdate++) { assertEquals("Fixed coupon bond security: clean price smoothness " + loopdate, cleanPriceForward[loopdate] - (loopdate == 87 ? couponJump : 0.0), cleanPriceForward[loopdate - 1] - jumpDays[loopdate - 1] * (0.03425 / 365.0), 3.0E-5); } } // UKT 5 09/07/14 - ISIN-GB0031829509 To check figures in the ex-dividend period private static final String ISSUER_UK_NAME = ISSUER_NAMES[3]; private static final LegalEntity ISSUER_UK = new LegalEntity(null, ISSUER_UK_NAME, null, null, null); private static final Currency GBP = Currency.GBP; private static final Period PAYMENT_TENOR_UK = Period.ofMonths(6); private static final int COUPON_PER_YEAR_G = 2; private static final Calendar CALENDAR_UK = new MondayToFridayCalendar("A"); private static final DayCount DAY_COUNT_UK = DayCounts.ACT_ACT_ICMA; // To check private static final BusinessDayConvention BUSINESS_DAY_UK = BusinessDayConventions.FOLLOWING; private static final boolean IS_EOM_UK = false; private static final Period BOND_TENOR_G = Period.ofYears(12); private static final int SETTLEMENT_DAYS_UK = 1; private static final int EX_DIVIDEND_DAYS_UK = 7; private static final ZonedDateTime START_ACCRUAL_DATE_UK = DateUtils.getUTCDate(2002, 9, 7); private static final ZonedDateTime MATURITY_DATE_UK = START_ACCRUAL_DATE_UK.plus(BOND_TENOR_G); private static final double RATE_UK = 0.0500; private static final double NOTIONAL_UK = 100; private static final YieldConvention YIELD_CONVENTION_UK = YieldConventionFactory.INSTANCE.getYieldConvention("UK:BUMP/DMO METHOD"); private static final BondFixedSecurityDefinition BOND_FIXED_SECURITY_DEFINITION_UK = BondFixedSecurityDefinition.from(GBP, MATURITY_DATE_UK, START_ACCRUAL_DATE_UK, PAYMENT_TENOR_UK, RATE_UK, SETTLEMENT_DAYS_UK, NOTIONAL_UK, EX_DIVIDEND_DAYS_UK, CALENDAR_UK, DAY_COUNT_UK, BUSINESS_DAY_UK, YIELD_CONVENTION_UK, IS_EOM_UK, ISSUER_UK_NAME, "RepoType"); private static final ZonedDateTime REFERENCE_DATE_3 = DateUtils.getUTCDate(2011, 9, 2); // Ex-dividend is 30-Aug-2011 private static final BondFixedSecurity BOND_FIXED_SECURITY_UK = BOND_FIXED_SECURITY_DEFINITION_UK.toDerivative(REFERENCE_DATE_3); private static final ZonedDateTime SPOT_3 = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE_3, SETTLEMENT_DAYS_UK, CALENDAR); private static final double REFERENCE_TIME_3 = TimeCalculator.getTimeBetween(REFERENCE_DATE_3, SPOT_3); @Test public void presentValueFixedExDividend() { final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_UK, ISSUER_SPECIFIC_MULTICURVES); final BondFixedSecurityDefinition bondNoExDefinition = BondFixedSecurityDefinition.from(GBP, MATURITY_DATE_UK, START_ACCRUAL_DATE_UK, PAYMENT_TENOR_UK, RATE_UK, SETTLEMENT_DAYS_UK, NOTIONAL_UK, 0, CALENDAR_UK, DAY_COUNT_UK, BUSINESS_DAY_UK, YIELD_CONVENTION_UK, IS_EOM_UK, ISSUER_UK_NAME, "RepoType"); final BondFixedSecurity BondNoEx = bondNoExDefinition.toDerivative(REFERENCE_DATE_3); final MultipleCurrencyAmount pvNoEx = METHOD_BOND_SECURITY.presentValue(BondNoEx, ISSUER_SPECIFIC_MULTICURVES); final CouponFixedDefinition couponDefinitionEx = BOND_FIXED_SECURITY_DEFINITION_UK.getCoupons().getNthPayment(17); final MulticurveProviderInterface multicurvesDecorated = new MulticurveProviderDiscountingDecoratedIssuer(ISSUER_SPECIFIC_MULTICURVES, GBP, ISSUER_UK); final MultipleCurrencyAmount pvCpn = couponDefinitionEx.toDerivative(REFERENCE_DATE_3).accept(PVDC, multicurvesDecorated); assertEquals("Fixed coupon bond security: present value ex dividend", pvNoEx.getAmount(GBP) - pvCpn.getAmount(GBP), pv.getAmount(GBP), TOLERANCE_PV); } @Test public void dirtyPriceFixedExDividend() { final MultipleCurrencyAmount pv = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_UK, ISSUER_SPECIFIC_MULTICURVES); final double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getDiscountFactor(GBP, REFERENCE_TIME_3); final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_UK, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Fixed coupon bond security: dirty price from curves", pv.getAmount(GBP) / df / BOND_FIXED_SECURITY_UK.getCoupon().getNthPayment(0).getNotional(), dirty); assertTrue("Fixed coupon bond security: dirty price is relative price", (0.50 < dirty) & (dirty < 2.0)); } @Test public void dirtyPriceFromYieldUKExDividend() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield); final double dirtyPriceExpected = 1.0277859038; // To be check with another source. assertEquals("Fixed coupon bond security: dirty price from yield UK", dirtyPriceExpected, dirtyPrice, 1E-8); } @Test public void dirtyPriceFromYieldUKLastPeriod() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2014, 6, 3); // In last period final BondFixedSecurity bondSecurity = BOND_FIXED_SECURITY_DEFINITION_UK.toDerivative(referenceDate); final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(bondSecurity, yield); final double dirtyPriceExpected = (1 + RATE_UK / COUPON_PER_YEAR_G) * Math.pow(1 + yield / COUPON_PER_YEAR_G, -bondSecurity.getFactorToNextCoupon()); assertEquals("Fixed coupon bond security: dirty price from yield UK - last period", dirtyPriceExpected, dirtyPrice, 1E-8); } @Test public void yieldFromDirtyPriceUKExDividend() { final double yield = 0.04; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield); final double yieldComputed = METHOD_BOND_SECURITY.yieldFromDirtyPrice(BOND_FIXED_SECURITY_UK, dirtyPrice); assertEquals("Fixed coupon bond security: yield from dirty price UK", yield, yieldComputed, 1E-10); } @Test public void modifiedDurationFromYieldUKExDividend() { final double yield = 0.04; final double modifiedDuration = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_UK, yield); final double modifiedDurationExpected = 2.7757118292; // To be check with another source. assertEquals("Fixed coupon bond security: modified duration from yield UK DMO - hard coded value", modifiedDurationExpected, modifiedDuration, 1E-8); final double shift = 1.0E-6; final double dirty = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield); final double dirtyP = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield + shift); final double dirtyM = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield - shift); final double modifiedDurationFD = -(dirtyP - dirtyM) / (2 * shift) / dirty; assertEquals("Fixed coupon bond security: modified duration from yield UK DMO - finite difference", modifiedDurationFD, modifiedDuration, 1E-8); } @Test public void macauleyDurationFromYieldUKExDividend() { final double yield = 0.04; final double macauleyDuration = METHOD_BOND_SECURITY.macaulayDurationFromYield(BOND_FIXED_SECURITY_UK, yield); final double macauleyDurationExpected = 2.909894241 / METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_UK, yield); // To be check with another source. assertEquals("Fixed coupon bond security: Macauley duration from yield UK DMO - hard coded value", macauleyDurationExpected, macauleyDuration, 1E-8); } // UKT 6 1/4 11/25/10 private static final DayCount DAY_COUNT_G2 = DayCounts.ACT_ACT_ICMA; // To check private static final int SETTLEMENT_DAYS_G2 = 1; private static final int EX_DIVIDEND_DAYS_G2 = 7; private static final ZonedDateTime START_ACCRUAL_DATE_G2 = DateUtils.getUTCDate(1999, 11, 25); private static final ZonedDateTime MATURITY_DATE_G2 = DateUtils.getUTCDate(2010, 11, 25); private static final double RATE_G2 = 0.0625; private static final double NOTIONAL_G2 = 100; private static final YieldConvention YIELD_CONVENTION_G2 = YieldConventionFactory.INSTANCE.getYieldConvention("UK:BUMP/DMO METHOD"); private static final BondFixedSecurityDefinition BOND_FIXED_SECURITY_DEFINITION_G2 = BondFixedSecurityDefinition.from(GBP, MATURITY_DATE_G2, START_ACCRUAL_DATE_G2, PAYMENT_TENOR_UK, RATE_G2, SETTLEMENT_DAYS_G2, NOTIONAL_G2, EX_DIVIDEND_DAYS_G2, CALENDAR_UK, DAY_COUNT_G2, BUSINESS_DAY_UK, YIELD_CONVENTION_G2, IS_EOM_UK, ISSUER_UK_NAME, ""); private static final ZonedDateTime REFERENCE_DATE_4 = DateUtils.getUTCDate(2001, 8, 10); private static final BondFixedSecurity BOND_FIXED_SECURITY_G2 = BOND_FIXED_SECURITY_DEFINITION_G2.toDerivative(REFERENCE_DATE_4); @Test public void dirtyPriceFromCleanPriceUK() { final double cleanPrice = 110.20 / 100.00; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromCleanPrice(BOND_FIXED_SECURITY_G2, cleanPrice); final double dirtyPriceExpected = 1.11558696; assertEquals("Fixed coupon bond security: dirty price from clean price", dirtyPriceExpected, dirtyPrice, 1E-8); } @Test public void yieldPriceFromCleanPriceUK() { final double cleanPrice = 110.20 / 100.00; final double yield = METHOD_BOND_SECURITY.yieldFromCleanPrice(BOND_FIXED_SECURITY_G2, cleanPrice); final double yieldExpected = 0.04870; assertEquals("Fixed coupon bond security: dirty price from clean price", yieldExpected, yield, 1E-5); } @Test public void modifiedDurationFromCleanPriceUK() { final double cleanPrice = 110.20 / 100.00; final double dirtyPrice = METHOD_BOND_SECURITY.dirtyPriceFromCleanPrice(BOND_FIXED_SECURITY_G2, cleanPrice); final double md = METHOD_BOND_SECURITY.modifiedDurationFromDirtyPrice(BOND_FIXED_SECURITY_G2, dirtyPrice); final double mdExpected = 7.039; assertEquals("Fixed coupon bond security: dirty price from clean price", mdExpected, md, 1E-3); } @Test public void yieldMethodVsCalculator() { double yield1 = METHOD_BOND_SECURITY.yieldFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); double yield2 = BOND_FIXED_SECURITY_G2.accept(YFCC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("Bill Security: discounting method - yield from curves", yield1, yield2, TOLERANCE_YIELD); yield1 = METHOD_BOND_SECURITY.yieldFromCleanPrice(BOND_FIXED_SECURITY_G2, 1.1); yield2 = BOND_FIXED_SECURITY_G2.accept(YFPC, 1.1); assertEquals("Bond Security: discounting method - yield from price", yield1, yield2, TOLERANCE_YIELD); } @Test public void modifiedDurationMethodVsCalculator() { double method = METHOD_BOND_SECURITY.modifiedDurationFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); double calculator = BOND_FIXED_SECURITY_G2.accept(MDFC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("bond Security: discounting method - modified duration", method, calculator, 1e-9); method = METHOD_BOND_SECURITY.modifiedDurationFromYield(BOND_FIXED_SECURITY_G2, 0.05); calculator = BOND_FIXED_SECURITY_G2.accept(MDFY, 0.05); assertEquals("bond Security: discounting method - modified duration", method, calculator, 1e-9); method = METHOD_BOND_SECURITY.modifiedDurationFromCleanPrice(BOND_FIXED_SECURITY_G2, 1.00); calculator = BOND_FIXED_SECURITY_G2.accept(MDFP, 1.00); assertEquals("bond Security: discounting method - modified duration", method, calculator, 1e-9); } @Test public void macaulayDurationMethodVsCalculator() { double method = METHOD_BOND_SECURITY.macaulayDurationFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); double calculator = BOND_FIXED_SECURITY_G2.accept(McDFC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("bond Security: discounting method - macaulay duration", method, calculator, 1e-9); method = METHOD_BOND_SECURITY.macaulayDurationFromYield(BOND_FIXED_SECURITY_G2, 0.05); calculator = BOND_FIXED_SECURITY_G2.accept(McDFY, 0.05); assertEquals("bond Security: discounting method - macaulay duration", method, calculator, 1e-9); } @Test public void dirtyPriceMethodVsCalculator() { double method = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); double calculator = BOND_FIXED_SECURITY_G2.accept(DPFC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("bond Security: discounting method - dirty price", method, calculator, 1e-9); method = METHOD_BOND_SECURITY.dirtyPriceFromYield(BOND_FIXED_SECURITY_G2, 0.05); calculator = BOND_FIXED_SECURITY_G2.accept(DPFY, 0.05); assertEquals("bond Security: discounting method - dirty price", method, calculator, 1e-9); } @Test public void convexityMethodVsCalculator() { final double method = METHOD_BOND_SECURITY.convexityFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); final double calculator = BOND_FIXED_SECURITY_G2.accept(CFC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("bond Security: discounting method - convexity", method, calculator * 100, 1e-9); } @Test public void cleanPriceMethodVsCalculator() { double method = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_G2, ISSUER_SPECIFIC_MULTICURVES); double calculator = BOND_FIXED_SECURITY_G2.accept(CPFC, ISSUER_SPECIFIC_MULTICURVES); assertEquals("bond Security: discounting method - clean price", method, calculator / 100, 1e-9); method = METHOD_BOND_SECURITY.cleanPriceFromYield(BOND_FIXED_SECURITY_G2, 0.05); calculator = BOND_FIXED_SECURITY_G2.accept(CPFY, 0.05); assertEquals("bond Security: discounting method - clean price", method, calculator / 100, 1e-9); } private static final double REL_TOL = 1.0e-7; private static final double REL_TOL_ID = 1.0e-13; /** * Test with periodic compounded rates using IssuerProviderIssuerDecoratedSpreadPeriodic. */ @Test public void annualyCompoundedRateTest() { String issuerName = ISSUER_SPECIFIC_MULTICURVES.getIssuerProvider().getName(ISSUER); YieldCurve originalIssuerCurve = (YieldCurve) ISSUER_SPECIFIC_MULTICURVES.getIssuerCurve(issuerName); YieldPeriodicCurve baseIssuerCurve = getAnnuallyCompoundedRates(originalIssuerCurve); String discountName = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getName(CUR); YieldCurve originalDiscountingCurve = (YieldCurve) ISSUER_SPECIFIC_MULTICURVES.getCurve(discountName); YieldPeriodicCurve baseDiscountCurve = getAnnuallyCompoundedRates(originalDiscountingCurve); LegalEntityFilter<LegalEntity> filter = new LegalEntityShortName(); IssuerProviderDiscount issuerProvider = new IssuerProviderDiscount(); issuerProvider.setCurve(Pairs.of((Object) ISSUER.getShortName(), filter), baseIssuerCurve); issuerProvider.setCurve(CUR, baseDiscountCurve); /* PV */ MultipleCurrencyAmount pvAnnual = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider); MultipleCurrencyAmount pvContinuous = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, ISSUER_SPECIFIC_MULTICURVES); // interpolation on cont compounded rates vs interpolation on ann compounded rates, // thus resulting values are close but necessarily different. assertRelative("annualyCompoundedRateTest", pvContinuous.getAmount(CUR), pvAnnual.getAmount(CUR), REL_TOL); /* PV via calculator */ PresentValueIssuerCalculator calc = PresentValueIssuerCalculator.getInstance(); MultipleCurrencyAmount pvAnnualVisit = BOND_FIXED_SECURITY_FULL_ENTITY_1.accept(calc, issuerProvider); assertRelative("annualyCompoundedRateTest", pvAnnual.getAmount(CUR), pvAnnualVisit.getAmount(CUR), REL_TOL_ID); /* With spread */ double spread = 0.05; IssuerProviderIssuerDecoratedSpreadPeriodic issuerSpread = new IssuerProviderIssuerDecoratedSpreadPeriodic( issuerProvider, BOND_FIXED_SECURITY_FULL_ENTITY_1.getIssuerEntity(), spread, 1); MultipleCurrencyAmount pvAnnualSpread1 = METHOD_BOND_SECURITY.presentValue(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerSpread); MultipleCurrencyAmount pvAnnualSpread2 = METHOD_BOND_SECURITY.presentValueFromZSpread( BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider, spread, true, 1); assertRelative("annualyCompoundedRateTest", pvAnnualSpread1.getAmount(CUR), pvAnnualSpread2.getAmount(CUR), REL_TOL_ID); /* sensitivity -- check sensitivity to the spread curve is not taken into account */ double tinySpread = 1.0e-10; IssuerProviderIssuerDecoratedSpreadPeriodic issuerTinySpread = new IssuerProviderIssuerDecoratedSpreadPeriodic( issuerProvider, BOND_FIXED_SECURITY_FULL_ENTITY_1.getIssuerEntity(), tinySpread, 1); MultipleCurrencyMulticurveSensitivity senseTinySpread = METHOD_BOND_SECURITY.presentValueCurveSensitivity( BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerTinySpread); MultipleCurrencyMulticurveSensitivity senseZeroSpread = METHOD_BOND_SECURITY.presentValueCurveSensitivity( BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider); AssertSensitivityObjects.assertEquals("annualyCompoundedRateTest", senseZeroSpread, senseTinySpread, pvAnnual.getAmount(CUR) * REL_TOL); /* spread finder -- round trip test */ double computedSpread = METHOD_BOND_SECURITY.zSpreadFromCurvesAndPV(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider, pvAnnual, true, 1); assertRelative("annualyCompoundedRateTest", 0.0, computedSpread, REL_TOL); computedSpread = METHOD_BOND_SECURITY.zSpreadFromCurvesAndPV(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider, pvAnnualSpread1, true, 1); assertRelative("annualyCompoundedRateTest", spread, computedSpread, REL_TOL); /* check ccy based discounting is not affected by the spread */ double dirtySpread1 = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerSpread); double dirtyAnnual = METHOD_BOND_SECURITY.dirtyPriceFromCurves(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider); double factorSpread = pvAnnualSpread1.getAmount(CUR) / dirtySpread1; double factorNoSpread = pvAnnual.getAmount(CUR) / dirtyAnnual; assertRelative("annualyCompoundedRateTest", factorNoSpread, factorSpread, REL_TOL); /* spread calculation from clean price */ double cleanSpread1 = METHOD_BOND_SECURITY.cleanPriceFromCurves(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerSpread); double spreadFromClean = METHOD_BOND_SECURITY.zSpreadFromCurvesAndClean(BOND_FIXED_SECURITY_FULL_ENTITY_1, issuerProvider, cleanSpread1, true, 1); assertRelative("annualyCompoundedRateTest", spread, spreadFromClean, REL_TOL); } private static void assertRelative(String message, double expected, double obtained, double relativeTol) { double ref = Math.max(Math.abs(expected), 1.0); assertEquals(message, expected, obtained, ref * relativeTol); } private YieldPeriodicCurve getAnnuallyCompoundedRates(YieldCurve originalCurve) { InterpolatedDoublesCurve interpCurve = (InterpolatedDoublesCurve) originalCurve.getCurve(); Double[] time = interpCurve.getXData(); Double[] rateCont = interpCurve.getYData(); int nData = time.length; Double[] rateAnn = new Double[nData]; int nPeriods = 1; for (int i = 0; i < nData; ++i) { rateAnn[i] = nPeriods * (Math.exp(rateCont[i] / nPeriods) - 1.0); } InterpolatedDoublesCurve curveAnn = InterpolatedDoublesCurve.fromSorted(time, rateAnn, interpCurve.getInterpolator(), interpCurve.getName()); return YieldPeriodicCurve.from(nPeriods, curveAnn); } }