public class CalibrationEurStandard { private static final DayCount CURVE_DC = ACT_365F; private static final LocalDateDoubleTimeSeries TS_EMTPY = LocalDateDoubleTimeSeries.empty(); private static final String SCHEME = "CALIBRATION"; /** Curve names */ private static final String DSCON_NAME = "EUR_EONIA_EOD"; public static final CurveName DSCON_CURVE_NAME = CurveName.of(DSCON_NAME); private static final String FWD3_NAME = "EUR_EURIBOR_3M"; public static final CurveName FWD3_CURVE_NAME = CurveName.of(FWD3_NAME); private static final String FWD6_NAME = "EUR_EURIBOR_6M"; public static final CurveName FWD6_CURVE_NAME = CurveName.of(FWD6_NAME); private static final String CURVE_GROUP_NAME_STR = "EUR-DSCON-EURIBOR3M-EURIBOR6M"; private static final CurveGroupName CURVE_GROUP_NAME = CurveGroupName.of(CURVE_GROUP_NAME_STR); /** 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 Map<Index, LocalDateDoubleTimeSeries> TS = new HashMap<>(); static { DSC_NAMES.put(DSCON_CURVE_NAME, EUR); Set<Index> eurEoniaSet = new HashSet<>(); eurEoniaSet.add(EUR_EONIA); IDX_NAMES.put(DSCON_CURVE_NAME, eurEoniaSet); Set<Index> eurEuribor3Set = new HashSet<>(); eurEuribor3Set.add(EUR_EURIBOR_3M); IDX_NAMES.put(FWD3_CURVE_NAME, eurEuribor3Set); Set<Index> eurEuriabor6Set = new HashSet<>(); eurEuriabor6Set.add(EUR_EURIBOR_6M); IDX_NAMES.put(FWD6_CURVE_NAME, eurEuriabor6Set); TS.put(EUR_EURIBOR_3M, TS_EMTPY); TS.put(EUR_EURIBOR_6M, TS_EMTPY); TS.put(EUR_EONIA, TS_EMTPY); } private static final CurveInterpolator INTERPOLATOR_LINEAR = new LinearInterpolator1D(); private static final CurveExtrapolator EXTRAPOLATOR_FLAT = new FlatExtrapolator1D(); private static final CalibrationMeasures CALIBRATION_MEASURES = CalibrationMeasures.DEFAULT; private static final CurveCalibrator CALIBRATOR = CurveCalibrator.of(1e-9, 1e-9, 100, CALIBRATION_MEASURES); public static ImmutableRatesProvider calibrateEurStandard( LocalDate valuationDate, double[] dscOisQuotes, Period[] dscOisTenors, double fwd3FixingQuote, double[] fwd3FraQuotes, double[] fwd3IrsQuotes, Period[] fwd3FraTenors, Period[] fwd3IrsTenors, double fwd6FixingQuote, double[] fwd6FraQuotes, double[] fwd6IrsQuotes, Period[] fwd6FraTenors, Period[] fwd6IrsTenors) { /* Curve Discounting/EUR-EONIA */ String[] dscIdValues = dscIdValues(dscOisTenors); /* Curve EUR-EURIBOR-3M */ double[] fwd3MarketQuotes = fwdMarketQuotes(fwd3FixingQuote, fwd3FraQuotes, fwd3IrsQuotes); String[] fwd3IdValues = fwdIdValue(3, fwd3FixingQuote, fwd3FraQuotes, fwd3IrsQuotes, fwd3FraTenors, fwd3IrsTenors); /* Curve EUR-EURIBOR-6M */ double[] fwd6MarketQuotes = fwdMarketQuotes(fwd6FixingQuote, fwd6FraQuotes, fwd6IrsQuotes); String[] fwd6IdValues = fwdIdValue(6, fwd6FixingQuote, fwd6FraQuotes, fwd6IrsQuotes, fwd6FraTenors, fwd6IrsTenors); /* All quotes for the curve calibration */ ObservableValues allQuotes = allQuotes( dscOisQuotes, dscIdValues, fwd3MarketQuotes, fwd3IdValues, fwd6MarketQuotes, fwd6IdValues); /* All nodes by groups. */ CurveGroupDefinition config = config( dscOisTenors, dscIdValues, fwd3FraTenors, fwd3IrsTenors, fwd3IdValues, fwd6FraTenors, fwd6IrsTenors, fwd6IdValues); /* Results */ return CALIBRATOR.calibrate(config, valuationDate, allQuotes, TS, FxMatrix.empty()); } public static String[] dscIdValues(Period[] dscOisTenors) { String[] dscIdValues = new String[dscOisTenors.length]; for (int i = 0; i < dscOisTenors.length; i++) { dscIdValues[i] = "OIS" + dscOisTenors[i].toString(); } return dscIdValues; } public static String[] fwdIdValue( int tenor, double fwdFixingQuote, double[] fwdFraQuotes, double[] fwdIrsQuotes, Period[] fwdFraTenors, Period[] fwdIrsTenors) { String[] fwdIdValue = new String[1 + fwdFraQuotes.length + fwdIrsQuotes.length]; fwdIdValue[0] = "FIXING" + tenor + "M"; for (int i = 0; i < fwdFraQuotes.length; i++) { fwdIdValue[i + 1] = "FRA" + fwdFraTenors[i].toString() + "x" + fwdFraTenors[i].plusMonths(tenor).toString(); } for (int i = 0; i < fwdIrsQuotes.length; i++) { fwdIdValue[i + 1 + fwdFraQuotes.length] = "IRS" + fwdIrsTenors[i].toString(); } return fwdIdValue; } public static double[] fwdMarketQuotes( double fwdFixingQuote, double[] fwdFraQuotes, double[] fwdIrsQuotes) { int fwdNbFraNodes = fwdFraQuotes.length; int fwdNbIrsNodes = fwdIrsQuotes.length; int fwdNbNodes = 1 + fwdNbFraNodes + fwdNbIrsNodes; double[] fwdMarketQuotes = new double[fwdNbNodes]; fwdMarketQuotes[0] = fwdFixingQuote; System.arraycopy(fwdFraQuotes, 0, fwdMarketQuotes, 1, fwdNbFraNodes); System.arraycopy(fwdIrsQuotes, 0, fwdMarketQuotes, 1 + fwdNbFraNodes, fwdNbIrsNodes); return fwdMarketQuotes; } public static CurveGroupDefinition config( Period[] dscOisTenors, String[] dscIdValues, Period[] fwd3FraTenors, Period[] fwd3IrsTenors, String[] fwd3IdValues, Period[] fwd6FraTenors, Period[] fwd6IrsTenors, String[] fwd6IdValues) { CurveNode[] dscNodes = new CurveNode[dscOisTenors.length]; for (int i = 0; i < dscOisTenors.length; i++) { dscNodes[i] = FixedOvernightSwapCurveNode.of( FixedOvernightSwapTemplate.of( Period.ZERO, Tenor.of(dscOisTenors[i]), EUR_FIXED_1Y_EONIA_OIS), QuoteKey.of(StandardId.of(SCHEME, dscIdValues[i]))); } CurveNode[] fwd3Nodes = new CurveNode[fwd3IdValues.length]; fwd3Nodes[0] = IborFixingDepositCurveNode.of( IborFixingDepositTemplate.of(EUR_EURIBOR_3M), QuoteKey.of(StandardId.of(SCHEME, fwd3IdValues[0]))); for (int i = 0; i < fwd3FraTenors.length; i++) { fwd3Nodes[i + 1] = FraCurveNode.of( FraTemplate.of(fwd3FraTenors[i], EUR_EURIBOR_3M), QuoteKey.of(StandardId.of(SCHEME, fwd3IdValues[i + 1]))); } for (int i = 0; i < fwd3IrsTenors.length; i++) { fwd3Nodes[i + 1 + fwd3FraTenors.length] = FixedIborSwapCurveNode.of( FixedIborSwapTemplate.of( Period.ZERO, Tenor.of(fwd3IrsTenors[i]), EUR_FIXED_1Y_EURIBOR_3M), QuoteKey.of(StandardId.of(SCHEME, fwd3IdValues[i + 1]))); } CurveNode[] fwd6Nodes = new CurveNode[fwd6IdValues.length]; fwd6Nodes[0] = IborFixingDepositCurveNode.of( IborFixingDepositTemplate.of(EUR_EURIBOR_6M), QuoteKey.of(StandardId.of(SCHEME, fwd6IdValues[0]))); for (int i = 0; i < fwd6FraTenors.length; i++) { fwd6Nodes[i + 1] = FraCurveNode.of( FraTemplate.of(fwd6FraTenors[i], EUR_EURIBOR_6M), QuoteKey.of(StandardId.of(SCHEME, fwd6IdValues[i + 1]))); } for (int i = 0; i < fwd6IrsTenors.length; i++) { fwd6Nodes[i + 1 + fwd6FraTenors.length] = FixedIborSwapCurveNode.of( FixedIborSwapTemplate.of( Period.ZERO, Tenor.of(fwd6IrsTenors[i]), EUR_FIXED_1Y_EURIBOR_6M), QuoteKey.of(StandardId.of(SCHEME, fwd6IdValues[i + 1]))); } 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(dscNodes) .build(); InterpolatedNodalCurveDefinition FWD3_CURVE_DEFN = InterpolatedNodalCurveDefinition.builder() .name(FWD3_CURVE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.ZERO_RATE) .dayCount(CURVE_DC) .interpolator(INTERPOLATOR_LINEAR) .extrapolatorLeft(EXTRAPOLATOR_FLAT) .extrapolatorRight(EXTRAPOLATOR_FLAT) .nodes(fwd3Nodes) .build(); InterpolatedNodalCurveDefinition FWD6_CURVE_DEFN = InterpolatedNodalCurveDefinition.builder() .name(FWD6_CURVE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.ZERO_RATE) .dayCount(CURVE_DC) .interpolator(INTERPOLATOR_LINEAR) .extrapolatorLeft(EXTRAPOLATOR_FLAT) .extrapolatorRight(EXTRAPOLATOR_FLAT) .nodes(fwd6Nodes) .build(); return CurveGroupDefinition.builder() .name(CURVE_GROUP_NAME) .addCurve(DSC_CURVE_DEFN, EUR, EUR_EONIA) .addForwardCurve(FWD3_CURVE_DEFN, EUR_EURIBOR_3M) .addForwardCurve(FWD6_CURVE_DEFN, EUR_EURIBOR_6M) .build(); } public static ObservableValues allQuotes( double[] dscOisQuotes, String[] dscIdValues, double[] fwd3MarketQuotes, String[] fwd3IdValue, double[] fwd6MarketQuotes, String[] fwd6IdValue) { /* All quotes for the curve calibration */ Map<ObservableKey, Double> allQuotes = new HashMap<>(); for (int i = 0; i < dscOisQuotes.length; i++) { allQuotes.put(QuoteKey.of(StandardId.of(SCHEME, dscIdValues[i])), dscOisQuotes[i]); } for (int i = 0; i < fwd3MarketQuotes.length; i++) { allQuotes.put(QuoteKey.of(StandardId.of(SCHEME, fwd3IdValue[i])), fwd3MarketQuotes[i]); } for (int i = 0; i < fwd6MarketQuotes.length; i++) { allQuotes.put(QuoteKey.of(StandardId.of(SCHEME, fwd6IdValue[i])), fwd6MarketQuotes[i]); } return ObservableValues.of(allQuotes); } }
/** * Test for curve calibration in USD and EUR. The USD curve is obtained by OIS and the EUR one by FX * Swaps from USD. */ @Test public class CalibrationZeroRateUsdEur2OisFxTest { private static final LocalDate VAL_DATE = LocalDate.of(2015, 11, 2); private static final CurveInterpolator INTERPOLATOR_LINEAR = CurveInterpolators.LINEAR; private static final CurveExtrapolator EXTRAPOLATOR_FLAT = CurveExtrapolators.FLAT; private static final DayCount CURVE_DC = ACT_365F; private static final String SCHEME = "CALIBRATION"; /** Curve names */ private static final String USD_DSCON_STR = "USD-DSCON-OIS"; private static final CurveName USD_DSCON_CURVE_NAME = CurveName.of(USD_DSCON_STR); private static final String EUR_DSC_STR = "EUR-DSC-FX"; private static final CurveName EUR_DSC_CURVE_NAME = CurveName.of(EUR_DSC_STR); /** 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 Map<Index, LocalDateDoubleTimeSeries> TS = new HashMap<>(); static { DSC_NAMES.put(USD_DSCON_CURVE_NAME, USD); Set<Index> usdFedFundSet = new HashSet<>(); usdFedFundSet.add(USD_FED_FUND); IDX_NAMES.put(USD_DSCON_CURVE_NAME, usdFedFundSet); } /** Data FX * */ private static final FxRate FX_RATE_EUR_USD = FxRate.of(EUR, USD, 1.10); /** Data for USD-DSCON curve */ /* Market values */ private static final double[] USD_DSC_MARKET_QUOTES = new double[] { 0.0016, 0.0022, 0.0013, 0.0016, 0.0020, 0.0026, 0.0033, 0.0039, 0.0053, 0.0066, 0.0090, 0.0111 }; private static final int USD_DSC_NB_NODES = USD_DSC_MARKET_QUOTES.length; private static final String[] USD_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" }; /* Nodes */ private static final CurveNode[] USD_DSC_NODES = new CurveNode[USD_DSC_NB_NODES]; /* Tenors */ private static final int[] USD_DSC_DEPO_OFFSET = new int[] {0, 1}; private static final int USD_DSC_NB_DEPO_NODES = USD_DSC_DEPO_OFFSET.length; private static final Period[] USD_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) }; private static final int USD_DSC_NB_OIS_NODES = USD_DSC_OIS_TENORS.length; static { USD_DSC_NODES[0] = TermDepositCurveNode.of( TermDepositTemplate.of(Period.ofDays(1), USD_DEPOSIT_T0), QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[0]))); USD_DSC_NODES[1] = TermDepositCurveNode.of( TermDepositTemplate.of(Period.ofDays(1), USD_DEPOSIT_T1), QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[1]))); for (int i = 0; i < USD_DSC_NB_OIS_NODES; i++) { USD_DSC_NODES[USD_DSC_NB_DEPO_NODES + i] = FixedOvernightSwapCurveNode.of( FixedOvernightSwapTemplate.of( Period.ZERO, Tenor.of(USD_DSC_OIS_TENORS[i]), USD_FIXED_1Y_FED_FUND_OIS), QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[USD_DSC_NB_DEPO_NODES + i]))); } } /** Data for EUR-DSC curve */ /* Market values */ private static final double[] EUR_DSC_MARKET_QUOTES = new double[] { 0.0004, 0.0012, 0.0019, 0.0043, 0.0074, 0.0109, 0.0193, 0.0294, 0.0519, 0.0757 }; private static final int EUR_DSC_NB_NODES = EUR_DSC_MARKET_QUOTES.length; private static final String[] EUR_DSC_ID_VALUE = new String[] { "EUR-USD-FX-1M", "EUR-USD-FX-2M", "EUR-USD-FX-3M", "EUR-USD-FX-6M", "EUR-USD-FX-9M", "EUR-USD-FX-1Y", "EUR-USD-FX-18M", "EUR-USD-FX-2Y", "EUR-USD-FX-3Y", "EUR-USD-FX-4Y" }; /* Nodes */ private static final CurveNode[] EUR_DSC_NODES = new CurveNode[EUR_DSC_NB_NODES]; /* Tenors */ private static final Period[] EUR_DSC_FX_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) }; private static final int EUR_DSC_NB_FX_NODES = EUR_DSC_FX_TENORS.length; static { for (int i = 0; i < EUR_DSC_NB_FX_NODES; i++) { EUR_DSC_NODES[i] = FxSwapCurveNode.of( FxSwapTemplate.of(EUR_DSC_FX_TENORS[i], EUR_USD), QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i]))); } } /** All quotes for the curve calibration */ private static final ImmutableMarketData ALL_QUOTES; static { Map<MarketDataKey<?>, Object> map = new HashMap<>(); for (int i = 0; i < USD_DSC_NB_NODES; i++) { map.put(QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])), USD_DSC_MARKET_QUOTES[i]); } for (int i = 0; i < EUR_DSC_NB_NODES; i++) { map.put(QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i])), EUR_DSC_MARKET_QUOTES[i]); } map.put(FxRateKey.of(EUR, USD), FX_RATE_EUR_USD); ALL_QUOTES = ImmutableMarketData.of(map); } private static final DiscountingSwapProductPricer SWAP_PRICER = DiscountingSwapProductPricer.DEFAULT; private static final DiscountingTermDepositProductPricer DEPO_PRICER = DiscountingTermDepositProductPricer.DEFAULT; private static final DiscountingFxSwapProductPricer FX_PRICER = DiscountingFxSwapProductPricer.DEFAULT; private static final MarketQuoteSensitivityCalculator MQC = MarketQuoteSensitivityCalculator.DEFAULT; private static final CalibrationMeasures CALIBRATION_MEASURES = CalibrationMeasures.DEFAULT; private static final CurveCalibrator CALIBRATOR = CurveCalibrator.of(1e-9, 1e-9, 100, CALIBRATION_MEASURES); // Constants private static final double TOLERANCE_PV = 1.0E-6; private static final double TOLERANCE_PV_DELTA = 1.0E+3; private static final CurveGroupName CURVE_GROUP_NAME = CurveGroupName.of("USD-DSCON-EUR-DSC"); private static final InterpolatedNodalCurveDefinition USD_DSC_CURVE_DEFN = InterpolatedNodalCurveDefinition.builder() .name(USD_DSCON_CURVE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.ZERO_RATE) .dayCount(CURVE_DC) .interpolator(INTERPOLATOR_LINEAR) .extrapolatorLeft(EXTRAPOLATOR_FLAT) .extrapolatorRight(EXTRAPOLATOR_FLAT) .nodes(USD_DSC_NODES) .build(); private static final InterpolatedNodalCurveDefinition EUR_DSC_CURVE_DEFN = InterpolatedNodalCurveDefinition.builder() .name(EUR_DSC_CURVE_NAME) .xValueType(ValueType.YEAR_FRACTION) .yValueType(ValueType.ZERO_RATE) .dayCount(CURVE_DC) .interpolator(INTERPOLATOR_LINEAR) .extrapolatorLeft(EXTRAPOLATOR_FLAT) .extrapolatorRight(EXTRAPOLATOR_FLAT) .nodes(EUR_DSC_NODES) .build(); private static final CurveGroupDefinition CURVE_GROUP_CONFIG = CurveGroupDefinition.builder() .name(CURVE_GROUP_NAME) .addCurve(USD_DSC_CURVE_DEFN, USD, USD_FED_FUND) .addDiscountCurve(EUR_DSC_CURVE_DEFN, EUR) .build(); // ------------------------------------------------------------------------- public void calibration_present_value_oneGroup() { ImmutableRatesProvider result = CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ALL_QUOTES, TS); assertPresentValue(result); } private void assertPresentValue(ImmutableRatesProvider result) { // Test PV USD; List<Trade> usdTrades = new ArrayList<>(); for (int i = 0; i < USD_DSC_NODES.length; i++) { usdTrades.add(USD_DSC_NODES[i].trade(VAL_DATE, ALL_QUOTES)); } // Depo for (int i = 0; i < USD_DSC_NB_DEPO_NODES; i++) { CurrencyAmount pvDep = DEPO_PRICER.presentValue(((TermDepositTrade) usdTrades.get(i)).getProduct(), result); assertEquals(pvDep.getAmount(), 0.0, TOLERANCE_PV); } // OIS for (int i = 0; i < USD_DSC_NB_OIS_NODES; i++) { MultiCurrencyAmount pvOis = SWAP_PRICER.presentValue( ((SwapTrade) usdTrades.get(USD_DSC_NB_DEPO_NODES + i)).getProduct(), result); assertEquals(pvOis.getAmount(USD).getAmount(), 0.0, TOLERANCE_PV); } // Test PV EUR; List<Trade> eurTrades = new ArrayList<>(); for (int i = 0; i < EUR_DSC_NODES.length; i++) { eurTrades.add(EUR_DSC_NODES[i].trade(VAL_DATE, ALL_QUOTES)); } // Depo for (int i = 0; i < EUR_DSC_NB_FX_NODES; i++) { MultiCurrencyAmount pvFx = FX_PRICER.presentValue(((FxSwapTrade) eurTrades.get(i)).getProduct(), result); assertEquals(pvFx.convertedTo(USD, result).getAmount(), 0.0, TOLERANCE_PV); } } public void calibration_market_quote_sensitivity_one_group() { double shift = 1.0E-6; Function<MarketData, ImmutableRatesProvider> f = ov -> CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ov, TS); calibration_market_quote_sensitivity_check(f, shift); } private void calibration_market_quote_sensitivity_check( Function<MarketData, ImmutableRatesProvider> calibrator, double shift) { double notional = 100_000_000.0; double fx = 1.1111; double fxPts = 0.0012; FxSwapTrade trade = EUR_USD.toTrade( VAL_DATE, Period.ofWeeks(6), Period.ofMonths(5), BuySell.BUY, notional, fx, fxPts); ImmutableRatesProvider result = CALIBRATOR.calibrate(CURVE_GROUP_CONFIG, VAL_DATE, ALL_QUOTES, TS); PointSensitivities pts = FX_PRICER.presentValueSensitivity(trade.getProduct(), result); CurveCurrencyParameterSensitivities ps = result.curveParameterSensitivity(pts); CurveCurrencyParameterSensitivities mqs = MQC.sensitivity(ps, result); double pvUsd = FX_PRICER.presentValue(trade.getProduct(), result).getAmount(USD).getAmount(); double pvEur = FX_PRICER.presentValue(trade.getProduct(), result).getAmount(EUR).getAmount(); double[] mqsUsd1Computed = mqs.getSensitivity(USD_DSCON_CURVE_NAME, USD).getSensitivity().toArray(); for (int i = 0; i < USD_DSC_NB_NODES; i++) { Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues()); map.put( QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])), USD_DSC_MARKET_QUOTES[i] + shift); ImmutableMarketData marketData = ImmutableMarketData.of(map); ImmutableRatesProvider rpShifted = calibrator.apply(marketData); double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(USD).getAmount(); assertEquals(mqsUsd1Computed[i], (pvS - pvUsd) / shift, TOLERANCE_PV_DELTA); } double[] mqsUsd2Computed = mqs.getSensitivity(USD_DSCON_CURVE_NAME, EUR).getSensitivity().toArray(); for (int i = 0; i < USD_DSC_NB_NODES; i++) { Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues()); map.put( QuoteKey.of(StandardId.of(SCHEME, USD_DSC_ID_VALUE[i])), USD_DSC_MARKET_QUOTES[i] + shift); ImmutableMarketData ov = ImmutableMarketData.of(map); ImmutableRatesProvider rpShifted = calibrator.apply(ov); double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(EUR).getAmount(); assertEquals(mqsUsd2Computed[i], (pvS - pvEur) / shift, TOLERANCE_PV_DELTA); } double[] mqsEur1Computed = mqs.getSensitivity(EUR_DSC_CURVE_NAME, USD).getSensitivity().toArray(); for (int i = 0; i < EUR_DSC_NB_NODES; i++) { assertEquals(mqsEur1Computed[i], 0.0, TOLERANCE_PV_DELTA); } double[] mqsEur2Computed = mqs.getSensitivity(EUR_DSC_CURVE_NAME, EUR).getSensitivity().toArray(); for (int i = 0; i < EUR_DSC_NB_NODES; i++) { Map<MarketDataKey<?>, Object> map = new HashMap<>(ALL_QUOTES.getValues()); map.put( QuoteKey.of(StandardId.of(SCHEME, EUR_DSC_ID_VALUE[i])), EUR_DSC_MARKET_QUOTES[i] + shift); ImmutableMarketData marketData = ImmutableMarketData.of(map); ImmutableRatesProvider rpShifted = calibrator.apply(marketData); double pvS = FX_PRICER.presentValue(trade.getProduct(), rpShifted).getAmount(EUR).getAmount(); assertEquals(mqsEur2Computed[i], (pvS - pvEur) / shift, TOLERANCE_PV_DELTA, "Node " + i); } } }