/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.equity.variance.pricing;
import static org.testng.AssertJUnit.assertEquals;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceConverter;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceDelta;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceLogMoneyness;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceMoneyness;
import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceStrike;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;
import com.opengamma.util.test.TestGroup;
/**
* Test.
*/
@Test(groups = TestGroup.UNIT)
public class ExpectedVarianceCalculatorTest {
private static final double TOL = 1e-10;
private static final double SPOT = 80;
private static final double DRIFT = 0.05;
private static final ForwardCurve FORWARD_CURVE = new ForwardCurve(SPOT, DRIFT);
private static final ExpectedVarianceStaticReplicationCalculator CALCULATOR = new ExpectedVarianceStaticReplicationCalculator(TOL);
/**
* Start with a Black volatility surface (strike) - which comes from a mixed log-normal model (hence we know the answer analytically) and convert the surface to ones
* parameterised by moneyness, log-moneyness and (Black) delta, then check we recover the expected value using all four surfaces.
*/
// @Test
public void testMixedLogNormalVolSurface() {
final double sigma1 = 0.2;
final double sigma2 = 1.0;
final double w = 0.9;
final Function<Double, Double> surf = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... x) {
final double t = x[0];
final double k = x[1];
@SuppressWarnings("synthetic-access")
final double fwd = FORWARD_CURVE.getForward(t);
final boolean isCall = k > fwd;
final double price = w * BlackFormulaRepository.price(fwd, k, t, sigma1, isCall) + (1 - w) * BlackFormulaRepository.price(fwd, k, t, sigma2, isCall);
if (price < 1e-100) {
return sigma2;
}
return BlackFormulaRepository.impliedVolatility(price, fwd, k, t, isCall);
}
};
final double expiry = 1.5;
final double fwd = FORWARD_CURVE.getForward(expiry);
final BlackVolatilitySurfaceStrike surfaceStrike = new BlackVolatilitySurfaceStrike(FunctionalDoublesSurface.from(surf));
final BlackVolatilitySurfaceMoneyness surfaceMoneyness = BlackVolatilitySurfaceConverter.toMoneynessSurface(surfaceStrike, FORWARD_CURVE);
final BlackVolatilitySurfaceLogMoneyness surfaceLogMoneyness = BlackVolatilitySurfaceConverter.toLogMoneynessSurface(surfaceStrike, FORWARD_CURVE);
final BlackVolatilitySurfaceDelta surfaceDelta = BlackVolatilitySurfaceConverter.toDeltaSurface(surfaceStrike, FORWARD_CURVE);
final double expected = w * sigma1 * sigma1 + (1 - w) * sigma2 * sigma2;
final double strikeVal = CALCULATOR.getAnnualizedVariance(fwd, expiry, surfaceStrike);
final double moneynessVal = CALCULATOR.getAnnualizedVariance(expiry, surfaceMoneyness);
final double logMoneynessVal = CALCULATOR.getAnnualizedVariance(expiry, surfaceLogMoneyness);
final double deltaVal = CALCULATOR.getAnnualizedVariance(fwd, expiry, surfaceDelta);
assertEquals("strike", expected, strikeVal, TOL);
assertEquals("moneyness", expected, moneynessVal, 200 * TOL); //TODO why do we loss a lot of accuracy
assertEquals("log-moneyness", expected, logMoneynessVal, 200 * TOL);
assertEquals("delta", expected, deltaVal, 100 * TOL);
}
}