Spaces:
Sleeping
Sleeping
File size: 7,671 Bytes
1eca702 e7ab402 b127fbd 00d1951 aed74fe 72f648f aed74fe f7b023a 00d1951 f7b023a ef62153 b127fbd 9ed40f8 68c0bb3 db216d9 c6677a7 4afb719 aad28e9 b127fbd 8217f0b 8365013 2244c21 b127fbd 18e014e b127fbd 18e014e b127fbd b0129c1 18e014e b127fbd 18e014e b0129c1 fcaaa24 b0129c1 fcaaa24 b127fbd fcaaa24 b0129c1 18e014e b127fbd 18e014e b0129c1 b127fbd 3e16c1e 641f42e 3e16c1e 18e014e 874d51b 3e16c1e b127fbd 8365013 dd68bef 1eca702 8803d67 7a0c4b6 1eca702 7a0c4b6 0f39e11 1eca702 0f39e11 f7b023a 68c8c82 f7b023a 68c0bb3 aed74fe 99631c2 aefc716 1eca702 7a0c4b6 1eca702 f7b023a 68c8c82 f7b023a 1eca702 68c0bb3 3711265 68c0bb3 f7b023a 00d30d0 1eca702 b127fbd 3cca38c 1eca702 5e42d81 b127fbd ef62153 3e1cb2c 5e42d81 b127fbd 8a87dea 1eca702 b127fbd 3cca38c 59d2785 1eca702 b127fbd 59d2785 1eca702 59d2785 b127fbd 59d2785 3e1cb2c 59d2785 b127fbd 59d2785 1eca702 b127fbd 6507acf b127fbd f7b023a 04706d1 5e42d81 b127fbd 16341e0 469627c b127fbd 4df6e43 b127fbd 27f3e8a e7ab402 b127fbd 4afb719 b127fbd 917b23a db216d9 9ed40f8 b127fbd 85c652b b127fbd 9ed40f8 b5147e5 85c652b 47320f8 e7ab402 00d1951 | 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 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | import gradio as gr
import sys
import time
import queue
import threading
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import os
from sklearn import datasets
from sklearn.cluster import KMeans
from sklearn.cluster import DBSCAN
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.tree import export_text
from sklearn import metrics
import datetime
from sklearn.neural_network import MLPClassifier
from stock_manager import StockDataManager
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
manager = StockDataManager()
def run_all(tickersymbol, download_data, download_update, use_train, PREDICT, predict_date):
# 產生設定參數摘要
config_str = f"股票代碼:{tickersymbol}\n"
config_str += f"更新資料:{'是' if download_data else '否'}{f' (日期: {download_update})' if download_data else ''}\n"
config_str += f"啟用訓練:{'是' if use_train else '否'}\n"
config_str += f"啟用預測:{'是' if PREDICT else '否'}{f'(日期: {predict_date})'if PREDICT else ''}\n"
yield config_str
# --- 新增自訂的標準輸出攔截器 ---
class GlobalStreamInterceptor:
def __init__(self, q, original_stdout):
self.q = q
self.original_stdout = original_stdout
def write(self, buf):
self.original_stdout.write(buf)
# 這裡不 strip,保留原始內容給邏輯判斷
if buf not in ["\n", ""]:
self.q.put(buf)
def flush(self):
# 必須呼叫原始 stdout 的 flush,確保資料被清出緩衝區
self.original_stdout.flush()
# 儲存最原始的 stdout
original_stdout = sys.stdout
stdout_lock = threading.Lock()
def run_external_code(tickersymbol, download_data, download_update, use_train, method, PREDICT, predict_date):
q = queue.Queue()
def background_task():
# 取得鎖,確保不會有兩個任務同時搶奪 stdout
with stdout_lock:
old_stdout = sys.stdout
sys.stdout = GlobalStreamInterceptor(q, old_stdout)
try:
# 執行原本的邏輯
if download_data:
manager.fetch_data(end_date=download_update)
else:
print("Populating ticker from files...")
manager.load_raw_data(isProcessData=False)
# reads CSV files saved by fetch_data()
if use_train:
manager.trainModel(
ticker = tickersymbol,
epochs_general = 10,
epochs_particular = 10
)
#manager.trainMTAModel(ticker=tickersymbol, loss_fn=method)
if PREDICT:
signal = manager.predict_day(ticker=tickersymbol, date=predict_date)
print(f"\nFinal signal: {signal:+.4f}")
except Exception as e:
print(f"Error occurred: {str(e)}")
finally:
# 確保還原
with stdout_lock:
sys.stdout = original_stdout
q.put(None)
thread = threading.Thread(target=background_task, daemon=True)
thread.start()
log_messages = ""
# 監聽佇列
while True:
try:
# 嘗試取得佇列內容
chunk = q.get(timeout=0.5)
# 檢查是否為結束信號
if chunk is None:
break
clean_chunk = str(chunk).strip()
if clean_chunk:
log_messages += clean_chunk + "\n"
yield log_messages
# 修正 SyntaxError:補上 try 對應的 except 區塊
except queue.Empty:
# 如果佇列空了但執行緒已結束,則跳出
if not thread.is_alive():
break
continue
def update_setup(is_checked):
return gr.update(visible=is_checked)
def train_setup(is_checked):
return gr.update(visible=is_checked)
def predict_setup(is_checked):
return gr.update(visible=is_checked)
def update_ticker_list(market_choice):
if market_choice == "TW50":
if not manager.tw50_tickers:
manager.fillTw50Tickers()
new_choices = manager.tw50_tickers if manager.tw50_tickers else ["抓取TW50失敗"]
return gr.update(choices=new_choices, value=new_choices[0])
elif market_choice == "SP500":
if not manager.sp500_tickers:
manager.fillSp500Tickers()
new_choices = manager.sp500_tickers if manager.sp500_tickers else ["抓取SP50失敗"]
return gr.update(choices=new_choices, value=new_choices[0])
return gr.update(choices=["No tickers loaded"], value="No tickers loaded")
symbol_list = ["No tickers loaded"]
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
tomorow = today + datetime.timedelta(days=1)
with gr.Blocks() as demo:
gr.Markdown("### 股票分析與訓練設定")
with gr.Row():
market_radio = gr.Radio(
choices = ["TW50", "SP500"],
label = "選擇市場板塊",
value = None
)
ticker_list = gr.Dropdown(
choices = symbol_list,
label = "股票代碼",
value = symbol_list[0]
)
with gr.Row():
UPDATE_DATA = gr.Checkbox(label="更新資料", value=False)
end_date = gr.DateTime(
label = "選擇數據更新日",
type = "string",
value = yesterday.strftime("%Y-%m-%d"),
interactive=True,
include_time = False,
visible = False
)
with gr.Row():
TRAIN = gr.Checkbox(label="啟用訓練功能", value=False)
with gr.Row():
PREDICT = gr.Checkbox(label="啟用預測功能", value=False)
predict_date = gr.DateTime(
label = "選擇預測日期",
type = "string",
value = today.strftime("%Y-%m-%d"),
interactive=True,
include_time = False,
visible = False
)
with gr.Row():
run_btn = gr.Button("啟動", variant="primary")
##--觸發事件--
market_radio.change(
fn = update_ticker_list,
inputs = market_radio,
outputs = ticker_list
)
UPDATE_DATA.change(
fn = update_setup,
inputs = UPDATE_DATA,
outputs = end_date
)
PREDICT.change(
fn = predict_setup,
inputs = PREDICT,
outputs = predict_date
)
#--兩個輸出欄位--
config_display = gr.Textbox(label="目前設定參數", lines=3)
# 加上 autoscroll=True 讓日誌自動向下捲動
output_text = gr.Textbox(label="控制台輸出內容", lines=10, autoscroll=True)
# 第一個 Click 事件負責更新左邊/上方的參數區塊
run_btn.click(
fn = run_all,
inputs = [ticker_list, UPDATE_DATA, end_date, TRAIN, PREDICT, predict_date],
outputs = [config_display]
)
# 第二個 Click 事件負責在背景跑訓練,並透過 yield 即時更新 output_text
run_btn.click(
fn = run_external_code,
inputs = [ticker_list, UPDATE_DATA, end_date, TRAIN, PREDICT, predict_date],
outputs = output_text
)
demo.launch(ssr_mode=False) |