//-------------------------------------------------------------------------
        /// <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
                }
            }
        }
Esempio n. 5
0
        //-------------------------------------------------------------------------
        /// <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);
                }
            }
        }