Spaces:
Runtime error
Runtime error
File size: 7,497 Bytes
faa7863 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
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 就沒問題了。
|