台股股票清單抓取工具 - 功能分析
📋 程式概述
這是一個從台灣證券交易所官方 ISIN 系統自動抓取台灣本地普通股清單的 Python 工具。透過多執行緒並行處理,快速取得上市、上櫃、興櫃及創新板的所有 4 碼股票資料。
🎯 核心功能
1. 資料來源覆蓋
程式涵蓋台灣證券市場的 5 大板塊:
| 板塊 | 市場代碼 | 資料來源 | 代碼後綴 | 說明 |
|------------------|----------|----------|----------|----------------|
| 上市普通股 | market=1 | TWSE | .TW | 主板上市公司 |
| 上櫃普通股 | market=2 | TWSE | .TWO | 櫃買中心掛牌 |
| 興櫃 | market=E | TWSE | .TWO | 興櫃市場 |
| 創新板(上市) | market=C | TWSE | .TW | 創新板上市 |
| 創新板(上櫃) | market=A | TWSE | .TWO | 創新板上櫃 |
2. 智能過濾機制
🔍 核心過濾規則:# ✅ 只保留 4 位數字的股票代號
if not (stock_code.isdigit() and len(stock_code) == 4):
continue
自動排除項目:
- ❌ TDR(台灣存託憑證)- 代碼格式不同
- ❌ ETF(指數股票型基金)- 通常為 5 碼或特殊碼
- ❌ 權證(認購/認售權證)- 代碼超過 4 碼
- ❌ 特別股 - 代碼格式特殊
- ❌ 其他衍生商品 - 非標準 4 碼格式
✅ 保留項目: 僅保留標準 4 碼普通股,如:
- 2330(台積電)
- 2317(鴻海)
- 2454(聯發科)
⚡ 技術特點
1. 多執行緒並行處理
# ✅ 只保留 4 位數字的股票代號
if not (stock_code.isdigit() and len(stock_code) == 4):
continue
優勢:
- 🚀 同時抓取 5 個市場資料
- ⏱️ 執行時間縮短 80%
- 🔄 自動處理執行緒同步
2. 智能去重機制
try:
time.sleep(0.5) # 防止請求過於頻繁
response.raise_for_status() # 檢查 HTTP 狀態
except Exception as e:
print(f"❌ 抓取失敗: {str(e)}")
特色:
- 保留首次出現的資料(優先順序:上市 > 上櫃 > 興櫃)
- 避免同一檔股票重複出現
- 自動處理跨板塊重複
3. 錯誤處理與穩定性
try:
time.sleep(0.5) # 防止請求過於頻繁
response.raise_for_status() # 檢查 HTTP 狀態
except Exception as e:
print(f"❌ 抓取失敗: {str(e)}")
保護機制:
- ⏸️ 每次請求間隔 0.5 秒
- 🛡️ 完整的異常處理
- ⏱️ 10 秒請求超時設定
📊 資料格式說明
輸出變數
- stockid - 股票代碼列表:
['0050.TW', '0051.TW', '1101.TW', '1102.TW', ...]
格式:股票代號.交易所後綴 已排序(數字順序) 可直接用於 yfinance 等套件
- stockname - 完整資訊列表:
[
'0050.TW&元大台灣50',
'1101.TW&台泥',
'2330.TW&台積電',
...
]
格式:代碼&公司名稱 方便分割取得代碼或名稱 保留完整中文名稱
💡 使用範例
基本使用
# 執行主程式
main()
# 查看結果
print(f"共抓取 {len(stockid)} 檔台股")
# 取得特定股票資訊
for info in stockname:
code, name = info.split('&')
if '台積電' in name:
print(f"找到: {code} - {name}")
進階應用
- 轉換為 DataFrame:
import pandas as pd
df = pd.DataFrame({
'code': [s.split('&')[0] for s in stockname],
'name': [s.split('&')[1] for s in stockname]
})
2.按市場分類:
listed = [s for s in stockid if s.endswith('.TW')]
otc = [s for s in stockid if s.endswith('.TWO')]
print(f"上市: {len(listed)} 檔")
print(f"上櫃: {len(otc)} 檔")
3.搜尋特定股票:
keyword = "電子"
results = [s for s in stockname if keyword in s]
print(f"包含'{keyword}'的股票: {len(results)} 檔")
🔧 依賴套件
pip install requests pandas lxml
套件說明:
- requests - HTTP 請求
- pandas - HTML 表格解析
- lxml - HTML 解析器(pandas 依賴)
📈 執行結果範例
預期輸出: ✅ 總共抓取「台灣本地普通股」數量(4碼,已去重):1,850
🔹 前10個 stockname 範例:
0050.TW&元大台灣50
0051.TW&元大中型100
1101.TW&台泥
1102.TW&亞泥
1103.TW&嘉泥
1104.TW&環泥
1108.TW&幸福
1109.TW&信大
1110.TW&東泥
1201.TW&味全
🔹 前10個 stockid 範例:
0050.TW
0051.TW
1101.TW
1102.TW
1103.TW
1104.TW
1108.TW
1109.TW
1110.TW
1201.TW
統計分析
| 指標項目 | 數值範圍說明 |
|------------------|--------------------------|
| 📊 總數量 | 約 1,800–2,000 檔 |
| 🏢 上市股票 | 約 950–1,000 檔 |
| 🏪 上櫃股票 | 約 800–900 檔 |
| 🆕 興櫃/創新板 | 約 50–150 檔 |
🎓 適用場景
- 量化交易系統:
# 建立台股交易標的池
for stock in stockid:
# 下載歷史資料
# 計算技術指標
# 執行回測
2.資料分析專案:
# 批次下載所有台股資料
import yfinance as yf
for stock in stockid[:10]: # 測試前 10 檔
data = yf.download(stock, start='2024-01-01')
3.股票監控系統:
# 監控特定產業股票
semiconductor = [s for s in stockname if '半導體' in s or '電子' in s]
print(f"半導體相關: {len(
完整程式碼
import requests
from io import StringIO
import pandas as pd
import concurrent.futures
import time
# 設定全域變數
stockid = []
stockname = []
# 定義「僅普通股」的網址配置(已移除 TDR、權證、ETF)
url_configs = [
{'name': 'listed', 'url': 'https://isin.twse.com.tw/isin/class_main.jsp?market=1&issuetype=1&Page=1&chklike=Y', 'suffix': '.TW'}, # 上市普通股
{'name': 'otc', 'url': 'https://isin.twse.com.tw/isin/class_main.jsp?market=2&issuetype=4&Page=1&chklike=Y', 'suffix': '.TWO'}, # 上櫃普通股
{'name': 'rotc', 'url': 'https://isin.twse.com.tw/isin/class_main.jsp?owncode=&stockname=&isincode=&market=E&issuetype=R&industry_code=&Page=1&chklike=Y', 'suffix': '.TWO'}, # 興櫃
{'name': 'tw_innovation', 'url': 'https://isin.twse.com.tw/isin/class_main.jsp?owncode=&stockname=&isincode=&market=C&issuetype=C&industry_code=&Page=1&chklike=Y', 'suffix': '.TW'}, # 創新板(上市)
{'name': 'otc_innovation', 'url': 'https://isin.twse.com.tw/isin/class_main.jsp?owncode=&stockname=&isincode=&market=A&issuetype=C&industry_code=&Page=1&chklike=Y', 'suffix': '.TWO'}, # 創新板(上櫃)
]
def fetch_data(url_config):
"""抓取單一類別證券資料的函數(僅處理普通股)"""
try:
time.sleep(0.5)
response = requests.get(url_config['url'], timeout=10)
response.raise_for_status()
df = pd.read_html(StringIO(response.text), header=0)[0]
stock_ids = []
stock_names = []
for _, row in df.iterrows():
code_col = '有價證券代號'
name_col = '有價證券名稱'
stock_code = str(row[code_col]).strip()
stock_label = str(row[name_col]).strip()
suffix = url_config['suffix']
# 跳過無效資料
if not stock_code or not stock_label or suffix is None:
continue
# ✅ 關鍵過濾:只保留「4 位數字」的股票代號(排除 TDR、ETF、亂碼等)
if not (stock_code.isdigit() and len(stock_code) == 4):
continue
stock_id = f"{stock_code}{suffix}"
stock_ids.append(stock_id)
stock_names.append(f"{stock_id}&{stock_label}")
return {'type': 'stock', 'ids': stock_ids, 'names': stock_names}
except Exception as e:
print(f"❌ 抓取 {url_config['name']} 時發生錯誤: {str(e)}")
return None
def main():
global stockid, stockname
# 使用執行緒池處理所有類別
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(fetch_data, config) for config in url_configs]
for future in concurrent.futures.as_completed(futures):
result = future.result()
if not result:
continue
if result['type'] == 'stock':
stockid.extend(result['ids'])
stockname.extend(result['names'])
# 移除重複項(保留首次出現的名稱)
unique_stock_info = {}
for info in stockname:
sid = info.split('&')[0]
if sid not in unique_stock_info:
unique_stock_info[sid] = info
stockid = sorted(unique_stock_info.keys())
stockname = [unique_stock_info[sid] for sid in stockid]
# 顯示結果
print(f"✅ 總共抓取「台灣本地普通股」數量(4碼,已去重): {len(stockid)}")
print("\n🔹 前10個 stockname 範例:")
for i in range(min(10, len(stockname))):
print(stockname[i])
print("\n🔹 前10個 stockid 範例:")
for i in range(min(10, len(stockid))):
print(stockid[i])
if __name__ == "__main__":
main()
這是主力模組,負責根據 stockname 清單,從 Yahoo Finance 擷取每檔股票的完整歷史日K資料,並儲存為 CSV。
# -*- coding: utf-8 -*-
# =========================================================
# 台股歷史資料下載器(多執行緒;✅ 智慧續傳版;✅ 生產就緒)
# 存放路徑:/content/drive/MyDrive/各國股票檔案/tw-share/dayK
# Log 路徑:/content/drive/MyDrive/Log/台股日K資料下載器/
# Copyright (c) 2025 <Your Name>
# License: MIT
#
# 免責聲明:
# 1) 僅供研究與教學,不構成投資建議。
# 2) 資料來自 Yahoo Finance,可能有延遲或錯誤。
# 3) 再執行一次即可續傳未完成項目。
# =========================================================
import os, time, threading
from concurrent.futures import ThreadPoolExecutor, as_completed
import pandas as pd
import yfinance as yf
from tqdm import tqdm
from pathlib import Path
# ========== 使用者可調整參數 ==========
# 🔽 你可以修改以下參數以適應需求
MARKET_CODE = "tw-share" # 資料夾名稱(可用 cn-share, us-share...)
DATA_SUBDIR = "dayK" # 日K子資料夾名(可改為 daily, kbar...)
PROJECT_NAME = "台股日K資料下載器" # 專案名稱(用於 Log)
BASE_DATA_DIR = f"/content/drive/MyDrive/各國股票檔案/{MARKET_CODE}"
DATA_DIR = f"{BASE_DATA_DIR}/{DATA_SUBDIR}"
LOG_PARENT_DIR = "/content/drive/MyDrive/各國股票檔案/Log"
LOG_DIR = f"{LOG_PARENT_DIR}/{PROJECT_NAME}"
CKPT_FILE = f"{LOG_DIR}/checkpoint_tw.csv"
MAX_WORKERS = 8 # 多執行緒數量(Colab 免費版建議 5~8)
RETRY_DELAY = 1.0 # 下載失敗後等待秒數
MIN_FILE_SIZE = 100 # 判斷檔案是否有效的最小 byte 數
AUTO_ADJUST = False # 是否使用 yfinance 的 auto_adjust(建議 False)
# ========== 環境檢查與路徑建立 ==========
try:
from google.colab import drive
print("🔗 正在掛載 Google Drive...")
drive.mount('/content/drive', force_remount=False)
print("✅ Drive 已掛載")
except Exception:
raise RuntimeError("此程式設計於 Google Colab 環境使用,請在 Colab 中執行。")
# 建立所有需要的資料夾
for d in [DATA_DIR, LOG_DIR]:
Path(d).mkdir(parents=True, exist_ok=True)
# ========== 日誌函數 ==========
def log(msg: str):
now = pd.Timestamp.now()
log_path = f"{LOG_DIR}/download_tw_{now:%Y%m%d}.txt"
with open(log_path, "a", encoding="utf-8-sig") as f:
f.write(f"{now:%Y-%m-%d %H:%M:%S}: {msg}\n")
print(msg)
# ========== 啟動資訊與使用者提示 ==========
now = pd.Timestamp.now()
print(f"""\
=========================================================
【台股日K資料下載器】
📁 資料存放:{DATA_DIR}
📝 Log 路徑:{LOG_DIR}
🕒 啟動時間:{now:%Y-%m-%d %H:%M:%S}
🔧 多執行緒數:{MAX_WORKERS}
🔄 續傳功能:✅ 啟用(透過 {os.path.basename(CKPT_FILE)})
❗ 若要「強制重新下載全部」,請刪除 checkpoint 檔案:
→ 刪除:{CKPT_FILE}
或執行:
!rm "{CKPT_FILE}" # Colab / Linux
del /f "{CKPT_FILE.replace('/', '\\')}" # Windows
=========================================================
【免責聲明】
1) 僅供研究與教學,不構成投資建議。
2) 資料來自 Yahoo Finance,可能有延遲或錯誤。
3) 再執行一次即可續傳未完成項目。
=========================================================
""")
# --- 檢查 stockname 是否存在 ---
try:
_ = stockname # 例如 ['2330.TW&台積電', '2317.TW&鴻海']
except NameError:
raise RuntimeError("❌ 找不到變數 `stockname`。請先定義股票清單再執行本段。")
tickers = [t.strip() for t in stockname if t.strip()]
log(f"📋 原始清單數量:{len(tickers)} 支股票")
# ========== 安全檔名處理與解析 ==========
def safe_filename(s: str) -> str:
return (s.replace("/", "_").replace("\\", "_").replace(":", "_")
.replace("*", "_").replace("?", "_").replace('"', "_")
.replace("<", "_").replace(">", "_").replace("|", "_"))
def parse_item(item: str):
if '&' in item:
tkr, nm = item.split('&', 1)
else:
tkr, nm = item.strip(), "未知股票"
return tkr.strip(), nm.strip()
# ========== 智慧型續傳機制 ==========
def build_checkpoint(items):
"""根據當前 DATA_DIR 實際狀態重建 checkpoint"""
rows = []
for it in items:
tkr, nm = parse_item(it)
out_path = os.path.join(DATA_DIR, f"{tkr}_{safe_filename(nm)}.csv")
if os.path.exists(out_path) and os.path.getsize(out_path) > MIN_FILE_SIZE:
status, err = "skipped", ""
else:
status, err = "pending", ""
rows.append((tkr, nm, status, err))
df = pd.DataFrame(rows, columns=["ticker", "name", "status", "last_error"])
df.to_csv(CKPT_FILE, index=False, encoding='utf-8-sig')
return df
def validate_and_load_checkpoint():
"""
智慧載入 checkpoint:
- 檢查欄位是否完整
- 抽查 'skipped' 項目的實際檔案是否存在
- 若都不存在 → 可能是路徑變更 → 重建
"""
if not os.path.exists(CKPT_FILE):
log("🆕 建立新的 checkpoint ...")
return build_checkpoint(tickers)
try:
ckpt = pd.read_csv(CKPT_FILE)
required_cols = {"ticker", "name", "status", "last_error"}
if not required_cols.issubset(ckpt.columns):
log("⚠️ checkpoint 欄位不完整,重新建立")
return build_checkpoint(tickers)
# 抽查 skipped 項目是否「真的存在」
skipped_items = ckpt[ckpt["status"] == "skipped"]
if len(skipped_items) == 0:
log(f"🔁 讀取 checkpoint:{len(ckpt)} 項(無跳過項目)")
return ckpt
found_any = False
sample_check_count = 0
for _, row in skipped_items.iterrows():
if sample_check_count >= 5:
break
tkr, nm = row["ticker"], row["name"]
out_path = os.path.join(DATA_DIR, f"{tkr}_{safe_filename(nm)}.csv")
if os.path.exists(out_path) and os.path.getsize(out_path) > MIN_FILE_SIZE:
found_any = True
break
sample_check_count += 1
if found_any:
log(f"🔁 讀取既有 checkpoint:{CKPT_FILE}({len(ckpt)} 項),驗證到部分檔案確實存在")
return ckpt
else:
log("⚠️ 檢測到 checkpoint 中的檔案均不存在 → 可能資料夾路徑已變更 → 重建 checkpoint")
log(f" 上次路徑可能為:.../dayK ?目前路徑:{DATA_DIR}")
return build_checkpoint(tickers)
except Exception as e:
log(f"⚠️ checkpoint 讀取失敗,重建:{e}")
return build_checkpoint(tickers)
# ✅ 使用智慧型載入
ckpt = validate_and_load_checkpoint()
# 篩選本次要處理的項目
todo = ckpt[ckpt["status"].isin(["pending", "failed"])].copy()
log(f"🚀 本輪待處理:{len(todo)} 支")
# --- 多執行緒鎖 ---
print_lock = threading.Lock()
def download_stock_data(row):
"""下載單一股票歷史資料(日K)"""
ticker_id, name = row["ticker"], row["name"]
try:
with print_lock:
print(f"📥 下載中: {name}({ticker_id})...")
out_path = os.path.join(DATA_DIR, f"{ticker_id}_{safe_filename(name)}.csv")
# 若已存在且有資料,跳過
if os.path.exists(out_path) and os.path.getsize(out_path) > MIN_FILE_SIZE:
return {"ticker": ticker_id, "name": name, "status": "skipped", "err": "", "rows": 0}
# 下載資料
tk = yf.Ticker(ticker_id)
hist = tk.history(period="max", auto_adjust=AUTO_ADJUST)
if hist is None or hist.empty:
with print_lock:
print(f"⚠️ 無資料: {name}({ticker_id})")
return {"ticker": ticker_id, "name": name, "status": "failed", "err": "empty_history", "rows": 0}
# 重設索引並儲存
hist.reset_index(inplace=True)
hist.to_csv(out_path, index=False, encoding='utf-8-sig')
num_rows = len(hist)
with print_lock:
print(f"✅ 完成: {name}({ticker_id}) | {num_rows} 筆資料 | 已存 {os.path.basename(out_path)}")
time.sleep(0.1) # 減少被節流風險
return {"ticker": ticker_id, "name": name, "status": "success", "err": "", "rows": num_rows}
except Exception as e:
err_msg = str(e)
with print_lock:
print(f"❌ 失敗: {name}({ticker_id}) → {err_msg[:100]}...")
log(f"[ERROR] {ticker_id}&{name}: {err_msg}")
time.sleep(RETRY_DELAY)
return {"ticker": ticker_id, "name": name, "status": "failed", "err": err_msg, "rows": 0}
# ========== 主流程 ==========
if __name__ == "__main__":
start_time = time.time()
total_count = len(todo)
if total_count == 0:
print("🎉 所有股票資料均已下載完成,無需處理。")
log("ℹ️ 無需處理項目。")
else:
print("="*60)
print(f"開始下載 {total_count} 支股票的日K資料...")
print("="*60)
pbar = tqdm(total=total_count, desc="整體進度", unit="支")
results = []
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
future_to_row = {executor.submit(download_stock_data, r): r for _, r in todo.iterrows()}
for future in as_completed(future_to_row):
r0 = future_to_row[future]
try:
result = future.result()
except Exception as e:
result = {
"ticker": r0["ticker"],
"name": r0["name"],
"status": "failed",
"err": f"uncaught: {e}",
"rows": 0
}
results.append(result)
# 即時更新 checkpoint
mask = (ckpt["ticker"] == result["ticker"])
ckpt.loc[mask, ["status", "last_error"]] = [result["status"], result["err"]]
ckpt.to_csv(CKPT_FILE, index=False, encoding='utf-8-sig')
pbar.set_postfix_str(f"最新: {result['name']} {result['status']}", refresh=False)
pbar.update(1)
pbar.close()
# ========== 統計與輸出 ==========
end_time = time.time()
duration = end_time - start_time
success = [r for r in results if r["status"] == "success"]
skipped = [r for r in results if r["status"] == "skipped"]
failed = [r for r in results if r["status"] == "failed"]
total_rows = sum(r["rows"] for r in success)
avg_rows = total_rows / len(success) if success else 0
# 📊 Console 輸出統計
print("\n" + "="*60)
print("📊 下載統計報告")
print("="*60)
print(f"📁 資料存放路徑: {DATA_DIR}")
print(f"📝 Log 路徑: {LOG_DIR}")
print(f"⏰ 執行時間: {duration:.2f} 秒")
print(f"📈 總計處理: {total_count} 支")
print(f"✅ 成功: {len(success)} 支 | 共 {total_rows:,} 筆日K資料 (平均 {avg_rows:.0f} 筆/支)")
print(f"🟡 跳過: {len(skipped)} 支 (已存在)")
print(f"❌ 失敗: {len(failed)} 支")
if failed:
print("📋 失敗清單:")
for r in failed:
print(f" - {r['name']}({r['ticker']})")
print("\n📌 提示:若仍有失敗項目,**直接重新執行本程式**即可續傳補抓。")
print("✅ 所有資料與日誌已儲存。")
print("="*60)
# Log 最終統計
log(f"📊 最終統計:成功={len(success)}, 跳過={len(skipped)}, 失敗={len(failed)}, 耗時={duration:.2f}s")
# ✅ 輸出失敗與成功清單
if failed:
fail_df = pd.DataFrame(failed)[["ticker", "name", "err"]]
fail_df.to_csv(f"{LOG_DIR}/failed_list.csv", index=False, encoding='utf-8-sig')
log(f"📁 已儲存失敗清單:{LOG_DIR}/failed_list.csv")
if success:
succ_df = pd.DataFrame(success)[["ticker", "name", "rows"]]
succ_df.to_csv(f"{LOG_DIR}/success_list.csv", index=False, encoding='utf-8-sig')
log(f"📁 已儲存成功清單:{LOG_DIR}/success_list.csv")
print(f"\n🧾 已輸出報告至:{LOG_DIR}/")
print(" - success_list.csv(成功清單)")
print(" - failed_list.csv(失敗清單)")
print(" - checkpoint_tw.csv(續傳點)")
print(" - download_tw_YYYYMMDD.txt(日誌)")
🧠 智慧續傳機制:
- 每次執行會自動建立或讀取 checkpoint_tw.csv
- 若檔案已存在且大小合理(>100 bytes),自動跳過
- 若下載失敗,會記錄錯誤訊息並保留於 checkpoint,供下次續傳
- 可隨時中斷與重啟,不會重複下載已完成的檔案
⚙️ 多執行緒加速:
- 使用 ThreadPoolExecutor 同時下載多檔(預設 8 執行緒)
- 每檔下載後即時更新 checkpoint,避免資料遺失
- 加入 time.sleep(0.1) 降低被 Yahoo 節流風險
📁 輸出內容:
- 每檔股票一個 CSV,命名格式為:<stock_id>_<stock_name>.csv
- 儲存於:/content/drive/MyDrive/各國股票檔案/tw-share/dayK/
- 同步輸出:
- checkpoint_tw.csv:續傳狀態
- success_list.csv:成功清單與筆數
- failed_list.csv:失敗清單與錯誤訊息
- download_tw_YYYYMMDD.txt:完整日誌
執行完後結果畫面會是如下

colab免費版執行時間是551秒,將近10分鐘

-----------------------------------------------------------------------------------------------------
將上方程式碼逐個貼上colab cell執行即可。預設會在goole driver建立資料夾存放日K檔案。

如果複製程式碼貼到colab上方會出現如下空白,導致執行後發生錯誤訊息
File "<tokenize>", line 205 IndentationError: unindent does not match any outer indentation level
請選擇該處空白選取候用取代方式全部取代,再次執行即可

-----------------------------------------------------------------------------------------------------
🧑🔬 作者身份與非專業聲明|AUTHOR'S STATUS AND INTENT 本報告的作者為獨立的、業餘數據研究愛好者,非專業量化分析師,亦不具備任何持牌金融顧問資格。本專題報告是作者利用全職工作外的個人時間完成。 The author of this report is an independent, amateur data researcher and NOT a professional quantitative analyst or a licensed financial advisor. This work is completed in the author's personal free time for statistical research purposes.
📊 數據來源與品質限制|DATA SOURCE LIMITATION 本報告所有歷史價格數據均來自免費公共資源(如 Yahoo Finance)。雖然作者已通過 V4.0 QA 系統盡力檢查並排除明顯錯誤,但由於數據源限制,作者不保證數據 100% 無誤。 All data is sourced from free public providers (e.g., Yahoo Finance). While the author uses the V4.0 QA System to minimize errors, the author offers NO WARRANTY of 100% accuracy. Data integrity is constrained by the free source.
🚫 無投資建議聲明|NO INVESTMENT ADVICE 本文內容、圖表及 AI 分析結果僅供研究參考與教學啟發之用,不構成任何投資買賣建議、諮詢或招攬。所有分析僅描述歷史統計規律。 This content is for statistical research and educational inspiration only. It does NOT constitute personalized financial advice, investment recommendations, or a solicitation to buy or sell securities.
⚠️ 風險與責任劃分|RISK & LIABILITY 股票市場投資涉及重大風險。您應自行判斷並承擔所有投資風險。作者(和平台)對您基於本報告所做出的任何投資決策和潛在損失,不承擔任何責任。 Stock market investing involves significant risk. The reader must exercise their own judgment. The author (and the platform) assumes NO LIABILITY for any financial losses incurred based on the information provided herein.








