public virtual void test_recovery_black_fixedRho() { SabrIborCapletFloorletVolatilityBootstrapDefinition definition = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, 0.0, CurveInterpolators.STEP_UPPER, CurveExtrapolators.FLAT, CurveExtrapolators.FLAT, SabrHaganVolatilityFunctionProvider.DEFAULT); DoubleMatrix volData = createFullBlackDataMatrix(); double errorValue = 1.0e-3; DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), errorValue); RawOptionData data = RawOptionData.of(createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, volData, error, ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities)res.Volatilities; double expSq = 0d; for (int i = 0; i < NUM_BLACK_STRIKES; ++i) { Pair <IList <ResolvedIborCapFloorLeg>, IList <double> > capsAndVols = getCapsBlackVols(i); IList <ResolvedIborCapFloorLeg> caps = capsAndVols.First; IList <double> vols = capsAndVols.Second; int nCaps = caps.Count; for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of(Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols[j]); BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_BLACK.presentValue(caps[j], RATES_PROVIDER, constVol).Amount; double priceCalib = LEG_PRICER_SABR.presentValue(caps[j], RATES_PROVIDER, resVols).Amount; expSq += Math.Pow((priceOrg - priceCalib) / priceOrg / errorValue, 2); assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL * 3d); } } assertEquals(res.ChiSquare, expSq, expSq * 1.0e-14); assertEquals(resVols.Index, USD_LIBOR_3M); assertEquals(resVols.Name, definition.Name); assertEquals(resVols.ValuationDateTime, CALIBRATION_TIME); assertEquals(resVols.Parameters.ShiftCurve, definition.ShiftCurve); assertEquals(resVols.Parameters.RhoCurve, definition.RhoCurve.get()); }
public virtual void test_recovery_normal_fixedRho() { SabrIborCapletFloorletVolatilityBootstrapDefinition definition = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedRho(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, 0.0, CurveInterpolators.LINEAR, CurveExtrapolators.FLAT, CurveExtrapolators.FLAT, SabrHaganVolatilityFunctionProvider.DEFAULT); RawOptionData data = RawOptionData.of(createNormalEquivMaturities(), createNormalEquivStrikes(), ValueType.STRIKE, createFullNormalEquivDataMatrix(), ValueType.NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities)res.Volatilities; for (int i = 1; i < NUM_BLACK_STRIKES; ++i) { Pair <IList <ResolvedIborCapFloorLeg>, IList <double> > capsAndVols = getCapsNormalEquivVols(i); IList <ResolvedIborCapFloorLeg> caps = capsAndVols.First; IList <double> vols = capsAndVols.Second; int nCaps = caps.Count; for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of(Surfaces.normalVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols[j]); NormalIborCapletFloorletExpiryStrikeVolatilities constVol = NormalIborCapletFloorletExpiryStrikeVolatilities.of(USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_NORMAL.presentValue(caps[j], RATES_PROVIDER, constVol).Amount; double priceCalib = LEG_PRICER_SABR.presentValue(caps[j], RATES_PROVIDER, resVols).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL * 3d); } } assertTrue(res.ChiSquare > 0d); assertEquals(resVols.Index, USD_LIBOR_3M); assertEquals(resVols.Name, definition.Name); assertEquals(resVols.ValuationDateTime, CALIBRATION_TIME); }
public virtual void test_invalid_data() { SabrIborCapletFloorletVolatilityBootstrapDefinition definition = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, 0.85, CurveInterpolators.LINEAR, CurveExtrapolators.FLAT, CurveExtrapolators.FLAT, SabrHaganVolatilityFunctionProvider.DEFAULT); RawOptionData data = RawOptionData.of(createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, createFullBlackDataMatrixInvalid(), ValueType.BLACK_VOLATILITY); assertThrowsIllegalArg(() => CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER)); }
public virtual void test_createSabrParameterMetadata() { SabrIborCapletFloorletVolatilityBootstrapDefinition @base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); ImmutableList <CurveMetadata> expected = ImmutableList.of(Curves.sabrParameterByExpiry(NAME.Name + "-Alpha", ACT_ACT_ISDA, SABR_ALPHA), Curves.sabrParameterByExpiry(NAME.Name + "-Beta", ACT_ACT_ISDA, SABR_BETA), Curves.sabrParameterByExpiry(NAME.Name + "-Rho", ACT_ACT_ISDA, SABR_RHO), Curves.sabrParameterByExpiry(NAME.Name + "-Nu", ACT_ACT_ISDA, SABR_NU)); ImmutableList <CurveMetadata> computed = @base.createSabrParameterMetadata(); assertEquals(computed, expected); }
//------------------------------------------------------------------------- public virtual void coverage() { SabrIborCapletFloorletVolatilityBootstrapDefinition test1 = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); coverImmutableBean(test1); SabrIborCapletFloorletVolatilityBootstrapDefinition test2 = SabrIborCapletFloorletVolatilityBootstrapDefinition.builder().index(GBP_LIBOR_3M).name(IborCapletFloorletVolatilitiesName.of("other")).interpolator(STEP_UPPER).extrapolatorLeft(FLAT).extrapolatorRight(CurveExtrapolators.LINEAR).rhoCurve(ConstantCurve.of("rho", 0.1d)).shiftCurve(ConstantCurve.of("shift", 0.01d)).dayCount(ACT_365F).sabrVolatilityFormula(SabrVolatilityFormula.hagan()).build(); coverBeanEquals(test1, test2); }
public virtual void test_createMetadata_wrongValueType() { SabrIborCapletFloorletVolatilityBootstrapDefinition @base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); RawOptionData capData = RawOptionData.of(ImmutableList.of(Period.ofYears(1), Period.ofYears(5)), DoubleArray.of(0.005, 0.01, 0.015), ValueType.STRIKE, DoubleMatrix.copyOf(new double[][] { new double[] { 0.15, 0.12, 0.13 }, new double[] { 0.1, 0.08, 0.09 } }), ValueType.PRICE); assertThrowsIllegalArg(() => @base.createMetadata(capData)); }
public virtual void test_createCap() { SabrIborCapletFloorletVolatilityBootstrapDefinition @base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, STEP_UPPER, FLAT, FLAT, SabrVolatilityFormula.hagan()); LocalDate startDate = LocalDate.of(2012, 4, 20); LocalDate endDate = LocalDate.of(2017, 4, 20); double strike = 0.01; IborCapFloorLeg expected = IborCapFloorLeg.builder().calculation(IborRateCalculation.of(USD_LIBOR_3M)).capSchedule(ValueSchedule.of(strike)).currency(USD_LIBOR_3M.Currency).notional(ValueSchedule.ALWAYS_1).paymentDateOffset(DaysAdjustment.NONE).paymentSchedule(PeriodicSchedule.of(startDate, endDate, Frequency.of(USD_LIBOR_3M.Tenor.Period), BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, USD_LIBOR_3M.FixingCalendar), StubConvention.NONE, RollConventions.NONE)).payReceive(PayReceive.RECEIVE).build(); IborCapFloorLeg computed = @base.createCap(startDate, endDate, strike); assertEquals(computed, expected); }
public virtual void test_createMetadata_black() { SabrIborCapletFloorletVolatilityBootstrapDefinition @base = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); RawOptionData capData = RawOptionData.of(ImmutableList.of(Period.ofYears(1), Period.ofYears(5)), DoubleArray.of(0.005, 0.01, 0.015), ValueType.STRIKE, DoubleMatrix.copyOf(new double[][] { new double[] { 0.15, 0.12, 0.13 }, new double[] { 0.1, 0.08, 0.09 } }), ValueType.BLACK_VOLATILITY); SurfaceMetadata expected = Surfaces.blackVolatilityByExpiryStrike(NAME.Name, ACT_ACT_ISDA); SurfaceMetadata computed = @base.createMetadata(capData); assertEquals(computed, expected); }
public virtual void test_ofFixedBeta_shift() { SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, 0.01, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); assertEquals(test.DayCount, ACT_ACT_ISDA); assertEquals(test.Index, USD_LIBOR_3M); assertEquals(test.Interpolator, LINEAR); assertEquals(test.ExtrapolatorLeft, FLAT); assertEquals(test.ExtrapolatorRight, FLAT); assertEquals(test.Name, NAME); assertEquals(test.BetaCurve.get(), ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.Name + "-Beta", ACT_ACT_ISDA, SABR_BETA), 0.5)); assertFalse(test.RhoCurve.Present); assertEquals(test.SabrVolatilityFormula, SabrVolatilityFormula.hagan()); assertEquals(test.ShiftCurve, ConstantCurve.of("Shift curve", 0.01)); }
public virtual void test_builder() { Curve betaCurve = ConstantCurve.of(Curves.sabrParameterByExpiry(NAME.Name + "-Beta", ACT_ACT_ISDA, SABR_BETA), 0.65); SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.builder().index(USD_LIBOR_3M).name(NAME).interpolator(LINEAR).extrapolatorLeft(FLAT).extrapolatorRight(CurveExtrapolators.LINEAR).dayCount(ACT_ACT_ISDA).sabrVolatilityFormula(SabrVolatilityFormula.hagan()).betaCurve(betaCurve).build(); assertEquals(test.DayCount, ACT_ACT_ISDA); assertEquals(test.Index, USD_LIBOR_3M); assertEquals(test.Interpolator, LINEAR); assertEquals(test.ExtrapolatorLeft, FLAT); assertEquals(test.ExtrapolatorRight, CurveExtrapolators.LINEAR); assertEquals(test.Name, NAME); assertEquals(test.BetaCurve.get(), betaCurve); assertFalse(test.RhoCurve.Present); assertEquals(test.SabrVolatilityFormula, SabrVolatilityFormula.hagan()); assertEquals(test.ShiftCurve, ConstantCurve.of("Zero shift", 0d)); }
public virtual void test_recovery_flatVol() { double beta = 0.8; SabrIborCapletFloorletVolatilityBootstrapDefinition definition = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, beta, CurveInterpolators.STEP_UPPER, CurveExtrapolators.FLAT, CurveExtrapolators.FLAT, SabrHaganVolatilityFunctionProvider.DEFAULT); RawOptionData data = RawOptionData.of(createBlackMaturities(), createBlackStrikes(), ValueType.STRIKE, createFullFlatBlackDataMatrix(), ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); SabrParametersIborCapletFloorletVolatilities resVols = (SabrParametersIborCapletFloorletVolatilities)res.Volatilities; for (int i = 0; i < NUM_BLACK_STRIKES; ++i) { Pair <IList <ResolvedIborCapFloorLeg>, IList <double> > capsAndVols = getCapsFlatBlackVols(i); IList <ResolvedIborCapFloorLeg> caps = capsAndVols.First; IList <double> vols = capsAndVols.Second; int nCaps = caps.Count; for (int j = 0; j < nCaps; ++j) { ConstantSurface volSurface = ConstantSurface.of(Surfaces.blackVolatilityByExpiryStrike("test", ACT_ACT_ISDA), vols[j]); BlackIborCapletFloorletExpiryStrikeVolatilities constVol = BlackIborCapletFloorletExpiryStrikeVolatilities.of(USD_LIBOR_3M, CALIBRATION_TIME, volSurface); double priceOrg = LEG_PRICER_BLACK.presentValue(caps[j], RATES_PROVIDER, constVol).Amount; double priceCalib = LEG_PRICER_SABR.presentValue(caps[j], RATES_PROVIDER, resVols).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } }
//------------------------------------------------------------------------- public override IborCapletFloorletVolatilityCalibrationResult calibrate(IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData, RatesProvider ratesProvider) { ArgChecker.isTrue(ratesProvider.ValuationDate.Equals(calibrationDateTime.toLocalDate()), "valuationDate of ratesProvider should be coherent to calibrationDateTime"); ArgChecker.isTrue(definition is SabrIborCapletFloorletVolatilityBootstrapDefinition, "definition should be SabrIborCapletFloorletVolatilityBootstrapDefinition"); SabrIborCapletFloorletVolatilityBootstrapDefinition bsDefinition = (SabrIborCapletFloorletVolatilityBootstrapDefinition)definition; IborIndex index = bsDefinition.Index; LocalDate calibrationDate = calibrationDateTime.toLocalDate(); LocalDate baseDate = index.EffectiveDateOffset.adjust(calibrationDate, ReferenceData); LocalDate startDate = baseDate.plus(index.Tenor); System.Func <Surface, IborCapletFloorletVolatilities> volatilitiesFunction = this.volatilitiesFunction(bsDefinition, calibrationDateTime, capFloorData); SurfaceMetadata metaData = bsDefinition.createMetadata(capFloorData); IList <Period> expiries = capFloorData.Expiries; int nExpiries = expiries.Count; DoubleArray strikes = capFloorData.Strikes; DoubleMatrix errorsMatrix = capFloorData.Error.orElse(DoubleMatrix.filled(nExpiries, strikes.size(), 1d)); IList <double> timeList = new List <double>(); IList <double> strikeList = new List <double>(); IList <double> volList = new List <double>(); IList <ResolvedIborCapFloorLeg> capList = new List <ResolvedIborCapFloorLeg>(); IList <double> priceList = new List <double>(); IList <double> errorList = new List <double>(); int[] startIndex = new int[nExpiries + 1]; for (int i = 0; i < nExpiries; ++i) { LocalDate endDate = baseDate.plus(expiries[i]); DoubleArray volatilityData = capFloorData.Data.row(i); DoubleArray errors = errorsMatrix.row(i); reduceRawData(bsDefinition, ratesProvider, strikes, volatilityData, errors, startDate, endDate, metaData, volatilitiesFunction, timeList, strikeList, volList, capList, priceList, errorList); startIndex[i + 1] = volList.Count; ArgChecker.isTrue(startIndex[i + 1] > startIndex[i], "no valid option data for {}", expiries[i]); } IList <CurveMetadata> metadataList = bsDefinition.createSabrParameterMetadata(); DoubleArray timeToExpiries = DoubleArray.of(nExpiries, i => timeList[startIndex[i]]); BitArray @fixed = new BitArray(); bool betaFix = false; Curve betaCurve; Curve rhoCurve; if (bsDefinition.BetaCurve.Present) { betaFix = true; @fixed.Set(1, true); betaCurve = bsDefinition.BetaCurve.get(); rhoCurve = InterpolatedNodalCurve.of(metadataList[2], timeToExpiries, DoubleArray.filled(nExpiries), bsDefinition.Interpolator, bsDefinition.ExtrapolatorLeft, bsDefinition.ExtrapolatorRight); } else { @fixed.Set(2, true); betaCurve = InterpolatedNodalCurve.of(metadataList[1], timeToExpiries, DoubleArray.filled(nExpiries), bsDefinition.Interpolator, bsDefinition.ExtrapolatorLeft, bsDefinition.ExtrapolatorRight); rhoCurve = bsDefinition.RhoCurve.get(); } InterpolatedNodalCurve alphaCurve = InterpolatedNodalCurve.of(metadataList[0], timeToExpiries, DoubleArray.filled(nExpiries), bsDefinition.Interpolator, bsDefinition.ExtrapolatorLeft, bsDefinition.ExtrapolatorRight); InterpolatedNodalCurve nuCurve = InterpolatedNodalCurve.of(metadataList[3], timeToExpiries, DoubleArray.filled(nExpiries), bsDefinition.Interpolator, bsDefinition.ExtrapolatorLeft, bsDefinition.ExtrapolatorRight); Curve shiftCurve = bsDefinition.ShiftCurve; SabrParameters sabrParams = SabrParameters.of(alphaCurve, betaCurve, rhoCurve, nuCurve, shiftCurve, bsDefinition.SabrVolatilityFormula); SabrParametersIborCapletFloorletVolatilities vols = SabrParametersIborCapletFloorletVolatilities.of(bsDefinition.Name, index, calibrationDateTime, sabrParams); double totalChiSq = 0d; ZonedDateTime prevExpiry = calibrationDateTime.minusDays(1L); // included if calibrationDateTime == fixingDateTime for (int i = 0; i < nExpiries; ++i) { DoubleArray start = computeInitialValues(ratesProvider, betaCurve, shiftCurve, timeList, volList, capList, startIndex, i, betaFix, capFloorData.DataType); UncoupledParameterTransforms transform = new UncoupledParameterTransforms(start, TRANSFORMS, @fixed); int nCaplets = startIndex[i + 1] - startIndex[i]; int currentStart = startIndex[i]; System.Func <DoubleArray, DoubleArray> valueFunction = createPriceFunction(ratesProvider, vols, prevExpiry, capList, priceList, startIndex, nExpiries, i, nCaplets, betaFix); System.Func <DoubleArray, DoubleMatrix> jacobianFunction = createJacobianFunction(ratesProvider, vols, prevExpiry, capList, priceList, index.Currency, startIndex, nExpiries, i, nCaplets, betaFix); NonLinearTransformFunction transFunc = new NonLinearTransformFunction(valueFunction, jacobianFunction, transform); DoubleArray adjustedPrices = this.adjustedPrices(ratesProvider, vols, prevExpiry, capList, priceList, startIndex, i, nCaplets); DoubleArray errors = DoubleArray.of(nCaplets, n => errorList[currentStart + n]); LeastSquareResults res = solver.solve(adjustedPrices, errors, transFunc.FittingFunction, transFunc.FittingJacobian, transform.transform(start)); LeastSquareResultsWithTransform resTransform = new LeastSquareResultsWithTransform(res, transform); vols = updateParameters(vols, nExpiries, i, betaFix, resTransform.ModelParameters); totalChiSq += res.ChiSq; prevExpiry = capList[startIndex[i + 1] - 1].FinalFixingDateTime; } return(IborCapletFloorletVolatilityCalibrationResult.ofLeastSquare(vols, totalChiSq)); }
public virtual void test_serialization() { SabrIborCapletFloorletVolatilityBootstrapDefinition test = SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, LINEAR, FLAT, FLAT, SabrVolatilityFormula.hagan()); assertSerialization(test); }
//------------------------------------------------------------------------- public virtual void test_of_wrongInterpolator() { assertThrowsIllegalArg(() => SabrIborCapletFloorletVolatilityBootstrapDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, 0.5, DOUBLE_QUADRATIC, FLAT, FLAT, SabrVolatilityFormula.hagan())); }