懶惰之最|GitHub 實測

想數均線交叉幾次?用 backtrader 餵證交所日資料,一秒列出日期

📌 數據僅限本工具現階段參考用。本文只示範工具怎麼安裝、設定、執行,不是投資建議,也不推薦任何股票。

重點摘要

  • pip install -e . 約 15 秒裝好 backtrader;要畫圖還得另外 pip install -r requirements.txt(約 14 秒)。
  • 餵入證交所 2330 日資料 83 列(2026-07-01 至 2026-11-02),跑 5 日線/20 日線交叉約 1 秒,列出 4 個交叉日,交易次數 2、最大回落 1.88%。
  • 直接畫圖依序遇到缺 plotly、缺 dash、TKAgg 需要視窗三個錯誤;補裝 requirements、改用 Agg 並以 figs[0][0].savefig 才存出圖。
  • c.plot 的 savefig=True 參數在本次實測沒有產生圖檔。
  • 結論: 算均線交叉與列日期很快,畫圖要先備好相依套件與無視窗環境設定。
  • 適合: 想用 Python 在台股日資料上自己驗證均線交叉、願意照步驟設定環境的人
  • 不適合: 不想碰命令列、需要多檔同時回測或即時資料的人(本次未測)
實測項目 結果
資料列數 83
安裝時間 約15秒(畫圖相依另約14秒)
交叉日數 4
交易次數 2
最大回落 1.88%
回測耗時 約1秒
畫圖錯誤 3 個(plotly、dash、TKAgg)

想驗證一句老話:「五日線穿過二十日線」在最近幾個月到底發生過幾次?用試算表拉公式,拉到一半日期就對不上。這篇用 Python 回測框架 backtrader,餵入證交所公開的日資料,讓它把交叉日一次列出來,也順便畫圖。

測試設備:Mac mini M4 Pro(12 核、64GB)。受測版本:cloudQuant/backtrader(GPL-3.0)master,版本 1.9.76.123,Python 3.12。本文示範資料是證交所公開資料,代號 2330 只是示範輸入,資料日期到 2026-11-02。

下載

git clone https://github.com/cloudQuant/backtrader
cd backtrader
pip install -e .          # 實測約 15 秒
pip install -r requirements.txt   # 畫圖需要,約 14 秒
pip install requests

重點:只做 pip install -e . 不會裝到畫圖用的 plotly、dash,下面的常見問題會說明。

設定

資料來源是證交所的個股日成交資訊(STOCK_DAY),一次一個月。下面的腳本抓 2026 年 7 月到 11 月,存成 2330.csv(日期、開高低收、成交量),共 83 列,從 2026-07-01 到 2026-11-02。

import requests, csv, time
rows=[]
for ym in ['20260701','20260801','20260901','20261001','20261101']:
    j=requests.get('https://www.twse.com.tw/exchangeReport/STOCK_DAY',
        params={'response':'json','date':ym,'stockNo':'2330'},timeout=30).json()
    for r in j.get('data',[]):
        y,m,d=r[0].split('/'); n=lambda s: float(s.replace(',',''))
        rows.append((f'{int(y)+1911}-{m}-{d}',n(r[3]),n(r[4]),n(r[5]),n(r[6]),int(n(r[1]))))
    time.sleep(3)   # 請求間隔,避免被擋
with open('2330.csv','w',newline='') as f:
    w=csv.writer(f); w.writerow(['date','open','high','low','close','volume']); w.writerows(rows)

跑起來

import matplotlib
matplotlib.use('Agg')
matplotlib.use=lambda *a,**k:None   # backtrader 會強制改成 TKAgg,這行擋掉
import backtrader as bt
class Cross(bt.Strategy):
    def __init__(self):
        self.cx=bt.indicators.CrossOver(bt.indicators.SMA(self.data.close,period=5),
                                        bt.indicators.SMA(self.data.close,period=20))
    def next(self):
        d=self.data.datetime.date(0)
        if self.cx>0: print(d,'5日線向上穿過20日線'); self.buy()
        elif self.cx<0 and self.position: print(d,'5日線向下穿過20日線'); self.close()
c=bt.Cerebro()
c.adddata(bt.feeds.GenericCSVData(dataname='2330.csv',dtformat='%Y-%m-%d',datetime=0,open=1,high=2,low=3,close=4,volume=5,openinterest=-1,headers=True))
c.addstrategy(Cross)
c.addanalyzer(bt.analyzers.TradeAnalyzer,_name='t')
c.addanalyzer(bt.analyzers.DrawDown,_name='dd')
r=c.run()[0]
print('交易次數',r.analyzers.t.get_analysis().total.closed,'最大回落%',round(r.analyzers.dd.get_analysis().max.drawdown,2))
figs=c.plot(style='line',iplot=False,backend='matplotlib')
figs[0][0].set_size_inches(10,6); figs[0][0].savefig('bt2330.png',dpi=110)

實測輸出(跑完約 1 秒):

終端機輸出

項目 結果
資料列數 83(2026-07-01 至 2026-11-02)
交叉日 08-06 向上、09-16 向下、09-21 向上、10-16 向下
交易次數 2
最大回落 1.88%

圖檔長這樣(收盤線、5 日與 20 日均線、成交量、下方是交叉指標):

backtrader 畫出的圖

以上是工具現階段算出的欄位與日期,只示範用法,不解讀好壞。

常見問題

專案連結:https://github.com/cloudQuant/backtrader 授權:GPL-3.0

測試設備:Mac mini M4 Pro(12 核、64GB)。內容依實際執行結果撰寫,數據為撰寫當時的實測值。

← 金融工具區|所有實測