File size: 4,156 Bytes
a79dcc6
 
 
 
f101777
 
 
 
a79dcc6
 
 
 
 
 
 
 
f101777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a79dcc6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f101777
 
 
a79dcc6
 
f101777
a79dcc6
f101777
 
 
a79dcc6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f101777
 
 
 
 
 
a79dcc6
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.font_manager as fm
import tempfile
import requests
from prophet import Prophet
from datetime import datetime, timedelta
import logging

# 設置日誌
logging.basicConfig(level=logging.INFO,
                   format='%(asctime)s - %(levelname)s - %(message)s')

# 字體設置
def setup_font():
    try:
        url_font = "https://drive.google.com/uc?id=1eGAsTN1HBpJAkeVM57_C7ccp7hbgSz3_"
        response_font = requests.get(url_font)
        
        with tempfile.NamedTemporaryFile(delete=False, suffix='.ttf') as tmp_file:
            tmp_file.write(response_font.content)
            tmp_file_path = tmp_file.name
        
        fm.fontManager.addfont(tmp_file_path)
        mpl.rc('font', family='Taipei Sans TC Beta')
    except Exception as e:
        logging.error(f"字體設置失敗: {str(e)}")
        # 使用備用字體
        mpl.rc('font', family='SimHei')

def predict_stock_price(stock_code, period, prediction_days):
    try:
        # 下載股票數據
        df = yf.download(stock_code, period=period)
        if df.empty:
            return "無法獲取股票數據", None
        
        # 準備數據
        data = df.reset_index()
        data = data[['Date', 'Close']]
        data.columns = ['ds', 'y']
        
        # 訓練 Prophet 模型
        model = Prophet(daily_seasonality=True)
        model.fit(data)
        
        # 創建未來日期
        future = model.make_future_dataframe(periods=prediction_days)
        forecast = model.predict(future)
        
        # 繪製圖表
        plt.figure(figsize=(12, 6))
        
        # 繪製實際數據
        plt.plot(data['ds'], data['y'], 
                label='實際收盤價', 
                color='blue')
        
        # 繪製預測數據
        plt.plot(forecast['ds'], forecast['yhat'],
                label='預測收盤價',
                color='orange',
                linestyle='--')
        
        # 添加預測區間
        plt.fill_between(forecast['ds'],
                        forecast['yhat_lower'],
                        forecast['yhat_upper'],
                        color='orange',
                        alpha=0.2)
        
        # 設置圖表格式
        plt.title(f'{stock_code} 股價預測', pad=20)
        plt.xlabel('日期')
        plt.ylabel('股價')
        plt.xticks(rotation=45)
        plt.legend()
        plt.grid(True, linestyle='--', alpha=0.7)
        plt.tight_layout()
        
        # 返回預測結果和圖表
        return forecast.tail(prediction_days).to_string(), plt.gcf()
        
    except Exception as e:
        logging.error(f"預測過程發生錯誤: {str(e)}")
        return f"預測過程發生錯誤: {str(e)}", None

# 初始化字體
setup_font()

# Gradio 介面
with gr.Blocks() as demo:
    gr.Markdown("# 股票價格 Stock Price 預測系統 Prophet")
    
    with gr.Column():
        # 輸入區域
        with gr.Row():
            stock_input = gr.Textbox(
                label="股票代碼",
                placeholder="例如: 2330.TW",
                value="2330.TW"
            )
            
            period_dropdown = gr.Dropdown(
                choices=["1mo", "3mo", "6mo", "1y", "2y", "5y", "10y", "max"],
                label="歷史數據期間",
                value="1y"
            )
            
            prediction_days = gr.Slider(
                minimum=5,
                maximum=30,
                value=5,
                step=1,
                label="預測天數"
            )
        
        predict_button = gr.Button("開始預測", variant="primary")
        
        # 輸出區域(垂直排列)
        output_plot = gr.Plot(label="股價預測圖")
        output_text = gr.Textbox(label="預測結果", lines=10)
    
    predict_button.click(
        predict_stock_price,
        inputs=[stock_input, period_dropdown, prediction_days],
        outputs=[output_text, output_plot]
    )

# 啟動應用
if __name__ == "__main__":
    demo.launch()