public void test_of() { EuropeanVanillaOption test = EuropeanVanillaOption.of(STRIKE, TIME, CALL); assertEquals(test.getStrike(), STRIKE, 0d); assertEquals(test.getTimeToExpiry(), TIME, 0d); assertEquals(test.getPutCall(), CALL); assertTrue(test.isCall()); }
@Override public Double apply(SabrFormulaData data) { ArgChecker.notNull(data, "data"); return FUNCTION.volatility(forward, option.getStrike(), option.getTimeToExpiry(), data); } };
/** * Tests that the smile and its derivatives are smooth enough in SABR model with extrapolation. */ public void smileSmooth() { int nbPts = 100; double rangeStrike = 0.02; double[] price = new double[nbPts + 1]; double[] strike = new double[nbPts + 1]; for (int looppts = 0; looppts <= nbPts; looppts++) { strike[looppts] = CUT_OFF_STRIKE - rangeStrike + looppts * 2.0 * rangeStrike / nbPts; EuropeanVanillaOption option = EuropeanVanillaOption.of(strike[looppts], TIME_TO_EXPIRY, PutCall.CALL); price[looppts] = SABR_EXTRAPOLATION.price(option.getStrike(), option.getPutCall()); } double[] priceD = new double[nbPts]; double[] priceD2 = new double[nbPts]; for (int looppts = 1; looppts < nbPts; looppts++) { priceD[looppts] = (price[looppts + 1] - price[looppts - 1]) / (strike[looppts + 1] - strike[looppts - 1]); priceD2[looppts] = (price[looppts + 1] + price[looppts - 1] - 2 * price[looppts]) / ((strike[looppts + 1] - strike[looppts]) * (strike[looppts + 1] - strike[looppts])); } for (int looppts = 2; looppts < nbPts; looppts++) { assertEquals(priceD[looppts - 1], priceD[looppts], 1.5E-3); assertEquals(priceD2[looppts - 1], priceD2[looppts], 1.5E-1); } }
private void volatilityAdjoint2ForInstrument(EuropeanVanillaOption option, double tolerance1, double tolerance2) { double volatility = FUNCTION.volatility(F, option.getStrike(), option.getTimeToExpiry(), DATA); double[] volatilityAdjoint = toArray(FUNCTION.volatilityAdjoint(F, option.getStrike(), option.getTimeToExpiry(), DATA)); double[] volD = new double[6]; double[][] volD2 = new double[2][2]; double vol = FUNCTION.volatilityAdjoint2(F, option.getStrike(), option.getTimeToExpiry(), DATA, volD, volD2); assertEquals(volatility, vol, tolerance1); double volatilityFP = FUNCTION.volatility(F + deltaF, option.getStrike(), option.getTimeToExpiry(), DATA); double volatilityFM = FUNCTION.volatility(F - deltaF, option.getStrike(), option.getTimeToExpiry(), DATA); double derivativeFF_FD = (volatilityFP + volatilityFM - 2 * volatility) / (deltaF * deltaF); assertEquals(derivativeFF_FD, volD2[0][0], tolerance2); double volatilityKP = FUNCTION.volatility(F, option.getStrike() + deltaK, option.getTimeToExpiry(), DATA); double volatilityKM = FUNCTION.volatility(F, option.getStrike() - deltaK, option.getTimeToExpiry(), DATA); double derivativeKK_FD = (volatilityKP + volatilityKM - 2 * volatility) / (deltaK * deltaK); assertEquals(derivativeKK_FD, volD2[1][1], tolerance2); double volatilityFPKP = FUNCTION.volatility(F + deltaF, option.getStrike() + deltaK, option.getTimeToExpiry(), DATA); double derivativeFK_FD = (volatilityFPKP + volatility - volatilityFP - volatilityKP) / (deltaF * deltaK); assertEquals(derivativeFK_FD, volD2[0][1], tolerance2);
/** * Tests the price put/call parity for options in SABR model with extrapolation. */ public void pricePutCallParity() { double strikeIn = 0.08; double strikeAt = CUT_OFF_STRIKE; double strikeOut = 0.12; EuropeanVanillaOption callIn = EuropeanVanillaOption.of(strikeIn, TIME_TO_EXPIRY, PutCall.CALL); EuropeanVanillaOption putIn = EuropeanVanillaOption.of(strikeIn, TIME_TO_EXPIRY, PutCall.PUT); EuropeanVanillaOption callAt = EuropeanVanillaOption.of(strikeAt, TIME_TO_EXPIRY, PutCall.CALL); EuropeanVanillaOption putAt = EuropeanVanillaOption.of(strikeAt, TIME_TO_EXPIRY, PutCall.PUT); EuropeanVanillaOption callOut = EuropeanVanillaOption.of(strikeOut, TIME_TO_EXPIRY, PutCall.CALL); EuropeanVanillaOption putOut = EuropeanVanillaOption.of(strikeOut, TIME_TO_EXPIRY, PutCall.PUT); double priceCallIn = SABR_EXTRAPOLATION.price(callIn.getStrike(), callIn.getPutCall()); double pricePutIn = SABR_EXTRAPOLATION.price(putIn.getStrike(), putIn.getPutCall()); assertEquals(FORWARD - strikeIn, priceCallIn - pricePutIn, TOLERANCE_PRICE); double priceCallAt = SABR_EXTRAPOLATION.price(callAt.getStrike(), callAt.getPutCall()); double pricePutAt = SABR_EXTRAPOLATION.price(putAt.getStrike(), putAt.getPutCall()); assertEquals(FORWARD - strikeAt, priceCallAt - pricePutAt, TOLERANCE_PRICE); double priceCallOut = SABR_EXTRAPOLATION.price(callOut.getStrike(), callOut.getPutCall()); double pricePutOut = SABR_EXTRAPOLATION.price(putOut.getStrike(), putOut.getPutCall()); assertEquals(FORWARD - strikeOut, priceCallOut - pricePutOut, TOLERANCE_PRICE); }
for (int looppts = 0; looppts <= nbPts; looppts++) { EuropeanVanillaOption option = EuropeanVanillaOption.of(strike[looppts], timeToExpiry[loopmat], PutCall.CALL); price[loopmat][looppts] = sabrExtrapolation[loopmat].price(option.getStrike(), option.getPutCall());
EuropeanVanillaOption optionOutKP = EuropeanVanillaOption.of(strikeOut + shiftK, TIME_TO_EXPIRY, PutCall.CALL); 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);
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);
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); assertEquals(1.0, abcDFExpected[loopparam] / abcDF[loopparam], 5E-2); 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);
EuropeanVanillaOption optionUp = EuropeanVanillaOption.of(option.getStrike(), T + eps, option.getPutCall()); EuropeanVanillaOption optionDw = EuropeanVanillaOption.of(option.getStrike(), T - eps, option.getPutCall()); double priceTimeUp = FUNCTION.getPriceFunction(optionUp).apply(ZERO_VOL_DATA); double priceTimeDw = FUNCTION.getPriceFunction(optionDw).apply(ZERO_VOL_DATA);
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);
public void greeksTest() { double tol = 1.0e-12; double eps = 1.0e-5; EuropeanVanillaOption[] options = new EuropeanVanillaOption[] { ITM_CALL, ITM_PUT, OTM_CALL, OTM_PUT, ATM_CALL, ATM_PUT}; for (EuropeanVanillaOption option : options) { // consistency with getPriceFunction for first order derivatives ValueDerivatives price = FUNCTION.getPriceAdjoint(option, VOL_DATA); double delta = FUNCTION.getDelta(option, VOL_DATA); double vega = FUNCTION.getVega(option, VOL_DATA); assertEquals(price.getDerivative(0), delta, tol); assertEquals(price.getDerivative(1), vega, tol); // testing second order derivative against finite difference approximation NormalFunctionData dataUp = NormalFunctionData.of(F + eps, DF, SIGMA); NormalFunctionData dataDw = NormalFunctionData.of(F - eps, DF, SIGMA); double deltaUp = FUNCTION.getDelta(option, dataUp); double deltaDw = FUNCTION.getDelta(option, dataDw); double ref = 0.5 * (deltaUp - deltaDw) / eps; double gamma = FUNCTION.getGamma(option, VOL_DATA); assertEquals(gamma, ref, eps); EuropeanVanillaOption optionUp = EuropeanVanillaOption.of(option.getStrike(), T + eps, option.getPutCall()); EuropeanVanillaOption optionDw = EuropeanVanillaOption.of(option.getStrike(), T - eps, option.getPutCall()); double priceTimeUp = FUNCTION.getPriceFunction(optionUp).apply(VOL_DATA); double priceTimeDw = FUNCTION.getPriceFunction(optionDw).apply(VOL_DATA); ref = -0.5 * (priceTimeUp - priceTimeDw) / eps; double theta = FUNCTION.getTheta(option, VOL_DATA); assertEquals(theta, ref, eps); } }
private double impliedVolatility( NormalFunctionData data, EuropeanVanillaOption option, double price) { return NormalFormulaRepository.impliedVolatility( price, data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), data.getNumeraire(), option.getPutCall()); }
@SuppressWarnings("synthetic-access") @Override public Double apply(NormalFunctionData data) { ArgChecker.notNull(data, "data"); return data.getNumeraire() * NormalFormulaRepository.price( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), option.getPutCall()); } };
/** * Computes forward delta of an option in the normally distributed assets hypothesis (Bachelier model). * * @param option the option description * @param data the model data * @return delta */ public double getDelta(EuropeanVanillaOption option, NormalFunctionData data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); return data.getNumeraire() * NormalFormulaRepository.delta( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), option.getPutCall()); }
/** * Computes theta of an option in the normally distributed assets hypothesis (Bachelier model). * * @param option the option description * @param data the model data * @return theta */ public double getTheta(EuropeanVanillaOption option, NormalFunctionData data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); return data.getNumeraire() * NormalFormulaRepository.theta( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), option.getPutCall()); }
/** * Computes forward gamma of an option in the normally distributed assets hypothesis (Bachelier model). * * @param option the option description * @param data the model data * @return gamma */ public double getGamma(EuropeanVanillaOption option, NormalFunctionData data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); return data.getNumeraire() * NormalFormulaRepository.gamma( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), option.getPutCall()); }
/** * Computes vega of an option in the normally distributed assets hypothesis (Bachelier model). * * @param option the option description * @param data the model data * @return vega */ public double getVega(EuropeanVanillaOption option, NormalFunctionData data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); return data.getNumeraire() * NormalFormulaRepository.vega( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), option.getPutCall()); }
/** * Computes the price of an option in the normally distributed assets hypothesis (Bachelier model). * The first order price derivatives are also provided. * * @param option the option description * @param data the model data * @return a {@link ValueDerivatives} with the price in the value and the derivatives with * respect to [0] the forward, [1] the volatility and [2] the strike */ public ValueDerivatives getPriceAdjoint(EuropeanVanillaOption option, NormalFunctionData data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); return NormalFormulaRepository.priceAdjoint( data.getForward(), option.getStrike(), option.getTimeToExpiry(), data.getNormalVolatility(), data.getNumeraire(), option.getPutCall()); }
private void testVolatilityAdjoint(double forward, EuropeanVanillaOption optionData, SabrFormulaData sabrData, double eps, double tol) { double volatility = FUNCTION.volatility(forward, optionData.getStrike(), optionData.getTimeToExpiry(), sabrData); double[] volatilityAdjoint = toArray(FUNCTION.volatilityAdjoint( forward, optionData.getStrike(), optionData.getTimeToExpiry(), sabrData)); assertEquals(volatility, volatilityAdjoint[0], tol); assertEqualsRelTol("Forward Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Forward, eps), volatilityAdjoint[1], tol); assertEqualsRelTol("Strike Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Strike, eps), volatilityAdjoint[2], tol); assertEqualsRelTol("Alpha Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Alpha, eps), volatilityAdjoint[3], tol); assertEqualsRelTol("Beta Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Beta, eps), volatilityAdjoint[4], tol); assertEqualsRelTol("Rho Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Rho, eps), volatilityAdjoint[5], tol); assertEqualsRelTol("Nu Sensitivity" + sabrData.toString(), fdSensitivity(optionData, forward, sabrData, SabrParameter.Nu, eps), volatilityAdjoint[6], tol); }