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()); }
private EuropeanVanillaOption withStrike(EuropeanVanillaOption option, double strike) { return EuropeanVanillaOption.of(strike, option.getTimeToExpiry(), option.getPutCall()); }
/** * 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); } }
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());
/** * 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); }
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);
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);
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);
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()); }
double priceInExpected = SABR_EXTRAPOLATION.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 = SABR_EXTRAPOLATION.priceAdjointSabr(optionIn.getStrike(), optionIn.getPutCall()); double priceIn = resIn.getValue(); double[] priceInDsabr = resIn.getDerivatives().toArray(); double priceAtExpected = SABR_EXTRAPOLATION.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()); priceAtPP[3] = sabrExtrapolationNP.price(optionAt.getStrike(), optionAt.getPutCall()); ValueDerivatives resAt = SABR_EXTRAPOLATION.priceAdjointSabr(optionAt.getStrike(), optionAt.getPutCall()); double priceAt = resAt.getValue(); double[] priceAtDsabr = resAt.getDerivatives().toArray(); double priceOutExpected = SABR_EXTRAPOLATION.price(optionOut.getStrike(), optionOut.getPutCall()); double[] priceOutPP = new double[4]; priceOutPP[0] = sabrExtrapolationAP.price(optionOut.getStrike(), optionOut.getPutCall()); priceOutPP[1] = sabrExtrapolationBP.price(optionOut.getStrike(), optionOut.getPutCall()); priceOutPP[2] = sabrExtrapolationRP.price(optionOut.getStrike(), optionOut.getPutCall()); priceOutPP[3] = sabrExtrapolationNP.price(optionOut.getStrike(), optionOut.getPutCall()); ValueDerivatives resOut = SABR_EXTRAPOLATION.priceAdjointSabr(optionOut.getStrike(), optionOut.getPutCall()); double priceOut = resOut.getValue(); double[] priceOutDsabr = resOut.getDerivatives().toArray();
@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()); } };
double priceOutExpected = sabrExtrapolation.price(option.getStrike(), option.getPutCall()); double[] priceOutPP = new double[4]; priceOutPP[0] = sabrExtrapolationAP.price(option.getStrike(), option.getPutCall()); priceOutPP[1] = sabrExtrapolationBP.price(option.getStrike(), option.getPutCall()); priceOutPP[2] = sabrExtrapolationRP.price(option.getStrike(), option.getPutCall()); priceOutPP[3] = sabrExtrapolationNP.price(option.getStrike(), option.getPutCall()); ValueDerivatives resOut = sabrExtrapolation.priceAdjointSabr(option.getStrike(), option.getPutCall()); double priceOut = resOut.getValue(); double[] priceOutDsabr = resOut.getDerivatives().toArray();
/** * 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()); }