/**
   * This calculates the sensitivity of the present value (PV) to a unit move in the forward. The
   * volatility surface remains unchanged.
   *
   * @param swap the VarianceSwap
   * @param market the VarianceSwapDataBundle
   * @param relShift Relative size of shift made in centered-finite difference approximation.
   * @return A Double. Currency amount per unit amount change in the black volatility
   */
  @SuppressWarnings({})
  public Double calcForwardSensitivity(
      final VarianceSwap swap, final VarianceSwapDataBundle market, final double relShift) {
    Validate.notNull(swap, "null VarianceSwap");
    Validate.notNull(market, "null VarianceSwapDataBundle");

    final VarianceSwapPresentValueCalculator pricer =
        VarianceSwapPresentValueCalculator.getInstance();

    // Shift UP
    VarianceSwapDataBundle bumpedMarket =
        new VarianceSwapDataBundle(
            market.getVolatilitySurface(),
            market.getDiscountCurve(),
            market.getForwardCurve().withFractionalShift(relShift));
    final double pvUp = pricer.visitVarianceSwap(swap, bumpedMarket);

    // Shift Down
    bumpedMarket =
        new VarianceSwapDataBundle(
            market.getVolatilitySurface(),
            market.getDiscountCurve(),
            market.getForwardCurve().withFractionalShift(-relShift));
    final double pvDown = pricer.visitVarianceSwap(swap, bumpedMarket);

    final double t = swap.getTimeToSettlement();
    final double fwd = market.getForwardCurve().getForward(t);
    // Centered-difference result
    return (pvUp - pvDown) / 2.0 / relShift / fwd;
  }
  /**
   * This calculates the sensitivity of the present value (PV) to the lognormal Black implied
   * volatities at the knot points of the surface.
   *
   * <p>Note - the change of the surface due to the movement of a single node is
   * interpolator-dependent, so an instrument may have non-local sensitivity
   *
   * @param swap the VarianceSwap
   * @param market the VarianceSwapDataBundle
   * @param shift Size of shift made in centered-finite difference approximation. e.g. 1% would be
   *     0.01, and 1bp 0.0001
   * @return A Double. Currency amount per unit amount change in the black volatility
   */
  @SuppressWarnings({})
  public Double calcBlackVegaParallel(
      final VarianceSwap swap, final VarianceSwapDataBundle market, final double shift) {
    Validate.notNull(swap, "null VarianceSwap");
    Validate.notNull(market, "null VarianceSwapDataBundle");

    final VarianceSwapPresentValueCalculator pricer =
        VarianceSwapPresentValueCalculator.getInstance();

    // Parallel shift UP
    final BlackVolatilitySurface<?> upSurface =
        market.getVolatilitySurface().withShift(shift, true);
    final double pvUp =
        pricer.visitVarianceSwap(
            swap,
            new VarianceSwapDataBundle(
                upSurface, market.getDiscountCurve(), market.getForwardCurve()));

    // Parallel shift DOWN
    final BlackVolatilitySurface<?> downSurface =
        market.getVolatilitySurface().withShift(-shift, true);
    final double pvDown =
        pricer.visitVarianceSwap(
            swap,
            new VarianceSwapDataBundle(
                downSurface, market.getDiscountCurve(), market.getForwardCurve()));

    // Centered-difference result
    return (pvUp - pvDown) / (2.0 * shift);
  }
  /**
   * Compute the price sensitivity to a shift of the Black volatility at a given maturity and
   * strike.
   *
   * <p>Note - the change of the surface due to the movement of a single node is
   * interpolator-dependent, so an instrument may have non-local sensitivity.
   *
   * <p>Important!!! If the <i>(x, y)</i> value(s) of the shift(s) are not in the nodal points of
   * the original surface, they are added (with shift) to the nodal points of the new surface.
   *
   * @param swap the VarianceSwap
   * @param market the VarianceSwapDataBundle
   * @param maturity a double in same unit as VolatilitySurface
   * @param strike a double in same unit as VolatilitySurface
   * @param shift Size of shift made in centered-finite difference approximation. e.g. 1% would be
   *     0.01, and 1bp 0.0001
   * @return Currency amount per unit amount change in the black volatility at the point provided
   */
  public double calcBlackVegaForSinglePoint(
      final VarianceSwap swap,
      final VarianceSwapDataBundle market,
      final double maturity,
      final double strike,
      final double shift) {

    final VarianceSwapPresentValueCalculator pricer =
        VarianceSwapPresentValueCalculator.getInstance();

    final Surface<Double, Double, Double> surface = market.getVolatilitySurface().getSurface();
    Validate.isTrue(
        surface instanceof InterpolatedDoublesSurface,
        "Currently will only accept a Equity VolatilitySurfaces based on an InterpolatedDoublesSurface");

    final InterpolatedDoublesSurface blackSurf = (InterpolatedDoublesSurface) surface;
    final InterpolatedSurfaceAdditiveShiftFunction volShifter =
        new InterpolatedSurfaceAdditiveShiftFunction();

    // shift UP
    final InterpolatedDoublesSurface bumpedVolUp =
        volShifter.evaluate(blackSurf, maturity, strike, shift);
    VarianceSwapDataBundle bumpedMarket =
        new VarianceSwapDataBundle(
            market.getVolatilitySurface().withSurface(bumpedVolUp),
            market.getDiscountCurve(),
            market.getForwardCurve());
    final double pvUp = pricer.visitVarianceSwap(swap, bumpedMarket);

    // shift DOWN
    final InterpolatedDoublesSurface bumpedVolDown =
        volShifter.evaluate(blackSurf, maturity, strike, -shift);
    bumpedMarket =
        new VarianceSwapDataBundle(
            market.getVolatilitySurface().withSurface(bumpedVolDown),
            market.getDiscountCurve(),
            market.getForwardCurve());
    final double pvDown = pricer.visitVarianceSwap(swap, bumpedMarket);

    // Centered-difference result
    return (pvUp - pvDown) / (2.0 * shift);
  }