Graphics

The Black Scholes Greeks Visualized

Visualizing the Greeks reveal some of the key dynamics we are trying to capture in an option portfolio. Some useful additional reading can be found at Robert McDonald and employing his R package Derivmkts seen in the previous page. As before we can define the Greeks as the units in which changes ·are conventionally measured.

Delta captures the option price change when the stock price increases by $ amount .

Gamma measures the change in delta when the stock price increases by $ amount .

Vega measures the change in the option price when there is an increase in volatility of one percentage unit.

Theta measures the change in the option price when there is a decrease in the time to maturity of 1 day/ 1 year.

Rho measures the change in the option price when there is a change in the interest rate.

Psi (W) measures the change in the option price when there is an change in the continuous dividend yield.

Professor MacDonald at the Kellogg School of Management has put together the derivmkts package for R. Here I used the template for estimating Greeks and the package is hugely powerful for visualizing Greeks

library("derivmkts")


s=100; k=100; v=0.2; r=0.05; tt=1; d=0;

greeks(bscall(s, k, v, r, tt, d), complete=FALSE, long=FALSE, initcaps=TRUE)

greeks2(bscall, list(s=s, k=k, v=v, r=r, tt=tt, d=d))

greeks2(bscall, list(s=s, k=k, v=v, r=r, tt=tt, d=d))[c('Delta', 'Gamma'), ]

bsopt(s, k, v, r, tt, d)

bsopt(s, c(90, 100, 110), v, r, tt, d)

bsopt(s, c(90, 100, 110), v, r, tt, d)[['Call']][c('Delta', 'Gamma'), ]


## plot Greeks for calls and puts for 500 different stock prices

k <- 100; v <- 0.20; r <- 0.05; tt <- 1; d <- 0

S <- seq(10, 200, by=5)

Call <- greeks(bscall(S, k, v, r, tt, d))

Put <- greeks(bsput(S, k, v, r, tt, d))

y <- list(Call=Call, Put=Put)

par(mfrow=c(4, 4), mar=c(2, 2, 2, 2)) ## create a 4x4 plot

for (i in names(y)) {

for (j in rownames(y[[i]])) { ## loop over greeks

plot(S, y[[i]][j, ], main=paste(i, j), ylab=j, type='l')

}

}

Understanding Analytical and Numerical Black Scholes Greeks through Visualization in Excel

Below we trace out the

Delta

Gamma

Vega

Theta

for a call with same parameters as above. We estimated the call using the Black Scholes models. We show how the numerical approach to estimating options can be set up and how the numerical approach converges to the analytical approach. The analytical Greeks are generated using the VBA code and Greeks formulae we used on the previous page.

Delta Numerical and Analytical with Excel Graphs

Gamma Numerical and Analytical with Excel Graphs

Vega Numerical and Analytical with Excel Graphs

Theta Numerical and Analytical with Excel Graphs

Python Code for Black Scholes Greeks with graphing

Below we adapted Clint Howards Python notebook to include dividends for Greeks. We then proceeded to use the graphing template set up in Clint's code to mirror the parameter values we have been using above and previously. That is S = 100, K = 100, r = 0.05, q = 0.0, vol = 0.2, T = 1, t = 0.

Lower case t denotes time passed since option was written. This allows us to compare against Professor Robert McDonald's Derivmkts package. Click on Google Colaboratory link adjacent and once you sign in to your google account you can run Python Notebook directly from Colab which maybe more intuitive than copying code below and pasting into compiler in Sections.

#https://clinthoward.github.io/portfolio/2017/04/16/BlackScholesGreeks/


import pandas as pd

import matplotlib.pyplot as plt

import numpy as np

plt.style.use('ggplot')

plt.rcParams['xtick.labelsize'] = 14

plt.rcParams['ytick.labelsize'] = 14

plt.rcParams['figure.titlesize'] = 18

plt.rcParams['figure.titleweight'] = 'medium'

plt.rcParams['lines.linewidth'] = 2.5


from scipy.stats import norm


# S: underlying asset price # K: Option strike price # r: risk free rate # q: dividend yield # vol: Volatility # T: time to expiry (assumed that we're measuring from t=0 to T)

def d1_calc(S, K, r, q, vol, T, t):

# Calculates d1 in the BSM equation

return (np.log(S/K) + (r - q + 0.5 * vol**2)*(T-t))/(vol*np.sqrt(T-t))


def BS_call(S, K, r, q, vol, T, t):

d1 = d1_calc(S, K, r, q, vol, T, t)

d2 = d1 - vol * np.sqrt(T-t)

return S * np.exp(-q*(T-t)) *norm.cdf(d1) - K * np.exp(-r*(T-t))*norm.cdf(d2)


def BS_put(S, K, r, q, vol, T, t):

return BS_call(S, K, r, q, vol, T, t) - S* np.exp(-q*(T-t)) + np.exp(-r*(T-t))*K


###########################################################################

#1st Order Greeks

def delta(S, K, r, q, vol, T, t, otype):

d1 = d1_calc(S, K, r, q, vol, T, t)

d2 = d1 - vol * np.sqrt(T-t)

if(otype == "call"):

delta = np.exp(-q*(T-t))*norm.cdf(d1)

elif(otype == "put"):

delta = -np.exp(-q*(T-t))*norm.cdf(-d1)


return delta


# Vega for calls/puts the same

def vega(S, K, r, q, vol, T, t, otype):

d1 = d1_calc(S, K, r, q, vol, T, t)

return S* np.exp(-q*(T-t)) * norm.pdf(d1) * np.sqrt(T-t)


def rho(S, K, r, q, vol, T, t, otype):

d1 = d1_calc(S, K, r, q, vol, T, t)

d2 = d1 - vol*np.sqrt(T-t)

if(otype == "call"):

rho = K*(T-t)*np.exp(-r*(T-t))*norm.cdf(d2)

elif(otype == "put"):

rho = -K*(T-t)*np.exp(-r*(T-t))*norm.cdf(-d2)

return rho


def theta(S, K, r, q, vol, T, t, otype):

d1 = d1_calc(S, K, r, q, vol, T, t)

d2 = d1 - vol*np.sqrt(T-t)

if(otype == "call"):

theta = -(S* np.exp(-q*(T-t))*norm.pdf(d1)*vol / (2*np.sqrt(T-t))) - r*K*np.exp(-r*(T-t))*norm.cdf(d2) + q*S*norm.cdf(d1)*np.exp(-q*(T-t))

elif(otype == "put"):

theta = -(S*np.exp(-q*(T-t))*norm.pdf(d1)*vol / (2*np.sqrt(T-t))) + r*K*np.exp(-r*(T-t))*norm.cdf(-d2) - q*S*norm.cdf(-d1)*np.exp(-q*(T-t))


return theta


#2nd Order Greeks

def gamma(S, K, r, q, vol, T, t, otype):

d1 = d1_calc(S, K, r, q, vol, T, t)

gamma = (norm.pdf(d1)*np.exp(-q*(T-t))) / (S * vol * np.sqrt(T-t))

return gamma

S = 100

K = 100

r = 0.05

q = 0.0

vol = 0.2

T = 1

t = 0


otype ="call"


print(BS_call(S, K, r, q, vol, T, t))

print(delta(S, K, r, q, vol, T, t, otype))

print(gamma(S, K, r, q, vol, T, t, otype))

print(vega(S, K, r, q, vol, T, t, otype))

print(theta(S, K, r, q, vol, T, t, otype))

print(theta(S, K, r, q, vol, T, t, otype)/365)

print(rho(S, K, r, q, vol, T, t, otype))

S = 100

K = 100

r = 0.05

q = 0.0

vol = 0.2

T = 1

t = 0


otype ="put"


print(BS_put(S, K, r, q, vol, T, t))


print(delta(S, K, r, q, vol, T, t, otype))

print(gamma(S, K, r, q, vol, T, t, otype))

print(vega(S, K, r, q, vol, T, t, otype))

print(theta(S, K, r, q, vol, T, t, otype))

print(theta(S, K, r, q, vol, T, t, otype)/365)

print(rho(S, K, r, q, vol, T, t, otype))

S = np.arange(0, 200)

#BS_call(S, K, r, q, vol, T, t)


vals_call = [BS_call(x, 100, 0.05, 0.0, 0.2, 1, 0) for x in S]

vals_put = [BS_put(x, 100, 0.05, 0.0, 0.2, 1, 0) for x in S]

plt.plot(S,vals_call, 'r', label = "Call")

plt.plot(S, vals_put, 'b', label = "Put")

plt.legend()

plt.ylabel("Stock Price ($)")

plt.xlabel("Option Price ($)")

plt.show()


fig, ax = plt.subplots(nrows=6, ncols=1, sharex=True, sharey=True, figsize=(40, 30))

fig.suptitle('Sensitivity of 1st Order European Option Greeks to Strike + Underlying', fontsize=20, fontweight='bold')

fig.text(0.5, 0.08, 'Stock/Underlying Price ($)', ha='center', fontsize=18, fontweight='bold')

vals = [100,100,100]


r = 0.05

q = 0.0

vol = 0.2

T = 1

t = 0


plt.subplot(321)

for i in vals:

tmp_c = [delta(s, i, r, q, vol, T, t, "call") for s in np.arange(1,200)]

tmp_p = [delta(s, i, r, q, vol, T, t, "put") for s in np.arange(1,200)]

plt.plot(tmp_c, label = ("Delta Call K=%i" % i ))

plt.plot(tmp_p, label = ("Delta Put K=%i" % i ))


plt.ylabel("Delta")

plt.legend()


plt.subplot(322)

for i in vals:

tmp_c = [gamma(s, i, r, q, vol, T, t, "call") for s in np.arange(1,200)]

tmp_p = [gamma(s, i, r, q, vol, T, t, "put") for s in np.arange(1,200)]

plt.plot(tmp_c, label = ("Gamma Call K=%i" % i ))

plt.plot(tmp_p, label = ("Gamma Put K=%i" % i ))


plt.ylabel("Gamma")

plt.legend()


plt.subplot(323)

for i in vals:

tmp_c = [vega(s, i, r, q, vol, T, t, "call") for s in np.arange(1,200)]

tmp_p = [vega(s, i, r, q, vol, T, t, "put") for s in np.arange(1,200)]

plt.plot(tmp_c, label = ("Vega Call K=%i" % i ))

plt.plot(tmp_p, label = ("Vega Put K=%i" % i ))


plt.ylabel("Vega")

plt.legend()


plt.subplot(324)


for i in vals:

tmp_c = [rho(s, i, r, q, vol, T, t, "call") for s in np.arange(1,200)]

tmp_p = [rho(s, i, r, q, vol, T, t, "put") for s in np.arange(1,200)]

plt.plot(tmp_c, label = ("Rho Call K=%i" % i ))

plt.plot(tmp_p, label = ("Rho Put K=%i" % i ))


plt.ylabel("Rho")

plt.legend()


plt.subplot(325)

for i in vals:

tmp_c = [theta(s, i, r, q, vol, T, t, "call") for s in np.arange(1,200)]

tmp_p = [theta(s, i, r, q, vol, T, t, "put") for s in np.arange(1,200)]

plt.plot(tmp_c, label = ("Theta Call K=%i" % i ))

plt.plot(tmp_p, label = ("Theta Put K=%i" % i ))


plt.ylabel("Theta")

plt.legend()


#plt.legend()

plt.show()

Python Code for Black Scholes Greeks 3d graphing and Greeks Derivation

Just adjacent, we implement some Python code provided by the The Smiles of Thales pdf file. The file includes python code and derivation for Greeks. A Python notebook is included here for graphing in 3d the delta(s) of range values. We will use seed values K = 100, r = 0.05, q = 0.0, vol = 0.2, T and S spanning varying ranges

Click on Google Colaboratory link adjacent to see the direct implementation of Delta 3d graphing. This link will normally work on phone or tablet.