public virtual void recovery_test_flat() { DoubleArray initial = DoubleArray.of(0.4, 0.95, 0.5, 0.05); SabrIborCapletFloorletVolatilityCalibrationDefinition definition = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, initial, LINEAR, FLAT, FLAT, HAGAN); DoubleArray strikes = createBlackStrikes(); RawOptionData data = RawOptionData.of(createBlackMaturities(), strikes, ValueType.STRIKE, createFullFlatBlackDataMatrix(), ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); SabrIborCapletFloorletVolatilities resVol = (SabrIborCapletFloorletVolatilities)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, resVol).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } }
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 SurfaceMetadata createMetadata(RawOptionData capFloorData) { IList <GenericVolatilitySurfacePeriodParameterMetadata> list = new List <GenericVolatilitySurfacePeriodParameterMetadata>(); ImmutableList <Period> expiries = capFloorData.Expiries; int nExpiries = expiries.size(); DoubleArray strikes = capFloorData.Strikes; int nStrikes = strikes.size(); for (int i = 0; i < nExpiries; ++i) { for (int j = 0; j < nStrikes; ++j) { if (Double.isFinite(capFloorData.Data.get(i, j))) { list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(expiries.get(i), SimpleStrike.of(strikes.get(j)))); } } } SurfaceMetadata metadata; if (capFloorData.DataType.Equals(ValueType.BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.Name, dayCount); } else if (capFloorData.DataType.Equals(ValueType.NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.Name, dayCount); } else { throw new System.ArgumentException("Data type not supported"); } return(metadata.withParameterMetadata(list)); }
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 recovery_test_shiftedBlack() { double lambdaT = 0.07; double lambdaK = 0.07; double error = 1.0e-5; ConstantCurve shiftCurve = ConstantCurve.of("Black shift", 0.02); DirectIborCapletFloorletVolatilityDefinition definition = DirectIborCapletFloorletVolatilityDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, lambdaT, lambdaK, INTERPOLATOR, shiftCurve); ImmutableList <Period> maturities = createBlackMaturities(); DoubleArray strikes = createBlackStrikes(); DoubleMatrix errorMatrix = DoubleMatrix.filled(maturities.size(), strikes.size(), error); RawOptionData data = RawOptionData.of(maturities, strikes, STRIKE, createFullBlackDataMatrix(), errorMatrix, BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities resVols = (ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; 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_BLACK.presentValue(caps[j], RATES_PROVIDER, resVols).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } assertTrue(res.ChiSquare > 0d); assertEquals(resVols.Index, USD_LIBOR_3M); assertEquals(resVols.Name, definition.Name); assertEquals(resVols.ValuationDateTime, CALIBRATION_TIME); assertEquals(resVols.ShiftCurve, definition.ShiftCurve.get()); }
public virtual void recovery_test_blackCurve() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR); DoubleArray strikes = createBlackStrikes(); for (int i = 0; i < strikes.size(); ++i) { Pair <IList <Period>, DoubleMatrix> trimedData = trimData(createBlackMaturities(), createBlackDataMatrixForStrike(i)); RawOptionData data = RawOptionData.of(trimedData.First, DoubleArray.of(strikes.get(i)), ValueType.STRIKE, trimedData.Second, ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); BlackIborCapletFloorletExpiryStrikeVolatilities resVol = (BlackIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; 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_BLACK.presentValue(caps[j], RATES_PROVIDER, resVol).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } }
public virtual void recovery_test_black_fixedRho() { double rho = 0.15; SabrIborCapletFloorletVolatilityCalibrationDefinition definition = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedRho(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, rho, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, DOUBLE_QUADRATIC, FLAT, FLAT, HAGAN); ImmutableList <Period> maturities = createBlackMaturities(); DoubleArray strikes = createBlackStrikes(); DoubleMatrix volData = createFullBlackDataMatrix(); DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), 1.0e-3); RawOptionData data = RawOptionData.of(maturities, strikes, ValueType.STRIKE, volData, error, 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 = 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; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL * 5d); } } assertEquals(resVols.Index, USD_LIBOR_3M); assertEquals(resVols.Name, definition.Name); assertEquals(resVols.ValuationDateTime, CALIBRATION_TIME); assertEquals(resVols.ParameterCount, ALPHA_KNOTS.size() + BETA_RHO_KNOTS.size() + NU_KNOTS.size() + 2); // beta, shift counted assertEquals(resVols.Parameters.ShiftCurve, definition.ShiftCurve); assertEquals(resVols.Parameters.RhoCurve, definition.RhoCurve.get()); }
public virtual void recovery_test_normal2_shift() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC, ConstantCurve.of("Black shift", 0.02)); DoubleArray strikes = createNormalEquivStrikes(); RawOptionData data = RawOptionData.of(createNormalEquivMaturities(), strikes, ValueType.STRIKE, createFullNormalEquivDataMatrix(), ValueType.NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities resVol = (ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; for (int i = 0; i < strikes.size(); ++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_BLACK.presentValue(caps[j], RATES_PROVIDER, resVol).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } assertEquals(res.ChiSquare, 0d); }
public virtual void recovery_test_blackSurface() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR); DoubleArray strikes = createBlackStrikes(); RawOptionData data = RawOptionData.of(createBlackMaturities(), strikes, ValueType.STRIKE, createFullBlackDataMatrix(), ValueType.BLACK_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); BlackIborCapletFloorletExpiryStrikeVolatilities resVol = (BlackIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; for (int i = 0; i < strikes.size(); ++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_BLACK.presentValue(caps[j], RATES_PROVIDER, resVol).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } assertEquals(res.ChiSquare, 0d); assertEquals(resVol.Index, USD_LIBOR_3M); assertEquals(resVol.Name, definition.Name); assertEquals(resVol.ValuationDateTime, CALIBRATION_TIME); InterpolatedNodalSurface surface = (InterpolatedNodalSurface)resVol.Surface; for (int i = 0; i < surface.ParameterCount; ++i) { GenericVolatilitySurfacePeriodParameterMetadata metadata = (GenericVolatilitySurfacePeriodParameterMetadata)surface.getParameterMetadata(i); assertEquals(metadata.Strike.Value, surface.YValues.get(i)); } }
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 recovery_test_normal() { double lambdaT = 0.07; double lambdaK = 0.07; double error = 1.0e-5; DirectIborCapletFloorletVolatilityDefinition definition = DirectIborCapletFloorletVolatilityDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, lambdaT, lambdaK, INTERPOLATOR); ImmutableList <Period> maturities = createNormalMaturities(); DoubleArray strikes = createNormalStrikes(); DoubleMatrix errorMatrix = DoubleMatrix.filled(maturities.size(), strikes.size(), error); RawOptionData data = RawOptionData.of(maturities, strikes, STRIKE, createFullNormalDataMatrix(), errorMatrix, NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); NormalIborCapletFloorletExpiryStrikeVolatilities resVol = (NormalIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; for (int i = 0; i < strikes.size(); ++i) { Pair <IList <ResolvedIborCapFloorLeg>, IList <double> > capsAndVols = getCapsNormalVols(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_NORMAL.presentValue(caps[j], RATES_PROVIDER, resVol).Amount; assertEquals(priceOrg, priceCalib, Math.Max(priceOrg, 1d) * TOL); } } }
public virtual void recovery_test_normal_shift_fixedRho() { double shift = 0.02; DoubleArray initial = DoubleArray.of(0.05, 0.35, 0.0, 0.9); SabrIborCapletFloorletVolatilityCalibrationDefinition definition = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedRho(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, shift, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, initial, DOUBLE_QUADRATIC, FLAT, FLAT, HAGAN); ImmutableList <Period> maturities = createNormalEquivMaturities(); DoubleArray strikes = createNormalEquivStrikes(); DoubleMatrix volData = createFullNormalEquivDataMatrix(); DoubleMatrix error = DoubleMatrix.filled(volData.rowCount(), volData.columnCount(), 1.0e-3); RawOptionData data = RawOptionData.of(maturities, strikes, ValueType.STRIKE, volData, error, ValueType.NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); SabrIborCapletFloorletVolatilities resVols = (SabrIborCapletFloorletVolatilities)res.Volatilities; for (int i = 0; i < strikes.size(); ++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 * 5d); } } }
public virtual void test_createMetadata() { SabrIborCapletFloorletVolatilityCalibrationDefinition @base = SabrIborCapletFloorletVolatilityCalibrationDefinition.ofFixedBeta(NAME, USD_LIBOR_3M, ACT_365F, BETA_RHO, ALPHA_KNOTS, BETA_RHO_KNOTS, NU_KNOTS, DOUBLE_QUADRATIC, FLAT, LINEAR, HAGAN); assertEquals(@base.createMetadata(SAMPLE_BLACK), Surfaces.blackVolatilityByExpiryStrike(NAME.Name, ACT_365F)); assertEquals(@base.createMetadata(SAMPLE_NORMAL), Surfaces.normalVolatilityByExpiryStrike(NAME.Name, ACT_365F)); assertThrowsIllegalArg(() => @base.createMetadata(RawOptionData.of(EXPIRIES, STRIKES, STRIKE, DATA, ValueType.PRICE))); }
public virtual void test_invalid_data() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition definition = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(IborCapletFloorletVolatilitiesName.of("test"), USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, LINEAR); DoubleArray strikes = createBlackStrikes(); RawOptionData data = RawOptionData.of(createBlackMaturities(), strikes, ValueType.STRIKE, createFullBlackDataMatrixInvalid(), ValueType.BLACK_VOLATILITY); assertThrowsIllegalArg(() => CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER)); }
/// <summary> /// Create a <seealso cref="RawOptionData"/> object for calibration from data. /// </summary> /// <param name="tenors"> the list of tenors </param> /// <param name="expiries"> the list of expiries </param> /// <param name="strikeLikeType"> the type of the strike-like dimension </param> /// <param name="strikeLikeData"> the data related to the strike-like dimension </param> /// <param name="dataType"> the type of the data </param> /// <param name="dataArray"> the array with the raw data, including potential Double.NaN for missing data. </param> /// <returns> the raw option data object </returns> public static TenorRawOptionData rawData(IList <Tenor> tenors, IList <Period> expiries, ValueType strikeLikeType, DoubleArray strikeLikeData, ValueType dataType, double[][][] dataArray) { IDictionary <Tenor, RawOptionData> raw = new SortedDictionary <Tenor, RawOptionData>(); for (int looptenor = 0; looptenor < dataArray.Length; looptenor++) { DoubleMatrix matrix = DoubleMatrix.ofUnsafe(dataArray[looptenor]); raw[tenors[looptenor]] = RawOptionData.of(expiries, strikeLikeData, strikeLikeType, matrix, dataType); } return(TenorRawOptionData.of(raw)); }
private static TenorRawOptionData rawData(double[][][] dataArray) { IDictionary <Tenor, RawOptionData> raw = new SortedDictionary <Tenor, RawOptionData>(); for (int looptenor = 0; looptenor < dataArray.Length; looptenor++) { DoubleMatrix matrix = DoubleMatrix.ofUnsafe(dataArray[looptenor]); raw[TENORS.get(looptenor)] = RawOptionData.of(EXPIRIES, MONEYNESS, SIMPLE_MONEYNESS, matrix, NORMAL_VOLATILITY); } return(TenorRawOptionData.of(raw)); }
public virtual void test_createMetadata_wrongValueType() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition @base = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC); 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)); }
/// <summary> /// Create a <seealso cref="RawOptionData"/> object for calibration from data and shift one point. /// </summary> /// <param name="tenors"> the list of tenors </param> /// <param name="expiries"> the list of expiries </param> /// <param name="strikeLikeType"> the type of the strike-like dimension </param> /// <param name="strikeLikeData"> the data related to the strike-like dimension </param> /// <param name="dataType"> the type of the data </param> /// <param name="dataArray"> the array with the raw data, including potential Double.NaN for missing data. </param> /// <param name="i"> the index of the tenor to shift </param> /// <param name="j"> the index of the expiry to shift </param> /// <param name="k"> the index of the strike-like dimension to shift </param> /// <param name="shift"> the size of the shift </param> /// <returns> the raw option data object </returns> public static TenorRawOptionData rawDataShiftPoint(IList <Tenor> tenors, IList <Period> expiries, ValueType strikeLikeType, DoubleArray strikeLikeData, ValueType dataType, double[][][] dataArray, int i, int j, int k, double shift) { IDictionary <Tenor, RawOptionData> raw = new SortedDictionary <Tenor, RawOptionData>(); for (int looptenor = 0; looptenor < dataArray.Length; looptenor++) { double[][] shiftedData = java.util.dataArray[looptenor].Select(row => row.clone()).ToArray(l => new double[l][]); // deep copy of 2d array if (looptenor == i) { shiftedData[j][k] += shift; } DoubleMatrix matrix = DoubleMatrix.ofUnsafe(shiftedData); raw[tenors[looptenor]] = RawOptionData.of(expiries, strikeLikeData, strikeLikeType, matrix, dataType); } return(TenorRawOptionData.of(raw)); }
//------------------------------------------------------------------------- public SurfaceMetadata createMetadata(RawOptionData capFloorData) { SurfaceMetadata metadata; if (capFloorData.DataType.Equals(BLACK_VOLATILITY)) { metadata = Surfaces.blackVolatilityByExpiryStrike(name.Name, dayCount); } else if (capFloorData.DataType.Equals(NORMAL_VOLATILITY)) { metadata = Surfaces.normalVolatilityByExpiryStrike(name.Name, dayCount); } else { throw new System.ArgumentException("Data type not supported"); } return(metadata); }
public virtual void test_createMetadata_normal() { SurfaceIborCapletFloorletVolatilityBootstrapDefinition @base = SurfaceIborCapletFloorletVolatilityBootstrapDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, LINEAR, DOUBLE_QUADRATIC); 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, Double.NaN, 0.09 } }), ValueType.NORMAL_VOLATILITY); IList <GenericVolatilitySurfacePeriodParameterMetadata> list = new List <GenericVolatilitySurfacePeriodParameterMetadata>(); list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.005))); list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.01))); list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(1), SimpleStrike.of(0.015))); list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(5), SimpleStrike.of(0.005))); list.Add(GenericVolatilitySurfacePeriodParameterMetadata.of(Period.ofYears(5), SimpleStrike.of(0.015))); SurfaceMetadata expected = Surfaces.normalVolatilityByExpiryStrike(NAME.Name, ACT_ACT_ISDA).withParameterMetadata(list); SurfaceMetadata computed = @base.createMetadata(capData); assertEquals(computed, expected); }
public virtual void recovery_test_normalFlat() { double lambdaT = 0.01; double lambdaK = 0.01; double error = 1.0e-3; DirectIborCapletFloorletVolatilityDefinition definition = DirectIborCapletFloorletVolatilityDefinition.of(NAME, USD_LIBOR_3M, ACT_ACT_ISDA, lambdaT, lambdaK, INTERPOLATOR); ImmutableList <Period> maturities = createBlackMaturities(); DoubleArray strikes = createBlackStrikes(); DoubleMatrix errorMatrix = DoubleMatrix.filled(maturities.size(), strikes.size(), error); RawOptionData data = RawOptionData.of(maturities, strikes, STRIKE, createFullFlatBlackDataMatrix(), errorMatrix, NORMAL_VOLATILITY); IborCapletFloorletVolatilityCalibrationResult res = CALIBRATOR.calibrate(definition, CALIBRATION_TIME, data, RATES_PROVIDER); NormalIborCapletFloorletExpiryStrikeVolatilities resVol = (NormalIborCapletFloorletExpiryStrikeVolatilities)res.Volatilities; Surface resSurface = resVol.Surface; int nParams = resSurface.ParameterCount; for (int i = 0; i < nParams; ++i) { assertEquals(resSurface.getParameter(i), 0.5, 1.0e-12); } }
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); } } }
/// <summary> /// Calibrates caplet volatilities to cap volatilities. /// </summary> /// <param name="definition"> the caplet volatility definition </param> /// <param name="calibrationDateTime"> the calibration time </param> /// <param name="capFloorData"> the cap data </param> /// <param name="ratesProvider"> the rates provider </param> /// <returns> the calibration result </returns> public abstract IborCapletFloorletVolatilityCalibrationResult calibrate(IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData, RatesProvider ratesProvider);
//------------------------------------------------------------------------- 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 SabrIborCapletFloorletVolatilityCalibrationDefinition, "definition should be SabrIborCapletFloorletVolatilityCalibrationDefinition"); SabrIborCapletFloorletVolatilityCalibrationDefinition sabrDefinition = (SabrIborCapletFloorletVolatilityCalibrationDefinition)definition; // unpack cap data, create node caps IborIndex index = sabrDefinition.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(sabrDefinition, calibrationDateTime, capFloorData); SurfaceMetadata metadata = sabrDefinition.createMetadata(capFloorData); IList <Period> expiries = capFloorData.Expiries; DoubleArray strikes = capFloorData.Strikes; int nExpiries = expiries.Count; 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>(); DoubleMatrix errorMatrix = capFloorData.Error.orElse(DoubleMatrix.filled(nExpiries, strikes.size(), 1d)); int[] startIndex = new int[nExpiries + 1]; for (int i = 0; i < nExpiries; ++i) { LocalDate endDate = baseDate.plus(expiries[i]); DoubleArray volatilityForTime = capFloorData.Data.row(i); DoubleArray errorForTime = errorMatrix.row(i); reduceRawData(sabrDefinition, ratesProvider, capFloorData.Strikes, volatilityForTime, errorForTime, 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]); } // create initial caplet vol surface IList <CurveMetadata> metadataList = sabrDefinition.createSabrParameterMetadata(); DoubleArray initialValues = sabrDefinition.createFullInitialValues(); IList <Curve> curveList = sabrDefinition.createSabrParameterCurve(metadataList, initialValues); SabrParameters sabrParamsInitial = SabrParameters.of(curveList[0], curveList[1], curveList[2], curveList[3], sabrDefinition.ShiftCurve, sabrDefinition.SabrVolatilityFormula); SabrParametersIborCapletFloorletVolatilities vols = SabrParametersIborCapletFloorletVolatilities.of(sabrDefinition.Name, index, calibrationDateTime, sabrParamsInitial); // solve least square UncoupledParameterTransforms transform = new UncoupledParameterTransforms(initialValues, sabrDefinition.createFullTransform(TRANSFORMS), new BitArray()); System.Func <DoubleArray, DoubleArray> valueFunction = createPriceFunction(sabrDefinition, ratesProvider, vols, capList, priceList); System.Func <DoubleArray, DoubleMatrix> jacobianFunction = createJacobianFunction(sabrDefinition, ratesProvider, vols, capList, priceList, index.Currency); NonLinearTransformFunction transFunc = new NonLinearTransformFunction(valueFunction, jacobianFunction, transform); LeastSquareResults res = solver.solve(DoubleArray.filled(priceList.Count, 1d), DoubleArray.copyOf(errorList), transFunc.FittingFunction, transFunc.FittingJacobian, transform.transform(initialValues)); LeastSquareResultsWithTransform resTransform = new LeastSquareResultsWithTransform(res, transform); vols = updateParameters(sabrDefinition, vols, resTransform.ModelParameters); return(IborCapletFloorletVolatilityCalibrationResult.ofLeastSquare(vols, res.ChiSq)); }
//------------------------------------------------------------------------- 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 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 DirectIborCapletFloorletVolatilityDefinition, "definition should be DirectIborCapletFloorletVolatilityDefinition"); DirectIborCapletFloorletVolatilityDefinition directDefinition = (DirectIborCapletFloorletVolatilityDefinition)definition; // unpack cap data, create node caps IborIndex index = directDefinition.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(directDefinition, calibrationDateTime, capFloorData); SurfaceMetadata metadata = directDefinition.createMetadata(capFloorData); IList <Period> expiries = capFloorData.Expiries; DoubleArray strikes = capFloorData.Strikes; int nExpiries = expiries.Count; 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>(); DoubleMatrix errorMatrix = capFloorData.Error.orElse(DoubleMatrix.filled(nExpiries, strikes.size(), 1d)); int[] startIndex = new int[nExpiries + 1]; for (int i = 0; i < nExpiries; ++i) { LocalDate endDate = baseDate.plus(expiries[i]); DoubleArray volatilityForTime = capFloorData.Data.row(i); DoubleArray errorForTime = errorMatrix.row(i); reduceRawData(directDefinition, ratesProvider, capFloorData.Strikes, volatilityForTime, errorForTime, 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]); } // create caplet nodes and initial caplet vol surface ResolvedIborCapFloorLeg cap = capList[capList.Count - 1]; int nCaplets = cap.CapletFloorletPeriods.size(); DoubleArray capletExpiries = DoubleArray.of(nCaplets, n => directDefinition.DayCount.relativeYearFraction(calibrationDate, cap.CapletFloorletPeriods.get(n).FixingDateTime.toLocalDate())); Triple <DoubleArray, DoubleArray, DoubleArray> capletNodes; DoubleArray initialVols = DoubleArray.copyOf(volList); if (directDefinition.ShiftCurve.Present) { metadata = Surfaces.blackVolatilityByExpiryStrike(directDefinition.Name.Name, directDefinition.DayCount); Curve shiftCurve = directDefinition.ShiftCurve.get(); if (capFloorData.DataType.Equals(NORMAL_VOLATILITY)) { initialVols = DoubleArray.of(capList.Count, n => volList[n] / (ratesProvider.iborIndexRates(index).rate(capList[n].FinalPeriod.IborRate.Observation) + shiftCurve.yValue(timeList[n]))); } InterpolatedNodalSurface capVolSurface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVols, INTERPOLATOR); capletNodes = createCapletNodes(capVolSurface, capletExpiries, strikes, directDefinition.ShiftCurve.get()); volatilitiesFunction = createShiftedBlackVolatilitiesFunction(index, calibrationDateTime, shiftCurve); } else { InterpolatedNodalSurface capVolSurface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVols, INTERPOLATOR); capletNodes = createCapletNodes(capVolSurface, capletExpiries, strikes); } InterpolatedNodalSurface baseSurface = InterpolatedNodalSurface.of(metadata, capletNodes.First, capletNodes.Second, capletNodes.Third, INTERPOLATOR); DoubleMatrix penaltyMatrix = directDefinition.computePenaltyMatrix(strikes, capletExpiries); // solve least square LeastSquareResults res = solver.solve(DoubleArray.copyOf(priceList), DoubleArray.copyOf(errorList), getPriceFunction(capList, ratesProvider, volatilitiesFunction, baseSurface), getJacobianFunction(capList, ratesProvider, volatilitiesFunction, baseSurface), capletNodes.Third, penaltyMatrix, POSITIVE); InterpolatedNodalSurface resSurface = InterpolatedNodalSurface.of(metadata, capletNodes.First, capletNodes.Second, res.FitParameters, directDefinition.Interpolator); return(IborCapletFloorletVolatilityCalibrationResult.ofLeastSquare(volatilitiesFunction(resSurface), res.ChiSq)); }
//------------------------------------------------------------------------- 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 SurfaceIborCapletFloorletVolatilityBootstrapDefinition, "definition should be SurfaceIborCapletFloorletVolatilityBootstrapDefinition"); SurfaceIborCapletFloorletVolatilityBootstrapDefinition bsDefinition = (SurfaceIborCapletFloorletVolatilityBootstrapDefinition)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]); } int nTotal = startIndex[nExpiries]; IborCapletFloorletVolatilities vols; int start; ZonedDateTime prevExpiry; DoubleArray initialVol = DoubleArray.copyOf(volList); if (bsDefinition.ShiftCurve.Present) { Curve shiftCurve = bsDefinition.ShiftCurve.get(); DoubleArray strikeShifted = DoubleArray.of(nTotal, n => strikeList[n] + shiftCurve.yValue(timeList[n])); if (capFloorData.DataType.Equals(NORMAL_VOLATILITY)) { // correct initial surface metadata = Surfaces.blackVolatilityByExpiryStrike(bsDefinition.Name.Name, bsDefinition.DayCount).withParameterMetadata(metadata.ParameterMetadata.get()); initialVol = DoubleArray.of(nTotal, n => volList[n] / (ratesProvider.iborIndexRates(index).rate(capList[n].FinalPeriod.IborRate.Observation) + shiftCurve.yValue(timeList[n]))); } InterpolatedNodalSurface surface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), strikeShifted, initialVol, bsDefinition.Interpolator); vols = ShiftedBlackIborCapletFloorletExpiryStrikeVolatilities.of(index, calibrationDateTime, surface, bsDefinition.ShiftCurve.get()); start = 0; prevExpiry = calibrationDateTime.minusDays(1L); // included if calibrationDateTime == fixingDateTime } else { InterpolatedNodalSurface surface = InterpolatedNodalSurface.of(metadata, DoubleArray.copyOf(timeList), DoubleArray.copyOf(strikeList), initialVol, bsDefinition.Interpolator); vols = volatilitiesFunction(surface); start = 1; prevExpiry = capList[startIndex[1] - 1].FinalFixingDateTime; } for (int i = start; i < nExpiries; ++i) { for (int j = startIndex[i]; j < startIndex[i + 1]; ++j) { System.Func <double, double[]> func = getValueVegaFunction(capList[j], ratesProvider, vols, prevExpiry, j); GenericImpliedVolatiltySolver solver = new GenericImpliedVolatiltySolver(func); double priceFixed = i == 0 ? 0d : this.priceFixed(capList[j], ratesProvider, vols, prevExpiry); double capletVol = solver.impliedVolatility(priceList[j] - priceFixed, initialVol.get(j)); vols = vols.withParameter(j, capletVol); } prevExpiry = capList[startIndex[i + 1] - 1].FinalFixingDateTime; } return(IborCapletFloorletVolatilityCalibrationResult.ofRootFind(vols)); }
// function creating volatilities object from surface protected internal virtual System.Func <Surface, IborCapletFloorletVolatilities> volatilitiesFunction(IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData) { IborIndex index = definition.Index; if (capFloorData.StrikeType.Equals(STRIKE)) { if (capFloorData.DataType.Equals(BLACK_VOLATILITY)) { return(blackVolatilitiesFunction(index, calibrationDateTime)); } else if (capFloorData.DataType.Equals(NORMAL_VOLATILITY)) { return(normalVolatilitiesFunction(index, calibrationDateTime)); } throw new System.ArgumentException("Data type not supported"); } throw new System.ArgumentException("strike type must be ValueType.STRIKE"); }