/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.measure.swap; import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.basics.date.DayCounts.THIRTY_U_360; import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND; import static com.opengamma.strata.collect.CollectProjectAssertions.assertThat; import static com.opengamma.strata.product.common.PayReceive.RECEIVE; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.offset; import java.time.LocalDate; import java.util.List; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.MoreExecutors; import com.opengamma.strata.basics.ImmutableReferenceData; 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.BusinessDayConventions; import com.opengamma.strata.basics.date.DaysAdjustment; import com.opengamma.strata.basics.index.IborIndex; import com.opengamma.strata.basics.index.IborIndices; import com.opengamma.strata.basics.index.ImmutableIborIndex; import com.opengamma.strata.basics.schedule.Frequency; import com.opengamma.strata.basics.schedule.PeriodicSchedule; import com.opengamma.strata.basics.schedule.StubConvention; import com.opengamma.strata.calc.CalculationRules; import com.opengamma.strata.calc.CalculationRunner; import com.opengamma.strata.calc.Column; import com.opengamma.strata.calc.Results; import com.opengamma.strata.calc.runner.CalculationFunctions; import com.opengamma.strata.collect.result.Result; import com.opengamma.strata.data.ImmutableMarketData; import com.opengamma.strata.data.MarketData; import com.opengamma.strata.market.curve.CurveGroupName; import com.opengamma.strata.market.curve.CurveId; import com.opengamma.strata.measure.Measures; import com.opengamma.strata.measure.StandardComponents; import com.opengamma.strata.measure.rate.RatesMarketDataLookup; import com.opengamma.strata.pricer.datasets.StandardDataSets; import com.opengamma.strata.pricer.swap.e2e.CalendarUSD; import com.opengamma.strata.product.TradeInfo; import com.opengamma.strata.product.common.PayReceive; 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.Swap; import com.opengamma.strata.product.swap.SwapLeg; import com.opengamma.strata.product.swap.SwapTrade; @Test public class SwapPricingTest { private static final ReferenceData REF_DATA = ReferenceData.standard() .combinedWith(ImmutableReferenceData.of(CalendarUSD.NYC, CalendarUSD.NYC_CALENDAR)); private static final IborIndex USD_LIBOR_1M = lockIndexCalendar(IborIndices.USD_LIBOR_1M); private static final IborIndex USD_LIBOR_3M = lockIndexCalendar(IborIndices.USD_LIBOR_3M); private static final IborIndex USD_LIBOR_6M = lockIndexCalendar(IborIndices.USD_LIBOR_6M); private static final NotionalSchedule NOTIONAL = NotionalSchedule.of(USD, 100_000_000); private static final BusinessDayAdjustment BDA_MF = BusinessDayAdjustment.of( BusinessDayConventions.MODIFIED_FOLLOWING, CalendarUSD.NYC); private static final BusinessDayAdjustment BDA_P = BusinessDayAdjustment.of( BusinessDayConventions.PRECEDING, CalendarUSD.NYC); private static final LocalDate VAL_DATE = StandardDataSets.VAL_DATE_2014_01_22; // tolerance private static final double TOLERANCE_PV = 1.0E-4; //------------------------------------------------------------------------- public void presentValueVanillaFixedVsLibor1mSwap() { SwapLeg payLeg = fixedLeg( LocalDate.of(2014, 9, 12), LocalDate.of(2016, 9, 12), Frequency.P6M, PayReceive.PAY, NOTIONAL, 0.0125, null); SwapLeg receiveLeg = RateCalculationSwapLeg.builder() .payReceive(RECEIVE) .accrualSchedule(PeriodicSchedule.builder() .startDate(LocalDate.of(2014, 9, 12)) .endDate(LocalDate.of(2016, 9, 12)) .frequency(Frequency.P1M) .businessDayAdjustment(BDA_MF) .build()) .paymentSchedule(PaymentSchedule.builder() .paymentFrequency(Frequency.P1M) .paymentDateOffset(DaysAdjustment.NONE) .build()) .notionalSchedule(NOTIONAL) .calculation(IborRateCalculation.builder() .index(USD_LIBOR_1M) .fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, CalendarUSD.NYC, BDA_P)) .build()) .build(); SwapTrade trade = SwapTrade.builder() .info(TradeInfo.builder().tradeDate(LocalDate.of(2014, 9, 10)).build()) .product(Swap.of(payLeg, receiveLeg)).build(); CurveGroupName groupName = CurveGroupName.of("Test"); CurveId idUsdDsc = CurveId.of(groupName, StandardDataSets.GROUP1_USD_DSC.getName()); CurveId idUsdOn = CurveId.of(groupName, StandardDataSets.GROUP1_USD_ON.getName()); CurveId idUsdL1M = CurveId.of(groupName, StandardDataSets.GROUP1_USD_L1M.getName()); CurveId idUsdL3M = CurveId.of(groupName, StandardDataSets.GROUP1_USD_L3M.getName()); CurveId idUsdL6M = CurveId.of(groupName, StandardDataSets.GROUP1_USD_L6M.getName()); MarketData suppliedData = ImmutableMarketData.builder(VAL_DATE) .addValue(idUsdDsc, StandardDataSets.GROUP1_USD_DSC) .addValue(idUsdOn, StandardDataSets.GROUP1_USD_ON) .addValue(idUsdL1M, StandardDataSets.GROUP1_USD_L1M) .addValue(idUsdL3M, StandardDataSets.GROUP1_USD_L3M) .addValue(idUsdL6M, StandardDataSets.GROUP1_USD_L6M) .build(); CalculationFunctions functions = StandardComponents.calculationFunctions(); RatesMarketDataLookup ratesLookup = RatesMarketDataLookup.of( ImmutableMap.of( USD, idUsdDsc), ImmutableMap.of( USD_FED_FUND, idUsdOn, USD_LIBOR_1M, idUsdL1M, USD_LIBOR_3M, idUsdL3M, USD_LIBOR_6M, idUsdL6M)); // create the calculation runner List<SwapTrade> trades = ImmutableList.of(trade); List<Column> columns = ImmutableList.of(Column.of(Measures.PRESENT_VALUE)); CalculationRules rules = CalculationRules.of(functions, USD, ratesLookup); // calculate results using the runner // using the direct executor means there is no need to close/shutdown the runner CalculationRunner runner = CalculationRunner.of(MoreExecutors.newDirectExecutorService()); Results results = runner.calculate(rules, trades, columns, suppliedData, REF_DATA); Result<?> result = results.get(0, 0); assertThat(result).isSuccess(); CurrencyAmount pv = (CurrencyAmount) result.getValue(); assertThat(pv.getAmount()).isCloseTo(-1003684.8402, offset(TOLERANCE_PV)); } private static SwapLeg fixedLeg( LocalDate start, LocalDate end, Frequency frequency, PayReceive payReceive, NotionalSchedule notional, double fixedRate, StubConvention stubConvention) { return RateCalculationSwapLeg.builder() .payReceive(payReceive) .accrualSchedule(PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(frequency) .businessDayAdjustment(BDA_MF) .stubConvention(stubConvention) .build()) .paymentSchedule(PaymentSchedule.builder() .paymentFrequency(frequency) .paymentDateOffset(DaysAdjustment.NONE) .build()) .notionalSchedule(notional) .calculation(FixedRateCalculation.of(fixedRate, THIRTY_U_360)) .build(); } //------------------------------------------------------------------------- // use a fixed known set of holiday dates to ensure tests produce same numbers private static IborIndex lockIndexCalendar(IborIndex index) { return ((ImmutableIborIndex) index).toBuilder() .fixingCalendar(CalendarUSD.NYC) .effectiveDateOffset( index.getEffectiveDateOffset().toBuilder() .calendar(CalendarUSD.NYC) .adjustment( index.getEffectiveDateOffset().getAdjustment().toBuilder() .calendar(CalendarUSD.NYC) .build()) .build()) .maturityDateOffset( index.getMaturityDateOffset().toBuilder() .adjustment( index.getMaturityDateOffset().getAdjustment().toBuilder() .calendar(CalendarUSD.NYC) .build()) .build()) .build(); } }