// Composition - forward part in the cutoff period; past/valuation date case dealt with in previous methods internal double compositionFactorCutoff() { if (!nextFixing.isAfter(lastFixingNonCutoff)) { OvernightIndexObservation obs = computation.observeOn(lastFixingNonCutoff); double rate = rates.rate(obs); double compositionFactor = 1.0d; for (int i = 0; i < cutoffOffset - 1; i++) { compositionFactor *= 1.0d + accrualFactorCutoff[i] * rate; } return(compositionFactor); } return(1.0d); }
//------------------------------------------------------------------------- // 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); }
/// <summary> /// Test for the case where publication lag=0, effective offset=0 (GBP conventions) and no cutoff period. /// The arithmetic average coupons are used mainly in USD. This test is more for completeness than a real case. /// </summary> public virtual void rateGbpNoCutOffSensitivity() { OvernightIndexRates mockRates = mock(typeof(OvernightIndexRates)); when(mockRates.Index).thenReturn(GBP_SONIA); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); for (int i = 0; i < GBP_OBS.Length; i++) { when(mockRates.rate(GBP_OBS[i])).thenReturn(FIXING_RATES[i]); OvernightRateSensitivity sensitivity = OvernightRateSensitivity.of(GBP_OBS[i], GBP_SONIA.Currency, 1d); when(mockRates.ratePointSensitivity(GBP_OBS[i])).thenReturn(sensitivity); } OvernightAveragedRateComputation ro = OvernightAveragedRateComputation.of(GBP_SONIA, START_DATE, END_DATE, 0, REF_DATA); ForwardOvernightAveragedRateComputationFn obsFn = ForwardOvernightAveragedRateComputationFn.DEFAULT; PointSensitivityBuilder sensitivityBuilderComputed = obsFn.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); PointSensitivities sensitivityComputed = sensitivityBuilderComputed.build().normalized(); double?[] sensitivityExpected = computedSensitivityFD(ro, GBP_SONIA, GBP_OBS); assertEquals(sensitivityComputed.Sensitivities.size(), sensitivityExpected.Length); for (int i = 0; i < sensitivityExpected.Length; ++i) { assertEquals(sensitivityComputed.Sensitivities.get(i).Sensitivity, sensitivityExpected[i], EPS_FD); } }
/// <summary> /// Test for the case where publication lag=0, effective offset=0 (GBP conventions) and no cutoff period. /// The arithmetic average coupons are used mainly in USD. This test is more for completeness than a real case. /// </summary> public virtual void rateGbpNoCutOff() { OvernightIndexRates mockRates = mock(typeof(OvernightIndexRates)); when(mockRates.Index).thenReturn(GBP_SONIA); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); for (int i = 0; i < GBP_OBS.Length; i++) { when(mockRates.rate(GBP_OBS[i])).thenReturn(FIXING_RATES[i]); } OvernightAveragedRateComputation ro = OvernightAveragedRateComputation.of(GBP_SONIA, START_DATE, END_DATE, 0, REF_DATA); ForwardOvernightAveragedRateComputationFn obsFn = ForwardOvernightAveragedRateComputationFn.DEFAULT; double accrualFactorTotal = 0.0d; double accruedRate = 0.0d; int indexLast = 5; // Fixing in the observation period are from 1 to 5 (inclusive) for (int i = 1; i <= indexLast; i++) { LocalDate startDate = GBP_OBS[i].EffectiveDate; LocalDate endDate = GBP_OBS[i].MaturityDate; double af = GBP_SONIA.DayCount.yearFraction(startDate, endDate); accrualFactorTotal += af; accruedRate += FIXING_RATES[i] * af; } double rateExpected = accruedRate / accrualFactorTotal; double rateComputed = obsFn.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); }
/// <summary> /// Test for the case where publication lag=1, effective offset=0 (USD conventions) and cutoff=2 (FedFund swaps). </summary> public virtual void rateFedFund() { OvernightIndexRates mockRates = mock(typeof(OvernightIndexRates)); when(mockRates.Index).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); for (int i = 0; i < USD_OBS.Length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } OvernightAveragedRateComputation ro = OvernightAveragedRateComputation.of(USD_FED_FUND, START_DATE, END_DATE, 2, REF_DATA); ForwardOvernightAveragedRateComputationFn obsFn = ForwardOvernightAveragedRateComputationFn.DEFAULT; double accrualFactorTotal = 0.0d; double accruedRate = 0.0d; int indexLast = 5; // Fixing in the observation period are from 1 to 5 (inclusive), but last is modified by cut-off for (int i = 1; i <= indexLast - 1; i++) { LocalDate endDate = USD_OBS[i].MaturityDate; double af = USD_FED_FUND.DayCount.yearFraction(FIXING_DATES[i], endDate); accrualFactorTotal += af; accruedRate += FIXING_RATES[i] * af; } // CutOff LocalDate endDate = USD_OBS[indexLast].MaturityDate; double af = USD_FED_FUND.DayCount.yearFraction(FIXING_DATES[indexLast], endDate); accrualFactorTotal += af; accruedRate += FIXING_RATES[indexLast - 1] * af; double rateExpected = accruedRate / accrualFactorTotal; double rateComputed = obsFn.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); }
// Accumulated rate - cutoff part if not fixed internal double cutOffAccumulation() { double accumulatedInterest = 0.0d; int nbPeriodNotCutOff = nbPeriods - cutoffOffset + 1; for (int i = Math.Max(fixedPeriod, nbPeriodNotCutOff); i < nbPeriods; i++) { OvernightIndexObservation obs = observations[i]; double forwardRate = rates.rate(obs); accumulatedInterest += obs.YearFraction * forwardRate; } return(accumulatedInterest); }
//------------------------------------------------------------------------- /// <summary> /// Test for the case where publication lag=1, effective offset=0 (USD conventions) and no cutoff period. </summary> public virtual void rateFedFundNoCutOff() { OvernightIndexRates mockRates = mock(typeof(OvernightIndexRates)); when(mockRates.Index).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); for (int i = 0; i < USD_OBS.Length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } OvernightAveragedRateComputation ro = OvernightAveragedRateComputation.of(USD_FED_FUND, START_DATE, END_DATE, 0, REF_DATA); // Accrual dates = fixing dates ForwardOvernightAveragedRateComputationFn obsFn = ForwardOvernightAveragedRateComputationFn.DEFAULT; double accrualFactorTotal = 0.0d; double accruedRate = 0.0d; int indexLast = 5; // Fixing in the observation period are from 1 to 5 (inclusive) for (int i = 1; i <= indexLast; i++) { LocalDate endDate = USD_OBS[i].MaturityDate; double af = USD_FED_FUND.DayCount.yearFraction(FIXING_DATES[i], endDate); accrualFactorTotal += af; accruedRate += FIXING_RATES[i] * af; } double rateExpected = accruedRate / accrualFactorTotal; double rateComputed = obsFn.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); // explain ExplainMapBuilder builder = ExplainMap.builder(); double explainedRate = obsFn.explainRate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv, builder); assertEquals(explainedRate, rateExpected, TOLERANCE_RATE); ExplainMap built = builder.build(); assertEquals(built.get(ExplainKey.OBSERVATIONS).Present, false); assertEquals(built.get(ExplainKey.COMBINED_RATE).Value.doubleValue(), rateExpected, TOLERANCE_RATE); }