-
Notifications
You must be signed in to change notification settings - Fork 0
/
multi_step_model.py
170 lines (141 loc) · 6.54 KB
/
multi_step_model.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import streamlit as st
import numpy as np
import yfinance as yf
import math
import matplotlib.pyplot as plt
# Used for calculating Discount Factor
# risk free rate = rate of return of an investment with zero risk
def get_risk_free_rate(expiration):
treasury_bill_symbol = '^IRX' # 13 week treasury bill currently about 5%
treasury_bill = yf.Ticker(treasury_bill_symbol)
# last close price
latest_yield = treasury_bill.history(period="1d")['Close'].iloc[-1]
risk_free_rate = latest_yield/100 #convert to decimal
if expiration < 1:
risk_free_rate = risk_free_rate * expiration
return risk_free_rate
def get_data(ticker_symbol):
#define ticker
ticker = yf.Ticker(ticker_symbol)
#historical data
historical_data = ticker.history(period="1y")
#Returns closing price
return historical_data["Close"]
def fetch_option_data(ticker_symbol):
# Define ticker
ticker = yf.Ticker(ticker_symbol)
# current price
current_price = ticker.history(period="1d")['Close'].iloc[-1]
#Options data (calls, puts: using options_data.calls, options_data.puts)
options_data = ticker.option_chain()
# Strike prices
strike = list(options_data.calls['strike'])
return current_price, options_data, strike
def up_down_move(vol, t_step):
u = (math.e)**(vol*math.sqrt(t_step))
d = (math.e)**(-vol*math.sqrt(t_step))
return u, d
def historical_data(ticker):
historical_data = get_data(ticker)
log_returns = np.log(historical_data / historical_data.shift(1))
return log_returns
def build_binomial_tree(current_price, u, d, steps):
tree = np.zeros([steps + 1, steps + 1])
for i in range(steps + 1):
for j in range(i + 1):
tree[j, i] = current_price * (u ** (i - j)) * (d ** j)
return tree
def calculate_call_option_values(tree, strike, risk_free_rate, steps, t_step):
call_option_tree = np.zeros_like(tree)
# Calculate the option value at expiration
call_option_tree[:, steps] = np.maximum(tree[:, steps] - strike, 0)
# Discount rate for each step
discount_rate = np.exp(-risk_free_rate * t_step)
# Work backward through the tree
for i in range(steps - 1, -1, -1):
for j in range(i + 1):
call_option_tree[j, i] = discount_rate * 0.5 * (call_option_tree[j, i + 1] + call_option_tree[j + 1, i + 1])
return call_option_tree
def calculate_put_option_values(tree, strike, risk_free_rate, steps, t_step):
put_option_tree = np.zeros_like(tree)
put_option_tree[:, steps] = np.maximum(strike - tree[:, steps], 0)
discount_rate = np.exp(-risk_free_rate * t_step)
for i in range(steps - 1, -1, -1):
for j in range(i + 1):
put_option_tree[j, i] = discount_rate * 0.5 * (put_option_tree[j, i + 1] + put_option_tree[j + 1, i + 1])
return put_option_tree
def plot_binomial_tree(tree):
steps = tree.shape[1]
plt.figure(figsize=(12, 12))
for i in range(steps):
for j in range(i + 1):
plt.scatter(i, tree[j, i], color='blue')
# Connect nodes with lines
if i < steps - 1:
plt.plot([i, i + 1], [tree[j, i], tree[j, i + 1]], color='black')
plt.plot([i, i + 1], [tree[j, i], tree[j + 1, i + 1]], color='black')
plt.title('Binomial Tree for Option Pricing')
plt.xlabel('Step')
plt.ylabel('Stock Price ($)')
plt.grid()
return plt
def plot_historical_data(ticker_symbol):
ticker = yf.Ticker(ticker_symbol)
historical_data_5y = ticker.history(period="5y")
plt.figure(figsize=(12, 6))
plt.plot(historical_data_5y.index, historical_data_5y['Close'], label='Closing Price')
plt.title(f'Historical Closing Prices - Last 5 Years of {ticker_symbol}')
plt.xlabel('Date')
plt.ylabel('Stock Price ($)')
plt.legend()
plt.grid()
return plt
def main():
st.title("Binomial Option Pricing Model")
# Input fields for user parameters
ticker = st.text_input("Stock Ticker Symbol(e.g. AMZN):", "AMZN")
expiration_map = {
"2 Weeks": 2/52,
"1 Month": 1/12,
"3 Months": 3/12,
"6 Months": 0.5,
"1 Year": 1,
"2 Years": 2,
"3 Years": 3,
"5 Years": 5
}
expiration = st.selectbox("Choose the expiration Timeframe", ["2 Weeks", "1 Month", "3 Months", "6 Months", "1 Year", "2 Years", "3 Years", "5 Years"])
exp_mapped = expiration_map[expiration]
steps = st.slider("Number of Steps:", min_value=1, max_value=10000, value=6)
if ticker:
current_price, _ , strike_list = fetch_option_data(ticker)
strike = st.selectbox("Select Strike Price:", strike_list)
if st.button("Calculate Option Prices"):
if steps and strike_list and expiration:
try:
# Fetch data and calculate option price
vol = np.std(historical_data(ticker)) * np.sqrt(252) # Annualize the volatility
r = get_risk_free_rate(exp_mapped) # Risk-free rate
t_step = exp_mapped / steps # Length of each time step
u, d = up_down_move(vol, t_step)
# Building the binomial tree for stock prices
stock_price_tree = build_binomial_tree(current_price, u, d, steps)
# Calculating option values using the binomial tree
call_option_tree = calculate_call_option_values(stock_price_tree, strike, r, steps, t_step)
put_option_tree = calculate_put_option_values(stock_price_tree, strike, r, steps, t_step)
# Display the option price
call_option_price = call_option_tree[0, 0]
put_option_price = put_option_tree[0, 0]
st.success(f"The calculated Call option price is: ${call_option_price:.2f}")
st.success(f"The calculated Put option price is: ${put_option_price:.2f}")
if steps < 100:
#Plotting binomial tree
plt_tree = plot_binomial_tree(stock_price_tree)
st.pyplot(plt_tree)
# plotting historical data (closing prices)
plt_historical = plot_historical_data(ticker)
st.pyplot(plt_historical)
except Exception as e:
st.error(f"An error occurred: {e}")
if __name__ == "__main__":
main()