In this video we cover
- Using and testing Black-Scholes model for option pricing
- Geometric Brownian Movement for option pricing
- Web Scraping for extraction of data required for option pricing
We will also see how to determine daily and annual volatility, risk free rate and cumulative distribution function. We develop functions that we can use later for finding gaps in option trading markets and use them to make profit.
I will write each function codes after the video.
# Black-Scholes model for pricing options
import datetime, numpy as np
def norm_cdf(x):
s = 0
x0 = 100
n = 1000
for i in range(1,n+1):
y = -x0 + (x + x0) / n * i
s = s + np.exp(-(y**2)/2) * (x + x0) / n
return s/np.sqrt(2*np.pi)
S = 172.57
K = 130
vol = 0.4634
r = 0.0475
dt = ((datetime.date(2023,9,15)-datetime.date(2023,5,12)).days+1)/365
d1 = (np.log(S/K) + ((r + (vol**2) / 2) * dt)) / (vol * np.sqrt(dt))
d2 = d1 - vol * np.sqrt(dt)
cdf_d1 = norm_cdf(d1)
cdf_d2 = norm_cdf(d2)
call_price = S * cdf_d1 - K * np.exp(-r * dt) * cdf_d2
print(call_price)
# Volatility and Geometric Brownian Motion
import numpy as np
from yfinance import download as get_data
import datetime as dt
import matplotlib.pyplot as plt
import time
start_date = dt.datetime.now() - dt.timedelta(days = 365*2)
end_date = dt.datetime.now()
data = get_data("SPY", start_date, end_date)
data = data["Adj Close"]
returns = data.pct_change()
mean_return = returns.mean()
std_dev = returns.std()
print(mean_return, " , ", std_dev*np.sqrt(252))
last_close = data[len(data)-1]
parice_paths=[]
for i in range(2000):
parice_paths.append([last_close])
y = np.random.normal(mean_return,std_dev,252)
for j in range(252):
parice_paths[i].append((1 + y[j]) * parice_paths[i][j])
plt.plot(parice_paths[i])
plt.pause(0.005)
print(last_close * ((1 + mean_return) ** 252), sum([line[-1] for line in parice_paths])/len(parice_paths))
plt.show()
# Scrape 1-year treasury bill (risk free rate) from ycharts.com
import requests
def risk_free_rate():
my_headers = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36" }
html_code = requests.get("https://ycharts.com/indicators/1_year_treasury_rate", headers = my_headers).text
html_code = html_code.split('<td class="text-right">')
for i in range(1,11):
r_text = html_code[i]
r_index = r_text.find("%")
print(r_text[r_index-4:r_index])
risk_free_rate()
# Scrape BHP option price details from asx.com.au
import requests,datetime,json
def get_options():
for d in range(0,31):
the_day = datetime.date.today() + datetime.timedelta(days = d)
if (the_day.weekday() == 3 and the_day.day > 14 and the_day.day < 22):
closest_option_date = the_day
break
html_code = requests.get("https://asx.api.markitdigital.com/asx-research/1.0/derivatives/equity/BHP/options/expiry-groups?callsPuts=calls&showOpenInterestOnly=false&showTheoreticalPricesOnly=false&styles=european&includeLepoToressOptions=false&expiryDates[]="
+ str(closest_option_date)).text
options_data = json.loads(html_code)
options = options_data["data"]["items"][0]["exerciseGroups"]
option_list = []
for option in options:
if option["call"]["volume"] > 0:
option_list.append([option["priceExercise"],option["call"]["priceLast"]])
return closest_option_date, option_list
print(get_options())