//-------------------------------------------------------------------------
        // Compute the approximated rate in the case where the whole period is forward.
        // There is no need to compute overnight periods, except for the cut-off period.
        private double rateForward(OvernightAveragedRateComputation computation, OvernightIndexRates rates)
        {
            OvernightIndex  index                 = computation.Index;
            HolidayCalendar calendar              = computation.FixingCalendar;
            LocalDate       startFixingDate       = computation.StartDate;
            LocalDate       endFixingDateP1       = computation.EndDate;
            LocalDate       endFixingDate         = calendar.previous(endFixingDateP1);
            LocalDate       onRateEndDate         = computation.calculateMaturityFromFixing(endFixingDate);
            LocalDate       onRateStartDate       = computation.calculateEffectiveFromFixing(startFixingDate);
            LocalDate       onRateNoCutOffEndDate = onRateEndDate;
            int             cutoffOffset          = computation.RateCutOffDays > 1 ? computation.RateCutOffDays : 1;
            double          accumulatedInterest   = 0.0d;
            double          accrualFactorTotal    = index.DayCount.yearFraction(onRateStartDate, onRateEndDate);

            if (cutoffOffset > 1)
            {     // Cut-off period
                LocalDate currentFixingDate            = endFixingDate;
                OvernightIndexObservation lastIndexObs = null;
                double cutOffAccrualFactorTotal        = 0d;
                for (int i = 1; i < cutoffOffset; i++)
                {
                    currentFixingDate         = calendar.previous(currentFixingDate);
                    lastIndexObs              = computation.observeOn(currentFixingDate);
                    onRateNoCutOffEndDate     = lastIndexObs.MaturityDate;
                    cutOffAccrualFactorTotal += lastIndexObs.YearFraction;
                }
                double forwardRateCutOff = rates.rate(lastIndexObs);
                accumulatedInterest += cutOffAccrualFactorTotal * forwardRateCutOff;
            }
            // Approximated part
            accumulatedInterest += approximatedInterest(computation.observeOn(onRateStartDate), onRateNoCutOffEndDate, rates);
            // final rate
            return(accumulatedInterest / accrualFactorTotal);
        }
        private PointSensitivityBuilder rateForwardSensitivity(OvernightAveragedRateComputation computation, OvernightIndexRates rates)
        {
            OvernightIndex          index                           = computation.Index;
            HolidayCalendar         calendar                        = computation.FixingCalendar;
            LocalDate               startFixingDate                 = computation.StartDate;
            LocalDate               endFixingDateP1                 = computation.EndDate;
            LocalDate               endFixingDate                   = calendar.previous(endFixingDateP1);
            LocalDate               onRateEndDate                   = computation.calculateMaturityFromFixing(endFixingDate);
            LocalDate               onRateStartDate                 = computation.calculateEffectiveFromFixing(startFixingDate);
            LocalDate               lastNonCutOffMatDate            = onRateEndDate;
            int                     cutoffOffset                    = computation.RateCutOffDays > 1 ? computation.RateCutOffDays : 1;
            PointSensitivityBuilder combinedPointSensitivityBuilder = PointSensitivityBuilder.none();
            double                  accrualFactorTotal              = index.DayCount.yearFraction(onRateStartDate, onRateEndDate);

            if (cutoffOffset > 1)
            {     // Cut-off period
                IList <double> noCutOffAccrualFactorList = new List <double>();
                LocalDate      currentFixingDate         = endFixingDateP1;
                LocalDate      cutOffEffectiveDate;
                for (int i = 0; i < cutoffOffset; i++)
                {
                    currentFixingDate    = calendar.previous(currentFixingDate);
                    cutOffEffectiveDate  = computation.calculateEffectiveFromFixing(currentFixingDate);
                    lastNonCutOffMatDate = computation.calculateMaturityFromEffective(cutOffEffectiveDate);
                    double accrualFactor = index.DayCount.yearFraction(cutOffEffectiveDate, lastNonCutOffMatDate);
                    noCutOffAccrualFactorList.Add(accrualFactor);
                }
                OvernightIndexObservation lastIndexObs = computation.observeOn(currentFixingDate);
                PointSensitivityBuilder   forwardRateCutOffSensitivity = rates.ratePointSensitivity(lastIndexObs);
                double totalAccrualFactor = 0.0;
                for (int i = 0; i < cutoffOffset - 1; i++)
                {
                    totalAccrualFactor += noCutOffAccrualFactorList[i];
                }
                forwardRateCutOffSensitivity    = forwardRateCutOffSensitivity.multipliedBy(totalAccrualFactor);
                combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(forwardRateCutOffSensitivity);
            }
            // Approximated part
            OvernightIndexObservation indexObs = computation.observeOn(onRateStartDate);
            PointSensitivityBuilder   approximatedInterestAndSensitivity = approximatedInterestSensitivity(indexObs, lastNonCutOffMatDate, rates);

            combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(approximatedInterestAndSensitivity);
            combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.multipliedBy(1.0 / accrualFactorTotal);
            // final rate
            return(combinedPointSensitivityBuilder);
        }