VolatilitySwapGreeksCalculator { public double[] getFXVolatilitySwapGreeks(final VolatilitySwapCalculatorResultWithStrikes result, final FXVolatilitySwap swap, final CarrLeeFXData data) { ArgumentChecker.notNull(result, "result"); ArgumentChecker.notNull(swap, "swap"); ArgumentChecker.notNull(data, "data"); final double spot = data.getSpot(); final double timeToExpiry = swap.getTimeToMaturity(); ArgumentChecker.isTrue(Doubles.isFinite(timeToExpiry), "timeToExpiry should be finite"); ArgumentChecker.isTrue(timeToExpiry > 0., "timeToExpiry should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(spot), "spot should be finite"); ArgumentChecker.isTrue(spot > 0., "spot should be positive"); final double domesticDF = data.getMulticurveProvider().getDiscountFactor(swap.getBaseCurrency(), timeToExpiry); final double foreignDF = data.getMulticurveProvider().getDiscountFactor(swap.getCounterCurrency(), timeToExpiry); final double domesticRate = -Math.log(domesticDF) / timeToExpiry; final double foreignRate = -Math.log(foreignDF) / timeToExpiry; ArgumentChecker.isTrue(Doubles.isFinite(domesticRate), "domestic rate should be finite"); ArgumentChecker.isTrue(Doubles.isFinite(foreignRate), "foreign rate should be finite"); final double[] putStrikes = result.getPutStrikes(); final double forward = spot * Math.exp((domesticRate - foreignRate) * timeToExpiry); final double[] callStrikes = result.getCallStrikes(); final int nPuts = putStrikes.length; final int nCalls = callStrikes.length; final SmileDeltaTermStructureParameters smile = data.getVolatilityData(); final double[] putVols = new double[nPuts]; final double[] callVols = new double[nCalls]; for (int i = 0; i < nPuts; ++i) { putVols[i] = smile.getVolatility(Triple.of(timeToExpiry, putStrikes[i], forward)); } final double stdVol = smile.getVolatility(Triple.of(timeToExpiry, forward, forward)); for (int i = 0; i < nCalls; ++i) { callVols[i] = smile.getVolatility(Triple.of(timeToExpiry, callStrikes[i], forward)); } return getGreeks(result, spot, putStrikes, callStrikes, timeToExpiry, domesticRate, foreignRate, putVols, stdVol, callVols); }  double[] getFXVolatilitySwapGreeks(final VolatilitySwapCalculatorResultWithStrikes result, final FXVolatilitySwap swap, final CarrLeeFXData data); double[] getFXVolatilitySwapGreeks(final FXVolatilitySwap swap, final CarrLeeFXData data);  }
@Test void sampleDataTest() { final CarrLeeFXVolatilitySwapCalculator cal = new CarrLeeFXVolatilitySwapCalculator(); final VolatilitySwapGreeksCalculator calGreeks = new VolatilitySwapGreeksCalculator(); final double spot = 0.8; final double timeToExpiry = 0.49; final double timeFromInception = 0.12; final double dr = 0.12; final double fr = 0.04; final double realizedVar = 6.7 * 6.7; final double[] timeToExpiration = new double[] {0.01, 0.1, 0.3 }; final int nTime = timeToExpiration.length; final double[] delta = new double[] {0.10, 0.25 }; final int nVols = 2 * delta.length + 1; final double[][] volatility = new double[nTime][nVols]; final double[] volSmile = new double[] {9. / 100., 8.1 / 100., 6.9 / 100., 6.45 / 100., 7.22 / 100. }; for (int i = 0; i < nTime; ++i) { System.arraycopy(volSmile, 0, volatility[i], 0, nVols); } final SmileDeltaTermStructureParametersStrikeInterpolation smile = new SmileDeltaTermStructureParametersStrikeInterpolation(timeToExpiration, delta, volatility); final Currency base = Currency.EUR; final Currency counter = Currency.USD; final Map<Currency, YieldAndDiscountCurve> discountingCurves = new LinkedHashMap<>(); discountingCurves.put(Currency.EUR, new YieldCurve("domestic", ConstantDoublesCurve.from(dr))); discountingCurves.put(Currency.USD, new YieldCurve("foreign", ConstantDoublesCurve.from(fr))); final FXMatrix fxMatrix = new FXMatrix(base, counter, spot); final MulticurveProviderDiscount curves = new MulticurveProviderDiscount(discountingCurves, new LinkedHashMap<IborIndex, YieldAndDiscountCurve>(), new LinkedHashMap<IndexON, YieldAndDiscountCurve>(), fxMatrix); final CarrLeeFXData data = new CarrLeeFXData(Pairs.of(base, counter), smile, curves, realizedVar); final FXVolatilitySwap swap = new FXVolatilitySwap(-timeFromInception, timeToExpiry, PeriodFrequency.DAILY, timeToExpiry, spot, 1, base, base, counter, 252); final VolatilitySwapCalculatorResultWithStrikes result = (VolatilitySwapCalculatorResultWithStrikes) swap.accept(cal, data); final double[] greeks = calGreeks.getFXVolatilitySwapGreeks(result, swap, data); final double[] greeksRe = calGreeks.getFXVolatilitySwapGreeks(swap, data); assertEquals(greeksRe[0], greeks[0], 1.e-14); assertEquals(greeksRe[1], greeks[1], 1.e-14); assertEquals(greeksRe[2], greeks[2], 1.e-14); assertEquals(greeksRe[3], greeks[3], 1.e-14); final double forward = spot * Math.exp((dr - fr) * timeToExpiry); final double[] expGreeks = new double[4]; for (int i = 0; i < result.getPutWeights().length; ++i) { expGreeks[0] += result.getPutWeights()[i] * BlackScholesFormulaRepository.delta(spot, result.getPutStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getPutStrikes()[i], forward), dr, dr - fr, false); expGreeks[1] += result.getPutWeights()[i] * BlackScholesFormulaRepository.gamma(spot, result.getPutStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getPutStrikes()[i], forward), dr, dr - fr); expGreeks[2] += result.getPutWeights()[i] * BlackScholesFormulaRepository.vega(spot, result.getPutStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getPutStrikes()[i], forward), dr, dr - fr); expGreeks[3] += -result.getPutWeights()[i] * BlackScholesFormulaRepository.theta(spot, result.getPutStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getPutStrikes()[i], forward), dr, dr - fr, false); } for (int i = 0; i < result.getCallWeights().length; ++i) { expGreeks[0] += result.getCallWeights()[i] * BlackScholesFormulaRepository.delta(spot, result.getCallStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getCallStrikes()[i], forward), dr, dr - fr, true); expGreeks[1] += result.getCallWeights()[i] * BlackScholesFormulaRepository.gamma(spot, result.getCallStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getCallStrikes()[i], forward), dr, dr - fr); expGreeks[2] += result.getCallWeights()[i] * BlackScholesFormulaRepository.vega(spot, result.getCallStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getCallStrikes()[i], forward), dr, dr - fr); expGreeks[3] += -result.getCallWeights()[i] * BlackScholesFormulaRepository.theta(spot, result.getCallStrikes()[i], timeToExpiry, smile.getVolatility(timeToExpiry, result.getCallStrikes()[i], forward), dr, dr - fr, true); } assertEquals(expGreeks[0], greeks[0], Math.abs(greeks[0]) * 1.e-13); assertEquals(expGreeks[1], greeks[1], Math.abs(greeks[1]) * 1.e-13); assertEquals(expGreeks[2], greeks[2], Math.abs(greeks[2]) * 1.e-13); assertEquals(expGreeks[3], greeks[3], Math.abs(greeks[3]) * 1.e-13); final FXVolatilitySwap swapNew = new FXVolatilitySwap(0., timeToExpiry, PeriodFrequency.DAILY, timeToExpiry, spot, 1, base, base, counter, 252); final FXVolatilitySwap swapSmall = new FXVolatilitySwap(1.e-5, timeToExpiry, PeriodFrequency.DAILY, timeToExpiry, spot, 1, base, base, counter, 252); final VolatilitySwapCalculatorResultWithStrikes resultNew = (VolatilitySwapCalculatorResultWithStrikes) swapNew.accept(cal, data); final VolatilitySwapCalculatorResultWithStrikes resultSmall = (VolatilitySwapCalculatorResultWithStrikes) swapSmall.accept(cal, data); final double[] greeksNew = calGreeks.getFXVolatilitySwapGreeks(resultNew, swapNew, data); final double[] greeksSmall = calGreeks.getFXVolatilitySwapGreeks(resultSmall, swapSmall, data); assertEquals(greeksNew[0], greeksSmall[0], 1.e-6); assertEquals(greeksNew[1], greeksSmall[1], 1.e-6); assertEquals(greeksNew[2], greeksSmall[2], 1.e-6); assertEquals(greeksNew[3], greeksSmall[3], 1.e-6); }
@Test public void flatVolSmileTest() { final CarrLeeFXVolatilitySwapCalculator cal = new CarrLeeFXVolatilitySwapCalculator(); final VolatilitySwapGreeksCalculator calGreeks = new VolatilitySwapGreeksCalculator(); final double spot = 1.3; final double timeToExpiry = 0.24; final double timeFromInception = 0.12; final double dr = 0.; final double fr = 0.; final double realizedVar = 6. * 6.; final double[] timeToExpiration = new double[] {0.01, 0.1, 0.3 }; final int nTime = timeToExpiration.length; final double[] delta = new double[] {0.10, 0.25 }; final int nVols = 2 * delta.length + 1; final double[][] volatility = new double[nTime][nVols]; for (int i = 0; i < nTime; ++i) { Arrays.fill(volatility[i], 0.06); } final Currency base = Currency.EUR; final Currency counter = Currency.USD; final SmileDeltaTermStructureParametersStrikeInterpolation smile = new SmileDeltaTermStructureParametersStrikeInterpolation(timeToExpiration, delta, volatility); final Map<Currency, YieldAndDiscountCurve> discountingCurves = new LinkedHashMap<>(); discountingCurves.put(Currency.EUR, new YieldCurve("domestic", ConstantDoublesCurve.from(dr))); discountingCurves.put(Currency.USD, new YieldCurve("foreign", ConstantDoublesCurve.from(fr))); final FXMatrix fxMatrix = new FXMatrix(base, counter, spot); final MulticurveProviderDiscount curves = new MulticurveProviderDiscount(discountingCurves, new LinkedHashMap<IborIndex, YieldAndDiscountCurve>(), new LinkedHashMap<IndexON, YieldAndDiscountCurve>(), fxMatrix); final CarrLeeFXData data = new CarrLeeFXData(Pairs.of(base, counter), smile, curves, realizedVar); final FXVolatilitySwap swap = new FXVolatilitySwap(-timeFromInception, timeToExpiry, PeriodFrequency.DAILY, timeToExpiry, spot, 1, base, base, counter, 252); final VolatilitySwapCalculatorResultWithStrikes result = (VolatilitySwapCalculatorResultWithStrikes) swap.accept(cal, data); final double[] greeks = calGreeks.getFXVolatilitySwapGreeks(result, swap, data); final double[] greeksRe = calGreeks.getFXVolatilitySwapGreeks(swap, data); assertEquals(greeksRe[0], greeks[0], 1.e-14); assertEquals(greeksRe[1], greeks[1], 1.e-14); assertEquals(greeksRe[2], greeks[2], 1.e-14); assertEquals(greeksRe[3], greeks[3], 1.e-14); final double[] expGreeks = new double[4]; for (int i = 0; i < result.getPutWeights().length; ++i) { expGreeks[0] += result.getPutWeights()[i] * BlackScholesFormulaRepository.delta(spot, result.getPutStrikes()[i], timeToExpiry, volatility[0][0], 0., 0., false); expGreeks[1] += result.getPutWeights()[i] * BlackScholesFormulaRepository.gamma(spot, result.getPutStrikes()[i], timeToExpiry, volatility[0][0], 0., 0.); expGreeks[2] += result.getPutWeights()[i] * BlackScholesFormulaRepository.vega(spot, result.getPutStrikes()[i], timeToExpiry, volatility[0][0], 0., 0.); expGreeks[3] += -result.getPutWeights()[i] * BlackScholesFormulaRepository.theta(spot, result.getPutStrikes()[i], timeToExpiry, volatility[0][0], 0., 0., false); } for (int i = 0; i < result.getCallWeights().length; ++i) { expGreeks[0] += result.getCallWeights()[i] * BlackScholesFormulaRepository.delta(spot, result.getCallStrikes()[i], timeToExpiry, volatility[0][0], 0., 0., true); expGreeks[1] += result.getCallWeights()[i] * BlackScholesFormulaRepository.gamma(spot, result.getCallStrikes()[i], timeToExpiry, volatility[0][0], 0., 0.); expGreeks[2] += result.getCallWeights()[i] * BlackScholesFormulaRepository.vega(spot, result.getCallStrikes()[i], timeToExpiry, volatility[0][0], 0., 0.); expGreeks[3] += -result.getCallWeights()[i] * BlackScholesFormulaRepository.theta(spot, result.getCallStrikes()[i], timeToExpiry, volatility[0][0], 0., 0., true); } assertEquals(expGreeks[0], greeks[0], 1.e-14); assertEquals(expGreeks[1], greeks[1], 1.e-14); assertEquals(expGreeks[2], greeks[2], 1.e-14); assertEquals(expGreeks[3], greeks[3], 1.e-14); }