ypchangchatgpt/European_option-streamlit-plotly-docker
0
1import numpy as np2from scipy.stats import qmc, norm3import plotly.graph_objects as go4import streamlit as st5 6# 設置 Streamlit 頁面的基本配置7st.set_page_config(page_title="European option", # 設定網頁標題8 layout="wide", # 設定頁面布局為寬屏模式9 initial_sidebar_state="expanded") # 初始時側邊欄狀態為展開10 11st.title("Geometric Brownian motion 模型下,利用模擬方法得到歐式選擇權 (European option) 評價")12 13with st.sidebar.form(key="my_form"):14 option_type = st.radio("選擇權型態",15 ("Call", "Put"),16 horizontal=True)17 18 S0 = st.slider("選擇期初股價 S0",19 min_value=50,20 max_value=300,21 value=100)22 23 K = st.slider("選擇履約價格 K",24 min_value=50,25 max_value=300,26 value=100)27 28 T = st.slider("選擇到期時間 T (年)",29 min_value=0.1,30 max_value=2.0,31 value=1.0,32 step=0.1)33 34 r = st.slider("選擇無風險利率 r",35 min_value=0.01,36 max_value=0.10,37 value=0.03,38 step=0.01)39 40 sigma = st.slider("選擇波動率 σ",41 min_value=0.1,42 max_value=0.5,43 value=0.2,44 step=0.05)45 46 n_simulations = st.slider("選擇模擬次數",47 min_value=1000,48 max_value=20000,49 value=10000,50 step=1000)51 52 n_experiments = st.slider("選擇實驗重複次數",53 min_value=100,54 max_value=10000,55 value=1000,56 step=100)57 58 seed = st.text_input(label="亂數種子", value="123457")59 60 submit_button = st.form_submit_button(label="Submit")61 62 63#%%64# 計算歐式選擇權價格並進行折現65def European_option_price(S0, K, r, T, sigma, option_type="Call"):66 # Black-Scholes 公式67 d1 = (np.log(S0/K)+(r+0.5*sigma**2)*T)/(sigma*np.sqrt(T))68 d2 = d1-sigma*np.sqrt(T)69 70 # 真實的 call option 價格71 if option_type == "Call":72 true_option_price = S0*norm.cdf(d1)-K*np.exp(-r*T)*norm.cdf(d2)73 74 # 真實的 put option 價格75 if option_type == "Put":76 true_option_price = K*np.exp(-r*T)*norm.cdf(-d2)-S0*norm.cdf(-d1)77 return true_option_price78 79def European_option_price_simulation(S0, K, r, T, sigma, z, option_type="Call"):80 ST = S0*np.exp((r-0.5*sigma**2)*T+sigma*np.sqrt(T)*z)81 if option_type == "Call":82 payoff = np.maximum(ST-K, 0)83 if option_type == "Put":84 payoff = np.maximum(K-ST, 0)85 option_price = np.exp(-r*T)*np.mean(payoff)86 return option_price87 88option_prices_pseudo, option_prices_quasi, option_prices_numpy = [], [], []89if submit_button:90 bar = st.progress(20, "Start calculation")91 # 顯示進度條92 93 np.random.seed(int(seed))94 sobol_engine = qmc.Sobol(d=1, scramble=True, seed=int(seed))95 for _ in range(n_experiments):96 # 使用 pseudo-random numbers97 u_pseudo_uniform = np.random.uniform(0, 1, n_simulations)98 z_pseudo_random = norm.ppf(u_pseudo_uniform)99 option_price_pseudo = European_option_price_simulation(S0, K, r, T, sigma, z_pseudo_random, option_type=option_type)100 option_prices_pseudo.append(option_price_pseudo)101 102 # 使用 quasi-random numbers103 u_quasi_random = sobol_engine.random(n=n_simulations).flatten()104 z_quasi_random = norm.ppf(u_quasi_random)105 option_price_quasi = European_option_price_simulation(S0, K, r, T, sigma, z_quasi_random, option_type=option_type)106 option_prices_quasi.append(option_price_quasi)107 108 # 使用 Numpy random109 z_numpy_random = np.random.normal(0, 1, n_simulations)110 option_price_numpy = European_option_price_simulation(S0, K, r, T, sigma, z_numpy_random, option_type=option_type)111 option_prices_numpy.append(option_price_numpy)112 113 true_option_price = European_option_price(S0, K, r, T, sigma, option_type=option_type)114 115 bar = bar.progress(80, "計算中")116 117 118#%%119 from plotly.subplots import make_subplots120 121 st.subheader(option_type+" option 價格分布比較")122 123 # 創建包含三個子圖的圖表124 fig = make_subplots(rows=3, cols=1, subplot_titles=("pseudo-random numbers (np.random.uniform)",125 "quasi-random numbers (qmc.Sobol)",126 "pseudo-random numbers (np.random.normal)"))127 128 nbinsx = 30129 fig.add_trace(130 go.Histogram(x=option_prices_pseudo,131 nbinsx=nbinsx,132 histnorm="probability density",133 name="pseudo-random numbers (np.random.uniform)",134 marker=dict(color="rgba(0,0,255,0.15)", line=dict(width=1, color="black")),135 opacity=1.0),136 row=1, col=1)137 138 fig.add_trace(139 go.Histogram(x=option_prices_quasi,140 nbinsx=nbinsx,141 histnorm="probability density",142 name="quasi-random numbers (qmc.Sobol)",143 marker=dict(color="rgba(255,0,0,0.15)", line=dict(width=1, color="black")),144 opacity=1.0),145 row=2, col=1)146 147 fig.add_trace(148 go.Histogram(x=option_prices_numpy,149 nbinsx=nbinsx,150 histnorm="probability density",151 name="pseudo-random numbers (np.random.normal)",152 marker=dict(color="rgba(0,255,0,0.15)", line=dict(width=1, color="black")),153 opacity=1.0),154 row=3, col=1)155 156 fig.add_vline(x=true_option_price,157 line_width=2,158 line_dash="dash",159 line_color="blue")160 161 fig.update_layout(162 title="不同方法計算的 "+option_type+" option 價格分布",163 height=900)164 165 fig.update_xaxes(title=option_type+" option 價格", row=1, col=1)166 fig.update_xaxes(title=option_type+" option 價格", row=2, col=1)167 fig.update_xaxes(title=option_type+" option 價格", row=3, col=1)168 169 fig.update_yaxes(title="density", row=1, col=1)170 fig.update_yaxes(title="density", row=2, col=1)171 fig.update_yaxes(title="density", row=3, col=1)172 173 st.plotly_chart(fig)174 175 bar = bar.progress(100, "OK")176 177# 打開 "命令提示字元" 或 "終端機",開始執行程式 (或進入 Command Prompt 視窗):178# (a) Anaconda => Anaconda Prompt (or Anaconda Powershell Prompt)179# (b) WinPython => WinPython Command Prompt.exe180# Streamlit run "c:\work\subject\112\simulation\tronclass\(2024.03.21) pseudo-random numbers vs quasi-random numbers-european_option\03-pseudo-random numbers vs quasi-random numbers-european_option-streamlit2.py"181# Google Chrome => http://localhost:8501/182# Google Chrome 不關掉,程式修改存檔後,可直接執行 Google Chrome output 畫面右上角的 Return。183# 指定 localhost port => streamlit run app.py --server.port 8502184# 需要終止該應用程式只需在終端中按 Ctrl + C。185# 路徑和檔名不能有中文。186# Mac 不能使用 MacOS 內建的 Safari 瀏覽器,改用 Google Chrome 就沒問題了。187 