/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.dsf;
import static com.opengamma.strata.basics.currency.Currency.USD;
import static com.opengamma.strata.basics.date.BusinessDayConventions.MODIFIED_FOLLOWING;
import static com.opengamma.strata.basics.date.BusinessDayConventions.PRECEDING;
import static com.opengamma.strata.basics.date.DayCounts.ACT_ACT_ISDA;
import static com.opengamma.strata.basics.date.DayCounts.THIRTY_U_360;
import static com.opengamma.strata.basics.index.IborIndices.USD_LIBOR_3M;
import static com.opengamma.strata.basics.schedule.Frequency.P3M;
import static com.opengamma.strata.basics.schedule.Frequency.P6M;
import static com.opengamma.strata.product.common.PayReceive.PAY;
import static com.opengamma.strata.product.common.PayReceive.RECEIVE;
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.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.date.HolidayCalendarId;
import com.opengamma.strata.basics.date.HolidayCalendarIds;
import com.opengamma.strata.basics.schedule.PeriodicSchedule;
import com.opengamma.strata.basics.schedule.StubConvention;
import com.opengamma.strata.basics.value.ValueSchedule;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.market.curve.CurveMetadata;
import com.opengamma.strata.market.curve.CurveName;
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.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.pricer.sensitivity.RatesFiniteDifferenceSensitivityCalculator;
import com.opengamma.strata.product.SecurityId;
import com.opengamma.strata.product.dsf.ResolvedDsf;
import com.opengamma.strata.product.swap.FixedRateCalculation;
import com.opengamma.strata.product.swap.IborRateCalculation;
import com.opengamma.strata.product.swap.NotionalSchedule;
import com.opengamma.strata.product.swap.PaymentSchedule;
import com.opengamma.strata.product.swap.RateCalculationSwapLeg;
import com.opengamma.strata.product.swap.ResolvedSwap;
import com.opengamma.strata.product.swap.Swap;
import com.opengamma.strata.product.swap.SwapLeg;
/**
* Test {@link DiscountingDsfProductPricer}.
*/
@Test
public class DiscountingDsfProductPricerTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
// curves
private static final CurveInterpolator INTERPOLATOR = CurveInterpolators.LINEAR;
private static final LocalDate VAL_DATE = LocalDate.of(2012, 9, 20);
private static final DoubleArray USD_DSC_TIME = DoubleArray.of(0.0, 0.5, 1.0, 2.0, 5.0, 10.0);
private static final DoubleArray USD_DSC_RATE = DoubleArray.of(0.0100, 0.0120, 0.0120, 0.0140, 0.0140, 0.0140);
private static final CurveName USD_DSC_NAME = CurveName.of("USD Dsc");
private static final CurveMetadata USD_DSC_METADATA = Curves.zeroRates(USD_DSC_NAME, ACT_ACT_ISDA);
private static final InterpolatedNodalCurve USD_DSC =
InterpolatedNodalCurve.of(USD_DSC_METADATA, USD_DSC_TIME, USD_DSC_RATE, INTERPOLATOR);
private static final DoubleArray USD_FWD3_TIME = DoubleArray.of(0.0, 0.5, 1.0, 2.0, 5.0, 10.0);
private static final DoubleArray USD_FWD3_RATE = DoubleArray.of(0.0150, 0.0125, 0.0150, 0.0175, 0.0150, 0.0150);
private static final CurveName USD_FWD3_NAME = CurveName.of("USD LIBOR 3M");
private static final CurveMetadata USD_FWD3_METADATA = Curves.zeroRates(USD_FWD3_NAME, ACT_ACT_ISDA);
private static final InterpolatedNodalCurve USD_FWD3 =
InterpolatedNodalCurve.of(USD_FWD3_METADATA, USD_FWD3_TIME, USD_FWD3_RATE, INTERPOLATOR);
private static final ImmutableRatesProvider PROVIDER = ImmutableRatesProvider.builder(VAL_DATE)
.discountCurve(USD, USD_DSC)
.iborIndexCurve(USD_LIBOR_3M, USD_FWD3)
.build();
// underlying swap
private static final NotionalSchedule UNIT_NOTIONAL = NotionalSchedule.of(USD, 1d);
private static final HolidayCalendarId CALENDAR = HolidayCalendarIds.SAT_SUN;
private static final BusinessDayAdjustment BDA_MF = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, CALENDAR);
private static final BusinessDayAdjustment BDA_P = BusinessDayAdjustment.of(PRECEDING, CALENDAR);
private static final LocalDate START = LocalDate.of(2012, 12, 19);
private static final LocalDate END = START.plusYears(10);
private static final double RATE = 0.0175;
private static final SwapLeg FIXED_LEG = RateCalculationSwapLeg.builder()
.payReceive(RECEIVE)
.accrualSchedule(PeriodicSchedule.builder()
.startDate(START)
.endDate(END)
.frequency(P6M)
.businessDayAdjustment(BDA_MF)
.stubConvention(StubConvention.SHORT_FINAL)
.build())
.paymentSchedule(PaymentSchedule.builder()
.paymentFrequency(P6M)
.paymentDateOffset(DaysAdjustment.NONE)
.build())
.notionalSchedule(UNIT_NOTIONAL)
.calculation(FixedRateCalculation.builder()
.dayCount(THIRTY_U_360)
.rate(ValueSchedule.of(RATE))
.build())
.build();
private static final SwapLeg IBOR_LEG = RateCalculationSwapLeg.builder()
.payReceive(PAY)
.accrualSchedule(PeriodicSchedule.builder()
.startDate(START)
.endDate(END)
.frequency(P3M)
.businessDayAdjustment(BDA_MF)
.stubConvention(StubConvention.SHORT_FINAL)
.build())
.paymentSchedule(PaymentSchedule.builder()
.paymentFrequency(P3M)
.paymentDateOffset(DaysAdjustment.NONE)
.build())
.notionalSchedule(UNIT_NOTIONAL)
.calculation(IborRateCalculation.builder()
.index(USD_LIBOR_3M)
.fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, CALENDAR, BDA_P))
.build())
.build();
private static final Swap SWAP = Swap.of(FIXED_LEG, IBOR_LEG);
private static final ResolvedSwap RSWAP = SWAP.resolve(REF_DATA);
// deliverable swap future
private static final LocalDate LAST_TRADE = LocalDate.of(2012, 12, 17);
private static final LocalDate DELIVERY = LocalDate.of(2012, 12, 19);
private static final double NOTIONAL = 100000;
private static final ResolvedDsf FUTURE = ResolvedDsf.builder()
.securityId(SecurityId.of("OG-Test", "DSF"))
.deliveryDate(DELIVERY)
.lastTradeDate(LAST_TRADE)
.notional(NOTIONAL)
.underlyingSwap(SWAP.resolve(REF_DATA))
.build();
// calculators
private static final double TOL = 1.0e-13;
private static final double EPS = 1.0e-6;
private static final DiscountingDsfProductPricer PRICER =
DiscountingDsfProductPricer.DEFAULT;
private static final RatesFiniteDifferenceSensitivityCalculator FD_CAL =
new RatesFiniteDifferenceSensitivityCalculator(EPS);
//-------------------------------------------------------------------------
public void test_price() {
double computed = PRICER.price(FUTURE, PROVIDER);
double pvSwap = PRICER.getSwapPricer().presentValue(RSWAP, PROVIDER).getAmount(USD).getAmount();
double yc = ACT_ACT_ISDA.relativeYearFraction(VAL_DATE, DELIVERY);
double df = Math.exp(-USD_DSC.yValue(yc) * yc);
double expected = 1d + pvSwap / df;
assertEquals(computed, expected, TOL);
}
public void test_priceSensitivity() {
PointSensitivities point = PRICER.priceSensitivity(FUTURE, PROVIDER);
CurrencyParameterSensitivities computed = PROVIDER.parameterSensitivity(point);
CurrencyParameterSensitivities expected =
FD_CAL.sensitivity(PROVIDER, (p) -> CurrencyAmount.of(USD, PRICER.price(FUTURE, (p))));
assertTrue(computed.equalWithTolerance(expected, 10d * EPS));
}
//-------------------------------------------------------------------------
public void regression() {
double price = PRICER.price(FUTURE, PROVIDER);
assertEquals(price, 1.022245377054993, TOL); // 2.x
}
}