Rooobert commited on
Commit
cc14865
·
verified ·
1 Parent(s): 10a2f18

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +205 -0
app.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import yfinance as yf
3
+ import plotly.graph_objects as go
4
+ from plotly.subplots import make_subplots
5
+ import pandas as pd
6
+ import twstock
7
+ from datetime import datetime, timedelta
8
+
9
+ def plot_stock_data(stock_symbols, period='1y'):
10
+ """
11
+ 繪製股票價格圖表
12
+ :param stock_symbols: 股票代號列表
13
+ :param period: 時間區間
14
+ :return: Plotly figure
15
+ """
16
+ # 創建子圖
17
+ fig = make_subplots(
18
+ rows=len(stock_symbols),
19
+ cols=1,
20
+ subplot_titles=[f"股價走勢: {symbol}" for symbol in stock_symbols],
21
+ vertical_spacing=0.05,
22
+ specs=[[{"secondary_y": True}] for _ in stock_symbols]
23
+ )
24
+
25
+ # 為每個股票繪製圖形
26
+ for idx, symbol in enumerate(stock_symbols, 1):
27
+ try:
28
+ # 獲取股票數據
29
+ stock = yf.Ticker(symbol)
30
+ df = stock.history(period=period)
31
+
32
+ if df.empty:
33
+ st.warning(f"無法找到 {symbol} 的股票數據")
34
+ continue
35
+
36
+ # 添加蠟燭圖
37
+ fig.add_trace(
38
+ go.Candlestick(
39
+ x=df.index,
40
+ open=df['Open'],
41
+ high=df['High'],
42
+ low=df['Low'],
43
+ close=df['Close'],
44
+ name=f'{symbol} 價格'
45
+ ),
46
+ row=idx, col=1
47
+ )
48
+
49
+ # 添加成交量柱狀圖
50
+ fig.add_trace(
51
+ go.Bar(
52
+ x=df.index,
53
+ y=df['Volume'],
54
+ name=f'{symbol} 成交量',
55
+ opacity=0.3
56
+ ),
57
+ row=idx, col=1,
58
+ secondary_y=True
59
+ )
60
+
61
+ # 添加移動平均線
62
+ for ma_days in [5, 20, 60]:
63
+ ma = df['Close'].rolling(window=ma_days).mean()
64
+ fig.add_trace(
65
+ go.Scatter(
66
+ x=df.index,
67
+ y=ma,
68
+ name=f'{symbol} MA{ma_days}',
69
+ line=dict(width=1)
70
+ ),
71
+ row=idx, col=1
72
+ )
73
+
74
+ except Exception as e:
75
+ st.error(f"處理 {symbol} 時發生錯誤: {str(e)}")
76
+
77
+ # 更新布局
78
+ fig.update_layout(
79
+ height=400 * len(stock_symbols),
80
+ title_text="台股分析圖",
81
+ showlegend=True,
82
+ xaxis_rangeslider_visible=False,
83
+ template="plotly_white"
84
+ )
85
+
86
+ # 更新軸標籤
87
+ for i in range(1, len(stock_symbols) + 1):
88
+ fig.update_xaxes(title_text="日期", row=i, col=1)
89
+ fig.update_yaxes(title_text="價格 (TWD)", row=i, col=1)
90
+ fig.update_yaxes(title_text="成交量", row=i, col=1, secondary_y=True)
91
+
92
+ return fig
93
+
94
+ def fetch_recent_stock_data(stock_code):
95
+ """
96
+ 使用 twstock 獲取近期股票交易數據
97
+ """
98
+ try:
99
+ stock = twstock.Stock(stock_code)
100
+ recent_data = stock.fetch_31() # 抓取最近 31 天的交易數據
101
+
102
+ if not recent_data:
103
+ st.warning(f"無法找到 {stock_code} 的交易數據。")
104
+ return None
105
+
106
+ # 將數據整理為 DataFrame 格式
107
+ data_list = [
108
+ {
109
+ "Date": data.date.strftime('%Y-%m-%d'),
110
+ "Open": data.open,
111
+ "High": data.high,
112
+ "Low": data.low,
113
+ "Close": data.close,
114
+ "Transaction": data.transaction,
115
+ "Capacity": data.capacity,
116
+ "Turnover": data.turnover
117
+ }
118
+ for data in recent_data
119
+ ]
120
+ df = pd.DataFrame(data_list)
121
+ return df
122
+
123
+ except Exception as e:
124
+ st.error(f"發生錯誤: {e}")
125
+ return None
126
+
127
+ def main():
128
+ st.set_page_config(page_title="台股分析工具", page_icon=":chart_with_upwards_trend:", layout="wide")
129
+
130
+ st.title("🚀 台股分析工具")
131
+
132
+ # 側邊欄設置
133
+ with st.sidebar:
134
+ st.header("股票分析設定")
135
+
136
+ # 股票代碼輸入
137
+ stock_input = st.text_input(
138
+ "股票代號 (用逗號分隔)",
139
+ value="2330.TW,2454.TW",
140
+ placeholder="例如: 2330.TW,2454.TW"
141
+ )
142
+
143
+ # 時間區間選擇
144
+ period_select = st.selectbox(
145
+ "選擇時間區間",
146
+ ["1mo", "3mo", "6mo", "1y", "2y", "5y", "max"],
147
+ index=3 # 預設為 1y
148
+ )
149
+
150
+ # 股票分析頁籤
151
+ tab1, tab2 = st.tabs(["股價走勢圖", "近期交易數據"])
152
+
153
+ with tab1:
154
+ # 股價走勢圖
155
+ if st.button("繪製股價走勢圖"):
156
+ # 處理股票代號
157
+ stocks = [s.strip() for s in stock_input.split(',')]
158
+ stocks = [f"{s}.TW" if not s.endswith('.TW') and s.isdigit() else s for s in stocks]
159
+
160
+ # 創建圖表
161
+ fig = plot_stock_data(stocks, period_select)
162
+ st.plotly_chart(fig, use_container_width=True)
163
+
164
+ with tab2:
165
+ # 近期交易數據
166
+ st.subheader("個股近期交易數據")
167
+
168
+ single_stock_code = st.text_input(
169
+ "請輸入股票代碼",
170
+ placeholder="例如: 2330"
171
+ )
172
+
173
+ if st.button("查詢交易數據"):
174
+ if single_stock_code:
175
+ # 獲取近期股票數據
176
+ df = fetch_recent_stock_data(single_stock_code)
177
+
178
+ if df is not None:
179
+ # 顯示數據
180
+ st.dataframe(df)
181
+
182
+ # 統計資訊
183
+ st.subheader("基本統計")
184
+ col1, col2, col3 = st.columns(3)
185
+
186
+ with col1:
187
+ st.metric("平均收盤價", f"{df['Close'].mean():.2f}")
188
+
189
+ with col2:
190
+ st.metric("最高價", f"{df['High'].max():.2f}")
191
+
192
+ with col3:
193
+ st.metric("最低價", f"{df['Low'].min():.2f}")
194
+
195
+ # 匯出 CSV
196
+ csv_data = df.to_csv(index=False).encode('utf-8-sig')
197
+ st.download_button(
198
+ label="下載CSV",
199
+ data=csv_data,
200
+ file_name=f"{single_stock_code}_recent_30days.csv",
201
+ mime="text/csv"
202
+ )
203
+
204
+ if __name__ == "__main__":
205
+ main()