//-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the Ibor cap/floor product.
        /// <para>
        /// The present value of the product is the value on the valuation date.
        /// </para>
        /// <para>
        /// The cap/floor leg and pay leg are typically in the same currency, thus the
        /// present value gamma is expressed as a single currency amount in most cases.
        ///
        /// </para>
        /// </summary>
        /// <param name="capFloor">  the Ibor cap/floor product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the volatilities </param>
        /// <returns> the present value </returns>
        public virtual MultiCurrencyAmount presentValue(ResolvedIborCapFloor capFloor, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities)
        {
            CurrencyAmount pvCapFloorLeg = capFloorLegPricer.presentValue(capFloor.CapFloorLeg, ratesProvider, volatilities);

            if (!capFloor.PayLeg.Present)
            {
                return(MultiCurrencyAmount.of(pvCapFloorLeg));
            }
            CurrencyAmount pvPayLeg = payLegPricer.presentValue(capFloor.PayLeg.get(), ratesProvider);

            return(MultiCurrencyAmount.of(pvCapFloorLeg).plus(pvPayLeg));
        }
        //-------------------------------------------------------------------------
        // create complete lists of caps, volatilities, strikes, expiries
        protected internal virtual void reduceRawData(IborCapletFloorletVolatilityDefinition definition, RatesProvider ratesProvider, DoubleArray strikes, DoubleArray volatilityData, DoubleArray errors, LocalDate startDate, LocalDate endDate, SurfaceMetadata metadata, System.Func <Surface, IborCapletFloorletVolatilities> volatilityFunction, IList <double> timeList, IList <double> strikeList, IList <double> volList, IList <ResolvedIborCapFloorLeg> capList, IList <double> priceList, IList <double> errorList)
        {
            int nStrikes = strikes.size();

            for (int i = 0; i < nStrikes; ++i)
            {
                if (Double.isFinite(volatilityData.get(i)))
                {
                    ResolvedIborCapFloorLeg capFloor = definition.createCap(startDate, endDate, strikes.get(i)).resolve(referenceData);
                    capList.Add(capFloor);
                    strikeList.Add(strikes.get(i));
                    volList.Add(volatilityData.get(i));
                    ConstantSurface constVolSurface     = ConstantSurface.of(metadata, volatilityData.get(i));
                    IborCapletFloorletVolatilities vols = volatilityFunction(constVolSurface);
                    timeList.Add(vols.relativeTime(capFloor.FinalFixingDateTime));
                    priceList.Add(pricer.presentValue(capFloor, ratesProvider, vols).Amount);
                    errorList.Add(errors.get(i));
                }
            }
        }