How to Derive Options Greeks from the Black-Scholes Formula

by | C++, Finance, Programming, Python, R, Tips

Options Greeks are a set of quantities representing an option’s price sensitivity to its underlying parameters. Each of them measures a different dimension of the risk in an option position.

They fall out elegantly from derivatives of the Black-Scholes options pricing formula.

This tutorial will go through the Options Greeks, and how to derive them from derivatives of the Black-Scholes option pricing formula for call and put options.

Then we will go through how to create functions to calculate the Options Greeks in Python, C++, and R with code examples.


What is the Black-Scholes Options Pricing Formula

The Black-Scholes or Black-Scholes-Merton model is a financial mathematical equation for pricing options contracts and other derivatives.

Using the Black-Scholes model, the price of a European call option is calculated using the formula:

$$C= S_{0}N(d_{1})~- Xe^{-r\tau}N(d_{2}) $$

and for the price of a European put option:

$$P= ~- Xe^{-r\tau}N(d_{2}) ~- S_{0}N(-d_{1})$$

With:

$$d_{1} = \frac{\text{ln}\frac{S_{0}}{X} + (r + \sigma^{2}/2)*\tau}{\sigma\sqrt{\tau}}, \qquad d_{2} = \frac{\text{ln}\frac{S_{0}}{X} + (r – \sigma^{2}/2)*\tau}{\sigma\sqrt{\tau}} = d_{1} – \sigma\sqrt{\tau}$$

Where:

  • C = price of the call option
  • S0 = price of the underlying stock
  • X = option exercise price or strike price
  • r = risk-free interest rate
  • 𝛕 = time until expiration (maturity)
  • 𝞂 = the volatility of the underlying asset.

N represents the cumulative distribution function for a normal (Gaussian) distribution, which we can understand as “the probability that a random variable is less or equal to its input for a normal distribution”.

We can think of the two terms in the sum as the current price in the stock weighted by the probability of exercising the option to buy the stock minus the discounted price of exercising the option weighted by the probability of exercising the option. In other words, what you will pay minus what you will receive (Introduction to the Black-Scholes formula, Khan Academy 2013).

The Option Greeks Explained

Option Greeks are a set of quantities representing an option’s price sensitivity to its underlying parameters. Each of them measures a different dimension of the risk in an option position.

Delta (Δ)

Delta measures the rate of change of option value with respect to changes in the underlying asset’s price

$$\Delta = \frac{\partial V}{\partial S_{0}} $$

Gamma (Γ)

Gamma measures the rate of change in Delta with respect to changes in the underlying price.

$$\Gamma = \frac{\partial \Delta}{\partial S_{0}} $$

Theta (ϴ)

Theta measures the sensitivity of the option value to the passage of time.

$$\Theta = -\frac{\partial V}{\partial \tau} $$

Vega (V)

Vega is the rate of change of the option price with respect to the underlying stock’s volatility.

$$\nu = \frac{\partial V}{\partial \sigma} $$

For further reading on how volatility is found, go to the article: How to Calculate Implied Volatility in Python.

Rho (ρ)

Rho is the rate of change of the option price with respect to the interest rate.

$$\rho = \frac{\partial V}{\partial r} $$

Where V denotes the option’s value, either C for the call option or P for the put option.

Options Greeks Expressions

Taking the Black-Scholes Formulae for call and put option pricing as follows:

$$ C= S_{0}N(d_{1}) ~- Xe^{-rt}N(d_{2}), \qquad P= -S_{0}N(-d_{1}) ~- Xe^{-rt}N(d_{2})$$

The expressions for the Options Greeks can be derived as follows:

Call option (C): $$ \Delta = \frac{\partial C}{\partial S_{0}} = N(d_{1})$$ $$ \Theta = -\frac{\partial C}{\partial \tau} = -rXe^{-r\tau}N(d_{2}) ~- \frac{\sigma}{2\sqrt{\tau}}S_{0}n(d_{1})$$ $$ \Gamma = \frac{\partial \Delta}{\partial S_{0}} = \frac{1}{S_{0}\sigma\sqrt{\tau}}n(d_{1})$$ $$ \nu = \frac{\partial C}{\partial \sigma} = \sqrt{\tau}S_{0}n(d_{1}) $$ $$ \rho = \frac{\partial C}{\partial r} = \tau Xe^{-r\tau}N(d_{2}) $$ Put option (C): $$ \Delta = \frac{\partial P}{\partial S_{0}} = N(d_{1}) ~- 1$$ $$ \Theta = ~-\frac{\partial P}{\partial \tau} = ~- \frac{\sigma}{2\sqrt{\tau}}S_{0}n(d_{1}) + rXe^{-r\tau}N(-d_{2}) $$ $$ \Gamma = \frac{\partial \Delta}{\partial S_{0}} = \frac{1}{S_{0}\sigma\sqrt{\tau}}n(d_{1})$$ $$ \nu = \frac{\partial P}{\partial \sigma} = \sqrt{\tau}S_{0}n(d_{1}) $$ $$ \rho = \frac{\partial P}{\partial r} = -\tau Xe^{-r\tau}N(-d_{2}) $$

Calculate Options Greeks using Black-Scholes Formula in Python

Let’s go through how to calculate the Options Greeks in Python. First, we will import the necessary mathematical and statistical functions from math and scipy.stats. Then, we will define functions for the d1 and d2 variables, and the call and put options pricing.

from math import log, sqrt, pi, exp
from scipy.stats import norm

# Function for d1 variable 

def d1(S,K,T,r,sigma):

    return(log(S/K)+(r+sigma**2/2.)*T)/(sigma*sqrt(T))

# Function for d2 variable 

def d2(S,K,T,r,sigma):

    return d1(S,K,T,r,sigma)-sigma*sqrt(T)

# Function for Call option pricing using Black-Scholes

def bs_call(S,K,T,r,sigma):

    return S*norm.cdf(d1(S,K,T,r,sigma))-K*exp(-r*T)*norm.cdf(d2(S,K,T,r,sigma))

# Function for Put option pricing using Black-Scholes

def bs_put(S,K,T,r,sigma):

    return K*exp(-r*T)*norm.cdf(-1 * d2(S,K,T,r,sigma)) - S*norm.cdf(-1*d1(S,K,T,r,sigma))

Next, we will define the call Option Greeks using the expressions in the Options Greeks Expressions section.

# Function for Call Delta function

def call_delta(S, K, T, r, sigma):

    return norm.cdf(d1(S,K,T,r,sigma))

# Function for Call Theta function

def call_theta(S,K,T,r,sigma):

    theta_1 = -r*K*exp(-r*T)*norm.cdf(d2(S,K,T,r,sigma))

    theta_2 = sigma*S*norm.pdf(d1(S,K,T,r,sigma))/(2*sqrt(T))
     # Divide by 365 to get the change in option price per one calendar day, otherwise change would be per one year
    theta = (theta_1 - theta_2) / 365

    return theta

# Function for Call Gamma function

def call_gamma(S, K, T, r, sigma):

    return norm.pdf(d1(S,K,T,r,sigma))/(S*sigma*sqrt(T))

# Function for Call Vega function

def call_vega(S, K, T, r, sigma):

    return 0.01 * (sqrt(T)*S*norm.pdf(d1(S, K, T, r, sigma)))

# Function for Call Rho function

def call_rho(S, K, T, r, sigma):

    return 0.01 * (T*K*exp(-r*T)*norm.cdf(d2(S, K, T, r, sigma)))

Next, we will define the put Option Greeks using the expressions in the Options Greeks Expressions section.

# Function for Put Delta function

def put_delta(S, K, T, r, sigma):

    return norm.cdf(d1(S,K,T,r,sigma)) - 1

# Function for Put Theta function

def put_theta(S, K, T, r, sigma):

    theta_1 = -1*sigma*S*norm.pdf(d1(S,K,T,r,sigma))/(2*sqrt(T))

    theta_2 = r*K*exp(-r*T)*norm.cdf(-1*d2(S,K,T,r,sigma))
     # Divide by 365 to get the change in option price per one calendar day, otherwise change would be per one year

    theta = (theta_1 + theta_2) / 365

    return theta

# Function for Put Gamma function

def put_gamma(S, K, T, r, sigma):

    return norm.pdf(d1(S,K,T,r,sigma))/(S*sigma*sqrt(T))

# Function for Put Vega function

def put_vega(S, K, T, r, sigma):

    return 0.01 * (sqrt(T)*S*norm.pdf(d1(S, K, T, r, sigma)))

# Function for Put Rho function

def put_rho(S, K, T, r, sigma):

    return 0.01 * -1* (T*K*exp(-r*T)*norm.cdf(-1*d2(S, K, T, r, sigma)))

Now, we can define our main function, and set values for the price of the underlying stock, the strike price, the risk-free interest rate, volatility, and the time until expiration. We can then price the call and put options and calculate the Options Greeks.

if __name__ == '__main__':

    S = 110
    K = 100
    T = 1
    r = 0.04
    sigma = 0.2


    call = bs_call(S, K, T, r, sigma)
    delta = call_delta(S,K,T,r,sigma)
    gamma = call_gamma(S,K,T,r,sigma)
    theta = call_theta(S,K,T,r,sigma)
    rho = call_rho(S,K,T,r,sigma)
    vega = call_vega(S,K,T,r,sigma)

    put = bs_put(S, K, T, r, sigma)
    put_delta = put_delta(S,K,T,r,sigma)
    put_gamma = put_gamma(S,K,T,r,sigma)
    put_theta = put_theta(S,K,T,r,sigma)
    put_rho = put_rho(S,K,T,r,sigma)
    put_vega = put_vega(S,K,T,r,sigma)


    print('Call option price:', round(call,2))
    print('Call Delta: ', round(delta,3))
    print('Call Gamma: ', round(gamma,3))
    print('Call Theta: ', round(theta,3))
    print('Call Rho: ', round(rho,3))
    print('Call Vega: ', round(vega,3))
    print('===================================')
    print('Put option price:', round(put,2))
    print('Put Delta: ', round(put_delta,3))
    print('Put Gamma: ', round(put_gamma,3))
    print('Put Theta: ', round(put_theta,3))
    print('Put Rho: ', round(put_rho,3))
    print('Put Vega: ', round(put_vega,3))

Let’s run the code to see the result:

Call option price: 16.97
Call Delta:  0.781
Call Gamma:  0.013
Call Theta:  -0.016
Call Rho:  0.69
Call Vega:  0.325
===================================
Put option price: 3.05
Put Delta:  -0.219
Put Gamma:  0.013
Put Theta:  -0.006
Put Rho:  -0.271
Put Vega:  0.325

Calculate Options Greeks using Black-Scholes Formula in C++

Let’s go through how to calculate the Options Greeks in C++. First, we will define the Standard normal probability density function, cumulative distribution function, the d1,d2 variables, and the call and put option pricing formulae.

#include <iostream>
#include <cmath>
// Standard normal probability density function

double norm_pdf(const double& x) {

    return (1.0/(pow(2*M_PI,0.5)))*exp(-0.5*x*x);

}

// Standard normal cumulative distribution function

double normalCDF(double x) // Phi(-∞, x) aka N(x){

    return std::erfc(-x/std::sqrt(2))/2;

}

// d1 variable

double d_1(const double& S, const double& K, const double& r, const double& T, const double& sig){

    return (log(S/K) + (r + pow(sig,2)/2)*T) / (sig*(pow(T,0.5)));

}

// d1 variable

double d_2(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return (log(S/K) + (r - pow(sig,2)/2)*T) / (sig*(pow(T,0.5)));

}

// Function for Call option pricing using Black-Scholes

double call_price(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return S * normalCDF((d_1(S, K, r, T, sig))) - K*exp(-r*T)* normalCDF(d_2(S,K, r, T, sig));

}

// Function for Put option pricing using Black-Scholes

double put_price(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return -S * normalCDF(-d_1(S, K, r, T, sig)) + K*exp(-r*T)* normalCDF(-d_2(S,K, r, T, sig));

}

Next, let’s define functions for the call and put Option Greeks using the expressions in the Options Greeks Expressions section.

// Function for Call Delta 

double call_delta(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return normalCDF(d_1(S,K,r,T,sig));

}

// Function for Call Gamma 

double call_gamma(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return norm_pdf(d_1(S,K,r,T,sig))/(S*sig*pow(T,0.5));

}

// Function for Call Theta 

double call_theta(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    double theta_1 = -r*K*exp(-r*T)* normalCDF(d_2(S,K,r,T,sig));

    double theta_2 = sig*S* norm_pdf(d_1(S,K,r,T,sig))/(2*pow(T,0.5));
    // Divide by 365 to get the change in option price per one calendar day, otherwise change would be per one year

    double theta = (theta_1 - theta_2) / 365;

    return theta;

}

// Function for Call Rho 

double call_rho(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return 0.01 * (T * K * exp(-r * T)* normalCDF(d_2(S,K,r,T,sig)));

}

// Function for Call Vega 

double call_vega(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return 0.01 * (pow(T,0.5) * S * norm_pdf(d_1(S,K,r,T,sig)));

}
// Function for Put Delta 

double put_delta(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return normalCDF(d_1(S,K,r,T,sig)) - 1;

}

// Function for Put Gamma 

double put_gamma(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return norm_pdf(d_1(S,K,r,T,sig))/(S*sig*pow(T,0.5));

}

// Function for Put Theta 

double put_theta(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    double theta_1 = -1*sig*S* norm_pdf(d_1(S,K,r,T,sig))/(2*pow(T,0.5));

    double theta_2 = r*K*exp(-r*T)* normalCDF(-1*d_2(S,K,r,T,sig));
    // Divide by 365 to get the change in option price per one calendar day, otherwise change would be per one year

    double theta = (theta_1 + theta_2) / 365;

    return theta;

}

// Function for Put Rho 

double put_rho(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return 0.01 * -1 *(T * K * exp(-r * T)* normalCDF(-1* d_2(S,K,r,T,sig)));

}

// Function for Put Vega 

double put_vega(const double& S, const double& K, const double& r, const double& T, const double& sig) {

    return 0.01 * (pow(T,0.5) * S * norm_pdf(d_1(S,K,r,T,sig)));

}

Now, we can define our main function, and set values for the price of the underlying stock, the strike price, the risk-free interest rate, the volatility, and the time until expiration. We can then price the call and put options and calculate the Options Greeks.

int main() {

    // First we create the parameter list
    double S = 110.0;  // Option price
    double K = 100.0;  // Strike price
    double r = 0.04;   // Risk-free rate (5%)
    double sig = 0.2;    // Volatility of the underlying (20%)
    double T = 1.0;    // One year until expiry

    // Then we calculate the call/put values
    // double call = call_price(S, K, r, T, sig);
    // double put = put_price(S, K, r, T, sig);
    // Then we calculate the call/put values
    double call = call_price(S, K, r, T, sig);
    double put = put_price(S, K, r, T, sig);

    double delta = call_delta(S, K, r, T, sig);
    double theta = call_theta(S, K, r, T, sig);
    double gamma = call_gamma(S, K, r, T, sig);
    double vega = call_vega(S, K, r, T, sig);
    double rho = call_rho(S, K, r, T, sig);

    double p_delta = put_delta(S, K, r, T, sig);
    double p_theta = put_theta(S, K, r, T, sig);
    double p_gamma = put_gamma(S, K, r, T, sig);
    double p_vega = put_vega(S, K, r, T, sig);
    double p_rho = put_rho(S, K, r, T, sig);

    // Output the parameters and prices

    std::cout << "Underlying:      " << S << std::endl;
    std::cout << "Strike:          " << K << std::endl;
    std::cout << "Risk-Free Rate:  " << r << std::endl;
    std::cout << "Volatility:      " << sig << std::endl;
    std::cout << "Maturity:        " << T << std::endl;

    std::cout << "Call Price:      " << call << std::endl;
    std::cout << "Put Price:       " << put << std::endl;

    std::cout << "Call Delta:       " << delta << std::endl;
    std::cout << "Call Gamma:       " << gamma << std::endl;
    std::cout << "Call Theta:       " << theta << std::endl;
    std::cout << "Call Rho:       " << rho << std::endl;
    std::cout << "Call Vega:       " << vega << std::endl;

    std::cout << "Put Delta:      " << p_delta << std::endl;
    std::cout << "Put Gamma:      " << p_gamma << std::endl;
    std::cout << "Put Theta:      " << p_theta << std::endl;
    std::cout << "Put Rho:      " << p_rho << std::endl;
    std::cout << "Put Vega:      " << p_vega << std::endl;

    return 0;

}

Let’s run the code to see the result:

Underlying:      110
Strike:          100
Risk-Free Rate:  0.04
Volatility:      0.2
Maturity:        1
Call Price:      16.9687
Put Price:       3.04762
Call Delta:       0.781288
Call Gamma:       0.0134135
Call Theta:       -0.016452
Call Vega:       0.324606
Call Rho:       0.68973
Put Delta:      -0.218712
Put Gamma:      0.0134135
Put Theta:      -0.00592279
Put Vega:      0.324606
Put Rho:      -0.271059

Calculate Options Greeks using Black-Scholes Formula in R

Let’s go through how to calculate the Options Greeks in R. First, we will define functions for the d1, d2 variables and the call and put option pricing.

# d1 variable

d1 <- function(S, K, r, T, sig){

    (log(S/K) + (r+sig^2/2)*T)/(sig*sqrt(T))

}

# d2 variable

d2 <- function(S, K, r, T, sig){

    (log(S/K) + (r-sig^2/2)*T)/(sig*sqrt(T))

}

# Function for Call option pricing using Black-Scholes

call_price <- function(S, K, r, T, sig){

    call <- S*pnorm(d1(S,K,r,T,sig)) - K*exp(-r*T)*pnorm(d2(S,K,r,T,sig))

    return (call)

}

# Function for Put option pricing using Black-Scholes

put_price <- function(S, K, r, T, sig){

    put <-  K*exp(-r*T)*pnorm(-d2(S,K,r,T,sig)) - S*pnorm(-d1(S,K,r,T,sig)) 

    return (put)

}

Let’s define the call and put Option Greeks using the expressions in the Options Greeks Expressions section.

# Function for Call Delta

call_delta <- function(S,K,r,T,sig){

   delta <- pnorm(d1(S,K,r,T,sig))

   return(delta)

}

# Function for Call Gamma

call_gamma <- function(S,K,r,T,sig){

   gamma <- dnorm(d1(S,K,r,T,sig))/(S*sig*sqrt(T))

   return(gamma)

}

# Function for Call Theta

call_theta <- function(S,K,r,T,sig){

   theta_1 = -1* r * K * exp(-r*T)*pnorm(d2(S,K,r,T,sig))

   theta_2 = sig * S * dnorm(d1(S,K,r,T,sig))/(2*sqrt(T))
   # Divide by 365 to get the change in option price per one calendar day, otherwise change would be per one year

   theta = (theta_1-theta_2)/365

   return (theta)

}

# Function for Call Rho

call_rho <- function(S,K,r,T,sig){

    rho <- 0.01 * (T * K * exp(-r*T)*pnorm(d2(S,K,r,T,sig)))

    return(rho)

}

# Function for Call Vega

call_vega <- function(S,K,r,T,sig){

  vega <- 0.01 * (sqrt(T) * S * dnorm(d1(S,K,r,T,sig)))

  return(vega)

}
# Function for Put Delta

put_delta <- function(S,K,r,T,sig){

   delta <- pnorm(d1(S,K,r,T,sig)) - 1

   return(delta)

}

# Function for Put Gamma

put_gamma <- function(S,K,r,T,sig){

   gamma <- dnorm(d1(S,K,r,T,sig))/(S*sig*sqrt(T))

}

# Function for Put Theta

put_theta <- function(S,K,r,T,sig){

   theta_1 = -1*sig * S * dnorm(d1(S,K,r,T,sig))/(2*sqrt(T))

   theta_2 = r * K * exp(-r*T)*pnorm(-1* d2(S,K,r,T,sig))

   theta = (theta_1+theta_2)/365

   return (theta)

}

# Function for Put Rho

put_rho <- function(S,K,r,T,sig){

    rho <- 0.01 * -1* (T * K * exp(-r*T)*pnorm(-1*d2(S,K,r,T,sig)))

}

# Function for Put Vega

put_vega <- function(S,K,r,T,sig){

  vega <- 0.01 * (sqrt(T) * S * dnorm(d1(S,K,r,T,sig)))

}

Next, we will call the defined functions to get the call and put options prices and the Options Greeks, then assign them to variables.

call <- call_price(110, 100, 0.04, 1, 0.2)
put <- put_price(110, 100, 0.04, 1, 0.2)

c_delta <- call_delta(110, 100, 0.04, 1, 0.2)
c_gamma <- call_gamma(110, 100, 0.04, 1, 0.2)
c_theta <- call_theta(110, 100, 0.04, 1, 0.2)
c_rho <- call_rho(110, 100, 0.04, 1, 0.2)
c_vega <- call_vega(110, 100, 0.04, 1, 0.2)

p_delta <- put_delta(110, 100, 0.04, 1, 0.2)
p_gamma <- put_gamma(110, 100, 0.04, 1, 0.2)
p_theta <- put_theta(110, 100, 0.04, 1, 0.2)
p_rho <- put_rho(110, 100, 0.04, 1, 0.2)
p_vega <- put_vega(110, 100, 0.04, 1, 0.2)

Next, we will use the cat function to print all of the values to the console:

cat("Call price=", call, 
"\nPut price=", put, 
"\nCall Delta=",c_delta, 
"\nCall Gamma=",c_gamma,
"\nCall Theta=",c_theta,
"\nCall Rho=",c_rho,
"\nCall Vega=",c_vega,
"\n\nPut Delta=",p_delta, 
"\nPut Gamma=",p_gamma,
"\nPut Theta=",p_theta,
"\nPut Rho=",p_rho,
"\nPut Vega=",p_vega
)

Let’s run the code to get the result:

Call price= 16.96868 
Put price= 3.047622 
Call Delta= 0.7812881 
Call Gamma= 0.01341346 
Call Theta= -0.01645199 
Call Rho= 0.6897301 
Call Vega= 0.3246057 

Put Delta= -0.2187119 
Put Gamma= 0.01341346 
Put Theta= -0.005922795 
Put Rho= -0.2710593 
Put Vega= 0.3246057

Summary

Congratulations on reading to the end of this tutorial!

For further reading on the Black-Scholes Option Pricing model and how to use it in R, Python, and C++, go to the articles:

You can use our free Black-Scholes option pricing calculator to estimate the fair value of a European call or put option.

You can use our free Implied Volatility calculator to estimate the Implied Volatility of a priced option.

Have fun and happy researching!

Profile Picture
Senior Advisor, Data Science | [email protected] | + posts

Suf is a senior advisor in data science with deep expertise in Natural Language Processing, Complex Networks, and Anomaly Detection. Formerly a postdoctoral research fellow, he applied advanced physics techniques to tackle real-world, data-heavy industry challenges. Before that, he was a particle physicist at the ATLAS Experiment of the Large Hadron Collider. Now, he’s focused on bringing more fun and curiosity to the world of science and research online.

Buy Me a Coffee