* There are tests below that compare computing Gamma and Vomma via 2nd order approximations of price to 1st order approximations of the 1st order greek - delta, vega respectively.
* This works well for the one-dimensional sensitivities above, but not well at all for the cross-derivative, Vanna. Comparison below, and in test above.
*
*/
public void testOfFiniteDifferenceMethods() {
final ForexOptionSingleBarrier optionForex = OPTION_BARRIER;
final SmileDeltaTermStructureDataBundle smile = SMILE_BUNDLE;
final double bp10 = 0.001;
final double relShift = 0.001;
// repackage for calls to BARRIER_FUNCTION
final String domesticCurveName = optionForex.getUnderlyingOption().getUnderlyingForex().getPaymentCurrency2().getFundingCurveName();
final String foreignCurveName = optionForex.getUnderlyingOption().getUnderlyingForex().getPaymentCurrency1().getFundingCurveName();
final double payTime = optionForex.getUnderlyingOption().getUnderlyingForex().getPaymentTime();
final double rateDomestic = smile.getCurve(domesticCurveName).getInterestRate(payTime);
final double rateForeign = smile.getCurve(foreignCurveName).getInterestRate(payTime);
final double costOfCarry = rateDomestic - rateForeign;
final double spot = smile.getFxRates().getFxRate(optionForex.getCurrency1(), optionForex.getCurrency2());
final double forward = spot * Math.exp(-rateForeign * payTime) / Math.exp(-rateDomestic * payTime);
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 vol = FXVolatilityUtils.getVolatility(smile, optionForex.getCurrency1(), optionForex.getCurrency2(), optionForex.getUnderlyingOption().getTimeToExpiry(), optionForex
.getUnderlyingOption().getStrike(), forward);
// Bump scenarios
final double volUp = (1.0 + relShift) * vol;
final double volDown = (1.0 - relShift) * vol;
final double spotUp = (1.0 + relShift) * spot;
final double spotDown = (1.0 - relShift) * spot;
// Prices in scenarios
final double pxBase = BLACK_BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spot, costOfCarry, rateDomestic, vol);
final double pxVolUp = BLACK_BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spot, costOfCarry, rateDomestic, volUp);
final double pxVolDown = BLACK_BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spot, costOfCarry, rateDomestic, volDown);
final double pxSpotUp = BLACK_BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spotUp, costOfCarry, rateDomestic, vol);
final double pxSpotDown = BLACK_BARRIER_FUNCTION.getPrice(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spotDown, costOfCarry, rateDomestic, vol);
// 1. Compare the analytic vega to the finite difference vega
// Bump vol and compute *price*
final double vegaFD = (pxVolUp - pxVolDown) / (2 * relShift * vol);
final double[] adjoint = new double[5];
final double pxBaseTest = BLACK_BARRIER_FUNCTION.getPriceAdjoint(optionForex.getUnderlyingOption(), optionForex.getBarrier(), rebateByForeignUnit, spot, costOfCarry, rateDomestic, vol, adjoint);
final double vegaBlack = adjoint[4];
assertEquals("Vega: Analytic and FiniteDifference are out.", vegaBlack, vegaFD, bp10);
// 2. Compare the price from getPrice vs getPriceAdjoint
assertTrue("Adjoint: Price from getPrice and getPriceAdjoint are out.", Math.abs(pxBase - pxBaseTest) < 1.0e-8 * Math.abs(foreignAmount));