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.