/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.curve;
import static com.opengamma.strata.basics.currency.Currency.USD;
import static com.opengamma.strata.basics.date.BusinessDayConventions.FOLLOWING;
import static com.opengamma.strata.basics.date.DayCounts.ACT_360;
import static com.opengamma.strata.basics.date.DayCounts.ACT_365F;
import static com.opengamma.strata.basics.date.HolidayCalendarIds.USNY;
import static com.opengamma.strata.basics.index.IborIndices.USD_LIBOR_3M;
import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND;
import static com.opengamma.strata.basics.index.PriceIndices.US_CPI_U;
import static com.opengamma.strata.product.swap.type.FixedOvernightSwapConventions.USD_FIXED_1Y_FED_FUND_OIS;
import static org.testng.Assert.assertEquals;
import java.time.LocalDate;
import java.time.Period;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.testng.annotations.Test;
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.CurrencyAmount;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.basics.date.BusinessDayAdjustment;
import com.opengamma.strata.basics.date.DayCount;
import com.opengamma.strata.basics.date.DaysAdjustment;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries;
import com.opengamma.strata.data.ImmutableMarketData;
import com.opengamma.strata.data.ImmutableMarketDataBuilder;
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.CurveName;
import com.opengamma.strata.market.curve.CurveNode;
import com.opengamma.strata.market.curve.CurveNodeDate;
import com.opengamma.strata.market.curve.InterpolatedNodalCurveDefinition;
import com.opengamma.strata.market.curve.interpolator.CurveExtrapolator;
import com.opengamma.strata.market.curve.interpolator.CurveExtrapolators;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolator;
import com.opengamma.strata.market.curve.interpolator.CurveInterpolators;
import com.opengamma.strata.market.curve.node.FixedInflationSwapCurveNode;
import com.opengamma.strata.market.curve.node.FixedOvernightSwapCurveNode;
import com.opengamma.strata.market.curve.node.TermDepositCurveNode;
import com.opengamma.strata.market.observable.IndexQuoteId;
import com.opengamma.strata.market.observable.QuoteId;
import com.opengamma.strata.pricer.deposit.DiscountingTermDepositProductPricer;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.swap.DiscountingSwapProductPricer;
import com.opengamma.strata.product.ResolvedTrade;
import com.opengamma.strata.product.deposit.ResolvedTermDepositTrade;
import com.opengamma.strata.product.deposit.type.ImmutableTermDepositConvention;
import com.opengamma.strata.product.deposit.type.TermDepositConvention;
import com.opengamma.strata.product.deposit.type.TermDepositTemplate;
import com.opengamma.strata.product.swap.ResolvedSwapTrade;
import com.opengamma.strata.product.swap.type.FixedInflationSwapConventions;
import com.opengamma.strata.product.swap.type.FixedInflationSwapTemplate;
import com.opengamma.strata.product.swap.type.FixedOvernightSwapTemplate;
/**
* Test for curve calibration with 2 curves in USD.
* One curve is Discounting and Fed Fund forward and the other one is USD CPI price index.
*/
@Test
public class CalibrationInflationUsdTest {
private static final LocalDate VAL_DATE = LocalDate.of(2015, 7, 21);
private static final CurveInterpolator INTERPOLATOR_LINEAR = CurveInterpolators.LINEAR;
private static final CurveExtrapolator EXTRAPOLATOR_FLAT = CurveExtrapolators.FLAT;
private static final CurveInterpolator INTERPOLATOR_LOGLINEAR = CurveInterpolators.LOG_LINEAR;
private static final CurveExtrapolator EXTRAPOLATOR_EXP = CurveExtrapolators.EXPONENTIAL;
private static final DayCount CURVE_DC = ACT_365F;
// reference data
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final String SCHEME = "CALIBRATION";
/** Curve names */
private static final String DSCON_NAME = "USD-DSCON-OIS";
private static final CurveName DSCON_CURVE_NAME = CurveName.of(DSCON_NAME);
private static final String CPI_NAME = "USD-CPI-ZC";
private static final CurveName CPI_CURVE_NAME = CurveName.of(CPI_NAME);
/** Curves associations to currencies and indices. */
private static final Map<CurveName, Currency> DSC_NAMES = new HashMap<>();
private static final Map<CurveName, Set<Index>> IDX_NAMES = new HashMap<>();
private static final LocalDateDoubleTimeSeries TS_USD_CPI =
LocalDateDoubleTimeSeries.builder().put(LocalDate.of(2015, 6, 30), 123.4).build();
static {
DSC_NAMES.put(DSCON_CURVE_NAME, USD);
Set<Index> usdFedFundSet = new HashSet<>();
usdFedFundSet.add(USD_FED_FUND);
IDX_NAMES.put(DSCON_CURVE_NAME, usdFedFundSet);
Set<Index> usdLibor3Set = new HashSet<>();
usdLibor3Set.add(USD_LIBOR_3M);
IDX_NAMES.put(CPI_CURVE_NAME, usdLibor3Set);
}
/** Data for USD-DSCON curve */
/* Market values */
private static final double[] DSC_MARKET_QUOTES = new double[] {
0.0005, 0.0005,
0.00072000, 0.00082000, 0.00093000, 0.00090000, 0.00105000,
0.00118500, 0.00318650, 0.00318650, 0.00704000, 0.01121500, 0.01515000,
0.01845500, 0.02111000, 0.02332000, 0.02513500, 0.02668500};
private static final int DSC_NB_NODES = DSC_MARKET_QUOTES.length;
private static final String[] DSC_ID_VALUE = new String[] {
"USD-ON", "USD-TN",
"USD-OIS-1M", "USD-OIS-2M", "USD-OIS-3M", "USD-OIS-6M", "USD-OIS-9M",
"USD-OIS-1Y", "USD-OIS-18M", "USD-OIS-2Y", "USD-OIS-3Y", "USD-OIS-4Y", "USD-OIS-5Y",
"USD-OIS-6Y", "USD-OIS-7Y", "USD-OIS-8Y", "USD-OIS-9Y", "USD-OIS-10Y"};
/* Nodes */
private static final CurveNode[] DSC_NODES = new CurveNode[DSC_NB_NODES];
/* Tenors */
private static final int[] DSC_DEPO_OFFSET = new int[] {0, 1};
private static final int DSC_NB_DEPO_NODES = DSC_DEPO_OFFSET.length;
private static final Period[] DSC_OIS_TENORS = new Period[] {
Period.ofMonths(1), Period.ofMonths(2), Period.ofMonths(3), Period.ofMonths(6), Period.ofMonths(9),
Period.ofYears(1), Period.ofMonths(18), Period.ofYears(2), Period.ofYears(3), Period.ofYears(4), Period.ofYears(5),
Period.ofYears(6), Period.ofYears(7), Period.ofYears(8), Period.ofYears(9), Period.ofYears(10)};
private static final int DSC_NB_OIS_NODES = DSC_OIS_TENORS.length;
static {
for (int i = 0; i < DSC_NB_DEPO_NODES; i++) {
BusinessDayAdjustment bda = BusinessDayAdjustment.of(FOLLOWING, USNY);
TermDepositConvention convention =
ImmutableTermDepositConvention.of(
"USD-Dep", USD, bda, ACT_360, DaysAdjustment.ofBusinessDays(DSC_DEPO_OFFSET[i], USNY));
DSC_NODES[i] = TermDepositCurveNode.of(TermDepositTemplate.of(Period.ofDays(1), convention),
QuoteId.of(StandardId.of(SCHEME, DSC_ID_VALUE[i])));
}
for (int i = 0; i < DSC_NB_OIS_NODES; i++) {
DSC_NODES[DSC_NB_DEPO_NODES + i] = FixedOvernightSwapCurveNode.of(
FixedOvernightSwapTemplate.of(Period.ZERO, Tenor.of(DSC_OIS_TENORS[i]), USD_FIXED_1Y_FED_FUND_OIS),
QuoteId.of(StandardId.of(SCHEME, DSC_ID_VALUE[DSC_NB_DEPO_NODES + i])));
}
}
/** Data for USD-CPI curve */
/* Market values */
private static final double[] CPI_MARKET_QUOTES = new double[] {
0.0200, 0.0200, 0.0200, 0.0200, 0.0200};
private static final int CPI_NB_NODES = CPI_MARKET_QUOTES.length;
private static final String[] CPI_ID_VALUE = new String[] {
"USD-CPI-1Y", "USD-CPI-2Y", "USD-CPI-3Y", "USD-CPI-4Y", "USD-CPI-5Y"};
/* Nodes */
private static final CurveNode[] CPI_NODES = new CurveNode[CPI_NB_NODES];
/* Tenors */
private static final Period[] CPI_TENORS = new Period[] {
Period.ofYears(1), Period.ofYears(2), Period.ofYears(3), Period.ofYears(4), Period.ofYears(5)};
static {
for (int i = 0; i < CPI_NB_NODES; i++) {
CPI_NODES[i] = FixedInflationSwapCurveNode.builder()
.template(FixedInflationSwapTemplate.of(Tenor.of(CPI_TENORS[i]), FixedInflationSwapConventions.USD_FIXED_ZC_US_CPI))
.rateId(QuoteId.of(StandardId.of(SCHEME, CPI_ID_VALUE[i])))
.date(CurveNodeDate.LAST_FIXING)
.build();
}
}
/** All quotes for the curve calibration */
private static final ImmutableMarketData ALL_QUOTES;
static {
ImmutableMarketDataBuilder builder = ImmutableMarketData.builder(VAL_DATE);
for (int i = 0; i < DSC_NB_NODES; i++) {
builder.addValue(QuoteId.of(StandardId.of(SCHEME, DSC_ID_VALUE[i])), DSC_MARKET_QUOTES[i]);
}
for (int i = 0; i < CPI_NB_NODES; i++) {
builder.addValue(QuoteId.of(StandardId.of(SCHEME, CPI_ID_VALUE[i])), CPI_MARKET_QUOTES[i]);
}
builder.addTimeSeries(IndexQuoteId.of(US_CPI_U), TS_USD_CPI);
ALL_QUOTES = builder.build();
}
/** All nodes by groups. */
private static final List<List<CurveNode[]>> CURVES_NODES = new ArrayList<>();
static {
List<CurveNode[]> groupDsc = new ArrayList<>();
groupDsc.add(DSC_NODES);
CURVES_NODES.add(groupDsc);
List<CurveNode[]> groupCpi = new ArrayList<>();
groupCpi.add(CPI_NODES);
CURVES_NODES.add(groupCpi);
}
private static final DiscountingSwapProductPricer SWAP_PRICER =
DiscountingSwapProductPricer.DEFAULT;
private static final DiscountingTermDepositProductPricer DEPO_PRICER =
DiscountingTermDepositProductPricer.DEFAULT;
private static final CurveCalibrator CALIBRATOR = CurveCalibrator.of(1e-9, 1e-9, 100);
// Constants
private static final double TOLERANCE_PV = 1.0E-6;
private static final CurveGroupName CURVE_GROUP_NAME = CurveGroupName.of("USD-DSCON-LIBOR3M");
private static final InterpolatedNodalCurveDefinition DSC_CURVE_DEFN =
InterpolatedNodalCurveDefinition.builder()
.name(DSCON_CURVE_NAME)
.xValueType(ValueType.YEAR_FRACTION)
.yValueType(ValueType.ZERO_RATE)
.dayCount(CURVE_DC)
.interpolator(INTERPOLATOR_LINEAR)
.extrapolatorLeft(EXTRAPOLATOR_FLAT)
.extrapolatorRight(EXTRAPOLATOR_FLAT)
.nodes(DSC_NODES).build();
private static final InterpolatedNodalCurveDefinition CPI_CURVE_UNDER_DEFN =
InterpolatedNodalCurveDefinition.builder()
.name(CPI_CURVE_NAME)
.xValueType(ValueType.MONTHS)
.yValueType(ValueType.PRICE_INDEX)
.dayCount(CURVE_DC)
.interpolator(INTERPOLATOR_LOGLINEAR)
.extrapolatorLeft(EXTRAPOLATOR_FLAT)
.extrapolatorRight(EXTRAPOLATOR_EXP)
.nodes(CPI_NODES).build();
private static final CurveGroupDefinition CURVE_GROUP_CONFIG =
CurveGroupDefinition.builder()
.name(CURVE_GROUP_NAME)
.addCurve(DSC_CURVE_DEFN, USD, USD_FED_FUND)
.addForwardCurve(CPI_CURVE_UNDER_DEFN, US_CPI_U).build();
//-------------------------------------------------------------------------
public void calibration_present_value_oneGroup() {
RatesProvider result = CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, ALL_QUOTES, REF_DATA);
assertPresentValue(result);
}
private void assertPresentValue(RatesProvider result) {
// Test PV Dsc
CurveNode[] dscNodes = CURVES_NODES.get(0).get(0);
List<ResolvedTrade> dscTrades = new ArrayList<>();
for (int i = 0; i < dscNodes.length; i++) {
dscTrades.add(dscNodes[i].resolvedTrade(1d, ALL_QUOTES, REF_DATA));
}
// Depo
for (int i = 0; i < DSC_NB_DEPO_NODES; i++) {
CurrencyAmount pvIrs = DEPO_PRICER.presentValue(
((ResolvedTermDepositTrade) dscTrades.get(i)).getProduct(), result);
assertEquals(pvIrs.getAmount(), 0.0, TOLERANCE_PV);
}
// OIS
for (int i = 0; i < DSC_NB_OIS_NODES; i++) {
MultiCurrencyAmount pvIrs = SWAP_PRICER.presentValue(
((ResolvedSwapTrade) dscTrades.get(DSC_NB_DEPO_NODES + i)).getProduct(), result);
assertEquals(pvIrs.getAmount(USD).getAmount(), 0.0, TOLERANCE_PV);
}
// Test PV Infaltion swaps
CurveNode[] cpiNodes = CURVES_NODES.get(1).get(0);
List<ResolvedTrade> cpiTrades = new ArrayList<>();
for (int i = 0; i < cpiNodes.length; i++) {
cpiTrades.add(cpiNodes[i].resolvedTrade(1d, ALL_QUOTES, REF_DATA));
}
// ZC swaps
for (int i = 0; i < CPI_NB_NODES; i++) {
MultiCurrencyAmount pvInfl = SWAP_PRICER.presentValue(
((ResolvedSwapTrade) cpiTrades.get(i)).getProduct(), result);
assertEquals(pvInfl.getAmount(USD).getAmount(), 0.0, TOLERANCE_PV);
}
}
//-------------------------------------------------------------------------
@SuppressWarnings("unused")
@Test(enabled = false)
public void performance() {
long startTime, endTime;
int nbTests = 100;
int nbRep = 3;
int count = 0;
for (int i = 0; i < nbRep; i++) {
startTime = System.currentTimeMillis();
for (int looprep = 0; looprep < nbTests; looprep++) {
RatesProvider result = CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, ALL_QUOTES, REF_DATA);
count += result.getValuationDate().getDayOfMonth();
}
endTime = System.currentTimeMillis();
System.out.println("Performance: " + nbTests + " calibrations for 2 curves with 35 nodes in "
+ (endTime - startTime) + " ms.");
}
System.out.println("Avoiding hotspot: " + count);
// Previous run: 275 ms for 100 calibrations (2 curves simultaneous - 35 nodes)
}
}