/** * Copyright (C) 2014 - 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 static org.testng.AssertJUnit.assertTrue; import org.testng.annotations.Test; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.datasets.CalendarTarget; import com.opengamma.analytics.financial.instrument.future.InterestRateFutureOptionMarginSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.InterestRateFutureOptionMarginTransactionDefinition; import com.opengamma.analytics.financial.instrument.future.InterestRateFutureSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.InterestRateFutureTransactionDefinition; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexIborMaster; import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureOptionMarginTransaction; import com.opengamma.analytics.financial.interestrate.future.derivative.InterestRateFutureTransaction; import com.opengamma.analytics.financial.provider.calculator.blackstirfutures.PresentValueBlackSTIRFutureOptionCalculator; import com.opengamma.analytics.financial.provider.calculator.blackstirfutures.PresentValueCurveSensitivityBlackSTIRFutureOptionCalculator; import com.opengamma.analytics.financial.provider.description.MulticurveProviderDiscountDataSets; import com.opengamma.analytics.financial.provider.description.StandardDataSetsBlack; import com.opengamma.analytics.financial.provider.description.interestrate.BlackSTIRFuturesExpLogMoneynessProvider; import com.opengamma.analytics.financial.provider.description.interestrate.BlackSTIRFuturesExpLogMoneynessProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.BlackSTIRFuturesProviderInterface; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.provider.sensitivity.blackstirfutures.ParameterSensitivityBlackSTIRFuturesExpLogMoneynessDiscountInterpolatedFDCalculator; import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity; import com.opengamma.analytics.financial.provider.sensitivity.parameter.ParameterSensitivityParameterCalculator; import com.opengamma.analytics.financial.util.AssertSensitivityObjects; import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface; import com.opengamma.financial.convention.calendar.Calendar; import com.opengamma.util.money.Currency; import com.opengamma.util.money.MultipleCurrencyAmount; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; /** * Test. */ @Test(groups = TestGroup.UNIT) public class STIRFuturesOptionMarginTransactionBlackExpLogMoneynessMethodTest { /** Option on STIR futures */ private static final IndexIborMaster MASTER_IBOR_INDEX = IndexIborMaster.getInstance(); private static final IborIndex EURIBOR3M = MASTER_IBOR_INDEX.getIndex("EURIBOR3M"); private static final Currency EUR = EURIBOR3M.getCurrency(); private static final ZonedDateTime LAST_TRADE_DATE = DateUtils.getUTCDate(2014, 12, 15); private static final double NOTIONAL = 1000000.0; // 1m private static final double FUTURE_FACTOR = 0.25; private static final String NAME = "ERZ4"; private static final Calendar TARGET = new CalendarTarget("TARGET"); private static final InterestRateFutureSecurityDefinition ERZ4_DEFINITION = new InterestRateFutureSecurityDefinition(LAST_TRADE_DATE, EURIBOR3M, NOTIONAL, FUTURE_FACTOR, NAME, TARGET); private static final ZonedDateTime EXPIRY_DATE = DateUtils.getUTCDate(2014, 11, 17); private static final double STRIKE_099 = 0.99; private static final boolean IS_CALL = true; private static final InterestRateFutureOptionMarginSecurityDefinition CALL_ERZ4_099_SEC_DEFINITION = new InterestRateFutureOptionMarginSecurityDefinition(ERZ4_DEFINITION, EXPIRY_DATE, STRIKE_099, IS_CALL); private static final InterestRateFutureOptionMarginSecurityDefinition PUT_ERZ4_099_SEC_DEFINITION = new InterestRateFutureOptionMarginSecurityDefinition(ERZ4_DEFINITION, EXPIRY_DATE, STRIKE_099, !IS_CALL); private static final int QUANTITY = 123; private static final ZonedDateTime TRADE_DATE = DateUtils.getUTCDate(2014, 3, 31); private static final double TRADE_PRICE = 0.01; private static final InterestRateFutureOptionMarginTransactionDefinition CALL_ERZ4_099_TRA_1_DEFINITION = new InterestRateFutureOptionMarginTransactionDefinition(CALL_ERZ4_099_SEC_DEFINITION, QUANTITY, TRADE_DATE, TRADE_PRICE); private static final InterestRateFutureOptionMarginTransactionDefinition CALL_ERZ4_099_TRA_2_DEFINITION = new InterestRateFutureOptionMarginTransactionDefinition(CALL_ERZ4_099_SEC_DEFINITION, QUANTITY, TRADE_DATE.minusDays(1), TRADE_PRICE); private static final InterestRateFutureOptionMarginTransactionDefinition PUT_ERZ4_099_TRA_1_DEFINITION = new InterestRateFutureOptionMarginTransactionDefinition(PUT_ERZ4_099_SEC_DEFINITION, QUANTITY, TRADE_DATE, TRADE_PRICE); private static final InterestRateFutureTransactionDefinition ERZ4_TRA_STRIKE_DEFINITION = new InterestRateFutureTransactionDefinition(ERZ4_DEFINITION, QUANTITY, TRADE_DATE, STRIKE_099); private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2014, 3, 31); private static final double REFERENCE_PRICE = 0.02; private static final InterestRateFutureOptionMarginTransaction CALL_ERZ4_099_TRA_1 = CALL_ERZ4_099_TRA_1_DEFINITION.toDerivative(REFERENCE_DATE, REFERENCE_PRICE); private static final InterestRateFutureOptionMarginTransaction CALL_ERZ4_099_TRA_2 = CALL_ERZ4_099_TRA_2_DEFINITION.toDerivative(REFERENCE_DATE, REFERENCE_PRICE); private static final InterestRateFutureOptionMarginTransaction PUT_ERZ4_099_TRA_1 = PUT_ERZ4_099_TRA_1_DEFINITION.toDerivative(REFERENCE_DATE, REFERENCE_PRICE); private static final InterestRateFutureTransaction ERZ4_TRA_STRIKE = ERZ4_TRA_STRIKE_DEFINITION.toDerivative(REFERENCE_DATE, 0.0); /** Black surface expiry/log-moneyness */ final private static InterpolatedDoublesSurface BLACK_SURFACE_LOGMONEY = StandardDataSetsBlack.blackSurfaceExpiryLogMoneyness(); /** EUR curves */ final private static MulticurveProviderDiscount MULTICURVE = MulticurveProviderDiscountDataSets.createMulticurveEUR(); final private static BlackSTIRFuturesExpLogMoneynessProviderDiscount MULTICURVE_BLACK = new BlackSTIRFuturesExpLogMoneynessProviderDiscount(MULTICURVE, BLACK_SURFACE_LOGMONEY, EURIBOR3M); /** Methods and calculators */ private static final InterestRateFutureOptionMarginSecurityBlackSTIRFuturesMethod METHOD_OPT_SEC = InterestRateFutureOptionMarginSecurityBlackSTIRFuturesMethod.getInstance(); private static final FuturesTransactionBlackSTIRFuturesMethod METHOD_OPT_TRA = new FuturesTransactionBlackSTIRFuturesMethod(); private static final FuturesTransactionMulticurveMethod METHOD_FUT_TRA = new FuturesTransactionMulticurveMethod(); private static final PresentValueBlackSTIRFutureOptionCalculator PVBFOC = PresentValueBlackSTIRFutureOptionCalculator.getInstance(); private static final PresentValueCurveSensitivityBlackSTIRFutureOptionCalculator PVCSBFOC = PresentValueCurveSensitivityBlackSTIRFutureOptionCalculator.getInstance(); private static final double SHIFT_FD = 1.0E-7; private static final ParameterSensitivityParameterCalculator<BlackSTIRFuturesProviderInterface> PSSFC = new ParameterSensitivityParameterCalculator<>(PVCSBFOC); private static final ParameterSensitivityBlackSTIRFuturesExpLogMoneynessDiscountInterpolatedFDCalculator PSSFC_FD = new ParameterSensitivityBlackSTIRFuturesExpLogMoneynessDiscountInterpolatedFDCalculator(PVBFOC, SHIFT_FD); /** Tolerances */ private static final double TOLERANCE_PV = 1.0E-3; private static final double TOLERANCE_PV_DELTA = 1.0E-1; public void presentValue() { final MultipleCurrencyAmount pvComputed1 = METHOD_OPT_TRA.presentValue(CALL_ERZ4_099_TRA_1, MULTICURVE_BLACK); final double priceOpt1 = METHOD_OPT_SEC.price(CALL_ERZ4_099_TRA_1.getUnderlyingSecurity(), MULTICURVE_BLACK); final double pvExpected1 = (priceOpt1 - TRADE_PRICE) * ERZ4_DEFINITION.getNotional() * ERZ4_DEFINITION.getPaymentAccrualFactor() * QUANTITY; assertEquals("BondFuturesOptionMarginTransactionBlackFlatMethod: present value", pvExpected1, pvComputed1.getAmount(ERZ4_DEFINITION.getCurrency()), TOLERANCE_PV); assertTrue("BondFuturesOptionMarginTransactionBlackFlatMethod: present value", pvComputed1.size() == 1); final MultipleCurrencyAmount pvCalculator = CALL_ERZ4_099_TRA_1.accept(PVBFOC, MULTICURVE_BLACK); assertEquals("BondFuturesOptionMarginTransactionBlackFlatMethod: present value", pvExpected1, pvCalculator.getAmount(EUR), TOLERANCE_PV); final MultipleCurrencyAmount pvComputed2 = METHOD_OPT_TRA.presentValue(CALL_ERZ4_099_TRA_2, MULTICURVE_BLACK); final double priceOpt2 = METHOD_OPT_SEC.price(CALL_ERZ4_099_TRA_2.getUnderlyingSecurity(), MULTICURVE_BLACK); final double pvExpected2 = (priceOpt2 - REFERENCE_PRICE) * ERZ4_DEFINITION.getNotional() * ERZ4_DEFINITION.getPaymentAccrualFactor() * QUANTITY; assertEquals("STIRFuturesOptionMarginTransactionBlackExpLogMoneynessMethod: present value", pvExpected2, pvComputed2.getAmount(ERZ4_DEFINITION.getCurrency()), TOLERANCE_PV); } public void presentValuePuCallParity() { final MultipleCurrencyAmount priceFutures = METHOD_FUT_TRA.presentValue(ERZ4_TRA_STRIKE, MULTICURVE); final MultipleCurrencyAmount pvCallComputed = METHOD_OPT_TRA.presentValue(CALL_ERZ4_099_TRA_1, MULTICURVE_BLACK); final MultipleCurrencyAmount pvPutComputed = METHOD_OPT_TRA.presentValue(PUT_ERZ4_099_TRA_1, MULTICURVE_BLACK); assertEquals("STIRFuturesOptionMarginTransactionBlackExpLogMoneynessMethod: put call parity present value", pvCallComputed.getAmount(EURIBOR3M.getCurrency()) - pvPutComputed.getAmount(EURIBOR3M.getCurrency()), priceFutures.getAmount(EURIBOR3M.getCurrency()), TOLERANCE_PV); } /** * Test using the flat smile. This is required for a finite difference comparison, as the model is the Black sensitivity and a full bump and re-price with * volatility interpolation would change the volatility (and the risk). */ @Test public void presentValueCurveSensitivity() { final MultipleCurrencyParameterSensitivity pvpsComputed = PSSFC.calculateSensitivity(CALL_ERZ4_099_TRA_1, MULTICURVE_BLACK); final MultipleCurrencyParameterSensitivity pvpsFD = PSSFC_FD.calculateSensitivity(CALL_ERZ4_099_TRA_1, MULTICURVE_BLACK); AssertSensitivityObjects.assertEquals("BondFuturesOptionMarginTransactionBlackFlatMethod: presentValueCurveSensitivity", pvpsFD, pvpsComputed, TOLERANCE_PV_DELTA); } /** * Compare the computed Black sensitivity (vega) with a finite difference approximation. */ public void presentValueBlackSensitivity() { final double shiftVega = 1.0E-6; final InterpolatedDoublesSurface shiftedSurfacePlus = StandardDataSetsBlack.blackSurfaceExpiryLogMoneyness(shiftVega); final InterpolatedDoublesSurface shiftedSurfaceMinus = StandardDataSetsBlack.blackSurfaceExpiryLogMoneyness(-shiftVega); final BlackSTIRFuturesExpLogMoneynessProvider blackShiftedPlus = new BlackSTIRFuturesExpLogMoneynessProvider(MULTICURVE, shiftedSurfacePlus, EURIBOR3M); final BlackSTIRFuturesExpLogMoneynessProvider blackShiftedMinus = new BlackSTIRFuturesExpLogMoneynessProvider(MULTICURVE, shiftedSurfaceMinus, EURIBOR3M); final MultipleCurrencyAmount pvP = METHOD_OPT_TRA.presentValue(CALL_ERZ4_099_TRA_1, blackShiftedPlus); final MultipleCurrencyAmount pvM = METHOD_OPT_TRA.presentValue(CALL_ERZ4_099_TRA_1, blackShiftedMinus); final double vegaExpected = (pvP.getAmount(CALL_ERZ4_099_TRA_1.getCurrency()) - pvM.getAmount(CALL_ERZ4_099_TRA_1.getCurrency())) / (2 * shiftVega); final double vegaComputed = METHOD_OPT_TRA.presentValueBlackSensitivity(CALL_ERZ4_099_TRA_1, MULTICURVE_BLACK).getSensitivity().toSingleValue(); assertEquals("STIRFuturesOptionMarginTransactionBlackExpLogMoneynessMethod: present value Black sensitivity", vegaExpected, vegaComputed, TOLERANCE_PV_DELTA); } }