Arbitrage with an Option Pricing App— Part 1

Mike Flynn
5 min readMar 3, 2023

In this blog post, we will explore how to create a Black-Scholes model to price options and compare it against the latest option price as a way to look for an arbitrage buying opportunity.

In Part 2 we are going to put this into a Dash App so we can check options for arbitrage opportunites.

ChatGPT defines black-scholes with the following :

“The Black-Scholes model is one of the most widely used models for pricing options. It was developed by Fischer Black and Myron Scholes in 1973, and has since become the standard for option pricing. The model takes into account factors such as the underlying asset’s price, time to expiration, volatility, interest rates, and strike price.“ ChatGPT

We are going to break this into a few steps over a couple blog posts.

Part 1

  1. Collect Stock Data
  2. Collect Interest Rate
  3. Write Black-Scholes Formula
  4. Price an Option

Part 2

  1. Create a Dash Layout
  2. Create the Callback for Live Prices
  3. Launch the App

We are going to focus on Part 1 in this post and a follow up post will show how to build the app.

1. Collect Stock & Options Data

We are going to pick up stock data from yahooquery with the code below.

from yahooquery import Ticker
import pandas as pd

def stockdata(ticker, sd, ed):
print("Grabbing stock prices for : " + ticker + " between : " + str(sd) + " and " + str(ed))
tickers_arg = Ticker(ticker)
df = tickers_arg.history(interval="1d", start=(sd), end=(ed)).reset_index()
print("Data picked up with : " + str(df['date'].count()) + " rows")
options_df = pd.DataFrame(tickers_arg.option_chain).reset_index()
call_options = options_df[options_df['optionType'] == 'calls']
put_options = options_df[options_df['optionType'] == 'puts']
return df, call_options, put_options

2. Pick up current Risk Free Interest Rate

We are going to define Risk Free Interest Rate as the 3-month US treasuary bill, and pick this up with the following function.

import pandas_datareader.data as pdr

def interest_rate():
#3 month treasury bill
data = pdr.get_data_fred('DTB3')
current_rate = data.iloc[-1]['DTB3']
print("Current risk free interest rate :", current_rate, "%")
return current_rate

cr = interest_rate()

3. Black Scholes Formula

Black Scholes formula is as follows

C = Call option Price

N = CDF of normal distribution

S = Spot price of an asset

K = Strike Price

r= risk free interest rate

t = time to maturity

σ = volitility of an asset

We writing this up as a python function as below, which includes one extra input of the option type — ‘call’ or ‘put’.

import numpy        as np
from scipy.stats import norm

#Black Scholes - calcultion
def black_scholes(S, K, T, r, sigma, option_type):
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
if option_type.lower() == "call":
option_price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
elif option_type.lower() == "put":
option_price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
else:
raise ValueError("Invalid option type. Please use 'call' or 'put'.")
return option_price

4. Price an Option

Pick up the data

As an example we are going to look at the ‘meme’ stock AMC.

import datetime
import numpy as np
today = datetime.date.today()
ed = today.strftime("%Y-%m-%d")
sd = (today - datetime.timedelta(days=364)).strftime("%Y-%m-%d")

ticker = 'AMC'
df,df_call,df_put = stockdata(ticker, sd, ed)

The dataframes look as follows

Stock Price

Pick up the current stock price.

S     = round(df["close"].iloc[-1],2)
print("Current stock price is : " + str(S))

Strike Price

The current strike price options can be seen below.

call['strike'].unique()
K = 7

Seelcting a strike price of $7.

Risk Free interest rate

Risk free interest rate using out function from above

r = interest_rate() / 100

Expiration Date

Can pick the Expiration dates from the call dataframe

list(set(call['expiration']))
t = (datetime.date(2023,9,15) - today).days / 365

We are going to select 15 September 2023 which should be just after an AMC earnings call.

Volitility of the asset

Calculate volitlity (sigma) with the following

sigma = df['adjclose'].pct_change().std() * np.sqrt(252)     
print("Annualised volatility " + str(sigma))

Black Scholes Option Price

So we have all the vairables to price an option and are now going to feed this into the Black-Scholes function we created earlier.

scholes_call_price = round(black_scholes(S,K,T,r,sigma,'call'),2)
scholes_put_price = round(black_scholes(S,K,T,r,sigma,'put'),2)

print("European Call price : " + str(scholes_call_price))
print("European Put price : " + str(scholes_put_price))

Looking for pricing discripencies

So we are pricing a call option at $1.92 and a put option at $2.64.

The current asking price


call_lastprice = call['lastPrice'].loc[(call['strike'] == K) & (call['expiration'] == pd.to_datetime(exp_dt))].iloc[0]
put_lastprice = puts['lastPrice'].loc[(puts['strike'] == K) & (puts['expiration'] == pd.to_datetime(exp_dt))].iloc[0]
print("The last call price was : " + str(round(call_lastprice,3))), print("The last Put ask price was : " + str(round(put_lastprice,3)))

So Black Scholes model is pricing a call option more valuable than that of the most recent asking price.

Assuming the model assumptions hold true here is an arbitrage opportunity. We could purchase the option and then sell it immediately at the black scholes price.

And as ChatGPT wisely says

‘However, it is important to note that the Black-Scholes model is just a theoretical model and is based on a number of assumptions. In practice, the actual price of an option can be influenced by a number of different factors such as market conditions, supply and demand, and the underlying asset’s performance. Therefore, it is important to conduct thorough research and analysis before making any investment decisions based on the Black-Scholes model.’

I am going to conclude Part 1 today will make a follow up with Part 2 that creates an option pricing Dash app.

BECOME a WRITER at MLearning.ai

--

--