# 不使用 for 迴圈。 # 發佈到 Hugging Face 伺服器,程式不能有 %reset -f (magic functions) import numpy as np from scipy import stats import matplotlib import matplotlib.pyplot as plt import mpltw matplotlib.use("Agg") # 使用 gradio+matplotlib 套件,這行一定要寫。 font_size = 8 plt.rcParams.update({"font.size": font_size}) plt.close("all") #%% # quasi-random numbers 時,調整避免產生的模擬資料是 0 或 1。 # 寫為函數: 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 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 European_option_simulation(S0, K, r, T, sigma, Z): ST = S0*np.exp((r-0.5*sigma**2)*T+sigma*np.sqrt(T)*Z) payoff = np.maximum(ST-K, 0) prices = np.exp(-r*T)*np.mean(payoff, axis=0) return prices #%% def plot_European_option(S0, K, r, T, sigma, n, m, seed, bins, alpha): S0 = np.float64(S0) K = np.float64(K) r = np.float64(r) T = np.float64(T) sigma = np.float64(sigma) price_true = Black_Scholes(S0, K, r, T, sigma, option_type="call") print("European call option price =", price_true) n = int(n) m = int(m) seed = int(seed) bins = int(bins) alpha = np.float64(alpha) # pseudo-random numbers np.random.seed(seed) u_pseudo = np.random.rand(n, m) Z_pseudo = stats.norm.ppf(u_pseudo) # quasi-random numbers Sobol_seq = stats.qmc.Sobol(d=m, scramble=True, seed=seed) """ scramble 內建值為 True。 Scramble 是指將一個序列或集合中的元素加干擾的過程。 """ u_quasi = generate_Sobol(Sobol_seq, n=n, epsilon=1e-8) Z_quasi = stats.norm.ppf(u_quasi) """ Sobol_seq = stats.qmc.Sobol(d=n, seed=seed) u_quasi = Sobol_seq.random(m) Z_quasi = stats.norm.ppf(u_quasi).T # 這個寫法沒有明顯效果,所以要注意 d 的設定。 """ prices_pseudo = European_option_simulation(S0, K, r, T, sigma, Z_pseudo) prices_quasi = European_option_simulation(S0, K, r, T, sigma, Z_quasi) fig = plt.figure(figsize=(4, 8)) plt.subplot(211) plt.hist(prices_pseudo, bins=bins, density=True, alpha=alpha, ec="black") plt.axvline(x=price_true, color="red") plt.xlabel("simulate option price") plt.ylabel("density") plt.title("Simulate option prices with pseudo-random numbers") plt.subplot(212) plt.hist(prices_quasi, bins=bins, density=True, alpha=alpha, ec="black") plt.axvline(x=price_true, color="red") plt.xlabel("simulate option price") plt.ylabel("density") plt.title("Simulate option prices with quasi-random numbers") plt.tight_layout() return fig #%% import gradio as gr S0 = gr.Textbox(value="100", label="S0") # initial stock price K = gr.Textbox(value="100", label="K") # strike price r = gr.Textbox(value="0.02", label="r") # risk-free interest rate T = gr.Textbox(value="0.5", label="T") # time to maturity sigma = gr.Textbox(value="0.2", label="sigma") # volatility n = gr.Textbox(value="10000", label="n") # number of simulations m = gr.Textbox(value="1000", label="m") # number of repeated experiments seed = gr.Textbox(value="123457", label="seed") bins = gr.Slider(minimum=10, maximum=60, step=5, value=40, label="bins") alpha = gr.Slider(minimum=0, maximum=1, step=0.1, value=0.6, label="alpha") inputs = [S0, K, r, T, sigma, n, m, seed, bins, alpha] outputs = [gr.Plot()] interface = gr.Interface(fn=plot_European_option, inputs=inputs, outputs=outputs, title="European call option") interface.launch(share=True) # share=True 一定要寫,瀏覽器才可以看到結果。 # 但發佈到 Hugging Face 伺服器,則 share=True 可以不寫。