Spaces:
Sleeping
Sleeping
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() |