/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.commodity.calculator; import com.opengamma.analytics.financial.commodity.derivative.CommodityFutureOption; import com.opengamma.analytics.financial.equity.StaticReplicationDataBundle; import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository; import com.opengamma.util.ArgumentChecker; /** * Black methods for commodity future option prices and greeks. */ public final class CommodityFutureOptionBlackMethod { /** A static instance of this class */ private static final CommodityFutureOptionBlackMethod INSTANCE = new CommodityFutureOptionBlackMethod(); /** * @return The static instance of this class */ public static CommodityFutureOptionBlackMethod getInstance() { return INSTANCE; } /** * Private constructor */ private CommodityFutureOptionBlackMethod() { } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the <b>forward</b> price of an option using the Black formula. PV / ZeroBond(timeToSettlement) */ public double forwardPrice(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double notional = derivative.getUnderlying().getUnitAmount(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double fwdPrice = BlackFormulaRepository.price(forward, strike, expiry, blackVol, derivative.isCall()); return notional * fwdPrice; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return Current DiscountBond or ZeroBond price for payment at the settlement date */ public double discountToSettlement(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double df = marketData.getDiscountCurve().getDiscountFactor(derivative.getUnderlying().getSettlement()); return df; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the <b>forward</b> value of the index, ie the fair strike of a forward agreement paying the index value at maturity */ public double forwardIndexValue(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double forward = marketData.getForwardCurve().getForward(expiry); return forward; } /** * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the <b>spot</b> value of the index, i.e. the current market value */ public double spotIndexValue(final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(marketData, "marketData"); final double spot = marketData.getForwardCurve().getSpot(); return spot; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the present value of the option */ public double presentValue(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double fwdPrice = forwardPrice(derivative, marketData); final double df = discountToSettlement(derivative, marketData); return df * fwdPrice; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the sensitivity of the present value wrt the discounting rate */ public double rho(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double ttm = derivative.getUnderlying().getSettlement(); final double pv = presentValue(derivative, marketData); return -ttm * pv; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the delta */ public double delta(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final boolean isCall = derivative.isCall(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); return BlackFormulaRepository.delta(forward, strike, expiry, blackVol, isCall); } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the forward delta wrt the forward underlying, ie the sensitivity of the undiscounted price to the forward value of the underlying, d(PV/Z)/d(fwdUnderlying) */ public double forwardDelta(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double undiscountDelta = delta(derivative, marketData); return undiscountDelta; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the sensitivity of the present value wrt the forward value of the underlying, d(PV)/d(fwdUnderlying) */ public double deltaWrtForward(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double forwardDelta = forwardDelta(derivative, marketData); final double zeroBond = discountToSettlement(derivative, marketData); return forwardDelta * zeroBond; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot delta wrt the underlying, d(PV)/d(spotUnderlying) */ public double deltaWrtSpot(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double deltaWrtForward = deltaWrtForward(derivative, marketData); final double forwardUnderlying = forwardIndexValue(derivative, marketData); final double spotUnderlying = marketData.getForwardCurve().getSpot(); final double dForwardDSpot = forwardUnderlying / spotUnderlying; return deltaWrtForward * dForwardDSpot; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the forward gamma wrt the forward underlying, ie the 2nd order sensitivity of the undiscounted price to the forward value of the underlying, * $\frac{\partial^2 (PV/Z)}{\partial F^2}$ */ public double forwardGamma(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double forwardGamma = BlackFormulaRepository.gamma(forward, strike, expiry, blackVol); return forwardGamma; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the sensitivity of the forward delta wrt the forward value of the underlying, $\frac{\partial^2 (PV)}{\partial F^2}$ */ public double gammaWrtForward(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double forwardGamma = forwardGamma(derivative, marketData); final double zeroBond = discountToSettlement(derivative, marketData); return forwardGamma * zeroBond; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot gamma wrt the spot underlying, ie the 2nd order sensitivity of the present value to the spot value of the underlying, * $\frac{\partial^2 (PV)}{\partial S^2}$ */ public double gammaWrtSpot(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double gammaWrtForward = gammaWrtForward(derivative, marketData); final double forwardUnderlying = forwardIndexValue(derivative, marketData); final double spotUnderlying = marketData.getForwardCurve().getSpot(); final double dForwardDSpot = forwardUnderlying / spotUnderlying; return gammaWrtForward * dForwardDSpot * dForwardDSpot; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the simple vega, d(PV)/d(blackVol) */ public double vega(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double fwdVega = BlackFormulaRepository.vega(forward, strike, expiry, blackVol); final double df = discountToSettlement(derivative, marketData); return df * fwdVega; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the lognormal Black Volatility */ public double impliedVol(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); return blackVol; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the forward Vomma, ie the 2nd order sensitivity of the undiscounted price to the implied vol, * $\frac{\partial^2 (PV/Z)}{\partial \sigma^2}$ */ public double forwardVomma(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double forwardVomma = BlackFormulaRepository.vomma(forward, strike, expiry, blackVol); return forwardVomma; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot Vomma, ie the 2nd order sensitivity of the spot price to the implied vol, * $\frac{\partial^2 (PV)}{\partial \sigma^2}$ */ public double vomma(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double forwardVomma = forwardVomma(derivative, marketData); final double zeroBond = discountToSettlement(derivative, marketData); return forwardVomma * zeroBond; } /** * Synonym for Vomma * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot Volga, ie the 2nd order sensitivity of the spot price to the implied vol, * $\frac{\partial^2 (PV)}{\partial \sigma^2}$ */ public double spotVolga(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); return vomma(derivative, marketData); } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the forward vanna wrt the forward underlying, ie the 2nd order cross-sensitivity of the undiscounted price to the forward and implied vol, * $\frac{\partial^2 (PV/Z)}{\partial F \partial \sigma}$ */ public double forwardVanna(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double strike = derivative.getStrike(); final double forward = marketData.getForwardCurve().getForward(expiry); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double forwardVanna = BlackFormulaRepository.vanna(forward, strike, expiry, blackVol); return forwardVanna; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot vanna wrt the forward underlying, ie the 2nd order cross-sensitivity of the present value to the forward and implied vol, * $\frac{\partial^2 (PV)}{\partial F \partial \sigma}$ */ public double vannaWrtForward(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double forwardVanna = forwardVanna(derivative, marketData); final double zeroBond = discountToSettlement(derivative, marketData); return forwardVanna * zeroBond; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the spot vanna wrt the spot underlying, ie the 2nd order cross-sensitivity of the present value to the spot and implied vol, * $\frac{\partial^2 (PV)}{\partial spot \partial \sigma}$ */ public double vannaWrtSpot(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double vannaWrtForward = vannaWrtForward(derivative, marketData); final double forwardUnderlying = forwardIndexValue(derivative, marketData); final double spotUnderlying = marketData.getForwardCurve().getSpot(); final double dForwardDSpot = forwardUnderlying / spotUnderlying; return vannaWrtForward * dForwardDSpot; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return Spot theta, ie the sensitivity of the present value to the time to expiration, * $\frac{\partial (PV)}{\partial t}$ */ public double theta(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double forward = marketData.getForwardCurve().getForward(expiry); final double strike = derivative.getStrike(); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double interestRate = marketData.getDiscountCurve().getInterestRate(expiry); final double theta = BlackFormulaRepository.theta(forward, strike, expiry, blackVol, derivative.isCall(), interestRate); return theta; } /** * @param derivative the OG-Analytics form of the derivative * @param marketData the data bundle containing a BlackVolatilitySurface, forward commodity and funding curves * @return the forward (i.e. driftless) theta */ public double forwardTheta(final CommodityFutureOption<?> derivative, final StaticReplicationDataBundle marketData) { ArgumentChecker.notNull(derivative, "derivative"); ArgumentChecker.notNull(marketData, "marketData"); final double expiry = derivative.getExpiry(); final double forward = marketData.getForwardCurve().getForward(expiry); final double strike = derivative.getStrike(); final double blackVol = marketData.getVolatilitySurface().getVolatility(expiry, strike); final double forwardTheta = BlackFormulaRepository.driftlessTheta(forward, strike, expiry, blackVol); return forwardTheta; } }