/// <summary> /// Calculates the market quote sensitivities from parameter sensitivity. /// <para> /// This calculates the market quote sensitivities of fixed incomes. /// The input parameter sensitivities must be computed based on the legal entity discounting provider. /// /// </para> /// </summary> /// <param name="paramSensitivities"> the curve parameter sensitivities </param> /// <param name="provider"> the legal entity discounting provider, containing Jacobian calibration information </param> /// <returns> the market quote sensitivities </returns> public virtual CurrencyParameterSensitivities sensitivity(CurrencyParameterSensitivities paramSensitivities, LegalEntityDiscountingProvider 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); }
// jacobian indirect, merging groups private static DoubleMatrix jacobianIndirect(DoubleMatrix res, DoubleMatrix pDmCurrentMatrix, int nbTrades, int totalParamsGroup, int totalParamsPrevious, ImmutableList <CurveParameterSize> orderPrevious, ImmutableMap <CurveName, JacobianCalibrationMatrix> jacobiansPrevious) { if (totalParamsPrevious == 0) { return(DoubleMatrix.EMPTY); } //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] nonDirect = new double[totalParamsGroup][totalParamsPrevious]; double[][] nonDirect = RectangularArrays.ReturnRectangularDoubleArray(totalParamsGroup, totalParamsPrevious); for (int i = 0; i < nbTrades; i++) { Array.Copy(res.rowArray(i), 0, nonDirect[i], 0, totalParamsPrevious); } DoubleMatrix pDpPreviousMatrix = (DoubleMatrix)MATRIX_ALGEBRA.scale(MATRIX_ALGEBRA.multiply(pDmCurrentMatrix, DoubleMatrix.copyOf(nonDirect)), -1d); // all curves: order and size int[] startIndexBefore = new int[orderPrevious.size()]; for (int i = 1; i < orderPrevious.size(); i++) { startIndexBefore[i] = startIndexBefore[i - 1] + orderPrevious.get(i - 1).ParameterCount; } // transition Matrix: all curves from previous groups //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] transition = new double[totalParamsPrevious][totalParamsPrevious]; double[][] transition = RectangularArrays.ReturnRectangularDoubleArray(totalParamsPrevious, totalParamsPrevious); for (int i = 0; i < orderPrevious.size(); i++) { int paramCountOuter = orderPrevious.get(i).ParameterCount; JacobianCalibrationMatrix thisInfo = jacobiansPrevious.get(orderPrevious.get(i).Name); DoubleMatrix thisMatrix = thisInfo.JacobianMatrix; int startIndexInner = 0; for (int j = 0; j < orderPrevious.size(); j++) { int paramCountInner = orderPrevious.get(j).ParameterCount; if (thisInfo.containsCurve(orderPrevious.get(j).Name)) { // If not, the matrix stay with 0 for (int k = 0; k < paramCountOuter; k++) { Array.Copy(thisMatrix.rowArray(k), startIndexInner, transition[startIndexBefore[i] + k], startIndexBefore[j], paramCountInner); } } startIndexInner += paramCountInner; } } DoubleMatrix transitionMatrix = DoubleMatrix.copyOf(transition); return((DoubleMatrix)MATRIX_ALGEBRA.multiply(pDpPreviousMatrix, transitionMatrix)); }
//------------------------------------------------------------------------- internal static ScenarioMarketData marketData(CurveName curveName) { DoubleMatrix jacobian = DoubleMatrix.ofUnsafe(new double[][] { new double[] { 0.985d, 0.01d, 0d }, new double[] { 0.01d, 0.98d, 0.01d }, new double[] { 0.005d, 0.01d, 0.99d } }); JacobianCalibrationMatrix jcm = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(curveName, 3)), jacobian); DoubleArray time = DoubleArray.of(0.1, 0.25, 0.5d); DoubleArray rate = DoubleArray.of(0.01, 0.015, 0.008d); Curve curve = InterpolatedNodalCurve.of(Curves.zeroRates(curveName, ACT_360).withInfo(CurveInfoType.JACOBIAN, jcm), time, rate, NATURAL_SPLINE); TestMarketDataMap md = new TestMarketDataMap(VAL_DATE, ImmutableMap.of(FORWARD_CURVE_ID, curve, QUOTE_KEY, MARKET_PRICE), ImmutableMap.of()); return(md); }
//------------------------------------------------------------------------- // calculates the Jacobian and builds the result, called once per group // this uses, but does not alter, data from previous groups private ImmutableMap <CurveName, JacobianCalibrationMatrix> updateJacobiansForGroup(ImmutableRatesProvider provider, ImmutableList <ResolvedTrade> trades, ImmutableList <CurveParameterSize> orderGroup, ImmutableList <CurveParameterSize> orderPrev, ImmutableList <CurveParameterSize> orderAll, ImmutableMap <CurveName, JacobianCalibrationMatrix> jacobians) { // sensitivity to all parameters in the stated order int totalParamsAll = orderAll.Select(e => e.ParameterCount).Sum(); DoubleMatrix res = derivatives(trades, provider, orderAll, totalParamsAll); // jacobian direct int nbTrades = trades.size(); int totalParamsGroup = orderGroup.Select(e => e.ParameterCount).Sum(); int totalParamsPrevious = totalParamsAll - totalParamsGroup; DoubleMatrix pDmCurrentMatrix = jacobianDirect(res, nbTrades, totalParamsGroup, totalParamsPrevious); // jacobian indirect: when totalParamsPrevious > 0 DoubleMatrix pDmPrevious = jacobianIndirect(res, pDmCurrentMatrix, nbTrades, totalParamsGroup, totalParamsPrevious, orderPrev, jacobians); // add to the map of jacobians, one entry for each curve in this group ImmutableMap.Builder <CurveName, JacobianCalibrationMatrix> jacobianBuilder = ImmutableMap.builder(); jacobianBuilder.putAll(jacobians); int startIndex = 0; foreach (CurveParameterSize order in orderGroup) { int paramCount = order.ParameterCount; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] pDmCurveArray = new double[paramCount][totalParamsAll]; double[][] pDmCurveArray = RectangularArrays.ReturnRectangularDoubleArray(paramCount, totalParamsAll); // copy data for previous groups if (totalParamsPrevious > 0) { for (int p = 0; p < paramCount; p++) { Array.Copy(pDmPrevious.rowArray(startIndex + p), 0, pDmCurveArray[p], 0, totalParamsPrevious); } } // copy data for this group for (int p = 0; p < paramCount; p++) { Array.Copy(pDmCurrentMatrix.rowArray(startIndex + p), 0, pDmCurveArray[p], totalParamsPrevious, totalParamsGroup); } // build final Jacobian matrix DoubleMatrix pDmCurveMatrix = DoubleMatrix.ofUnsafe(pDmCurveArray); jacobianBuilder.put(order.Name, JacobianCalibrationMatrix.of(orderAll, pDmCurveMatrix)); startIndex += paramCount; } return(jacobianBuilder.build()); }
// build the map of additional info private CurveMetadata childMetadata(CurveMetadata metadata, CurveDefinition curveDefn, IDictionary <CurveName, JacobianCalibrationMatrix> jacobians, IDictionary <CurveName, DoubleArray> sensitivitiesMarketQuote) { JacobianCalibrationMatrix jacobian = jacobians[curveDefn.Name]; CurveMetadata metadataResult = metadata; if (jacobian != null) { metadataResult = metadata.withInfo(CurveInfoType.JACOBIAN, jacobian); } DoubleArray sensitivity = sensitivitiesMarketQuote[curveDefn.Name]; if (sensitivity != null) { metadataResult = metadataResult.withInfo(CurveInfoType.PV_SENSITIVITY_TO_MARKET_QUOTE, sensitivity); } return(metadataResult); }
//------------------------------------------------------------------------- internal static ScenarioMarketData marketData() { CurveParameterSize issuerSize = CurveParameterSize.of(ISSUER_CURVE_ID.CurveName, 3); CurveParameterSize repoSize = CurveParameterSize.of(REPO_CURVE_ID.CurveName, 2); JacobianCalibrationMatrix issuerMatrix = JacobianCalibrationMatrix.of(ImmutableList.of(issuerSize, repoSize), DoubleMatrix.copyOf(new double[][] { new double[] { 0.95, 0.03, 0.01, 0.006, 0.004 }, new double[] { 0.03, 0.95, 0.01, 0.005, 0.005 }, new double[] { 0.03, 0.01, 0.95, 0.002, 0.008 } })); JacobianCalibrationMatrix repoMatrix = JacobianCalibrationMatrix.of(ImmutableList.of(issuerSize, repoSize), DoubleMatrix.copyOf(new double[][] { new double[] { 0.003, 0.003, 0.004, 0.97, 0.02 }, new double[] { 0.003, 0.006, 0.001, 0.05, 0.94 } })); CurveMetadata issuerMetadata = Curves.zeroRates(ISSUER_CURVE_ID.CurveName, ACT_360).withInfo(CurveInfoType.JACOBIAN, issuerMatrix); CurveMetadata repoMetadata = Curves.zeroRates(REPO_CURVE_ID.CurveName, ACT_360).withInfo(CurveInfoType.JACOBIAN, repoMatrix); Curve issuerCurve = InterpolatedNodalCurve.of(issuerMetadata, DoubleArray.of(1.0, 5.0, 10.0), DoubleArray.of(0.02, 0.04, 0.01), CurveInterpolators.LINEAR); Curve repoCurve = InterpolatedNodalCurve.of(repoMetadata, DoubleArray.of(0.5, 3.0), DoubleArray.of(0.005, 0.008), CurveInterpolators.LINEAR); return(new TestMarketDataMap(VALUATION_DATE, ImmutableMap.of(REPO_CURVE_ID, repoCurve, ISSUER_CURVE_ID, issuerCurve), ImmutableMap.of())); }
//------------------------------------------------------------------------- // shift the curve private NodalCurve withShift(InterpolatedNodalCurve curve, IList <ParameterMetadata> parameterMetadata, DoubleMatrix sensitivity, bool computeJacobian, double shift) { int nNode = curve.ParameterCount; if (shift < curve.XValues.get(0)) { //offset less than t value of 1st knot, so no knots are not removed double eta = curve.YValues.get(0) * shift; DoubleArray time = DoubleArray.of(nNode, i => curve.XValues.get(i) - shift); DoubleArray rate = DoubleArray.of(nNode, i => (curve.YValues.get(i) * curve.XValues.get(i) - eta) / time.get(i)); CurveMetadata metadata = curve.Metadata.withParameterMetadata(parameterMetadata); if (computeJacobian) { //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] transf = new double[nNode][nNode]; double[][] transf = RectangularArrays.ReturnRectangularDoubleArray(nNode, nNode); for (int i = 0; i < nNode; ++i) { transf[i][0] = -shift / time.get(i); transf[i][i] += curve.XValues.get(i) / time.get(i); } DoubleMatrix jacobianMatrix = (DoubleMatrix)MATRIX_ALGEBRA.multiply(DoubleMatrix.ofUnsafe(transf), MATRIX_ALGEBRA.getInverse(sensitivity)); JacobianCalibrationMatrix jacobian = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(curve.Name, nNode)), jacobianMatrix); return(curve.withValues(time, rate).withMetadata(metadata.withInfo(CurveInfoType.JACOBIAN, jacobian))); } return(curve.withValues(time, rate).withMetadata(metadata)); } if (shift >= curve.XValues.get(nNode - 1)) { //new base after last knot. The new 'curve' has a constant zero rate which we represent with a nominal knot at 1.0 double time = 1d; double interval = curve.XValues.get(nNode - 1) - curve.XValues.get(nNode - 2); double rate = (curve.YValues.get(nNode - 1) * curve.XValues.get(nNode - 1) - curve.YValues.get(nNode - 2) * curve.XValues.get(nNode - 2)) / interval; if (computeJacobian) { //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] transf = new double[1][nNode]; double[][] transf = RectangularArrays.ReturnRectangularDoubleArray(1, nNode); transf[0][nNode - 2] = -curve.XValues.get(nNode - 2) / interval; transf[0][nNode - 1] = curve.XValues.get(nNode - 1) / interval; DoubleMatrix jacobianMatrix = (DoubleMatrix)MATRIX_ALGEBRA.multiply(DoubleMatrix.ofUnsafe(transf), MATRIX_ALGEBRA.getInverse(sensitivity)); JacobianCalibrationMatrix jacobian = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(curve.Name, nNode)), jacobianMatrix); return(ConstantNodalCurve.of(curve.Metadata.withInfo(CurveInfoType.JACOBIAN, jacobian), time, rate)); } return(ConstantNodalCurve.of(curve.Metadata, time, rate)); } //offset greater than (or equal to) t value of 1st knot, so at least one knot must be removed int index = Arrays.binarySearch(curve.XValues.toArray(), shift); if (index < 0) { index = -(index + 1); } else { index++; } double interval = curve.XValues.get(index) - curve.XValues.get(index - 1); double tt1 = curve.XValues.get(index - 1) * (curve.XValues.get(index) - shift); double tt2 = curve.XValues.get(index) * (shift - curve.XValues.get(index - 1)); double eta = (curve.YValues.get(index - 1) * tt1 + curve.YValues.get(index) * tt2) / interval; int m = nNode - index; CurveMetadata metadata = curve.Metadata.withParameterMetadata(parameterMetadata.subList(index, nNode)); //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final int indexFinal = index; int indexFinal = index; DoubleArray time = DoubleArray.of(m, i => curve.XValues.get(i + indexFinal) - shift); DoubleArray rate = DoubleArray.of(m, i => (curve.YValues.get(i + indexFinal) * curve.XValues.get(i + indexFinal) - eta) / time.get(i)); if (computeJacobian) { //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] transf = new double[m][nNode]; double[][] transf = RectangularArrays.ReturnRectangularDoubleArray(m, nNode); for (int i = 0; i < m; ++i) { transf[i][index - 1] -= tt1 / (time.get(i) * interval); transf[i][index] -= tt2 / (time.get(i) * interval); transf[i][i + index] += curve.XValues.get(i + index) / time.get(i); } DoubleMatrix jacobianMatrix = (DoubleMatrix)MATRIX_ALGEBRA.multiply(DoubleMatrix.ofUnsafe(transf), MATRIX_ALGEBRA.getInverse(sensitivity)); JacobianCalibrationMatrix jacobian = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(curve.Name, nNode)), jacobianMatrix); return(curve.withValues(time, rate).withMetadata(metadata.withInfo(CurveInfoType.JACOBIAN, jacobian))); } return(curve.withValues(time, rate).withMetadata(metadata)); }
//------------------------------------------------------------------------- /// <summary> /// Calibrates the ISDA compliant discount curve to the market data. /// <para> /// This creates the single discount curve for a specified currency. /// The curve nodes in {@code IsdaCreditCurveDefinition} should be term deposit or fixed-for-Ibor swap, /// and the number of nodes should be greater than 1. /// /// </para> /// </summary> /// <param name="curveDefinition"> the curve definition </param> /// <param name="marketData"> the market data </param> /// <param name="refData"> the reference data </param> /// <returns> the ISDA compliant discount curve </returns> public IsdaCreditDiscountFactors calibrate(IsdaCreditCurveDefinition curveDefinition, MarketData marketData, ReferenceData refData) { //JAVA TO C# CONVERTER WARNING: Java wildcard generics have no direct equivalent in .NET: //ORIGINAL LINE: java.util.List<? extends com.opengamma.strata.market.curve.IsdaCreditCurveNode> curveNodes = curveDefinition.getCurveNodes(); IList <IsdaCreditCurveNode> curveNodes = curveDefinition.CurveNodes; int nNodes = curveNodes.Count; ArgChecker.isTrue(nNodes > 1, "the number of curve nodes must be greater than 1"); LocalDate curveSnapDate = marketData.ValuationDate; LocalDate curveValuationDate = curveDefinition.CurveValuationDate; DayCount curveDayCount = curveDefinition.DayCount; BasicFixedLeg[] swapLeg = new BasicFixedLeg[nNodes]; double[] termDepositYearFraction = new double[nNodes]; double[] curveNodeTime = new double[nNodes]; double[] rates = new double[nNodes]; ImmutableList.Builder <ParameterMetadata> paramMetadata = ImmutableList.builder(); int nTermDeposit = 0; LocalDate curveSpotDate = null; for (int i = 0; i < nNodes; i++) { LocalDate cvDateTmp; IsdaCreditCurveNode node = curveNodes[i]; rates[i] = marketData.getValue(node.ObservableId); LocalDate adjMatDate = node.date(curveSnapDate, refData); paramMetadata.add(node.metadata(adjMatDate)); if (node is DepositIsdaCreditCurveNode) { DepositIsdaCreditCurveNode termDeposit = (DepositIsdaCreditCurveNode)node; cvDateTmp = termDeposit.SpotDateOffset.adjust(curveSnapDate, refData); curveNodeTime[i] = curveDayCount.relativeYearFraction(cvDateTmp, adjMatDate); termDepositYearFraction[i] = termDeposit.DayCount.relativeYearFraction(cvDateTmp, adjMatDate); ArgChecker.isTrue(nTermDeposit == i, "TermDepositCurveNode should not be after FixedIborSwapCurveNode"); ++nTermDeposit; } else if (node is SwapIsdaCreditCurveNode) { SwapIsdaCreditCurveNode swap = (SwapIsdaCreditCurveNode)node; cvDateTmp = swap.SpotDateOffset.adjust(curveSnapDate, refData); curveNodeTime[i] = curveDayCount.relativeYearFraction(cvDateTmp, adjMatDate); BusinessDayAdjustment busAdj = swap.BusinessDayAdjustment; swapLeg[i] = new BasicFixedLeg(this, cvDateTmp, cvDateTmp.plus(swap.Tenor), swap.PaymentFrequency.Period, swap.DayCount, curveDayCount, busAdj, refData); } else { throw new System.ArgumentException("unsupported cuve node type"); } if (i > 0) { ArgChecker.isTrue(curveNodeTime[i] - curveNodeTime[i - 1] > 0, "curve nodes should be ascending in terms of tenor"); ArgChecker.isTrue(cvDateTmp.Equals(curveSpotDate), "spot lag should be common for all of the curve nodes"); } else { ArgChecker.isTrue(curveNodeTime[i] >= 0d, "the first node should be after curve spot date"); curveSpotDate = cvDateTmp; } } ImmutableList <ParameterMetadata> parameterMetadata = paramMetadata.build(); double[] ratesMod = Arrays.copyOf(rates, nNodes); for (int i = 0; i < nTermDeposit; ++i) { double dfInv = 1d + ratesMod[i] * termDepositYearFraction[i]; ratesMod[i] = Math.Log(dfInv) / curveNodeTime[i]; } InterpolatedNodalCurve curve = curveDefinition.curve(DoubleArray.ofUnsafe(curveNodeTime), DoubleArray.ofUnsafe(ratesMod)); for (int i = nTermDeposit; i < nNodes; ++i) { curve = fitSwap(i, swapLeg[i], curve, rates[i]); } Currency currency = curveDefinition.Currency; DoubleMatrix sensi = quoteValueSensitivity(nTermDeposit, termDepositYearFraction, swapLeg, ratesMod, curve, curveDefinition.ComputeJacobian); if (curveValuationDate.isEqual(curveSpotDate)) { if (curveDefinition.ComputeJacobian) { JacobianCalibrationMatrix jacobian = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(curveDefinition.Name, nNodes)), MATRIX_ALGEBRA.getInverse(sensi)); NodalCurve curveWithParamMetadata = curve.withMetadata(curve.Metadata.withInfo(CurveInfoType.JACOBIAN, jacobian).withParameterMetadata(parameterMetadata)); return(IsdaCreditDiscountFactors.of(currency, curveValuationDate, curveWithParamMetadata)); } NodalCurve curveWithParamMetadata = curve.withMetadata(curve.Metadata.withParameterMetadata(parameterMetadata)); return(IsdaCreditDiscountFactors.of(currency, curveValuationDate, curveWithParamMetadata)); } double offset = curveDayCount.relativeYearFraction(curveSpotDate, curveValuationDate); return(IsdaCreditDiscountFactors.of(currency, curveValuationDate, withShift(curve, parameterMetadata, sensi, curveDefinition.ComputeJacobian, offset))); }
/// <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); } } }
internal virtual LegalEntitySurvivalProbabilities calibrate(IList <CdsIsdaCreditCurveNode> curveNodes, CurveName name, MarketData marketData, ImmutableCreditRatesProvider ratesProvider, DayCount definitionDayCount, Currency definitionCurrency, bool computeJacobian, bool storeTrade, ReferenceData refData) { //JAVA TO C# CONVERTER TODO TASK: Method reference arbitrary object instance method syntax is not converted by Java to C# Converter: //JAVA TO C# CONVERTER TODO TASK: Most Java stream collectors are not converted by Java to C# Converter: IEnumerator <StandardId> legalEntities = curveNodes.Select(CdsIsdaCreditCurveNode::getLegalEntityId).collect(Collectors.toSet()).GetEnumerator(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: StandardId legalEntityId = legalEntities.next(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: ArgChecker.isFalse(legalEntities.hasNext(), "legal entity must be common to curve nodes"); //JAVA TO C# CONVERTER TODO TASK: Most Java stream collectors are not converted by Java to C# Converter: IEnumerator <Currency> currencies = curveNodes.Select(n => n.Template.Convention.Currency).collect(Collectors.toSet()).GetEnumerator(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: Currency currency = currencies.next(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: ArgChecker.isFalse(currencies.hasNext(), "currency must be common to curve nodes"); ArgChecker.isTrue(definitionCurrency.Equals(currency), "curve definition currency must be the same as the currency of CDS"); //JAVA TO C# CONVERTER TODO TASK: Most Java stream collectors are not converted by Java to C# Converter: IEnumerator <CdsQuoteConvention> quoteConventions = curveNodes.Select(n => n.QuoteConvention).collect(Collectors.toSet()).GetEnumerator(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: CdsQuoteConvention quoteConvention = quoteConventions.next(); //JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops: ArgChecker.isFalse(quoteConventions.hasNext(), "quote convention must be common to curve nodes"); LocalDate valuationDate = marketData.ValuationDate; ArgChecker.isTrue(valuationDate.Equals(marketData.ValuationDate), "ratesProvider and marketDate must be based on the same valuation date"); CreditDiscountFactors discountFactors = ratesProvider.discountFactors(currency); ArgChecker.isTrue(definitionDayCount.Equals(discountFactors.DayCount), "credit curve and discount curve must be based on the same day count convention"); RecoveryRates recoveryRates = ratesProvider.recoveryRates(legalEntityId); int nNodes = curveNodes.Count; double[] coupons = new double[nNodes]; double[] pufs = new double[nNodes]; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] diag = new double[nNodes][nNodes]; double[][] diag = RectangularArrays.ReturnRectangularDoubleArray(nNodes, nNodes); ImmutableList.Builder <ResolvedCdsTrade> tradesBuilder = ImmutableList.builder(); for (int i = 0; i < nNodes; i++) { CdsCalibrationTrade tradeCalibration = curveNodes[i].trade(1d, marketData, refData); ResolvedCdsTrade trade = tradeCalibration.UnderlyingTrade.resolve(refData); tradesBuilder.add(trade); double[] temp = getStandardQuoteForm(trade, tradeCalibration.Quote, valuationDate, discountFactors, recoveryRates, computeJacobian, refData); coupons[i] = temp[0]; pufs[i] = temp[1]; diag[i][i] = temp[2]; } ImmutableList <ResolvedCdsTrade> trades = tradesBuilder.build(); NodalCurve nodalCurve = calibrate(trades, DoubleArray.ofUnsafe(coupons), DoubleArray.ofUnsafe(pufs), name, valuationDate, discountFactors, recoveryRates, refData); if (computeJacobian) { LegalEntitySurvivalProbabilities creditCurve = LegalEntitySurvivalProbabilities.of(legalEntityId, IsdaCreditDiscountFactors.of(currency, valuationDate, nodalCurve)); ImmutableCreditRatesProvider ratesProviderNew = ratesProvider.toBuilder().creditCurves(ImmutableMap.of(Pair.of(legalEntityId, currency), creditCurve)).build(); System.Func <ResolvedCdsTrade, DoubleArray> sensiFunc = quoteConvention.Equals(CdsQuoteConvention.PAR_SPREAD) ? getParSpreadSensitivityFunction(ratesProviderNew, name, currency, refData) : getPointsUpfrontSensitivityFunction(ratesProviderNew, name, currency, refData); DoubleMatrix sensi = DoubleMatrix.ofArrayObjects(nNodes, nNodes, i => sensiFunc(trades.get(i))); sensi = (DoubleMatrix)MATRIX_ALGEBRA.multiply(DoubleMatrix.ofUnsafe(diag), sensi); JacobianCalibrationMatrix jacobian = JacobianCalibrationMatrix.of(ImmutableList.of(CurveParameterSize.of(name, nNodes)), MATRIX_ALGEBRA.getInverse(sensi)); nodalCurve = nodalCurve.withMetadata(nodalCurve.Metadata.withInfo(CurveInfoType.JACOBIAN, jacobian)); } ImmutableList <ParameterMetadata> parameterMetadata; if (storeTrade) { parameterMetadata = IntStream.range(0, nNodes).mapToObj(n => ResolvedTradeParameterMetadata.of(trades.get(n), curveNodes[n].Label)).collect(Guavate.toImmutableList()); } else { parameterMetadata = IntStream.range(0, nNodes).mapToObj(n => curveNodes[n].metadata(trades.get(n).Product.ProtectionEndDate)).collect(Guavate.toImmutableList()); } nodalCurve = nodalCurve.withMetadata(nodalCurve.Metadata.withParameterMetadata(parameterMetadata)); return(LegalEntitySurvivalProbabilities.of(legalEntityId, IsdaCreditDiscountFactors.of(currency, valuationDate, nodalCurve))); }