ForexOptionSingleBarrierBlackMethod { public MultipleCurrencyAmount presentValue(final ForexOptionSingleBarrier 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.getUnderlyingOption().getUnderlyingForex().getPaymentTime(); final double dfDomestic = multicurves.getDiscountFactor(optionForex.getCurrency2(), payTime); final double dfForeign = multicurves.getDiscountFactor(optionForex.getCurrency1(), payTime); final double rateDomestic = -Math.log(dfDomestic) / payTime; final double rateForeign = -Math.log(dfForeign) / payTime; final double spot = multicurves.getFxRate(optionForex.getCurrency1(), optionForex.getCurrency2()); final double forward = spot * dfForeign / dfDomestic; final double foreignAmount = optionForex.getUnderlyingOption().getUnderlyingForex().getPaymentCurrency1().getAmount(); final double rebateByForeignUnit = optionForex.getRebate() / Math.abs(foreignAmount); final double sign = (optionForex.getUnderlyingOption().isLong() ? 1.0 : -1.0); final double volatility = smileMulticurves.getVolatility(optionForex.getCurrency1(), optionForex.getCurrency2(), optionForex.getUnderlyingOption().getTimeToExpiry(), optionForex .getUnderlyingOption().getStrike(), forward); double price = BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spot, rateDomestic - rateForeign, rateDomestic, volatility); price *= Math.abs(foreignAmount) * sign; final CurrencyAmount priceCurrency = CurrencyAmount.of(optionForex.getUnderlyingOption().getUnderlyingForex().getCurrency2(), price); return MultipleCurrencyAmount.of(priceCurrency); } private  ForexOptionSingleBarrierBlackMethod(); static ForexOptionSingleBarrierBlackMethod getInstance(); MultipleCurrencyAmount presentValue(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); MultipleCurrencyAmount currencyExposure(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); PresentValueForexBlackVolatilityNodeSensitivityDataBundle presentValueBlackVolatilityNodeSensitivity(final ForexOptionSingleBarrier optionForex,
      final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount gammaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount gammaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount vommaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount vommaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount vannaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount vannaFd(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves); CurrencyAmount dVegaDSpotFD(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount dDeltaDVolFD(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount d2PriceDSpotDVolFD(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift); CurrencyAmount d2PriceDSpotDVolFdAlt(final ForexOptionSingleBarrier optionForex, final BlackForexSmileProviderInterface smileMulticurves, final double relShift);  }
@Test public void comparisonOfBarrierPricersWithVeryHighAndVeryLowBarrierLevels() { final MultipleCurrencyAmount priceBarrierUp = METHOD_BARRIER.presentValue(BARRIER_LIKE_VANILLA_UP, SMILE_MULTICURVES); final MultipleCurrencyAmount priceBarrierDown = METHOD_BARRIER.presentValue(BARRIER_LIKE_VANILLA_DOWN, SMILE_MULTICURVES); assertTrue("PV : Knock-Out Barrier with unreachably HIGH level doesn't match one with unreachably LOWlevel", Math.abs(priceBarrierDown.getAmount(USD) / priceBarrierUp.getAmount(USD) - 1) < 1e-4); }
@Test public void testKnockInOutParity() { final ForexOptionVanillaDefinition vanillaDefn = new ForexOptionVanillaDefinition(FOREX_DEFINITION, OPTION_PAY_DATE, IS_CALL, IS_LONG); final ForexOptionVanilla vanillaExpiryEqualsPay = vanillaDefn.toDerivative(REFERENCE_DATE); final ForexOptionSingleBarrier knockOut = new ForexOptionSingleBarrier(vanillaExpiryEqualsPay, BARRIER_KO, 0.0); final ForexOptionSingleBarrier knockIn = new ForexOptionSingleBarrier(vanillaExpiryEqualsPay, BARRIER_KI, 0.0); final ForexOptionSingleBarrier impossibleKnockOut = new ForexOptionSingleBarrier(vanillaExpiryEqualsPay, BARRIER_IMPOSSIBLE_DOWN, 0.0); final double priceVanilla = METHOD_VANILLA.presentValue(vanillaExpiryEqualsPay, SMILE_MULTICURVES).getAmount(USD); final double priceBarrierKO = METHOD_BARRIER.presentValue(knockOut, SMILE_MULTICURVES).getAmount(USD); final double priceBarrierKI = METHOD_BARRIER.presentValue(knockIn, SMILE_MULTICURVES).getAmount(USD); final double priceBarrierDown = METHOD_BARRIER.presentValue(impossibleKnockOut, SMILE_MULTICURVES).getAmount(USD); assertTrue("PV : Knock-Out + Knock-In Barriers do not sum to the underlying vanilla (as approximated by a barrierOption with an impossibly low barrier", Math.abs((priceBarrierKO + priceBarrierKI) / priceBarrierDown - 1.0) < 1e-4); assertTrue("PV : Knock-Out + Knock-In Barriers do not sum to the underlying vanilla", ((priceBarrierKO + priceBarrierKI) / priceVanilla - 1.0) < 1e-4); }
@Test public void comparisonVanilla() { final MultipleCurrencyAmount priceVanilla = METHOD_VANILLA.presentValue(VANILLA_LONG, SMILE_MULTICURVES); final MultipleCurrencyAmount priceBarrier = METHOD_BARRIER.presentValue(OPTION_BARRIER, SMILE_MULTICURVES); assertTrue("Barriers are cheaper than vanilla", priceVanilla.getAmount(USD) > priceBarrier.getAmount(USD)); }
@Test public void presentValue() { final MultipleCurrencyAmount priceMethod = METHOD_BARRIER.presentValue(OPTION_BARRIER, SMILE_MULTICURVES); final double payTime = VANILLA_LONG.getUnderlyingForex().getPaymentTime(); final double dfDomestic = MULTICURVES.getDiscountFactor(VANILLA_LONG.getCurrency2(), payTime); final double dfForeign = MULTICURVES.getDiscountFactor(VANILLA_LONG.getCurrency1(), payTime); final double rateDomestic = -Math.log(dfDomestic) / payTime; final double rateForeign = -Math.log(dfForeign) / payTime; final double costOfCarry = rateDomestic - rateForeign; final double forward = SPOT * Math.exp(-rateForeign * payTime) / Math.exp(-rateDomestic * payTime); final double volatility = SMILE_TERM.getVolatility(Triple.of(VANILLA_LONG.getTimeToExpiry(), STRIKE, forward)); final double priceComputed = BLACK_BARRIER_FUNCTION.getPrice(VANILLA_LONG, BARRIER_KI, REBATE / NOTIONAL, SPOT, costOfCarry, rateDomestic, volatility) * NOTIONAL; assertEquals("Barriers present value", priceComputed, priceMethod.getAmount(USD), TOLERANCE_PV); }
@Test public void scaleLongShortParity() { final MultipleCurrencyAmount priceBarrier = METHOD_BARRIER.presentValue(OPTION_BARRIER, SMILE_MULTICURVES); final double scale = 10; final ForexDefinition fxDefinitionScale = new ForexDefinition(EUR, USD, OPTION_PAY_DATE, NOTIONAL * scale, STRIKE); final ForexOptionVanillaDefinition optionDefinitionScale = new ForexOptionVanillaDefinition(fxDefinitionScale, OPTION_EXPIRY_DATE, IS_CALL, IS_LONG); final ForexOptionVanilla optionScale = optionDefinitionScale.toDerivative(REFERENCE_DATE); final ForexOptionSingleBarrier optionBarrierScale = new ForexOptionSingleBarrier(optionScale, BARRIER_KI, scale * REBATE); final MultipleCurrencyAmount priceBarrierScale = METHOD_BARRIER.presentValue(optionBarrierScale, SMILE_MULTICURVES); assertEquals("Barriers are cheaper than vanilla", priceBarrier.getAmount(USD) * scale, priceBarrierScale.getAmount(USD), TOLERANCE_PV); final MultipleCurrencyAmount priceBarrierShort = METHOD_BARRIER.presentValue(BARRIER_SHORT, SMILE_MULTICURVES); assertEquals("Barriers are cheaper than vanilla", -priceBarrier.getAmount(USD), priceBarrierShort.getAmount(USD), TOLERANCE_PV); }
@Test public void presentValueMethodVsCalculator() { final MultipleCurrencyAmount pvMethod = METHOD_BARRIER.presentValue(OPTION_BARRIER, SMILE_MULTICURVES); final MultipleCurrencyAmount pvCalculator = OPTION_BARRIER.accept(PVFBC, SMILE_MULTICURVES); assertEquals("Forex vanilla option: present value Method vs Calculator", pvMethod.getAmount(USD), pvCalculator.getAmount(USD), TOLERANCE_PV); }