package com.opengamma.analytics.financial.model.option.pricing.fourier;
import static org.testng.AssertJUnit.assertEquals;
import java.util.HashSet;
import org.apache.commons.lang.NotImplementedException;
import org.testng.annotations.Test;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.Sets;
import com.opengamma.analytics.financial.greeks.Greek;
import com.opengamma.analytics.financial.greeks.GreekResultCollection;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.model.option.definition.BlackOptionDataBundle;
import com.opengamma.analytics.financial.model.option.definition.EuropeanVanillaOptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.OptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.StandardOptionDataBundle;
import com.opengamma.analytics.financial.model.option.pricing.OptionModel;
import com.opengamma.analytics.financial.model.option.pricing.analytic.BlackScholesMertonModel;
import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurface;
import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
import com.opengamma.analytics.math.surface.ConstantDoublesSurface;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Expiry;
/**
* Test.
*/
@Test(groups = TestGroup.UNIT)
public class FFTOptionModelTest {
private static final HashSet<Greek> GREEKS = Sets.newHashSet(Greek.FAIR_PRICE);
private static final double R = 0.005;
private static final YieldCurve YIELD_CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
private static final double BLACK_VOL = 0.34;
private static final VolatilitySurface VOLATILITY_SURFACE = new VolatilitySurface(ConstantDoublesSurface.from(BLACK_VOL));
private static final double FORWARD = 100;
private static final double T = 2;
private static final ZonedDateTime DATE = DateUtils.getUTCDate(2011, 1, 1);
private static final ZonedDateTime MATURITY = DATE.plusYears((int) T);
private static final Expiry EXPIRY = new Expiry(MATURITY);
private static final EuropeanVanillaOptionDefinition ITM_CALL = new EuropeanVanillaOptionDefinition(99, EXPIRY, true);
private static final EuropeanVanillaOptionDefinition OTM_CALL = new EuropeanVanillaOptionDefinition(101, EXPIRY, true);
private static final EuropeanVanillaOptionDefinition ITM_PUT = new EuropeanVanillaOptionDefinition(101, EXPIRY, false);
private static final EuropeanVanillaOptionDefinition OTM_PUT = new EuropeanVanillaOptionDefinition(99, EXPIRY, false);
private static final MartingaleCharacteristicExponent GAUSSIAN = new GaussianMartingaleCharacteristicExponent(BLACK_VOL);
private static final StandardOptionDataBundle BSM_DATA = new StandardOptionDataBundle(YIELD_CURVE, R, VOLATILITY_SURFACE, Math.exp(-R * T) * FORWARD, DATE);
private static final BlackOptionDataBundle BLACK_DATA = new BlackOptionDataBundle(FORWARD, YIELD_CURVE, VOLATILITY_SURFACE, DATE);
private static final OptionModel<EuropeanVanillaOptionDefinition, BlackOptionDataBundle> FFT_MODEL = new FFTOptionModel(GAUSSIAN);
private static final OptionModel<OptionDefinition, StandardOptionDataBundle> BSM_MODEL = new BlackScholesMertonModel();
private static final double EPS = 1e-2;
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullCharacteristicExponent1() {
new FFTOptionModel(null);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullCharacteristicExponent2() {
new FFTOptionModel(null, 100, 10, -0.5, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNegativeNStrikes() {
new FFTOptionModel(GAUSSIAN, -100, 10, -0.5, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNegativeDelta() {
new FFTOptionModel(GAUSSIAN, 100, -10, -0.5, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testZeroAlpha() {
new FFTOptionModel(GAUSSIAN, 100, 10, 0, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testAlpha() {
new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNegativeTolerance() {
new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullDefinition() {
FFT_MODEL.getGreeks(null, BLACK_DATA, GREEKS);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullData() {
FFT_MODEL.getGreeks(ITM_CALL, null, GREEKS);
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNullGreeks() {
FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, null);
}
@Test(expectedExceptions = NotImplementedException.class)
public void testWrongGreeks() {
FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, Sets.newHashSet(Greek.DELTA, Greek.GAMMA));
}
@Test
public void testPricing() {
GreekResultCollection fftPrice = FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, GREEKS);
GreekResultCollection bsmPrice = BSM_MODEL.getGreeks(ITM_CALL, BSM_DATA, GREEKS);
assertEquals(fftPrice.size(), 1);
assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
fftPrice = FFT_MODEL.getGreeks(OTM_CALL, BLACK_DATA, GREEKS);
bsmPrice = BSM_MODEL.getGreeks(OTM_CALL, BSM_DATA, GREEKS);
assertEquals(fftPrice.size(), 1);
assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
fftPrice = FFT_MODEL.getGreeks(OTM_PUT, BLACK_DATA, GREEKS);
bsmPrice = BSM_MODEL.getGreeks(OTM_PUT, BSM_DATA, GREEKS);
assertEquals(fftPrice.size(), 1);
assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
fftPrice = FFT_MODEL.getGreeks(ITM_PUT, BLACK_DATA, GREEKS);
bsmPrice = BSM_MODEL.getGreeks(ITM_PUT, BSM_DATA, GREEKS);
assertEquals(fftPrice.size(), 1);
assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS);
}
}