/**
  * Computes the option security price curve sensitivity. The future price is computed without
  * convexity adjustment. It is supposed that for a given strike the volatility does not change
  * with the curves (sticky strike).
  *
  * @param security The future option security.
  * @param normalData The normal volatility and multi-curves provider.
  * @return The security price curve sensitivity.
  */
 @Override
 public MulticurveSensitivity priceCurveSensitivity(
     final InterestRateFutureOptionMarginSecurity security,
     final NormalSTIRFuturesSmileProviderInterface normalData) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(normalData, "Normal data");
   // Forward sweep
   final double priceFuture =
       METHOD_FUTURE.price(security.getUnderlyingFuture(), normalData.getMulticurveProvider());
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(
           security.getStrike(), security.getExpirationTime(), security.isCall());
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double volatility =
       normalData.getVolatility(security.getExpirationTime(), security.getStrike(), delay);
   final NormalFunctionData normalPoint = new NormalFunctionData(priceFuture, 1.0, volatility);
   // Backward sweep
   final double[] priceAdjoint = new double[3];
   NORMAL_FUNCTION.getPriceAdjoint(option, normalPoint, priceAdjoint);
   final double priceBar = 1.0;
   final double priceFutureBar = priceAdjoint[0] * priceBar;
   final MulticurveSensitivity priceFutureDerivative =
       METHOD_FUTURE.priceCurveSensitivity(
           security.getUnderlyingFuture(), normalData.getMulticurveProvider());
   return priceFutureDerivative.multipliedBy(priceFutureBar);
 }
 /**
  * Computes the option security price volatility sensitivity. The future price is computed without
  * convexity adjustment.
  *
  * @param security The future option security.
  * @param normalData The normal volatility and multi-curves provider.
  * @return The security price Black volatility sensitivity.
  */
 public SurfaceValue priceNormalSensitivity(
     final InterestRateFutureOptionMarginSecurity security,
     final NormalSTIRFuturesSmileProviderInterface normalData) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(normalData, "Normal data");
   // Forward sweep
   final double priceFuture =
       METHOD_FUTURE.price(security.getUnderlyingFuture(), normalData.getMulticurveProvider());
   final double strike = security.getStrike();
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(strike, security.getExpirationTime(), security.isCall());
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double volatility =
       normalData.getVolatility(security.getExpirationTime(), security.getStrike(), delay);
   final NormalFunctionData normalPoint = new NormalFunctionData(priceFuture, 1.0, volatility);
   // Backward sweep
   final double[] priceAdjoint = new double[3];
   NORMAL_FUNCTION.getPriceAdjoint(option, normalPoint, priceAdjoint);
   final double priceBar = 1.0;
   final double volatilityBar = priceAdjoint[1] * priceBar;
   final DoublesPair expiryStrikeDelay = new DoublesPair(security.getExpirationTime(), strike);
   final SurfaceValue sensi = SurfaceValue.from(expiryStrikeDelay, volatilityBar);
   return sensi;
 }
 /**
  * Computes the option security price curve sensitivity. The future price is computed without
  * convexity adjustment.
  *
  * @param security The future option security.
  * @param sabrData The SABR data bundle.
  * @return The security price curve sensitivity.
  */
 public PresentValueSABRSensitivityDataBundle priceSABRSensitivity(
     final InterestRateFutureOptionMarginSecurity security,
     final SABRInterestRateDataBundle sabrData) {
   final PresentValueSABRSensitivityDataBundle sensi = new PresentValueSABRSensitivityDataBundle();
   // Forward sweep
   final double priceFuture = METHOD_FUTURE.price(security.getUnderlyingFuture(), sabrData);
   final double rateStrike = 1.0 - security.getStrike();
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall());
   final double forward = 1 - priceFuture;
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double[] volatilityAdjoint =
       sabrData
           .getSABRParameter()
           .getVolatilityAdjoint(security.getExpirationTime(), delay, rateStrike, forward);
   final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatilityAdjoint[0]);
   final double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
   // Backward sweep
   final double priceBar = 1.0;
   final double volatilityBar = priceAdjoint[2] * priceBar;
   final DoublesPair expiryDelay = new DoublesPair(security.getExpirationTime(), delay);
   sensi.addAlpha(expiryDelay, volatilityAdjoint[3] * volatilityBar);
   sensi.addBeta(expiryDelay, volatilityAdjoint[4] * volatilityBar);
   sensi.addRho(expiryDelay, volatilityAdjoint[5] * volatilityBar);
   sensi.addNu(expiryDelay, volatilityAdjoint[6] * volatilityBar);
   return sensi;
 }
 /**
  * Computes the option security price curve sensitivity. The future price is computed without
  * convexity adjustment.
  *
  * @param security The future option security.
  * @param sabrData The SABR data bundle.
  * @return The security price curve sensitivity.
  */
 public InterestRateCurveSensitivity priceCurveSensitivity(
     final InterestRateFutureOptionMarginSecurity security,
     final SABRInterestRateDataBundle sabrData) {
   // Forward sweep
   final double priceFuture = METHOD_FUTURE.price(security.getUnderlyingFuture(), sabrData);
   final double rateStrike = 1.0 - security.getStrike();
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall());
   final double forward = 1 - priceFuture;
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double[] volatilityAdjoint =
       sabrData
           .getSABRParameter()
           .getVolatilityAdjoint(security.getExpirationTime(), delay, rateStrike, forward);
   final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatilityAdjoint[0]);
   final double[] priceAdjoint = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
   // Backward sweep
   final double priceBar = 1.0;
   final double volatilityBar = priceAdjoint[2] * priceBar;
   final double forwardBar = priceAdjoint[1] * priceBar + volatilityAdjoint[1] * volatilityBar;
   final double priceFutureBar = -forwardBar;
   final InterestRateCurveSensitivity priceFutureDerivative =
       METHOD_FUTURE.priceCurveSensitivity(security.getUnderlyingFuture(), sabrData);
   return priceFutureDerivative.multipliedBy(priceFutureBar);
 }
 /**
  * Interpolates and returns the option's implied volatility The future price is computed without
  * convexity adjustment.
  *
  * @param security The future option security.
  * @param normalData The normal volatility and multi-curves provider.
  * @return Lognormal Implied Volatility.
  */
 public double impliedVolatility(
     final InterestRateFutureOptionMarginSecurity security,
     final NormalSTIRFuturesSmileProviderInterface normalData) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(normalData, "Normal data");
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   return normalData.getVolatility(security.getExpirationTime(), security.getStrike(), delay);
 }
 /**
  * Computes the option security price from future price.
  *
  * @param security The future option security.
  * @param normalData The normal volatility and multi-curves provider.
  * @param priceFuture The price of the underlying future.
  * @return The security price.
  */
 public double priceFromFuturePrice(
     final InterestRateFutureOptionMarginSecurity security,
     final NormalSTIRFuturesSmileProviderInterface normalData,
     final double priceFuture) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(normalData, "Normal data");
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(
           security.getStrike(), security.getExpirationTime(), security.isCall());
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double volatility =
       normalData.getVolatility(security.getExpirationTime(), security.getStrike(), delay);
   final NormalFunctionData normalPoint = new NormalFunctionData(priceFuture, 1.0, volatility);
   final double priceSecurity = NORMAL_FUNCTION.getPriceFunction(option).evaluate(normalPoint);
   return priceSecurity;
 }
 /**
  * Computes the option security price from future price.
  *
  * @param security The future option security.
  * @param sabrData The SABR data bundle.
  * @param priceFuture The price of the underlying future.
  * @return The security price.
  */
 public double optionPriceFromFuturePrice(
     final InterestRateFutureOptionMarginSecurity security,
     final SABRInterestRateDataBundle sabrData,
     final double priceFuture) {
   final double rateStrike = 1.0 - security.getStrike();
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(rateStrike, security.getExpirationTime(), !security.isCall());
   final double forward = 1 - priceFuture;
   final double delay =
       security.getUnderlyingFuture().getLastTradingTime() - security.getExpirationTime();
   final double volatility =
       sabrData
           .getSABRParameter()
           .getVolatility(new double[] {security.getExpirationTime(), delay, rateStrike, forward});
   final BlackFunctionData dataBlack = new BlackFunctionData(forward, 1.0, volatility);
   final double priceSecurity = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack);
   return priceSecurity;
 }
 /**
  * Computes the price curve sensitivity in the Hull-White one factor model.
  *
  * @param security The option security.
  * @param hwMulticurves The multi-curves provider with Hull-White one factor parameters.
  * @return The curve sensitivity.
  */
 @Override
 public MulticurveSensitivity priceCurveSensitivity(
     final InterestRateFutureOptionMarginSecurity security,
     final HullWhiteOneFactorProviderInterface hwMulticurves) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(hwMulticurves, "Hull-White and multi-curves data");
   ArgumentChecker.isTrue(
       security.getCurrency().equals(hwMulticurves.getHullWhiteCurrency()),
       "Model currency incompatible with security currency");
   final MulticurveProviderInterface multicurves = hwMulticurves.getMulticurveProvider();
   final HullWhiteOneFactorPiecewiseConstantParameters parameters =
       hwMulticurves.getHullWhiteParameters();
   final double k = security.getStrike();
   final double ktilde = 1.0 - k;
   final double theta = security.getExpirationTime();
   final double delta = security.getUnderlyingFuture().getFixingPeriodAccrualFactor();
   final double t0 = security.getUnderlyingFuture().getTradingLastTime();
   final double t1 = security.getUnderlyingFuture().getFixingPeriodStartTime();
   final double t2 = security.getUnderlyingFuture().getFixingPeriodEndTime();
   // forward sweep
   final double alpha = MODEL.alpha(parameters, 0.0, theta, t1, t2);
   final double gamma = MODEL.futuresConvexityFactor(parameters, t0, t1, t2);
   final double forward =
       multicurves.getSimplyCompoundForwardRate(
           security.getUnderlyingFuture().getIborIndex(), t1, t2, delta);
   final double kappa =
       -Math.log((1 + delta * ktilde) / (1 + delta * forward) / gamma) / alpha - 0.5 * alpha;
   // Bakcward sweep
   final double priceBar = 1.0;
   double forwardBar;
   if (security.isCall()) {
     final double normalAlphaKappa = NORMAL.getCDF(-kappa - alpha);
     forwardBar = -gamma * normalAlphaKappa * priceBar;
   } else {
     final double normalAlphaKappa = NORMAL.getCDF(kappa + alpha);
     forwardBar = gamma * normalAlphaKappa * priceBar;
   }
   final Map<String, List<ForwardSensitivity>> mapFwd = new HashMap<>();
   final List<ForwardSensitivity> listForward = new ArrayList<>();
   listForward.add(new SimplyCompoundedForwardSensitivity(t1, t2, delta, forwardBar));
   mapFwd.put(
       hwMulticurves
           .getMulticurveProvider()
           .getName(security.getUnderlyingFuture().getIborIndex()),
       listForward);
   return MulticurveSensitivity.ofForward(mapFwd);
 }
 /**
  * Computes the price in the Hull-White one factor model.
  *
  * @param security The option security.
  * @param hwMulticurves The multi-curves provider with Hull-White one factor parameters.
  * @return The price.
  */
 @Override
 public double price(
     final InterestRateFutureOptionMarginSecurity security,
     final HullWhiteOneFactorProviderInterface hwMulticurves) {
   ArgumentChecker.notNull(security, "Option security");
   ArgumentChecker.notNull(hwMulticurves, "Hull-White and multi-curves data");
   ArgumentChecker.isTrue(
       security.getCurrency().equals(hwMulticurves.getHullWhiteCurrency()),
       "Model currency incompatible with security currency");
   final MulticurveProviderInterface multicurves = hwMulticurves.getMulticurveProvider();
   final HullWhiteOneFactorPiecewiseConstantParameters parameters =
       hwMulticurves.getHullWhiteParameters();
   final double k = security.getStrike();
   final double ktilde = 1.0 - k;
   final double theta = security.getExpirationTime();
   final double delta = security.getUnderlyingFuture().getFixingPeriodAccrualFactor();
   final double t0 = security.getUnderlyingFuture().getTradingLastTime();
   final double t1 = security.getUnderlyingFuture().getFixingPeriodStartTime();
   final double t2 = security.getUnderlyingFuture().getFixingPeriodEndTime();
   final double alpha = MODEL.alpha(parameters, 0.0, theta, t1, t2);
   final double gamma = MODEL.futuresConvexityFactor(parameters, t0, t1, t2);
   final double forward =
       multicurves.getSimplyCompoundForwardRate(
           security.getUnderlyingFuture().getIborIndex(), t1, t2, delta);
   final double kappa =
       -Math.log((1 + delta * ktilde) / (1 + delta * forward) / gamma) / alpha - 0.5 * alpha;
   if (security.isCall()) {
     final double normalKappa = NORMAL.getCDF(-kappa);
     final double normalAlphaKappa = NORMAL.getCDF(-kappa - alpha);
     return (1 - k + 1.0 / delta) * normalKappa
         - (1.0 / delta + forward) * gamma * normalAlphaKappa;
   }
   final double normalKappa = NORMAL.getCDF(kappa);
   final double normalAlphaKappa = NORMAL.getCDF(kappa + alpha);
   return (1.0 / delta + forward) * gamma * normalAlphaKappa - (1 - k + 1.0 / delta) * normalKappa;
 }