/**
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.measure.curve;
import static com.opengamma.strata.collect.TestHelper.assertThrows;
import static com.opengamma.strata.collect.TestHelper.assertThrowsIllegalArg;
import static com.opengamma.strata.collect.TestHelper.date;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.LocalDate;
import java.time.Period;
import java.util.List;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.StandardId;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.date.DayCounts;
import com.opengamma.strata.basics.index.IborIndices;
import com.opengamma.strata.calc.marketdata.MarketDataConfig;
import com.opengamma.strata.calc.marketdata.MarketDataRequirements;
import com.opengamma.strata.data.MarketDataNotFoundException;
import com.opengamma.strata.data.ObservableSource;
import com.opengamma.strata.data.scenario.ImmutableScenarioMarketData;
import com.opengamma.strata.data.scenario.MarketDataBox;
import com.opengamma.strata.data.scenario.ScenarioMarketData;
import com.opengamma.strata.market.ValueType;
import com.opengamma.strata.market.curve.CurveGroupDefinition;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.curve.CurveInputs;
import com.opengamma.strata.market.curve.CurveInputsId;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.market.curve.InterpolatedNodalCurveDefinition;
import com.opengamma.strata.market.curve.interpolator.CurveExtrapolators;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolators;
import com.opengamma.strata.market.curve.node.FraCurveNode;
import com.opengamma.strata.market.observable.QuoteId;
import com.opengamma.strata.market.param.ParameterMetadata;
import com.opengamma.strata.product.fra.type.FraTemplate;
/**
* Test {@link CurveInputsMarketDataFunction}.
*/
@Test
public class CurveInputsMarketDataFunctionTest {
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final LocalDate VAL_DATE = date(2011, 3, 8);
/**
* Test that the curve node requirements are extracted and returned.
*/
public void requirements() {
FraCurveNode node1x4 = fraNode(1, "a");
FraCurveNode node2x5 = fraNode(2, "b");
FraCurveNode node3x6 = fraNode(3, "c");
InterpolatedNodalCurveDefinition curve = InterpolatedNodalCurveDefinition.builder()
.name(CurveName.of("curve"))
.interpolator(CurveInterpolators.DOUBLE_QUADRATIC)
.extrapolatorLeft(CurveExtrapolators.FLAT)
.extrapolatorRight(CurveExtrapolators.FLAT)
.nodes(node1x4, node2x5, node3x6)
.build();
CurveGroupDefinition groupDefn = CurveGroupDefinition.builder()
.name(CurveGroupName.of("curve group"))
.addDiscountCurve(curve, Currency.USD)
.build();
MarketDataConfig marketDataConfig = MarketDataConfig.builder()
.add(groupDefn.getName(), groupDefn)
.build();
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId = CurveInputsId.of(groupDefn.getName(), curve.getName(), ObservableSource.NONE);
MarketDataRequirements requirements = marketDataFunction.requirements(curveInputsId, marketDataConfig);
assertThat(requirements.getObservables())
.contains(QuoteId.of(StandardId.of("test", "a")))
.contains(QuoteId.of(StandardId.of("test", "b")))
.contains(QuoteId.of(StandardId.of("test", "c")));
}
/**
* Test that an exception is thrown if there is no curve group configuration corresponding to the ID
*/
public void requirementsMissingGroupConfig() {
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId =
CurveInputsId.of(CurveGroupName.of("curve group"), CurveName.of("curve"), ObservableSource.NONE);
assertThrowsIllegalArg(() -> marketDataFunction.requirements(curveInputsId, MarketDataConfig.empty()));
}
/**
* Test that requirements are empty if the curve group config exists but not the curve
*/
public void requirementsMissingCurveDefinition() {
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId =
CurveInputsId.of(CurveGroupName.of("curve group"), CurveName.of("curve"), ObservableSource.NONE);
CurveGroupDefinition groupDefn = CurveGroupDefinition.builder().name(CurveGroupName.of("curve group")).build();
MarketDataConfig marketDataConfig = MarketDataConfig.builder().add(groupDefn.getName(), groupDefn).build();
MarketDataRequirements requirements = marketDataFunction.requirements(curveInputsId, marketDataConfig);
assertThat(requirements.getObservables()).isEmpty();
}
/**
* Test that inputs are correctly built from market data.
*/
public void build() {
FraCurveNode node1x4 = fraNode(1, "a");
FraCurveNode node2x5 = fraNode(2, "b");
FraCurveNode node3x6 = fraNode(3, "c");
InterpolatedNodalCurveDefinition curveDefn = InterpolatedNodalCurveDefinition.builder()
.name(CurveName.of("curve"))
.xValueType(ValueType.YEAR_FRACTION)
.yValueType(ValueType.ZERO_RATE)
.dayCount(DayCounts.ACT_ACT_ISDA)
.interpolator(CurveInterpolators.DOUBLE_QUADRATIC)
.extrapolatorLeft(CurveExtrapolators.FLAT)
.extrapolatorRight(CurveExtrapolators.FLAT)
.nodes(node1x4, node2x5, node3x6)
.build();
CurveGroupDefinition groupDefn = CurveGroupDefinition.builder()
.name(CurveGroupName.of("curve group"))
.addDiscountCurve(curveDefn, Currency.USD)
.build();
MarketDataConfig marketDataConfig = MarketDataConfig.builder()
.add(groupDefn.getName(), groupDefn)
.build();
QuoteId idA = QuoteId.of(StandardId.of("test", "a"));
QuoteId idB = QuoteId.of(StandardId.of("test", "b"));
QuoteId idC = QuoteId.of(StandardId.of("test", "c"));
ScenarioMarketData marketData = ImmutableScenarioMarketData.builder(VAL_DATE)
.addValue(idA, 1d)
.addValue(idB, 2d)
.addValue(idC, 3d)
.build();
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId = CurveInputsId.of(groupDefn.getName(), curveDefn.getName(), ObservableSource.NONE);
MarketDataBox<CurveInputs> result = marketDataFunction.build(curveInputsId, marketDataConfig, marketData, REF_DATA);
CurveInputs curveInputs = result.getSingleValue();
assertThat(curveInputs.getMarketData().get(idA)).isEqualTo(1d);
assertThat(curveInputs.getMarketData().get(idB)).isEqualTo(2d);
assertThat(curveInputs.getMarketData().get(idC)).isEqualTo(3d);
List<ParameterMetadata> expectedMetadata = ImmutableList.of(
node1x4.metadata(VAL_DATE, REF_DATA),
node2x5.metadata(VAL_DATE, REF_DATA),
node3x6.metadata(VAL_DATE, REF_DATA));
assertThat(curveInputs.getCurveMetadata().getParameterMetadata()).hasValue(expectedMetadata);
}
/**
* Test that a failure is returned if there is no config for the curve group.
*/
public void buildMissingGroupConfig() {
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId =
CurveInputsId.of(CurveGroupName.of("curve group"), CurveName.of("curve"), ObservableSource.NONE);
ScenarioMarketData emptyData = ScenarioMarketData.empty();
assertThrows(
() -> marketDataFunction.build(curveInputsId, MarketDataConfig.empty(), emptyData, REF_DATA),
IllegalArgumentException.class,
"No configuration found of type .*");
}
/**
* Test that a failure is returned if there is config for the curve group but it doesn't contain the named curve.
*/
public void buildMissingCurveDefinition() {
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId =
CurveInputsId.of(CurveGroupName.of("curve group"), CurveName.of("curve"), ObservableSource.NONE);
CurveGroupDefinition groupDefn = CurveGroupDefinition.builder().name(CurveGroupName.of("curve group")).build();
MarketDataConfig marketDataConfig = MarketDataConfig.builder().add(groupDefn.getName(), groupDefn).build();
ScenarioMarketData emptyData = ScenarioMarketData.empty();
assertThrows(
() -> marketDataFunction.build(curveInputsId, marketDataConfig, emptyData, REF_DATA),
IllegalArgumentException.class,
"No curve named .*");
}
/**
* Test that a failure is returned if the observable data isn't available.
*/
public void buildMissingMarketData() {
FraCurveNode node1x4 = fraNode(1, "a");
FraCurveNode node2x5 = fraNode(2, "b");
FraCurveNode node3x6 = fraNode(3, "c");
InterpolatedNodalCurveDefinition curve = InterpolatedNodalCurveDefinition.builder()
.name(CurveName.of("curve"))
.interpolator(CurveInterpolators.DOUBLE_QUADRATIC)
.extrapolatorLeft(CurveExtrapolators.FLAT)
.extrapolatorRight(CurveExtrapolators.FLAT)
.nodes(node1x4, node2x5, node3x6)
.build();
CurveGroupDefinition groupDefn = CurveGroupDefinition.builder()
.name(CurveGroupName.of("curve group"))
.addDiscountCurve(curve, Currency.USD)
.build();
MarketDataConfig marketDataConfig = MarketDataConfig.builder()
.add(groupDefn.getName(), groupDefn)
.build();
ScenarioMarketData emptyData = ScenarioMarketData.of(1, date(2016, 6, 30), ImmutableMap.of(), ImmutableMap.of());
CurveInputsMarketDataFunction marketDataFunction = new CurveInputsMarketDataFunction();
CurveInputsId curveInputsId = CurveInputsId.of(groupDefn.getName(), curve.getName(), ObservableSource.NONE);
assertThrows(
() -> marketDataFunction.build(curveInputsId, marketDataConfig, emptyData, REF_DATA),
MarketDataNotFoundException.class);
}
//-------------------------------------------------------------------------
private static FraCurveNode fraNode(int startTenor, String marketDataId) {
Period periodToStart = Period.ofMonths(startTenor);
FraTemplate template = FraTemplate.of(periodToStart, IborIndices.USD_LIBOR_3M);
return FraCurveNode.of(template, QuoteId.of(StandardId.of("test", marketDataId)));
}
}