/** * Data bundle for pricing in a normal framework. * That is, the forward value of the underlying asset is a martingale in the chosen numeraire measure. * * @param forward the forward value of the underlying asset, such as forward value of a stock, or forward Libor rate * @param numeraire the numeraire associated with the equation * @param normalVolatility the normal volatility (sigma) * @return the function data */ public static NormalFunctionData of(double forward, double numeraire, double normalVolatility) { return new NormalFunctionData(forward, numeraire, normalVolatility); }
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()); }
NormalFunctionData dataFP = NormalFunctionData.of(F + deltaF, DF, SIGMA); NormalFunctionData dataFM = NormalFunctionData.of(F - deltaF, DF, SIGMA); double priceFP = FUNCTION.getPriceFunction(ITM_CALL).apply(dataFP); double priceFM = FUNCTION.getPriceFunction(ITM_CALL).apply(dataFM); NormalFunctionData dataVP = NormalFunctionData.of(F, DF, SIGMA + deltaV); NormalFunctionData dataVM = NormalFunctionData.of(F, DF, SIGMA - deltaV); double priceVP = FUNCTION.getPriceFunction(ITM_CALL).apply(dataVP); double priceVM = FUNCTION.getPriceFunction(ITM_CALL).apply(dataVM);
@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()); } };
public void present_value_formula() { double forward = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD); double pvbp = PRICER_SWAP.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), MULTI_USD); double volatility = NORMAL_VOLS_USD_STD.volatility(SWAPTION_LONG_REC.getExpiry(), SWAP_TENOR_YEAR, STRIKE, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); double expiry = NORMAL_VOLS_USD_STD.relativeTime(SWAPTION_LONG_REC.getExpiry()); EuropeanVanillaOption option = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT); double pvExpected = NORMAL.getPriceFunction(option).apply(normalData); CurrencyAmount pvComputed = PRICER_SWAPTION_NORMAL.presentValue(SWAPTION_LONG_REC, MULTI_USD, NORMAL_VOLS_USD_STD); assertEquals(pvComputed.getCurrency(), USD); assertEquals(pvComputed.getAmount(), pvExpected, TOLERANCE_PV); }
/** * 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()); }
public void present_value_delta_formula() { double forward = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD); double pvbp = PRICER_SWAP.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), MULTI_USD); double volatility = NORMAL_VOLS_USD_STD.volatility(SWAPTION_LONG_REC.getExpiry(), SWAP_TENOR_YEAR, STRIKE, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); double expiry = NORMAL_VOLS_USD_STD.relativeTime(SWAPTION_LONG_REC.getExpiry()); EuropeanVanillaOption option = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT); double pvDeltaExpected = NORMAL.getDelta(option, normalData); CurrencyAmount pvDeltaComputed = PRICER_SWAPTION_NORMAL.presentValueDelta(SWAPTION_LONG_REC, MULTI_USD, NORMAL_VOLS_USD_STD); assertEquals(pvDeltaComputed.getCurrency(), USD); assertEquals(pvDeltaComputed.getAmount(), pvDeltaExpected, TOLERANCE_PV); }
/** * 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()); }
public void price_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionPriceExpected = NORMAL_FUNCTION.getPriceFunction(option).apply(normalPoint); double optionPriceComputed = OPTION_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionPriceComputed, optionPriceExpected, TOLERANCE_PRICE); }
/** * 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()); }
public void present_value_gamma_formula() { double forward = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD); double pvbp = PRICER_SWAP.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), MULTI_USD); double volatility = NORMAL_VOLS_USD_STD.volatility(SWAPTION_LONG_REC.getExpiry(), SWAP_TENOR_YEAR, STRIKE, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); double expiry = NORMAL_VOLS_USD_STD.relativeTime(SWAPTION_LONG_REC.getExpiry()); EuropeanVanillaOption option = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT); double pvGammaExpected = NORMAL.getGamma(option, normalData); CurrencyAmount pvGammaComputed = PRICER_SWAPTION_NORMAL.presentValueGamma(SWAPTION_LONG_REC, MULTI_USD, NORMAL_VOLS_USD_STD); assertEquals(pvGammaComputed.getCurrency(), USD); assertEquals(pvGammaComputed.getAmount(), pvGammaExpected, TOLERANCE_PV); }
/** * 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()); }
public void present_value_theta_formula() { double forward = PRICER_SWAP.parRate(RSWAP_REC, MULTI_USD); double pvbp = PRICER_SWAP.getLegPricer().pvbp(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), MULTI_USD); double volatility = NORMAL_VOLS_USD_STD.volatility(SWAPTION_LONG_REC.getExpiry(), SWAP_TENOR_YEAR, STRIKE, forward); NormalFunctionData normalData = NormalFunctionData.of(forward, Math.abs(pvbp), volatility); double expiry = NORMAL_VOLS_USD_STD.relativeTime(SWAPTION_LONG_REC.getExpiry()); EuropeanVanillaOption option = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT); double pvThetaExpected = NORMAL.getTheta(option, normalData); CurrencyAmount pvThetaComputed = PRICER_SWAPTION_NORMAL.presentValueTheta(SWAPTION_LONG_REC, MULTI_USD, NORMAL_VOLS_USD_STD); assertEquals(pvThetaComputed.getCurrency(), USD); assertEquals(pvThetaComputed.getAmount(), pvThetaExpected, TOLERANCE_PV); }
/** * 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()); }
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); } }
public void intrinsic_price() { NormalFunctionData data = NormalFunctionData.of(1.0, 1.0, 0.01); EuropeanVanillaOption option1 = EuropeanVanillaOption.of(0.5, 1.0, PutCall.CALL); assertThrowsIllegalArg(() -> impliedVolatility(data, option1, 1e-6)); EuropeanVanillaOption option2 = EuropeanVanillaOption.of(1.5, 1.0, PutCall.PUT); assertThrowsIllegalArg(() -> impliedVolatility(data, option2, 1e-6)); }
public void delta_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionDeltaExpected = NORMAL_FUNCTION.getDelta(option, normalPoint); double optionDeltaComputed = OPTION_PRICER.deltaStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionDeltaComputed, optionDeltaExpected, TOLERANCE_PRICE); }
public void test_presentValue() { CurrencyAmount pvRecComputed = PRICER_SWAPTION.presentValue(SWAPTION_REC_LONG, RATE_PROVIDER, VOLS); CurrencyAmount pvPayComputed = PRICER_SWAPTION.presentValue(SWAPTION_PAY_SHORT, RATE_PROVIDER, VOLS); double forward = PRICER_SWAP.parRate(RSWAP_REC, RATE_PROVIDER); double annuityCash = PRICER_SWAP.getLegPricer().annuityCash(RSWAP_REC.getLegs(SwapLegType.FIXED).get(0), forward); double volatility = VOLS.volatility(SWAPTION_REC_LONG.getExpiry(), SWAP_TENOR_YEAR, STRIKE, forward); double discount = RATE_PROVIDER.discountFactor(USD, SETTLE_DATE); NormalFunctionData normalData = NormalFunctionData.of(forward, annuityCash * discount, volatility); double expiry = VOLS.relativeTime(SWAPTION_REC_LONG.getExpiry()); EuropeanVanillaOption optionRec = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.PUT); EuropeanVanillaOption optionPay = EuropeanVanillaOption.of(STRIKE, expiry, PutCall.CALL); double pvRecExpected = NORMAL.getPriceFunction(optionRec).apply(normalData); double pvPayExpected = -NORMAL.getPriceFunction(optionPay).apply(normalData); assertEquals(pvRecComputed.getCurrency(), USD); assertEquals(pvRecComputed.getAmount(), pvRecExpected, NOTIONAL * TOL); assertEquals(pvPayComputed.getCurrency(), USD); assertEquals(pvPayComputed.getAmount(), pvPayExpected, NOTIONAL * TOL); }
public void priceSensitivityNormalVolatility_from_future_price() { IborIndexRates mockIbor = mock(IborIndexRates.class); SimpleRatesProvider prov = new SimpleRatesProvider(); prov.setIborRates(mockIbor); when(mockIbor.rate(OPTION.getUnderlyingFuture().getIborRate().getObservation())).thenReturn(RATE); double futurePrice = 0.9875; double strike = OPTION.getStrikePrice(); double timeToExpiry = ACT_365F.relativeYearFraction(VAL_DATE, OPTION.getExpiryDate()); double priceSimpleMoneyness = strike - futurePrice; double normalVol = PARAMETERS_PRICE.zValue(timeToExpiry, priceSimpleMoneyness); EuropeanVanillaOption option = EuropeanVanillaOption.of(strike, timeToExpiry, OPTION.getPutCall()); NormalFunctionData normalPoint = NormalFunctionData.of(futurePrice, 1.0, normalVol); double optionVegaExpected = NORMAL_FUNCTION.getVega(option, normalPoint); IborFutureOptionSensitivity optionVegaComputed = OPTION_PRICER.priceSensitivityModelParamsVolatility( OPTION, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice); assertEquals(optionVegaComputed.getSensitivity(), optionVegaExpected, TOLERANCE_PRICE); assertEquals(optionVegaComputed.getExpiry(), timeToExpiry); assertEquals(optionVegaComputed.getFixingDate(), OPTION.getUnderlyingFuture().getIborRate().getObservation().getFixingDate()); assertEquals(optionVegaComputed.getStrikePrice(), OPTION.getStrikePrice()); assertEquals(optionVegaComputed.getFuturePrice(), futurePrice); }