/** * General method when you wish to compute the expected variance from a log-moneyness * parametrised surface to within a certain tolerance * * @param surface log-moneyness parametrised volatility surface * @return expected variance */ @SuppressWarnings("synthetic-access") @Override public Double visitLogMoneyness(final BlackVolatilitySurfaceLogMoneyness surface) { final double atmVol = surface.getVolatilityForLogMoneyness(_t, 0.0); if (_t < 1e-4) { return atmVol * atmVol; } final double rootT = Math.sqrt(_t); final double invNorTol = NORMAL.getInverseCDF(_tol); final Function1D<Double, Double> integrand = getLogMoneynessIntegrand(surface); double putPart; if (_addResidual) { putPart = _integrator.integrate(integrand, Math.log(_lowStrikeCutoff / _f), 0.0); putPart += _residual; } else { final double l = invNorTol * atmVol * rootT; // initial estimate of lower limit putPart = _integrator.integrate(integrand, l, 0.0); double rem = integrand.evaluate(l); double error = rem / putPart; int step = 1; while (error > _tol) { putPart += _integrator.integrate(integrand, (step + 1) * l, step * l); step++; rem = integrand.evaluate((step + 1) * l); error = rem / putPart; } putPart += rem; // add on the (very small) remainder estimate otherwise we'll always underestimate // variance } final double u = _f * Math.exp(-invNorTol * atmVol * rootT); // initial estimate of upper limit double callPart = _integrator.integrate(integrand, 0.0, u); double rem = integrand.evaluate(u); double error = rem / callPart; int step = 1; while (error > _tol) { callPart += _integrator.integrate(integrand, step * u, (1 + step) * u); step++; rem = integrand.evaluate((1 + step) * u); error = rem / putPart; } // callPart += rem; // don't add on the remainder estimate as it is very conservative, and likely too large return 2 * (putPart + callPart) / _t; }
@Test public void test() { for (int i = 0; i < 10; i++) { final double x = A + (B - A) * RANDOM.nextDouble(); final double y = 5 * NORMAL.nextRandom(); assertRoundTrip(RANGE_LIMITS, x); assertReverseRoundTrip(RANGE_LIMITS, y); assertGradient(RANGE_LIMITS, x); assertInverseGradient(RANGE_LIMITS, y); assertGradientRoundTrip(RANGE_LIMITS, x); } }
/** * @param token The token to analyse. * @return The text size corresponding to the given latex token or null. * @since 3.0 */ public static TextSize getTextSizeFromToken(final String token) { TextSize textSize; if (TINY.equals(token)) textSize = TINY; else if (FOOTNOTE.equals(token)) textSize = FOOTNOTE; else if (HUGE1.equals(token)) textSize = HUGE1; else if (HUGE2.equals(token)) textSize = HUGE2; else if (LARGE1.equals(token)) textSize = LARGE1; else if (LARGE2.equals(token)) textSize = LARGE2; else if (LARGE3.equals(token)) textSize = LARGE3; else if (NORMAL.equals(token)) textSize = NORMAL; else if (SCRIPT.equals(token)) textSize = SCRIPT; else if (SMALL.equals(token)) textSize = SMALL; else textSize = null; return textSize; }
@SuppressWarnings("synthetic-access") @Override public Double visitStrike(final BlackVolatilitySurfaceStrike surface) { final double atmVol = surface.getVolatility(_t, _f); if (_t < 1e-4) { return atmVol * atmVol; } final double rootT = Math.sqrt(_t); final double invNorTol = NORMAL.getInverseCDF(_tol); final Function1D<Double, Double> integrand = getStrikeIntegrand(surface); final Function1D<Double, Double> remainder = new Function1D<Double, Double>() { @Override public Double evaluate(final Double strike) { if (strike == 0) { return 0.0; } final boolean isCall = strike >= _f; final double vol = surface.getVolatility(_t, strike); final double otmPrice = BlackFormulaRepository.price(_f, strike, _t, vol, isCall); final double res = (isCall ? otmPrice / strike : otmPrice / 2 / strike); return res; } }; double putPart; if (_addResidual) { putPart = _integrator.integrate(integrand, _lowStrikeCutoff, _f); putPart += _residual; } else { double l = _f * Math.exp(invNorTol * atmVol * rootT); // initial estimate of lower limit putPart = _integrator.integrate(integrand, l, _f); double rem = remainder.evaluate(l); double error = rem / putPart; while (error > _tol) { l /= 2.0; putPart += _integrator.integrate(integrand, l, 2 * l); rem = remainder.evaluate(l); error = rem / putPart; } putPart += rem; // add on the (very small) remainder estimate otherwise we'll always underestimate // variance } double u = _f * Math.exp(-invNorTol * atmVol * rootT); // initial estimate of upper limit double callPart = _integrator.integrate(integrand, _f, u); double rem = remainder.evaluate(u); double error = rem / callPart; while (error > _tol) { callPart += _integrator.integrate(integrand, u, 2 * u); u *= 2.0; rem = remainder.evaluate(u); error = rem / putPart; } // callPart += rem/2.0; // don't add on the remainder estimate as it is very conservative, and likely too large return 2 * (putPart + callPart) / _t; }