//------------------------------------------------------------------------- /// <summary> /// Calculates the market quote sensitivities from parameter sensitivity. /// </summary> /// <param name="paramSensitivities"> the curve parameter sensitivities </param> /// <param name="provider"> the rates provider, containing Jacobian calibration information </param> /// <returns> the market quote sensitivities </returns> public virtual CurrencyParameterSensitivities sensitivity(CurrencyParameterSensitivities paramSensitivities, RatesProvider provider) { ArgChecker.notNull(paramSensitivities, "paramSensitivities"); ArgChecker.notNull(provider, "provider"); CurrencyParameterSensitivities result = CurrencyParameterSensitivities.empty(); foreach (CurrencyParameterSensitivity paramSens in paramSensitivities.Sensitivities) { // find the matching calibration info Curve curve = provider.findData(paramSens.MarketDataName).filter(v => v is Curve).map(v => (Curve)v).orElseThrow(() => new System.ArgumentException("Market Quote sensitivity requires curve: " + paramSens.MarketDataName)); JacobianCalibrationMatrix info = curve.Metadata.findInfo(CurveInfoType.JACOBIAN).orElseThrow(() => new System.ArgumentException("Market Quote sensitivity requires Jacobian calibration information")); // calculate the market quote sensitivity using the Jacobian DoubleMatrix jacobian = info.JacobianMatrix; DoubleArray paramSensMatrix = paramSens.Sensitivity; DoubleArray marketQuoteSensMatrix = (DoubleArray)MATRIX_ALGEBRA.multiply(paramSensMatrix, jacobian); DoubleArray marketQuoteSens = marketQuoteSensMatrix; // split between different curves IDictionary <CurveName, DoubleArray> split = info.splitValues(marketQuoteSens); foreach (KeyValuePair <CurveName, DoubleArray> entry in split.SetOfKeyValuePairs()) { CurveName curveName = entry.Key; CurrencyParameterSensitivity maketQuoteSens = provider.findData(curveName).map(c => c.createParameterSensitivity(paramSens.Currency, entry.Value)).orElse(CurrencyParameterSensitivity.of(curveName, paramSens.Currency, entry.Value)); result = result.combinedWith(maketQuoteSens); } } return(result); }
/// <summary> /// Calibrate a single curve to 4 points. Use the resulting calibrated curves as starting point of the computation /// of a Jacobian. Compare the direct Jacobian and the one reconstructed from trades. /// </summary> public virtual void direct_one_curve() { /* Create trades */ IList <ResolvedTrade> trades = new List <ResolvedTrade>(); IList <LocalDate> nodeDates = new List <LocalDate>(); for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_SINGLE_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); nodeDates.Add(t.Product.EndDate); trades.Add(t); } /* Par rate sensitivity */ System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => MULTICURVE_EUR_SINGLE_CALIBRATED.parameterSensitivity(PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_SINGLE_CALIBRATED).build()); DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(LIST_CURVE_NAMES_1, trades, sensitivityFunction); DoubleMatrix jiExpected = MULTICURVE_EUR_SINGLE_CALIBRATED.findData(EUR_SINGLE_NAME).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get().JacobianMatrix; /* Comparison */ assertEquals(jiComputed.rowCount(), jiExpected.rowCount()); assertEquals(jiComputed.columnCount(), jiExpected.columnCount()); for (int i = 0; i < jiComputed.rowCount(); i++) { for (int j = 0; j < jiComputed.columnCount(); j++) { assertEquals(jiComputed.get(i, j), jiExpected.get(i, j), TOLERANCE_JAC); } } }
public virtual void test_ratesProvider() { ImmutableMap <Currency, CurveId> discounts = ImmutableMap.of(USD, CURVE_ID_DSC); ImmutableMap <Index, CurveId> forwards = ImmutableMap.of(USD_FED_FUND, CURVE_ID_DSC, USD_LIBOR_3M, CURVE_ID_FWD, US_CPI_U, CURVE_ID_FWD); RatesMarketDataLookup test = RatesMarketDataLookup.of(discounts, forwards); LocalDate valDate = date(2015, 6, 30); Curve dscCurve = ConstantCurve.of(Curves.discountFactors(CURVE_ID_DSC.CurveName, ACT_360), 1d); Curve fwdCurve = ConstantCurve.of(Curves.discountFactors(CURVE_ID_FWD.CurveName, ACT_360), 2d); MarketData md = ImmutableMarketData.of(valDate, ImmutableMap.of(CURVE_ID_DSC, dscCurve, CURVE_ID_FWD, fwdCurve)); RatesProvider ratesProvider = test.ratesProvider(md); assertEquals(ratesProvider.ValuationDate, valDate); assertEquals(ratesProvider.findData(CURVE_ID_DSC.CurveName), dscCurve); assertEquals(ratesProvider.findData(CURVE_ID_FWD.CurveName), fwdCurve); assertEquals(ratesProvider.findData(CurveName.of("Rubbish")), null); assertEquals(ratesProvider.IborIndices, ImmutableSet.of(USD_LIBOR_3M)); assertEquals(ratesProvider.OvernightIndices, ImmutableSet.of(USD_FED_FUND)); assertEquals(ratesProvider.PriceIndices, ImmutableSet.of(US_CPI_U)); assertEquals(ratesProvider.TimeSeriesIndices, ImmutableSet.of()); // check discount factors SimpleDiscountFactors df = (SimpleDiscountFactors)ratesProvider.discountFactors(USD); assertEquals(df.Curve.Name, dscCurve.Name); assertThrowsIllegalArg(() => ratesProvider.discountFactors(GBP)); // check Ibor DiscountIborIndexRates ibor = (DiscountIborIndexRates)ratesProvider.iborIndexRates(USD_LIBOR_3M); SimpleDiscountFactors iborDf = (SimpleDiscountFactors)ibor.DiscountFactors; assertEquals(iborDf.Curve.Name, fwdCurve.Name); assertThrowsIllegalArg(() => ratesProvider.iborIndexRates(GBP_LIBOR_3M)); // check Overnight DiscountOvernightIndexRates on = (DiscountOvernightIndexRates)ratesProvider.overnightIndexRates(USD_FED_FUND); SimpleDiscountFactors onDf = (SimpleDiscountFactors)on.DiscountFactors; assertEquals(onDf.Curve.Name, dscCurve.Name); assertThrowsIllegalArg(() => ratesProvider.overnightIndexRates(GBP_SONIA)); // check price curve must be interpolated assertThrowsIllegalArg(() => ratesProvider.priceIndexValues(US_CPI_U)); // to immutable ImmutableRatesProvider expectedImmutable = ImmutableRatesProvider.builder(valDate).fxRateProvider(MarketDataFxRateProvider.of(md)).discountCurve(USD, dscCurve).indexCurve(USD_FED_FUND, dscCurve).indexCurve(USD_LIBOR_3M, fwdCurve).indexCurve(US_CPI_U, fwdCurve).build(); assertEquals(ratesProvider.toImmutableRatesProvider(), expectedImmutable); }
/// <summary> /// Start from a generic zero-coupon curve. Compute the (inverse) Jacobian matrix using linear projection to a small /// number of points and the Jacobian utility. Compare the direct Jacobian obtained by calibrating a curve /// based on the trades with market quotes computed from the zero-coupon curve. /// </summary> public virtual void with_rebucketing_one_curve() { /* Create trades */ IList <ResolvedTrade> trades = new List <ResolvedTrade>(); IList <LocalDate> nodeDates = new List <LocalDate>(); double[] marketQuotes = new double[TENORS_STD_1.Length]; for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); marketQuotes[looptenor] = MARKET_QUOTE.value(t0, MULTICURVE_EUR_SINGLE_INPUT); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_1[looptenor], BuySell.BUY, 1.0, marketQuotes[looptenor], REF_DATA).resolve(REF_DATA); nodeDates.Add(t.Product.EndDate); trades.Add(t); } System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => CurveSensitivityUtils.linearRebucketing(MULTICURVE_EUR_SINGLE_INPUT.parameterSensitivity(PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_SINGLE_INPUT).build()), nodeDates, VALUATION_DATE); /* Market quotes for comparison */ IDictionary <QuoteId, double> mqCmp = new Dictionary <QuoteId, double>(); for (int looptenor = 0; looptenor < TENORS_STD_1.Length; looptenor++) { mqCmp[QuoteId.of(StandardId.of(OG_TICKER, TICKERS_STD_1[looptenor]))] = marketQuotes[looptenor]; } ImmutableMarketData marketQuotesObject = ImmutableMarketData.of(VALUATION_DATE, mqCmp); RatesProvider multicurveCmp = CALIBRATOR.calibrate(GROUPS_IN_1, marketQuotesObject, REF_DATA); /* Comparison */ DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(LIST_CURVE_NAMES_1, trades, sensitivityFunction); DoubleMatrix jiExpected = multicurveCmp.findData(EUR_SINGLE_NAME).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get().JacobianMatrix; assertEquals(jiComputed.rowCount(), jiExpected.rowCount()); assertEquals(jiComputed.columnCount(), jiExpected.columnCount()); for (int i = 0; i < jiComputed.rowCount(); i++) { for (int j = 0; j < jiComputed.columnCount(); j++) { assertEquals(jiComputed.get(i, j), jiExpected.get(i, j), TOLERANCE_JAC_APPROX); // The comparison is not perfect due to the incoherences introduced by the re-bucketing } } }
//------------------------------------------------------------------------- /// <summary> /// Calculates the notional equivalent from the present value market quote sensitivities. /// <para> /// The notional equivalent is the notional in each instrument used to calibrate the curves to have the same /// sensitivity as the one of the portfolio described by the market quote sensitivities. /// /// </para> /// </summary> /// <param name="marketQuoteSensitivities"> the market quote sensitivities </param> /// <param name="provider"> the rates provider, containing sensitivity information </param> /// <returns> the notionals </returns> public virtual CurrencyParameterSensitivities notionalEquivalent(CurrencyParameterSensitivities marketQuoteSensitivities, RatesProvider provider) { IList <CurrencyParameterSensitivity> equivalentList = new List <CurrencyParameterSensitivity>(); foreach (CurrencyParameterSensitivity s in marketQuoteSensitivities.Sensitivities) { ArgChecker.isTrue(s.MarketDataName is CurveName, "curve name"); CurveName name = (CurveName)s.MarketDataName; Optional <Curve> curveOpt = provider.findData(name); ArgChecker.isTrue(curveOpt.Present, "Curve {} in the sensitiivty is not present in the provider", name); Curve curve = curveOpt.get(); Optional <DoubleArray> pvSensiOpt = curve.Metadata.findInfo(CurveInfoType.PV_SENSITIVITY_TO_MARKET_QUOTE); ArgChecker.isTrue(pvSensiOpt.Present, "Present value sensitivity curve info is required"); DoubleArray pvSensi = pvSensiOpt.get(); double[] notionalArray = new double[pvSensi.size()]; for (int i = 0; i < pvSensi.size(); i++) { notionalArray[i] = s.Sensitivity.get(i) / pvSensi.get(i); } DoubleArray notional = DoubleArray.ofUnsafe(notionalArray); equivalentList.Add(CurrencyParameterSensitivity.of(name, s.ParameterMetadata, s.Currency, notional)); } return(CurrencyParameterSensitivities.of(equivalentList)); }
/// <summary> /// Calibrate a single curve to 4 points. Use the resulting calibrated curves as starting point of the computation /// of a Jacobian. Compare the direct Jacobian and the one reconstructed from trades. /// </summary> public virtual void direct_two_curves() { JacobianCalibrationMatrix jiObject = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_DSCON_OIS).get().Metadata.findInfo(CurveInfoType.JACOBIAN).get(); ImmutableList <CurveParameterSize> order = jiObject.Order; // To obtain the order of the curves in the jacobian /* Create trades */ IList <ResolvedTrade> tradesDsc = new List <ResolvedTrade>(); for (int looptenor = 0; looptenor < TENORS_STD_2_OIS.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EONIA_OIS.createTrade(VALUATION_DATE, TENORS_STD_2_OIS[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_2_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EONIA_OIS.createTrade(VALUATION_DATE, TENORS_STD_2_OIS[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); tradesDsc.Add(t); } IList <ResolvedTrade> tradesE3 = new List <ResolvedTrade>(); // Fixing IborFixingDepositConvention c = IborFixingDepositConvention.of(EUR_EURIBOR_6M); ResolvedIborFixingDepositTrade fix0 = c.createTrade(VALUATION_DATE, EUR_EURIBOR_6M.Tenor.Period, BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rateFixing = MARKET_QUOTE.value(fix0, MULTICURVE_EUR_2_CALIBRATED); ResolvedIborFixingDepositTrade fix = c.createTrade(VALUATION_DATE, EUR_EURIBOR_6M.Tenor.Period, BuySell.BUY, 1.0, rateFixing, REF_DATA).resolve(REF_DATA); tradesE3.Add(fix); // IRS for (int looptenor = 0; looptenor < TENORS_STD_2_IRS.Length; looptenor++) { ResolvedSwapTrade t0 = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_2_IRS[looptenor], BuySell.BUY, 1.0, 0.0, REF_DATA).resolve(REF_DATA); double rate = MARKET_QUOTE.value(t0, MULTICURVE_EUR_2_CALIBRATED); ResolvedSwapTrade t = EUR_FIXED_1Y_EURIBOR_6M.createTrade(VALUATION_DATE, TENORS_STD_2_IRS[looptenor], BuySell.BUY, 1.0, rate, REF_DATA).resolve(REF_DATA); tradesE3.Add(t); } IList <ResolvedTrade> trades = new List <ResolvedTrade>(); if (order.get(0).Name.Equals(EUR_DSCON_OIS)) { ((IList <ResolvedTrade>)trades).AddRange(tradesDsc); ((IList <ResolvedTrade>)trades).AddRange(tradesE3); } else { ((IList <ResolvedTrade>)trades).AddRange(tradesE3); ((IList <ResolvedTrade>)trades).AddRange(tradesDsc); } /* Par rate sensitivity */ System.Func <ResolvedTrade, CurrencyParameterSensitivities> sensitivityFunction = (t) => MULTICURVE_EUR_2_CALIBRATED.parameterSensitivity((t is ResolvedSwapTrade) ? PRICER_SWAP_PRODUCT.parRateSensitivity(((ResolvedSwapTrade)t).Product, MULTICURVE_EUR_2_CALIBRATED).build() : PRICER_IBORFIX_PRODUCT.parRateSensitivity(((ResolvedIborFixingDepositTrade)t).Product, MULTICURVE_EUR_2_CALIBRATED)); DoubleMatrix jiComputed = CurveSensitivityUtils.jacobianFromMarketQuoteSensitivities(order, trades, sensitivityFunction); DoubleMatrix jiExpectedDsc = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_DSCON_OIS).get().Metadata.getInfo(CurveInfoType.JACOBIAN).JacobianMatrix; DoubleMatrix jiExpectedE3 = MULTICURVE_EUR_2_CALIBRATED.findData(EUR_EURIBOR6M_IRS).get().Metadata.getInfo(CurveInfoType.JACOBIAN).JacobianMatrix; /* Comparison */ assertEquals(jiComputed.rowCount(), jiExpectedDsc.rowCount() + jiExpectedE3.rowCount()); assertEquals(jiComputed.columnCount(), jiExpectedDsc.columnCount()); assertEquals(jiComputed.columnCount(), jiExpectedE3.columnCount()); int shiftDsc = order.get(0).Name.Equals(EUR_DSCON_OIS) ? 0 : jiExpectedE3.rowCount(); for (int i = 0; i < jiExpectedDsc.rowCount(); i++) { for (int j = 0; j < jiExpectedDsc.columnCount(); j++) { assertEquals(jiComputed.get(i + shiftDsc, j), jiExpectedDsc.get(i, j), TOLERANCE_JAC); } } int shiftE3 = order.get(0).Name.Equals(EUR_DSCON_OIS) ? jiExpectedDsc.rowCount() : 0; for (int i = 0; i < jiExpectedE3.rowCount(); i++) { for (int j = 0; j < jiExpectedDsc.columnCount(); j++) { assertEquals(jiComputed.get(i + shiftE3, j), jiExpectedE3.get(i, j), TOLERANCE_JAC); } } }