/** * Test small forward. */ @Test public void smallForwardTest() { double smallForward = 0.1e-6; double smallCutoff = 0.9e-6; for (VolatilityFunctionProvider<SabrFormulaData> func : FUNCTIONS) { SabrExtrapolationRightFunction right = SabrExtrapolationRightFunction.of(smallForward, SABR_DATA, smallCutoff, TIME_TO_EXPIRY, MU, func); for (PutCall isCall : new PutCall[] {PutCall.CALL, PutCall.PUT}) { double priceBase = right.price(smallCutoff, isCall); double priceUp = right.price(smallCutoff + EPS * 0.1, isCall); double priceDw = right.price(smallCutoff - EPS * 0.1, isCall); assertEquals(priceBase, priceUp, EPS * 10.0); assertEquals(priceBase, priceDw, EPS * 10.0); } } }
/** * The Black price and its derivative with respect to the forward. * * @param strike the strike. * @return the Black price and its derivative. */ private double[] bsbsp(double strike) { double[] result = new double[2]; double strikeShifted = Math.max(strike + getShift(), 0d); // handle tiny but negative number result[0] = getSabrExtrapolation().price(strikeShifted, getPutCall()); result[1] = getSabrExtrapolation().priceDerivativeForward(strikeShifted, getPutCall()); return result; }
/** * Obtains an instance with volatility provider specified. * * @param forward the forward * @param sabrData the SABR formula data * @param cutOffStrike the cut-off-strike * @param timeToExpiry the time to expiration * @param mu the mu parameter * @param volatilityFunction the volatility function * @return the instance */ public static SabrExtrapolationRightFunction of( double forward, SabrFormulaData sabrData, double cutOffStrike, double timeToExpiry, double mu, VolatilityFunctionProvider<SabrFormulaData> volatilityFunction) { return new SabrExtrapolationRightFunction(forward, sabrData, cutOffStrike, timeToExpiry, mu, volatilityFunction); }
/** * Tests getter. */ public void getter() { SabrExtrapolationRightFunction func = SabrExtrapolationRightFunction.of( FORWARD, SABR_DATA, CUT_OFF_STRIKE, TIME_TO_EXPIRY, MU, SabrHaganVolatilityFunctionProvider.DEFAULT); assertEquals(func.getCutOffStrike(), CUT_OFF_STRIKE); assertEquals(func.getMu(), MU); assertEquals(func.getSabrData(), SABR_DATA); assertEquals(func.getTimeToExpiry(), TIME_TO_EXPIRY); }
/** * Extrapolator is not calibrated in this case, then the gap may be produced at the cutoff. */ @Test public void smallExpiryTest() { double smallExpiry = 0.5e-6; for (VolatilityFunctionProvider<SabrFormulaData> func : FUNCTIONS) { SabrExtrapolationRightFunction right = SabrExtrapolationRightFunction.of(FORWARD * 0.01, SABR_DATA, CUT_OFF_STRIKE, smallExpiry, MU, func); for (PutCall isCall : new PutCall[] {PutCall.CALL, PutCall.PUT}) { double priceBase = right.price(CUT_OFF_STRIKE, isCall); double priceUp = right.price(CUT_OFF_STRIKE + EPS * 0.1, isCall); double priceDw = right.price(CUT_OFF_STRIKE - EPS * 0.1, isCall); assertEquals(priceBase, priceUp, EPS); assertEquals(priceBase, priceDw, EPS); assertEquals(right.getParameter()[0], -1.0E4, 1.e-12); assertEquals(right.getParameter()[1], 0.0, 1.e-12); assertEquals(right.getParameter()[2], 0.0, 1.e-12); } } }
double forward = 0.0404500579038675; SabrExtrapolationRightFunction sabrExtrapolation = SabrExtrapolationRightFunction.of(forward, t, sabrData, cutOff, mu); double shift = 0.000001; SabrFormulaData sabrDataAP = SabrFormulaData.of(alpha + shift, beta, rho, nu); SabrFormulaData sabrDataNP = SabrFormulaData.of(alpha, beta, rho, nu + shift); SabrExtrapolationRightFunction sabrExtrapolationAP = SabrExtrapolationRightFunction.of(forward, t, sabrDataAP, cutOff, mu); SabrExtrapolationRightFunction sabrExtrapolationBP = SabrExtrapolationRightFunction.of(forward, t, sabrDataBP, cutOff, mu); SabrExtrapolationRightFunction sabrExtrapolationRP = SabrExtrapolationRightFunction.of(forward, t, sabrDataRP, cutOff, mu); SabrExtrapolationRightFunction sabrExtrapolationNP = SabrExtrapolationRightFunction.of(forward, t, sabrDataNP, cutOff, mu); double[] abc = sabrExtrapolation.getParameter(); double[][] abcDP = sabrExtrapolation.getParameterDerivativeSabr(); double[][] abcPP = new double[4][3]; abcPP[0] = sabrExtrapolationAP.getParameter(); abcPP[1] = sabrExtrapolationBP.getParameter(); abcPP[2] = sabrExtrapolationRP.getParameter(); abcPP[3] = sabrExtrapolationNP.getParameter(); double[][] abcDPExpected = new double[4][3]; for (int loopparam = 0; loopparam < 4; loopparam++) { double priceOutExpected = sabrExtrapolation.price(option.getStrike(), option.getPutCall()); double[] priceOutPP = new double[4]; priceOutPP[0] = sabrExtrapolationAP.price(option.getStrike(), option.getPutCall());
SabrExtrapolationRightFunction func = SabrExtrapolationRightFunction.of( FORWARD, SABR_DATA, CUT_OFF_STRIKE, TIME_TO_EXPIRY, MU, SabrHaganVolatilityFunctionProvider.DEFAULT); double strikeIn = 0.08; SabrFormulaData sabrDataFP = SabrFormulaData.of(ALPHA, BETA, RHO, NU); SabrExtrapolationRightFunction sabrExtrapolationFP = SabrExtrapolationRightFunction.of(FORWARD + shiftF, TIME_TO_EXPIRY, sabrDataFP, CUT_OFF_STRIKE, MU); double priceIn = func.price(optionIn.getStrike(), optionIn.getPutCall()); double priceInFP = sabrExtrapolationFP.price(optionIn.getStrike(), optionIn.getPutCall()); double priceInDF = func.priceDerivativeForward(optionIn.getStrike(), optionIn.getPutCall()); double priceInDFExpected = (priceInFP - priceIn) / shiftF; assertEquals(priceInDFExpected, priceInDF, 1E-5); double priceAt = func.price(optionAt.getStrike(), optionAt.getPutCall()); double priceAtFP = sabrExtrapolationFP.price(optionAt.getStrike(), optionAt.getPutCall()); double priceAtDF = func.priceDerivativeForward(optionAt.getStrike(), optionAt.getPutCall()); double priceAtDFExpected = (priceAtFP - priceAt) / shiftF; assertEquals(priceAtDFExpected, priceAtDF, 1E-6); double priceOut = func.price(optionOut.getStrike(), optionOut.getPutCall()); double priceOutFP = sabrExtrapolationFP.price(optionOut.getStrike(), optionOut.getPutCall()); double priceOutDF = func.priceDerivativeForward(optionOut.getStrike(), optionOut.getPutCall()); double priceOutDFExpected = (priceOutFP - priceOut) / shiftF; assertEquals(priceOutDFExpected, priceOutDF, 1E-5); double[] abc = func.getParameter(); double[] abcDF = func.getParameterDerivativeForward(); double[] abcFP = sabrExtrapolationFP.getParameter(); double[] abcDFExpected = new double[3];
EuropeanVanillaOption optionOutKP = EuropeanVanillaOption.of(strikeOut + shiftK, TIME_TO_EXPIRY, PutCall.PUT); double priceIn = SABR_EXTRAPOLATION.price(optionIn.getStrike(), optionIn.getPutCall()); double priceInKP = SABR_EXTRAPOLATION.price(optionInKP.getStrike(), optionInKP.getPutCall()); double priceInDK = SABR_EXTRAPOLATION.priceDerivativeStrike(optionIn.getStrike(), optionIn.getPutCall()); double priceInDFExpected = (priceInKP - priceIn) / shiftK; assertEquals(priceInDFExpected, priceInDK, 1E-5); double priceAt = SABR_EXTRAPOLATION.price(optionAt.getStrike(), optionAt.getPutCall()); double priceAtKP = SABR_EXTRAPOLATION.price(optionAtKP.getStrike(), optionAtKP.getPutCall()); double priceAtDK = SABR_EXTRAPOLATION.priceDerivativeStrike(optionAt.getStrike(), optionAt.getPutCall()); double priceAtDFExpected = (priceAtKP - priceAt) / shiftK; assertEquals(priceAtDFExpected, priceAtDK, 1E-5); double priceOut = SABR_EXTRAPOLATION.price(optionOut.getStrike(), optionOut.getPutCall()); double priceOutKP = SABR_EXTRAPOLATION.price(optionOutKP.getStrike(), optionOutKP.getPutCall()); double priceOutDK = SABR_EXTRAPOLATION.priceDerivativeStrike(optionOut.getStrike(), optionOut.getPutCall()); double priceOutDFExpected = (priceOutKP - priceOut) / shiftK; assertEquals(priceOutDFExpected, priceOutDK, 1E-5);
/** * The Black price with numeraire 1 as function of the strike. * * @param strike the strike. * @return the Black prcie. */ double bs(double strike) { double strikeShifted = Math.max(strike + getShift(), 0d); // handle tiny but negative number return sabrExtrapolation.price(strikeShifted, putCall); } }
@Override public Double apply(Double x) { double[] kD = kpkpp(x); // Implementation note: kD[0] contains the first derivative of k; kD[1] the second derivative of k. double xShifted = Math.max(x + shift, 0d); // handle tiny but negative number DoubleArray priceDerivativeSabr = getSabrExtrapolation().priceAdjointSabr(xShifted, putCall).getDerivatives(); return priceDerivativeSabr.get(i) * (factor * (kD[1] * (x - strike) + 2d * kD[0])); } };
this.shift = swaptionVolatilities.shift(timeToExpiry, tenor); this.sabrExtrapolation = SabrExtrapolationRightFunction .of(forward + shift, timeToExpiry, sabrPoint, cutOffStrike + shift, mu); this.putCall = cmsPeriod.getCmsPeriodType().equals(CmsPeriodType.FLOORLET) ? PutCall.PUT : PutCall.CALL; this.strike = strike;
parameterDerivativeForward = computesParametersDerivativeForward(); double f = extrapolation(strike); double fDa = f; double fDb = f / strike;
parameterDerivativeSabr = computesParametersDerivativeSabr(); double f = extrapolation(strike); double fDa = f; double fDb = f / strike;
intProv.k(strike) * intProv.getSabrExtrapolation().priceDerivativeStrike(strike + shift, intProv.getPutCall()); return cmsPeriod.getNotional() * cmsPeriod.getYearFraction() * factor * (firstPart + secondPart + thirdPart);
private double extrapolationDerivative(double strike) { return -extrapolation(strike) * (mu + (parameter[1] + 2 * parameter[2] / strike) / strike) / strike; }
/** * Gets the three fitting parameters derivatives with respect to the SABR parameters. * * @return the parameters derivative */ public double[][] getParameterDerivativeSabr() { if (parameterDerivativeSabr == null) { parameterDerivativeSabr = computesParametersDerivativeSabr(); } return parameterDerivativeSabr; }
/** * Gets the three fitting parameters derivatives with respect to the forward. * * @return the parameters derivative */ public double[] getParameterDerivativeForward() { if (parameterDerivativeForward == null) { parameterDerivativeForward = computesParametersDerivativeForward(); } return parameterDerivativeForward; }
private SabrExtrapolationRightFunction(double forward, SabrFormulaData sabrData, double cutOffStrike, double timeToExpiry, double mu, VolatilityFunctionProvider<SabrFormulaData> volatilityFunction) { ArgChecker.notNull(sabrData, "sabrData"); ArgChecker.notNull(volatilityFunction, "volatilityFunction"); this.sabrFunction = volatilityFunction; this.forward = forward; this.sabrData = sabrData; this.cutOffStrike = cutOffStrike; this.timeToExpiry = timeToExpiry; this.mu = mu; if (timeToExpiry > SMALL_EXPIRY) { parameter = computesFittingParameters(); } else { // Implementation note: when time to expiry is very small, the price above the cut-off strike and its derivatives should be 0 (or at least very small). parameter = new double[] {SMALL_PARAMETER, 0.0, 0.0}; parameterDerivativeForward = new double[3]; parameterDerivativeSabr = new double[4][3]; } }
SabrExtrapolationRightFunction func = SabrExtrapolationRightFunction.of( FORWARD, SABR_DATA, CUT_OFF_STRIKE, TIME_TO_EXPIRY, MU, SabrHaganVolatilityFunctionProvider.DEFAULT); double strikeIn = 0.08; SabrFormulaData sabrDataNP = SabrFormulaData.of(ALPHA, BETA, RHO, NU + shift); SabrExtrapolationRightFunction sabrExtrapolationAP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataAP, CUT_OFF_STRIKE, MU); SabrExtrapolationRightFunction sabrExtrapolationBP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataBP, CUT_OFF_STRIKE, MU); SabrExtrapolationRightFunction sabrExtrapolationRP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataRP, CUT_OFF_STRIKE, MU); SabrExtrapolationRightFunction sabrExtrapolationNP = SabrExtrapolationRightFunction.of(FORWARD, TIME_TO_EXPIRY, sabrDataNP, CUT_OFF_STRIKE, MU); double priceInExpected = func.price(optionIn.getStrike(), optionIn.getPutCall()); double[] priceInPP = new double[4]; priceInPP[0] = sabrExtrapolationAP.price(optionIn.getStrike(), optionIn.getPutCall()); priceInPP[1] = sabrExtrapolationBP.price(optionIn.getStrike(), optionIn.getPutCall()); priceInPP[2] = sabrExtrapolationRP.price(optionIn.getStrike(), optionIn.getPutCall()); priceInPP[3] = sabrExtrapolationNP.price(optionIn.getStrike(), optionIn.getPutCall()); ValueDerivatives resIn = func.priceAdjointSabr(optionIn.getStrike(), optionIn.getPutCall()); double priceIn = resIn.getValue(); double[] priceInDsabr = resIn.getDerivatives().toArray(); double priceAtExpected = func.price(optionAt.getStrike(), optionAt.getPutCall()); double[] priceAtPP = new double[4]; priceAtPP[0] = sabrExtrapolationAP.price(optionAt.getStrike(), optionAt.getPutCall()); priceAtPP[1] = sabrExtrapolationBP.price(optionAt.getStrike(), optionAt.getPutCall()); priceAtPP[2] = sabrExtrapolationRP.price(optionAt.getStrike(), optionAt.getPutCall());
SabrFormulaData sabrDataFP = SabrFormulaData.of(ALPHA, BETA, RHO, NU); SabrExtrapolationRightFunction sabrExtrapolationFP = SabrExtrapolationRightFunction.of(FORWARD + shiftF, TIME_TO_EXPIRY, sabrDataFP, CUT_OFF_STRIKE, MU); double priceIn = SABR_EXTRAPOLATION.price(optionIn.getStrike(), optionIn.getPutCall()); double priceInFP = sabrExtrapolationFP.price(optionIn.getStrike(), optionIn.getPutCall()); double priceInDF = SABR_EXTRAPOLATION.priceDerivativeForward(optionIn.getStrike(), optionIn.getPutCall()); double priceInDFExpected = (priceInFP - priceIn) / shiftF; assertEquals(priceInDFExpected, priceInDF, 1E-5); double priceAt = SABR_EXTRAPOLATION.price(optionAt.getStrike(), optionAt.getPutCall()); double priceAtFP = sabrExtrapolationFP.price(optionAt.getStrike(), optionAt.getPutCall()); double priceAtDF = SABR_EXTRAPOLATION.priceDerivativeForward(optionAt.getStrike(), optionAt.getPutCall()); double priceAtDFExpected = (priceAtFP - priceAt) / shiftF; assertEquals(priceAtDFExpected, priceAtDF, 1E-6); double[] abc = SABR_EXTRAPOLATION.getParameter(); double[] abcDF = SABR_EXTRAPOLATION.getParameterDerivativeForward(); double[] abcFP = sabrExtrapolationFP.getParameter(); double[] abcDFExpected = new double[3]; for (int loopparam = 0; loopparam < 3; loopparam++) { double priceOut = SABR_EXTRAPOLATION.price(optionOut.getStrike(), optionOut.getPutCall()); double priceOutFP = sabrExtrapolationFP.price(optionOut.getStrike(), optionOut.getPutCall()); double priceOutDF = SABR_EXTRAPOLATION.priceDerivativeForward(optionOut.getStrike(), optionOut.getPutCall()); double priceOutDFExpected = (priceOutFP - priceOut) / shiftF; assertEquals(priceOutDFExpected, priceOutDF, 1E-5);