Lin.Log|Studio
// 01 · deploy-finpilot-from-clone-to-online$ cat deploy-finpilot-from-clone-to-online.md

從 git clone 到上線——我部署了一個台股量化小助手

2026.05.12技術筆記7 分鐘閱讀
從 git clone 到上線——我部署了一個台股量化小助手

技術主題: FinPilot 部署 + 擴充(歷史 DB / 回測報告 / 持倉日報 / Dashboard)
實作時間: 2026/05
工時估計: 約 3 天(含睡覺)
紀錄者: _YLin_Lai
參考資料:
- https://github.com/hu0937/FinPilot
- https://finmindtrade.com/
- https://www.finlab.finance/

1.主題

這篇的主軸是「找到一個夠好的開源量化平台、把它跑起來、然後把我認為缺的東西一個一個補上去」。

FinPilot 是 GitHub user hu0937 開源的台股 + 美股日線量化分析平台。它整合了:Telegram Bot 接 Claude AI 做自然語言查詢、APScheduler 管排程抓資料、FinLab 的 sim() 引擎做回測,加上兩條常駐的自動策略探索 daemon——月頻因子型和事件驅動型——背景不停地跑、篩出達標策略就自動存檔並推播。README 用箭頭圖把整個平台說得很清楚,code 結構是 core / agents / scheduler / bot 四層,看兩遍就懂。

我把它 clone 到自己的 Ubuntu VM 上,跑起來之後開始補東西——然後就停不下來。這篇是整個 session 的序章,後面 4 篇會分別深入每個 sub-project 的設計、踩雷、和突破。

2.背景(需求簡介)

我為何選 FinPilot,不是隨便找的。

挑開源量化框架,有幾個死穴很容易踩到:Bot 介面很漂亮但沒有回測引擎、回測引擎跑得動但沒有 scheduler 所以等於不能 production、daemon 有了但沒有任何監控介面只能 ssh 去 grep log。FinPilot 把這幾塊都拼起來了——Bot、scheduler、FinLab 回測、兩條探索 daemon 全都整合在同一個 repo 裡,而且已經有 5 個通過嚴格 OOS 驗證的自動探索策略(CAGR 介於 20%~45%,Sharpe 介於 1.31~1.67)。我不想從頭自己搭,這就是我的起點。

跑起來大概 10 分鐘。問題是——跑起來之後我才知道缺什麼。

痛點一:歷史資料只有 60 天。

原本的 data_fetcher.py 只抓觀察清單股票最近 60 天的收盤資料,夠維持 Bot 查詢用,但做不了長期回測。我要讓 FinLab 的 sim() 跑 10 年的因子組合,底層要有真實的歷史 OHLCV 對應,60 天根本不夠用。

痛點二:回測只算總指標,不知道歷年命中哪些股票。

原本的 run_all_backtests.py 跑完一個策略輸出 CAGR / Sharpe / MDD,很完整,但我想要的是——這個策略在歷史上每個月實際選了誰、跟 0050 比的 alpha 是多少、Top winners 是哪幾檔——這些都沒有。

痛點三:16 個策略對持倉的 exit signal 沒有匯總。

strategy_monitor.py 每晚 20:00 推播,但它只看 PEG 和處置股這 2 個策略,剩下 14 個自動探索策略對我現有持倉的看法一概不知道。我想要一個每天告訴我「你手上這幾檔,今天各策略怎麼看」的報告。

痛點四:8 個 cron job 跑得怎樣,沒有 dashboard 只能盲猜。

scheduler 每天排了台股 / 美股更新、心跳推播、策略監控、回測 pipeline、月營收抓取,加上兩條 daemon 常駐——我怎麼知道有沒有人掛掉?每次都要 ssh 去手動 tail -f scheduler.log 再 grep ERROR,這不是長久之計。

3.使用技術(部署環境)

部署環境很樸素:Ubuntu VM、Python 3.12 venv,FinMind 和 FinLab 都用免費 register tier 的 token 就跑得起來。資料庫是兩個 SQLite——原本的 quant.db 放 watchlist / 持倉 / 策略記錄,我加了一個 history.db 放 10 年 OHLCV + 三大法人 + 大盤指數 + 月營收,最後長到 9.6 GB。服務管理是 nohup + scripts/start.sh,啟一個指令同時把 Telegram Bot 和 APScheduler 拉起來、PID 存到 scripts/pids/、重啟一行搞定。

開發這整個 session 我用的是 Claude Code(claude-opus-4-7 model),配合三個 superpowers skill 的工作流:

brainstorming → writing-plans → subagent-driven-development

這個工作流的設計有點強制性——brainstorming 強迫我先說清楚「我要解決什麼問題」、writing-plans 強迫我把假設和設計決定寫成文字、subagent-driven-development 讓每個 task 獨立跑、跑完有 review checkpoint 才接著下一個。我在這個 session 前兩個 sub-project 覺得這三步走起來太重,但後來每次跳過就踩雷,最後乖乖回來照做。

4.整 session 全景

整個 session 分成幾個 sub-project,每個都有自己的 spec + plan 文件在 docs/ 下面。用一句話把每個說完:

Phase 1:歷史 DB — 從零設計 history.db schema,抓 10 年台股 OHLCV / 三大法人 / 大盤指數 / 月營收,最後寫入 9.6 GB。這一段的麻煩事是資料源 pivot 了兩次,後面第 2 篇會說。

回測模組 — 在原本的 run_all_backtests.py 之上加 backtest_engine.pybacktest_store.py,把 sim() 的結果整理成 Obsidian 相容的 Markdown 月報,含每月 Top winners 和 vs 0050 的 alpha 計算。這一段踩了一個 NaN bug,後面第 3 篇深入。

Phase 2a:月營收 — MOPS 公開資訊觀測站的月營收資料直接用 HTTP GET 抓 CSV,避開了 Playwright,12 萬筆月營收寫進 history.db

持倉日報 — 每天 21:00 新開一個 cron job,用 Yahoo Finance 抓持股新聞摘要、交給 Claude AI 對每個持股寫評語、打包成 Telegram 訊息推出去。這一段的問題是 Yahoo 的 HTML 結構不穩,後面第 4 篇說。

Monitoring dashboard — FastAPI + Jinja2 做一個本機監控頁,7 個區塊:scheduler 狀態、daemon 存活、DB 統計、log tail、錯誤摘要、持倉快照、策略命中摘要——30 秒自動 reload,再也不用 ssh grep。這一段的雷是 COUNT(*) 在 9.6 GB 的 SQLite 上直接超時,後面第 5 篇說。

整體數字:52 個 commits / 79 個 unit tests / 9.6 GB DB / 5 個新 cron job。整個 session 如果只算清醒時間大概 2 天多,加上睡覺算 3 天。

架構最後長成這樣:

              FinPilot/ (原版)
              |
  data_fetcher.py  →  quant.db (Bot / 策略 / 持倉)
  APScheduler      →  strategy_explorer daemon (x2)
  Telegram Bot     ←  notifier.py

              +我加的 (新版)
              |
  history_fetcher.py  →  history.db (9.6 GB, 10年)
  TwseFetcher         →  TWSE / TPEx 官方 endpoint
  MopsBrowser         →  MOPS 月營收 CSV
  backtest_engine.py  →  sim() → Markdown 月報
  backtest_store.py   →  reports/ (Obsidian)
  settlement_analyzer →  Yahoo 新聞 + Claude 評語
  daily_settlement    →  Telegram 21:00 持倉日報
  FastAPI dashboard   →  本機監控頁 (7 區塊)

5.心得

這個 session 結束之後我有幾個感想值得記下來。

不要先寫 code,先讀別人的 README 與架構圖。

FinPilot 的 README 很長,大約 800 行,但真的值得逐字看。開頭那個 ASCII 架構圖把資料流、服務邊界、Agent 職責全說清楚了。我第一次 clone 時忍不住直接跑 start.sh,結果對架構一知半解,改了一個地方不知道會影響哪裡。後來強迫自己把 README 重新讀一遍,省了我至少兩小時的亂猜。

「spec → plan → subagent」工作流的價值,是讓假設變成文字。

brainstorming 那一步聽起來很麻煩——我只是要加一個 history DB,幹嘛還要對話討論。但寫 spec 的過程讓我意識到,我對「TWSE 的 endpoint 格式是什麼」「月營收什麼時候才是已公告」這些假設其實並不確定。假設寫出來之後才容易修,不寫出來就是等到跑錯了才發現。後面的 5 個 sub-project 有一半的假設後來被現實打臉,但都是在 plan review 階段就抓到,沒有變成真正的 bug。

既有 code 不要動,獨立 module 往旁邊加。

我在整個 session 幾乎沒有改動原本的 strategies/bot/telegram_bot.pystrategy_explorer.py 的核心邏輯。新加的 history fetcher、dashboard、日報都是獨立 module,掛進 scheduler 的方式是在 job_runner.py 加一行 cron,不去動原本的排程邏輯。這讓我每次改出問題時只要 revert 新加的部分,不用害怕把原版 daemon 搞壞。

開源專案的真正成本不在跑起來,是「跑起來之後缺什麼」。

原 repo 給了 60% 的東西——Bot 指令、策略 daemon、回測引擎、部署腳本,全部到位。剩下 40% 取決於你想拿這個地基蓋什麼。我的 40% 是:長期歷史資料 + 回測可讀報告 + 持倉日報 + 監控介面。別人的 40% 可能完全不同。這不是 repo 的問題,是「你要用這個地基蓋什麼」的問題——所以序章要做的事是把這個問題先問清楚。

結語:

這個序章先到這邊。後面 4 篇會分別深入每個 sub-project 的設計、踩雷、突破:


本系列文章源自我部署的 FinPilot 專案。原專案由 hu0937 開源並維護,是一個整合 Telegram Bot + Claude AI + APScheduler 的台股量化分析平台。本次的歷程是「部署 + 擴充」,所有原始的 Bot 指令、策略 daemon、sim() 回測架構都來自原作者的設計。

原專案:https://github.com/hu0937/FinPilot

感謝原作者把這麼完整的 base 開源出來,讓我可以站在這個地基上加東西。

相關紀錄

linlog@studio $ exit

有東西想一起做出來?

[聯繫我]
email dannylaii@linlogstudio.com
hours Mon – Fri · After 7PM
base Taiwan · 遠端優先
Connection to lin.log closed. © 2026 Lin.Log|Studio