ForexOptionVanillaVannaVolgaMethod { public MultipleCurrencyAmount currencyExposure(final ForexOptionVanilla optionForex, final BlackForexVannaVolgaProviderInterface smileMulticurves) { Validate.notNull(optionForex, "Forex option"); Validate.notNull(smileMulticurves, "Smile"); Validate.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 SmileDeltaParameters smileAtTime = smileMulticurves.getSmile(optionForex.getCurrency1(), optionForex.getCurrency2(), optionForex.getTimeToExpiry()); final double[] strikesVV = smileAtTime.getStrike(forward); final double[] volVV = smileAtTime.getVolatility(); final double volATM = volVV[1]; final double[][] priceVVATM = new double[3][]; final double[][] priceVVsmile = new double[3][]; final BlackFunctionData dataBlackATM = new BlackFunctionData(forward, dfDomestic, volATM); for (int loopvv = 0; loopvv < 3; loopvv = loopvv + 2) { final BlackFunctionData dataBlackSmile = new BlackFunctionData(forward, dfDomestic, volVV[loopvv]); final EuropeanVanillaOption optionVV = new EuropeanVanillaOption(strikesVV[loopvv], optionForex.getTimeToExpiry(), true); priceVVATM[loopvv] = BLACK_FUNCTION.getPriceAdjoint(optionVV, dataBlackATM); priceVVsmile[loopvv] = BLACK_FUNCTION.getPriceAdjoint(optionVV, dataBlackSmile); } final double[] priceFlat = BLACK_FUNCTION.getPriceAdjoint(optionForex, dataBlackATM); final double[] x = vannaVolgaWeights(optionForex, forward, dfDomestic, strikesVV, volVV); double price = priceFlat[0]; for (int loopvv = 0; loopvv < 3; loopvv = loopvv + 2) { price += x[loopvv] * (priceVVsmile[loopvv][0] - priceVVATM[loopvv][0]); } price *= Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * (optionForex.isLong() ? 1.0 : -1.0); double deltaSpot = priceFlat[1]; for (int loopvv = 0; loopvv < 3; loopvv = loopvv + 2) { deltaSpot += x[loopvv] * (priceVVsmile[loopvv][1] - priceVVATM[loopvv][1]); } deltaSpot *= dfForeign / dfDomestic; final double sign = (optionForex.isLong() ? 1.0 : -1.0); final CurrencyAmount[] currencyExposure = new CurrencyAmount[2]; currencyExposure[0] = CurrencyAmount.of(optionForex.getUnderlyingForex().getCurrency1(), deltaSpot * Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * sign); currencyExposure[1] = CurrencyAmount.of(optionForex.getUnderlyingForex().getCurrency2(), -deltaSpot * Math.abs(optionForex.getUnderlyingForex().getPaymentCurrency1().getAmount()) * spot * sign + price); return MultipleCurrencyAmount.of(currencyExposure); } private  ForexOptionVanillaVannaVolgaMethod(); static ForexOptionVanillaVannaVolgaMethod getInstance(); MultipleCurrencyAmount presentValue(final ForexOptionVanilla optionForex, final BlackForexVannaVolgaProviderInterface smileMulticurves); MultipleCurrencyAmount currencyExposure(final ForexOptionVanilla optionForex, final BlackForexVannaVolgaProviderInterface smileMulticurves); PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final ForexOptionVanilla optionForex, final BlackForexVannaVolgaProviderInterface smileMulticurves); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexOptionVanilla optionForex, final BlackForexVannaVolgaProviderInterface smileMulticurves); double[] vannaVolgaWeights(final ForexOptionVanilla optionForex, final double forward, final double dfDomestic, final double[] strikesReference, final double[] volatilitiesReference); double[] vannaVolgaWeights(final ForexOptionVanilla optionForex, final double forward, final double dfDomestic, final double[] strikesReference, final double[] volatilitiesReference,
      final double[] vega);  }
@Test public void currencyExposure() { final int nbStrike = 10; final double strikeMin = 1.00; final double strikeRange = 0.80; final double[] strikes = new double[nbStrike + 1]; final boolean isCall = true; final boolean isLong = true; final double notional = 100000000; final ZonedDateTime optionExpiry = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, Period.ofMonths(18), BUSINESS_DAY, CALENDAR); final ZonedDateTime optionPay = ScheduleCalculator.getAdjustedDate(optionExpiry, SETTLEMENT_DAYS, CALENDAR); final ForexOptionVanilla[] forexOption = new ForexOptionVanilla[nbStrike + 1]; for (int loopstrike = 0; loopstrike <= nbStrike; loopstrike++) { strikes[loopstrike] = strikeMin + loopstrike * strikeRange / nbStrike; final ForexDefinition forexUnderlyingDefinition = new ForexDefinition(EUR, USD, optionPay, notional, strikes[loopstrike]); final ForexOptionVanillaDefinition forexOptionDefinition = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, optionExpiry, isCall, isLong); forexOption[loopstrike] = forexOptionDefinition.toDerivative(REFERENCE_DATE); } final double forward = METHOD_BLACK.forwardForexRate(forexOption[0], MULTICURVES); final double dfDomestic = MULTICURVES.getDiscountFactor(USD, forexOption[0].getUnderlyingForex().getPaymentTime()); final SmileDeltaParameters smileAtTime = VANNAVOLGA_MULTICURVES.getSmile(EUR, USD, forexOption[0].getTimeToExpiry()); final double[] strikesVV = smileAtTime.getStrike(forward); final double[] volVV = smileAtTime.getVolatility(); final ForexOptionVanilla[] optReference = new ForexOptionVanilla[3]; for (int loopvv = 0; loopvv < 3; loopvv++) { final ForexDefinition forexUnderlyingDefinition = new ForexDefinition(EUR, USD, optionPay, notional, strikesVV[loopvv]); final ForexOptionVanillaDefinition forexOptionDefinition = new ForexOptionVanillaDefinition(forexUnderlyingDefinition, optionExpiry, isCall, isLong); optReference[loopvv] = forexOptionDefinition.toDerivative(REFERENCE_DATE); } final MultipleCurrencyAmount[] ceVV = new MultipleCurrencyAmount[nbStrike + 1]; final MultipleCurrencyAmount[] ceFlat = new MultipleCurrencyAmount[nbStrike + 1]; final MultipleCurrencyAmount[] ceExpected = new MultipleCurrencyAmount[nbStrike + 1]; final MultipleCurrencyAmount[] ceVVATM = new MultipleCurrencyAmount[3]; final MultipleCurrencyAmount[] ceVVsmile = new MultipleCurrencyAmount[3]; final MultipleCurrencyAmount[] ceVVadj = new MultipleCurrencyAmount[3]; for (int loopvv = 0; loopvv < 3; loopvv++) { ceVVATM[loopvv] = METHOD_BLACK.currencyExposure(optReference[loopvv], SMILE_FLAT_MULTICURVES); ceVVsmile[loopvv] = METHOD_BLACK.currencyExposure(optReference[loopvv], SMILE_MULTICURVES); ceVVadj[loopvv] = ceVVsmile[loopvv].plus(ceVVATM[loopvv].multipliedBy(-1.0)); } for (int loopstrike = 0; loopstrike <= nbStrike; loopstrike++) { ceVV[loopstrike] = METHOD_VANNA_VOLGA.currencyExposure(forexOption[loopstrike], VANNAVOLGA_MULTICURVES); final double[] weights = METHOD_VANNA_VOLGA.vannaVolgaWeights(forexOption[loopstrike], forward, dfDomestic, strikesVV, volVV); ceFlat[loopstrike] = METHOD_BLACK.currencyExposure(forexOption[loopstrike], SMILE_FLAT_MULTICURVES); ceExpected[loopstrike] = ceFlat[loopstrike]; for (int loopvv = 0; loopvv < 3; loopvv++) { ceExpected[loopstrike] = ceExpected[loopstrike].plus(ceVVadj[loopvv].multipliedBy(weights[loopvv])); } assertEquals("Forex vanilla option: currency exposure vanna-volga", ceExpected[loopstrike].getAmount(EUR), ceVV[loopstrike].getAmount(EUR), TOLERANCE_PV); assertEquals("Forex vanilla option: currency exposure vanna-volga", ceExpected[loopstrike].getAmount(USD), ceVV[loopstrike].getAmount(USD), TOLERANCE_PV); } }