/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.impl.rate; import static com.opengamma.strata.basics.date.DayCounts.ACT_ACT_ISDA; import static com.opengamma.strata.basics.index.OvernightIndices.CHF_TOIS; import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND; import static com.opengamma.strata.collect.TestHelper.assertThrows; import static com.opengamma.strata.collect.TestHelper.date; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import org.testng.annotations.Test; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.index.OvernightIndexObservation; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeriesBuilder; import com.opengamma.strata.market.curve.Curve; import com.opengamma.strata.market.curve.Curves; import com.opengamma.strata.market.curve.InterpolatedNodalCurve; import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; import com.opengamma.strata.market.explain.ExplainKey; import com.opengamma.strata.market.explain.ExplainMap; import com.opengamma.strata.market.explain.ExplainMapBuilder; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; import com.opengamma.strata.pricer.PricingException; import com.opengamma.strata.pricer.rate.ImmutableRatesProvider; import com.opengamma.strata.pricer.rate.OvernightIndexRates; import com.opengamma.strata.pricer.rate.OvernightRateSensitivity; import com.opengamma.strata.pricer.rate.SimpleRatesProvider; import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator; import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; /** * Test {@link ForwardOvernightCompoundedRateComputationFn}. */ @Test public class ForwardOvernightCompoundedRateComputationFnTest { private static final ReferenceData REF_DATA = ReferenceData.standard(); private static final LocalDate DUMMY_ACCRUAL_START_DATE = date(2015, 1, 1); // Accrual dates irrelevant for the rate private static final LocalDate DUMMY_ACCRUAL_END_DATE = date(2015, 1, 31); // Accrual dates irrelevant for the rate private static final LocalDate FIXING_START_DATE = date(2015, 1, 8); private static final LocalDate FIXING_END_DATE = date(2015, 1, 15); // 1w only to decrease data private static final LocalDate FIXING_FINAL_DATE = date(2015, 1, 14); private static final LocalDate[] FIXING_DATES = new LocalDate[] { date(2015, 1, 7), date(2015, 1, 8), date(2015, 1, 9), date(2015, 1, 12), date(2015, 1, 13), date(2015, 1, 14), date(2015, 1, 15)}; private static final OvernightIndexObservation[] USD_OBS = new OvernightIndexObservation[] { OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 7), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 8), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 9), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 12), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 13), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 14), REF_DATA), OvernightIndexObservation.of(USD_FED_FUND, date(2015, 1, 15), REF_DATA)}; private static final OvernightIndexObservation[] GBP_OBS = new OvernightIndexObservation[] { OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 7), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 8), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 9), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 12), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 13), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 14), REF_DATA), OvernightIndexObservation.of(GBP_SONIA, date(2015, 1, 15), REF_DATA)}; private static final OvernightIndexObservation[] CHF_OBS = new OvernightIndexObservation[] { OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 7), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 8), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 9), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 12), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 13), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 14), REF_DATA), OvernightIndexObservation.of(CHF_TOIS, date(2015, 1, 15), REF_DATA)}; private static final double[] FIXING_RATES = { 0.0012, 0.0023, 0.0034, 0.0045, 0.0056, 0.0067, 0.0078}; private static final double[] FORWARD_RATES = { 0.0112, 0.0123, 0.0134, 0.0145, 0.0156, 0.0167, 0.0178}; private static final double TOLERANCE_RATE = 1.0E-10; private static final double EPS_FD = 1.0E-7; private static final ForwardOvernightCompoundedRateComputationFn OBS_FWD_ONCMP = ForwardOvernightCompoundedRateComputationFn.DEFAULT; /** No cutoff period and the period entirely forward. Test the forward part only. */ public void rateFedFundNoCutOffForward() { // publication=1, cutoff=0, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); double rateCmp = 0.0123; when(mockRates.periodRate(USD_OBS[1], FIXING_END_DATE)).thenReturn(rateCmp); double rateExpected = rateCmp; for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } // explain ExplainMapBuilder builder = ExplainMap.builder(); double explainedRate = OBS_FWD_ONCMP.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).isPresent(), false); assertEquals(built.get(ExplainKey.COMBINED_RATE).get().doubleValue(), rateExpected, TOLERANCE_RATE); } /** No cutoff period and the period entirely forward. Test the forward part only against FD approximation. */ public void rateFedFundNoCutOffForwardSensitivity() { // publication=1, cutoff=0, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); double rateCmp = 0.0123; when(mockRates.periodRate(USD_OBS[1], FIXING_END_DATE)).thenReturn(rateCmp); PointSensitivityBuilder rateSensitivity = OvernightRateSensitivity.ofPeriod(USD_OBS[1], FIXING_END_DATE, 1.0); when(mockRates.periodRatePointSensitivity(USD_OBS[1], FIXING_END_DATE)).thenReturn( rateSensitivity); OvernightIndexRates mockRatesUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvUp = new SimpleRatesProvider(mockRatesUp); when(mockRatesUp.periodRate(USD_OBS[1], FIXING_END_DATE)).thenReturn( rateCmp + EPS_FD); OvernightIndexRates mockRatesDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvDw = new SimpleRatesProvider(mockRatesDw); when(mockRatesDw.periodRate(USD_OBS[1], FIXING_END_DATE)).thenReturn( rateCmp - EPS_FD); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw); double sensitivityExpected = 0.5 * (rateUp - rateDw) / EPS_FD; PointSensitivityBuilder sensitivityBuilderExpected = OvernightRateSensitivity.ofPeriod(USD_OBS[1], FIXING_END_DATE, sensitivityExpected); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } /** Two days cutoff and the period is entirely forward. Test forward part plus cutoff specifics. * Almost all Overnight Compounding coupon (OIS) don't use cutoff period.*/ public void rateFedFund2CutOffForward() { // publication=1, cutoff=2, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); for (int i = 0; i < FIXING_DATES.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } double investmentFactor = 1.0; double afNonCutoff = 0.0; for (int i = 1; i < 5; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNonCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNonCutoff; when(mockRates.periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp); LocalDate fixingCutOff = FIXING_DATES[5]; LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(fixingCutOff, REF_DATA); double afCutOff = USD_FED_FUND.getDayCount().yearFraction(fixingCutOff, endDate); double rateExpected = ((1.0 + rateCmp * afNonCutoff) * (1.0d + FORWARD_RATES[4] * afCutOff) - 1.0d) / (afNonCutoff + afCutOff); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Two days cutoff and the period is entirely forward. Test forward part plus cutoff specifics against FD. * Almost all Overnight Compounding coupon (OIS) don't use cutoff period.*/ public void rateFedFund2CutOffForwardSensitivity() { // publication=1, cutoff=2, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); int nFixings = FIXING_DATES.length; OvernightIndexRates[] mockRatesUp = new OvernightIndexRates[nFixings]; SimpleRatesProvider[] simpleProvUp = new SimpleRatesProvider[nFixings]; OvernightIndexRates[] mockRatesDw = new OvernightIndexRates[nFixings]; SimpleRatesProvider[] simpleProvDw = new SimpleRatesProvider[nFixings]; OvernightIndexRates mockRatesPeriodUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvPeriodUp = new SimpleRatesProvider(mockRatesPeriodUp); OvernightIndexRates mockRatesPeriodDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvPeriodDw = new SimpleRatesProvider(mockRatesPeriodDw); double[][] forwardRatesUp = new double[nFixings][nFixings]; double[][] forwardRatesDw = new double[nFixings][nFixings]; for (int i = 0; i < nFixings; i++) { mockRatesUp[i] = mock(OvernightIndexRates.class); simpleProvUp[i] = new SimpleRatesProvider(mockRatesUp[i]); mockRatesDw[i] = mock(OvernightIndexRates.class); simpleProvDw[i] = new SimpleRatesProvider(mockRatesDw[i]); for (int j = 0; j < nFixings; j++) { double rateForUp = i == j ? FORWARD_RATES[j] + EPS_FD : FORWARD_RATES[j]; double rateForDw = i == j ? FORWARD_RATES[j] - EPS_FD : FORWARD_RATES[j]; forwardRatesUp[i][j] = rateForUp; forwardRatesDw[i][j] = rateForDw; } } for (int i = 0; i < nFixings; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); when(mockRatesPeriodUp.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); when(mockRatesPeriodDw.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); LocalDate fixingStartDate = USD_FED_FUND.calculateEffectiveFromFixing(FIXING_DATES[i], REF_DATA); LocalDate fixingEndDate = USD_FED_FUND.calculateMaturityFromEffective(fixingStartDate, REF_DATA); PointSensitivityBuilder rateSensitivity = OvernightRateSensitivity.ofPeriod(USD_OBS[i], fixingEndDate, 1.0); when(mockRates.ratePointSensitivity(USD_OBS[i])).thenReturn(rateSensitivity); for (int j = 0; j < nFixings; ++j) { when(mockRatesUp[j].rate(USD_OBS[i])).thenReturn(forwardRatesUp[j][i]); when(mockRatesDw[j].rate(USD_OBS[i])).thenReturn(forwardRatesDw[j][i]); } } double investmentFactor = 1.0; double afNonCutoff = 0.0; for (int i = 1; i < 5; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNonCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNonCutoff; when(mockRates.periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp); when(mockRatesPeriodUp.periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp + EPS_FD); when(mockRatesPeriodDw.periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp - EPS_FD); PointSensitivityBuilder rateSensitivity = OvernightRateSensitivity.ofPeriod(USD_OBS[1], FIXING_FINAL_DATE, 1.0); when(mockRates.periodRatePointSensitivity(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateSensitivity); for (int i = 0; i < nFixings; ++i) { when(mockRatesUp[i].periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp); when(mockRatesDw[i].periodRate(USD_OBS[1], FIXING_FINAL_DATE)).thenReturn(rateCmp); } for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesPeriodUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesPeriodDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); PointSensitivityBuilder sensitivityBuilderExpected1 = PointSensitivityBuilder.none(); for (int i = 0; i < nFixings; ++i) { when(mockRatesUp[i].getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw[i].getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp[i]); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw[i]); double cutoffSensitivity = 0.5 * (rateUp - rateDw) / EPS_FD; // [4] is nonzero LocalDate fixingStartDate = USD_FED_FUND.calculateEffectiveFromFixing(FIXING_DATES[i], REF_DATA); LocalDate fixingEndDate = USD_FED_FUND.calculateMaturityFromEffective(fixingStartDate, REF_DATA); sensitivityBuilderExpected1 = cutoffSensitivity == 0.0 ? sensitivityBuilderExpected1 : sensitivityBuilderExpected1.combinedWith( OvernightRateSensitivity.ofPeriod(USD_OBS[i], fixingEndDate, cutoffSensitivity)); } double ratePeriodUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvPeriodUp); double ratePeriodDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvPeriodDw); double periodSensitivity = 0.5 * (ratePeriodUp - ratePeriodDw) / EPS_FD; PointSensitivityBuilder sensitivityBuilderExpected2 = OvernightRateSensitivity.ofPeriod(USD_OBS[1], FIXING_FINAL_DATE, periodSensitivity); PointSensitivityBuilder sensitivityBuilderExpected = sensitivityBuilderExpected1 .combinedWith(sensitivityBuilderExpected2); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } /** No cutoff and one already fixed ON rate. Test the already fixed portion with only one fixed ON rate.*/ public void rateFedFund0CutOffValuation1() { // publication=1, cutoff=0, effective offset=0, TS: Fixing 1 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); for (int i = 0; i < 2; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < 2; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = 2; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } LocalDate fixingknown = FIXING_DATES[1]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double afKnown = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); double investmentFactor = 1.0; double afNoCutoff = 0.0; for (int i = 2; i < 6; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNoCutoff; when(mockRates.periodRate(USD_OBS[2], FIXING_END_DATE)).thenReturn(rateCmp); double rateExpected = ((1.0d + FIXING_RATES[1] * afKnown) * (1.0 + rateCmp * afNoCutoff) - 1.0d) / (afKnown + afNoCutoff); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** No cutoff and one already fixed ON rate. Test the already fixed portion with only one fixed ON rate against FD.*/ public void rateFedFund0CutOffValuation1Sensitivity() { // publication=1, cutoff=0, effective offset=0, TS: Fixing 1 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); for (int i = 0; i < 2; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); OvernightIndexRates mockRatesUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvUp = new SimpleRatesProvider(mockRatesUp); OvernightIndexRates mockRatesDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvDw = new SimpleRatesProvider(mockRatesDw); when(mockRatesUp.getFixings()).thenReturn(tsb.build()); when(mockRatesDw.getFixings()).thenReturn(tsb.build()); double investmentFactor = 1.0; double afNoCutoff = 0.0; for (int i = 2; i < 6; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNoCutoff; when(mockRates.periodRate(USD_OBS[2], FIXING_END_DATE)).thenReturn(rateCmp); when(mockRatesUp.periodRate(USD_OBS[2], FIXING_END_DATE)).thenReturn(rateCmp + EPS_FD); when(mockRatesDw.periodRate(USD_OBS[2], FIXING_END_DATE)).thenReturn(rateCmp - EPS_FD); PointSensitivityBuilder periodSensitivity = OvernightRateSensitivity.ofPeriod(USD_OBS[2], FIXING_END_DATE, 1.0d); when(mockRates.periodRatePointSensitivity(USD_OBS[2], FIXING_END_DATE)).thenReturn(periodSensitivity); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw); double sensitivityExpected = 0.5 * (rateUp - rateDw) / EPS_FD; PointSensitivityBuilder sensitivityBuilderExpected = OvernightRateSensitivity.ofPeriod(USD_OBS[2], FIXING_END_DATE, sensitivityExpected); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } //------------------------------------------------------------------------- /** No cutoff period and two already fixed ON rate. ON index is SONIA. */ public void rateSonia0CutOffValuation2() { // publication=0, cutoff=0, effective offset=0, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(GBP_SONIA, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(GBP_SONIA); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(GBP_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < GBP_OBS.length; i++) { when(mockRates.rate(GBP_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 0; i < lastFixing - 1; i++) { LocalDate fixingknown = FIXING_DATES[i + 1]; LocalDate endDateKnown = GBP_SONIA.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = GBP_SONIA.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[i + 1] * af; } double afNoCutoff = 0.0d; double investmentFactorNoCutoff = 1.0d; for (int i = lastFixing; i < 6; i++) { LocalDate endDate = GBP_SONIA.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = GBP_SONIA.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactorNoCutoff *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactorNoCutoff - 1.0d) / afNoCutoff; when(mockRates.periodRate(GBP_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp); double rateExpected = (investmentFactorKnown * (1.0 + rateCmp * afNoCutoff) - 1.0d) / (afKnown + afNoCutoff); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity against FD approximation. * No cutoff period and two already fixed ON rate. ON index is SONIA. */ public void rateSonia0CutOffValuation2Sensitivity() { // publication=0, cutoff=0, effective offset=0, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(GBP_SONIA, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(GBP_SONIA); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); OvernightIndexRates mockRatesUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvUp = new SimpleRatesProvider(mockRatesUp); OvernightIndexRates mockRatesDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvDw = new SimpleRatesProvider(mockRatesDw); when(mockRatesUp.getFixings()).thenReturn(tsb.build()); when(mockRatesDw.getFixings()).thenReturn(tsb.build()); double afNoCutoff = 0.0d; double investmentFactorNoCutoff = 1.0d; for (int i = lastFixing; i < 6; i++) { LocalDate endDate = GBP_SONIA.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = GBP_SONIA.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactorNoCutoff *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactorNoCutoff - 1.0d) / afNoCutoff; when(mockRates.periodRate(GBP_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp); when(mockRatesUp.periodRate(GBP_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp + EPS_FD); when(mockRatesDw.periodRate(GBP_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp - EPS_FD); OvernightRateSensitivity periodSensitivity = OvernightRateSensitivity.ofPeriod(GBP_OBS[lastFixing], FIXING_DATES[6], 1.0d); when(mockRates.periodRatePointSensitivity(GBP_OBS[lastFixing], FIXING_DATES[6])) .thenReturn(periodSensitivity); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw); double sensitivityExpected = 0.5 * (rateUp - rateDw) / EPS_FD; OvernightRateSensitivity sensitivityBuilderExpected = OvernightRateSensitivity.ofPeriod(GBP_OBS[lastFixing], FIXING_DATES[6], sensitivityExpected); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } //------------------------------------------------------------------------- /** No cutoff period and two already fixed ON rate. ON index is TOIS (with a effective offset of 1; TN rate). */ public void rateTois0CutOffValuation2() { // publication=0, cutoff=0, effective offset=1, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of( CHF_TOIS, CHF_TOIS.calculateEffectiveFromFixing(FIXING_START_DATE, REF_DATA), CHF_TOIS.calculateEffectiveFromFixing(FIXING_END_DATE, REF_DATA), 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(CHF_TOIS); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(CHF_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < CHF_OBS.length; i++) { when(mockRates.rate(CHF_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 1; i < lastFixing; i++) { LocalDate fixingknown = FIXING_DATES[i]; LocalDate startDateKnown = CHF_TOIS.calculateEffectiveFromFixing(fixingknown, REF_DATA); LocalDate endDateKnown = CHF_TOIS.calculateMaturityFromEffective(startDateKnown, REF_DATA); double af = CHF_TOIS.getDayCount().yearFraction(startDateKnown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + af * FIXING_RATES[i]; } double afNoCutoff = 0.0d; double investmentFactorNoCutoff = 1.0d; for (int i = lastFixing; i < 6; i++) { LocalDate fixing = FIXING_DATES[i]; LocalDate startDate = CHF_TOIS.calculateEffectiveFromFixing(fixing, REF_DATA); LocalDate endDate = CHF_TOIS.calculateMaturityFromEffective(startDate, REF_DATA); double af = CHF_TOIS.getDayCount().yearFraction(startDate, endDate); afNoCutoff += af; investmentFactorNoCutoff *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactorNoCutoff - 1.0d) / afNoCutoff; LocalDate dateMat = CHF_TOIS.calculateMaturityFromFixing(FIXING_DATES[5], REF_DATA); OvernightIndexObservation obs = OvernightIndexObservation.of(CHF_TOIS, FIXING_DATES[lastFixing], REF_DATA); when(mockRates.periodRate(obs, dateMat)).thenReturn(rateCmp); double rateExpected = (investmentFactorKnown * (1.0 + rateCmp * afNoCutoff) - 1.0d) / (afKnown + afNoCutoff); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity against FD approximation. * No cutoff period and two already fixed ON rate. ON index is TOIS (with a effective offset of 1; TN rate). */ public void rateTois0CutOffValuation2Sensitivity() { // publication=0, cutoff=0, effective offset=1, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 9), date(2015, 1, 12)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of( CHF_TOIS, CHF_TOIS.calculateEffectiveFromFixing(FIXING_START_DATE, REF_DATA), CHF_TOIS.calculateEffectiveFromFixing(FIXING_END_DATE, REF_DATA), 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(CHF_TOIS); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); OvernightIndexRates mockRatesUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvUp = new SimpleRatesProvider(mockRatesUp); OvernightIndexRates mockRatesDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvDw = new SimpleRatesProvider(mockRatesDw); when(mockRatesUp.getFixings()).thenReturn(tsb.build()); when(mockRatesDw.getFixings()).thenReturn(tsb.build()); double afNoCutoff = 0.0d; double investmentFactorNoCutoff = 1.0d; for (int i = lastFixing; i < 6; i++) { LocalDate fixing = FIXING_DATES[i]; LocalDate startDate = CHF_TOIS.calculateEffectiveFromFixing(fixing, REF_DATA); LocalDate endDate = CHF_TOIS.calculateMaturityFromEffective(startDate, REF_DATA); double af = CHF_TOIS.getDayCount().yearFraction(startDate, endDate); afNoCutoff += af; investmentFactorNoCutoff *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactorNoCutoff - 1.0d) / afNoCutoff; LocalDate dateMat = CHF_TOIS.calculateMaturityFromFixing(FIXING_DATES[5], REF_DATA); OvernightIndexObservation obs = OvernightIndexObservation.of(CHF_TOIS, FIXING_DATES[lastFixing], REF_DATA); when(mockRates.periodRate(obs, dateMat)).thenReturn(rateCmp); when(mockRatesUp.periodRate(obs, dateMat)).thenReturn(rateCmp + EPS_FD); when(mockRatesDw.periodRate(obs, dateMat)).thenReturn(rateCmp - EPS_FD); OvernightRateSensitivity periodSensitivity = OvernightRateSensitivity.ofPeriod(obs, dateMat, 1.0d); when(mockRates.periodRatePointSensitivity(obs, dateMat)).thenReturn(periodSensitivity); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw); double sensitivityExpected = 0.5 * (rateUp - rateDw) / EPS_FD; OvernightRateSensitivity sensitivityBuilderExpected = OvernightRateSensitivity.ofPeriod(obs, dateMat, sensitivityExpected); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } //------------------------------------------------------------------------- /** No cutoff and two already fixed ON rate. ON index is Fed Fund. */ public void rateFedFund0CutOffValuation2() { // publication=1, cutoff=0, effective offset=0, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 12), date(2015, 1, 13)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 0; i < lastFixing - 1; i++) { LocalDate fixingknown = FIXING_DATES[i + 1]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[i + 1] * af; } double investmentFactor = 1.0; double afNoCutoff = 0.0; for (int i = lastFixing; i < 6; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNoCutoff; when(mockRates.periodRate(USD_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp); double rateExpected = (investmentFactorKnown * (1.0 + rateCmp * afNoCutoff) - 1.0d) / (afKnown + afNoCutoff); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity against FD approximation. * No cutoff and two already fixed ON rate. ON index is Fed Fund. */ public void rateFedFund0CutOffValuation2Sensitivity() { // publication=1, cutoff=0, effective offset=0, TS: Fixing 2 LocalDate[] valuationDate = {date(2015, 1, 12), date(2015, 1, 13)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 3; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); OvernightIndexRates mockRatesUp = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvUp = new SimpleRatesProvider(mockRatesUp); OvernightIndexRates mockRatesDw = mock(OvernightIndexRates.class); SimpleRatesProvider simpleProvDw = new SimpleRatesProvider(mockRatesDw); when(mockRatesUp.getFixings()).thenReturn(tsb.build()); when(mockRatesDw.getFixings()).thenReturn(tsb.build()); double investmentFactor = 1.0; double afNoCutoff = 0.0; for (int i = lastFixing; i < 6; i++) { LocalDate endDate = USD_FED_FUND.calculateMaturityFromEffective(FIXING_DATES[i], REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(FIXING_DATES[i], endDate); afNoCutoff += af; investmentFactor *= 1.0d + af * FORWARD_RATES[i]; } double rateCmp = (investmentFactor - 1.0d) / afNoCutoff; when(mockRates.periodRate(USD_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp); when(mockRatesUp.periodRate(USD_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp + EPS_FD); when(mockRatesDw.periodRate(USD_OBS[lastFixing], FIXING_DATES[6])).thenReturn(rateCmp - EPS_FD); OvernightRateSensitivity periodSensitivity = OvernightRateSensitivity.ofPeriod(USD_OBS[lastFixing], FIXING_DATES[6], 1.0d); when(mockRates.periodRatePointSensitivity(USD_OBS[lastFixing], FIXING_DATES[6])).thenReturn(periodSensitivity); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesUp.getValuationDate()).thenReturn(valuationDate[loopvaldate]); when(mockRatesDw.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateUp = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvUp); double rateDw = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProvDw); double sensitivityExpected = 0.5 * (rateUp - rateDw) / EPS_FD; OvernightRateSensitivity sensitivityBuilderExpected = OvernightRateSensitivity.ofPeriod(USD_OBS[lastFixing], FIXING_DATES[6], sensitivityExpected); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertTrue(sensitivityBuilderComputed.build().normalized().equalWithTolerance( sensitivityBuilderExpected.build().normalized(), EPS_FD)); } } /** No cutoff, all ON rates already fixed. Time series up to 14-Jan (last fixing date used). */ public void rateFedFund0CutOffValuationEndTs14() { // publication=1, cutoff=0, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 15), date(2015, 1, 16), date(2015, 1, 17)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 6; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 0; i < 5; i++) { LocalDate fixingknown = FIXING_DATES[i + 1]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[i + 1] * af; } double rateExpected = (investmentFactorKnown - 1.0d) / afKnown; for (int loopvaldate = 0; loopvaldate < valuationDate.length; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity. No cutoff, all ON rates already fixed. Thus expected sensitivity is none. * Time series up to 14-Jan (last fixing date used). */ public void rateFedFund0CutOffValuationEndTs14Sensitivity() { // publication=1, cutoff=0, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 15), date(2015, 1, 16), date(2015, 1, 17)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 6; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int loopvaldate = 0; loopvaldate < valuationDate.length; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); PointSensitivityBuilder sensitivityComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(sensitivityComputed, PointSensitivityBuilder.none()); } } /** No cutoff, all ON rates already fixed. Time series up to 15-Jan (one day after the last fixing date). */ public void rateFedFund0CutOffValuationEndTs15() { // publication=1, cutoff=0, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 16), date(2015, 1, 17)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 7; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 0; i < 5; i++) { LocalDate fixingknown = FIXING_DATES[i + 1]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[i + 1] * af; } double rateExpected = (investmentFactorKnown - 1.0d) / afKnown; for (int loopvaldate = 0; loopvaldate < valuationDate.length; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity. No cutoff, all ON rates already fixed. Thus expected sensitivity is none. * Time series up to 15-Jan (one day after the last fixing date). */ public void rateFedFund0CutOffValuationEndTs15Sensitivity() { // publication=1, cutoff=0, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 16), date(2015, 1, 17)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 7; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int loopvaldate = 0; loopvaldate < valuationDate.length; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); PointSensitivityBuilder sensitivityComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(sensitivityComputed, PointSensitivityBuilder.none()); } } /** Two days cutoff, all ON rates already fixed. */ public void rateFedFund2CutOffValuationEnd() { // publication=1, cutoff=2, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 14), date(2015, 1, 15), date(2015, 1, 16)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 5; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } double afKnown = 0.0d; double investmentFactorKnown = 1.0d; for (int i = 0; i < 4; i++) { LocalDate fixingknown = FIXING_DATES[i + 1]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[i + 1] * af; } LocalDate fixingknown = FIXING_DATES[5]; LocalDate endDateKnown = USD_FED_FUND.calculateMaturityFromEffective(fixingknown, REF_DATA); double af = USD_FED_FUND.getDayCount().yearFraction(fixingknown, endDateKnown); afKnown += af; investmentFactorKnown *= 1.0d + FIXING_RATES[4] * af; //Cutoff double rateExpected = (investmentFactorKnown - 1.0d) / afKnown; for (int loopvaldate = 0; loopvaldate < 3; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); double rateComputed = OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(rateExpected, rateComputed, TOLERANCE_RATE); } } /** Test rate sensitivity. Two days cutoff, all ON rates already fixed. Thus none is expected. */ public void rateFedFund2CutOffValuationEndSensitivity() { // publication=1, cutoff=2, effective offset=0, TS: Fixing all LocalDate[] valuationDate = {date(2015, 1, 14), date(2015, 1, 15), date(2015, 1, 16)}; OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(mockRates); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 5; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int loopvaldate = 0; loopvaldate < 3; loopvaldate++) { when(mockRates.getValuationDate()).thenReturn(valuationDate[loopvaldate]); PointSensitivityBuilder sensitivityComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv); assertEquals(sensitivityComputed, PointSensitivityBuilder.none()); } } /** One past fixing missing. Checking the error thrown. */ public void rateFedFund0CutOffValuation2MissingFixing() { // publication=1, cutoff=0, effective offset=0, TS: Fixing 2 LocalDate valuationDate = date(2015, 1, 13); OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); OvernightIndexRates mockRates = mock(OvernightIndexRates.class); when(mockRates.getIndex()).thenReturn(USD_FED_FUND); SimpleRatesProvider simpleProv = new SimpleRatesProvider(valuationDate, mockRates); when(mockRates.getValuationDate()).thenReturn(valuationDate); LocalDateDoubleTimeSeriesBuilder tsb = LocalDateDoubleTimeSeries.builder(); int lastFixing = 2; for (int i = 0; i < lastFixing; i++) { tsb.put(FIXING_DATES[i], FIXING_RATES[i]); } when(mockRates.getFixings()).thenReturn(tsb.build()); for (int i = 0; i < lastFixing; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FIXING_RATES[i]); } for (int i = lastFixing; i < USD_OBS.length; i++) { when(mockRates.rate(USD_OBS[i])).thenReturn(FORWARD_RATES[i]); } assertThrows( () -> OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv), PricingException.class); assertThrows( () -> OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, simpleProv), PricingException.class); } //------------------------------------------------------------------------- private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.DOUBLE_QUADRATIC; private static final LocalDateDoubleTimeSeries TIME_SERIES; static { LocalDateDoubleTimeSeriesBuilder builder = LocalDateDoubleTimeSeries.builder(); for (int i = 0; i < FIXING_DATES.length; i++) { builder.put(FIXING_DATES[i], FIXING_RATES[i]); } TIME_SERIES = builder.build(); } private static final RatesFiniteDifferenceSensitivityCalculator CAL_FD = new RatesFiniteDifferenceSensitivityCalculator(EPS_FD); /** Test parameter sensitivity with fd calculator. No cutoff. */ public void rateNoCutOffForwardParameterSensitivity() { // publication=1, cutoff=0, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; DoubleArray time_usd = DoubleArray.of(0.0, 0.5, 1.0, 2.0, 5.0, 10.0); DoubleArray rate_usd = DoubleArray.of(0.0100, 0.0110, 0.0115, 0.0130, 0.0135, 0.0135); OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 0, REF_DATA); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { Curve fedFundCurve = InterpolatedNodalCurve.of( Curves.zeroRates("USD-Fed-Fund", ACT_ACT_ISDA), time_usd, rate_usd, INTERPOLATOR); ImmutableRatesProvider prov = ImmutableRatesProvider.builder(valuationDate[loopvaldate]) .overnightIndexCurve(USD_FED_FUND, fedFundCurve, TIME_SERIES) .build(); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, prov); CurrencyParameterSensitivities parameterSensitivityComputed = prov.parameterSensitivity(sensitivityBuilderComputed.build()); CurrencyParameterSensitivities parameterSensitivityExpected = CAL_FD.sensitivity(prov, (p) -> CurrencyAmount.of(USD_FED_FUND.getCurrency(), OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, (p)))); assertTrue(parameterSensitivityComputed.equalWithTolerance(parameterSensitivityExpected, EPS_FD * 10.0)); } } /** Test parameter sensitivity with fd calculator. Two days cutoff. */ public void rate2CutOffForwardParameterSensitivity() { // publication=1, cutoff=2, effective offset=0, Forward LocalDate[] valuationDate = {date(2015, 1, 1), date(2015, 1, 8)}; DoubleArray time_usd = DoubleArray.of(0.0, 0.5, 1.0, 2.0, 5.0, 10.0); DoubleArray rate_usd = DoubleArray.of(0.0100, 0.0110, 0.0115, 0.0130, 0.0135, 0.0135); OvernightCompoundedRateComputation ro = OvernightCompoundedRateComputation.of(USD_FED_FUND, FIXING_START_DATE, FIXING_END_DATE, 2, REF_DATA); for (int loopvaldate = 0; loopvaldate < 2; loopvaldate++) { Curve fedFundCurve = InterpolatedNodalCurve.of( Curves.zeroRates("USD-Fed-Fund", ACT_ACT_ISDA), time_usd, rate_usd, INTERPOLATOR); ImmutableRatesProvider prov = ImmutableRatesProvider.builder(valuationDate[loopvaldate]) .overnightIndexCurve(USD_FED_FUND, fedFundCurve, TIME_SERIES) .build(); PointSensitivityBuilder sensitivityBuilderComputed = OBS_FWD_ONCMP.rateSensitivity(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, prov); CurrencyParameterSensitivities parameterSensitivityComputed = prov.parameterSensitivity(sensitivityBuilderComputed.build()); CurrencyParameterSensitivities parameterSensitivityExpected = CAL_FD.sensitivity(prov, (p) -> CurrencyAmount.of(USD_FED_FUND.getCurrency(), OBS_FWD_ONCMP.rate(ro, DUMMY_ACCRUAL_START_DATE, DUMMY_ACCRUAL_END_DATE, (p)))); assertTrue(parameterSensitivityComputed.equalWithTolerance(parameterSensitivityExpected, EPS_FD * 10.0)); } } }