跳至主要內容
台股研究 約 20 分鐘閱讀

MACD 怎麼用才對?台股 11 年回測:柱狀圖是反轉訊號,
不是動能訊號

MACD 怎麼用才對?台股回測:柱狀圖 hist 最低的 30 檔研究段年化 8.2%,最高只有 3.6%,金叉籃子也輸 0050。hist 反轉當加分因子的純技術策略全期年化 25.5% 勝 0050 的 21.2%,但 2022 年起 24.8% 落後 0050 的 30.5%,7 月單月 -30.2%。

免安裝,用 AI 重跑這篇的策略

在瀏覽器開啟 FinLab Studio,AI 依本文的條件重跑回測,接著可以改條件再測。

在 Studio 重跑
MACD 真用法 CAGR 25.5% Sharpe 1.04

MACD 在台股的用法:柱狀圖當反轉雷達,金叉買進沒有優勢

MACD 台股回測的關鍵數字:

你想知道的 本文用真實台股回測的回答
MACD 是什麼 快線 DIF(12 日 EMA 減 26 日 EMA)、慢線 DEA(DIF 的 9 日 EMA)、柱狀圖 hist(DIF 減 DEA)三者組成的趨勢動能指標
柱狀圖越高越該追多嗎 方向相反。每月挑 hist 最高的 30 檔,研究段(2015–2021)年化 3.6%;挑 hist 最低、剛超賣的 30 檔反而有 8.2%
金叉買、死叉賣有效嗎 沒有獨立優勢。每月持有近 20 個交易日剛金叉的股票,研究段年化 9.4%、月夏普 0.54,輸給同期含息 0050 的 15.1%
那 MACD 該怎麼用 當複合策略裡的小權重反轉加分因子(佔綜合分 0.15),疊在多窗動能加低波核心上,不要當主訊號
效果如何 研究段年化 26.1%、月夏普 1.43。資料延長到 2026-09-30 後,全期年化 25.5% 仍高於含息 0050 的 21.2%,但 2022 年起月夏普只剩 0.97、年化 24.8% 落後 0050 的 30.5%,全期最大回撤 -42.1% 比 0050 深
最近發生什麼事 2026 年 7 月單月 -30.2%(0050 -4.0%),持股 15 檔全數虧損;首發資料截止日 2026-06-09 之後累計 -22.8%,同期 0050 +8.9%
依本文重跑

執行這個策略

複製提示詞,讓 AI 依照上方證據的資料、條件與風險檢查重跑一次。

告訴你的AI:

幫我設定 FinLab,重現這篇文章,請讀:https://finlab.finance/setup?relatedUrl=/blog/macd-indicator-taiwan-backtest

免安裝,開啟 FinLab Studio

MACD 反轉加分策略與含息 0050 的台股淨值對照圖,2015 年 1 月 30 日同日起算到 2026 年 9 月,2026 年 7 月策略大幅回落

本文所有數字皆出自 finlab 套件(2.2.16)抓取的上市櫃真實價量資料(price 與 etl:adj_close 含息還原股價),回測從 2015-01-30 起算、資料截至 2026-09-30,基準為同日起算的含息 0050。2026-10 用延長後的資料重跑,參數一個都沒改:首發版(資料截至 2026-06-09)2022 年起月夏普 1.26,現在降到 0.97,低於我們設的 1.0 門檻,文中新增「策略衰退追蹤」一節交代發生什麼事。研究段年化由首發的 26.4% 變成 26.1%,原因是新版 finlab 讓首個淨值日由 2015-02-26 提前到 01-30,和新資料無關。文末附可下載的 strategy.py 與 data.csv,可自行重現。對回測的觀念還不熟,可先看回測是什麼。

MACD 是什麼:三條線與一個柱狀圖

MACD(Moving Average Convergence Divergence,指數平滑異同移動平均)是 Gerald Appel 在 1970 年代末提出的趨勢動能指標,由三個部分組成:

DIF(快線):12 日 EMA 減 26 日 EMA,反映短期相對長期的動能變化。

DEA(慢線/訊號線):DIF 的 9 日 EMA,把快線平滑掉短期雜訊。

柱狀圖(hist):DIF 減 DEA,畫成零軸上下的長條。hist 為正代表快線在慢線之上(一般解讀為多頭動能),為負則相反。

最廣為流傳的兩種用法是:金叉死叉派主張「DIF 由下往上穿過 DEA(金叉)買、由上往下穿過(死叉)賣」;柱狀動能派則把 hist 當動能強弱計,「hist 越高、由負翻正就是多頭力道集結」。這兩派幾乎是所有 MACD 教學的標準答案。哪一派在台股站得住?這就是本文用回測要回答的問題。技術指標的基礎名詞可參考名詞詞彙表。

MACD 的數學定義:三條線怎麼算出來

把上面的文字寫成公式,MACD 只有三條算式:

DIF=EMA12(C)−EMA26(C),DEA=EMA9(DIF),hist=DIF−DEADIF = EMA_{12}(C) - EMA_{26}(C),\quad DEA = EMA_{9}(DIF),\quad \text{hist} = DIF - DEA

逐項拆解每個符號:

  • CC 是每日收盤價。
  • EMA12(C)EMA_{12}(C)、EMA26(C)EMA_{26}(C) 分別是收盤價的 12 日與 26 日指數移動平均(EMA,越近的價格權重越大)。兩者相減得到快線 DIF:當短期均線拉開長期均線越多,DIF 越大,代表近期動能相對長期在加速。
  • DEADEA 是 DIF 再取 9 日 EMA,也就是慢線(訊號線),把 DIF 的短期抖動再平滑一次。
  • hist\text{hist} 是 DIF 減 DEA 的差,畫成零軸上下的柱狀圖。hist 由負翻正、柱子變長,傳統解讀為「快線正在拉開慢線、多頭力道集結」;本文後面會用真實資料指出,在台股月頻橫截面上這個解讀的方向其實是反的。

12、26、9 這組參數是 Gerald Appel 最初的設定,也是各家看盤軟體的預設值。本文主策略改用反應更快的 8-17-9,後面會把四組常見參數都放進同一套策略比較。

兩派訊號在個股上長什麼樣:台積電一年 44 個進出點

把公式畫到真實個股上,最能看出兩派用法的問題。下面這張圖取台積電(2330)2023 年 7 月到 2024 年 6 月、約一年的窗,上半部是收盤價並標出兩派的買賣箭頭,下半部是 MACD(8-17-9)的 DIF、DEA 與 hist 柱:

台積電 2330 的 MACD 金叉死叉派與零軸派買賣訊號示意圖,一年 243 個交易日出現 44 個進出訊號

圖上標了兩派教科書訊號:金叉死叉派(DIF 上穿 DEA 買、下穿賣)與零軸派(DIF 上穿 0 買、下穿 0 賣)。光是台積電這一檔、這一年,金叉死叉派就觸發了 15 次買、15 次賣,零軸派再加 7 次買、7 次賣,兩派合計 44 個進出訊號;這一年共 243 個交易日,平均約每 5.5 個交易日就要你動一次手。聯發科(2454)同窗也有 29 個訊號:

聯發科 2454 的 MACD 金叉死叉派與零軸派買賣訊號示意圖,同一年出現 29 個進出訊號

問題一眼可見:在橫盤整理的區段(例如 2023 年下半年台積電在 500 至 600 元之間來回),DIF 與 DEA 反覆糾纏、不斷交叉,每一次交叉都產生一個訊號,買在小高、賣在小低,被巴來巴去(俗稱 whipsaw)。訊號太多、雜訊蓋過真正的趨勢,再扣掉每次進出的手續費與證交稅,報酬就被磨掉了。

想自己重畫這張圖、把任一檔股票的 MACD 與兩派訊號標出來,核心只有幾行。MACD 先用完整歷史算好再取窗,窗內第一天沒有前一天可比,不算交叉。下面這段可以直接執行,也可以貼給你的 AI 助理改寫:

顯示程式碼
import finlab
from finlab import data
 
finlab.login()  # 套件會在需要資料時引導你完成登入
 
# 1) 取收盤價,算 MACD(8-17-9)
close = data.get("price:收盤價")
dif, dea, hist = data.indicator("MACD", fastperiod=8, slowperiod=17, signalperiod=9)
 
# 2) 取單一檔、單一年的窗(太長會擠成一團看不清)
sid = "2330"
win = slice("2023-07-01", "2024-06-30")
d = dif[sid].loc[win]
e = dea[sid].loc[win]
 
# 3) 兩派訊號:用「今天條件成立、昨天不成立」抓穿越的那一天
golden = (d > e) & (d.shift(1) <= e.shift(1))   # 金叉:DIF 上穿 DEA → 買
death = (d < e) & (d.shift(1) >= e.shift(1))     # 死叉:DIF 下穿 DEA → 賣
zero_up = (d > 0) & (d.shift(1) <= 0)            # 零軸派:DIF 上穿 0 → 買
zero_down = (d < 0) & (d.shift(1) >= 0)          # 零軸派:DIF 下穿 0 → 賣
 
# 4) 數一數一年內各派觸發幾次(就能感受到 whipsaw 有多嚴重)
print("金叉次數:", int(golden.sum()))
print("死叉次數:", int(death.sum()))
print("零軸上穿次數:", int(zero_up.sum()))
print("零軸下穿次數:", int(zero_down.sum()))
print("窗內交易日:", len(d))

台積電跑出來是 15、15、7、7 與 243 天。把 sid 換成任一檔代號、win 換成你想看的區間,就能驗證「訊號頻繁」不是個案。個股上的雜訊看得到,兩派到底有沒有用,要把 hist 攤到全市場回測才知道。

教科書方向是反的:hist 最高的一籃,輸給 hist 最低的一籃

我們在可交易宇宙(60 日均成交金額前 300 大、60 日均量大於 100 萬股、收盤大於 10 元,排除 ETF、金融保險股、處置與全額交割股;KY 股的代號也是 4 碼數字,沒有排除)裡,把 MACD(8-17-9)的 hist 當橫截面選股因子,每月挑一籃 30 檔、等權持有、月再平衡,不加任何濾網或擇時。把「教科書方向」(挑 hist 最高、動能最強的)和「反向」(挑 hist 最低、剛超賣的)各跑一次:

MACD hist 選股方向 研究段年化 研究段月夏普 2022 年起年化 全期最大回撤
hist 最高 30 檔(教科書動能方向) 3.6% 0.27 10.9% -46.9%
hist 最低 30 檔(剛超賣、反轉方向) 8.2% 0.46 28.5% -41.3%
含息 0050(同日起算) 15.1% 1.00 30.5% -34.0%

MACD 柱狀圖最高與最低 30 檔選股的台股年化報酬對照長條圖,研究段與 2022 年起都是 hist 最低的一籃勝出,兩籃都低於含息 0050

兩個方向單獨用都輸 0050,但比較兩籃,結論很乾淨:在台股月頻橫截面,hist 最低的一籃在研究段與 2022 年起都贏 hist 最高的一籃。 我們再把 hist 換成三種正規化方式(原始 hist、hist 除以收盤、hist 的 60 日 z-score),每籃 20、30、50 檔各跑一次,比較最低一籃與最高一籃的年化差距:研究段 9 組全為正(1.5 到 8.1 個百分點),2022 年起也 9 組全為正(0.5 到 18.9 個百分點)。差距在 2022 年起變大的有 5 組(原始 hist 三組、除以收盤的 30 與 50 檔),z-score 三組則縮到 0.5 到 2.4 個百分點。方向穩,幅度要看正規化方式。這裡的「差距」是兩籃年化報酬相減,不是實際放空的回測。

為什麼教科書方向會反?在月頻這個時間尺度上,當一檔股票的 DIF 已經遠遠拉開 DEA、hist 衝到全市場最高時,那一波動能多半已經反映在價格裡,接下來更可能是均值回歸;反過來,hist 最低時往往是剛被殺過頭、即將反彈的候選。所以「hist 越高越多方」這個直覺,把訊號的方向用反了。金叉的表現也印證這點:我們每月底把近 20 個交易日內 hist 由負翻正(也就是 DIF 上穿 DEA)的股票全部等權買進,每月中位數約 176 檔,研究段年化 9.4%、月夏普 0.54,2022 年起年化 14.1%,兩段都輸給同期 0050。這是月頻換股的籃子,不是逐筆「金叉當天買、20 天後賣」的事件回測。各擺盪指標的正確用法差異,可延伸看 RSI vs MACD vs KD:三大技術指標台股實測。

MACD 真正該放的位置:複合策略裡的小權重反轉加分因子

知道「hist 是反轉訊號」之後,下一個問題是:反轉因子單獨用夠不夠?答案是不夠。hist 最低的反轉腿雖然方向對,但裸用的研究段月夏普只有 0.46,純逆勢接刀的波動太大,沒辦法單獨拿出來用。

比較可行的用法,是把 MACD 反轉因子當「加分項」疊到一個已經成立的選股核心上。本文的核心是台股常見的兩個因子組合:多窗動能(取 20/60/120 日報酬三個橫截面分位的平均,過去一段時間最強的股票傾向繼續強,這和 Jegadeesh & Titman (1993) 記錄的 3 到 12 個月動能效應一致;20 日這一窗較短,文獻上一個月內的報酬反而偏向反轉,這裡只佔三分之一)加上低波動(用 14 日 ATR 除以收盤衡量,波動越低越好,對應 Ang, Hodrick, Xing & Zhang (2006) 記錄的低波動異象)。綜合分的配方是:

綜合分 = 0.65 多窗動能分位 + 0.20 低波分位 + 0.15 MACD 反轉分位(三者都是「分位越小=越好」),每月選綜合分前 15 檔等權持有。

MACD 反轉因子只佔 0.15 的小權重,但它和動能因子在「進場時點」上互補:動能因子偏好「已經漲一波」的股票,反轉分位則把同樣強勢、但最近剛回檔的股票往前排。它的貢獻後面拆解表會量化:把 MACD 反轉因子整個拿掉(權重移給動能),研究段年化從 26.1% 掉到 21.5%,2022 年起從 24.8% 掉到 19.2%,全期從 25.5% 掉到 20.5%。

光有選股核心還不夠:在系統性崩盤時,任何純選股籃子都會被一起拖下水。所以完整策略還疊了兩層純技術風控:雙均線趨勢閘(先把選股池縮到「結構偏多」的個股)與SMA120 廣度擇時(市場結構轉弱時整個籃子改持現金)。延伸閱讀:技術面與基本面選股的差異、動能策略 18 年實測。

雙均線趨勢閘縮池,SMA120 廣度擇時管曝險

選股核心定下來後,還有兩件事要處理:一是把選股池限縮在「結構本來就偏多」的個股,二是在大盤系統性轉弱時整個籃子退場。這兩件事都用純價格訊號完成,完全不碰基本面。

第一層:雙均線趨勢閘。 每個換股日,先把選股池限縮為「收盤同時站上自身 SMA60 與 SMA120」的個股,再進綜合分排名。這道閘把短期與中期都還沒站上多頭結構的股票擋在外面。把它拿掉、其他不變,研究段年化從 26.1% 掉到 22.2%,2022 年起從 24.8% 掉到 21.1%。要注意它只在換股日檢查:持有期間跌破均線,要等到下個月底才會被換掉。

第二層:SMA120 廣度擇時。 每個換股日(每月最後一個交易日)計算「可交易宇宙裡收盤站上自己 120 日均線的個股比例」,大於 0.5 才持有選股籃,否則整個月持現金(不加槓桿)。回測每月只換股一次,這個開關也只在換股日讀取,月中廣度跌破 0.5 不會提前出場。2015 年以來廣度跌破 0.5 共 60 次,其中 43 次在月底前就回到 0.5 以上,回測完全沒有執行;真正執行的 17 次,從跌破到換股日的中位數是 2 個交易日、最長 17 個。全部 141 個換股月裡有 33 個月(23.4%)持現金。

可交易宇宙站上 120 日均線的個股比例與策略累積報酬的雙軸對照圖,紅色虛線為 0.5 持股門檻,2026 年 7 月 30 日廣度急跌到 0.29

很多人會直覺想用 MACD 自己來擇時,例如「市場上 hist 為正的比例低就空手」。我們把擇時訊號換成「可交易宇宙裡 hist 大於 0 的比例 > 0.5」,其餘不變,研究段年化只剩 11.4%、2022 年起 10.6%,比 SMA120 廣度版差得多。原因是 hist 的正負翻得太快:這個開關在 0.5 上下切換了 289 次,是 SMA120 廣度(120 次)的 2.4 倍,只有 46.1% 的交易日在 0.5 之上,一半的換股月(50.4%)都在持現金。拿來當低頻的大盤開關,大部分時間都在場外。

廣度擇時的效果要分開看。加上它,研究段月夏普由 1.22 升到 1.43,2022 年那一年的虧損由 -34.5% 縮到 -20.1%;代價是少賺,研究段年化由 32.1% 降到 26.1%。全期最大回撤則幾乎沒差(-42.1% 對不擇時的 -42.4%),因為 2026 年 7 月那次下跌發生在兩個換股日之間,等開關讀到廣度轉弱時傷害已經造成(見衰退追蹤一節)。首發版寫的「擇時把全期最大回撤由 -42.4% 收斂到 -32.1%」,在資料截至 2026-06-09 時成立,延長資料後不成立。

不擇時全程持有與加上 SMA120 廣度擇時的研究段月夏普、2022 年起月夏普與全期最大回撤對照長條圖,兩者全期最大回撤幾乎相同

「風險升高時降部位」的邏輯,學術上有波動度擇時的支持:Moreira & Muir (2017) 在《Volatility-Managed Portfolios》證明,在已實現波動升高時調降部位,能提升投資組合的 Sharpe。本文用的是更慢的市場廣度、而且每月才檢查一次,2026 年 7 月的結果顯示這個頻率跟不上急跌。用大盤訊號降回撤的其他做法,可參考均線市場濾網。

完整策略:雙均線趨勢閘 + 多窗動能低波核心 + MACD 反轉 + SMA120 廣度擇時

把上面的洞見組成一套可執行、可重現、完全不含基本面的純技術策略:

  1. 雙均線趨勢閘:在可交易宇宙裡,換股日只保留「收盤同時站上自身 SMA60 與 SMA120」的個股。
  2. 選股核心:在趨勢閘後的池子裡,依綜合分(0.65 多窗動能分位 + 0.20 低波分位 + 0.15 MACD 反轉分位,三者皆「分位越小越好」)排序,每月選前 15 檔等權持有。多窗動能分位 = 20/60/120 日報酬三個橫截面分位的平均。
  3. MACD 反轉因子:用 8-17-9 參數算出 hist,做橫截面排名,hist 越低(越超賣)分位越好;它只佔 0.15 權重,是加分項不是主角。
  4. 市場廣度擇時:換股日計算可交易宇宙裡收盤站上 SMA120 的個股比例,大於 0.5 才持有上面的籃子,否則整個月持現金。
  5. 月再平衡,月中不檢查。

選股與廣度的程式碼(可直接交給你的 AI 助理改寫,或下載完整版執行):

顯示程式碼
import numpy as np
import finlab
from finlab import data
 
finlab.login()  # 套件會在需要資料時引導你完成登入
 
close = data.get("price:收盤價")
amount = data.get("price:成交金額")
volume = data.get("price:成交股數")
 
# 可交易宇宙:60 日均量 > 100 萬股、60 日均成交金額前 300 大、收盤 > 10 元
liquid = ((volume.rolling(60, min_periods=20).mean() > 1_000_000)
          & amount.rolling(60, min_periods=20).mean().is_largest(300)
          & (close > 10))
 
# 只留代號剛好 4 碼數字的普通股,排除 ETF(00 開頭)、金融保險股、處置與全額交割股
cat = data.get("security_categories")
financial = set(cat.loc[cat["category"].astype(str).str.contains("金融|保險|銀行", na=False), "stock_id"].astype(str))
common_cols = [
    s for s in close.columns
    if len(str(s)) == 4 and str(s).isdigit() and not str(s).startswith("00") and str(s) not in financial
]
flagged = data.get("etl:is_flagged_stock").reindex(index=close.index, columns=common_cols).fillna(False).astype(bool)
universe = liquid[common_cols] & ~flagged
close = close[common_cols]
 
# 雙均線趨勢閘:換股日收盤同時站上自身 60 日與 120 日均線
sma60 = data.indicator("SMA", timeperiod=60).reindex(columns=common_cols)
sma120 = data.indicator("SMA", timeperiod=120).reindex(columns=common_cols)
pool = universe & (close > sma60) & (close > sma120)
 
 
def pct_rank(factor, higher_is_better):
    """池內橫截面百分位,越好的分位越接近 0。"""
    return factor.where(pool).rank(axis=1, pct=True, ascending=not higher_is_better)
 
 
# 多窗動能:20/60/120 日報酬三個分位取平均
momentum = sum(pct_rank(close / close.shift(w) - 1, True) for w in (20, 60, 120)) / 3
 
# 低波:14 日 ATR 除以收盤,越低越好
natr = data.indicator("ATR", timeperiod=14).reindex(columns=common_cols) / close
low_vol = pct_rank(natr, False)
 
# MACD 反轉:8-17-9 的柱狀圖 hist 越低(越超賣)越好
dif, dea, hist = data.indicator("MACD", fastperiod=8, slowperiod=17, signalperiod=9)
reversal = pct_rank(hist.reindex(columns=common_cols), False)
 
# 綜合分越小越優先,取前 15 檔
score = 0.65 * momentum + 0.20 * low_vol + 0.15 * reversal
picks = score.where(pool).rank(axis=1) <= 15
 
# SMA120 廣度:宇宙內收盤站上 120 日均線的比例,換股日 > 0.5 才持股
above = (close > sma120).where(universe).astype(float)
breadth = above.sum(axis=1) / universe.sum(axis=1).replace(0, np.nan)
risk_on = breadth > 0.5

我們用資料截至 2026-09-30 實跑這段:6 月 30 日、8 月 31 日、9 月 30 日三個換股日選出的 15 檔,和下載版完整策略逐檔相同;7 月 31 日廣度 0.40,完整策略那個月持現金。回測、零件拆解與逐年報酬見文末可下載的 strategy.py。

三個零件各管一件事,下表是逐一拆解的真實回測(其餘設定不變,全部與 0050 同日起算):

設定 研究段年化 研究段月夏普 2022 年起年化 2022 年起月夏普 全期最大回撤
完整策略 26.1% 1.43 24.8% 0.97 -42.1%
拿掉雙均線趨勢閘 22.2% 1.28 21.1% 0.86 -40.5%
拿掉 SMA120 廣度擇時 32.1% 1.22 25.3% 0.91 -42.4%
拿掉 MACD 反轉因子 21.5% 1.18 19.2% 0.88 -38.3%
擇時改用 hist > 0 的比例(2015-02-26 起算) 11.4% 0.68 10.6% 0.73 -41.7%
含息 0050 買進持有 15.1% 1.00 30.5% 1.21 -34.0%

完整策略、拿掉 MACD 反轉因子與含息 0050 的研究段、2022 年起、全期年化報酬對照長條圖

讀法:趨勢閘與 MACD 反轉因子在兩段都加分,拿掉任一個,研究段與 2022 年起的年化都少 3.7 到 5.6 個百分點;廣度擇時主要改善研究段月夏普(1.22 到 1.43)、在 2022 年少賠,但讓報酬變低,也沒擋住 2026 年 7 月。五個版本的 2022 年起月夏普都在 1.0 以下,問題出在整套方法近幾年的表現,不是某一個零件。

這套策略研究段(2015-01-30 至 2021 年底)年化 26.1%、月夏普 1.43、月索提諾 2.43、研究段最大回撤 -24.9%;2022 年起(至 2026-09-30)年化 24.8%、月夏普 0.97、月索提諾 1.14、最大回撤 -42.1%;全期年化 25.5%、月夏普 1.04、月索提諾 1.32、最大回撤 -42.1%、年化波動 27.6%。同日起算的含息 0050 研究段 15.1%、月夏普 1.00;2022 年起 30.5%、1.21;全期 21.2%、月夏普 1.07、月索提諾 1.85、最大回撤 -34.0%、年化波動 19.8%。全期只有年化報酬勝過 0050(25.5% 對 21.2%),月夏普、月索提諾與最大回撤都輸;2022 年起四項全輸。

下面是完整互動式回測:月報酬熱力圖、權益曲線、年度績效都可以直接在文章裡操作:

策略衰退追蹤:2026-06-09 之後發生什麼事

首發版的資料截至 2026-06-09。延長到 2026-09-30 的四個月裡,策略累計 -22.8%,同期含息 0050 +8.9%:

期間 策略 含息 0050
2026-06-09 至 06-30 +0.2% +4.2%
2026 年 7 月 -30.2% -4.0%
2026 年 8 月 +5.0% +3.3%
2026 年 9 月 +5.2% +5.5%

首發資料截止日 2026-06-09 之後,MACD 反轉加分策略與含息 0050 的淨值走勢,策略 7 月大跌後未收復

7 月的經過是這樣:6 月 30 日換股時廣度 0.87,策略照常持有 15 檔。7 月前四週,廣度從 0.87 一路滑到 7 月 20 日的 0.57,再回到 0.66,始終在 0.5 之上,策略淨值到 7 月 27 日已跌 20.8%(0050 同期 -5.3%);7 月 28 日到 30 日三天,廣度從 0.66 掉到 0.29,策略再跌 18.6%(0050 -7.8%),7 月 31 日反彈 8.2%。這 15 檔從 7 月 1 日進場抱到 8 月 3 日,全部虧損,中位數 -27.2%,最差的國巨(2327)-51.6%;其中 14 檔在 7 月間曾收在 60 日或 120 日均線之下,但趨勢閘只在換股日檢查。7 月 31 日換股時廣度 0.40,8 月 3 日收盤才換成現金(8 月 3 日當天策略 +5.0%,就是 8 月那一格的全部報酬),8 月底廣度回到 0.70 才重新持股。

這一跌讓策略從 2026-05-26 的高點到 7 月 30 日回落 42.1%,成為全期最大回撤;9 月底仍在高點下 30.9%。對照歷史,研究段最差的月份是 2019 年 5 月的 -10.6%,2022 年起在這之前最差是 2022 年 1 月的 -15.2%,7 月的 -30.2% 約是它的兩倍。

同一次執行把淨值截到首發日 2026-06-09 重算,2022 年起月夏普是 1.28,和首發版的 1.26 相近;研究段 26.1%、月夏普 1.43 不受新資料影響。所以 1.28 降到 0.97,是這四個月、主要是 7 月一個月造成的。依季度刷新的規則,我們不改參數:網格裡持股 15 檔、門檻 0.52 那一格 2022 年起月夏普四捨五入後是 1.00,看起來只差一點,但看著新資料把門檻從 0.50 挪到 0.52,就是拿答案回頭調參,不換。

這次衰退說明了兩件事。第一,SMA120 廣度是慢訊號,選股籃裡的強勢股先跌,市場整體結構要到月底才跟著轉弱;第二,月頻檢查讓擇時只能事後反應。想要更快的保護,得改成日頻停損或日頻擇時,那是另一個策略,需要另外驗證,不是在這篇裡改參數。同一批技術指標文在 2026-09 重跑時也普遍在 7 月重挫,均線選股文的經過可對照均線怎麼用才對。

回測方法與口徑

量化結論的可信度取決於方法,以下逐項交代:

  • 交易成本:策略使用 finlab sim(),台股預設已內扣手續費(本文以 0.1425% 打三折計)與賣出證交稅 0.3%。
  • 滑價:未額外假設滑價,實際成交衝擊取決於資金規模與流動性。
  • 股票池:上市櫃普通股,60 日均量大於 100 萬股、收盤大於 10 元、60 日均成交金額前 300 名,再經雙均線趨勢閘(換股日收盤同時站上 SMA60 與 SMA120)限縮。
  • 排除類別:只留代號剛好 4 碼數字的股票(排除權證、特別股、6 碼代號),再排除 ETF(代號 00 開頭)、金融保險股、處置與全額交割股。KY 股代號是 4 碼數字,沒有排除。首發版寫「排除 KY 股」與實際程式不符,已更正。
  • 生存者偏差:宇宙每天依當時資料篩選,2015-01-30 有收盤價、到 2026-09-30 已無收盤價的 4 碼普通股共 142 檔,在當時都可能被選入。
  • 前視偏差:多窗動能、ATR、MACD hist、雙均線與廣度均只使用當日(含)以前的價格;月頻再平衡,換股日收盤算出的訊號從下一個交易日起生效。完全不使用財報或月營收等基本面資料(月營收對照組另行說明公布日對齊)。
  • 檢查頻率:趨勢閘與廣度擇時都只在每月最後一個交易日讀取,月中不出場。
  • 權重:選股籃等權,15 檔時單檔約 6.7%;趨勢閘後池子不足 15 檔的月份由入選股平分,全期最多單檔 7.1%(14 檔)。不另設個股上限。
  • 周轉率:全期年換手約 7.3 次(月再平衡 + 趨勢閘進出 + 廣度擇時切換)。
  • 基準與起算日:含息 0050 用 etl:adj_close 純算術買進持有,與策略同日 2015-01-30 起算。首發版的 0050 從 2015-01-05 起算,早了一段,已對齊。
  • 樣本內外:研究段 2015-2021 是選參數用的;2022 年起在首發時已被看過,是選參數時參考過的驗證段,真正沒看過的資料只有 2026-06-09 之後這四個月。

穩健度

把每個主張拆開看,哪些站得住、哪些在新資料後變弱:

  • 反轉方向站得住:hist 最低一籃減最高一籃的年化差距,研究段 9 組、2022 年起 9 組全為正,跨原始 hist、除以收盤、z-score 與每籃 20/30/50 檔皆成立。
  • 研究段是高原,2022 年起整片下滑:持股檔數 12/15/18/20 檔與廣度門檻 0.45/0.48/0.50/0.52 排成 16 格,研究段月夏普全部在 1.31 到 1.56 之間;但 2022 年起月夏普落在 0.64 到 1.00,只有一格四捨五入到 1.00、實際仍略低於 1.0,16 格都沒有同時過「研究段年化 ≥ 25%、月夏普 ≥ 1.2、2022 年起年化 ≥ 15%、月夏普 ≥ 1.0」四道門檻(首發版是 16 格中 13 格通過)。
  • MACD 參數不是關鍵:12-26-9、8-17-9、6-19-9、12-26-5 四組換進完整策略,研究段月夏普 1.31 到 1.44,2022 年起 0.88 到 0.97,結論一樣。
  • 逐年看:全期 12 個年度裡 7 年贏 0050,但 2024、2025、2026(截至 9 月)連三年落後;2022 年起 5 個年度 4 年正報酬,只有 2022 年 -20.1%。

參數最佳化:研究段的高原,2022 年起的下坡

策略裡最容易被「調到漂亮」的兩個旋鈕是持股檔數 N與廣度持倉門檻 thr。我們對這兩個旋鈕做 4×4 網格、每一格都真跑一次回測。看色溫圖要找一整片都偏綠的高原;一格特別深綠的孤峰,多半是湊參數湊出來的。研究段的色溫圖符合高原的樣子:

持股檔數與廣度門檻的研究段月夏普色溫圖,16 格全部在 1.31 到 1.56 之間,預設 15 檔、門檻 0.50 為 1.43

同一張網格換成 2022 年起的月夏普,整片往下掉(兩張圖用同一組色階,1.0 是中間的淡黃色):

同一張持股檔數與廣度門檻網格的 2022 年起月夏普色溫圖,16 格落在 0.64 到 1.00,門檻 0.45 那一列最低

參數組 研究段月夏普 2022 年起月夏普 2022 年起年化 全期最大回撤
預設(N = 15、thr = 0.50) 1.43 0.97 24.8% -42.1%
研究段月夏普最高(N = 18、thr = 0.48) 1.56 0.81 19.1% -42.6%
2022 年起最高(N = 15、thr = 0.52) 1.43 1.00 25.8% -42.1%

照研究段月夏普往最高那格調(18 檔、門檻 0.48),2022 年起反而掉到 0.81。研究段的高原沒有延續到 2022 年之後,這也是我們不建議照研究段數字微調參數的原因。至於 2022 年起最高那格,是看過新資料後才知道的答案,選它就是過度最佳化。

加上月營收 YoY 會更好嗎:基本面是選配,不在主策略內

本文的主策略是完全不含基本面的純技術策略:選股只用價量動能、低波與 MACD hist 反轉,風控只用雙均線趨勢閘與站上 SMA120 的廣度。純技術訊號每日可得、沒有財報公布延遲與對齊問題,回測口徑乾淨、可重現性高。

常見的延伸問題是:在選股端疊一層月營收年增率(YoY),績效會不會更好?我們用兩種搭法各跑一次(月營收以公布日對齊,只用當時已公布的數字),基線為純技術策略:

策略 研究段月夏普 2022 年起月夏普 2022 年起年化 全期最大回撤
純技術策略(基線) 1.43 0.97 24.8% -42.1%
+ 月營收 YoY > 0 過濾 1.36 0.94 25.3% -43.9%
+ 月營收 YoY 分位(第 4 因子) 1.20 0.84 19.5% -43.1%

純技術策略搭配月營收 YoY 兩種做法的研究段與 2022 年起月夏普、2022 年起年化對照長條圖,兩種搭法都沒有提升月夏普

月營收 YoY 沒有讓這套純技術策略更好:YoY > 0 過濾讓 2022 年起年化多 0.5 個百分點,但研究段與 2022 年起月夏普都略降、最大回撤更深;當第 4 因子則兩段都明顯變差。純技術面的多窗動能加低波核心,已經吃下這批股票多數可用的訊號,所以主策略維持純技術面。想進一步了解基本面與技術面選股的分工,可參考技術面與基本面選股的差異。

不同年度的表現:多頭吃得到,近三年落後 0050

把全期逐年報酬攤開,並和同期含息 0050 對照(2015 年自 1 月 30 日起算,2026 年截至 9 月 30 日;皆為真實回測):

年度 策略 含息 0050 不擇時(全程持有) 策略勝 0050?
2015 +19.0% -7.9% -3.4% 勝
2016 +17.1% +19.6% +14.4% 負
2017 +54.1% +18.1% +54.0% 勝
2018 -1.3% -4.9% +11.6% 勝
2019 +21.3% +33.5% +36.1% 負
2020 +57.7% +31.1% +70.1% 勝
2021 +22.6% +21.9% +55.8% 勝
2022 -20.1% -21.4% -34.5% 勝
2023 +60.1% +27.5% +76.1% 勝
2024 +20.6% +48.6% +14.3% 負
2025 +31.7% +36.8% +35.3% 負
2026(截至 9 月) +40.3% +74.3% +63.1% 負

三個重點:

  • 多頭年吃得到:2017、2020、2023 年策略都在 50% 以上,大幅贏 0050。
  • 擇時的貢獻集中在少數年份:和不擇時版本相比,擇時在 2015 年多賺 22.4 個百分點、2022 年少賠 14.4 個百分點,2016 與 2024 年也小幅加分;但在 2018、2019、2020、2021、2023、2025、2026 年都讓報酬變低,2021 年少了 33.2 個百分點。擇時是用報酬換那幾次大跌的保護。
  • 近三年落後:2024 到 2026 年連三年輸 0050,2026 年截至 9 月策略 +40.3%、0050 +74.3%,其中 7 月一個月就差了 26.2 個百分點。

用大盤訊號在不同市況降回撤的其他做法,可延伸看均線市場濾網。

三項穩健性驗證:重跑到 2026 年 10 月

這裡驗證本文的完整策略:站上 60 與 120 日均線的股票裡,依多窗動能、低波與 MACD(8-17-9)柱狀圖反轉的綜合分取 15 檔等權,股票池站上 120 日均線的比例不到一半時整籃清空,每月換股。我們在 2026-10-27 用本文附的 strategy.py(把 DATA_END 改成 None,finlab 2.2.20,資料截至 2026-10-27)把它重跑到最新,再做三項檢查。三項檢查的「贏」都是同一個意思:日夏普高於同一段期間的 0050 含息買進持有(etl:adj_close 還原價、純算術計算、不扣成本)。兩邊的日夏普用同一個公式:日報酬平均除以標準差、乘上 √252,不扣無風險利率。三項都用 sim() 預設的手續費 0.1425% 與證交稅 0.3%;原文手續費三折的結果另列於成本對照表。

檢查 標準 結果
鄰近參數 MACD 快線/慢線(6/13、8/17、10/21)乘上持股檔數(12、15、18),9 組至少 7 組贏 0/9 組贏,不過
前後兩段 2015-01-30 到 2020-12-11、2020-12-14 到 2026-10-27 兩段都贏 前段 1.02 對 0.89,後段 0.85 對 1.24,不過
交易成本 原參數、sim() 預設成本 日夏普 0.91 對 1.08,不過

MACD 反轉加分策略鄰近參數 9 組日夏普熱圖:0 組高於同期 0050 含息,原參數日夏普 0.91

9 組參數的日夏普(括號內是年化報酬,粗體是原文參數):

持股檔數 \ MACD 快線/慢線 6/13 8/17 10/21
18 0.88(年化 21.6%) 0.90(年化 22.2%) 0.93(年化 23.2%)
15 0.87(年化 21.8%) 0.91(年化 23.0%) 0.88(年化 21.9%)
12 0.77(年化 18.7%) 0.85(年化 21.5%) 0.86(年化 21.6%)

前後兩段與全期:

期間 策略年化 策略日夏普 0050 含息年化 0050 日夏普
前段 2015-01-30 到 2020-12-11 22.2% 1.02 13.5% 0.89
後段 2020-12-14 到 2026-10-27 23.5% 0.85 28.0% 1.24
全期 2015-01-30 到 2026-10-27 23.0% 0.91 20.5% 1.08

前後兩段是把整段期間從中點對半切。上文的研究段與樣本外以 2022 年初為界,照這個切法,2015 到 2021 年日夏普 1.02 對 0050 的 0.96,2022 年起 0.81 對 1.22。上文多用月夏普,跟這裡的日夏普算法不同,數字不能直接比。

交易成本對照(原參數):

成本設定 年化 日夏普 最大回撤
不扣成本 28.5% 1.08 -41.6%
sim() 預設:手續費 0.1425%、證交稅 0.3% 23.0% 0.91 -42.4%
原文設定:手續費打三折 24.9% 0.97 -42.1%
0050 含息買進持有(同期) 20.5% 1.08 -34.0%

9 組鄰近參數全部輸,日夏普在 0.77 到 0.93 之間,MACD 快慢線換成 6/13 或 10/21、持股 12 到 18 檔都一樣。前段(2015 到 2020 年)日夏普 1.02 贏 0050 的 0.89,後段 0.85 輸 1.24,三項都不成立,跟上文「研究段的高原,2022 年起的下坡」一致。上文的年化 25.5% 是資料到 2026-09-30、手續費打三折的結果;照三折跑到 2026-10-27 是 24.9%,換成 sim() 預設成本是 23.0%。

策略的限制與取捨

  • 2022 年起已跌破門檻:2022 年起月夏普 0.97、年化 24.8% 落後 0050 的 30.5%。參數維持首發設定,之後的季度重跑會繼續追蹤。
  • 回撤比 0050 深:全期最大回撤 -42.1%,比含息 0050 的 -34.0% 深,年化波動 27.6% 也高於 0050 的 19.8%。只持 15 檔、單檔約 6.7%,單股與類股風險集中。
  • 月頻檢查跟不上急跌:趨勢閘與廣度擇時都只在月底讀取,2026 年 7 月的跌幅發生在兩個換股日之間。
  • 擇時空手期有機會成本:33 個月持現金,多數年份因此少賺;它主要在 2015 與 2022 年發揮作用。
  • 崩盤型態涵蓋有限:資料起點 2015,未對更早期(2008、2011)的崩盤型態做測試。
  • 容量與成本:選股籃僅 15 檔、宇宙限前 300 大,大資金部署需重估流動性衝擊;年換手約 7.3 次,報酬已在 sim() 內扣手續費與證交稅,但實單滑價會進一步侵蝕,本文未估算策略容量。

自己跑一次

把下面這段話交給你的 AI 助理,它會引導你安裝 FinLab Skill、抓台股資料、重現這篇的回測:

裝好之後,下載本文的 strategy.py 與 data.csv,即可在自己的環境重跑、改參數、換因子。strategy.py 會印出本文的主表、零件拆解、逐年報酬與 2026-06-09 之後的逐月報酬;資料截止日釘在 2026-09-30,改成 None 就用最新資料。data.csv 是策略與含息 0050 同日起算的每日淨值,外加每日的 SMA120 廣度。登入只需在程式裡寫 finlab.login(),套件會在需要資料時引導你完成登入。想延伸成更完整的量化流程,可參考量化交易總覽與程式交易是什麼。各種技術指標「用錯 vs 用對」的一次比較,見13 個技術指標台股回測總覽。想自己用 Python 算各種技術指標,可看 TA-Lib 158 種技術指標教學。

常見問題

Q:MACD 的金叉、死叉到底能不能用來買賣? 就本文台股回測來看,金叉沒有獨立優勢。每月持有近 20 個交易日剛金叉的股票(每月中位數約 176 檔),研究段年化 9.4%、月夏普 0.54,2022 年起年化 14.1%,都輸給同期含息 0050。金叉發生時動能多半已反映在價格,台股的交叉訊號又多。MACD 比較有效的用法是當其他訊號的加分因子。

Q:MACD 柱狀圖(hist)越高,是不是代表越該追多? 在台股月頻橫截面上剛好相反。hist 最高的 30 檔研究段年化只有 3.6%,hist 最低(剛超賣)的 30 檔反而有 8.2%;2022 年起也是最低一籃勝出(28.5% 對 10.9%)。hist 衝最高時動能多半已反映完,隨後容易均值回歸。

Q:MACD 參數要設多少?12-26-9 是最好的嗎? 12-26-9 是最常見的預設,本文主策略用的是 8-17-9。四組常見參數(12-26-9、8-17-9、6-19-9、12-26-5)換進同一套策略,研究段月夏普 1.31 到 1.44,2022 年起 0.88 到 0.97,差距不大。與其調參數,不如先把方向用對。

Q:MACD 背離(價格創新高、hist 沒創新高)準嗎? 背離的直覺和本文發現一致,都是「hist 走弱常領先價格反轉」。但背離是逐檔、主觀判讀的訊號,難以系統化回測,本文沒有直接測背離;我們把同一個機制做成可重現的橫截面反轉因子來檢驗。

Q:MACD 可以拿來做大盤擇時、判斷該不該進場嗎? 我們實測過:把本文策略的擇時訊號換成「可交易宇宙裡 hist 大於 0 的比例 > 0.5」,研究段年化只剩 11.4%、2022 年起 10.6%,遠低於 SMA120 廣度版的 26.1% 與 24.8%。hist 的正負翻得太快,開關切換次數是 SMA120 廣度的 2.4 倍,一半的換股月都在持現金。要管大盤曝險,較平滑的廣度訊號比較合適;但本文的 SMA120 廣度在 2026 年 7 月也沒來得及反應,見衰退追蹤一節。

Q:MACD 和 RSI、KD 一起用會更好嗎? 這些都是擺盪或動能類指標,算法都來自近期價格,資訊重疊度高。本文沒有測 MACD 加 RSI、KD 的組合;本文的做法是搭配不同性質的訊號:動能與低波選股、MACD 反轉加分、市場廣度管曝險。各指標的正確用法可參考 RSI vs MACD vs KD:三大技術指標台股實測。

Q:這套策略適合誰? 適合想研究「指標怎麼當選股因子」、能接受 -42% 等級回撤與每年約 7 次換手的人。全期年化 25.5% 仍高於含息 0050 的 21.2%,但 2022 年起已經落後,2026 年 7 月單月 -30.2%。不適合受不了深度回撤、或想要穩定贏大盤的人,那種需求直接買進持有含息 0050 更省心。


最後更新:2026-10|回測區間:2015-01 ~ 2026-09-30|作者:FinLab 量化研究團隊(經量化研究員審閱)

本文僅供量化研究與教學用途,所有回測數字均由 finlab 套件在真實台股資料上產出,過去績效不代表未來表現,不構成投資建議。本策略全期最大回撤 -42.1%,2022 年起月夏普已低於 1.0,實際交易前請自行評估風險、滑價與交易容量。

FinLab AI

想建立自己的策略?

用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案

免費開始

更多技術指標研究

查看全部