static { LEGS_DEFINITION[0] = AnnuityDefinitionBuilder.couponFixed( EUR, SETTLEMENT_DATE, MATURITY_DATE, EUR1YEURIBOR6M.getFixedLegPeriod(), TARGET, EUR1YEURIBOR6M.getFixedLegDayCount(), EUR1YEURIBOR6M.getBusinessDayConvention(), EUR1YEURIBOR6M.isEndOfMonth(), NOTIONAL, SPREAD, IS_PAYER_SPREAD, STUB, 0); LEGS_DEFINITION[1] = AnnuityDefinitionBuilder.couponIbor( SETTLEMENT_DATE, MATURITY_DATE, EURIBOR3M.getTenor(), NOTIONAL, EURIBOR3M, IS_PAYER_SPREAD, EURIBOR3M.getDayCount(), EURIBOR3M.getBusinessDayConvention(), EURIBOR3M.isEndOfMonth(), TARGET, STUB, 0); LEGS_DEFINITION[2] = AnnuityDefinitionBuilder.couponIbor( SETTLEMENT_DATE, MATURITY_DATE, EURIBOR6M.getTenor(), NOTIONAL, EURIBOR6M, !IS_PAYER_SPREAD, EURIBOR6M.getDayCount(), EURIBOR6M.getBusinessDayConvention(), EURIBOR6M.isEndOfMonth(), TARGET, STUB, 0); }
/** * Tests related to the pricing of CMS coupons with Hull-White (extended Vasicek) model and * different numerical methods. */ public class CouponCMSHullWhiteMethodsTest { private static final Calendar TARGET = new MondayToFridayCalendar("TARGET"); private static final GeneratorSwapFixedIborMaster GENERATOR_SWAP_MASTER = GeneratorSwapFixedIborMaster.getInstance(); private static final GeneratorSwapFixedIbor GENERATOR_EUR1YEURIBOR6M = GENERATOR_SWAP_MASTER.getGenerator("EUR1YEURIBOR6M", TARGET); private static final Period TENOR_SWAP = Period.ofYears(10); private static final IndexSwap SWAP_EUR10Y = new IndexSwap(GENERATOR_EUR1YEURIBOR6M, TENOR_SWAP); private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2012, 1, 17); // Coupon CMS: 6m fixing in advance (payment in arrears); ACT/360 private static final Period TENOR_COUPON = Period.ofMonths(6); private static final Period TENOR_FIXING = Period.ofMonths(60); private static final DayCount ACT360 = DayCountFactory.INSTANCE.getDayCount("Actual/360"); private static final ZonedDateTime FIXING_DATE = ScheduleCalculator.getAdjustedDate( REFERENCE_DATE, TENOR_FIXING, GENERATOR_EUR1YEURIBOR6M.getBusinessDayConvention(), TARGET, GENERATOR_EUR1YEURIBOR6M.isEndOfMonth()); private static final ZonedDateTime START_DATE = ScheduleCalculator.getAdjustedDate( FIXING_DATE, GENERATOR_EUR1YEURIBOR6M.getSpotLag(), TARGET); private static final ZonedDateTime PAYMENT_DATE = ScheduleCalculator.getAdjustedDate( START_DATE, TENOR_COUPON, GENERATOR_EUR1YEURIBOR6M.getBusinessDayConvention(), TARGET, GENERATOR_EUR1YEURIBOR6M.isEndOfMonth()); private static final double NOTIONAL = 100000000; // 100m private static final double ACCRUAL_FACTOR = ACT360.getDayCountFraction(START_DATE, PAYMENT_DATE); private static final CouponCMSDefinition CPN_CMS_DEFINITION = CouponCMSDefinition.from( PAYMENT_DATE, START_DATE, PAYMENT_DATE, ACCRUAL_FACTOR, NOTIONAL, SWAP_EUR10Y); private static final YieldCurveBundle CURVES = TestsDataSetsSABR.createCurves2(); private static final String[] CURVE_NAMES = TestsDataSetsSABR.curves2Names(); private static final HullWhiteOneFactorPiecewiseConstantParameters PARAMETERS_HW = TestsDataSetHullWhite.createHullWhiteParameters(); private static final HullWhiteOneFactorPiecewiseConstantDataBundle BUNDLE_HW = new HullWhiteOneFactorPiecewiseConstantDataBundle(PARAMETERS_HW, CURVES); private static final CouponCMS CPN_CMS = (CouponCMS) CPN_CMS_DEFINITION.toDerivative( REFERENCE_DATE, new String[] {CURVE_NAMES[0], CURVE_NAMES[2]}); private static final CouponCMSHullWhiteNumericalIntegrationMethod METHOD_NI = CouponCMSHullWhiteNumericalIntegrationMethod.getInstance(); private static final CouponCMSHullWhiteApproximationMethod METHOD_APP = CouponCMSHullWhiteApproximationMethod.getInstance(); private static final CouponCMSDiscountingMethod METHOD_DSC = CouponCMSDiscountingMethod.getInstance(); private static final double TOLERANCE_PRICE = 1.0E-2; private static final double TOLERANCE_PRICE_APP = 5.0E+0; @Test public void presentValueNumericalIntegration() { CurrencyAmount pvNumericalIntegration = METHOD_NI.presentValue(CPN_CMS, BUNDLE_HW); double pvPrevious = 1124760.482; // From previous run assertEquals( "Coupon CMS - Hull-White - present value - numerical integration", pvPrevious, pvNumericalIntegration.getAmount(), TOLERANCE_PRICE); // Comparison with non-adjusted figures: to have the right order of magnitude CurrencyAmount pvDiscounting = METHOD_DSC.presentValue(CPN_CMS, BUNDLE_HW); assertEquals( "Coupon CMS - Hull-White - present value - numerical integration", 1.0, pvDiscounting.getAmount() / pvNumericalIntegration.getAmount(), 0.20); } @Test public void presentValueApproximation() { CurrencyAmount pvNumericalIntegration = METHOD_NI.presentValue(CPN_CMS, BUNDLE_HW); CurrencyAmount pvApproximation = METHOD_APP.presentValue(CPN_CMS, BUNDLE_HW); assertEquals( "Coupon CMS - Hull-White - present value - approximation", pvApproximation.getAmount(), pvNumericalIntegration.getAmount(), TOLERANCE_PRICE_APP); } }
public class SwaptionPhysicalFixedIborBlackMethodTest { private static final MulticurveProviderDiscount MULTICURVES = MulticurveProviderDiscountDataSets.createMulticurveEurUsd(); private static final IborIndex EURIBOR6M = MulticurveProviderDiscountDataSets.getIndexesIborMulticurveEurUsd()[1]; private static final Calendar CALENDAR = MulticurveProviderDiscountDataSets.getEURCalendar(); private static final Currency EUR = EURIBOR6M.getCurrency(); // Data private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2012, 1, 10); private static final GeneratorSwapFixedIborMaster GENERATOR_SWAP_MASTER = GeneratorSwapFixedIborMaster.getInstance(); private static final GeneratorSwapFixedIbor GENERATOR_EUR1YEURIBOR6M = GENERATOR_SWAP_MASTER.getGenerator("EUR1YEURIBOR6M", CALENDAR); private static final BlackFlatSwaptionParameters BLACK = BlackDataSets.createBlackSwaptionEUR6(); private static final BlackSwaptionFlatProviderDiscount BLACK_MULTICURVES = new BlackSwaptionFlatProviderDiscount(MULTICURVES, BLACK); // Swaption private static final Period EXPIRY_TENOR = Period.ofMonths(26); // To be between nodes. private static final ZonedDateTime EXPIRY_DATE = ScheduleCalculator.getAdjustedDate( REFERENCE_DATE, EXPIRY_TENOR, GENERATOR_EUR1YEURIBOR6M.getBusinessDayConvention(), CALENDAR, GENERATOR_EUR1YEURIBOR6M.isEndOfMonth()); private static final ZonedDateTime SETTLE_DATE = ScheduleCalculator.getAdjustedDate( EXPIRY_DATE, GENERATOR_EUR1YEURIBOR6M.getSpotLag(), CALENDAR); private static final int SWAP_TENOR_YEAR = 5; private static final Period SWAP_TENOR = Period.ofYears(SWAP_TENOR_YEAR); private static final double NOTIONAL = 123456789.0; private static final double RATE = 0.02; private static final SwapFixedIborDefinition SWAP_DEFINITION_REC = SwapFixedIborDefinition.from( SETTLE_DATE, SWAP_TENOR, GENERATOR_EUR1YEURIBOR6M, NOTIONAL, RATE, false); private static final SwaptionPhysicalFixedIborDefinition SWAPTION_DEFINITION_LONG_REC = SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, SWAP_DEFINITION_REC, true); private static final SwaptionPhysicalFixedIbor SWAPTION_LONG_REC = SWAPTION_DEFINITION_LONG_REC.toDerivative(REFERENCE_DATE); // Method - calculator private static final double TOLERANCE_PV = 1.0E-2; private static final double TOLERANCE_PV_DELTA = 1.0E+2; // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. private static final SwaptionPhysicalFixedIborBlackMethod METHOD_BLACK = SwaptionPhysicalFixedIborBlackMethod.getInstance(); private static final SwapFixedCouponDiscountingMethod METHOD_SWAP = SwapFixedCouponDiscountingMethod.getInstance(); private static final ParRateDiscountingCalculator PRDC = ParRateDiscountingCalculator.getInstance(); private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance(); private static final PresentValueBlackSwaptionCalculator PVBSC = PresentValueBlackSwaptionCalculator.getInstance(); private static final PresentValueCurveSensitivityBlackSwaptionCalculator PVCSBSC = PresentValueCurveSensitivityBlackSwaptionCalculator.getInstance(); private static final PresentValueBlackSensitivityBlackSwaptionCalculator PVBSSBSC = PresentValueBlackSensitivityBlackSwaptionCalculator.getInstance(); private static final double SHIFT = 1.0E-6; private static final ParameterSensitivityParameterCalculator<BlackSwaptionFlatProviderInterface> PS_BS_C = new ParameterSensitivityParameterCalculator<>(PVCSBSC); private static final ParameterSensitivityBlackSwaptionDiscountInterpolatedFDCalculator PS_BS_FDC = new ParameterSensitivityBlackSwaptionDiscountInterpolatedFDCalculator(PVBSC, SHIFT); private static final BlackSwaptionSensitivityNodeCalculator BSSNC = new BlackSwaptionSensitivityNodeCalculator(); @Test public void presentValue() { final MultipleCurrencyAmount pvMethod = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, BLACK_MULTICURVES); final double forward = SWAPTION_LONG_REC.getUnderlyingSwap().accept(PRDC, MULTICURVES); final double pvbp = METHOD_SWAP.presentValueBasisPoint(SWAPTION_LONG_REC.getUnderlyingSwap(), MULTICURVES); final double volatility = BLACK.getVolatility( SWAPTION_LONG_REC.getTimeToExpiry(), SWAPTION_LONG_REC.getMaturityTime()); final BlackPriceFunction blackFunction = new BlackPriceFunction(); final BlackFunctionData dataBlack = new BlackFunctionData(forward, pvbp, volatility); final Function1D<BlackFunctionData, Double> func = blackFunction.getPriceFunction(SWAPTION_LONG_REC); final double pvExpected = func.evaluate(dataBlack); assertEquals( "Swaption Black method: present value", pvExpected, pvMethod.getAmount(EUR), TOLERANCE_PV); } @Test /** Tests the payer/receiver parity for swaptions present value. */ public void presentValuePayerReceiverParity() { final SwapFixedIborDefinition swapDefinitionPay = SwapFixedIborDefinition.from( SETTLE_DATE, SWAP_TENOR, GENERATOR_EUR1YEURIBOR6M, NOTIONAL, RATE, true); final SwaptionPhysicalFixedIborDefinition swaptionDefinitionShortPayer = SwaptionPhysicalFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPay, false); final SwaptionPhysicalFixedIbor swaptionShortPayer = swaptionDefinitionShortPayer.toDerivative(REFERENCE_DATE); final InstrumentDerivative swapRec = SWAP_DEFINITION_REC.toDerivative(REFERENCE_DATE); final MultipleCurrencyAmount pvLR = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, BLACK_MULTICURVES); final MultipleCurrencyAmount pvSP = METHOD_BLACK.presentValue(swaptionShortPayer, BLACK_MULTICURVES); final MultipleCurrencyAmount pvSwap = swapRec.accept(PVDC, MULTICURVES); assertEquals( "Swaption Black method: present value", pvSwap.getAmount(EUR), pvLR.getAmount(EUR) + pvSP.getAmount(EUR), TOLERANCE_PV); } @Test /** Compare the method figures to the Calculator figures. */ public void presentValueMethodVsCalculator() { final MultipleCurrencyAmount pvMethod = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, BLACK_MULTICURVES); final MultipleCurrencyAmount pvCalculator = SWAPTION_LONG_REC.accept(PVBSC, BLACK_MULTICURVES); assertEquals( "Swaption Black method: present value", pvCalculator.getAmount(EUR), pvMethod.getAmount(EUR), TOLERANCE_PV); } @Test /** Tests the curve sensitivity for the explicit formula. */ public void presentValueCurveSensitivity() { final MultipleCurrencyParameterSensitivity pvpsExact = PS_BS_C.calculateSensitivity( SWAPTION_LONG_REC, BLACK_MULTICURVES, BLACK_MULTICURVES.getMulticurveProvider().getAllNames()); final MultipleCurrencyParameterSensitivity pvpsFD = PS_BS_FDC.calculateSensitivity(SWAPTION_LONG_REC, BLACK_MULTICURVES); AssertSensivityObjects.assertEquals( "Swaption Black method: presentValueCurveSensitivity ", pvpsExact, pvpsFD, TOLERANCE_PV_DELTA); } @Test /** Compare the method figures to the Calculator figures. */ public void presentValueCurveSensitivityMethodVsCalculator() { final MultipleCurrencyMulticurveSensitivity pvcsMethod = METHOD_BLACK.presentValueCurveSensitivity(SWAPTION_LONG_REC, BLACK_MULTICURVES); final MultipleCurrencyMulticurveSensitivity pvcsCalculator = SWAPTION_LONG_REC.accept(PVCSBSC, BLACK_MULTICURVES); AssertSensivityObjects.assertEquals( "Swaption Black method: present value", pvcsMethod, pvcsCalculator, TOLERANCE_PV_DELTA); } @Test /** Tests the Black volatility sensitivity (vega). */ public void presentValueBlackSensitivity() { final double shift = 1.0E-6; final PresentValueBlackSwaptionSensitivity pvbvs = METHOD_BLACK.presentValueBlackSensitivity(SWAPTION_LONG_REC, BLACK_MULTICURVES); final BlackFlatSwaptionParameters BlackP = BlackDataSets.createBlackSwaptionEUR6Shift(shift); final BlackSwaptionFlatProviderDiscount curvesBlackP = new BlackSwaptionFlatProviderDiscount(MULTICURVES, BlackP); final MultipleCurrencyAmount pvP = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, curvesBlackP); final BlackFlatSwaptionParameters BlackM = BlackDataSets.createBlackSwaptionEUR6Shift(-shift); final BlackSwaptionFlatProviderDiscount curvesBlackM = new BlackSwaptionFlatProviderDiscount(MULTICURVES, BlackM); final MultipleCurrencyAmount pvM = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, curvesBlackM); final DoublesPair point = new DoublesPair(SWAPTION_LONG_REC.getTimeToExpiry(), SWAPTION_LONG_REC.getMaturityTime()); assertEquals( "Swaption Black method: present value volatility sensitivity", (pvP.getAmount(EUR) - pvM.getAmount(EUR)) / (2 * shift), pvbvs.getSensitivity().getMap().get(point), TOLERANCE_PV_DELTA); } @Test /** Tests the Black volatility sensitivity (vega). */ public void presentValueBlackSensitivityMethodVsCalculator() { final PresentValueBlackSwaptionSensitivity pvbsMethod = METHOD_BLACK.presentValueBlackSensitivity(SWAPTION_LONG_REC, BLACK_MULTICURVES); final PresentValueBlackSwaptionSensitivity pvbsCalculator = SWAPTION_LONG_REC.accept(PVBSSBSC, BLACK_MULTICURVES); assertEquals("Swaption Black method: present value", pvbsMethod, pvbsCalculator); } @Test /** Tests the Black volatility sensitivity (vega). */ public void presentValueBlackNodeSensitivity() { final double shift = 1.0E-6; final PresentValueBlackSwaptionSensitivity pvbvs = METHOD_BLACK.presentValueBlackSensitivity(SWAPTION_LONG_REC, BLACK_MULTICURVES); final PresentValueBlackSwaptionSensitivity pvbns = BSSNC.calculateNodeSensitivities(pvbvs, BLACK); final double[] x = ((InterpolatedDoublesSurface) BLACK.getVolatilitySurface()).getXDataAsPrimitive(); final double[] y = ((InterpolatedDoublesSurface) BLACK.getVolatilitySurface()).getYDataAsPrimitive(); for (int loopindex = 0; loopindex < x.length; loopindex++) { final BlackFlatSwaptionParameters BlackP = BlackDataSets.createBlackSwaptionEUR6Shift(loopindex, shift); final BlackSwaptionFlatProviderDiscount curvesBlackP = new BlackSwaptionFlatProviderDiscount(MULTICURVES, BlackP); final MultipleCurrencyAmount pvP = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, curvesBlackP); final BlackFlatSwaptionParameters BlackM = BlackDataSets.createBlackSwaptionEUR6Shift(loopindex, -shift); final BlackSwaptionFlatProviderDiscount curvesBlackM = new BlackSwaptionFlatProviderDiscount(MULTICURVES, BlackM); final MultipleCurrencyAmount pvM = METHOD_BLACK.presentValue(SWAPTION_LONG_REC, curvesBlackM); assertEquals( "Swaption Black method: present value volatility sensitivity", (pvP.getAmount(EUR) - pvM.getAmount(EUR)) / (2 * shift), pvbns.getSensitivity().getMap().get(new DoublesPair(x[loopindex], y[loopindex])), TOLERANCE_PV_DELTA); } } }