@Test /** Test the present value. */ public void presentValueExplicit() { final MultipleCurrencyAmount pv = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES); final double timeToExpiry = SWAPTION_LONG_PAYER.getTimeToExpiry(); final AnnuityPaymentFixed cfe = CFEC.visitSwap(SWAPTION_LONG_PAYER.getUnderlyingSwap(), MULTICURVES); final int numberOfPayments = cfe.getNumberOfPayments(); final double alpha[] = new double[numberOfPayments]; final double disccf[] = new double[numberOfPayments]; for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) { alpha[loopcf] = MODEL.alpha( HW_PARAMETERS, 0.0, timeToExpiry, timeToExpiry, cfe.getNthPayment(loopcf).getPaymentTime()); disccf[loopcf] = MULTICURVES.getDiscountFactor(EUR, cfe.getNthPayment(loopcf).getPaymentTime()) * cfe.getNthPayment(loopcf).getAmount(); } final double kappa = MODEL.kappa(disccf, alpha); double pvExpected = 0.0; for (int loopcf = 0; loopcf < numberOfPayments; loopcf++) { pvExpected += disccf[loopcf] * NORMAL.getCDF(-kappa - alpha[loopcf]); } assertEquals( "Swaption physical - Hull-White - present value", pvExpected, pv.getAmount(EUR), 1E-2); final MultipleCurrencyAmount pv2 = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, cfe, HW_MULTICURVES); assertEquals("Swaption physical - Hull-White - present value", pv, pv2); }
public void curveConstructionTest( final InstrumentDefinition<?>[][][] definitions, final MulticurveProviderDiscount curves, final boolean withToday, final int block) { final int nbBlocks = definitions.length; for (int loopblock = 0; loopblock < nbBlocks; loopblock++) { final InstrumentDerivative[][] instruments = convert(definitions[loopblock], withToday); final double[][] pv = new double[instruments.length][]; for (int loopcurve = 0; loopcurve < instruments.length; loopcurve++) { pv[loopcurve] = new double[instruments[loopcurve].length]; for (int loopins = 0; loopins < instruments[loopcurve].length; loopins++) { pv[loopcurve][loopins] = curves .getFxRates() .convert(instruments[loopcurve][loopins].accept(PVC, curves), AUD) .getAmount(); assertEquals( "Curve construction: block " + block + ", unit " + loopblock + " - instrument " + loopins, 0, pv[loopcurve][loopins], TOLERANCE_CAL); } } } }
@Test(enabled = true) /** * Tests to estimate the impact of mu on the CMS coupon pricing. "enabled = false" for the * standard testing. */ public void testPriceMultiMu() { final double[] mu = new double[] {1.10, 1.30, 1.55, 2.25, 3.50, 6.00, 15.0}; final int nbMu = mu.length; final double priceCouponStd = METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); @SuppressWarnings("unused") final double rateCouponStd = priceCouponStd / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double[] priceCouponExtra = new double[nbMu]; final double[] rateCouponExtra = new double[nbMu]; for (int loopmu = 0; loopmu < nbMu; loopmu++) { final CouponCMSSABRExtrapolationRightReplicationMethod methodExtrapolation = new CouponCMSSABRExtrapolationRightReplicationMethod(CUT_OFF_STRIKE, mu[loopmu]); priceCouponExtra[loopmu] = methodExtrapolation.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR); rateCouponExtra[loopmu] = priceCouponExtra[loopmu] / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); } final double priceCouponNoAdj = METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR); final double rateCouponNoAdj = priceCouponNoAdj / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); for (int loopmu = 1; loopmu < nbMu; loopmu++) { assertTrue( "Extrapolation: comparison with standard method", rateCouponExtra[loopmu - 1] > rateCouponExtra[loopmu]); } assertTrue( "Extrapolation: comparison with standard method", rateCouponExtra[nbMu - 1] > rateCouponNoAdj); }
@Test public void presentValueMarketDiscount() { final MultipleCurrencyAmount pvComputed = METHOD_CPN_IBOR.presentValue(CPN_IBOR, MULTICURVES); final double forward = MULTICURVES.getForwardRate( EURIBOR3M, CPN_IBOR.getFixingPeriodStartTime(), CPN_IBOR.getFixingPeriodEndTime(), CPN_IBOR.getFixingAccrualFactor()); final double df = MULTICURVES.getDiscountFactor(EURIBOR3M.getCurrency(), CPN_IBOR.getPaymentTime()); final double pvExpected = NOTIONAL * ACCRUAL_FACTOR * forward * df; assertEquals( "CouponIborDiscountingMarketMethod: present value", pvExpected, pvComputed.getAmount(EURIBOR3M.getCurrency()), TOLERANCE_PV); }
/** * Test the present value for a CMS coupon with pricing by replication in the SABR with * extrapolation framework. The present value is tested against hard-coded value and cap of strike * 0. */ public void presentValue() { // CMS cap/floor with strike 0 has the same price as a CMS coupon. final double priceCouponStd = METHOD_STANDARD_CPN.presentValue(CMS_COUPON, SABR_MULTICURVES).getAmount(EUR).getAmount(); final double rateCouponStd = priceCouponStd / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double priceCouponExtra = METHOD_EXTRAPOLATION_CPN .presentValue(CMS_COUPON, SABR_MULTICURVES) .getAmount(EUR) .getAmount(); final double rateCouponExtra = priceCouponExtra / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); final double priceCouponNoAdj = METHOD_DSC_CPN.presentValue(CMS_COUPON, MULTICURVES).getAmount(EUR).getAmount(); final double rateCouponNoAdj = priceCouponNoAdj / (CMS_COUPON.getPaymentYearFraction() * CMS_COUPON.getNotional() * MULTICURVES.getDiscountFactor(EUR, CMS_COUPON.getPaymentTime())); assertEquals( "Extrapolation: comparison with standard method", rateCouponStd > rateCouponExtra, true); assertEquals( "Extrapolation: comparison with no convexity adjustment", rateCouponExtra > rateCouponNoAdj, true); final double rateCouponExtraExpected = 0.0189864; // From previous run. assertEquals("Extrapolation: hard-coded value", rateCouponExtraExpected, rateCouponExtra, 1E-6); final double priceCap0Extra = METHOD_EXTRAPOLATION_CAP .presentValue(CMS_CAP_0, SABR_MULTICURVES) .getAmount(EUR) .getAmount(); assertEquals( "Extrapolation: CMS coupon vs Cap 0", priceCouponExtra, priceCap0Extra, TOLERANCE_PV); }
@Test /** Test the price curve sensitivity versus a finite difference computation. */ public void priceCurveSensitivity() { final SimpleParameterSensitivity pcsExact = SPSHWC.calculateSensitivity(ERU2, HW_MULTICURVES, MULTICURVES.getAllNames()); final SimpleParameterSensitivity pcsFD = SPSHWC_FD.calculateSensitivity(ERU2, HW_MULTICURVES); AssertSensitivityObjects.assertEquals( "DeliverableSwapFuturesSecurityHullWhiteMethod: priceCurveSensitivity", pcsExact, pcsFD, TOLERANCE_PRICE_DELTA); }
@Test public void parSpreadMarketQuoteDiscountingCalculator() { final double psmq = SWAP_MULTI_LEG.accept(PSMQDC, MULTICURVES); final double pv = -MULTICURVES .getFxRates() .convert( SWAP_MULTI_LEG.accept(PVDC, MULTICURVES), SWAP_MULTI_LEG.getLegs()[0].getCurrency()) .getAmount(); final double pvbp = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSC, MULTICURVES); assertEquals( "SwapMultileg: parSpreadMarketQuoteDiscountingCalculator", psmq, pv / pvbp, TOLERANCE_RATE); }
@Test public void parSpreadMarketQuoteCurveSensitivityDiscountingCalculator() { final double pv = MULTICURVES .getFxRates() .convert( SWAP_MULTI_LEG.accept(PVDC, MULTICURVES), SWAP_MULTI_LEG.getLegs()[0].getCurrency()) .getAmount(); final double pvbp = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSC, MULTICURVES); final MulticurveSensitivity pvcs = SWAP_MULTI_LEG .accept(PVCSDC, MULTICURVES) .converted(EUR, MULTICURVES.getFxRates()) .getSensitivity(EUR); final MulticurveSensitivity pvbpcs = SWAP_MULTI_LEG.getLegs()[0].accept(PVMQSCSC, MULTICURVES); final MulticurveSensitivity psmqcsExpected = pvcs.multipliedBy(-1.0d / pvbp).plus(pvbpcs.multipliedBy(pv / (pvbp * pvbp))).cleaned(); final MulticurveSensitivity psmqcs = SWAP_MULTI_LEG.accept(PSMQCSDC, MULTICURVES).cleaned(); AssertSensitivityObjects.assertEquals( "SwapMultileg: presentValueCurveSensitivityDiscountingCalculator", psmqcs, psmqcsExpected, TOLERANCE_RATE_DELTA); }
@Override protected void buildMessage( final FudgeSerializer serializer, final MutableFudgeMsg message, final MulticurveProviderDiscount object) { final Map<Currency, YieldAndDiscountCurve> discountingCurves = object.getDiscountingCurves(); for (final Map.Entry<Currency, YieldAndDiscountCurve> entry : discountingCurves.entrySet()) { message.add(CURRENCY_FIELD, entry.getKey().getCode()); serializer.addToMessageWithClassHeaders( message, DISCOUNTING_CURVE_FIELD, null, entry.getValue()); } final Map<IborIndex, YieldAndDiscountCurve> forwardIborCurves = object.getForwardIborCurves(); for (final Map.Entry<IborIndex, YieldAndDiscountCurve> entry : forwardIborCurves.entrySet()) { serializer.addToMessageWithClassHeaders(message, INDEX_IBOR_FIELD, null, entry.getKey()); serializer.addToMessageWithClassHeaders(message, INDEX_IBOR_CURVE, null, entry.getValue()); } final Map<IndexON, YieldAndDiscountCurve> forwardONCurves = object.getForwardONCurves(); for (final Map.Entry<IndexON, YieldAndDiscountCurve> entry : forwardONCurves.entrySet()) { serializer.addToMessageWithClassHeaders(message, INDEX_ON_FIELD, null, entry.getKey()); serializer.addToMessageWithClassHeaders( message, OVERNIGHT_CURVE_FIELD, null, entry.getValue()); } serializer.addToMessageWithClassHeaders(message, FX_MATRIX_FIELD, null, object.getFxRates()); }
@Test /** Test the convexity adjustment */ public void convexityAdjustment() { final double price = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES); final double forward = MULTICURVES.getSimplyCompoundForwardRate( EURIBOR3M, ERU2.getFixingPeriodStartTime(), ERU2.getFixingPeriodEndTime(), ERU2.getFixingPeriodAccrualFactor()); final double convexityAdjustment = METHOD_IRFUT_HW.convexityAdjustment(ERU2, HW_MULTICURVES); assertEquals( "InterestRateFutureSecurityHullWhiteProviderMethod: convexity adjustment", price - (1.0d - forward), convexityAdjustment, TOLERANCE_PRICE); final double caCalculator = ERU2.accept(CAHWC, HW_MULTICURVES); assertEquals( "DeliverableSwapFuturesSecurityDefinition: convexity adjustment", caCalculator, convexityAdjustment, TOLERANCE_PRICE); }
@Test /** Test the price computed from the curves and HW parameters. */ public void price() { final double price = METHOD_IRFUT_HW.price(ERU2, HW_MULTICURVES); final double forward = MULTICURVES.getSimplyCompoundForwardRate( EURIBOR3M, ERU2.getFixingPeriodStartTime(), ERU2.getFixingPeriodEndTime(), ERU2.getFixingPeriodAccrualFactor()); final double factor = MODEL.futuresConvexityFactor( MODEL_PARAMETERS, ERU2.getTradingLastTime(), ERU2.getFixingPeriodStartTime(), ERU2.getFixingPeriodEndTime()); final double expectedPrice = 1.0 - factor * forward + (1 - factor) / ERU2.getFixingPeriodAccrualFactor(); assertEquals( "InterestRateFutureSecurityHullWhiteProviderMethod: price", expectedPrice, price, TOLERANCE_PRICE); }
@Test(enabled = false) /** Tests present value curve sensitivity when the valuation date is on trade date. */ public void presentValueCurveSensitivityStability() { // 5Yx5Y final MultipleCurrencyParameterSensitivity pvpsExact = PS_HW_C.calculateSensitivity( SWAPTION_SHORT_RECEIVER, HW_MULTICURVES, HW_MULTICURVES.getMulticurveProvider().getAllNames()); final double derivativeExact = pvpsExact.totalSensitivity(MULTICURVES.getFxRates(), EUR); final double startingShift = 1.0E-4; final double ratio = Math.sqrt(2.0); final int nbShift = 55; final double[] eps = new double[nbShift + 1]; final double[] derivative_FD = new double[nbShift]; final double[] diff = new double[nbShift]; eps[0] = startingShift; for (int loopshift = 0; loopshift < nbShift; loopshift++) { final ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator fdShift = new ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(PVHWC, eps[loopshift]); final MultipleCurrencyParameterSensitivity pvpsFD = fdShift.calculateSensitivity(SWAPTION_SHORT_RECEIVER, HW_MULTICURVES); derivative_FD[loopshift] = pvpsFD.totalSensitivity(MULTICURVES.getFxRates(), EUR); diff[loopshift] = derivative_FD[loopshift] - derivativeExact; eps[loopshift + 1] = eps[loopshift] / ratio; } // 1Mx5Y final Period expirationPeriod = Period.ofDays( 1); // Period.ofDays(1); Period.ofDays(7); Period.ofMonths(1); Period.ofYears(1); // Period.ofYears(10); final ZonedDateTime expiryDateExp = ScheduleCalculator.getAdjustedDate(REFERENCE_DATE, expirationPeriod, EURIBOR6M, CALENDAR); final ZonedDateTime settlementDateExp = ScheduleCalculator.getAdjustedDate(expiryDateExp, SPOT_LAG, CALENDAR); final double ATM = 0.0151; // 1W: 1.52% - 1M: 1.52% - 1Y: 1.51% - 10Y: 1.51% final SwapFixedIborDefinition swapExpx5YDefinition = SwapFixedIborDefinition.from( settlementDateExp, SWAP_TENOR, EUR1YEURIBOR6M, NOTIONAL, ATM, !FIXED_IS_PAYER); final SwaptionPhysicalFixedIborDefinition swaptionExpx5YDefinition = SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, swapExpx5YDefinition, !IS_LONG); final SwaptionPhysicalFixedIbor swaptionExpx5Y = swaptionExpx5YDefinition.toDerivative(REFERENCE_DATE); // final double forward = swaptionExpx5Y.getUnderlyingSwap().accept(PRDC, MULTICURVES); final MultipleCurrencyParameterSensitivity pvpsExactExp = PS_HW_C.calculateSensitivity( swaptionExpx5Y, HW_MULTICURVES, HW_MULTICURVES.getMulticurveProvider().getAllNames()); final double derivativeExactExp = pvpsExactExp.totalSensitivity(MULTICURVES.getFxRates(), EUR); final double[] derivative_FDExp = new double[nbShift]; final double[] diffExp = new double[nbShift]; for (int loopshift = 0; loopshift < nbShift; loopshift++) { final ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator fdShift = new ParameterSensitivityHullWhiteDiscountInterpolatedFDCalculator(PVHWC, eps[loopshift]); final MultipleCurrencyParameterSensitivity pvpsFD = fdShift.calculateSensitivity(swaptionExpx5Y, HW_MULTICURVES); derivative_FDExp[loopshift] = pvpsFD.totalSensitivity(MULTICURVES.getFxRates(), EUR); diffExp[loopshift] = derivative_FDExp[loopshift] - derivativeExactExp; } // int t = 0; // t++; }