/** * Copyright (C) 2012 - 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.ZonedDateTime; import com.opengamma.analytics.financial.instrument.future.BondFuturesDataSets; import com.opengamma.analytics.financial.instrument.future.BondFuturesOptionPremiumSecurityDefinition; import com.opengamma.analytics.financial.instrument.future.BondFuturesSecurityDefinition; import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesOptionPremiumSecurity; import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesSecurity; import com.opengamma.analytics.financial.legalentity.LegalEntity; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackPriceFunction; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption; import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository; import com.opengamma.analytics.financial.provider.description.IssuerProviderDiscountDataSets; import com.opengamma.analytics.financial.provider.description.StandardDataSetsBlack; import com.opengamma.analytics.financial.provider.description.interestrate.BlackBondFuturesExpStrikeProvider; import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderDiscount; import com.opengamma.analytics.math.surface.InterpolatedDoublesSurface; import com.opengamma.util.test.TestGroup; import com.opengamma.util.time.DateUtils; /** * Tests related to the pricing methods for bond future options with up-front premium payment. */ @Test(groups = TestGroup.UNIT) public class BondFuturesOptionPremiumSecurityBlackExpStrikeMethodTest { /** Bond future option: JGB */ private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2015, 5, 12); private static final BondFuturesSecurityDefinition JBM5_DEFINITION = BondFuturesDataSets.JBM5_DEFINITION; private static final BondFuturesSecurity JBM5 = JBM5_DEFINITION.toDerivative(REFERENCE_DATE); private static final double STRIKE_147 = 1.47; // To be close to ATM for the data set used. private static final ZonedDateTime EXPIRY_DATE_OPT = DateUtils.getUTCDate(2015, 5, 31); private static final boolean IS_CALL = true; private static final BondFuturesOptionPremiumSecurityDefinition CALL_JB_147_DEFINITION = new BondFuturesOptionPremiumSecurityDefinition(JBM5_DEFINITION, EXPIRY_DATE_OPT, STRIKE_147, IS_CALL); private static final BondFuturesOptionPremiumSecurityDefinition PUT_JB_147_DEFINITION = new BondFuturesOptionPremiumSecurityDefinition(JBM5_DEFINITION, EXPIRY_DATE_OPT, STRIKE_147, !IS_CALL); private static final BondFuturesOptionPremiumSecurity CALL_JB_147 = CALL_JB_147_DEFINITION.toDerivative(REFERENCE_DATE); private static final BondFuturesOptionPremiumSecurity PUT_JB_147 = PUT_JB_147_DEFINITION.toDerivative(REFERENCE_DATE); /** Black surface expiry/log-moneyness */ final private static InterpolatedDoublesSurface BLACK_SURFACE_EXP_STRIKE = StandardDataSetsBlack.BLACK_SURFACE_BND_EXP_STRIKE; /** Curves for a specific issuer name */ private static final IssuerProviderDiscount ISSUER_SPECIFIC_MULTICURVES = IssuerProviderDiscountDataSets.ISSUER_SPECIFIC_MULTICURVE_JP; /** The legal entity */ private static final LegalEntity LEGAL_ENTITY_JAPAN = IssuerProviderDiscountDataSets.JP_GOVT; /** The Black bond futures provider **/ //TODO: Change to strike private static final BlackBondFuturesExpStrikeProvider BLACK_EXP_STRIKE_BNDFUT = new BlackBondFuturesExpStrikeProvider(ISSUER_SPECIFIC_MULTICURVES, BLACK_SURFACE_EXP_STRIKE, LEGAL_ENTITY_JAPAN); /** Methods and calculators */ private static final BondFuturesOptionPremiumSecurityBlackBondFuturesMethod METHOD_OPT = BondFuturesOptionPremiumSecurityBlackBondFuturesMethod.getInstance(); private static final BondFuturesSecurityDiscountingMethod METHOD_FUTURE = BondFuturesSecurityDiscountingMethod.getInstance(); private static final BlackPriceFunction BLACK_FUNCTION = new BlackPriceFunction(); /** Tolerances */ private static final double TOLERANCE_RATE = 1.0E-10; private static final double TOLERANCE_DELTA = 1.0E-8; public void impliedVolatility() { final double strike = STRIKE_147; final double expiry = CALL_JB_147.getExpirationTime(); final double ivExpected = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, strike); final double ivComputed = METHOD_OPT.impliedVolatility(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackSurfaceMethod: impliedVolatility", ivExpected, ivComputed, TOLERANCE_RATE); } public void futurePrice() { final double priceExpected = METHOD_FUTURE.price(JBM5, ISSUER_SPECIFIC_MULTICURVES); final double priceComputed = METHOD_OPT.underlyingFuturePrice(CALL_JB_147, ISSUER_SPECIFIC_MULTICURVES); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price", priceExpected, priceComputed, TOLERANCE_RATE); } public void priceFromFuturesPrice() { final double price = 1.465; final EuropeanVanillaOption option = new EuropeanVanillaOption(STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double logmoney = Math.log(STRIKE_147 / price); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, logmoney); double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider().getDiscountFactor(JBM5_DEFINITION.getCurrency(), expiry); final BlackFunctionData dataBlack = new BlackFunctionData(price, df, volatility); final double priceExpected = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack); final double priceComputed = METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, price); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price", priceExpected, priceComputed, TOLERANCE_RATE); } public void priceFromCurves() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final double priceExpected = METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, priceFutures); final double priceComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price", priceExpected, priceComputed, TOLERANCE_RATE); } public void putCallParity() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final double priceCallComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); final double pricePutComputed = METHOD_OPT.price(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT); double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime()); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: put call parity price", priceCallComputed - pricePutComputed, (priceFutures - STRIKE_147) * df, TOLERANCE_RATE); } public void vega() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final EuropeanVanillaOption option = new EuropeanVanillaOption(STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147); double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime()); final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility); final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); final double vegaExpected = priceAD[2]; final double vegaComputed = METHOD_OPT.vega(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: Black parameters sensitivity", vegaExpected, vegaComputed, TOLERANCE_RATE); } public void delta() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final EuropeanVanillaOption option = new EuropeanVanillaOption(STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147); double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime()); final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility); final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); final double deltaCallExpected = priceAD[1]; final double deltaCallComputed = METHOD_OPT.delta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta", deltaCallExpected, deltaCallComputed, TOLERANCE_DELTA); final double deltaPutComputed = METHOD_OPT.delta(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta", deltaCallExpected - deltaPutComputed, df, TOLERANCE_DELTA); } public void gamma() { final double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); final EuropeanVanillaOption option = new EuropeanVanillaOption(STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall()); final double expiry = CALL_JB_147.getExpirationTime(); final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147); double df = ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider() .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime()); final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility); final double[] firstDerivs = new double[3]; final double[][] secondDerivs = new double[3][3]; BLACK_FUNCTION.getPriceAdjoint2(option, dataBlack, firstDerivs, secondDerivs); final double gammaCallExpected = secondDerivs[0][0]; final double gammaCallComputed = METHOD_OPT.gamma(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: gamma", gammaCallExpected, gammaCallComputed, TOLERANCE_DELTA); } public void theta() { double priceFutures = METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES); double expiry = CALL_JB_147.getExpirationTime(); double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147); double rate = -Math.log(ISSUER_SPECIFIC_MULTICURVES.getMulticurveProvider() .getDiscountFactor(CALL_JB_147.getCurrency(), CALL_JB_147.getExpirationTime())) / CALL_JB_147.getExpirationTime(); double thetaCallExpected = BlackFormulaRepository.theta(priceFutures, STRIKE_147, CALL_JB_147.getExpirationTime(), volatility, CALL_JB_147.isCall(), rate); double thetaCallComputed = METHOD_OPT.theta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT); assertEquals("BondFuturesOptionMarginSecurityBlackFlatMethod: theta", thetaCallExpected, thetaCallComputed, TOLERANCE_DELTA); } }