BlackFormulaRepository { public static double impliedVolatility(final double price, final double forward, final double strike, final double timeToExpiry, final boolean isCall) { ArgumentChecker.isTrue(price >= 0.0, "negative/NaN price; have {}", price); ArgumentChecker.isTrue(forward > 0.0, "negative/NaN forward; have {}", forward); ArgumentChecker.isTrue(strike >= 0.0, "negative/NaN strike; have {}", strike); ArgumentChecker.isTrue(timeToExpiry >= 0.0, "negative/NaN timeToExpiry; have {}", timeToExpiry); ArgumentChecker.isFalse(Double.isInfinite(forward), "forward is Infinity"); ArgumentChecker.isFalse(Double.isInfinite(strike), "strike is Infinity"); ArgumentChecker.isFalse(Double.isInfinite(timeToExpiry), "timeToExpiry is Infinity"); final double intrinsicPrice = Math.max(0., (isCall ? 1 : -1) * (forward - strike)); final double targetPrice = price - intrinsicPrice; final double sigmaGuess = 0.3; return impliedVolatility(targetPrice, forward, strike, timeToExpiry, sigmaGuess); }  @ExternalFunction static double price(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall); static double price(final SimpleOptionData data, final double lognormalVol); static double price(final SimpleOptionData[] data, final double lognormalVol); @ExternalFunction static double delta(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall); static double strikeForDelta(final double forward, final double forwardDelta, final double timeToExpiry,
      final double lognormalVol, final boolean isCall); @ExternalFunction static double dualDelta(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall); @ExternalFunction static double simpleDelta(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall); @ExternalFunction static double gamma(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double dualGamma(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double crossGamma(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double theta(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall, final double interestRate); @ExternalFunction static double thetaMod(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol, final boolean isCall, final double interestRate); @ExternalFunction static double driftlessTheta(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double vega(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double vega(final SimpleOptionData data, final double lognormalVol); @ExternalFunction static double vanna(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double dualVanna(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double vomma(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); @ExternalFunction static double volga(final double forward, final double strike, final double timeToExpiry,
      final double lognormalVol); static double impliedVolatility(final double price, final double forward, final double strike,
      final double timeToExpiry, final boolean isCall); @ExternalFunction static double impliedVolatility(final double otmPrice, final double forward, final double strike,
      final double timeToExpiry, final double volGuess); static double impliedVolatility(final SimpleOptionData data, final double price); static double impliedVolatility(final SimpleOptionData[] data, final double price); @ExternalFunction static double impliedStrike(final double delta, final boolean isCall, final double forward, final double time,
      final double volatility); static double impliedStrike(final double delta, final boolean isCall, final double forward, final double time,
      final double volatility, final double[] derivatives);  }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativePriceErrorImpliedVolatilityTest() { BlackFormulaRepository.impliedVolatility(-10., FORWARD, STRIKES_INPUT[1], TIME_TO_EXPIRY, true); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeFwdErrorImpliedVolatilityTest() { BlackFormulaRepository.impliedVolatility(10., -FORWARD, STRIKES_INPUT[1], TIME_TO_EXPIRY, true); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeStrikeErrorImpliedVolatilityTest() { BlackFormulaRepository.impliedVolatility(10., FORWARD, -STRIKES_INPUT[1], TIME_TO_EXPIRY, true); }
@Test(expectedExceptions = IllegalArgumentException.class) public void negativeTimeErrorImpliedVolatilityTest() { BlackFormulaRepository.impliedVolatility(10., FORWARD, STRIKES_INPUT[1], -TIME_TO_EXPIRY, true); }
@Test public void volInitialGuessTest() { final int nStrikes = STRIKES_INPUT.length; final int nVols = VOLS.length; for (int i = 0; i < nStrikes; ++i) { for (int j = 0; j < nVols; ++j) { final double strike = STRIKES_INPUT[i]; final double vol = VOLS[j]; final double zero = BlackFormulaRepository.impliedVolatility(0., FORWARD, strike, TIME_TO_EXPIRY, vol); final double atm = BlackFormulaRepository.impliedVolatility(Math.pow(strike, 0.6), strike, strike, TIME_TO_EXPIRY, vol); assertEquals(0., zero, Math.abs(vol) * 1.e-13); assertEquals(NORMAL.getInverseCDF(0.5 * (Math.pow(strike, 0.6) / strike + 1)) * 2 / Math.sqrt(TIME_TO_EXPIRY), atm, 1.e-13); } } }