Exemplo n.º 1
0
        public void Implied_VolSample_Test()
        {
            const double mat    = 1.0;
            const double strike = 1.50;
            var          vols   = GridUtils.RegularGrid(0.015, 2.0, 100);

            foreach (double vol in vols)
            {
                var option     = BlackScholesOption.Price(1.0, strike, vol, mat, 1);
                var impliedVol = BlackScholesOption.ImpliedVol(option, 1.0, strike, mat, 1);

                var errRelative = (impliedVol - vol) / vol;
                Assert.IsTrue(Math.Abs(errRelative) < 6 * DoubleUtils.MachineEpsilon);
            }
        }
Exemplo n.º 2
0
        public void ImpliedVol_MoneynessSample_Test()
        {
            const double mat         = 0.5;
            const double vol         = 0.253251;
            var          moneynesses = GridUtils.RegularGrid(-5.0, 5.0, 100);

            foreach (double m in moneynesses)
            {
                var strike     = Math.Exp(m);
                var option     = BlackScholesOption.Price(1.0, strike, vol, mat, m > 0 ? 1 : -1);
                var impliedVol = BlackScholesOption.ImpliedVol(option, 1.0, strike, mat, m > 0 ? 1 : -1);

                var errRelative = (impliedVol - vol) / vol;
                Assert.IsTrue(Math.Abs(errRelative) < 6 * DoubleUtils.MachineEpsilon);
            }
        }
Exemplo n.º 3
0
        public static object BlackImpliedVol(double forward, double strike, double maturity, double price, string optionType)
        {
            return(FunctionRunnerUtils.Run("BlackImpliedVol", () =>
            {
                double q;
                switch (optionType.Trim().ToLower())
                {
                case "call":
                    q = 1.0;
                    break;

                case "put":
                    q = -1.0;
                    break;

                default:
                    throw new Exception(string.Format("Unknow option type : {0}", optionType));
                }
                return BlackScholesOption.ImpliedVol(price, forward, strike, maturity, q);
            }));
        }
        /// <summary>
        /// Implied volatility from option price. (Inversion of the two step quadrature formula.)
        /// </summary>
        /// <param name="maturity">option maturity</param>
        /// <param name="strike">option strike</param>
        /// <param name="price">option price </param>
        /// <param name="q">option type : 1 for call, -1 for put</param>
        /// <returns></returns>
        public double ImpliedVol(double maturity, double strike, double price, double q)
        {
            //Proxy using Lehman Formula
            double proxyFwd, proxyDk;

            affineDivUtils.LehmanProxy(maturity, spot, out proxyFwd, out proxyDk);
            double lehmanTargetVol = BlackScholesOption.ImpliedVol(price, proxyFwd, strike + proxyDk, maturity, q);

            var pricer = new BsDivPrice(maturity, strike, spot, affineDivUtils, quadPoints, quadWeights);
            Func <double, double> volToLehmanVolErr =
                v => BlackScholesOption.ImpliedVol(pricer.Price(v, q), proxyFwd, strike + proxyDk, maturity, q) - lehmanTargetVol;

            //Solve
            double v1   = lehmanTargetVol;
            double err1 = volToLehmanVolErr(v1);

            double v2   = lehmanTargetVol - err1;
            double err2 = volToLehmanVolErr(v2);
            double v3   = v1 - err1 * (v2 - v1) / (err2 - err1);

            if (Math.Abs(v3 - v2) < v2 * 1.0e-13)
            {
                return(v3);
            }
            double err3 = volToLehmanVolErr(v3);
            double v4   = RootUtils.TrinomRoot(v1, v2, v3, err1, err2, err3);

            if (Math.Abs(v4 - v3) < v3 * 1.0e-13)
            {
                return(v4);
            }
            double err4 = volToLehmanVolErr(v4);
            double v5   = RootUtils.TrinomRoot(v2, v3, v4, err2, err3, err4);

            return(v5);
        }
        public double[] CalibrateVol(double[] maturities, double[] targetPrices, double[] strikes, double[] optionTypes)
        {
            Contract.Requires(EnumerableUtils.IsSorted(maturities));
            Contract.Requires(maturities.Length == strikes.Length &&
                              strikes.Length == targetPrices.Length &&
                              targetPrices.Length == optionTypes.Length);

            double[] variances = new double[maturities.Length + 1];
            double[] varPillars = new[] { 0.0 }.Concat(maturities).ToArray();

            double[] calibVols = new double[maturities.Length];
            for (int step = 0; step < maturities.Length; step++)
            {
                var maturity    = maturities[step];
                var strike      = strikes[step];
                var targetPrice = targetPrices[step];
                var q           = optionTypes[step];

                //Proxy using Lehman Formula
                double proxyFwd, proxyDk;
                affineDivUtils.LehmanProxy(maturity, spot, out proxyFwd, out proxyDk);
                double lehmanTargetVol = BlackScholesOption.ImpliedVol(targetPrice, proxyFwd, strike + proxyDk, maturity, q);

                var pricer = new BsDivPrice(maturities[step], strikes[step], spot, affineDivUtils, quadPoints, quadWeights);
                Func <double, double> volToLehmanVolErr = v =>
                {
                    variances[1 + step] = v * v * maturity;
                    var varFunc = RrFunctions.LinearInterpolation(varPillars, variances);

                    Func <double, double> volFunc = t => Math.Sqrt(varFunc.Eval(t) / t);
                    var price = pricer.Price(volFunc, q);
                    return(BlackScholesOption.ImpliedVol(price, proxyFwd, strike + proxyDk, maturity, q) - lehmanTargetVol);
                };//TODO use a cache


                //Bracket & Solve
                double v1 = lehmanTargetVol;
                double v2;
                if (step == 0)
                {
                    v2 = lehmanTargetVol - volToLehmanVolErr(lehmanTargetVol);
                }
                else
                {
                    var volIfZeroVolOnStep = Math.Sqrt(calibVols[step - 1] * calibVols[step - 1] * maturities[step - 1] / maturities[step]);
                    var minError           = volToLehmanVolErr(volIfZeroVolOnStep);
                    if (minError > 0.0) //saturation case
                    {
                        calibVols[step]     = volIfZeroVolOnStep;
                        variances[1 + step] = volIfZeroVolOnStep * volIfZeroVolOnStep * maturity;
                        continue;
                    }
                    v2 = volIfZeroVolOnStep;
                }

                if (!RootUtils.Bracket(volToLehmanVolErr, v1, v2, out v1, out v2))
                {
                    throw new Exception("Failed to inverse vol");
                }
                var impliedVol = RootUtils.Brenth(volToLehmanVolErr, v1, v2, 1.0e-10, 2.0 * DoubleUtils.MachineEpsilon, 10);

                calibVols[step]     = impliedVol;
                variances[1 + step] = impliedVol * impliedVol * maturity;
            }

            return(calibVols);
        }