//------------------------------------------------------------------------- /// <summary> /// Computes the present value curve sensitivity by simple forward rate estimation. /// </summary> /// <param name="cmsPeriod"> the CMS </param> /// <param name="provider"> the rates provider </param> /// <returns> the present value sensitivity </returns> public virtual PointSensitivityBuilder presentValueSensitivity(CmsPeriod cmsPeriod, RatesProvider provider) { Currency ccy = cmsPeriod.Currency; LocalDate valuationDate = provider.ValuationDate; if (valuationDate.isAfter(cmsPeriod.PaymentDate)) { return(PointSensitivityBuilder.none()); } LocalDate fixingDate = cmsPeriod.FixingDate; double dfPayment = provider.discountFactor(ccy, cmsPeriod.PaymentDate); if (!fixingDate.isAfter(valuationDate)) { // Using fixing double?fixedRate = provider.timeSeries(cmsPeriod.Index).get(fixingDate); if (fixedRate.HasValue) { double payoff = 0d; switch (cmsPeriod.CmsPeriodType) { case CAPLET: payoff = Math.Max(fixedRate.Value - cmsPeriod.Strike, 0d); break; case FLOORLET: payoff = Math.Max(cmsPeriod.Strike - fixedRate.Value, 0d); break; case COUPON: payoff = fixedRate.Value; break; default: throw new System.ArgumentException("unsupported CMS type"); } return(provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate).multipliedBy(payoff * cmsPeriod.Notional * cmsPeriod.YearFraction)); } else if (fixingDate.isBefore(valuationDate)) { throw new System.ArgumentException(Messages.format("Unable to get fixing for {} on date {}, no time-series supplied", cmsPeriod.Index, fixingDate)); } } if (!cmsPeriod.CmsPeriodType.Equals(CmsPeriodType.COUPON)) { throw new System.ArgumentException("Unable to price cap or floor in this pricer"); } // Using forward ResolvedSwap swap = cmsPeriod.UnderlyingSwap; ZeroRateSensitivity dfPaymentdr = provider.discountFactors(ccy).zeroRatePointSensitivity(cmsPeriod.PaymentDate); double forward = swapPricer.parRate(swap, provider); PointSensitivityBuilder forwardSensi = swapPricer.parRateSensitivity(swap, provider); return(forwardSensi.multipliedBy(dfPayment).combinedWith(dfPaymentdr.multipliedBy(forward)).multipliedBy(cmsPeriod.Notional * cmsPeriod.YearFraction)); }
public virtual void test_presentValueSensitivityRatesStickyStrike_parity() { CurrencyParameterSensitivities pvSensiRecLong = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS).build()); CurrencyParameterSensitivities pvSensiRecShort = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_REC_SHORT, RATE_PROVIDER, VOLS).build()); CurrencyParameterSensitivities pvSensiPayLong = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_LONG, RATE_PROVIDER, VOLS).build()); CurrencyParameterSensitivities pvSensiPayShort = RATE_PROVIDER.parameterSensitivity(PRICER_SWAPTION.presentValueSensitivityRatesStickyStrike(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS).build()); assertTrue(pvSensiRecLong.equalWithTolerance(pvSensiRecShort.multipliedBy(-1d), NOTIONAL * TOL)); assertTrue(pvSensiPayLong.equalWithTolerance(pvSensiPayShort.multipliedBy(-1d), NOTIONAL * TOL)); double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER); PointSensitivityBuilder forwardSensi = PRICER_SWAP.parRateSensitivity(RSWAP_REC, RATE_PROVIDER); double annuityCash = PRICER_SWAP.LegPricer.annuityCash(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward); double annuityCashDeriv = PRICER_SWAP.LegPricer.annuityCashDerivative(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward).getDerivative(0); double discount = RATE_PROVIDER.discountFactor(USD, SETTLE_DATE); PointSensitivityBuilder discountSensi = RATE_PROVIDER.discountFactors(USD).zeroRatePointSensitivity(SETTLE_DATE); PointSensitivities expecedPoint = discountSensi.multipliedBy(annuityCash * (forward - STRIKE)).combinedWith(forwardSensi.multipliedBy(discount * annuityCash + discount * annuityCashDeriv * (forward - STRIKE))).build(); CurrencyParameterSensitivities expected = RATE_PROVIDER.parameterSensitivity(expecedPoint); assertTrue(expected.equalWithTolerance(pvSensiPayLong.combinedWith(pvSensiRecLong.multipliedBy(-1d)), NOTIONAL * TOL)); assertTrue(expected.equalWithTolerance(pvSensiRecShort.combinedWith(pvSensiPayShort.multipliedBy(-1d)), NOTIONAL * TOL)); }
/// <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 calibration_transition_coherence_par_rate() { RatesProvider provider = CalibrationEurStandard.calibrateEurStandard(VAL_DATE, DSC_MARKET_QUOTES, DSC_OIS_TENORS, FWD3_FIXING_QUOTE, FWD3_FRA_QUOTES, FWD3_IRS_QUOTES, FWD3_FRA_TENORS, FWD3_IRS_TENORS, FWD6_FIXING_QUOTE, FWD6_FRA_QUOTES, FWD6_IRS_QUOTES, FWD6_FRA_TENORS, FWD6_IRS_TENORS); /* Curve Discounting/EUR-EONIA */ string[] dscIdValues = CalibrationEurStandard.dscIdValues(DSC_OIS_TENORS); /* Curve EUR-EURIBOR-3M */ double[] fwd3MarketQuotes = CalibrationEurStandard.fwdMarketQuotes(FWD3_FIXING_QUOTE, FWD3_FRA_QUOTES, FWD3_IRS_QUOTES); string[] fwd3IdValue = CalibrationEurStandard.fwdIdValue(3, FWD3_FIXING_QUOTE, FWD3_FRA_QUOTES, FWD3_IRS_QUOTES, FWD3_FRA_TENORS, FWD3_IRS_TENORS); /* Curve EUR-EURIBOR-6M */ double[] fwd6MarketQuotes = CalibrationEurStandard.fwdMarketQuotes(FWD6_FIXING_QUOTE, FWD6_FRA_QUOTES, FWD6_IRS_QUOTES); string[] fwd6IdValue = CalibrationEurStandard.fwdIdValue(6, FWD6_FIXING_QUOTE, FWD6_FRA_QUOTES, FWD6_IRS_QUOTES, FWD6_FRA_TENORS, FWD6_IRS_TENORS); /* All quotes for the curve calibration */ MarketData allQuotes = CalibrationEurStandard.allQuotes(VAL_DATE, DSC_MARKET_QUOTES, dscIdValues, fwd3MarketQuotes, fwd3IdValue, fwd6MarketQuotes, fwd6IdValue); /* All nodes by groups. */ RatesCurveGroupDefinition config = CalibrationEurStandard.config(DSC_OIS_TENORS, dscIdValues, FWD3_FRA_TENORS, FWD3_IRS_TENORS, fwd3IdValue, FWD6_FRA_TENORS, FWD6_IRS_TENORS, fwd6IdValue); ImmutableList <CurveDefinition> definitions = config.CurveDefinitions; // Test PV Dsc ImmutableList <CurveNode> dscNodes = definitions.get(0).Nodes; IList <ResolvedTrade> dscTrades = new List <ResolvedTrade>(); for (int i = 0; i < dscNodes.size(); i++) { dscTrades.Add(dscNodes.get(i).resolvedTrade(1d, allQuotes, REF_DATA)); } // OIS for (int loopnode = 0; loopnode < DSC_MARKET_QUOTES.Length; loopnode++) { PointSensitivities pts = SWAP_PRICER.parRateSensitivity(((ResolvedSwapTrade)dscTrades[loopnode]).Product, provider).build(); CurrencyParameterSensitivities ps = provider.parameterSensitivity(pts); CurrencyParameterSensitivities mqs = MQC.sensitivity(ps, provider); assertEquals(mqs.size(), 3); // Calibration of all curves simultaneously CurrencyParameterSensitivity mqsDsc = mqs.getSensitivity(CalibrationEurStandard.DSCON_CURVE_NAME, EUR); assertTrue(mqsDsc.MarketDataName.Equals(CalibrationEurStandard.DSCON_CURVE_NAME)); assertTrue(mqsDsc.Currency.Equals(EUR)); DoubleArray mqsData = mqsDsc.Sensitivity; assertEquals(mqsData.size(), DSC_MARKET_QUOTES.Length); for (int i = 0; i < mqsData.size(); i++) { assertEquals(mqsData.get(i), (i == loopnode) ? 1.0 : 0.0, TOLERANCE_DELTA); } } // Test PV Fwd3 ImmutableList <CurveNode> fwd3Nodes = definitions.get(1).Nodes; IList <ResolvedTrade> fwd3Trades = new List <ResolvedTrade>(); for (int i = 0; i < fwd3Nodes.size(); i++) { fwd3Trades.Add(fwd3Nodes.get(i).resolvedTrade(1d, allQuotes, REF_DATA)); } for (int loopnode = 0; loopnode < fwd3MarketQuotes.Length; loopnode++) { PointSensitivities pts = null; if (fwd3Trades[loopnode] is ResolvedIborFixingDepositTrade) { pts = PRICER_FIXING.parSpreadSensitivity(((ResolvedIborFixingDepositTrade)fwd3Trades[loopnode]).Product, provider); } if (fwd3Trades[loopnode] is ResolvedFraTrade) { pts = PRICER_FRA.parSpreadSensitivity(((ResolvedFraTrade)fwd3Trades[loopnode]).Product, provider); } if (fwd3Trades[loopnode] is ResolvedSwapTrade) { pts = SWAP_PRICER.parSpreadSensitivity(((ResolvedSwapTrade)fwd3Trades[loopnode]).Product, provider).build(); } CurrencyParameterSensitivities ps = provider.parameterSensitivity(pts); CurrencyParameterSensitivities mqs = MQC.sensitivity(ps, provider); assertEquals(mqs.size(), 3); // Calibration of all curves simultaneously CurrencyParameterSensitivity mqsDsc = mqs.getSensitivity(CalibrationEurStandard.DSCON_CURVE_NAME, EUR); CurrencyParameterSensitivity mqsFwd3 = mqs.getSensitivity(CalibrationEurStandard.FWD3_CURVE_NAME, EUR); DoubleArray mqsDscData = mqsDsc.Sensitivity; assertEquals(mqsDscData.size(), DSC_MARKET_QUOTES.Length); for (int i = 0; i < mqsDscData.size(); i++) { assertEquals(mqsDscData.get(i), 0.0, TOLERANCE_DELTA); } DoubleArray mqsFwd3Data = mqsFwd3.Sensitivity; assertEquals(mqsFwd3Data.size(), fwd3MarketQuotes.Length); for (int i = 0; i < mqsFwd3Data.size(); i++) { assertEquals(mqsFwd3Data.get(i), (i == loopnode) ? 1.0 : 0.0, TOLERANCE_DELTA); } } // Test PV Fwd6 ImmutableList <CurveNode> fwd6Nodes = definitions.get(2).Nodes; IList <ResolvedTrade> fwd6Trades = new List <ResolvedTrade>(); for (int i = 0; i < fwd6Nodes.size(); i++) { fwd6Trades.Add(fwd6Nodes.get(i).resolvedTrade(1d, allQuotes, REF_DATA)); } for (int loopnode = 0; loopnode < fwd6MarketQuotes.Length; loopnode++) { PointSensitivities pts = null; if (fwd6Trades[loopnode] is ResolvedIborFixingDepositTrade) { pts = PRICER_FIXING.parSpreadSensitivity(((ResolvedIborFixingDepositTrade)fwd6Trades[loopnode]).Product, provider); } if (fwd6Trades[loopnode] is ResolvedFraTrade) { pts = PRICER_FRA.parSpreadSensitivity(((ResolvedFraTrade)fwd6Trades[loopnode]).Product, provider); } if (fwd6Trades[loopnode] is ResolvedSwapTrade) { pts = SWAP_PRICER.parSpreadSensitivity(((ResolvedSwapTrade)fwd6Trades[loopnode]).Product, provider).build(); } CurrencyParameterSensitivities ps = provider.parameterSensitivity(pts); CurrencyParameterSensitivities mqs = MQC.sensitivity(ps, provider); assertEquals(mqs.size(), 3); CurrencyParameterSensitivity mqsDsc = mqs.getSensitivity(CalibrationEurStandard.DSCON_CURVE_NAME, EUR); CurrencyParameterSensitivity mqsFwd3 = mqs.getSensitivity(CalibrationEurStandard.FWD3_CURVE_NAME, EUR); CurrencyParameterSensitivity mqsFwd6 = mqs.getSensitivity(CalibrationEurStandard.FWD6_CURVE_NAME, EUR); DoubleArray mqsDscData = mqsDsc.Sensitivity; assertEquals(mqsDscData.size(), DSC_MARKET_QUOTES.Length); for (int i = 0; i < mqsDscData.size(); i++) { assertEquals(mqsDscData.get(i), 0.0, TOLERANCE_DELTA); } DoubleArray mqsFwd3Data = mqsFwd3.Sensitivity; assertEquals(mqsFwd3Data.size(), fwd3MarketQuotes.Length); for (int i = 0; i < mqsFwd3Data.size(); i++) { assertEquals(mqsFwd3Data.get(i), 0.0, TOLERANCE_DELTA); } DoubleArray mqsFwd6Data = mqsFwd6.Sensitivity; assertEquals(mqsFwd6Data.size(), fwd6MarketQuotes.Length); for (int i = 0; i < mqsFwd6Data.size(); i++) { assertEquals(mqsFwd6Data.get(i), (i == loopnode) ? 1.0 : 0.0, TOLERANCE_DELTA); } } }