ForexOptionDigitalBlackSmileMethod { public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(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 payTime = optionForex.getUnderlyingForex().getPaymentTime(); final double expiry = optionForex.getExpirationTime(); final Currency domesticCcy; final Currency foreignCcy; final double strike; final double amount; final double omega; if (optionForex.payDomestic()) { domesticCcy = optionForex.getUnderlyingForex().getCurrency2(); foreignCcy = optionForex.getUnderlyingForex().getCurrency1(); 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(); amount = Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()); omega = optionForex.isCall() ? -1.0 : 1.0; } final double dfDomestic = multicurves.getDiscountFactor(domesticCcy, payTime); final double dfForeign = multicurves.getDiscountFactor(foreignCcy, payTime); 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 pvBar = 1.0; final double dMBar = amount * dfDomestic * NORMAL.getPDF(omega * dM) * (optionForex.isLong() ? 1.0 : -1.0) * omega * pvBar; final double forwardBar = 1 / (forward * sigmaRootT) * dMBar; final double dfForeignBar = spot / dfDomestic * forwardBar; final double dfDomesticBar = -spot / (dfDomestic * dfDomestic) * dfForeign * forwardBar + pv / dfDomestic * pvBar; final double rForeignBar = -payTime * dfForeign * dfForeignBar; final double rDomesticBar = -payTime * dfDomestic * dfDomesticBar; final Map<String, List<DoublesPair>> resultMap = new HashMap<>(); final List<DoublesPair> listForeign = new ArrayList<>(); listForeign.add(DoublesPair.of(payTime, rForeignBar)); resultMap.put(multicurves.getName(foreignCcy), listForeign); final List<DoublesPair> listDomestic = new ArrayList<>(); listDomestic.add(DoublesPair.of(payTime, rDomesticBar)); resultMap.put(multicurves.getName(domesticCcy), listDomestic); final MulticurveSensitivity result = MulticurveSensitivity.ofYieldDiscounting(resultMap); return MultipleCurrencyMulticurveSensitivity.of(domesticCcy, result); } 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 presentValueCurveSensitivity() { 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 ForexOptionDigital forexOptionCall = forexOptionDefinitionCall.toDerivative(REFERENCE_DATE); final MultipleCurrencyParameterSensitivity pvpsExact = PS_FBS_C.calculateSensitivity(forexOptionCall, SMILE_FLAT_MULTICURVES, SMILE_FLAT_MULTICURVES .getMulticurveProvider().getAllNames()); final MultipleCurrencyParameterSensitivity pvpsFD = PS_FBS_FDC.calculateSensitivity(forexOptionCall, SMILE_FLAT_MULTICURVES); AssertSensitivityObjects.assertEquals("FX digital option: presentValueCurveSensitivity ", pvpsExact, pvpsFD, TOLERANCE_PV_DELTA); }
@Test public void presentValueCurveSensitivityMethodVsCalculator() { final MultipleCurrencyMulticurveSensitivity pvcsMethod = METHOD_BLACK_DIGITAL.presentValueCurveSensitivity(FOREX_DIGITAL_CALL_DOM, SMILE_MULTICURVES); final MultipleCurrencyMulticurveSensitivity pvcsCalculator = FOREX_DIGITAL_CALL_DOM.accept(PVCSFBC, SMILE_MULTICURVES); assertEquals("Forex present value curve sensitivity: Method vs Calculator", pvcsMethod, pvcsCalculator); }