/** * This calculates the sensitivity of the present value (PV) to the lognormal Black implied * volatities at the knot points of the surface. * * <p>The return format is a DoubleMatrix2D with rows equal to the total number of maturities and * columns equal to the number of strikes. * * <p>Note - the change of the surface due to the movement of a single node is * interpolator-dependent, so an instrument may have non-local sensitivity * * @param swap the VarianceSwap * @param market the VarianceSwapDataBundle * @param shift Size of shift made in centered-finite difference approximation. e.g. 1% would be * 0.01, and 1bp 0.0001 * @return A NodalDoublesSurface with same axes as market.getVolatilitySurface(). Contains * currency amount per unit amount change in the black volatility of each node */ public NodalDoublesSurface calcBlackVegaForEntireSurface( final VarianceSwap swap, final VarianceSwapDataBundle market, final double shift) { Validate.notNull(swap, "null VarianceSwap"); Validate.notNull(market, "null VarianceSwapDataBundle"); // Unpack market data final Surface<Double, Double, Double> surface = market.getVolatilitySurface().getSurface(); Validate.isTrue( surface instanceof InterpolatedDoublesSurface, "Currently will only accept a Equity VolatilitySurfaces based on an InterpolatedDoublesSurface"); final InterpolatedDoublesSurface blackSurf = (InterpolatedDoublesSurface) surface; final Double[] maturities = blackSurf.getXData(); final Double[] strikes = blackSurf.getYData(); final int nNodes = maturities.length; Validate.isTrue(nNodes == strikes.length); // Bump and reprice final Double[] vegas = new Double[nNodes]; for (int j = 0; j < nNodes; j++) { vegas[j] = calcBlackVegaForSinglePoint(swap, market, maturities[j], strikes[j], shift); } return new NodalDoublesSurface(maturities, strikes, vegas); }
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); }
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 static InterpolatedDoublesSurface createBlackSurfaceExpiryTenorShift(final double shift) { return InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {2, 2, 2, 10, 10, 10}, new double[] { 0.35 + shift, 0.34 + shift, 0.25 + shift, 0.30 + shift, 0.25 + shift, 0.20 + shift }, INTERPOLATOR_LINEAR_2D); }
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); }
/** * Create the same surface as createBlackSwaptionEUR6() but with one volatility shifted. * * @param index The index of the shifted volatility. * @param shift The shift. * @return The surface. */ public static BlackFlatSwaptionParameters createBlackSwaptionEUR6Shift( final int index, final double shift) { final double[] vol = new double[] {0.35, 0.34, 0.25, 0.30, 0.25, 0.20}; vol[index] += shift; final InterpolatedDoublesSurface surfaceShift = InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {2, 2, 2, 10, 10, 10}, vol, INTERPOLATOR_LINEAR_2D); return new BlackFlatSwaptionParameters(surfaceShift, EUR1YEURIBOR6M); }
public static InterpolatedDoublesSurface createBlackSurfaceExpiryStrikeShift(final double shift) { return InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {0.01, 0.01, 0.01, 0.02, 0.02, 0.02, 0.03, 0.03, 0.03}, new double[] { 0.35 + shift, 0.34 + shift, 0.25 + shift, 0.30 + shift, 0.25 + shift, 0.20 + shift, 0.28 + shift, 0.23 + shift, 0.18 + shift }, INTERPOLATOR_LINEAR_2D); }
@Override public Set<ComputedValue> execute( final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target, final Set<ValueRequirement> desiredValues) { final Clock snapshotClock = executionContext.getValuationClock(); final ZonedDateTime now = ZonedDateTime.now(snapshotClock); final Object volatilitySurfaceDataObject = inputs.getValue(_requirement); if (volatilitySurfaceDataObject == null) { throw new OpenGammaRuntimeException("Could not get " + _requirement); } @SuppressWarnings("unchecked") final VolatilitySurfaceData<LocalDate, Double> volatilitySurfaceData = (VolatilitySurfaceData<LocalDate, Double>) volatilitySurfaceDataObject; final int n = volatilitySurfaceData.getXs().length; final int m = volatilitySurfaceData.getYs().length; final DoubleArrayList t = new DoubleArrayList(); final DoubleArrayList k = new DoubleArrayList(); final DoubleArrayList sigma = new DoubleArrayList(); final LocalDate[] xDates = volatilitySurfaceData.getXs(); final Double[] y = volatilitySurfaceData.getYs(); for (int i = 0; i < n; i++) { final Double time = DateUtils.getDifferenceInYears(now.toLocalDate(), xDates[i]); for (int j = 0; j < m; j++) { final Double strike = y[j]; final Double vol = volatilitySurfaceData.getVolatility(xDates[i], y[j]); if (time != null && strike != null && vol != null) { t.add(time); k.add(strike); sigma.add(vol); } } } final Surface<Double, Double, Double> surface = InterpolatedDoublesSurface.from( t.toDoubleArray(), k.toDoubleArray(), sigma.toDoubleArray(), _interpolator); final VolatilitySurface volatilitySurface = new VolatilitySurface(surface); return Collections.singleton(new ComputedValue(_result, volatilitySurface)); }
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); }
/** Sets of market data used in tests. */ public class TestsDataSetsBlack { private static final Interpolator1D LINEAR_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); private static final GridInterpolator2D INTERPOLATOR_LINEAR_2D = new GridInterpolator2D(LINEAR_FLAT, LINEAR_FLAT); private static final Calendar CALENDAR = new MondayToFridayCalendar("TARGET"); private static final GeneratorSwapFixedIborMaster GENERATOR_SWAP_MASTER = GeneratorSwapFixedIborMaster.getInstance(); private static final GeneratorSwapFixedIbor EUR1YEURIBOR6M = GENERATOR_SWAP_MASTER.getGenerator("EUR1YEURIBOR6M", CALENDAR); private static final GeneratorSwapFixedIbor EUR1YEURIBOR3M = GENERATOR_SWAP_MASTER.getGenerator("EUR1YEURIBOR3M", CALENDAR); private static final InterpolatedDoublesSurface BLACK_SURFACE_EXP_TEN = InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {2, 2, 2, 10, 10, 10}, new double[] {0.35, 0.34, 0.25, 0.30, 0.25, 0.20}, INTERPOLATOR_LINEAR_2D); private static final InterpolatedDoublesSurface BLACK_SURFACE_EXP_STR = InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {0.01, 0.01, 0.01, 0.02, 0.02, 0.02, 0.03, 0.03, 0.03}, new double[] {0.35, 0.34, 0.25, 0.30, 0.25, 0.20, 0.28, 0.23, 0.18}, INTERPOLATOR_LINEAR_2D); private static final BlackFlatSwaptionParameters BLACK_SWAPTION_EUR6 = new BlackFlatSwaptionParameters(BLACK_SURFACE_EXP_TEN, EUR1YEURIBOR6M); private static final BlackFlatSwaptionParameters BLACK_SWAPTION_EUR3 = new BlackFlatSwaptionParameters(BLACK_SURFACE_EXP_TEN, EUR1YEURIBOR3M); public static InterpolatedDoublesSurface createBlackSurfaceExpiryTenor() { return BLACK_SURFACE_EXP_TEN; } public static InterpolatedDoublesSurface createBlackSurfaceExpiryStrike() { return BLACK_SURFACE_EXP_STR; } public static InterpolatedDoublesSurface createBlackSurfaceExpiryTenorShift(final double shift) { return InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {2, 2, 2, 10, 10, 10}, new double[] { 0.35 + shift, 0.34 + shift, 0.25 + shift, 0.30 + shift, 0.25 + shift, 0.20 + shift }, INTERPOLATOR_LINEAR_2D); } public static InterpolatedDoublesSurface createBlackSurfaceExpiryStrikeShift(final double shift) { return InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {0.01, 0.01, 0.01, 0.02, 0.02, 0.02, 0.03, 0.03, 0.03}, new double[] { 0.35 + shift, 0.34 + shift, 0.25 + shift, 0.30 + shift, 0.25 + shift, 0.20 + shift, 0.28 + shift, 0.23 + shift, 0.18 + shift }, INTERPOLATOR_LINEAR_2D); } public static BlackFlatSwaptionParameters createBlackSwaptionEUR6() { return BLACK_SWAPTION_EUR6; } public static BlackFlatSwaptionParameters createBlackSwaptionEUR3() { return BLACK_SWAPTION_EUR3; } /** * Create the same surface as createBlackSwaptionEUR6() but with a given parallel shift. * * @param shift The shift. * @return The surface. */ public static BlackFlatSwaptionParameters createBlackSwaptionEUR6Shift(final double shift) { final InterpolatedDoublesSurface surfaceShift = createBlackSurfaceExpiryTenorShift(shift); return new BlackFlatSwaptionParameters(surfaceShift, EUR1YEURIBOR6M); } /** * Create the same surface as createBlackSwaptionEUR6() but with one volatility shifted. * * @param index The index of the shifted volatility. * @param shift The shift. * @return The surface. */ public static BlackFlatSwaptionParameters createBlackSwaptionEUR6Shift( final int index, final double shift) { final double[] vol = new double[] {0.35, 0.34, 0.25, 0.30, 0.25, 0.20}; vol[index] += shift; final InterpolatedDoublesSurface surfaceShift = InterpolatedDoublesSurface.from( new double[] {0.5, 1.0, 5.0, 0.5, 1.0, 5.0}, new double[] {2, 2, 2, 10, 10, 10}, vol, INTERPOLATOR_LINEAR_2D); return new BlackFlatSwaptionParameters(surfaceShift, EUR1YEURIBOR6M); } public static YieldCurveBundle createCurvesEUR() { final String discountingCurvename = "EUR Discounting"; final String forward3MCurveName = "Forward EURIBOR3M"; final String forward6MCurveName = "Forward EURIBOR6M"; final InterpolatedDoublesCurve dscC = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 20.0}, new double[] {0.0050, 0.0100, 0.0150, 0.0200, 0.0200, 0.0300}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, discountingCurvename); final InterpolatedDoublesCurve fwd3C = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 25.0}, new double[] {0.0070, 0.0120, 0.0165, 0.0215, 0.0210, 0.0310}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, forward3MCurveName); final InterpolatedDoublesCurve fwd6C = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 30.0}, new double[] {0.0075, 0.0125, 0.0170, 0.0220, 0.0212, 0.0312}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, forward6MCurveName); final YieldCurveBundle curves = new YieldCurveBundle(); curves.setCurve(discountingCurvename, YieldCurve.from(dscC)); curves.setCurve(forward3MCurveName, YieldCurve.from(fwd3C)); curves.setCurve(forward6MCurveName, YieldCurve.from(fwd6C)); return curves; } public static String[] curvesEURNames() { final String discountingCurvename = "EUR Discounting"; final String forward3MCurveName = "Forward EURIBOR3M"; final String forward6MCurveName = "Forward EURIBOR6M"; return new String[] {discountingCurvename, forward3MCurveName, forward6MCurveName}; } public static YieldCurveBundle createCurvesUSD() { final String discountingCurvename = "USD Discounting"; final String forward3MCurveName = "Forward USDLIBOR3M"; final String forward6MCurveName = "Forward USDLIBOR6M"; final InterpolatedDoublesCurve dscC = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 20.0}, new double[] {0.0050, 0.0100, 0.0150, 0.0200, 0.0200, 0.0300}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, discountingCurvename); final InterpolatedDoublesCurve fwd3C = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 25.0}, new double[] {0.0070, 0.0120, 0.0165, 0.0215, 0.0210, 0.0310}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, forward3MCurveName); final InterpolatedDoublesCurve fwd6C = new InterpolatedDoublesCurve( new double[] {0.05, 1.0, 2.0, 5.0, 10.0, 30.0}, new double[] {0.0075, 0.0125, 0.0170, 0.0220, 0.0212, 0.0312}, CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.DOUBLE_QUADRATIC, Interpolator1DFactory.LINEAR_EXTRAPOLATOR), true, forward6MCurveName); final YieldCurveBundle curves = new YieldCurveBundle(); curves.setCurve(discountingCurvename, YieldCurve.from(dscC)); curves.setCurve(forward3MCurveName, YieldCurve.from(fwd3C)); curves.setCurve(forward6MCurveName, YieldCurve.from(fwd6C)); return curves; } /** * Create a yield curve bundle with three curves. One called "Credit" with a constant rate of 5%, * one called "Discounting" with a constant rate of 4%, and one called "Forward" with a constant * rate of 4.5%. * * @return The yield curve bundle. */ public static YieldCurveBundle createCurvesBond() { final String CREDIT_CURVE_NAME = "Credit"; final String DISCOUNTING_CURVE_NAME = "Repo"; final String FORWARD_CURVE_NAME = "Forward"; final YieldAndDiscountCurve CURVE_5 = YieldCurve.from(ConstantDoublesCurve.from(0.05)); final YieldAndDiscountCurve CURVE_4 = YieldCurve.from(ConstantDoublesCurve.from(0.04)); final YieldAndDiscountCurve CURVE_45 = YieldCurve.from(ConstantDoublesCurve.from(0.045)); final YieldCurveBundle curves = new YieldCurveBundle(); curves.setCurve(CREDIT_CURVE_NAME, CURVE_5); curves.setCurve(DISCOUNTING_CURVE_NAME, CURVE_4); curves.setCurve(FORWARD_CURVE_NAME, CURVE_45); return curves; } public static YieldCurveWithBlackCubeBundle createCubesBondFutureOption() { return new YieldCurveWithBlackCubeBundle(BLACK_SURFACE_EXP_TEN, createCurvesBond()); } }
/** Tests for interest rate future options analytics functions using the black calculator. */ @Test(groups = TestGroup.UNIT) public class IRFutureOptionFnTest { private static final ZonedDateTime VALUATION_TIME = DateUtils.getUTCDate(2014, 1, 22); public static final LocalDate TRADE_DATE = LocalDate.of(2000, 1, 1); public static final OffsetTime TRADE_TIME = OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC); private static final LocalDate MARKET_DATA_DATE = LocalDate.of(2014, 2, 18); private static final double STD_TOLERANCE_PV = 1.0E-3; private IRFutureOptionFn _blackIRFutureOptionFn; private IRFutureOptionFn _normalIRFutureOptionFn; private InterestRateFutureSecurity _irFuture = createIRFuture(); private IRFutureOptionTrade _irFutureOptionTrade = createIRFutureOptionTrade(); private FunctionRunner _functionRunner; private static final CalculationArguments ARGS = CalculationArguments.builder() .valuationTime(VALUATION_TIME) .marketDataSpecification(LiveMarketDataSpecification.LIVE_SPEC) .build(); private static final Interpolator1D LINEAR_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); private static final GridInterpolator2D INTERPOLATOR_2D = new GridInterpolator2D(LINEAR_FLAT, LINEAR_FLAT); private static final InterpolatedDoublesSurface TEST_SURFACE = InterpolatedDoublesSurface.from( new double[] {.1, .2, .3}, new double[] {.1, .2, .3}, new double[] {.1, .2, .3}, INTERPOLATOR_2D); private static MarketDataEnvironment createSuppliedData() { LocalDateDoubleTimeSeries optionPrice = ImmutableLocalDateDoubleTimeSeries.of(VALUATION_TIME.toLocalDate(), 0.975); RawId<Double> optionRawId = RawId.of(ExternalSchemes.syntheticSecurityId("Test future option").toBundle()); MarketDataEnvironmentBuilder builder = new MarketDataEnvironmentBuilder(); builder.add(optionRawId, optionPrice); builder.add(VolatilitySurfaceId.of("TestExchange"), new VolatilitySurface(TEST_SURFACE)); builder.valuationTime(VALUATION_TIME); return builder.build(); } @BeforeClass public void setUpClass() { ImmutableMap<Class<?>, Object> components = generateComponents(); VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(Instant.now()); ServiceContext serviceContext = ServiceContext.of(components).with(VersionCorrectionProvider.class, vcProvider); ThreadLocalServiceContext.init(serviceContext); ComponentMap componentMap = ComponentMap.of(components); MarketDataSource marketDataSource = InterestRateMockSources.createMarketDataSource(MARKET_DATA_DATE, true); TestMarketDataFactory marketDataFactory = new TestMarketDataFactory(marketDataSource); ConfigLink<CurrencyMatrix> currencyMatrixLink = ConfigLink.resolved(componentMap.getComponent(CurrencyMatrix.class)); List<MarketDataBuilder> builders = MarketDataBuilders.standard(componentMap, "dataSource", currencyMatrixLink); MarketDataEnvironmentFactory environmentFactory = new MarketDataEnvironmentFactory(marketDataFactory, builders); _functionRunner = new FunctionRunner(environmentFactory); _normalIRFutureOptionFn = FunctionModel.build(IRFutureOptionFn.class, normalConfig(), componentMap); _blackIRFutureOptionFn = FunctionModel.build(IRFutureOptionFn.class, blackConfig(), componentMap); } private FunctionModelConfig blackConfig() { FunctionModelConfig config = config( arguments( function( MarketExposureSelector.class, argument( "exposureFunctions", ConfigLink.resolved(InterestRateMockSources.mockExposureFunctions()))), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1))))), implementations( IRFutureOptionFn.class, DefaultIRFutureOptionFn.class, IRFutureOptionCalculatorFactory.class, IRFutureOptionBlackCalculatorFactory.class, CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class, FXMatrixFn.class, DefaultFXMatrixFn.class, BlackSTIRFuturesProviderFn.class, TestBlackSTIRFuturesProviderFn.class, DiscountingMulticurveCombinerFn.class, ExposureFunctionsDiscountingMulticurveCombinerFn.class, CurveDefinitionFn.class, DefaultCurveDefinitionFn.class, CurveLabellingFn.class, CurveDefinitionCurveLabellingFn.class, CurveSpecificationFn.class, DefaultCurveSpecificationFn.class, CurveConstructionConfigurationSource.class, ConfigDBCurveConstructionConfigurationSource.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class, HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class, FixingsFn.class, DefaultFixingsFn.class, MarketDataFn.class, DefaultMarketDataFn.class, CurveSelector.class, MarketExposureSelector.class, DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class)); return config; } private FunctionModelConfig normalConfig() { FunctionModelConfig config = config( arguments( function( MarketExposureSelector.class, argument( "exposureFunctions", ConfigLink.resolved(InterestRateMockSources.mockExposureFunctions()))), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( TestIRFutureOptionNormalSurfaceProviderFn.class, argument("moneynessOnPrice", false)), function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1))))), implementations( IRFutureOptionFn.class, DefaultIRFutureOptionFn.class, IRFutureOptionCalculatorFactory.class, IRFutureOptionNormalCalculatorFactory.class, CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class, FXMatrixFn.class, DefaultFXMatrixFn.class, CurveDefinitionFn.class, DefaultCurveDefinitionFn.class, CurveLabellingFn.class, CurveDefinitionCurveLabellingFn.class, CurveSpecificationFn.class, DefaultCurveSpecificationFn.class, CurveConstructionConfigurationSource.class, ConfigDBCurveConstructionConfigurationSource.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class, HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class, FixingsFn.class, DefaultFixingsFn.class, MarketDataFn.class, DefaultMarketDataFn.class, CurveSelector.class, MarketExposureSelector.class, IRFutureOptionNormalSurfaceProviderFn.class, TestIRFutureOptionNormalSurfaceProviderFn.class, DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class)); return config; } private ImmutableMap<Class<?>, Object> generateComponents() { ImmutableMap.Builder<Class<?>, Object> builder = ImmutableMap.builder(); for (Map.Entry<Class<?>, Object> entry : InterestRateMockSources.generateBaseComponents().entrySet()) { Class<?> key = entry.getKey(); if (key.equals(SecuritySource.class)) { appendSecuritySource((SecuritySource) entry.getValue()); } builder.put(key, entry.getValue()); } return builder.build(); } // TODO - this assumes knowledge of the underlying source, should find a better way to do this private void appendSecuritySource(SecuritySource source) { SecurityMaster master = ((MasterSecuritySource) source).getMaster(); master.add(new SecurityDocument(_irFuture)); } private InterestRateFutureSecurity createIRFuture() { Expiry expiry = new Expiry(ZonedDateTime.of(LocalDate.of(2014, 6, 18), LocalTime.of(0, 0), ZoneOffset.UTC)); String tradingExchange = ""; String settlementExchange = ""; Currency currency = Currency.USD; double unitAmount = 1000; ExternalId underlyingId = InterestRateMockSources.getLiborIndexId(); String category = ""; InterestRateFutureSecurity irFuture = new InterestRateFutureSecurity( expiry, tradingExchange, settlementExchange, currency, unitAmount, underlyingId, category); // Need this for time series lookup ExternalId irFutureId = ExternalSchemes.syntheticSecurityId("Test future"); irFuture.setExternalIdBundle(irFutureId.toBundle()); return irFuture; } private IRFutureOptionTrade createIRFutureOptionTrade() { String exchange = "TestExchange"; ExerciseType exerciseType = new EuropeanExerciseType(); double pointValue = Double.NaN; boolean margined = true; double strike = 0.99; OptionType optionType = OptionType.PUT; ExternalId irFutureId = Iterables.getOnlyElement(_irFuture.getExternalIdBundle()); IRFutureOptionSecurity irFutureOption = new IRFutureOptionSecurity( exchange, _irFuture.getExpiry(), exerciseType, irFutureId, pointValue, margined, _irFuture.getCurrency(), strike, optionType); // Need this for time series lookup irFutureOption.setExternalIdBundle( ExternalSchemes.syntheticSecurityId("Test future option").toBundle()); Counterparty counterparty = new SimpleCounterparty(ExternalId.of(Counterparty.DEFAULT_SCHEME, "COUNTERPARTY")); BigDecimal tradeQuantity = BigDecimal.valueOf(1); SimpleTrade trade = new SimpleTrade(irFutureOption, tradeQuantity, counterparty, TRADE_DATE, TRADE_TIME); trade.setPremium(10.0); trade.setPremiumCurrency(Currency.USD); return new IRFutureOptionTrade(trade); } @Test public void testBlackPresentValue() { Result<MultipleCurrencyAmount> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<MultipleCurrencyAmount>>() { @Override public Result<MultipleCurrencyAmount> apply(Environment env) { return _blackIRFutureOptionFn.calculatePV(env, _irFutureOptionTrade); } }); assertSuccess(result); MultipleCurrencyAmount mca = result.getValue(); assertThat( mca.getCurrencyAmount(Currency.USD).getAmount(), is(closeTo(-972.460677, STD_TOLERANCE_PV))); } @Test public void testBlackBucketedZeroDelta() { Result<BucketedCurveSensitivities> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<BucketedCurveSensitivities>>() { @Override public Result<BucketedCurveSensitivities> apply(Environment env) { return _blackIRFutureOptionFn.calculateBucketedZeroIRDelta( env, _irFutureOptionTrade); } }); assertSuccess(result); } @Test public void testNormalPresentValue() { Result<MultipleCurrencyAmount> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<MultipleCurrencyAmount>>() { @Override public Result<MultipleCurrencyAmount> apply(Environment env) { return _normalIRFutureOptionFn.calculatePV(env, _irFutureOptionTrade); } }); assertSuccess(result); MultipleCurrencyAmount mca = result.getValue(); assertThat( mca.getCurrencyAmount(Currency.USD).getAmount(), is(closeTo(-902.7156551, STD_TOLERANCE_PV))); } @Test public void testNormalPrice() { Result<Double> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<Double>>() { @Override public Result<Double> apply(Environment env) { return _normalIRFutureOptionFn.calculateModelPrice(env, _irFutureOptionTrade); } }); assertSuccess(result); Double price = result.getValue(); assertThat(price, is(closeTo(0.072284344, STD_TOLERANCE_PV))); } @Test public void testNormalBucketedZeroDelta() { Result<BucketedCurveSensitivities> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<BucketedCurveSensitivities>>() { @Override public Result<BucketedCurveSensitivities> apply(Environment env) { return _normalIRFutureOptionFn.calculateBucketedZeroIRDelta( env, _irFutureOptionTrade); } }); assertSuccess(result); } }