예제 #1
0
        private double solveByBisection(double optionPrice, double lowerSigma, double upperSigma)
        {
            BisectionSingleRootFinder rootFinder = new BisectionSingleRootFinder(VOL_TOL);

            System.Func <double, double> func = (double?volatility) =>
            {
                double trialPrice = priceFunc.apply(volatility);
                return(trialPrice / optionPrice - 1.0);
            };
            return(rootFinder.getRoot(func, lowerSigma, upperSigma).Value);
        }
예제 #2
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Computes the implied volatility.
        /// <para>
        /// If the volatility data is not zero, it is used as a starting point for the volatility search.
        /// </para>
        /// <para>
        /// Note that the 'numeraire' is a simple multiplier and is the responsibility of the caller.
        ///
        /// </para>
        /// </summary>
        /// <param name="optionPrice">  the price of the option </param>
        /// <param name="forward">  the forward value of the underlying </param>
        /// <param name="strike">  the strike </param>
        /// <param name="timeToExpiry">  the time to expiry </param>
        /// <param name="initialNormalVol">  the normal volatility used to start the search </param>
        /// <param name="numeraire">  the numeraire </param>
        /// <param name="putCall">  whether it is put or call </param>
        /// <returns> the implied volatility </returns>
        public static double impliedVolatility(double optionPrice, double forward, double strike, double timeToExpiry, double initialNormalVol, double numeraire, PutCall putCall)
        {
            double intrinsicPrice = numeraire * Math.Max(0, (putCall.Call ? 1 : -1) * (forward - strike));

            ArgChecker.isTrue(optionPrice > intrinsicPrice || DoubleMath.fuzzyEquals(optionPrice, intrinsicPrice, 1e-6), "Option price (" + optionPrice + ") less than intrinsic value (" + intrinsicPrice + ")");
            if (System.BitConverter.DoubleToInt64Bits(optionPrice) == Double.doubleToLongBits(intrinsicPrice))
            {
                return(0d);
            }
            double           sigma     = (Math.Abs(initialNormalVol) < 1e-10 ? 0.3 * forward : initialNormalVol);
            double           maxChange = 0.5 * forward;
            ValueDerivatives price     = priceAdjoint(forward, strike, timeToExpiry, sigma, numeraire, putCall);
            double           vega      = price.getDerivative(1);
            double           change    = (price.Value - optionPrice) / vega;
            double           sign      = Math.Sign(change);

            change = sign * Math.Min(maxChange, Math.Abs(change));
            if (change > 0 && change > sigma)
            {
                change = sigma;
            }
            int count = 0;

            while (Math.Abs(change) > EPS)
            {
                sigma -= change;
                price  = priceAdjoint(forward, strike, timeToExpiry, sigma, numeraire, putCall);
                vega   = price.getDerivative(1);
                change = (price.Value - optionPrice) / vega;
                sign   = Math.Sign(change);
                change = sign * Math.Min(maxChange, Math.Abs(change));
                if (change > 0 && change > sigma)
                {
                    change = sigma;
                }
                if (count++ > MAX_ITERATIONS)
                {
                    BracketRoot bracketer = new BracketRoot();
                    BisectionSingleRootFinder    rootFinder = new BisectionSingleRootFinder(EPS);
                    System.Func <double, double> func       = (double?volatility) =>
                    {
                        return(numeraire * NormalFormulaRepository.price(forward, strike, timeToExpiry, volatility.Value, putCall) - optionPrice);
                    };
                    double[] range = bracketer.getBracketedPoints(func, 0d, 10d);
                    return(rootFinder.getRoot(func, range[0], range[1]).Value);
                }
            }
            return(sigma);
        }