/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.future.provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.opengamma.analytics.financial.interestrate.future.derivative.BondFuturesOptionPremiumSecurity;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackPriceFunction;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.provider.description.interestrate.BlackBondFuturesProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.IssuerProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MulticurveSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.DoublesPair;
/**
* Method for the pricing of bond future options securities with up-front premium.
* The pricing is done with a Black approach.
* The future prices are computed without convexity adjustments and without delivery option.
*/
public final class BondFuturesOptionPremiumSecurityBlackBondFuturesMethod {
/** The method default instance. */
private static final BondFuturesOptionPremiumSecurityBlackBondFuturesMethod DEFAULT =
new BondFuturesOptionPremiumSecurityBlackBondFuturesMethod();
/** The Black function used in the pricing. */
private static final BlackPriceFunction BLACK_FUNCTION = new BlackPriceFunction();
/** The method used to compute the future price. */
private final FuturesSecurityIssuerMethod _methodFutures;
/**
* Default constructor.
*/
private BondFuturesOptionPremiumSecurityBlackBondFuturesMethod() {
_methodFutures = BondFuturesSecurityDiscountingMethod.getInstance();
}
/**
* Constructor from a particular bond futures method. The method is used to compute the price and price curve
* sensitivity of the underlying futures.
* @param methodFutures The bond futures method.
*/
public BondFuturesOptionPremiumSecurityBlackBondFuturesMethod(FuturesSecurityIssuerMethod methodFutures) {
_methodFutures = methodFutures;
}
/**
* Return the method unique instance.
* @return The instance.
*/
public static BondFuturesOptionPremiumSecurityBlackBondFuturesMethod getInstance() {
return DEFAULT;
}
/**
* Computes the option security price from future price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param price The underlying futures price.
* @return The security price.
*/
public double priceFromUnderlyingPrice(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black, double price) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
final double strike = security.getStrike();
final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, security.getExpirationTime(),
security.isCall());
final double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
final double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, price);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), security.getExpirationTime());
final BlackFunctionData dataBlack = new BlackFunctionData(price, df, volatility);
final double priceSecurity = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack);
return priceSecurity;
}
/**
* Computes the option security price without future price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The security price.
*/
public double price(BondFuturesOptionPremiumSecurity security, BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return priceFromUnderlyingPrice(security, black, priceFutures);
}
/**
* Computes the option security price curve sensitivity.
* It is supposed that for a given strike the volatility does not change with the curves.
* The option price and its derivative wrt the futures price is computed using the futures price.
* The derivatives of the futures price with respect to the curves are computed using the curves.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param price The underlying futures price.
* @return The security price curve sensitivity.
*/
public MulticurveSensitivity priceCurveSensitivityFromUnderlyingPrice(final BondFuturesOptionPremiumSecurity security,
final BlackBondFuturesProviderInterface black, final double price) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
// Forward sweep
double strike = security.getStrike();
double expiry = security.getExpirationTime();
EuropeanVanillaOption option = new EuropeanVanillaOption(strike, security.getExpirationTime(), security.isCall());
double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
double volatility = black.getVolatility(expiry, delay, strike, price);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), expiry);
final BlackFunctionData dataBlack = new BlackFunctionData(price, 1.0, volatility);
double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack); // price to be multiplied by df
// Backward sweep
double priceFutureBar = priceAdjoint[1] * df;
double dfBar = priceAdjoint[0];
double rBar = -expiry * df * dfBar;
Map<String, List<DoublesPair>> mapDsc = new HashMap<>();
List<DoublesPair> listDiscounting = new ArrayList<>();
listDiscounting.add(DoublesPair.of(expiry, rBar));
mapDsc.put(black.getMulticurveProvider().getName(security.getCurrency()), listDiscounting);
MulticurveSensitivity pvDdf = MulticurveSensitivity.ofYieldDiscounting(mapDsc);
MulticurveSensitivity priceFutureDerivative = _methodFutures.priceCurveSensitivity(
security.getUnderlyingFuture(), black.getIssuerProvider());
MulticurveSensitivity result = priceFutureDerivative.multipliedBy(priceFutureBar).plus(pvDdf);
return result;
}
/**
* Computes the option security price curve sensitivity.
* It is supposed that for a given strike the volatility does not change with the curves.
* The option price and its derivative wrt the futures price is computed using the futures price.
* The derivatives of the futures price with respect to the curves are computed using the curves.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The security price curve sensitivity.
*/
public MulticurveSensitivity priceCurveSensitivity(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return priceCurveSensitivityFromUnderlyingPrice(security, black, priceFutures);
}
/**
* Interpolates and returns the option's implied volatility
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return Lognormal Implied Volatility.
*/
public double impliedVolatility(final BondFuturesOptionPremiumSecurity security,
final BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
final double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
final double strike = security.getStrike();
final double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
final double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, priceFutures);
return volatility;
}
/**
* Computes the underlying future security price.
* @param security The future option security, not null
* @param issuerMulticurves Issuer and multi-curves provider.
* @return The security price.
*/
public double underlyingFuturePrice(final BondFuturesOptionPremiumSecurity security,
final IssuerProviderInterface issuerMulticurves) {
ArgumentChecker.notNull(security, "security");
return _methodFutures.price(security.getUnderlyingFuture(), issuerMulticurves);
}
/**
* The theoretical delta in the Black model. The underlying futures price is computed from the curves
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The delta.
*/
public double delta(BondFuturesOptionPremiumSecurity security, BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return deltaFromUnderlyingPrice(security, black, priceFutures);
}
/**
* The theoretical delta in the Black model from a given underlying futures price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param priceFutures The underlying futures price.
* @return The delta.
*/
public double deltaFromUnderlyingPrice(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black, double priceFutures) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double strike = security.getStrike();
EuropeanVanillaOption option = new EuropeanVanillaOption(strike, security.getExpirationTime(), security.isCall());
double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, priceFutures);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), security.getExpirationTime());
BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
return priceAdjoint[1];
}
/**
* The theoretical gamma in the Black model. The underlying futures price is computed from the curves
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The gamma.
*/
public double gamma(BondFuturesOptionPremiumSecurity security, BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return gammaFromUnderlyingPrice(security, black, priceFutures);
}
/**
* The theoretical gamma in the Black model from a given underlying futures price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param priceFutures The underlying futures price.
* @return The gamma.
*/
public double gammaFromUnderlyingPrice(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black, double priceFutures) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double strike = security.getStrike();
EuropeanVanillaOption option = new EuropeanVanillaOption(strike, security.getExpirationTime(), security.isCall());
final double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, priceFutures);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), security.getExpirationTime());
BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
double[] firstDerivs = new double[3];
double[][] secondDerivs = new double[3][3];
BLACK_FUNCTION.getPriceAdjoint2(option, dataBlack, firstDerivs, secondDerivs);
return secondDerivs[0][0];
}
/**
* The theoretical vega in the Black model. The underlying futures price is computed from the curves.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The vega.
*/
public double vega(BondFuturesOptionPremiumSecurity security, BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return vegaFromUnderlyingPrice(security, black, priceFutures);
}
/**
* The theoretical vega in the Black model from a given underlying futures price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param priceFutures The underlying futures price.
* @return The vega.
*/
public double vegaFromUnderlyingPrice(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black, double priceFutures) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double strike = security.getStrike();
EuropeanVanillaOption option = new EuropeanVanillaOption(strike, security.getExpirationTime(), security.isCall());
double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, priceFutures);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), security.getExpirationTime());
BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
return BLACK_FUNCTION.getVegaFunction(option).evaluate(dataBlack);
}
/**
* The theoretical theta in the Black model. The underlying futures price is computed from the curves.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @return The theta.
*/
public double theta(BondFuturesOptionPremiumSecurity security, BlackBondFuturesProviderInterface black) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double priceFutures = _methodFutures.price(security.getUnderlyingFuture(), black.getIssuerProvider());
return thetaFromUnderlyingPrice(security, black, priceFutures);
}
/**
* The theoretical theta in the Black model from a given underlying futures price.
* @param security The future option security, not null
* @param black The curve and Black volatility data, not null
* @param priceFutures The underlying futures price.
* @return The theta.
*/
public double thetaFromUnderlyingPrice(BondFuturesOptionPremiumSecurity security,
BlackBondFuturesProviderInterface black, double priceFutures) {
ArgumentChecker.notNull(security, "security");
ArgumentChecker.notNull(black, "Black data");
double strike = security.getStrike();
double delay = security.getUnderlyingFuture().getNoticeLastTime() - security.getExpirationTime();
double volatility = black.getVolatility(security.getExpirationTime(), delay, strike, priceFutures);
double df = black.getMulticurveProvider().getDiscountFactor(security.getCurrency(), security.getExpirationTime());
double rate = -Math.log(df) / security.getExpirationTime();
return BlackFormulaRepository.theta(priceFutures, strike, security.getExpirationTime(), volatility,
security.isCall(), rate);
}
}