/** * 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 com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository; import com.opengamma.analytics.financial.model.volatility.local.LocalVolatilitySurfaceStrike; import com.opengamma.analytics.financial.model.volatility.local.PureLocalVolatilitySurface; import com.opengamma.analytics.financial.model.volatility.surface.BlackVolatilitySurfaceStrike; import com.opengamma.analytics.financial.model.volatility.surface.PureImpliedVolatilitySurface; import com.opengamma.analytics.math.function.Function; import com.opengamma.analytics.math.surface.FunctionalDoublesSurface; import com.opengamma.util.ArgumentChecker; /** * Class containing utility methods for pure volatility surfaces */ public class VolatilitySurfaceConverter { /** * Converts a Black volatility surface (parameterised by strike) to a pure implied volatility surface. * @param volSurface The Black volatility surface, not null * @param divCurves Bundle containing a discounting curve, forward curve and dividends data, not null * @return A pure implied surface */ public static PureImpliedVolatilitySurface convertImpliedVolSurface(final BlackVolatilitySurfaceStrike volSurface, final EquityDividendsCurvesBundle divCurves) { ArgumentChecker.notNull(volSurface, "volatility surface"); ArgumentChecker.notNull(divCurves, "curves and dividend data"); final Function<Double, Double> impVol = new Function<Double, Double>() { @Override public Double evaluate(final Double... tx) { final double t = tx[0]; final double x = tx[1]; final double f = divCurves.getF(t); final double d = divCurves.getD(t); final boolean isCall = x > 1.0; final double k = (f - d) * x + d; final double vol = volSurface.getVolatility(t, k); final double price = BlackFormulaRepository.price(f, k, t, vol, isCall); if (price < 0.0) { return 0.0; } final double vol2 = BlackFormulaRepository.impliedVolatility(price / (f - d), 1.0, x, t, isCall); return vol2; } }; return new PureImpliedVolatilitySurface(FunctionalDoublesSurface.from(impVol)); } /** * Converts a pure implied volatility surface to a Black volatility surface parameterised by strike. * @param pureVolSurface The pure volatility surface, not null * @param divCurves Bundle containing a discounting curve, forward curve and dividends data, not null * @return A Black volatility surface parameterised by strike */ public static BlackVolatilitySurfaceStrike convertImpliedVolSurface(final PureImpliedVolatilitySurface pureVolSurface, final EquityDividendsCurvesBundle divCurves) { ArgumentChecker.notNull(pureVolSurface, "pure volatility surface"); ArgumentChecker.notNull(divCurves, "curves and dividend data"); final Function<Double, Double> impVol = new Function<Double, Double>() { @Override public Double evaluate(final Double... tk) { final double t = tk[0]; final double k = tk[1]; final double f = divCurves.getF(t); final double d = divCurves.getD(t); if (k < d) { return 0.0; } final boolean isCall = k > f; final double x = (k - d) / (f - d); final double vol = pureVolSurface.getVolatility(t, x); final double price = (f - d) * BlackFormulaRepository.price(1.0, x, t, vol, isCall); if (price < 0.0) { return 0.0; } final double vol2 = BlackFormulaRepository.impliedVolatility(price, f, k, t, isCall); return vol2; } }; return new BlackVolatilitySurfaceStrike(FunctionalDoublesSurface.from(impVol)); } /** * Converts a local volatility surface (parameterised by strike) to a pure implied volatility surface. * @param volSurface The local volatility surface, not null * @param divCurves Bundle containing a discounting curve, forward curve and dividends data, not null * @return A Black volatility surface parameterised by strike */ public static PureLocalVolatilitySurface convertLocalVolSurface(final LocalVolatilitySurfaceStrike volSurface, final EquityDividendsCurvesBundle divCurves) { ArgumentChecker.notNull(volSurface, "volatility surface"); ArgumentChecker.notNull(divCurves, "curves and dividend data"); final Function<Double, Double> pureLocalVol = new Function<Double, Double>() { @Override public Double evaluate(final Double... tx) { final double t = tx[0]; final double x = tx[1]; final double d = divCurves.getD(t); final double f = divCurves.getF(t); final double s = (f - d) * x + d; return volSurface.getVolatility(t, s) * s / (s - d); } }; return new PureLocalVolatilitySurface(FunctionalDoublesSurface.from(pureLocalVol)); } /** * Converts a pure local volatility surface to a local volatility surface. * @param pureVolSurface The pure local volatility surface, not null * @param divCurves Bundle containing a discounting curve, forward curve and dividends data, not null * @return A local volatility surface */ public static LocalVolatilitySurfaceStrike convertLocalVolSurface(final PureLocalVolatilitySurface pureVolSurface, final EquityDividendsCurvesBundle divCurves) { ArgumentChecker.notNull(pureVolSurface, "volatility surface"); ArgumentChecker.notNull(divCurves, "curves and dividend data"); final Function<Double, Double> localVol = new Function<Double, Double>() { @Override public Double evaluate(final Double... ts) { final double t = ts[0]; final double s = ts[1]; final double d = divCurves.getD(t); if (s < d) { return 0.0; } final double f = divCurves.getF(t); final double x = (s - d) / (f - d); return pureVolSurface.getVolatility(t, x) * (s - d) / s; } }; return new LocalVolatilitySurfaceStrike(FunctionalDoublesSurface.from(localVol)); } }