/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.pricing; import static org.testng.AssertJUnit.assertEquals; import org.testng.annotations.Test; import com.opengamma.analytics.financial.model.option.DistributionFromImpliedVolatility; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.NormalFunctionData; import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.NormalPriceFunction; import com.opengamma.analytics.financial.model.volatility.BlackImpliedVolatilityFormula; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.analytics.math.statistics.distribution.NormalDistribution; import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution; import com.opengamma.util.test.TestGroup; /** * Test. */ @Test(groups = TestGroup.UNIT) public class DistributionFromImpliedVolatilityTest { private static double F = 4.0; private static double VOL = 0.3; private static double NORMAL_VOL; private static double T = 2.5; private static double ROOT_T = Math.sqrt(T); private static double ROOT_2_PI = Math.sqrt(2 * Math.PI); private static ProbabilityDistribution<Double> BLACK; private static ProbabilityDistribution<Double> BACHELIER; private static ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1); private static final BlackImpliedVolatilityFormula BLACK_IMPLIED_VOL = new BlackImpliedVolatilityFormula(); private static final NormalPriceFunction NORMAL_PRICE_FUNCTION = new NormalPriceFunction(); private static Function1D<Double, Double> FLAT = new Function1D<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double x) { return VOL; } }; private static Function1D<Double, Double> NORM = new Function1D<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double x) { final EuropeanVanillaOption option = new EuropeanVanillaOption(x, T, true); final NormalFunctionData dataNormal = new NormalFunctionData(F, 1, NORMAL_VOL); final double price = NORMAL_PRICE_FUNCTION.getPriceFunction(option).evaluate(dataNormal); final BlackFunctionData dataBlack = new BlackFunctionData(F, 1, VOL); return BLACK_IMPLIED_VOL.getImpliedVolatility(dataBlack, option, price); } }; static { BLACK = new DistributionFromImpliedVolatility(F, T, FLAT); BACHELIER = new DistributionFromImpliedVolatility(F, T, NORM); NORMAL_VOL = F * VOL; } @Test public void logNormalTest() { for (int i = 0; i < 100; i++) { final double x = 0.1 + 0.1 * i; // System.out.println(x + "\t" + logNormalPDF(x) + "\t" + BLACK.getPDF(x)); assertEquals(logNormalPDF(x), BLACK.getPDF(x), 1e-6); assertEquals(logNormalCDF(x), BLACK.getCDF(x), 1e-6); } } @Test public void normalTest() { for (int i = 0; i < 100; i++) { final double x = 0.1 + 0.1 * i; // System.out.println(x + "\t" + normalPDF(x) + "\t" + BACHELIER.getPDF(x)); assertEquals(normalPDF(x), BACHELIER.getPDF(x), 1e-4); assertEquals(normalCDF(x), BACHELIER.getCDF(x), 1e-4); } } private double normalPDF(final double x) { return NORMAL.getPDF((x - F) / NORMAL_VOL / ROOT_T) / NORMAL_VOL / ROOT_T; } private double normalCDF(final double x) { return NORMAL.getCDF((x - F) / NORMAL_VOL / ROOT_T); } private double logNormalPDF(final double x) { if (x <= 0) { return 0.0; } final double d1 = (Math.log(x / F) + VOL * VOL * T / 2) / VOL / ROOT_T; return Math.exp(-d1 * d1 / 2) / ROOT_2_PI / VOL / ROOT_T / x; } private double logNormalCDF(final double x) { if (x <= 0) { return 0.0; } final double d2 = (Math.log(F / x) - VOL * VOL * T / 2) / VOL / ROOT_T; return NORMAL.getCDF(-d2); } }