/** * Computes the log-normal implied volatility and its derivative with respect to price. * * @param price The forward price, which is the market price divided by the numeraire, * for example the zero bond p(0,T) for the T-forward measure * @param forward the forward value of the underlying * @param strike the strike * @param timeToExpiry the time to expiry * @param isCall true for call, false for put * @return log-normal (Black) implied volatility and tis derivative w.r.t. the price */ public static ValueDerivatives impliedVolatilityAdjoint( double price, double forward, double strike, double timeToExpiry, boolean isCall) { ArgChecker.isTrue(price >= 0d, "negative/NaN price; have {}", price); ArgChecker.isTrue(forward > 0d, "negative/NaN forward; have {}", forward); ArgChecker.isTrue(strike >= 0d, "negative/NaN strike; have {}", strike); ArgChecker.isTrue(timeToExpiry >= 0d, "negative/NaN timeToExpiry; have {}", timeToExpiry); ArgChecker.isFalse(Double.isInfinite(forward), "forward is Infinity"); ArgChecker.isFalse(Double.isInfinite(strike), "strike is Infinity"); ArgChecker.isFalse(Double.isInfinite(timeToExpiry), "timeToExpiry is Infinity"); double intrinsicPrice = Math.max(0., (isCall ? 1 : -1) * (forward - strike)); double targetPrice = price - intrinsicPrice; // Math.max(0., price - intrinsicPrice) should not used for least chi square double sigmaGuess = 0.3; return impliedVolatilityAdjoint(targetPrice, forward, strike, timeToExpiry, sigmaGuess); }
public void implied_volatility_adjoint() { double vol = 0.4342; // Deliberately picked an arbitrary vol double t = 0.1; double f = 10.0d; double shiftFd = 1.0E-6; double toleranceVol = 1.0E-3; double toleranceVolDelta = 1.0E-3; int nbPoints = 25; for (int i = 0; i <= nbPoints; i++) { double k = 0.75 * f + i * 0.5 * f / 25; double cPrice = BlackFormulaRepository.price(f, k, t, vol, true); double pPrice = BlackFormulaRepository.price(f, k, t, vol, false); ValueDerivatives ivCallAdj = BlackFormulaRepository.impliedVolatilityAdjoint(cPrice, f, k, t, true); ValueDerivatives ivPutAdj = BlackFormulaRepository.impliedVolatilityAdjoint(pPrice, f, k, t, false); assertEquals(ivCallAdj.getValue(), vol, toleranceVol); assertEquals(ivPutAdj.getValue(), vol, toleranceVol); double ivCallP = BlackFormulaRepository.impliedVolatility(cPrice + shiftFd, f, k, t, true); double ivCallM = BlackFormulaRepository.impliedVolatility(cPrice - shiftFd, f, k, t, true); double ivCallDerivative = (ivCallP - ivCallM) / (2 * shiftFd); assertEquals(ivCallAdj.getDerivative(0), ivCallDerivative, toleranceVolDelta); assertEquals(ivPutAdj.getDerivative(0), ivCallAdj.getDerivative(0), toleranceVolDelta); // Vega and its inverse are the same for call and puts } }
/** * Creates an array of shifted Black volatilities from option prices and the sensitivities of the * Black volatilities with respect to the price inputs. * * @param forward the forward rate * @param shiftOutput the shift required in the output * @param timeToExpiry the time to expiration * @param strikes the option strikes * @param prices the option prices * @return the shifted black volatilities and their derivatives */ public Pair<DoubleArray, DoubleArray> blackVolatilitiesShiftedFromPrices( double forward, double shiftOutput, double timeToExpiry, DoubleArray strikes, DoubleArray prices) { int nbStrikes = strikes.size(); double[] impliedVolatility = new double[nbStrikes]; double[] impliedVolatilityDerivatives = new double[nbStrikes]; for (int i = 0; i < nbStrikes; i++) { ValueDerivatives iv = BlackFormulaRepository.impliedVolatilityAdjoint( prices.get(i), forward + shiftOutput, strikes.get(i) + shiftOutput, timeToExpiry, true); impliedVolatility[i] = iv.getValue(); impliedVolatilityDerivatives[i] = iv.getDerivative(0); } return Pair.of(DoubleArray.ofUnsafe(impliedVolatility), DoubleArray.ofUnsafe(impliedVolatilityDerivatives)); }
ValueDerivatives price = BlackFormulaRepository.priceAdjoint( forward + shiftInput, strikes.get(i) + shiftInput, timeToExpiry, blackVolatilities.get(i), true); // vega-[3] ValueDerivatives iv = BlackFormulaRepository.impliedVolatilityAdjoint( price.getValue(), forward + shiftOutput, strikes.get(i) + shiftOutput, timeToExpiry, true); impliedVolatility[i] = iv.getValue();