/**
   * Calculates the price of the bond future product with z-spread.
   *
   * <p>The price of the product is the price on the valuation date.
   *
   * <p>The z-spread is a parallel shift applied to continuously compounded rates or periodic
   * compounded rates of the issuer discounting curve.
   *
   * @param future the future to price
   * @param provider the rates provider
   * @param zSpread the z-spread
   * @param compoundedRateType the compounded rate type
   * @param periodPerYear the number of periods per year
   * @return the price of the product, in decimal form
   */
  public double priceWithZSpread(
      BondFuture future,
      LegalEntityDiscountingProvider provider,
      double zSpread,
      CompoundedRateType compoundedRateType,
      int periodPerYear) {

    ImmutableList<Security<FixedCouponBond>> bondSecurity = future.getBondSecurityBasket();
    int size = bondSecurity.size();
    double[] priceBonds = new double[size];
    for (int i = 0; i < size; ++i) {
      Security<FixedCouponBond> bond = bondSecurity.get(i);
      double dirtyPrice =
          bondPricer.dirtyPriceFromCurvesWithZSpread(
              bond,
              provider,
              zSpread,
              compoundedRateType,
              periodPerYear,
              future.getLastDeliveryDate());
      priceBonds[i] =
          bondPricer.cleanPriceFromDirtyPrice(
                  bond.getProduct(), future.getLastDeliveryDate(), dirtyPrice)
              / future.getConversionFactor().get(i);
    }
    return Doubles.min(priceBonds);
  }
  private void extremaOp(TiffMeta surface, GridCoverage2D gridCoverage2D) {
    double min = Double.MAX_VALUE;
    double max = Double.MIN_VALUE;

    RenderedImage img = gridCoverage2D.getRenderedImage();

    RenderedOp extremaOp = ExtremaDescriptor.create(img, null, 10, 10, false, 1, null);
    double[] allMins = (double[]) extremaOp.getProperty("minimum");
    min = Doubles.min(allMins);

    double[] allMaxs = (double[]) extremaOp.getProperty("maximum");
    max = Doubles.max(allMaxs);

    surface.setMaxVal(max);
    surface.setMinVal(min);
  }