barrier_option / app.py
ypchang's picture
Update app.py
a67932a
import numpy as np
from scipy import stats
import matplotlib
import matplotlib.pyplot as plt
import mpltw
font_size = 8
plt.rcParams.update({"font.size": font_size})
#先把公式寫好(先把函數寫好)
def Black_Scholes(S0, K, r, T, sigma, option_type):
d1 = (np.log(S0/K)+(r+sigma**2/2)*T)/(sigma*np.sqrt(T))
d2 = d1-sigma*np.sqrt(T)
if option_type == "call":
return S0*stats.norm.cdf(d1)-K*np.exp(-r*T)*stats.norm.cdf(d2)
if option_type == "put":
return K*np.exp(-r*T)*stats.norm.cdf(-d2)-S0*stats.norm.cdf(-d1)
def generate_Sobol(Sobol_seq, n=1, epsilon=0):
quasi_random_numbers = Sobol_seq.random(n)
# quasi_random_numbers = epsilon + (1 - 2 * epsilon) * quasi_random_numbers
d = Sobol_seq.d
l_bounds = np.repeat(epsilon, d)
u_bounds = np.repeat(1-epsilon, d)
quasi_random_numbers = stats.qmc.scale(quasi_random_numbers, l_bounds, u_bounds)
return quasi_random_numbers
#股價路徑
def GBM_simulation_paths(S0, K, r, T, sigma, Z):
NumPath, n = Z.shape
dt = T/n
logS = np.log(S0)*np.ones((NumPath, n+1)) #模擬的是log S,講義上的Y
for j in range(n):
logS[:,j+1] = logS[:,j]+(r-sigma**2/2)*dt+sigma*np.sqrt(dt)*Z[:,j]
S = np.exp(logS)
return S
#%%
#障礙選擇權公式解
def barrier_option(S0, K, r, T, sigma, b, q):
lr = (r - q + (1/2) * sigma**2) / sigma**2
y = (np.log(b / S0) + np.log(b / K)) / (sigma * np.sqrt(T)) + lr * sigma * np.sqrt(T)
x1 = (np.log(S0 / b) / (sigma * np.sqrt(T))) + lr * sigma * np.sqrt(T)
y1 = np.log(b / S0) / (sigma * np.sqrt(T)) + lr * sigma * np.sqrt(T)
bs_value = Black_Scholes(S0, K, r, T, sigma, 'put')
if S0 < b:
if b > K:
uip = -S0*np.exp(-q*T)*(b/S0)**(2*lr)*stats.norm.cdf(-y)+K*np.exp(-r*T)*(b/S0)**(2*lr-2)*stats.norm.cdf(-y+sigma*np.sqrt(T))
uop = bs_value - uip
return uip,uop
if b <= K:
uop = -S0*np.exp(-q*T)*stats.norm.cdf(-x1)+K*np.exp(-r*T)*stats.norm.cdf(-x1+sigma*np.sqrt(T))+S0*np.exp(-q*T)*(b/S0)**(2*lr)*(stats.norm.cdf(-y1))-K*np.exp(-r*T)*(b/S0)**(2*lr-2)*(stats.norm.cdf(-y1+sigma*np.sqrt(T)))
uip = bs_value - uop
return uip,uop
if S0 > b:
if b > K:
dop = 0
dip = bs_value
return dip,dop
if b <= K:
dip = -S0*np.exp(-q*T)*stats.norm.cdf(-x1)+K*np.exp(-r*T)*stats.norm.cdf(-x1+sigma*np.sqrt(T))+S0*np.exp(-q*T)*(b/S0)**(2*lr)*(stats.norm.cdf(y) - stats.norm.cdf(y1))-K*np.exp(-r*T)*((b/S0)**(2*lr-2))*(stats.norm.cdf(y-sigma*np.sqrt(T)) - stats.norm.cdf(y1-sigma*np.sqrt(T)))
dop = bs_value - dip
return dip,dop
#%%
#模擬
def cal_option_value(S0, K, T, r, sigma, b, q, NumPath, 模擬路徑, in_or_out):
x = np.zeros((len(模擬路徑),1))
for i in range(len(模擬路徑)): #i是第幾條路徑
path = 模擬路徑[i,:]
if S0 <= b:
if in_or_out == '生效':
if np.any(path >= b) == True: #判斷是否有大於某一個值
x[i,0] = np.maximum(K - path[-1], 0)
if np.any(path >= b) == False:
x[i,0] = 0
if in_or_out == '無效':
if np.any(path >= b) == True:
x[i,0] = 0
if np.any(path >= b) == False:
x[i,0] = np.maximum(K - path[-1],0)
if S0 > b:
if in_or_out == '生效':
if np.any(path <= b) == True:
x[i,0] = np.maximum(K - path[-1], 0)
if np.any(path <= b) == False:
x[i,0] = 0
if in_or_out == '無效':
if np.any(path <= b) == True:
x[i,0] = 0
if np.any(path <= b) == False:
x[i,0] = np.maximum(K - path[-1],0)
option_price = np.mean(x) * np.exp(-r * T)
option_std = np.std(x) / np.sqrt(NumPath)
return option_price, option_std
def random_number(n, NumPath, Sobol_seq, random_type):
if random_type == "pseudo":
u = np.random.rand(NumPath, n)
z = stats.norm.ppf(u)
if random_type == 'quasi':
u = generate_Sobol(Sobol_seq, n=NumPath, epsilon=1e-8)
z = stats.norm.ppf(u)
if random_type == 'normal':
z = np.random.normal(0, 1, (NumPath, n))
return z
#%%
def plot_European(S0, K, r, T, sigma_L, sigma_U, num_sigma, q, NumPath, time_intervals_year, seed, in_or_out='生效', up_or_down= '上升'):
S0 = np.float64(S0)
K = np.float64(K)
r = np.float64(r)
T = np.float64(T)
sigma_L = np.float64(sigma_L)
sigma_U = np.float64(sigma_U)
num_sigma = int(num_sigma)
q = int(q)
NumPath = int(NumPath)
time_intervals_year = int(time_intervals_year)
seed = int(seed)
dt = 1/time_intervals_year
n = int(T/dt) # 時間分割區間數 (或一條 path 之模擬亂數)
np.random.seed(seed)
Sobol_seq = stats.qmc.Sobol(d=n, scramble=True, seed=seed)
Z_pseudo = random_number(n, NumPath, Sobol_seq, 'pseudo')
Z_quasi = random_number(n, NumPath, Sobol_seq, 'quasi')
Z_normal = random_number(n, NumPath, Sobol_seq, 'normal')
if up_or_down == '上升':
b = 110
if up_or_down == '下降':
b = 90
sigma = np.linspace(sigma_L, sigma_U, num_sigma)
#算出公式解
formula_array = np.zeros((num_sigma, 1))
if in_or_out == '生效':
for i in range(num_sigma):
formula_array[i,0],_ = barrier_option(S0, K, r, T, sigma[i], b, q)
if in_or_out == '無效':
for i in range(num_sigma):
_,formula_array[i,0] = barrier_option(S0, K, r, T, sigma[i], b, q)
simulate_array_price_pseudo = np.zeros((num_sigma, 1))
simulate_array_std_pseudo = np.zeros((num_sigma, 1))
simulate_array_price_quasi = np.zeros((num_sigma, 1))
simulate_array_std_quasi = np.zeros((num_sigma, 1))
simulate_array_price_normal = np.zeros((num_sigma, 1))
simulate_array_std_normal = np.zeros((num_sigma, 1))
for i in range(num_sigma):
S_SDE_pseudo = GBM_simulation_paths(S0, K, r, T, sigma[i], Z_pseudo)
S_SDE_quasi = GBM_simulation_paths(S0, K, r, T, sigma[i], Z_quasi)
S_SDE_normal = GBM_simulation_paths(S0, K, r, T, sigma[i], Z_normal)
simulate_array_price_pseudo[i,0],simulate_array_std_pseudo[i,0] = cal_option_value(S0, K, T, r, sigma[i], b, q, NumPath, S_SDE_pseudo, in_or_out)
simulate_array_price_quasi[i,0],simulate_array_std_quasi[i,0] = cal_option_value(S0, K, T, r, sigma[i], b, q, NumPath, S_SDE_quasi, in_or_out)
simulate_array_price_normal[i,0],simulate_array_std_normal[i,0] = cal_option_value(S0, K, T, r, sigma[i], b, q, NumPath, S_SDE_normal, in_or_out)
fig = plt.figure(figsize=(15, 6))
plt.subplot(131)
plt.plot(sigma, formula_array[:,0], color="red",label = '公式解')
plt.plot(sigma, simulate_array_price_pseudo[:,0], color="blue", label = '模擬')
plt.fill_between(sigma,
simulate_array_price_pseudo[:,0]-1.96*simulate_array_std_pseudo[:,0],
simulate_array_price_pseudo[:,0]+1.96*simulate_array_std_pseudo[:,0],
color="green",
alpha=0.1)
plt.xlabel('sigma')
plt.ylabel("put option price")
plt.legend()
plt.title(f"pseudo {up_or_down}_{in_or_out}_b={b}")
plt.subplot(132)
plt.plot(sigma, formula_array[:,0], color="red",label = '公式解')
plt.plot(sigma, simulate_array_price_quasi[:,0], color="blue", label = '模擬')
plt.fill_between(sigma,
simulate_array_price_quasi[:,0]-1.96*simulate_array_std_quasi[:,0],
simulate_array_price_quasi[:,0]+1.96*simulate_array_std_quasi[:,0],
color="blue",
alpha=0.1)
plt.xlabel('sigma')
plt.ylabel("put option price")
plt.legend()
plt.title(f"quasi {up_or_down}_{in_or_out}_b={b}")
plt.subplot(133)
plt.plot(sigma, formula_array[:,0], color="red", label = '公式解')
plt.plot(sigma, simulate_array_price_normal[:,0], color="blue", label = '模擬')
plt.fill_between(sigma,
simulate_array_price_normal[:,0]-1.96*simulate_array_std_normal[:,0],
simulate_array_price_normal[:,0]+1.96*simulate_array_std_normal[:,0],
color="blue",
alpha=0.1)
plt.xlabel('sigma')
plt.ylabel("put option price")
plt.legend()
plt.title(f"normal {up_or_down}_{in_or_out}_b={b}")
plt.subplots_adjust(left=0.05, right=0.95, bottom=0.1, top=0.95,
wspace=0.2, hspace=0.5)
"""
wspace: 圖 column 與 column 間之大小
hspace: 圖 row 與 row 間之大小
"""
return fig
#%%
# https://www.machinelearningnuggets.com/gradio-tutorial/
import gradio as gr
with gr.Blocks() as app:
with gr.Row():
S0 = gr.Textbox(value="100", label="S0") # initial stock price
K = gr.Textbox(value="95", label="K") # sigma
r = gr.Textbox(value="0.05", label="r") # risk-free interest rate
T = gr.Textbox(value="0.5", label="T") # time to maturity
sigma_L = gr.Textbox(value="0.2", label="sigma下限")
sigma_U = gr.Textbox(value="0.4", label="sigma上限")
num_sigma = gr.Textbox(value="30", label="sigma數量")
q = gr.Textbox(value="0", label="q")
NumPath = gr.Textbox(value="100000", label="路徑數量")
time_intervals_year = gr.Textbox(value="252", label="時間切割")
seed = gr.Textbox(value="123457", label="seed") #設定種子
in_or_out= gr.Radio(choices=['生效', '無效'], value='False', label= "方向")
up_or_down= gr.Radio(choices=['上升', '下降'], value='False', label= "種類")
inputs = [S0, K, r, T, sigma_L, sigma_U, num_sigma, q, NumPath, time_intervals_year, seed, in_or_out, up_or_down]
button = gr.Button(value="Submit")
outputs = [gr.Plot()]
button.click(fn=plot_European,
inputs=inputs,
outputs=outputs)
app.launch()