BlackFormulaRepository { @ExternalFunction public static double impliedStrike(final double delta, final boolean isCall, final double forward, final double time, final double volatility) { Validate.isTrue(delta > -1 && delta < 1, "Delta out of range"); Validate.isTrue(isCall ^ (delta < 0), "Delta incompatible with call/put: " + isCall + ", " + delta); Validate.isTrue(forward > 0, "Forward negative"); final double omega = (isCall ? 1.0 : -1.0); final double strike = forward * Math.exp(-volatility * Math.sqrt(time) * omega * NORMAL.getInverseCDF(omega * delta) + volatility * volatility * time / 2); return strike; }  @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 public void impliedStrike() { final BlackPriceFunction function = new BlackPriceFunction(); final int nbStrike = STRIKES_INPUT.length; final int nbVols = VOLS.length; boolean callput = false; for (int loopcall = 0; loopcall < 2; loopcall++) { callput = !callput; for (int loopstrike = 0; loopstrike < nbStrike; loopstrike++) { for (int loopVols = 0; loopVols < nbVols; loopVols++) { final EuropeanVanillaOption option = new EuropeanVanillaOption(STRIKES_INPUT[loopstrike], TIME_TO_EXPIRY, callput); final BlackFunctionData data = new BlackFunctionData(FORWARD, 1.0, VOLS[loopVols]); final double[] d = function.getPriceAdjoint(option, data); final double delta = d[1]; final double strikeOutput = BlackFormulaRepository.impliedStrike(delta, callput, FORWARD, TIME_TO_EXPIRY, VOLS[loopVols]); assertEquals("Implied strike: (data " + loopstrike + " / " + callput + ")", STRIKES_INPUT[loopstrike], strikeOutput, 1.0E-8); } } } }
@Test public void impliedStrikeDerivatives() { final double[] delta = new double[] {0.25, -0.25, 0.49 }; final boolean[] cap = new boolean[] {true, false, true }; final double[] forward = new double[] {104, 100, 10 }; final double[] time = new double[] {2.5, 5.0, 0.5 }; final double[] vol = new double[] {0.25, 0.10, 0.50 }; final double shift = 0.000001; final double shiftF = 0.001; final double[] derivatives = new double[4]; for (int loop = 0; loop < delta.length; loop++) { final double strike = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop], time[loop], vol[loop], derivatives); final double strikeD = BlackFormulaRepository.impliedStrike(delta[loop] + shift, cap[loop], forward[loop], time[loop], vol[loop]); assertEquals("Implied strike: derivative delta", (strikeD - strike) / shift, derivatives[0], 1.0E-3); final double strikeF = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop] + shiftF, time[loop], vol[loop]); assertEquals("Implied strike: derivative forward", (strikeF - strike) / shiftF, derivatives[1], 1.0E-5); final double strikeT = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop], time[loop] + shift, vol[loop]); assertEquals("Implied strike: derivative time", (strikeT - strike) / shift, derivatives[2], 1.0E-4); final double strikeV = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop], time[loop], vol[loop] + shift); assertEquals("Implied strike: derivative volatility", (strikeV - strike) / shift, derivatives[3], 1.0E-3); } }
@Test(enabled = false) public void impliedStrikePerformanceDerivatives() { final double[] delta = new double[] {0.25, -0.25, 0.49 }; final boolean[] cap = new boolean[] {true, false, true }; final double[] forward = new double[] {104, 100, 10 }; final double[] time = new double[] {2.5, 5.0, 0.5 }; final double[] vol = new double[] {0.25, 0.10, 0.50 }; final double[] derivatives = new double[4]; long startTime, endTime; final int nbTest = 100000; @SuppressWarnings("unused") double strike; startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { for (int loop = 0; loop < delta.length; loop++) { strike = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop], time[loop], vol[loop]); } } endTime = System.currentTimeMillis(); System.out.println(nbTest + " implied strike: " + (endTime - startTime) + " ms"); startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { for (int loop = 0; loop < delta.length; loop++) { strike = BlackFormulaRepository.impliedStrike(delta[loop], cap[loop], forward[loop], time[loop], vol[loop], derivatives); } } endTime = System.currentTimeMillis(); System.out.println(nbTest + " implied strike + derivatives : " + (endTime - startTime) + " ms"); }