Пример #1
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European options with dividend. Delta = d[price]/d[underlyingPrice].
        /// </summary>
        /// <returns>option delta</returns>
        public static double BlackScholesDelta(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 N1    = Distributions.StandardNormalCumulativeDistributionFunction(d1);

            if (putCallFlag == PutCallFlag.Call)
            {
                return(Math.Exp(-dividendYield * yearsToExpiry) * N1);
            }
            return(Math.Exp(-dividendYield * yearsToExpiry) * (N1 - 1.0));
        }
Пример #2
0
        /// <summary>
        /// Black, Scholes, Merton formula (1973) for European options with dividend. Rho = d[price]/d[riskFreeRate].
        /// </summary>
        /// <returns>option rho</returns>
        public static double BlackScholesRho(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);

            if (putCallFlag == PutCallFlag.Call)
            {
                double N2 = Distributions.StandardNormalCumulativeDistributionFunction(d2);
                return(yearsToExpiry * strike * Math.Exp(-riskFreeRate * yearsToExpiry) * N2);
            }
            double Nn2 = Distributions.StandardNormalCumulativeDistributionFunction(-d2);

            return(-yearsToExpiry *strike *Math.Exp(-riskFreeRate *yearsToExpiry) * Nn2);
        }
Пример #3
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));
        }
Пример #4
0
        /// <summary>
        /// Used in Bjerksund and Stensland formula
        /// </summary>
        private static double BjerksundStenslandPhi(double s, double t, double gamma, double h, double i, double r, double b, double v)
        {
            double lambda = (-r + gamma * b + 0.5 * gamma * (gamma - 1) * v * v) * t;
            double d1a    = Math.Log(s / h);
            double d1b    = (b + (gamma - 0.5) * v * v) * t;
            double d1     = -(d1a + d1b); //-(Math.Log(s / h) + (b + (gamma - 0.5) * v * v) * t) ;
            double d2     = (v * Math.Sqrt(t));
            double d      = d1 / d2;      //-(Math.Log(s / h) + (b + (gamma - 0.5) * v * v) * t) / (v * Math.Sqrt(t));
            double kappa  = 2 * b / (v * v) + 2 * gamma - 1;
            double n1     = Distributions.StandardNormalCumulativeDistributionFunction(d);
            double n2     = Distributions.StandardNormalCumulativeDistributionFunction(d - 2.0 * Math.Log(i / s) / (v * Math.Sqrt(t)));
            double p1     = Math.Exp(lambda);
            double p2     = Math.Pow(s, gamma);
            double p3     = n2 == 0 ? n1 : n1 - Math.Pow(i / s, kappa) * n2;
            double phi    = p1 * p2 * p3;

            return(phi);
        }
Пример #5
0
        /// <summary>
        /// Gereralized Black, Scholes, Merton formula (1973) for European options with dividend
        /// </summary>
        /// <returns>price of the option</returns>
        public static double BlackScholesPrice(double strike, double underlyingPrice, double yearsToExpiry, double vol, double riskFreeRate, double dividendYield, PutCallFlag putCallFlag)
        {
            //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;

            if (putCallFlag == PutCallFlag.Call)
            {
                double N1 = Distributions.StandardNormalCumulativeDistributionFunction(d1);
                double N2 = Distributions.StandardNormalCumulativeDistributionFunction(d2);
                return(N1 * underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry) - N2 * strike * Math.Exp(-riskFreeRate * yearsToExpiry));
            }
            double Nn1 = Distributions.StandardNormalCumulativeDistributionFunction(-d1);
            double Nn2 = Distributions.StandardNormalCumulativeDistributionFunction(-d2);

            return(Nn2 * strike * Math.Exp(-riskFreeRate * yearsToExpiry) - Nn1 * underlyingPrice * Math.Exp(-dividendYield * yearsToExpiry));
        }
Пример #6
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));
        }
Пример #7
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);
        }
Пример #8
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);
        }
Пример #9
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
        }