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 套件(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 只有三條算式:
逐項拆解每個符號:
- 是每日收盤價。
- 、 分別是收盤價的 12 日與 26 日指數移動平均(EMA,越近的價格權重越大)。兩者相減得到快線 DIF:當短期均線拉開長期均線越多,DIF 越大,代表近期動能相對長期在加速。
- 是 DIF 再取 9 日 EMA,也就是慢線(訊號線),把 DIF 的短期抖動再平滑一次。
- 是 DIF 減 DEA 的差,畫成零軸上下的柱狀圖。hist 由負翻正、柱子變長,傳統解讀為「快線正在拉開慢線、多頭力道集結」;本文後面會用真實資料指出,在台股月頻橫截面上這個解讀的方向其實是反的。
12、26、9 這組參數是 Gerald Appel 最初的設定,也是各家看盤軟體的預設值。本文主策略改用反應更快的 8-17-9,後面會把四組常見參數都放進同一套策略比較。
兩派訊號在個股上長什麼樣:台積電一年 44 個進出點
把公式畫到真實個股上,最能看出兩派用法的問題。下面這張圖取台積電(2330)2023 年 7 月到 2024 年 6 月、約一年的窗,上半部是收盤價並標出兩派的買賣箭頭,下半部是 MACD(8-17-9)的 DIF、DEA 與 hist 柱:

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

兩個方向單獨用都輸 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%)持現金。

很多人會直覺想用 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 時成立,延長資料後不成立。

「風險升高時降部位」的邏輯,學術上有波動度擇時的支持:Moreira & Muir (2017) 在《Volatility-Managed Portfolios》證明,在已實現波動升高時調降部位,能提升投資組合的 Sharpe。本文用的是更慢的市場廣度、而且每月才檢查一次,2026 年 7 月的結果顯示這個頻率跟不上急跌。用大盤訊號降回撤的其他做法,可參考均線市場濾網。
完整策略:雙均線趨勢閘 + 多窗動能低波核心 + MACD 反轉 + SMA120 廣度擇時
把上面的洞見組成一套可執行、可重現、完全不含基本面的純技術策略:
- 雙均線趨勢閘:在可交易宇宙裡,換股日只保留「收盤同時站上自身 SMA60 與 SMA120」的個股。
- 選股核心:在趨勢閘後的池子裡,依綜合分(0.65 多窗動能分位 + 0.20 低波分位 + 0.15 MACD 反轉分位,三者皆「分位越小越好」)排序,每月選前 15 檔等權持有。多窗動能分位 = 20/60/120 日報酬三個橫截面分位的平均。
- MACD 反轉因子:用 8-17-9 參數算出 hist,做橫截面排名,hist 越低(越超賣)分位越好;它只佔 0.15 權重,是加分項不是主角。
- 市場廣度擇時:換股日計算可交易宇宙裡收盤站上 SMA120 的個股比例,大於 0.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 反轉因子在兩段都加分,拿掉任一個,研究段與 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% |

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 網格、每一格都真跑一次回測。看色溫圖要找一整片都偏綠的高原;一格特別深綠的孤峰,多半是湊參數湊出來的。研究段的色溫圖符合高原的樣子:

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

| 參數組 | 研究段月夏普 | 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 沒有讓這套純技術策略更好: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,不過 |

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 自動驗證、回測、給你答案
免費開始

