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() |