/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.volatilityswap;
import static org.testng.AssertJUnit.assertEquals;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.model.volatility.BlackScholesFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.volatilityswap.CarrLeeFXData;
import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
import com.opengamma.financial.convention.frequency.PeriodFrequency;
import com.opengamma.util.money.Currency;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.tuple.Pairs;
/**
*
*/
@Test(groups = TestGroup.UNIT)
public class VolatilitySwapGreeksCalculatorTest {
/**
*
*/
@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);
}
}