Exemple #1
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European options with dividend. Vega = d[price]/d[vol].
        /// </summary>
        /// <returns>option vega</returns>
        public static double BlackScholesVega(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag)
        {
            //Put and call values are the same. I've left putCallFlag in parameters so that all the Black Scholes formulas have the same argument list.
            double sqrtT = Math.Sqrt(yearsToExpiry);
            double d1    = (Math.Log(underlyingPrice / strike) + (riskFreeRate - dividendYield + 0.5 * vol * vol) * yearsToExpiry) / (vol * sqrtT);
            double n1    = Distributions.StandardNormalProbabilityDensityFunction(d1);

            return(underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) * n1 * sqrtT);
        }
Exemple #2
0
        /// <summary>
        /// Used for BlackScholesImpliedVol
        /// </summary>
        /// <returns>price of option</returns>
        private static double BlackScholesPriceAndVega(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag, out double vega)
        {
            double sqrtT = Math.Sqrt(yearsToExpiry);
            double d1    = (Math.Log(underlyingPrice / strike) + (riskFreeRate - dividendYield + 0.5 * vol * vol) * yearsToExpiry) / (vol * sqrtT);
            double d2    = d1 - vol * sqrtT;

            if (putCallFlag == PutCallFlag.Call)
            {
                double N1  = Distributions.StandardNormalCumulativeDistributionFunction(d1);
                double N2  = Distributions.StandardNormalCumulativeDistributionFunction(d2);
                double nn1 = Distributions.StandardNormalProbabilityDensityFunction(d1);

                vega = underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) * nn1 * sqrtT;
                return(N1 * underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) - N2 * strike * Math.Exp(-riskFreeRate * yearsToExpiry));
            }
            double Nn1 = Distributions.StandardNormalCumulativeDistributionFunction(-d1);
            double Nn2 = Distributions.StandardNormalCumulativeDistributionFunction(-d2);
            double n1  = Distributions.StandardNormalProbabilityDensityFunction(d1);

            vega = underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) * n1 * sqrtT;
            return(Nn2 * strike * Math.Exp(-riskFreeRate * yearsToExpiry) - Nn1 * underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry));
        }
Exemple #3
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European options with dividend. Convexity = second derivative of price with respect to interest rate.
        /// Not considered a standard Greek, but can be useful for portfolios with fixed income instruments and equity options.
        /// </summary>
        /// <returns>option interest rate convexity</returns>
        public static double BlackScholesRateConvexity(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag)
        {
            double sqrtT = Math.Sqrt(yearsToExpiry);
            double d2    = (Math.Log(underlyingPrice / strike) + (riskFreeRate - dividendYield - 0.5 * vol * vol) * yearsToExpiry) / (vol * sqrtT);
            double N2    = Distributions.StandardNormalCumulativeDistributionFunction(d2);
            double n2    = Distributions.StandardNormalProbabilityDensityFunction(d2);

            double rho, convexity;

            if (putCallFlag == PutCallFlag.Call)
            {
                rho       = yearsToExpiry * strike * Math.Exp(-riskFreeRate * yearsToExpiry) * N2;
                convexity = rho * ((n2 * sqrtT) / (N2 * vol) - yearsToExpiry);
            }
            else
            {
                rho = -yearsToExpiry *strike *Math.Exp(-riskFreeRate *yearsToExpiry) * (1 - N2);

                convexity = -rho * ((n2 * sqrtT) / ((1 - N2) * vol) + yearsToExpiry);
            }
            return(convexity);
        }
Exemple #4
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European option.
        /// Returns the price, and outputs the Greeks.
        /// Not as elegant looking, but faster than calculating each separately.
        /// </summary>
        public static double BlackScholesPriceAndGreeks(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag, out double delta, out double gamma, out double vega, out double theta, out double rho, out double convexity)
        {
            //setting dividendYield = 0 gives the classic Black Scholes model
            //setting dividendYield = foreign risk-free rate gives a model for European currency options, see Garman and Kohlhagen (1983)

            double sqrtT = Math.Sqrt(yearsToExpiry);
            double d1    = (Math.Log(underlyingPrice / strike) + (riskFreeRate - dividendYield + 0.5 * vol * vol) * yearsToExpiry) / (vol * sqrtT);
            double d2    = d1 - vol * sqrtT;
            double N1    = Distributions.StandardNormalCumulativeDistributionFunction(d1);
            double N2    = Distributions.StandardNormalCumulativeDistributionFunction(d2);
            double n1    = Distributions.StandardNormalProbabilityDensityFunction(d1);
            double n2    = Distributions.StandardNormalProbabilityDensityFunction(d2);

            double eNegRiskFreeRateTimesYearsToExpiry = Math.Exp(-riskFreeRate * yearsToExpiry);
            double eNegDivYieldYearsToExpiry          = Math.Exp(-dividendYield * yearsToExpiry);

            double price;

            if (putCallFlag == PutCallFlag.Call)
            {
                price = N1 * underlyingPrice * eNegDivYieldYearsToExpiry - N2 * strike * eNegRiskFreeRateTimesYearsToExpiry;
            }
            else
            {
                price = (1 - N2) * strike * eNegRiskFreeRateTimesYearsToExpiry - (1 - N1) * underlyingPrice * eNegDivYieldYearsToExpiry;
            }

            if (putCallFlag == PutCallFlag.Call)
            {
                delta = eNegDivYieldYearsToExpiry * N1;
            }
            else
            {
                delta = eNegDivYieldYearsToExpiry * (N1 - 1.0);
            }

            gamma = eNegDivYieldYearsToExpiry * n1 / (underlyingPrice * vol * sqrtT);
            vega  = underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) * n1 * sqrtT;

            if (putCallFlag == PutCallFlag.Call)
            {
                rho = yearsToExpiry * strike * eNegRiskFreeRateTimesYearsToExpiry * N2;
            }
            else
            {
                rho = -yearsToExpiry * strike * eNegRiskFreeRateTimesYearsToExpiry * (1 - N2);
            }

            double a = -underlyingPrice * eNegDivYieldYearsToExpiry * n1 * vol / (2.0 * sqrtT);
            double b = dividendYield * underlyingPrice * eNegDivYieldYearsToExpiry;

            if (putCallFlag == PutCallFlag.Call)
            {
                theta = a + b * N1 - riskFreeRate * strike * eNegRiskFreeRateTimesYearsToExpiry * N2;
            }
            else
            {
                theta = a - b * (1 - N1) + riskFreeRate * strike * eNegRiskFreeRateTimesYearsToExpiry * (1 - N2);
            }

            if (putCallFlag == PutCallFlag.Call)
            {
                convexity = rho * ((n2 * sqrtT) / (N2 * vol) - yearsToExpiry);
            }
            else
            {
                convexity = -rho * ((n2 * sqrtT) / ((1 - N2) * vol) + yearsToExpiry);
            }

            return(price);
        }
Exemple #5
0
        /// <summary>
        /// Barone Adesi and Whaley price approximation for an American option
        /// </summary>
        /// <returns>price of the option</returns>
        public static double BaroneAdesiWhaley(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag)
        {
            if (dividendYield <= 0 && putCallFlag == PutCallFlag.Call)
            {
                return(BlackScholesPrice(strike, underlyingPrice, yearsToExpiry, vol, riskFreeRate, dividendYield, putCallFlag));
            }

            const double accuracy      = 0.00001;
            const double maxIterations = 500;

            double volSqrd = vol * vol;
            double sqrtT   = Math.Sqrt(yearsToExpiry);
            double m       = 2.0 * riskFreeRate / volSqrd;
            double n       = 2.0 * (riskFreeRate - dividendYield) / volSqrd;
            double k       = 1.0 - Math.Exp(-riskFreeRate * yearsToExpiry);
            double a       = Math.Sqrt(Math.Pow((n - 1), 2.0) + (4.0 * m / k));
            double q;

            if (putCallFlag == PutCallFlag.Call)
            {
                q = 0.5 * (1 - n + a);
            }
            else
            {
                q = 0.5 * (1 - n - a);
            }

            //calculate seed value
            double undPriceSeed;

            if (putCallFlag == PutCallFlag.Call)
            {
                double b = -(n - 1.0) + Math.Sqrt(Math.Pow((n - 1), 2.0) + 4.0 * m);
                double undPriceStarInf = strike / (1.0 - 2.0 / b);
                double h = -((riskFreeRate - dividendYield) * yearsToExpiry + 2.0 * vol * sqrtT) * (strike / (undPriceStarInf - strike));
                undPriceSeed = strike + (undPriceStarInf - strike) * (1.0 - Math.Exp(h));
            }
            else
            {
                double b = -(n - 1.0) - Math.Sqrt(Math.Pow((n - 1), 2.0) + 4.0 * m);
                double undPriceStarInf = strike / (1.0 - 2.0 / b);
                double h = ((riskFreeRate - dividendYield) * yearsToExpiry - 2.0 * vol * sqrtT) * (strike / (strike - undPriceStarInf));
                undPriceSeed = undPriceStarInf + (strike - undPriceStarInf) * Math.Exp(h);
            }

            //Newton-Raphson
            int    nIterations = 0;
            double undPriceI   = undPriceSeed;
            double g           = 1.0;
            double gPrime      = 1.0;

            while ((Math.Abs(g) > accuracy) && (Math.Abs(gPrime) > accuracy) && (nIterations++ < maxIterations) && (undPriceI > 0.0))
            {
                double bsPrice = BlackScholesPrice(strike, undPriceI, yearsToExpiry, vol, riskFreeRate, dividendYield, putCallFlag);
                double d1      = (Math.Log(undPriceI / strike) + (riskFreeRate - dividendYield + 0.5 * volSqrd) * yearsToExpiry) / (vol * sqrtT);
                if (putCallFlag == PutCallFlag.Call)
                {
                    g      = (1.0 - 1.0 / q) * undPriceI - strike - bsPrice + (1.0 / q) * undPriceI * Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(d1);
                    gPrime = (1.0 - 1.0 / q) * (1.0 - Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(d1))
                             + (1.0 / q) * Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalProbabilityDensityFunction(d1) * (1.0 / (vol * sqrtT));
                }
                else
                {
                    g      = strike - undPriceI - bsPrice + (undPriceI / q) * (1.0 - Math.Exp(-dividendYield * yearsToExpiry));
                    gPrime = (1.0 / q - 1.0) * (1.0 - Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(-d1))
                             + (1.0 / q) * Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalProbabilityDensityFunction(-d1) * (1.0 / (vol * sqrtT));
                }
                undPriceI = undPriceI - (g / gPrime);
            }

            double undPriceStar;

            if (Math.Abs(g) > accuracy)
            {
                //undPriceStar = undPriceSeed; //could continue with this value, currently throws exception
                throw new Exception("Newton-Raphson did not converge");
            }
            undPriceStar = undPriceI;

            double price;
            double bsPrice2 = BlackScholesPrice(strike, underlyingPrice, yearsToExpiry, vol, riskFreeRate, dividendYield, putCallFlag);

            if (putCallFlag == PutCallFlag.Call && underlyingPrice >= undPriceStar)
            {
                price = underlyingPrice - strike;
            }
            else if (putCallFlag == PutCallFlag.Put && underlyingPrice <= undPriceStar)
            {
                price = strike - underlyingPrice;
            }
            else
            {
                double d1 = (Math.Log(undPriceStar / strike) + (riskFreeRate - dividendYield + 0.5 * volSqrd) * yearsToExpiry) / (vol * sqrtT);
                if (putCallFlag == PutCallFlag.Put)
                {
                    d1 *= -1.0;
                }
                double A = (1.0 - Math.Exp(-dividendYield * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(d1)) * (undPriceStar / q);
                if (putCallFlag == PutCallFlag.Put)
                {
                    A *= -1.0;
                }
                price = bsPrice2 + A * Math.Pow((underlyingPrice / undPriceStar), q);
            }
            return(Math.Max(price, bsPrice2)); // know value will never be less than BS value
        }
Exemple #6
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European options with dividend. Theta = -d[price]/d[yearsToExpiry].
        /// </summary>
        /// <returns>option theta</returns>
        public static double BlackScholesTheta(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag)
        {
            double sqrtT = Math.Sqrt(yearsToExpiry);
            double d1    = (Math.Log(underlyingPrice / strike) + (riskFreeRate - dividendYield + 0.5 * vol * vol) * yearsToExpiry) / (vol * sqrtT);
            double d2    = d1 - vol * sqrtT;
            double a     = -underlyingPrice *Math.Exp(-dividendYield *yearsToExpiry) * Distributions.StandardNormalProbabilityDensityFunction(d1) * vol / (2.0 * sqrtT);

            double b = dividendYield * underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry);

            if (putCallFlag == PutCallFlag.Call)
            {
                return(a + b * Distributions.StandardNormalCumulativeDistributionFunction(d1) - riskFreeRate * strike * Math.Exp(-riskFreeRate * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(d2));
            }
            return(a - b * Distributions.StandardNormalCumulativeDistributionFunction(-d1) + riskFreeRate * strike * Math.Exp(-riskFreeRate * yearsToExpiry) * Distributions.StandardNormalCumulativeDistributionFunction(-d2));
        }