Spaces:
Runtime error
Runtime error
import numpy as np | |
from scipy.stats import qmc, norm | |
import plotly.graph_objects as go | |
import streamlit as st | |
# 設置 Streamlit 頁面的基本配置 | |
st.set_page_config(page_title="European option", # 設定網頁標題 | |
layout="wide", # 設定頁面布局為寬屏模式 | |
initial_sidebar_state="expanded") # 初始時側邊欄狀態為展開 | |
st.title("Geometric Brownian motion 模型下,利用模擬方法得到歐式選擇權 (European option) 評價") | |
with st.sidebar.form(key="my_form"): | |
option_type = st.radio("選擇權型態", | |
("Call", "Put"), | |
horizontal=True) | |
S0 = st.slider("選擇期初股價 S0", | |
min_value=50, | |
max_value=300, | |
value=100) | |
K = st.slider("選擇履約價格 K", | |
min_value=50, | |
max_value=300, | |
value=100) | |
T = st.slider("選擇到期時間 T (年)", | |
min_value=0.1, | |
max_value=2.0, | |
value=1.0, | |
step=0.1) | |
r = st.slider("選擇無風險利率 r", | |
min_value=0.01, | |
max_value=0.10, | |
value=0.03, | |
step=0.01) | |
sigma = st.slider("選擇波動率 σ", | |
min_value=0.1, | |
max_value=0.5, | |
value=0.2, | |
step=0.05) | |
n_simulations = st.slider("選擇模擬次數", | |
min_value=1000, | |
max_value=20000, | |
value=10000, | |
step=1000) | |
n_experiments = st.slider("選擇實驗重複次數", | |
min_value=100, | |
max_value=10000, | |
value=1000, | |
step=100) | |
seed = st.text_input(label="亂數種子", value="123457") | |
submit_button = st.form_submit_button(label="Submit") | |
#%% | |
# 計算歐式選擇權價格並進行折現 | |
def European_option_price(S0, K, r, T, sigma, option_type="Call"): | |
# Black-Scholes 公式 | |
d1 = (np.log(S0/K)+(r+0.5*sigma**2)*T)/(sigma*np.sqrt(T)) | |
d2 = d1-sigma*np.sqrt(T) | |
# 真實的 call option 價格 | |
if option_type == "Call": | |
true_option_price = S0*norm.cdf(d1)-K*np.exp(-r*T)*norm.cdf(d2) | |
# 真實的 put option 價格 | |
if option_type == "Put": | |
true_option_price = K*np.exp(-r*T)*norm.cdf(-d2)-S0*norm.cdf(-d1) | |
return true_option_price | |
def European_option_price_simulation(S0, K, r, T, sigma, z, option_type="Call"): | |
ST = S0*np.exp((r-0.5*sigma**2)*T+sigma*np.sqrt(T)*z) | |
if option_type == "Call": | |
payoff = np.maximum(ST-K, 0) | |
if option_type == "Put": | |
payoff = np.maximum(K-ST, 0) | |
option_price = np.exp(-r*T)*np.mean(payoff) | |
return option_price | |
option_prices_pseudo, option_prices_quasi, option_prices_numpy = [], [], [] | |
if submit_button: | |
bar = st.progress(20, "Start calculation") | |
# 顯示進度條 | |
np.random.seed(int(seed)) | |
sobol_engine = qmc.Sobol(d=1, scramble=True, seed=int(seed)) | |
for _ in range(n_experiments): | |
# 使用 pseudo-random numbers | |
u_pseudo_uniform = np.random.uniform(0, 1, n_simulations) | |
z_pseudo_random = norm.ppf(u_pseudo_uniform) | |
option_price_pseudo = European_option_price_simulation(S0, K, r, T, sigma, z_pseudo_random, option_type=option_type) | |
option_prices_pseudo.append(option_price_pseudo) | |
# 使用 quasi-random numbers | |
u_quasi_random = sobol_engine.random(n=n_simulations).flatten() | |
z_quasi_random = norm.ppf(u_quasi_random) | |
option_price_quasi = European_option_price_simulation(S0, K, r, T, sigma, z_quasi_random, option_type=option_type) | |
option_prices_quasi.append(option_price_quasi) | |
# 使用 Numpy random | |
z_numpy_random = np.random.normal(0, 1, n_simulations) | |
option_price_numpy = European_option_price_simulation(S0, K, r, T, sigma, z_numpy_random, option_type=option_type) | |
option_prices_numpy.append(option_price_numpy) | |
true_option_price = European_option_price(S0, K, r, T, sigma, option_type=option_type) | |
bar = bar.progress(80, "計算中") | |
#%% | |
from plotly.subplots import make_subplots | |
st.subheader(option_type+" option 價格分布比較") | |
# 創建包含三個子圖的圖表 | |
fig = make_subplots(rows=3, cols=1, subplot_titles=("pseudo-random numbers (np.random.uniform)", | |
"quasi-random numbers (qmc.Sobol)", | |
"pseudo-random numbers (np.random.normal)")) | |
nbinsx = 30 | |
fig.add_trace( | |
go.Histogram(x=option_prices_pseudo, | |
nbinsx=nbinsx, | |
histnorm="probability density", | |
name="pseudo-random numbers (np.random.uniform)", | |
marker=dict(color="rgba(0,0,255,0.15)", line=dict(width=1, color="black")), | |
opacity=1.0), | |
row=1, col=1) | |
fig.add_trace( | |
go.Histogram(x=option_prices_quasi, | |
nbinsx=nbinsx, | |
histnorm="probability density", | |
name="quasi-random numbers (qmc.Sobol)", | |
marker=dict(color="rgba(255,0,0,0.15)", line=dict(width=1, color="black")), | |
opacity=1.0), | |
row=2, col=1) | |
fig.add_trace( | |
go.Histogram(x=option_prices_numpy, | |
nbinsx=nbinsx, | |
histnorm="probability density", | |
name="pseudo-random numbers (np.random.normal)", | |
marker=dict(color="rgba(0,255,0,0.15)", line=dict(width=1, color="black")), | |
opacity=1.0), | |
row=3, col=1) | |
fig.add_vline(x=true_option_price, | |
line_width=2, | |
line_dash="dash", | |
line_color="blue") | |
fig.update_layout( | |
title="不同方法計算的 "+option_type+" option 價格分布", | |
height=900) | |
fig.update_xaxes(title=option_type+" option 價格", row=1, col=1) | |
fig.update_xaxes(title=option_type+" option 價格", row=2, col=1) | |
fig.update_xaxes(title=option_type+" option 價格", row=3, col=1) | |
fig.update_yaxes(title="density", row=1, col=1) | |
fig.update_yaxes(title="density", row=2, col=1) | |
fig.update_yaxes(title="density", row=3, col=1) | |
st.plotly_chart(fig) | |
bar = bar.progress(100, "OK") | |
# 打開 "命令提示字元" 或 "終端機",開始執行程式 (或進入 Command Prompt 視窗): | |
# (a) Anaconda => Anaconda Prompt (or Anaconda Powershell Prompt) | |
# (b) WinPython => WinPython Command Prompt.exe | |
# 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" | |
# Google Chrome => http://localhost:8501/ | |
# Google Chrome 不關掉,程式修改存檔後,可直接執行 Google Chrome output 畫面右上角的 Return。 | |
# 指定 localhost port => streamlit run app.py --server.port 8502 | |
# 需要終止該應用程式只需在終端中按 Ctrl + C。 | |
# 路徑和檔名不能有中文。 | |
# Mac 不能使用 MacOS 內建的 Safari 瀏覽器,改用 Google Chrome 就沒問題了。 | |