ForexOptionVanillaBlackSmileMethod { public MultipleCurrencyAmount currencyExposure(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves) { ArgumentChecker.notNull(optionForex, "Forex option"); ArgumentChecker.notNull(smileMulticurves, "Smile"); ArgumentChecker.isTrue(smileMulticurves.checkCurrencies(optionForex.getCurrency1(), optionForex.getCurrency2()), "Option currencies not compatible with smile data"); final MulticurveProviderInterface multicurves = smileMulticurves.getMulticurveProvider(); final double dfDomestic = multicurves.getDiscountFactor(optionForex.getCurrency2(), optionForex.getUnderlyingForex().getPaymentTime()); final double dfForeign = multicurves.getDiscountFactor(optionForex.getCurrency1(), optionForex.getUnderlyingForex().getPaymentTime()); final double spot = multicurves.getFxRate(optionForex.getCurrency1(), optionForex.getCurrency2()); final double forward = spot * dfForeign / dfDomestic; final double volatility = smileMulticurves.getVolatility(optionForex.getCurrency1(), optionForex.getCurrency2(), optionForex.getTimeToExpiry(), optionForex.getStrike(), forward); final BlackFunctionData dataBlack = new BlackFunctionData(forward, dfDomestic, volatility); final double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(optionForex, dataBlack); final double sign = (optionForex.isLong() ? 1.0 : -1.0); final double price = priceAdjoint[0] * Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * sign; final double deltaSpot = priceAdjoint[1] * dfForeign / dfDomestic; MultipleCurrencyAmount currencyExposure = MultipleCurrencyAmount.of(optionForex.getUnderlyingForex().getCurrency1(), deltaSpot * Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * sign); currencyExposure = currencyExposure.plus(optionForex.getUnderlyingForex().getCurrency2(), -deltaSpot * Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * spot * sign + price); return currencyExposure; } private  ForexOptionVanillaBlackSmileMethod(); static ForexOptionVanillaBlackSmileMethod getInstance(); MultipleCurrencyAmount presentValue(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double impliedVolatility(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); MultipleCurrencyAmount currencyExposure(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount delta(
      ForexOptionVanilla optionForex,
      BlackForexSmileProviderInterface smileMulticurves,
      boolean directQuote); double deltaRelative(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); double deltaRelativeSpot(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); double spotDeltaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double forwardDeltaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double gammaRelative(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); double gammaRelativeSpot(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); CurrencyAmount gamma(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); double spotGammaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double forwardGammaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount gammaSpot(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves, final boolean directQuote); CurrencyAmount thetaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double forwardDriftlessThetaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double forwardVegaTheoretical(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount vanna(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount vomma(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); double forwardForexRate(final ForexOptionVanilla optionForex, final MulticurveProviderInterface multicurves); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final ForexOptionVanilla optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilityNodeSensitivityDataBundle presentValueBlackVolatilityNodeSensitivity(final ForexOptionVanilla optionForex,
      final BlackForexSmileProviderInterface smileMulticurves);  }
@Test public void currencyExposure() { final double strike = 1.45; final boolean isCall = true; final boolean isLong = true; final double notional = 100000000; final ZonedDateTime payDate = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR); final ZonedDateTime expDate = ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR); final double timeToExpiry = TimeCalculator.getTimeBetween(REFERENCE_DATE, expDate); final ForexDefinition forexUnderlyingDefinition = new ForexDefinition(EUR, USD, payDate, notional, strike); final ForexOptionVanillaDefinition forexOptionDefinitionCall = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionVanillaDefinition forexOptionDefinitionPut = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong); final ForexOptionVanilla forexOptionCall = forexOptionDefinitionCall.toDerivative(REFERENCE_DATE); final ForexOptionVanilla forexOptionPut = forexOptionDefinitionPut.toDerivative(REFERENCE_DATE); final double dfDomestic = MULTICURVES.getDiscountFactor(USD, TimeCalculator.getTimeBetween(REFERENCE_DATE, payDate)); final double dfForeign = MULTICURVES.getDiscountFactor(EUR, TimeCalculator.getTimeBetween(REFERENCE_DATE, payDate)); final double forward = SPOT * dfForeign / dfDomestic; final double volatility = SMILE_TERM.getVolatility(Triple.of(timeToExpiry, strike, forward)); final BlackFunctionData dataBlack = new BlackFunctionData(forward, dfDomestic, volatility); final double[] priceAdjointCall = BLACK_FUNCTION.getPriceAdjoint(forexOptionCall, dataBlack); final double[] priceAdjointPut = BLACK_FUNCTION.getPriceAdjoint(forexOptionPut, dataBlack); final double deltaForwardCall = priceAdjointCall[1]; final double deltaForwardPut = priceAdjointPut[1]; final double deltaSpotCall = deltaForwardCall * dfForeign / dfDomestic; final double deltaSpotPut = deltaForwardPut * dfForeign / dfDomestic; final MultipleCurrencyAmount priceComputedCall = METHOD_OPTION.presentValue(forexOptionCall, SMILE_MULTICURVES); final MultipleCurrencyAmount priceComputedPut = METHOD_OPTION.presentValue(forexOptionPut, SMILE_MULTICURVES); final MultipleCurrencyAmount currencyExposureCallComputed = METHOD_OPTION.currencyExposure(forexOptionCall, SMILE_MULTICURVES); assertEquals("Forex vanilla option: currency exposure foreign - call", deltaSpotCall * notional, currencyExposureCallComputed.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure domestic - call", -deltaSpotCall * notional * SPOT + priceComputedCall.getAmount(USD), currencyExposureCallComputed.getAmount(USD), 1E-2); final MultipleCurrencyAmount currencyExposurePutComputed = METHOD_OPTION.currencyExposure(forexOptionPut, SMILE_MULTICURVES); assertEquals("Forex vanilla option: currency exposure foreign- put", deltaSpotPut * notional, currencyExposurePutComputed.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure domestic - put", -deltaSpotPut * notional * SPOT + priceComputedPut.getAmount(USD), currencyExposurePutComputed.getAmount(USD), 1E-2); }
@Test public void currencyExposureCallPut() { final double strike = 1.45; final boolean isCall = true; final boolean isLong = true; final double notional = 100000000; final ZonedDateTime payDate = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR); final ZonedDateTime expDate = ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR); final ForexDefinition forexEURUSDDefinition = new ForexDefinition(EUR, USD, payDate, notional, strike); final ForexDefinition forexUSDEURDefinition = new ForexDefinition(USD, EUR, payDate, -notional * strike, 1.0 / strike); final ForexOptionVanillaDefinition callEURUSDDefinition = new ForexOptionVanillaDefinition(forexEURUSDDefinition, expDate, isCall, isLong); final ForexOptionVanillaDefinition putUSDEURDefinition = new ForexOptionVanillaDefinition(forexUSDEURDefinition, expDate, isCall, isLong); final ForexOptionVanilla callEURUSD = callEURUSDDefinition.toDerivative(REFERENCE_DATE); final ForexOptionVanilla putUSDEUR = putUSDEURDefinition.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount pvCallEURUSD = METHOD_OPTION.currencyExposure(callEURUSD, SMILE_MULTICURVES); final MultipleCurrencyAmount pvPutUSDEUR = METHOD_OPTION.currencyExposure(putUSDEUR, SMILE_MULTICURVES); assertEquals("Forex vanilla option: currency exposure", pvCallEURUSD.getAmount(EUR), pvPutUSDEUR.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure", pvCallEURUSD.getAmount(USD), pvPutUSDEUR.getAmount(USD), TOLERANCE_PV); }
@Test public void currencyExposurePutCallParity() { final double strike = 1.45; final boolean isCall = true; final boolean isLong = true; final double notional = 100000000; final ZonedDateTime payDate = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR); final ZonedDateTime expDate = ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR); final ForexDefinition forexUnderlyingDefinition = new ForexDefinition(EUR, USD, payDate, notional, strike); final ForexOptionVanillaDefinition forexOptionDefinitionCall = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionVanillaDefinition forexOptionDefinitionPut = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong); final ForexOptionVanilla forexOptionCall = forexOptionDefinitionCall.toDerivative(REFERENCE_DATE); final ForexOptionVanilla forexOptionPut = forexOptionDefinitionPut.toDerivative(REFERENCE_DATE); final Forex forexForward = forexUnderlyingDefinition.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount currencyExposureCall = METHOD_OPTION.currencyExposure(forexOptionCall, SMILE_MULTICURVES); final MultipleCurrencyAmount currencyExposurePut = METHOD_OPTION.currencyExposure(forexOptionPut, SMILE_MULTICURVES); final MultipleCurrencyAmount currencyExposureForward = METHOD_DISC.currencyExposure(forexForward, MULTICURVES); assertEquals("Forex vanilla option: currency exposure put/call parity foreign", currencyExposureForward.getAmount(EUR), currencyExposureCall.getAmount(EUR) - currencyExposurePut.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure put/call parity domestic", currencyExposureForward.getAmount(USD), currencyExposureCall.getAmount(USD) - currencyExposurePut.getAmount(USD), TOLERANCE_PV); }
@Test public void currencyExposureMethodVsCalculator() { final double strike = 1.45; final boolean isCall = true; final boolean isLong = true; final double notional = 100000000; final ZonedDateTime payDate = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofMonths(9), BUSINESS_DAY, CALENDAR); final ZonedDateTime expDate = ScheduleCalculator.getAdjustedDate(payDate, -SETTLEMENT_DAYS, CALENDAR); final ForexDefinition forexUnderlyingDefinition = new ForexDefinition(EUR, USD, payDate, notional, strike); final ForexOptionVanillaDefinition forexOptionDefinition = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionVanilla forexOption = forexOptionDefinition.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount ceMethod = METHOD_OPTION.currencyExposure(forexOption, SMILE_MULTICURVES); final MultipleCurrencyAmount ceCalculator = forexOption.accept(CEFBC, SMILE_MULTICURVES); assertEquals("Forex vanilla option: currency exposure Method vs Calculator", ceMethod.getAmount(EUR), ceCalculator.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure Method vs Calculator", ceMethod.getAmount(USD), ceCalculator.getAmount(USD), TOLERANCE_PV); }