// ------------------------------------------------------------------------- @Override public double volatility( double forward, double strike, double timeToExpiry, SsviFormulaData data) { ArgChecker.isTrue( timeToExpiry > MIN_TIME_TO_EXPIRY, "time to expiry must not be zero to be able to compute volatility"); double volatilityAtm = data.getSigma(); double rho = data.getRho(); double eta = data.getEta(); double theta = volatilityAtm * volatilityAtm * timeToExpiry; double phi = eta / Math.sqrt(theta); double k = Math.log(strike / forward); double w = 0.5 * theta * (1.0d + rho * phi * k + Math.sqrt(1.0d + 2 * rho * phi * k + phi * k * phi * k)); return Math.sqrt(w / timeToExpiry); }
/** * Computes the implied volatility in the SSVI formula and its derivatives. * * <p>The derivatives are stored in an array with: * * <ul> * <li>[0] derivative with respect to the forward * <li>[1] derivative with respect to the strike * <li>[2] derivative with respect to the time to expiry * <li>[3] derivative with respect to the sigma (ATM volatility) * <li>[4] derivative with respect to the rho * <li>[5] derivative with respect to the eta * </ul> * * @param forward the forward value of the underlying * @param strike the strike value of the option * @param timeToExpiry the time to expiry of the option * @param data the SSVI data * @return the volatility and associated derivatives */ @Override public ValueDerivatives volatilityAdjoint( double forward, double strike, double timeToExpiry, SsviFormulaData data) { ArgChecker.isTrue( timeToExpiry > MIN_TIME_TO_EXPIRY, "time to expiry must not be zero to be able to compute volatility"); double volatilityAtm = data.getSigma(); double rho = data.getRho(); double eta = data.getEta(); double theta = volatilityAtm * volatilityAtm * timeToExpiry; double stheta = Math.sqrt(theta); double phi = eta / stheta; double k = Math.log(strike / forward); double s = Math.sqrt(1.0d + 2 * rho * phi * k + phi * k * phi * k); double w = 0.5 * theta * (1.0d + rho * phi * k + s); double volatility = Math.sqrt(w / timeToExpiry); // Backward sweep. double[] derivatives = new double[6]; // 6 inputs double volatilityBar = 1.0; double wBar = 0.5 * volatility / w * volatilityBar; derivatives[2] += -0.5 * volatility / timeToExpiry * volatilityBar; double thetaBar = w / theta * wBar; derivatives[4] += 0.5 * theta * phi * k * wBar; double phiBar = 0.5 * theta * rho * k * wBar; double kBar = 0.5 * theta * rho * phi * wBar; double sBar = 0.5 * theta * wBar; derivatives[4] += phi * k / s * sBar; phiBar += (rho * k + phi * k * k) / s * sBar; kBar += (rho * phi + phi * phi * k) / s * sBar; derivatives[1] += 1.0d / strike * kBar; derivatives[0] += -1.0d / forward * kBar; derivatives[5] += phiBar / stheta; double sthetaBar = -eta / (stheta * stheta) * phiBar; thetaBar += 0.5 / stheta * sthetaBar; derivatives[3] += 2 * volatilityAtm * timeToExpiry * thetaBar; derivatives[2] += volatilityAtm * volatilityAtm * thetaBar; return ValueDerivatives.of(volatility, DoubleArray.ofUnsafe(derivatives)); }