static CurveSensitivityUtilsJacobianTest() { Tenor[] tenors = new Tenor[] { Tenor.TENOR_1D, Tenor.TENOR_1M, Tenor.TENOR_3M, Tenor.TENOR_6M, Tenor.TENOR_1Y, Tenor.TENOR_2Y, Tenor.TENOR_3Y, Tenor.TENOR_4Y, Tenor.TENOR_5Y, Tenor.TENOR_7Y, Tenor.TENOR_10Y, Tenor.TENOR_15Y, Tenor.TENOR_20Y, Tenor.TENOR_30Y }; IList <TenorParameterMetadata> metadataList = new List <TenorParameterMetadata>(); for (int looptenor = 0; looptenor < tenors.Length; looptenor++) { metadataList.Add(TenorParameterMetadata.of(tenors[looptenor])); } DoubleArray rate_eur = DoubleArray.of(0.0160, 0.0165, 0.0155, 0.0155, 0.0155, 0.0150, 0.0150, 0.0160, 0.0165, 0.0155, 0.0155, 0.0155, 0.0150, 0.0140); InterpolatedNodalCurve curve_single_eur = InterpolatedNodalCurve.builder().metadata(DefaultCurveMetadata.builder().curveName(EUR_SINGLE_NAME).parameterMetadata(metadataList).dayCount(ACT_365F).xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).build()).xValues(TIME_EUR).yValues(rate_eur).extrapolatorLeft(CurveExtrapolators.FLAT).extrapolatorRight(CurveExtrapolators.FLAT).interpolator(CurveInterpolators.LINEAR).build(); MULTICURVE_EUR_SINGLE_INPUT = ImmutableRatesProvider.builder(VALUATION_DATE).discountCurve(EUR, curve_single_eur).iborIndexCurve(EUR_EURIBOR_6M, curve_single_eur).build(); LIST_CURVE_NAMES_1.Add(CurveParameterSize.of(EUR_SINGLE_NAME, TIME_EUR.size())); }
//------------------------------------------------------------------------- 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))); }
//------------------------------------------------------------------------- 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); }
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))); }