/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.interestrate.future.provider; import static org.testng.AssertJUnit.assertEquals; import org.testng.annotations.Test; import org.threeten.bp.Period; import org.threeten.bp.ZoneId; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.instrument.bond.BondFixedSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.BondFuturesOptionMarginSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.BondFuturesOptionMarginTransactionDefinition; import com.opengamma.analytics.financial.instrument.future.BondFuturesSecurityDefinition; import com.opengamma.analytics.financial.interestrate.bond.definition.BondFixedSecurity; import com.opengamma.analytics.financial.interestrate.bond.provider.BondSecurityDiscountingMethod; import com.opengamma.analytics.financial.interestrate.future.calculator.DeltaBlackBondFuturesCalculator; import com.opengamma.analytics.financial.interestrate.future.calculator.FuturesPriceBlackBondFuturesCalculator; import com.opengamma.analytics.financial.interestrate.future.calculator.GammaBlackBondFuturesCalculator; import com.opengamma.analytics.financial.interestrate.future.calculator.ThetaBlackBondFuturesCalculator; import com.opengamma.analytics.financial.interestrate.future.calculator.VegaBlackBondFuturesCalculator; import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesOptionMarginTransaction; import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesSecurity; 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.legalentity.Sector; import com.opengamma.analytics.financial.model.interestrate.curve.YieldPeriodicCurve; import com.opengamma.analytics.financial.provider.calculator.blackbondfutures.PresentValueBlackBondFuturesOptionCalculator; import com.opengamma.analytics.financial.provider.calculator.blackbondfutures.PresentValueCurveSensitivityBlackBondFuturesOptionCalculator; import com.opengamma.analytics.financial.provider.calculator.discounting.PV01CurveParametersCalculator; import com.opengamma.analytics.financial.provider.description.interestrate.BlackBondFuturesExpLogMoneynessProvider; import com.opengamma.analytics.financial.provider.description.interestrate.BlackBondFuturesExpLogMoneynessProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.BlackBondFuturesProviderInterface; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderIssuerDecoratedSpreadPeriodic; import com.opengamma.analytics.financial.provider.sensitivity.parameter.ParameterSensitivityParameterCalculator; import com.opengamma.analytics.math.curve.ConstantDoublesCurve; import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve; import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory; import com.opengamma.analytics.math.interpolation.GridInterpolator2D; import com.opengamma.analytics.math.interpolation.Interpolator1D; import com.opengamma.analytics.math.interpolation.Interpolator1DFactory; import com.opengamma.analytics.math.matrix.DoubleMatrix1D; import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface; 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.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCounts; import com.opengamma.financial.convention.yield.SimpleYieldConvention; import com.opengamma.financial.convention.yield.YieldConvention; 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.tuple.Pairs; /** * End-to-end test for bond futures option based on Black model with moneyness-expiry volatility surface */ @Test(groups = TestGroup.UNIT) public class BondFuturesOptionMarginTransactionBlackExpLogMoneynessMethodE2ETest { private static final BondAndSTIRFuturesE2EExamplesData DATA = new BondAndSTIRFuturesE2EExamplesData(); private static final Calendar EUR_CALENDAR = DATA.getEURCalendar(); private static final Currency EUR = Currency.EUR; private static final ZonedDateTime VALUATION_DATE = ZonedDateTime.of(2014, 2, 17, 9, 0, 0, 0, ZoneId.of("Z")); /* names */ private static final String ISSUER_NAME_SCH = "SCH EUR"; private static final String ISSUER_NAME_BUN = "BUN EUR"; private static final String ISSUER_NAME_BOB = "BOB EUR"; private static final String CURVE_NAME_SCH = "SCH EURBond"; private static final String CURVE_NAME_BUN = "BUN EURBond"; private static final String CURVE_NAME_BOB = "BOB EURBond"; private static final LegalEntity LEGAL_ENTITY_SCH = new LegalEntity(null, ISSUER_NAME_SCH, null, Sector.of("EU"), Region.of("EU", Country.of("EU"), EUR)); private static final LegalEntity LEGAL_ENTITY_BUN = new LegalEntity(null, ISSUER_NAME_BUN, null, Sector.of("EU"), Region.of("EU", Country.of("EU"), EUR)); private static final LegalEntity LEGAL_ENTITY_BOB = new LegalEntity(null, ISSUER_NAME_BOB, null, Sector.of("EU"), Region.of("EU", Country.of("EU"), EUR)); private static final InterpolatedDoublesSurface VOL_SURFACE_MONEYNESS; static { Interpolator1D squareFlat = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.SQUARE_LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); Interpolator1D timeSquareFlat = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.TIME_SQUARE, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); GridInterpolator2D INTERPOLATOR_2D = new GridInterpolator2D(timeSquareFlat, squareFlat); VOL_SURFACE_MONEYNESS = InterpolatedDoublesSurface.from(DATA.getExpiry(), DATA.getSimpleMoneyness(), DATA.getVolatility(), INTERPOLATOR_2D); } private static final Interpolator1D INTERPOLATOR = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.LINEAR_EXTRAPOLATOR); // Note that repo rate is contained as a currency based discount curve. // However, this is not used in the option pricing part as the numeraire is always 1. private static final BlackBondFuturesExpLogMoneynessProviderDiscount BLACK_PROVIDER_SCH; static { IssuerProviderDiscount issuerProvider = new IssuerProviderDiscount(); InterpolatedDoublesCurve interpolatedCurve = InterpolatedDoublesCurve.fromSorted(DATA.getTimeGER(), DATA.getRateGER(), INTERPOLATOR, CURVE_NAME_SCH); YieldPeriodicCurve yieldCurve = YieldPeriodicCurve.from(1, interpolatedCurve); LegalEntityFilter<LegalEntity> filter = new LegalEntityShortName(); issuerProvider.setCurve(Pairs.of((Object) ISSUER_NAME_SCH, filter), yieldCurve); ConstantDoublesCurve constantDoublesCurve = ConstantDoublesCurve.from(DATA.getRepoSCHOp()); YieldPeriodicCurve repoCurve = YieldPeriodicCurve.from(1, constantDoublesCurve); issuerProvider.setCurve(EUR, repoCurve); BLACK_PROVIDER_SCH = new BlackBondFuturesExpLogMoneynessProviderDiscount(issuerProvider, VOL_SURFACE_MONEYNESS, LEGAL_ENTITY_SCH); } private static final BlackBondFuturesExpLogMoneynessProviderDiscount BLACK_PROVIDER_BUN; static { IssuerProviderDiscount issuerProvider = new IssuerProviderDiscount(); InterpolatedDoublesCurve interpolatedCurve = InterpolatedDoublesCurve.fromSorted(DATA.getTimeGER(), DATA.getRateGER(), INTERPOLATOR, CURVE_NAME_BUN); YieldPeriodicCurve yieldCurve = YieldPeriodicCurve.from(1, interpolatedCurve); LegalEntityFilter<LegalEntity> filter = new LegalEntityShortName(); issuerProvider.setCurve(Pairs.of((Object) ISSUER_NAME_BUN, filter), yieldCurve); ConstantDoublesCurve constantDoublesCurve = ConstantDoublesCurve.from(DATA.getRepoBUNOp()); YieldPeriodicCurve repoCurve = YieldPeriodicCurve.from(1, constantDoublesCurve); issuerProvider.setCurve(EUR, repoCurve); BLACK_PROVIDER_BUN = new BlackBondFuturesExpLogMoneynessProviderDiscount(issuerProvider, VOL_SURFACE_MONEYNESS, LEGAL_ENTITY_BUN); } private static final BlackBondFuturesExpLogMoneynessProviderDiscount BLACK_PROVIDER_BOB; static { IssuerProviderDiscount issuerProvider = new IssuerProviderDiscount(); InterpolatedDoublesCurve interpolatedCurve = InterpolatedDoublesCurve.fromSorted(DATA.getTimeGER(), DATA.getRateGER(), INTERPOLATOR, CURVE_NAME_BOB); YieldPeriodicCurve yieldCurve = YieldPeriodicCurve.from(1, interpolatedCurve); LegalEntityFilter<LegalEntity> filter = new LegalEntityShortName(); issuerProvider.setCurve(Pairs.of((Object) ISSUER_NAME_BOB, filter), yieldCurve); ConstantDoublesCurve constantDoublesCurve = ConstantDoublesCurve.from(DATA.getRepoBOBOp()); YieldPeriodicCurve repoCurve = YieldPeriodicCurve.from(1, constantDoublesCurve); issuerProvider.setCurve(EUR, repoCurve); BLACK_PROVIDER_BOB = new BlackBondFuturesExpLogMoneynessProviderDiscount(issuerProvider, VOL_SURFACE_MONEYNESS, LEGAL_ENTITY_BOB); } private static final int QUANTITY = 1; private static final double NOTIONAL = 1000.0; private static final BusinessDayConvention BUSINESS_DAY = BusinessDayConventions.FOLLOWING; private static final DayCount DAY_COUNT = DayCounts.ACT_ACT_ICMA; private static ZonedDateTime TRADE_DATE = ZonedDateTime.of(2008, 8, 27, 1, 0, 0, 0, ZoneId.of("Z")); // 2008-08-27T01:00Z private static final double TRADE_PRICE = 0.0; private static final double LAST_MARGIN_PRICE = 0.0; /* Schatz */ private static final BondFuturesOptionMarginTransaction TRANSACTION_SCH; private static final double BOND_MARKET_PRICE_SCH = 99.825; static { ZonedDateTime tradingLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); // 2014-03-10T23:59Z ZonedDateTime noticeFirstDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime noticeLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryFirstDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime firstAccrualDate = ZonedDateTime.of(2013, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2013-02-15T00:00Z ZonedDateTime firstCouponDate = ZonedDateTime.of(2014, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-02-15T00:00Z ZonedDateTime maturityDate = ZonedDateTime.of(2023, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2023-02-15T00:00Z Period paymentPeriod = Period.ofMonths(12); double fixedRate = 0.015; int settlementDays = 3; YieldConvention yieldConvention = SimpleYieldConvention.GERMAN_BOND; boolean isEOM = false; BondFixedSecurityDefinition bondFixed = BondFixedSecurityDefinition.from(EUR, firstAccrualDate, firstCouponDate, maturityDate, paymentPeriod, fixedRate, settlementDays, EUR_CALENDAR, DAY_COUNT, BUSINESS_DAY, yieldConvention, isEOM, LEGAL_ENTITY_SCH); BondFixedSecurityDefinition[] deliveryBasket = new BondFixedSecurityDefinition[] {bondFixed }; double[] conversionFactor = new double[] {0.695531 }; BondFuturesSecurityDefinition bondFuturesDefinition = new BondFuturesSecurityDefinition(tradingLastDate, noticeFirstDate, noticeLastDate, deliveryFirstDate, deliveryLastDate, NOTIONAL, deliveryBasket, conversionFactor); ZonedDateTime lastTradingDate = ZonedDateTime.of(2014, 3, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-03-06T00:00Z ZonedDateTime expirationDate = ZonedDateTime.of(2014, 3, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-03-06T00:00Z double strike = 1.1; boolean isCall = true; BondFuturesOptionMarginSecurityDefinition underlyingOption = new BondFuturesOptionMarginSecurityDefinition( bondFuturesDefinition, lastTradingDate, expirationDate, strike, isCall); BondFuturesOptionMarginTransactionDefinition transactionDefinition = new BondFuturesOptionMarginTransactionDefinition( underlyingOption, QUANTITY, TRADE_DATE, TRADE_PRICE); TRANSACTION_SCH = transactionDefinition.toDerivative(VALUATION_DATE, LAST_MARGIN_PRICE); } /* Bund */ private static final BondFuturesOptionMarginTransaction TRANSACTION_BUN; private static final double BOND_MARKET_PRICE_BUN = 99.935; static { ZonedDateTime tradingLastDate = ZonedDateTime.of(2014, 6, 10, 23, 59, 0, 0, ZoneId.of("Z")); // 2014-06-10T23:59Z ZonedDateTime noticeFirstDate = ZonedDateTime.of(2014, 6, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime noticeLastDate = ZonedDateTime.of(2014, 6, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryFirstDate = ZonedDateTime.of(2014, 6, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryLastDate = ZonedDateTime.of(2014, 6, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime firstAccrualDate = ZonedDateTime.of(2013, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2013-02-15T00:00Z ZonedDateTime firstCouponDate = ZonedDateTime.of(2014, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-02-15T00:00Z ZonedDateTime maturityDate = ZonedDateTime.of(2023, 2, 15, 0, 0, 0, 0, ZoneId.of("Z")); // 2023-02-15T00:00Z Period paymentPeriod = Period.ofMonths(12); double fixedRate = 0.015; int settlementDays = 3; YieldConvention yieldConvention = SimpleYieldConvention.GERMAN_BOND; boolean isEOM = false; BondFixedSecurityDefinition bondFixed = BondFixedSecurityDefinition.from(EUR, firstAccrualDate, firstCouponDate, maturityDate, paymentPeriod, fixedRate, settlementDays, EUR_CALENDAR, DAY_COUNT, BUSINESS_DAY, yieldConvention, isEOM, LEGAL_ENTITY_BUN); BondFixedSecurityDefinition[] deliveryBasket = new BondFixedSecurityDefinition[] {bondFixed }; double[] conversionFactor = new double[] {0.702055 }; BondFuturesSecurityDefinition bondFuturesDefinition = new BondFuturesSecurityDefinition(tradingLastDate, noticeFirstDate, noticeLastDate, deliveryFirstDate, deliveryLastDate, NOTIONAL, deliveryBasket, conversionFactor); ZonedDateTime lastTradingDate = ZonedDateTime.of(2014, 6, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-06-06T00:00Z ZonedDateTime expirationDate = ZonedDateTime.of(2014, 6, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-06-06T00:00Z double strike = 1.4; boolean isCall = true; BondFuturesOptionMarginSecurityDefinition underlyingOption = new BondFuturesOptionMarginSecurityDefinition( bondFuturesDefinition, lastTradingDate, expirationDate, strike, isCall); BondFuturesOptionMarginTransactionDefinition transactionDefinition = new BondFuturesOptionMarginTransactionDefinition( underlyingOption, QUANTITY, TRADE_DATE, TRADE_PRICE); TRANSACTION_BUN = transactionDefinition.toDerivative(VALUATION_DATE, LAST_MARGIN_PRICE); } /* Bobl */ private static final BondFuturesOptionMarginTransaction TRANSACTION_BOB; private static final double BOND_MARKET_PRICE_BOB = 115.195; static { ZonedDateTime tradingLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); // 2014-03-10T23:59Z ZonedDateTime noticeFirstDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime noticeLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryFirstDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime deliveryLastDate = ZonedDateTime.of(2014, 3, 10, 23, 59, 0, 0, ZoneId.of("Z")); ZonedDateTime firstAccrualDate = ZonedDateTime.of(2009, 1, 4, 0, 0, 0, 0, ZoneId.of("Z")); // 2009-01-04T00:00Z ZonedDateTime firstCouponDate = ZonedDateTime.of(2010, 1, 4, 0, 0, 0, 0, ZoneId.of("Z")); // 2010-01-04T00:00Z ZonedDateTime maturityDate = ZonedDateTime.of(2019, 1, 4, 0, 0, 0, 0, ZoneId.of("Z")); // 2019-01-04T00:00Z Period paymentPeriod = Period.ofMonths(12); double fixedRate = 0.0375; int settlementDays = 3; YieldConvention yieldConvention = SimpleYieldConvention.GERMAN_BOND; boolean isEOM = false; BondFixedSecurityDefinition bondFixed = BondFixedSecurityDefinition.from(EUR, firstAccrualDate, firstCouponDate, maturityDate, paymentPeriod, fixedRate, settlementDays, EUR_CALENDAR, DAY_COUNT, BUSINESS_DAY, yieldConvention, isEOM, LEGAL_ENTITY_BOB); BondFixedSecurityDefinition[] deliveryBasket = new BondFixedSecurityDefinition[] {bondFixed }; double[] conversionFactor = new double[] {0.907986 }; BondFuturesSecurityDefinition bondFuturesDefinition = new BondFuturesSecurityDefinition(tradingLastDate, noticeFirstDate, noticeLastDate, deliveryFirstDate, deliveryLastDate, NOTIONAL, deliveryBasket, conversionFactor); ZonedDateTime lastTradingDate = ZonedDateTime.of(2014, 3, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-03-06T00:00Z ZonedDateTime expirationDate = ZonedDateTime.of(2014, 3, 6, 0, 0, 0, 0, ZoneId.of("Z")); // 2014-03-06T00:00Z double strike = 1.27; boolean isCall = false; BondFuturesOptionMarginSecurityDefinition underlyingOption = new BondFuturesOptionMarginSecurityDefinition( bondFuturesDefinition, lastTradingDate, expirationDate, strike, isCall); BondFuturesOptionMarginTransactionDefinition transactionDefinition = new BondFuturesOptionMarginTransactionDefinition( underlyingOption, QUANTITY, TRADE_DATE, TRADE_PRICE); TRANSACTION_BOB = transactionDefinition.toDerivative(VALUATION_DATE, LAST_MARGIN_PRICE); } /* underlying method */ private static final BondSecurityDiscountingMethod BOND_METHOD = BondSecurityDiscountingMethod.getInstance(); /* calculator */ private static final FuturesPriceBlackBondFuturesCalculator FPBFC = FuturesPriceBlackBondFuturesCalculator .getInstance(); private static final PresentValueBlackBondFuturesOptionCalculator PVBFC = PresentValueBlackBondFuturesOptionCalculator .getInstance(); private static final PresentValueCurveSensitivityBlackBondFuturesOptionCalculator PVCSBFC = new PresentValueCurveSensitivityBlackBondFuturesOptionCalculator(); private static final ParameterSensitivityParameterCalculator<BlackBondFuturesProviderInterface> PSSFC = new ParameterSensitivityParameterCalculator<>(PVCSBFC); private static final PV01CurveParametersCalculator<BlackBondFuturesProviderInterface> PV01PC = new PV01CurveParametersCalculator<>(PVCSBFC); private static final DeltaBlackBondFuturesCalculator DBFC = DeltaBlackBondFuturesCalculator.getInstance(); private static final GammaBlackBondFuturesCalculator GBFC = GammaBlackBondFuturesCalculator.getInstance(); private static final ThetaBlackBondFuturesCalculator TBFC = ThetaBlackBondFuturesCalculator.getInstance(); private static final VegaBlackBondFuturesCalculator VBFC = VegaBlackBondFuturesCalculator.getInstance(); private final double HUNDRED = 100.0; private static final double BP1 = 1.0E-4; private static final double TOL = 1.0e-10; /** * Schatz */ @Test public void SCHTest() { BondFuturesSecurity futures = TRANSACTION_SCH.getUnderlyingSecurity().getUnderlyingFuture(); BondFixedSecurity bondAtSpot = futures.getDeliveryBasketAtSpotDate()[0]; LegalEntity legalEntity = bondAtSpot.getIssuerEntity(); double spread = BOND_METHOD.zSpreadFromCurvesAndClean(bondAtSpot, BLACK_PROVIDER_SCH.getIssuerProvider(), BOND_MARKET_PRICE_SCH / HUNDRED, true, 1) / BP1; IssuerProviderIssuerDecoratedSpreadPeriodic curveWithSpread = new IssuerProviderIssuerDecoratedSpreadPeriodic( BLACK_PROVIDER_SCH.getIssuerProvider(), legalEntity, spread * BP1, 1); BlackBondFuturesExpLogMoneynessProvider blackNew = new BlackBondFuturesExpLogMoneynessProvider( curveWithSpread, BLACK_PROVIDER_SCH.getBlackParameters(), BLACK_PROVIDER_SCH.getLegalEntity()); double price = TRANSACTION_SCH.getUnderlyingSecurity().accept(FPBFC, blackNew) * HUNDRED; MultipleCurrencyAmount pv = TRANSACTION_SCH.accept(PVBFC, blackNew); // multiplied by notional DoubleMatrix1D bucketedPv01 = PSSFC.calculateSensitivity(TRANSACTION_SCH, blackNew) .multipliedBy(BP1).getSensitivity(CURVE_NAME_SCH, EUR); double pv01 = TRANSACTION_SCH.accept(PV01PC, blackNew).getMap().get(Pairs.of(CURVE_NAME_SCH, EUR)); double delta = TRANSACTION_SCH.getUnderlyingSecurity().accept(DBFC, blackNew); double gamma = TRANSACTION_SCH.getUnderlyingSecurity().accept(GBFC, blackNew); double theta = TRANSACTION_SCH.getUnderlyingSecurity().accept(TBFC, blackNew); double vega = TRANSACTION_SCH.getUnderlyingSecurity().accept(VBFC, blackNew); double[] bucketExpected = new double[] {0.0, 0.0, 0.0, 0.0, -1.0423326047608712E-5, -0.0019402794580315554, -0.003858201768632529, -0.00575895407513098, -0.007584169326455068, -0.009238481853954652, -0.011014901502395579, -0.012431820569196617, -0.01921332999829044, -1.0042223062140274, 0.0, 0.0, 0.0, 0.0 }; assertRelative("SCHTest", 1.8985746330408042, spread, TOL); assertRelative("SCHTest", 35.183034488344134, price, TOL); assertRelative("SCHTest", 351.83034488344134, pv.getAmount(EUR), TOL); assertArrayRelative("", bucketExpected, bucketedPv01.getData(), TOL); assertRelative("SCHTest", -1.0752728680921624, pv01, TOL); assertRelative("SCHTest", 0.8983317096780475, delta, TOL); assertRelative("SCHTest", 0.5401942777969126, gamma, TOL); assertRelative("SCHTest", -0.6264331723356449, theta, TOL); assertRelative("SCHTest", 0.05498292195291605, vega, TOL); } /** * Bund */ @Test public void BUNTest() { BondFuturesSecurity futures = TRANSACTION_BUN.getUnderlyingSecurity().getUnderlyingFuture(); BondFixedSecurity bondAtSpot = futures.getDeliveryBasketAtSpotDate()[0]; LegalEntity legalEntity = bondAtSpot.getIssuerEntity(); double spread = BOND_METHOD.zSpreadFromCurvesAndClean(bondAtSpot, BLACK_PROVIDER_BUN.getIssuerProvider(), BOND_MARKET_PRICE_BUN / HUNDRED, true, 1) / BP1; IssuerProviderIssuerDecoratedSpreadPeriodic curveWithSpread = new IssuerProviderIssuerDecoratedSpreadPeriodic( BLACK_PROVIDER_BUN.getIssuerProvider(), legalEntity, spread * BP1, 1); BlackBondFuturesExpLogMoneynessProvider blackNew = new BlackBondFuturesExpLogMoneynessProvider( curveWithSpread, BLACK_PROVIDER_BUN.getBlackParameters(), BLACK_PROVIDER_BUN.getLegalEntity()); double price = TRANSACTION_BUN.getUnderlyingSecurity().accept(FPBFC, blackNew) * HUNDRED; MultipleCurrencyAmount pv = TRANSACTION_BUN.accept(PVBFC, blackNew); // multiplied by notional DoubleMatrix1D bucketedPv01 = PSSFC.calculateSensitivity(TRANSACTION_BUN, blackNew) .multipliedBy(BP1).getSensitivity(CURVE_NAME_BUN, EUR); double pv01 = TRANSACTION_BUN.accept(PV01PC, blackNew).getMap().get(Pairs.of(CURVE_NAME_BUN, EUR)); double delta = TRANSACTION_BUN.getUnderlyingSecurity().accept(DBFC, blackNew); double gamma = TRANSACTION_BUN.getUnderlyingSecurity().accept(GBFC, blackNew); double theta = TRANSACTION_BUN.getUnderlyingSecurity().accept(TBFC, blackNew); double vega = TRANSACTION_BUN.getUnderlyingSecurity().accept(VBFC, blackNew); double[] bucketExpected = new double[] {0.0, 0.0, 0.0, 0.0, -7.043872687701196E-6, -0.0013112035838708407, -0.002607644487398833, -0.0038928242105677065, -0.005127274086907749, -0.006246485024304067, -0.007448577673891045, -0.008407825293669284, -0.012996416494364633, -0.6793455067559377, 0.0, 0.0, 0.0, 0.0 }; assertRelative("BUNTest", 0.5612849466207794, spread, TOL); assertRelative("BUNTest", 30.113033433034087, price, TOL); assertRelative("BUNTest", 301.1303343303409, pv.getAmount(EUR), TOL); assertArrayRelative("", bucketExpected, bucketedPv01.getData(), TOL); assertRelative("BUNTest", -0.7273908014835997, pv01, TOL); assertRelative("BUNTest", 0.6126650490480057, delta, TOL); assertRelative("BUNTest", 0.5131248273894041, gamma, TOL); assertRelative("BUNTest", -0.47845638404975527, theta, TOL); assertRelative("BUNTest", 0.2965232966302743, vega, TOL); } /** * Bobl */ @Test public void BOBTest() { BondFuturesSecurity futures = TRANSACTION_BOB.getUnderlyingSecurity().getUnderlyingFuture(); BondFixedSecurity bondAtSpot = futures.getDeliveryBasketAtSpotDate()[0]; LegalEntity legalEntity = bondAtSpot.getIssuerEntity(); double spread = BOND_METHOD.zSpreadFromCurvesAndClean(bondAtSpot, BLACK_PROVIDER_BOB.getIssuerProvider(), BOND_MARKET_PRICE_BOB / HUNDRED, true, 1) / BP1; IssuerProviderIssuerDecoratedSpreadPeriodic curveWithSpread = new IssuerProviderIssuerDecoratedSpreadPeriodic( BLACK_PROVIDER_BOB.getIssuerProvider(), legalEntity, spread * BP1, 1); BlackBondFuturesExpLogMoneynessProvider blackNew = new BlackBondFuturesExpLogMoneynessProvider( curveWithSpread, BLACK_PROVIDER_BOB.getBlackParameters(), BLACK_PROVIDER_BOB.getLegalEntity()); double price = TRANSACTION_BOB.getUnderlyingSecurity().accept(FPBFC, blackNew) * HUNDRED; MultipleCurrencyAmount pv = TRANSACTION_BOB.accept(PVBFC, blackNew); // multiplied by notional DoubleMatrix1D bucketedPv01 = PSSFC.calculateSensitivity(TRANSACTION_BOB, blackNew) .multipliedBy(BP1).getSensitivity(CURVE_NAME_BOB, EUR); double pv01 = TRANSACTION_BOB.accept(PV01PC, blackNew).getMap().get(Pairs.of(CURVE_NAME_BOB, EUR)); double delta = TRANSACTION_BOB.getUnderlyingSecurity().accept(DBFC, blackNew); double gamma = TRANSACTION_BOB.getUnderlyingSecurity().accept(GBFC, blackNew); double theta = TRANSACTION_BOB.getUnderlyingSecurity().accept(TBFC, blackNew); double vega = TRANSACTION_BOB.getUnderlyingSecurity().accept(VBFC, blackNew); double[] bucketExpected = new double[] {0.0, 0.0, 0.0, 0.0, 3.9939567069155403E-4, 0.0017598422748673222, 0.0038884332824756437, 0.005802403467586379, 0.03716178737504283, 0.22340950463905093, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; assertRelative("BOBTest", -3.9954021134091353, spread, TOL); assertRelative("BOBTest", 8.837066933825167, price, TOL); assertRelative("BOBTest", 88.37066933825166, pv.getAmount(EUR), TOL); assertArrayRelative("", bucketExpected, bucketedPv01.getData(), TOL); assertRelative("BOBTest", 0.2724213667097147, pv01, TOL); assertRelative("BOBTest", -0.47202802974084884, delta, TOL); assertRelative("BOBTest", 1.8320961337443291, gamma, TOL); assertRelative("BOBTest", -0.9280515056338662, theta, TOL); assertRelative("BOBTest", 0.1087833907611784, vega, TOL); } private void assertArrayRelative(String message, double[] expected, double[] obtained, double relativeTol) { int nData = expected.length; assertEquals(message, nData, obtained.length); for (int i = 0; i < nData; ++i) { assertRelative(message, expected[i], obtained[i], relativeTol); } } private 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); } }