// Special case for EquityIndexOptions
} else if (market.getVolatilitySurface() instanceof BlackVolatilitySurfaceMoneynessFcnBackedByGrid) {
final BlackVolatilitySurfaceMoneynessFcnBackedByGrid surfaceBundle = (BlackVolatilitySurfaceMoneynessFcnBackedByGrid) market.getVolatilitySurface();
final EquityIndexOption option;
if (derivative instanceof EquityIndexOption) {
option = (EquityIndexOption) derivative;
} else {
throw new OpenGammaRuntimeException("Calculator with BlackVolatilitySurfaceMoneynessFcnBackedByGrid was expecting an EquityIndexOption.");
}
// Unpack
final SmileSurfaceDataBundle volGrid = surfaceBundle.getGridData();
final double[] forwards = volGrid.getForwards();
final double[] volExpiries = volGrid.getExpiries();
final int nExpiries = volGrid.getNumExpiries();
final double[][] strikes = volGrid.getStrikes();
final double[][] vols = volGrid.getVolatilities();
final VolatilitySurfaceInterpolator surfaceInterpolator = surfaceBundle.getInterpolator();
final GeneralSmileInterpolator strikeInterpolator = surfaceInterpolator.getSmileInterpolator();
// Base price and set of independent smile fits (one function vol(k) for each expiry)
final Double pvBase = option.accept(_pricer, market);
final Function1D<Double, Double>[] smileFitsBase = surfaceInterpolator.getIndependentSmileFits(volGrid);
// Bump and reprice - loop over expiry and strike
final List<Triple<Double, Double, Double>> triplesExpiryStrikeVega = new ArrayList<>();
// TODO: REVIEW: We can drastically reduce the time it takes to compute this if we are sensible about avoiding points which almost certainly won't have any sensitivity
// Of course, this is all based upon the interpolor's scheme...
final int expiryIndex = SurfaceArrayUtils.getLowerBoundIndex(volExpiries, option.getTimeToExpiry());
for (int t = Math.max(0, expiryIndex - 3); t < Math.min(nExpiries, expiryIndex + 4); t++) {
final int nStrikes = strikes[t].length;
final int strikeIndex = SurfaceArrayUtils.getLowerBoundIndex(strikes[t], option.getStrike());
for (int k = Math.max(0, strikeIndex - 6); k < Math.min(nStrikes, strikeIndex + 7); k++) {
// TODO: REVIEW We only recompute the smile function for the specific expiry we are bumping..
final double[] bumpedVols = Arrays.copyOf(vols[t], nStrikes);
bumpedVols[k] = vols[t][k] - shift;
final Function1D<Double, Double> thisExpirysSmile = strikeInterpolator.getVolatilityFunction(forwards[t], strikes[t], volExpiries[t], bumpedVols);
final Function1D<Double, Double>[] scenarioSmileFits = Arrays.copyOf(smileFitsBase, smileFitsBase.length);
scenarioSmileFits[t] = thisExpirysSmile;
final BlackVolatilitySurfaceMoneynessFcnBackedByGrid shiftedSurface = surfaceInterpolator.combineIndependentSmileFits(scenarioSmileFits, volGrid);
//BlackVolatilitySurfaceMoneynessFcnBackedByGrid shiftedSurface = surfaceInterpolator.getBumpedVolatilitySurface(volGrid, t, k, -shift);
final StaticReplicationDataBundle shiftedMarket = market.withShiftedSurface(shiftedSurface);
final Double pvScenario = option.accept(_pricer, shiftedMarket);
ArgumentChecker.notNull(pvScenario, "Null PV in shifted scenario, T = " + volExpiries[t] + ", k = " + strikes[t][k]);
final Double vega = (pvScenario - pvBase) / -shift;
final Triple<Double, Double, Double> xyz = new Triple<>(volExpiries[t], strikes[t][k], vega);
triplesExpiryStrikeVega.add(xyz);