public void theta() {
   double priceFutures =
       METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
   double expiry = CALL_JB_147.getExpirationTime();
   double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
   double rate =
       -Math.log(
               ISSUER_SPECIFIC_MULTICURVES
                   .getMulticurveProvider()
                   .getDiscountFactor(CALL_JB_147.getCurrency(), CALL_JB_147.getExpirationTime()))
           / CALL_JB_147.getExpirationTime();
   double thetaCallExpected =
       BlackFormulaRepository.theta(
           priceFutures,
           STRIKE_147,
           CALL_JB_147.getExpirationTime(),
           volatility,
           CALL_JB_147.isCall(),
           rate);
   double thetaCallComputed = METHOD_OPT.theta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   assertEquals(
       "BondFuturesOptionMarginSecurityBlackFlatMethod: theta",
       thetaCallExpected,
       thetaCallComputed,
       TOLERANCE_DELTA);
 }
 public void delta() {
   final double priceFutures =
       METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
   final EuropeanVanillaOption option =
       new EuropeanVanillaOption(
           STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall());
   final double expiry = CALL_JB_147.getExpirationTime();
   final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
   double df =
       ISSUER_SPECIFIC_MULTICURVES
           .getMulticurveProvider()
           .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
   final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
   final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
   final double deltaCallExpected = priceAD[1];
   final double deltaCallComputed = METHOD_OPT.delta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   assertEquals(
       "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta",
       deltaCallExpected,
       deltaCallComputed,
       TOLERANCE_DELTA);
   final double deltaPutComputed = METHOD_OPT.delta(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   assertEquals(
       "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta",
       deltaCallExpected - deltaPutComputed,
       df,
       TOLERANCE_DELTA);
 }
 public void futurePrice() {
   final double priceExpected = METHOD_FUTURE.price(JBM5, ISSUER_SPECIFIC_MULTICURVES);
   final double priceComputed =
       METHOD_OPT.underlyingFuturePrice(CALL_JB_147, ISSUER_SPECIFIC_MULTICURVES);
   assertEquals(
       "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price",
       priceExpected,
       priceComputed,
       TOLERANCE_RATE);
 }
 public void priceFromCurves() {
   final double priceFutures =
       METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
   final double priceExpected =
       METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, priceFutures);
   final double priceComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   assertEquals(
       "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price",
       priceExpected,
       priceComputed,
       TOLERANCE_RATE);
 }
 public void putCallParity() {
   final double priceFutures =
       METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
   final double priceCallComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   final double pricePutComputed = METHOD_OPT.price(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT);
   double df =
       ISSUER_SPECIFIC_MULTICURVES
           .getMulticurveProvider()
           .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
   assertEquals(
       "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: put call parity price",
       priceCallComputed - pricePutComputed,
       (priceFutures - STRIKE_147) * df,
       TOLERANCE_RATE);
 }
/** Tests related to the pricing methods for bond future options with up-front premium payment. */
@Test(groups = TestGroup.UNIT)
public class BondFuturesOptionPremiumSecurityBlackExpStrikeMethodTest {

  /** Bond future option: JGB */
  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2015, 5, 12);

  private static final BondFuturesSecurityDefinition JBM5_DEFINITION =
      BondFuturesDataSets.JBM5_DEFINITION;
  private static final BondFuturesSecurity JBM5 = JBM5_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final double STRIKE_147 = 1.47; // To be close to ATM for the data set used.
  private static final ZonedDateTime EXPIRY_DATE_OPT = DateUtils.getUTCDate(2015, 5, 31);
  private static final boolean IS_CALL = true;
  private static final BondFuturesOptionPremiumSecurityDefinition CALL_JB_147_DEFINITION =
      new BondFuturesOptionPremiumSecurityDefinition(
          JBM5_DEFINITION, EXPIRY_DATE_OPT, STRIKE_147, IS_CALL);
  private static final BondFuturesOptionPremiumSecurityDefinition PUT_JB_147_DEFINITION =
      new BondFuturesOptionPremiumSecurityDefinition(
          JBM5_DEFINITION, EXPIRY_DATE_OPT, STRIKE_147, !IS_CALL);
  private static final BondFuturesOptionPremiumSecurity CALL_JB_147 =
      CALL_JB_147_DEFINITION.toDerivative(REFERENCE_DATE);
  private static final BondFuturesOptionPremiumSecurity PUT_JB_147 =
      PUT_JB_147_DEFINITION.toDerivative(REFERENCE_DATE);
  /** Black surface expiry/log-moneyness */
  private static final InterpolatedDoublesSurface BLACK_SURFACE_EXP_STRIKE =
      StandardDataSetsBlack.BLACK_SURFACE_BND_EXP_STRIKE;
  /** Curves for a specific issuer name */
  private static final IssuerProviderDiscount ISSUER_SPECIFIC_MULTICURVES =
      IssuerProviderDiscountDataSets.ISSUER_SPECIFIC_MULTICURVE_JP;
  /** The legal entity */
  private static final LegalEntity LEGAL_ENTITY_JAPAN = IssuerProviderDiscountDataSets.JP_GOVT;
  /** The Black bond futures provider * */
  // TODO: Change to strike
  private static final BlackBondFuturesExpStrikeProvider BLACK_EXP_STRIKE_BNDFUT =
      new BlackBondFuturesExpStrikeProvider(
          ISSUER_SPECIFIC_MULTICURVES, BLACK_SURFACE_EXP_STRIKE, LEGAL_ENTITY_JAPAN);
  /** Methods and calculators */
  private static final BondFuturesOptionPremiumSecurityBlackBondFuturesMethod METHOD_OPT =
      BondFuturesOptionPremiumSecurityBlackBondFuturesMethod.getInstance();

  private static final BondFuturesSecurityDiscountingMethod METHOD_FUTURE =
      BondFuturesSecurityDiscountingMethod.getInstance();
  private static final BlackPriceFunction BLACK_FUNCTION = new BlackPriceFunction();

  /** Tolerances */
  private static final double TOLERANCE_RATE = 1.0E-10;

  private static final double TOLERANCE_DELTA = 1.0E-8;

  public void impliedVolatility() {
    final double strike = STRIKE_147;
    final double expiry = CALL_JB_147.getExpirationTime();
    final double ivExpected = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, strike);
    final double ivComputed = METHOD_OPT.impliedVolatility(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackSurfaceMethod: impliedVolatility",
        ivExpected,
        ivComputed,
        TOLERANCE_RATE);
  }

  public void futurePrice() {
    final double priceExpected = METHOD_FUTURE.price(JBM5, ISSUER_SPECIFIC_MULTICURVES);
    final double priceComputed =
        METHOD_OPT.underlyingFuturePrice(CALL_JB_147, ISSUER_SPECIFIC_MULTICURVES);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price",
        priceExpected,
        priceComputed,
        TOLERANCE_RATE);
  }

  public void priceFromFuturesPrice() {
    final double price = 1.465;
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(
            STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall());
    final double logmoney = Math.log(STRIKE_147 / price);
    final double expiry = CALL_JB_147.getExpirationTime();
    final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, logmoney);
    double df =
        ISSUER_SPECIFIC_MULTICURVES
            .getMulticurveProvider()
            .getDiscountFactor(JBM5_DEFINITION.getCurrency(), expiry);
    final BlackFunctionData dataBlack = new BlackFunctionData(price, df, volatility);
    final double priceExpected = BLACK_FUNCTION.getPriceFunction(option).evaluate(dataBlack);
    final double priceComputed =
        METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, price);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price",
        priceExpected,
        priceComputed,
        TOLERANCE_RATE);
  }

  public void priceFromCurves() {
    final double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    final double priceExpected =
        METHOD_OPT.priceFromUnderlyingPrice(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT, priceFutures);
    final double priceComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: underlying futures price",
        priceExpected,
        priceComputed,
        TOLERANCE_RATE);
  }

  public void putCallParity() {
    final double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    final double priceCallComputed = METHOD_OPT.price(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    final double pricePutComputed = METHOD_OPT.price(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    double df =
        ISSUER_SPECIFIC_MULTICURVES
            .getMulticurveProvider()
            .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: put call parity price",
        priceCallComputed - pricePutComputed,
        (priceFutures - STRIKE_147) * df,
        TOLERANCE_RATE);
  }

  public void vega() {
    final double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(
            STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall());
    final double expiry = CALL_JB_147.getExpirationTime();
    final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
    double df =
        ISSUER_SPECIFIC_MULTICURVES
            .getMulticurveProvider()
            .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
    final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
    final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
    final double vegaExpected = priceAD[2];
    final double vegaComputed = METHOD_OPT.vega(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: Black parameters sensitivity",
        vegaExpected,
        vegaComputed,
        TOLERANCE_RATE);
  }

  public void delta() {
    final double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(
            STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall());
    final double expiry = CALL_JB_147.getExpirationTime();
    final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
    double df =
        ISSUER_SPECIFIC_MULTICURVES
            .getMulticurveProvider()
            .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
    final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
    final double[] priceAD = BLACK_FUNCTION.getPriceAdjoint(option, dataBlack);
    final double deltaCallExpected = priceAD[1];
    final double deltaCallComputed = METHOD_OPT.delta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta",
        deltaCallExpected,
        deltaCallComputed,
        TOLERANCE_DELTA);
    final double deltaPutComputed = METHOD_OPT.delta(PUT_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: delta",
        deltaCallExpected - deltaPutComputed,
        df,
        TOLERANCE_DELTA);
  }

  public void gamma() {
    final double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    final EuropeanVanillaOption option =
        new EuropeanVanillaOption(
            STRIKE_147, CALL_JB_147.getExpirationTime(), CALL_JB_147.isCall());
    final double expiry = CALL_JB_147.getExpirationTime();
    final double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
    double df =
        ISSUER_SPECIFIC_MULTICURVES
            .getMulticurveProvider()
            .getDiscountFactor(JBM5_DEFINITION.getCurrency(), CALL_JB_147.getExpirationTime());
    final BlackFunctionData dataBlack = new BlackFunctionData(priceFutures, df, volatility);
    final double[] firstDerivs = new double[3];
    final double[][] secondDerivs = new double[3][3];
    BLACK_FUNCTION.getPriceAdjoint2(option, dataBlack, firstDerivs, secondDerivs);
    final double gammaCallExpected = secondDerivs[0][0];
    final double gammaCallComputed = METHOD_OPT.gamma(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionPremiumSecurityBlackBondFuturesMethod: gamma",
        gammaCallExpected,
        gammaCallComputed,
        TOLERANCE_DELTA);
  }

  public void theta() {
    double priceFutures =
        METHOD_FUTURE.price(CALL_JB_147.getUnderlyingFuture(), ISSUER_SPECIFIC_MULTICURVES);
    double expiry = CALL_JB_147.getExpirationTime();
    double volatility = BLACK_SURFACE_EXP_STRIKE.getZValue(expiry, STRIKE_147);
    double rate =
        -Math.log(
                ISSUER_SPECIFIC_MULTICURVES
                    .getMulticurveProvider()
                    .getDiscountFactor(CALL_JB_147.getCurrency(), CALL_JB_147.getExpirationTime()))
            / CALL_JB_147.getExpirationTime();
    double thetaCallExpected =
        BlackFormulaRepository.theta(
            priceFutures,
            STRIKE_147,
            CALL_JB_147.getExpirationTime(),
            volatility,
            CALL_JB_147.isCall(),
            rate);
    double thetaCallComputed = METHOD_OPT.theta(CALL_JB_147, BLACK_EXP_STRIKE_BNDFUT);
    assertEquals(
        "BondFuturesOptionMarginSecurityBlackFlatMethod: theta",
        thetaCallExpected,
        thetaCallComputed,
        TOLERANCE_DELTA);
  }
}