/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.market.curve.node; import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; import static com.opengamma.strata.basics.date.HolidayCalendarIds.USNY; import static com.opengamma.strata.collect.TestHelper.assertSerialization; import static com.opengamma.strata.collect.TestHelper.assertThrows; import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg; import static com.opengamma.strata.collect.TestHelper.assertThrowsWithCause; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; import static com.opengamma.strata.collect.TestHelper.date; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.time.LocalDate; import java.time.Period; import java.util.Set; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.StandardId; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyPair; import com.opengamma.strata.basics.currency.FxRate; import com.opengamma.strata.basics.date.DaysAdjustment; import com.opengamma.strata.basics.date.HolidayCalendarId; import com.opengamma.strata.basics.date.Tenor; import com.opengamma.strata.data.FxRateId; import com.opengamma.strata.data.ImmutableMarketData; import com.opengamma.strata.data.MarketData; import com.opengamma.strata.data.MarketDataId; import com.opengamma.strata.data.MarketDataNotFoundException; import com.opengamma.strata.data.ObservableSource; import com.opengamma.strata.market.ValueType; import com.opengamma.strata.market.curve.CurveNodeDate; import com.opengamma.strata.market.observable.QuoteId; import com.opengamma.strata.market.param.DatedParameterMetadata; import com.opengamma.strata.market.param.ParameterMetadata; import com.opengamma.strata.market.param.TenorDateParameterMetadata; import com.opengamma.strata.product.common.BuySell; import com.opengamma.strata.product.fx.FxSwapTrade; import com.opengamma.strata.product.fx.type.FxSwapTemplate; import com.opengamma.strata.product.fx.type.ImmutableFxSwapConvention; /** * Test {@link FxSwapCurveNode}. */ @Test public class FxSwapCurveNodeTest { private static final ReferenceData REF_DATA = ReferenceData.standard(); private static final LocalDate VAL_DATE = date(2015, 6, 30); private static final CurrencyPair EUR_USD = CurrencyPair.of(Currency.EUR, Currency.USD); private static final HolidayCalendarId EUTA_USNY = EUTA.combinedWith(USNY); private static final DaysAdjustment PLUS_TWO_DAYS = DaysAdjustment.ofBusinessDays(2, EUTA_USNY); private static final ImmutableFxSwapConvention CONVENTION = ImmutableFxSwapConvention.of(EUR_USD, PLUS_TWO_DAYS); private static final Period NEAR_PERIOD = Period.ofMonths(3); private static final Period FAR_PERIOD = Period.ofMonths(6); private static final FxSwapTemplate TEMPLATE = FxSwapTemplate.of(NEAR_PERIOD, FAR_PERIOD, CONVENTION); private static final ObservableSource OBS_SOURCE = ObservableSource.of("Vendor"); private static final FxRateId FX_RATE_ID = FxRateId.of(EUR_USD); private static final FxRateId FX_RATE_ID2 = FxRateId.of(EUR_USD, OBS_SOURCE); private static final QuoteId QUOTE_ID_PTS = QuoteId.of(StandardId.of("OG-Ticker", "EUR_USD_3M_6M")); private static final QuoteId QUOTE_ID_PTS2 = QuoteId.of(StandardId.of("OG-Ticker", "EUR_USD_3M_6M2")); private static final FxRate FX_RATE_NEAR = FxRate.of(EUR_USD, 1.30d); private static final double FX_RATE_PTS = 0.0050d; private static final String LABEL = "Label"; private static final String LABEL_AUTO = "6M"; private static final MarketData MARKET_DATA = ImmutableMarketData.builder(VAL_DATE) .addValue(FX_RATE_ID, FX_RATE_NEAR) .addValue(QUOTE_ID_PTS, FX_RATE_PTS) .build(); //------------------------------------------------------------------------- public void test_builder() { FxSwapCurveNode test = FxSwapCurveNode.builder() .label(LABEL) .template(TEMPLATE) .fxRateId(FX_RATE_ID2) .farForwardPointsId(QUOTE_ID_PTS) .date(CurveNodeDate.LAST_FIXING) .build(); assertEquals(test.getLabel(), LABEL); assertEquals(test.getFxRateId(), FX_RATE_ID2); assertEquals(test.getFarForwardPointsId(), QUOTE_ID_PTS); assertEquals(test.getTemplate(), TEMPLATE); assertEquals(test.getDate(), CurveNodeDate.LAST_FIXING); } public void test_builder_defaults() { FxSwapCurveNode test = FxSwapCurveNode.builder() .template(TEMPLATE) .farForwardPointsId(QUOTE_ID_PTS) .build(); assertEquals(test.getLabel(), LABEL_AUTO); assertEquals(test.getFxRateId(), FX_RATE_ID); assertEquals(test.getFarForwardPointsId(), QUOTE_ID_PTS); assertEquals(test.getTemplate(), TEMPLATE); assertEquals(test.getDate(), CurveNodeDate.END); } public void test_builder_noTemplate() { assertThrowsIllegalArg(() -> FxSwapCurveNode.builder().label(LABEL).farForwardPointsId(QUOTE_ID_PTS).build()); } public void test_of() { FxSwapCurveNode test = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); assertEquals(test.getLabel(), LABEL_AUTO); assertEquals(test.getFxRateId(), FX_RATE_ID); assertEquals(test.getFarForwardPointsId(), QUOTE_ID_PTS); assertEquals(test.getTemplate(), TEMPLATE); } public void test_of_withLabel() { FxSwapCurveNode test = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS, LABEL); assertEquals(test.getLabel(), LABEL); assertEquals(test.getFxRateId(), FX_RATE_ID); assertEquals(test.getFarForwardPointsId(), QUOTE_ID_PTS); assertEquals(test.getTemplate(), TEMPLATE); } public void test_requirements() { FxSwapCurveNode test = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); Set<? extends MarketDataId<?>> setExpected = ImmutableSet.of(FX_RATE_ID, QUOTE_ID_PTS); Set<? extends MarketDataId<?>> set = test.requirements(); assertTrue(set.equals(setExpected)); } public void test_trade() { FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); FxSwapTrade trade = node.trade(1d, MARKET_DATA, REF_DATA); double rate = FX_RATE_NEAR.fxRate(EUR_USD); FxSwapTrade expected = TEMPLATE.createTrade(VAL_DATE, BuySell.BUY, 1.0, rate, FX_RATE_PTS, REF_DATA); assertEquals(trade, expected); assertEquals(node.resolvedTrade(1d, MARKET_DATA, REF_DATA), trade.resolve(REF_DATA)); } public void test_trade_noMarketData() { FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); MarketData marketData = MarketData.empty(VAL_DATE); assertThrows(() -> node.trade(1d, marketData, REF_DATA), MarketDataNotFoundException.class); } public void test_initialGuess() { FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); assertEquals(node.initialGuess(MARKET_DATA, ValueType.ZERO_RATE), 0.0d); assertEquals(node.initialGuess(MARKET_DATA, ValueType.DISCOUNT_FACTOR), 1.0d); } public void test_metadata_end() { FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); LocalDate valuationDate = LocalDate.of(2015, 1, 22); LocalDate endDate = CONVENTION.getBusinessDayAdjustment() .adjust(CONVENTION.getSpotDateOffset().adjust(valuationDate, REF_DATA).plus(FAR_PERIOD), REF_DATA); ParameterMetadata metadata = node.metadata(valuationDate, REF_DATA); assertEquals(((TenorDateParameterMetadata) metadata).getDate(), endDate); assertEquals(((TenorDateParameterMetadata) metadata).getTenor(), Tenor.of(FAR_PERIOD)); } public void test_metadata_fixed() { LocalDate nodeDate = VAL_DATE.plusMonths(1); FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS).withDate(CurveNodeDate.of(nodeDate)); LocalDate valuationDate = LocalDate.of(2015, 1, 22); DatedParameterMetadata metadata = node.metadata(valuationDate, REF_DATA); assertEquals(metadata.getDate(), nodeDate); assertEquals(metadata.getLabel(), node.getLabel()); } public void test_metadata_last_fixing() { FxSwapCurveNode node = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS).withDate(CurveNodeDate.LAST_FIXING); assertThrowsWithCause(() -> node.metadata(VAL_DATE, REF_DATA), UnsupportedOperationException.class); } //------------------------------------------------------------------------- public void coverage() { FxSwapCurveNode test = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); coverImmutableBean(test); FxSwapCurveNode test2 = FxSwapCurveNode.builder() .label(LABEL) .template(FxSwapTemplate.of(Period.ZERO, FAR_PERIOD, CONVENTION)) .fxRateId(FX_RATE_ID2) .farForwardPointsId(QUOTE_ID_PTS2) .date(CurveNodeDate.LAST_FIXING) .build(); coverBeanEquals(test, test2); } public void test_serialization() { FxSwapCurveNode test = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS); assertSerialization(test); } }