/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.volatility; import com.opengamma.util.ArgumentChecker; /** * Given a set of European-type option data (price, spot, time to expiry) and futures (or discount factor), * derive implied volatility via {@link BlackFormulaRepository}, then compute Greeks by using the derived volatility * * The inverse is also implemented, i.e., volatility -> price, where the Greeks are computed at the same time. */ public class BlackImpliedVolatilityWithGreeks { /** * Compute implied volatility, spot option delta, spot option gamma, spot option vega WITH forward price of underlying * @param spotOptionPrice Option price of spot * @param forward Forward price of underlying * @param spot Spot price of underlying * @param strike Strike price * @param timeToExpiry Time to expiry * @param isCall True for call, false for put * @return {implied volatility, delta, gamma, vega} */ public double[] getImpliedVolatilityAndGreeksForward(final double spotOptionPrice, final double forward, final double spot, final double strike, final double timeToExpiry, final boolean isCall) { ArgumentChecker.isTrue(spotOptionPrice > 0.0, "non-positive/NaN spot option price; have {}", spotOptionPrice); ArgumentChecker.isTrue(forward > 0.0, "non-positive/NaN forward; have {}", forward); ArgumentChecker.isTrue(spot > 0.0, "non-positive/NaN spot; have {}", spot); ArgumentChecker.isTrue(strike > 0.0, "non-positive/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry > 0.0, "non-positive/NaN time to expiry; have {}", timeToExpiry); final double df = spot / forward; final double rescaledPrice = spotOptionPrice / df; final double impliedVol = BlackFormulaRepository.impliedVolatility(rescaledPrice, forward, strike, timeToExpiry, isCall); final double delta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, impliedVol, isCall); final double gamma = BlackFormulaRepository.gamma(forward, strike, timeToExpiry, impliedVol) / df; final double vega = df * BlackFormulaRepository.vega(forward, strike, timeToExpiry, impliedVol); return new double[] {impliedVol, delta, gamma, vega }; } /** * Compute implied volatility, spot option delta, spot option gamma, spot option vega WITH forward option price * @param spotOptionPrice Spot option price * @param forwardOptionPrice Forward option price * @param spot Spot price of underlying * @param strike Strike price * @param timeToExpiry Time to expiry * @param isCall True for call, false for put * @return {implied volatility, delta, gamma, vega} */ public double[] getImpliedVolatilityAndGreeksForwardOption(final double spotOptionPrice, final double forwardOptionPrice, final double spot, final double strike, final double timeToExpiry, final boolean isCall) { ArgumentChecker.isTrue(spotOptionPrice > 0.0, "non-positive/NaN spot option price; have {}", spotOptionPrice); ArgumentChecker.isTrue(forwardOptionPrice > 0.0, "non-positive/NaN forward option price; have {}", forwardOptionPrice); ArgumentChecker.isTrue(spot > 0.0, "non-positive/NaN spot; have {}", spot); ArgumentChecker.isTrue(strike > 0.0, "non-positive/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry > 0.0, "non-positive/NaN time to expiry; have {}", timeToExpiry); final double df = spotOptionPrice / forwardOptionPrice; final double forward = spot / df; final double impliedVol = BlackFormulaRepository.impliedVolatility(forwardOptionPrice, forward, strike, timeToExpiry, isCall); final double delta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, impliedVol, isCall); final double gamma = BlackFormulaRepository.gamma(forward, strike, timeToExpiry, impliedVol) / df; final double vega = df * BlackFormulaRepository.vega(forward, strike, timeToExpiry, impliedVol); return new double[] {impliedVol, delta, gamma, vega }; } /** * Compute implied volatility, spot option delta, spot option gamma, spot option vega WITH discount factor * @param spotOptionPrice Spot option price * @param discountFactor Discount factor * @param spot Spot price of underlying * @param strike Strike price * @param timeToExpiry Time to expiry * @param isCall True for call, false for put * @return {implied volatility, delta, gamma, vega} */ public double[] getImpliedVolatilityAndGreeksDiscountFactor(final double spotOptionPrice, final double discountFactor, final double spot, final double strike, final double timeToExpiry, final boolean isCall) { ArgumentChecker.isTrue(spotOptionPrice > 0.0, "non-positive/NaN spot option price; have {}", spotOptionPrice); ArgumentChecker.isTrue(discountFactor > 0.0, "non-positive/NaN discount factor; have {}", discountFactor); ArgumentChecker.isTrue(spot > 0.0, "non-positive/NaN spot; have {}", spot); ArgumentChecker.isTrue(strike > 0.0, "non-positive/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry > 0.0, "non-positive/NaN time to expiry; have {}", timeToExpiry); final double rescaledPrice = spotOptionPrice / discountFactor; final double forward = spot / discountFactor; final double impliedVol = BlackFormulaRepository.impliedVolatility(rescaledPrice, forward, strike, timeToExpiry, isCall); final double delta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, impliedVol, isCall); final double gamma = BlackFormulaRepository.gamma(forward, strike, timeToExpiry, impliedVol) / discountFactor; final double vega = discountFactor * BlackFormulaRepository.vega(forward, strike, timeToExpiry, impliedVol); return new double[] {impliedVol, delta, gamma, vega }; } /** * Compute spot option price, spot option delta, spot option gamma, spot option vega * @param forward Forward price of underlying * @param spot Spot price of underlying * @param strike Strike price * @param timeToExpiry Time to expiry * @param vol Volatility * @param isCall True for call, false for put * @return {price, delta, gamma, vega} */ public double[] getPriceAndGreeksForward(final double forward, final double spot, final double strike, final double timeToExpiry, final double vol, final boolean isCall) { ArgumentChecker.isTrue(forward > 0.0, "non-positive/NaN forward; have {}", forward); ArgumentChecker.isTrue(spot > 0.0, "non-positive/NaN spot; have {}", spot); ArgumentChecker.isTrue(strike > 0.0, "non-positive/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry > 0.0, "non-positive/NaN time to expiry; have {}", timeToExpiry); ArgumentChecker.isTrue(vol > 0.0, "non-positive/NaN volatility; have {}", vol); final double df = spot / forward; final double price = df * BlackFormulaRepository.price(forward, strike, timeToExpiry, vol, isCall); final double delta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, vol, isCall); final double gamma = BlackFormulaRepository.gamma(forward, strike, timeToExpiry, vol) / df; final double vega = df * BlackFormulaRepository.vega(forward, strike, timeToExpiry, vol); return new double[] {price, delta, gamma, vega }; } /** * Compute spot option price, spot option delta, spot option gamma, spot option vega * @param discountFactor Discount factor * @param spot Spot price of underlying * @param strike Strike price * @param timeToExpiry Time to expiry * @param vol Volatility * @param isCall True for call, false for put * @return {price, delta, gamma, vega} */ public double[] getPriceAndGreeksDiscountFactor(final double discountFactor, final double spot, final double strike, final double timeToExpiry, final double vol, final boolean isCall) { ArgumentChecker.isTrue(discountFactor > 0.0, "non-positive/NaN discount factor; have {}", discountFactor); ArgumentChecker.isTrue(spot > 0.0, "non-positive/NaN spot; have {}", spot); ArgumentChecker.isTrue(strike > 0.0, "non-positive/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry > 0.0, "non-positive/NaN time to expiry; have {}", timeToExpiry); ArgumentChecker.isTrue(vol > 0.0, "non-positive/NaN volatility; have {}", vol); final double forward = spot / discountFactor; final double price = discountFactor * BlackFormulaRepository.price(forward, strike, timeToExpiry, vol, isCall); final double delta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, vol, isCall); final double gamma = BlackFormulaRepository.gamma(forward, strike, timeToExpiry, vol) / discountFactor; final double vega = discountFactor * BlackFormulaRepository.vega(forward, strike, timeToExpiry, vol); return new double[] {price, delta, gamma, vega }; } }