/// <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); } }
// Accumulated rate sensitivity - cutoff part if not fixed internal PointSensitivityBuilder cutOffAccumulationSensitivity() { PointSensitivityBuilder combinedPointSensitivityBuilder = PointSensitivityBuilder.none(); int nbPeriodNotCutOff = nbPeriods - cutoffOffset + 1; for (int i = Math.Max(fixedPeriod, nbPeriodNotCutOff); i < nbPeriods; i++) { OvernightIndexObservation obs = observations[i]; PointSensitivityBuilder forwardRateSensitivity = rates.ratePointSensitivity(obs).multipliedBy(obs.YearFraction); combinedPointSensitivityBuilder = combinedPointSensitivityBuilder.combinedWith(forwardRateSensitivity); } return(combinedPointSensitivityBuilder); }
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); }
// Composition - forward part in the cutoff period; past/valuation date case dealt with in previous methods internal ObjDoublePair <PointSensitivityBuilder> compositionFactorAndSensitivityCutoff() { OvernightIndexObservation obs = computation.observeOn(lastFixingNonCutoff); if (!nextFixing.isAfter(lastFixingNonCutoff)) { double rate = rates.rate(obs); double compositionFactor = 1.0d; double compositionFactorDerivative = 0.0; for (int i = 0; i < cutoffOffset - 1; i++) { compositionFactor *= 1.0d + accrualFactorCutoff[i] * rate; compositionFactorDerivative += accrualFactorCutoff[i] / (1.0d + accrualFactorCutoff[i] * rate); } compositionFactorDerivative *= compositionFactor; PointSensitivityBuilder rateSensitivity = cutoffOffset <= 1 ? PointSensitivityBuilder.none() : rates.ratePointSensitivity(obs); rateSensitivity = rateSensitivity.multipliedBy(compositionFactorDerivative); return(ObjDoublePair.of(rateSensitivity, compositionFactor)); } return(ObjDoublePair.of(PointSensitivityBuilder.none(), 1.0d)); }