File size: 4,373 Bytes
fdbabd0 |
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 |
import gradio as gr
import yfinance as yf
import pandas as pd
import plotly.graph_objs as go
from plotly.subplots import make_subplots
def fetch_etf_data(ticker_codes):
"""
抓取台灣ETF歷史數據
參數:
ticker_codes (str): ETF代碼,逗號分隔
返回:
tuple: 數據框和圖表
"""
# 拆分代碼
ticker_list = [code.strip() for code in ticker_codes.split(',')]
# 儲存所有ETF的數據
results = {}
# 創建子圖
fig = make_subplots(
rows=len(ticker_list),
cols=1,
shared_xaxes=True,
vertical_spacing=0.02,
subplot_titles=[f"{code}.TW" for code in ticker_list]
)
# 顏色列表
colors = ['blue', 'green', 'red', 'purple', 'orange']
# 遍歷每個ETF代碼
output_text = ""
for i, ticker_code in enumerate(ticker_list, 1):
try:
# 添加 ".TW" 後綴(台灣交易所)
full_ticker = f"{ticker_code}.TW"
# 獲取ETF數據
etf = yf.Ticker(full_ticker)
# 獲取1年歷史數據
df = etf.history(period="1y")
# 如果數據為空,跳過此ETF
if df.empty:
output_text += f"警告:未找到 {full_ticker} 的數據\n"
continue
# 儲存數據
results[ticker_code] = df
# 添加K線圖
fig.add_trace(
go.Candlestick(
x=df.index,
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
name=full_ticker,
increasing_line_color=colors[i % len(colors)],
decreasing_line_color='gray'
),
row=i, col=1
)
# 添加成交量柱狀圖
fig.add_trace(
go.Bar(
x=df.index,
y=df['Volume'],
name=f'{full_ticker} 成交量',
opacity=0.5
),
row=i, col=1
)
# 生成文本輸出
output_text += f"\n{full_ticker} 最近數據:\n"
output_text += df.tail().to_string() + "\n"
except Exception as e:
output_text += f"{ticker_code} 發生錯誤: {e}\n"
# 更新佈局
fig.update_layout(
height=300 * len(ticker_list), # 根據ETF數量調整高度
title='台灣ETF走勢圖',
xaxis_rangeslider_visible=False # 關閉範圍滑塊
)
# 合併CSV
if results:
combined_df = pd.concat([df for df in results.values()], keys=results.keys(), names=['ETF', 'index'])
combined_df.to_csv("combined_etf_data.csv", encoding='utf-8-sig')
output_text += "\n所有ETF數據已合併保存到 combined_etf_data.csv"
return fig, output_text
def create_gradio_interface():
"""
創建Gradio界面
"""
with gr.Blocks(title="台灣ETF數據分析") as demo:
gr.Markdown("## 台灣ETF數據抓取與分析")
with gr.Row():
with gr.Column():
# 輸入框
ticker_input = gr.Textbox(
label="輸入ETF代碼",
placeholder="例如:00878, 00940, 0050",
value="00878, 00940, 0050"
)
# 提交按鈕
submit_btn = gr.Button("分析ETF")
with gr.Column():
# 文本輸出
output_text = gr.Textbox(label="分析結果")
# 圖表輸出
output_plot = gr.Plot(label="ETF走勢圖")
# 提交事件
submit_btn.click(
fn=fetch_etf_data,
inputs=ticker_input,
outputs=[output_plot, output_text]
)
return demo
# 啟動Gradio應用
def main():
demo = create_gradio_interface()
demo.launch(
share=True, # 創建公開連結
server_name='0.0.0.0', # 允許外部訪問
server_port=7860 # 指定端口
)
# 運行主程序
if __name__ == "__main__":
main() |