ypchangchatgpt commited on
Commit
faa7863
1 Parent(s): 5f6bd31

Upload 2 files

Browse files
Files changed (2) hide show
  1. Dockerfile +27 -0
  2. app.py +186 -0
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.8.9
2
+
3
+ WORKDIR /app
4
+
5
+ COPY ./requirements.txt /app/requirements.txt
6
+ COPY ./packages.txt /app/packages.txt
7
+
8
+ RUN apt-get update && xargs -r -a /app/packages.txt apt-get install -y && rm -rf /var/lib/apt/lists/*
9
+ RUN pip3 install --no-cache-dir -r /app/requirements.txt
10
+
11
+ # User
12
+ RUN useradd -m -u 1000 user
13
+ USER user
14
+ ENV HOME /home/user
15
+ ENV PATH $HOME/.local/bin:$PATH
16
+
17
+ WORKDIR $HOME
18
+ RUN mkdir app
19
+ WORKDIR $HOME/app
20
+ COPY . $HOME/app
21
+
22
+ EXPOSE 8501
23
+ CMD streamlit run app.py \
24
+ --server.headless true \
25
+ --server.enableCORS false \
26
+ --server.enableXsrfProtection false \
27
+ --server.fileWatcherType none
app.py ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from scipy.stats import qmc, norm
3
+ import plotly.graph_objects as go
4
+ import streamlit as st
5
+
6
+ # 設置 Streamlit 頁面的基本配置
7
+ st.set_page_config(page_title="European option", # 設定網頁標題
8
+ layout="wide", # 設定頁面布局為寬屏模式
9
+ initial_sidebar_state="expanded") # 初始時側邊欄狀態為展開
10
+
11
+ st.title("Geometric Brownian motion 模型下,利用模擬方法得到歐式選擇權 (European option) 評價")
12
+
13
+ with 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
+ # 計算歐式選擇權價格並進行折現
65
+ def 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_price
78
+
79
+ def 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_price
87
+
88
+ option_prices_pseudo, option_prices_quasi, option_prices_numpy = [], [], []
89
+ if 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 numbers
97
+ 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 numbers
103
+ 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 random
109
+ 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_subplots
120
+
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 = 30
129
+ 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.exe
180
+ # 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 8502
184
+ # 需要終止該應用程式只需在終端中按 Ctrl + C。
185
+ # 路徑和檔名不能有中文。
186
+ # Mac 不能使用 MacOS 內建的 Safari 瀏覽器,改用 Google Chrome 就沒問題了。