ForexOptionDigitalBlackSmileMethod { public MultipleCurrencyAmount currencyExposure(final ForexOptionDigital 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 expiry = optionForex.getExpirationTime(); final Currency domesticCcy; final Currency foreignCcy; final double strike; final double dfDomestic; final double dfForeign; final double amount; final double omega; if (optionForex.payDomestic()) { domesticCcy = optionForex.getUnderlyingForex().getCurrency2(); foreignCcy = optionForex.getUnderlyingForex().getCurrency1(); dfDomestic = multicurves.getDiscountFactor(optionForex.getCurrency2(), optionForex.getUnderlyingForex().getPaymentTime()); dfForeign = multicurves.getDiscountFactor(optionForex.getCurrency1(), optionForex.getUnderlyingForex().getPaymentTime()); strike = optionForex.getStrike(); amount = Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency2().getAmount()); omega = optionForex.isCall() ? 1.0 : -1.0; } else { strike = 1.0 / optionForex.getStrike(); domesticCcy = optionForex.getUnderlyingForex().getCurrency1(); foreignCcy = optionForex.getUnderlyingForex().getCurrency2(); dfDomestic = multicurves.getDiscountFactor(optionForex.getCurrency1(), optionForex.getUnderlyingForex().getPaymentTime()); dfForeign = multicurves.getDiscountFactor(optionForex.getCurrency2(), optionForex.getUnderlyingForex().getPaymentTime()); amount = Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()); omega = optionForex.isCall() ? -1.0 : 1.0; } final double spot = multicurves.getFxRate(foreignCcy, domesticCcy); final double forward = spot * dfForeign / dfDomestic; final double volatility = smileMulticurves.getVolatility(foreignCcy, domesticCcy, optionForex.getExpirationTime(), strike, forward); final double sigmaRootT = volatility * Math.sqrt(expiry); final double dM = Math.log(forward / strike) / sigmaRootT - 0.5 * sigmaRootT; final double pv = amount * dfDomestic * NORMAL.getCDF(omega * dM) * (optionForex.isLong() ? 1.0 : -1.0); final double deltaSpot = amount * dfDomestic * NORMAL.getPDF(dM) * omega / (sigmaRootT * spot) * (optionForex.isLong() ? 1.0 : -1.0); final CurrencyAmount[] currencyExposure = new CurrencyAmount[2]; currencyExposure[0] = CurrencyAmount.of(foreignCcy, deltaSpot); currencyExposure[1] = CurrencyAmount.of(domesticCcy, -deltaSpot * spot + pv); return MultipleCurrencyAmount.of(currencyExposure); } private  ForexOptionDigitalBlackSmileMethod(); static ForexOptionDigitalBlackSmileMethod getInstance(); MultipleCurrencyAmount presentValue(final ForexOptionDigital optionForex, final BlackForexSmileProviderInterface smileMulticurves); MultipleCurrencyAmount currencyExposure(final ForexOptionDigital optionForex, final BlackForexSmileProviderInterface smileMulticurves); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexOptionDigital optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final ForexOptionDigital optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilityNodeSensitivityDataBundle presentValueBlackVolatilityNodeSensitivity(final ForexOptionDigital 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 ForexOptionDigitalDefinition forexOptionDefinitionCall = new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionDigitalDefinition forexOptionDefinitionPut = new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong); final ForexOptionDigital forexOptionCall = forexOptionDefinitionCall.toDerivative(REFERENCE_DATE); final ForexOptionDigital 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 double sigmaRootT = volatility * Math.sqrt(forexOptionCall.getExpirationTime()); final double dM = Math.log(forward / strike) / sigmaRootT - 0.5 * sigmaRootT; final double deltaSpotCall = dfDomestic * notional * strike * NORMAL.getPDF(dM) / (sigmaRootT * SPOT); final double deltaSpotPut = -dfDomestic * notional * strike * NORMAL.getPDF(dM) / (sigmaRootT * SPOT); final MultipleCurrencyAmount priceComputedCall = METHOD_BLACK_DIGITAL.presentValue(forexOptionCall, SMILE_MULTICURVES); final MultipleCurrencyAmount priceComputedPut = METHOD_BLACK_DIGITAL.presentValue(forexOptionPut, SMILE_MULTICURVES); final MultipleCurrencyAmount currencyExposureCallComputed = METHOD_BLACK_DIGITAL.currencyExposure(forexOptionCall, SMILE_MULTICURVES); assertEquals("Forex Digital option: currency exposure foreign - call", deltaSpotCall, currencyExposureCallComputed.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex Digital option: currency exposure domestic - call", -deltaSpotCall * SPOT + priceComputedCall.getAmount(USD), currencyExposureCallComputed.getAmount(USD), TOLERANCE_PV); final MultipleCurrencyAmount currencyExposurePutComputed = METHOD_BLACK_DIGITAL.currencyExposure(forexOptionPut, SMILE_MULTICURVES); assertEquals("Forex Digital option: currency exposure foreign- put", deltaSpotPut, currencyExposurePutComputed.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex Digital option: currency exposure domestic - put", -deltaSpotPut * SPOT + priceComputedPut.getAmount(USD), currencyExposurePutComputed.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 ForexOptionDigitalDefinition forexOptionDefinitionCall = new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionDigitalDefinition forexOptionDefinitionPut = new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, !isCall, isLong); final ForexOptionDigital forexOptionCall = forexOptionDefinitionCall.toDerivative(REFERENCE_DATE); final ForexOptionDigital forexOptionPut = forexOptionDefinitionPut.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount currencyExposureCall = METHOD_BLACK_DIGITAL.currencyExposure(forexOptionCall, SMILE_MULTICURVES); final MultipleCurrencyAmount currencyExposurePut = METHOD_BLACK_DIGITAL.currencyExposure(forexOptionPut, SMILE_MULTICURVES); final MultipleCurrencyAmount pvCash = forexOptionPut.getUnderlyingForex().getPaymentCurrency2().accept(PVDC, MULTICURVES); assertEquals("Forex Digital option: currency exposure put/call parity foreign", 0, currencyExposureCall.getAmount(EUR) + currencyExposurePut.getAmount(EUR), TOLERANCE_PV); assertEquals("Forex Digital option: currency exposure put/call parity domestic", Math.abs(pvCash.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 ForexOptionDigitalDefinition forexOptionDefinition = new ForexOptionDigitalDefinition(forexUnderlyingDefinition, expDate, isCall, isLong); final ForexOptionDigital forexOption = forexOptionDefinition.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount ceMethod = METHOD_BLACK_DIGITAL.currencyExposure(forexOption, SMILE_MULTICURVES); final MultipleCurrencyAmount ceCalculator = forexOption.accept(CEFBC, SMILE_MULTICURVES); assertEquals("Forex Digital option: currency exposure Method vs Calculator", ceMethod.getAmount(EUR), ceCalculator.getAmount(EUR), 1E-2); assertEquals("Forex Digital option: currency exposure Method vs Calculator", ceMethod.getAmount(USD), ceCalculator.getAmount(USD), 1E-2); }