//------------------------------------------------------------------------- /// <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> /// get the k^th order penalty matrix, P. This is defined as P = (D^T)*D , where D is the k^th order difference /// matrix (see getDifferenceMatrix), so the scalar amount (x^T)*P*x = |Dx|^2 is greater the more k^th order /// differences there are in the vector, x. This can then act as a penalty on x in some optimisation routine where /// x is the vector of (fit) parameters. </summary> /// <param name="m"> Length of the vector. </param> /// <param name="k"> Difference order. Require m > k </param> /// <returns> The k^th order penalty matrix, P </returns> public static DoubleMatrix getPenaltyMatrix(int m, int k) { ArgChecker.notNegativeOrZero(m, "m"); ArgChecker.notNegative(k, "k"); ArgChecker.isTrue(k < m, "Difference order too high, require m > k, but have: m = {} and k = {}", m, k); if (k == 0) { return(DoubleMatrix.identity(m)); } DoubleMatrix d = getDifferenceMatrix(m, k); DoubleMatrix dt = MA.getTranspose(d); return((DoubleMatrix)MA.multiply(dt, d)); }
// 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)); }
private DoubleMatrix getDiffMatrix(int m, int k) { ArgChecker.isTrue(k < m, "difference order too high"); //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[][] data = new double[m][m]; double[][] data = RectangularArrays.ReturnRectangularDoubleArray(m, m); if (m == 0) { return(DoubleMatrix.copyOf(data)); } int[] coeff = new int[k + 1]; int sign = 1; for (int i = k; i >= 0; i--) { coeff[i] = (int)(sign * binomialCoefficient(k, i)); sign *= -1; } for (int i = k; i < m; i++) { for (int j = 0; j < k + 1; j++) { data[i][j + i - k] = coeff[j]; } } DoubleMatrix d = DoubleMatrix.copyOf(data); DoubleMatrix dt = _algebra.getTranspose(d); return((DoubleMatrix)_algebra.multiply(dt, d)); }
//------------------------------------------------------------------------- // 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)); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test public void differenceMatrix1DTest() public virtual void differenceMatrix1DTest() { int n = 7; DoubleMatrix d0 = PenaltyMatrixGenerator.getDifferenceMatrix(n, 0); //zeroth order AssertMatrix.assertEqualsMatrix(DoubleMatrix.identity(n), d0, 1e-15); DoubleArray zeroVector = DoubleArray.filled(n); DoubleMatrix d1 = PenaltyMatrixGenerator.getDifferenceMatrix(n, 1); //first order difference matrix assertEquals(n, d1.rowCount()); assertEquals(n, d1.columnCount()); AssertMatrix.assertEqualsVectors(zeroVector, d1.row(0), 1e-15); //first row should be zero DoubleArray x = DoubleArray.filled(n, 1.0); DoubleArray d1x = (DoubleArray)MA.multiply(d1, x); //a constant vector should have zero first order differences AssertMatrix.assertEqualsVectors(zeroVector, d1x, 1e-14); DoubleMatrix d2 = PenaltyMatrixGenerator.getDifferenceMatrix(n, 2); //second order difference matrix assertEquals(n, d2.rowCount()); assertEquals(n, d2.columnCount()); AssertMatrix.assertEqualsVectors(zeroVector, d2.row(0), 1e-15); //first two rows should be zero AssertMatrix.assertEqualsVectors(zeroVector, d2.row(1), 1e-15); DoubleArray x2 = DoubleArray.of(n, i => i); d1x = (DoubleArray)MA.multiply(d1, x2); //first element of the diff vector is set to zero DoubleArray ones = DoubleArray.filled(n, 1.0).with(0, 0); //vector with differences of one AssertMatrix.assertEqualsVectors(ones, d1x, 1e-14); DoubleArray d2x = (DoubleArray)MA.multiply(d2, x2); //a linear vector should have zero second order differences AssertMatrix.assertEqualsVectors(zeroVector, d2x, 1e-14); DoubleMatrix d3 = PenaltyMatrixGenerator.getDifferenceMatrix(n, 3); //third order difference matrix assertEquals(n, d3.rowCount()); assertEquals(n, d3.columnCount()); AssertMatrix.assertEqualsVectors(zeroVector, d3.row(0), 1e-15); //first three rows should be zero AssertMatrix.assertEqualsVectors(zeroVector, d3.row(1), 1e-15); AssertMatrix.assertEqualsVectors(zeroVector, d3.row(2), 1e-15); DoubleArray x3 = DoubleArray.of(n, i => 0.5 + i + 0.1 * i * i); d1x = (DoubleArray)MA.multiply(d1, x3); // expected first order diff, first element is zero DoubleArray exp = DoubleArray.of(n, i => 0.9 + 0.2 * i).with(0, 0); AssertMatrix.assertEqualsVectors(exp, d1x, 1e-14); // expected second order diff, first two elements are zero exp = DoubleArray.filled(n, 0.2).with(0, 0).with(1, 0); d2x = (DoubleArray)MA.multiply(d2, x3); AssertMatrix.assertEqualsVectors(exp, d2x, 1e-14); DoubleArray d3x = (DoubleArray)MA.multiply(d3, x3); //a quadratic vector should have zero third order differences AssertMatrix.assertEqualsVectors(zeroVector, d3x, 1e-14); }
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))); }