//-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value of the CDS index product.
        /// <para>
        /// The present value of the product is based on {@code referenceDate}.
        /// This is typically the valuation date, or cash settlement date if the product is associated with a {@code Trade}.
        /// </para>
        /// <para>
        /// This method can calculate the clean or dirty present value, see <seealso cref="PriceType"/>.
        /// If calculating the clean value, the accrued interest is calculated based on the step-in date.
        ///
        /// </para>
        /// </summary>
        /// <param name="cdsIndex">  the product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="referenceDate">  the reference date </param>
        /// <param name="priceType">  the price type </param>
        /// <param name="refData">  the reference data </param>
        /// <returns> the present value </returns>
        public virtual CurrencyAmount presentValue(ResolvedCdsIndex cdsIndex, CreditRatesProvider ratesProvider, LocalDate referenceDate, PriceType priceType, ReferenceData refData)
        {
            if (isExpired(cdsIndex, ratesProvider))
            {
                return(CurrencyAmount.of(cdsIndex.Currency, 0d));
            }
            ResolvedCds cds                = cdsIndex.toSingleNameCds();
            LocalDate   stepinDate         = cds.StepinDateOffset.adjust(ratesProvider.ValuationDate, refData);
            LocalDate   effectiveStartDate = cds.calculateEffectiveStartDate(stepinDate);
            double      recoveryRate       = underlyingPricer.recoveryRate(cds, ratesProvider);
            Triple <CreditDiscountFactors, LegalEntitySurvivalProbabilities, double> rates = reduceDiscountFactors(cds, ratesProvider);
            double protectionLeg = (1d - recoveryRate) * underlyingPricer.protectionFull(cds, rates.First, rates.Second, referenceDate, effectiveStartDate);
            double rpv01         = underlyingPricer.riskyAnnuity(cds, rates.First, rates.Second, referenceDate, stepinDate, effectiveStartDate, priceType);
            double amount        = cds.BuySell.normalize(cds.Notional) * rates.Third * (protectionLeg - rpv01 * cds.FixedRate);

            return(CurrencyAmount.of(cds.Currency, amount));
        }