布林通道在台股的正確用法:拆成選股因子加大盤風控
| 你想知道的 | 本文用真實台股回測的回答 |
|---|---|
| 布林通道是什麼 | 以 20 日均線為中軌、上下各 2 個標準差為通道的波動指標;%b 衡量價格在通道中的位置 |
| 觸下軌買進有效嗎 | 研究段(2015-2021)年化僅 2.5%、月夏普 0.22;觸上軌追突破也只有 9.6%,兩者都輸同期含息 0050 的 14.7% |
| 布林通道能拿來選股嗎 | 單獨選股不行;但「擠壓狀態下的 %b」放進綜合分有用,拿掉它研究段月夏普由 1.24 掉到 0.85 |
| 那它該怎麼用 | 兩個零件分工:擠壓 %b 當選股因子之一,股票池內站上中軌的比例(布林廣度)當大盤風控開關 |
| 效果如何 | 全期(2015-02~2026-09)年化 27.0%、月夏普 1.13,勝含息 0050 的 21.0%、1.06;研究段大幅領先,但 2022 年起年化 24.6% 落後 0050 的 30.5% |
| 要注意什麼 | 風控只在每月換股日讀取:2026 年 7 月廣度在 7/17 就轉弱,部位到 8/3 才換成半倉 0050,策略當月 -22.9% |
執行這個策略
複製提示詞,讓 AI 依照上方證據的資料、條件與風險檢查重跑一次。
告訴你的AI:
幫我設定 FinLab,重現這篇文章,請讀:https://finlab.finance/setup?relatedUrl=/blog/bollinger-bands-taiwan
若想比較布林通道以外的選股規則,可看營收篩選創新高策略,核對股價新高、RSI 與營收條件如何形成持股。

本文所有數字皆出自 finlab 套件抓取的上市櫃真實價量資料(
price與etl:adj_close含息還原股價),回測區間 2015-02-26 至 2026-09-30(2026-10-12 重跑),基準為與策略同一天起算的含息 0050。文末附可下載的strategy.py與data.csv,執行strategy.py會印出本文的主要表格。對回測的觀念還不熟,可先看回測是什麼。
布林通道是什麼
布林通道(Bollinger Bands)是 John Bollinger 在 1980 年代提出的波動指標,由三條線組成:中軌是 N 日移動平均(常用 20 日),上下軌則是中軌加減 K 個標準差(常用 2 個)。標準差會隨波動放大或收縮,所以通道會「呼吸」:盤整時收窄、急漲急跌時張開。布林通道的學理整理見 John Bollinger(2001)的《Bollinger on Bollinger Bands》。技術指標的基礎名詞可參考名詞詞彙表。
實務上常用兩個衍生量:
%b:價格在通道中的相對位置,公式為 %b =(收盤價 − 下軌)/(上軌 − 下軌)。等於 0 代表貼著下軌、等於 1 代表貼著上軌、0.5 代表在中軌。
帶寬(Bandwidth):(上軌 − 下軌)/ 中軌,衡量通道張開的程度。帶寬收到很窄稱為「擠壓(squeeze)」,常被視為波動即將放大的前兆。
布林通道在台股有兩派互斥用法:均值回歸派主張「觸下軌買、觸上軌賣」,假設價格會回到中軌;擠壓突破派則主張在帶寬收窄後,等價格向上突破上軌再追。哪一派對?直接回測。
布林通道的數學定義:四條算式
把上面的文字寫成公式,布林通道只有中軌、上軌、下軌三條線,外加一個衍生的位置指標 %b:
逐項拆解每個符號:
- 是每日收盤價, 是回看天數(常用 20 日), 是標準差倍數(常用 2)。
- (Middle Band,中軌)是收盤價的 日簡單移動平均 ,也就是這段期間的平均成本線。
- 是同一段 日收盤價的標準差,衡量這段期間的波動大小。波動放大, 就變大。
- (上軌)、(下軌)分別是中軌加減 個標準差。因為 會隨波動呼吸,通道在盤整時收窄、在急漲急跌時張開,這是布林通道和固定百分比通道最大的差別。
- 把收盤價換算成「在通道裡的相對位置」:等於 0 貼著下軌、等於 1 貼著上軌、0.5 在中軌、超過 1 代表收在上軌之上。它把三條線壓縮成一個 0 到 1 附近的數字,方便橫截面比較。
帶寬則定義為 ,是把通道張開程度標準化成中軌的百分比,後面的擠壓濾網就是用它來判斷波動是否收斂。
這裡有一個性質直接關係到「參數要設多少」:把公式展開,。同一天所有股票用同一個 ,%b 的高低排序就和 無關;擠壓濾網比的是帶寬和自己過去的中位數, 在兩邊同時出現、互相抵銷;廣度風控只看收盤有沒有站上中軌,中軌本身不含 。所以本文策略不論 設 1.5、2 還是 2.5,選出來的股票與風控訊號都一樣,真正會影響結果的是週期 。
看一張圖就懂:兩派訊號在個股上長什麼樣
先用台積電(2330)一段約 12 個月的走勢,把兩派教科書訊號標在圖上。價格面板疊上布林上中下軌(20 日、±2 標準差),並標出均值回歸派(跌破下軌買、站上上軌賣)與擠壓突破派(帶寬擠壓後突破上軌買)各自的進出點:

光是 2023 年 7 月到 2024 年 6 月這 12 個月,台積電就觸發了 19 個教科書訊號:均值回歸派的「跌破下軌買」3 次、「站上上軌賣」12 次,擠壓突破派的「擠壓後突破上軌買」4 次。問題一眼可見:在這段台積電整體往上的趨勢裡,均值回歸派的「站上上軌就賣」會一路在低位把上漲的部位賣光,等於賣在起漲點;而「跌破下軌就買」在真正的回檔段又常常買得太早。換成聯發科(2454)更明顯,同一套規則觸發 21 個訊號、其中 14 次是上軌賣出訊號:

這就是布林通道單獨當買賣訊號的結構性問題:觸軌訊號又多又雜,在盤整盤裡會反覆把人甩出場(whipsaw),在趨勢段又會追高殺低。 訊號頻繁往往代表雜訊大,未必代表優勢多;把同樣的規則攤到整個股票池回測,研究段幾乎沒賺到錢。
想自己數出這些訊號、換成任何一檔股票,把下面的 sid 改掉即可(2330 會印出 3、12、4,2454 會印出 2、14、5):
顯示程式碼
import finlab
from finlab import data
# 套件會在需要資料時自動引導登入
finlab.login()
close = data.get("price:收盤價")
# 布林通道:20 日、±2 標準差(直接取 finlab 內建指標)
upper, middle, lower = data.indicator(
"BBANDS", timeperiod=20, nbdevup=2.0, nbdevdn=2.0
)
sid = "2330"
# 帶寬與擠壓用完整歷史計算,避免 120 日中位數在短窗內算不出來
bandwidth = (upper[sid] - lower[sid]) / middle[sid]
squeeze = bandwidth < bandwidth.rolling(120, min_periods=60).median()
# 取一段約 12 個月的窗來看訊號
px = close[sid].loc["2023-07":"2024-06"].dropna()
ub = upper[sid].loc[px.index]
lb = lower[sid].loc[px.index]
def first_days(condition):
"""條件由不成立轉為成立的日子。"""
previous = condition.shift(1, fill_value=False)
return condition.index[condition & ~previous]
# 均值回歸派:收盤跌破下軌當天 = 買、站上上軌當天 = 賣
meanrev_buy = first_days(px < lb)
meanrev_sell = first_days(px > ub)
# 擠壓突破派:站上上軌的那天,帶寬正處於擠壓狀態才算數
squeeze_breakout = [day for day in meanrev_sell if squeeze[day]]
print("均值回歸買點:", len(meanrev_buy), "賣點:", len(meanrev_sell))
print("擠壓突破買點:", len(squeeze_breakout))散戶最常見的「觸下軌買」,研究段年化只有 2.5%
我們在可交易宇宙(60 日均成交金額前 300 大、收盤 > 10 元,排除 ETF、金融股、處置股)裡,把幾種「布林通道選股」用法各跑一次月再平衡的回測(30 檔等權、不加任何風控),結果如下:
| 布林通道用法 | 研究段年化(2015-2021) | 研究段月夏普 | 樣本外年化(2022-01~2026-09) |
|---|---|---|---|
| 觸下軌買進(%b 最低 30 檔,均值回歸) | 2.5% | 0.22 | 17.9% |
| 觸上軌追突破(%b 最高 30 檔) | 9.6% | 0.57 | 9.9% |
| 只在擠壓股裡取 %b 最高 30 檔 | 13.5% | 0.74 | 8.5% |
| 純動能籃(不靠布林,70 日最強 10 檔,反波動加權) | 19.3% | 0.67 | 9.8% |
| 含息 0050 買進持有(與策略同日起算) | 14.7% | 0.97 | 30.5% |

最多人用的「觸下軌買進」在研究段年化只有 2.5%、月夏普 0.22,接近無效。 它在樣本外年化回到 17.9%,但同期含息 0050 是 30.5%,四種用法沒有一種在兩段都站得住。原因不難理解:%b 是個「雙義訊號」,低 %b 可能是健康回檔(該買),也可能是趨勢轉空的起點(該跑);把它單獨拿來橫截面排名選股,等於把兩種互斥邏輯混在一起互相抵消。我們也測了 %b 的多空價差(做多 %b 最低 30 檔、放空 %b 最高 30 檔),研究段年化 -6.6%、樣本外 -0.7%,兩段都是負的。
%b 並非全無資訊,問題在於它被當成全天候訊號。如果先用「帶寬擠壓」把雜訊濾掉,只在帶寬收到自身近 120 日中位以下、波動已收斂的個股裡看 %b,研究段年化由 9.6% 提高到 13.5%、月夏普由 0.57 提高到 0.74。但這個改善沒有延續到樣本外:2022 年起擠壓版年化 8.5%,反而略低於不設濾網的 9.9%。單獨拿來選股,擠壓 %b 仍然不夠;它的價值要放進綜合分才看得出來。延伸閱讀:技術面與基本面選股的差異、動能策略。
把布林通道拆成兩個有用的零件
整個布林通道當買賣訊號失效,但拆開來看,它有兩個零件放進策略後有用,本文的純技術策略就建立在這兩個零件上。
零件一:擠壓狀態下的 %b 當選股因子
擠壓突破派的核心論點是「帶寬收窄代表能量累積,後面的動作比較真」。我們把它變成一個選股因子:只在「帶寬低於自身近 120 日中位(處於擠壓狀態)」時,才計算個股 %b 的橫截面排名,不在擠壓狀態的股票這一項不給分。上一節已經看到,這個因子單獨用並不穩定;它在本文策略裡的角色,是和 70 日動能、低波一起加總成綜合分,在動能相近的股票裡,優先挑出波動已經收斂、價格又位在通道偏上方的那幾檔。
拿掉這一項的對照最能說明它的貢獻:其餘條件完全相同,只把綜合分裡的擠壓 %b 移除,研究段年化由 28.9% 掉到 14.6%、月夏普由 1.24 掉到 0.85,樣本外月夏普也由 1.10 降到 0.98。
零件二:站上中軌的股票比例當大盤風控
單看一檔指數(例如 0050)有沒有站上自己的布林中軌,訊號太雜:盤整期會反覆穿越、來回甩巴掌。如果改看「可交易股票池裡有多少比例的股票站上各自的布林中軌」,就得到一個橫截面的、較平滑的大盤多空力道度量,我們稱為布林廣度。這裡的股票池就是選股用的同一個宇宙(60 日均成交金額前 300 名、排除 ETF 與金融股等);0.42 與 0.27 兩條門檻是在這個池子上定的,改用全市場計算,訊號會不一樣。廣度高,代表多數個股結構偏多;廣度崩落,代表系統性轉弱。把它取 10 日指數移動平均,再用兩條門檻做成 risk-on / risk-off 開關,就是整套策略的防禦腿。

圖上紫線是每天的布林廣度(左軸),兩條紅色虛線是轉換門檻,藍線是策略淨值(右軸,對數刻度)。要注意的是,回測每月只換股一次,廣度狀態也只在每月最後一個交易日讀取:2015 年以來廣度一共 23 次轉入 risk-off,其中 8 次在月底前就回到 risk-on,回測完全沒有執行;其餘 15 次從轉弱到換股日生效,中位數要等 6 個交易日、最長 14 個交易日。這個落差在 2026 年 7 月造成明顯損失,細節見後面的新資料追蹤。
這種「市場風險升高時降低曝險」的思路,學術上最接近的是 Moreira & Muir (2017) 的《Volatility-Managed Portfolios》:他們用前一個月的已實現變異數縮放股票曝險,發現能提高投資組合的 Sharpe。布林廣度量的是橫截面的市場結構,兩者不是同一個變數,本文也沒有驗證兩者等價;能引用的只是「依風險狀態調整曝險」這個共同方向。
把兩個零件疊上動能與低波組成完整策略後,可以逐層看每一步的效果。下圖從「裸動能籃」(同宇宙、70 日動能最強 10 檔、反波動加權,不加擠壓 %b、不加低波、不加廣度風控)開始,先加入擠壓 %b 與低波兩個選股因子,再加上中軌廣度風控:

| 逐層 | 研究段年化 | 研究段月夏普 | 樣本外年化 | 樣本外月夏普 | 全期最大回撤 |
|---|---|---|---|---|---|
| 裸動能籃(無布林、無風控) | 19.3% | 0.67 | 9.8% | 0.57 | -60.2% |
| +擠壓 %b 與低波(無風控) | 32.0% | 1.31 | 23.1% | 1.01 | -43.0% |
| +中軌廣度風控(完整策略) | 28.9% | 1.24 | 24.6% | 1.10 | -33.4% |
兩個零件的分工很清楚:月夏普的提升主要來自選股端,研究段由 0.67 拉到 1.31;回撤的收斂主要來自廣度風控,全期最大回撤由 -43.0% 收斂到 -33.4%,樣本外月夏普也由 1.01 提高到 1.10。代價是研究段少賺一些:加上風控後,研究段年化由 32.0% 降到 28.9%。
選股端用「買最強的股票」,沒有用「買最弱的等反彈」,這和 Jegadeesh & Titman (1993) 記錄的動能效應一致:過去 3 到 12 個月的贏家,在接下來幾個月傾向繼續贏。本文的 70 個交易日約 3 個多月,落在這個範圍的短端。關於用大盤訊號降低回撤,也可參考均線市場濾網如何降低回撤。
完整策略:布林雙核心純技術選股
把上面兩個零件疊上動能與低波,組成一套可執行、可重現、完全不含基本面的純技術策略:
- 選股綜合分(三個技術因子相加):在可交易宇宙裡,每檔股票算三項橫截面百分位再相加:①70 日報酬(動能);②擠壓狀態下的 %b(帶寬低於自身近 120 日中位時才計分);③0.35 倍的低 NATR(ATR20 ÷ 收盤,取負後排名,越低波越高分)。
- 持股:取綜合分最高的 10 檔,以反波動(1 ÷ NATR)加權,波動越低的股票配重越高。
- 大盤風控(布林廣度):在同一個可交易宇宙裡,計算「收盤站上各自布林中軌(20 日、±2 標準差)」的個股比例,取 10 日指數移動平均平滑,再用雙門檻判斷多空:廣度 > 0.42 轉為 risk-on、< 0.27 轉為 risk-off,介於中間維持前一個狀態,避免在門檻附近反覆切換。
- 資產配置:risk-on 時滿倉持有那 10 檔選股籃;risk-off 時選股清零,改持 0050 佔總曝險 0.5,另一半為現金。
- 月再平衡:每月最後一個交易日產生訊號、下一個交易日收盤換股。廣度狀態也只在這一天讀取,月中轉弱要等到月底才減碼。
選股端的核心程式碼如下(可直接交給你的 AI 助理改寫;這裡的宇宙條件是簡化版,完整條件與回測在文末可下載的 strategy.py):
顯示程式碼
from finlab import data
close = data.get("price:收盤價")
amount = data.get("price:成交金額")
# 可交易宇宙(簡化版):60 日均成交金額前 300 大、收盤 > 10 元,排除 ETF 與權證
liquidity = amount.rolling(60, min_periods=20).mean()
common_cols = [
s for s in close.columns
if str(s)[:4].isdigit() and not str(s).startswith("00")
]
universe = (liquidity.is_largest(300) & (close > 10))[common_cols]
# 布林通道(20 日、±2 標準差)與衍生量
upper, middle, lower = data.indicator("BBANDS", timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
percent_b = (close - lower) / (upper - lower) # %b:價格在通道中的位置
bandwidth = (upper - lower) / middle # 帶寬
# 因子一:70 日動能橫截面百分位
mom_rank = (close / close.shift(70) - 1).where(universe).rank(axis=1, pct=True)
# 因子二:只在擠壓(帶寬 < 近 120 日中位)時計分的 %b 橫截面百分位
squeeze = bandwidth < bandwidth.rolling(120, min_periods=60).median()
squeeze_pb_rank = percent_b.where(universe & squeeze).rank(axis=1, pct=True)
# 因子三:低波 NATR = ATR20 / 收盤,取負後排名(權重 0.35)
natr = data.indicator("ATR", timeperiod=20) / close
lowvol_rank = (-natr).where(universe).rank(axis=1, pct=True)
# 綜合分取最高 10 檔,之後以 1 / NATR 反波動加權
score = mom_rank.add(squeeze_pb_rank, fill_value=0) + 0.35 * lowvol_rank
basket = score.where(universe).rank(axis=1, ascending=False) <= 10完整的廣度風控、配置與回測請見文末可下載的 strategy.py。三段績效與同一天起算的含息 0050 並列如下(資料截至 2026-09-30):
| 區間 | 策略年化 | 策略月夏普 | 策略月索提諾 | 策略最大回撤 | 0050 年化 | 0050 月夏普 | 0050 月索提諾 | 0050 最大回撤 |
|---|---|---|---|---|---|---|---|---|
| 研究段 2015-02~2021-12 | 28.9% | 1.24 | 2.85 | -32.2% | 14.7% | 0.97 | 1.44 | -28.2% |
| 樣本外 2022-01~2026-09 | 24.6% | 1.10 | 1.54 | -31.9% | 30.5% | 1.21 | 2.44 | -34.0% |
| 全期 2015-02~2026-09 | 27.0% | 1.13 | 1.84 | -33.4% | 21.0% | 1.06 | 1.83 | -34.0% |
讀法:研究段年化、月夏普、月索提諾三項大幅領先,年化多出 14 個百分點,最大回撤比 0050 深 4 個百分點;樣本外只有最大回撤略淺,年化少 5.9 個百分點、月夏普與月索提諾也落後。全期加總後,策略勝在年化報酬(27.0% 對 21.0%)與月夏普(1.13 對 1.06),月索提諾與最大回撤和 0050 幾乎打平,年化波動 23.8% 則高於 0050 的 19.8%。它的定位是「長期年化較高、風險調整後小幅領先,但 2022 年起跑輸 0050」的動能策略,全程不吃任何財報或營收資料。
完整互動式回測(月報酬熱力圖、權益曲線、年度績效):
回測方法與口徑
量化結論的可信度取決於方法,以下逐項交代:
- 交易成本:策略使用 finlab
sim(),台股預設已內扣手續費(本文以 0.1425% 打三折計)與賣出證交稅 0.3%。 - 滑價:未額外假設滑價,實際成交衝擊取決於資金規模與流動性。
- 股票池:上市櫃普通股,60 日均成交金額前 300 名、收盤 > 10 元、60 日均量 > 100 萬股。
- 排除類別:排除 ETF(代號 00 開頭)、權證與特別股等非 4 碼數字代號、金融保險股、處置與全額交割股,以降低不可交易標的污染。KY 股的代號也是 4 碼數字,沒有被排除。
- 生存者偏差:價格資料保留了後來下市或停止交易的股票(2015-02-26 有收盤價、2026-09-30 已無收盤價的 4 碼代號個股共 153 檔,含本來就不在股票池內的金融股),宇宙每天依當時的成交資料篩選,符合條件的就會被納入,沒有只用今天還存在的股票回推。
- 前視偏差:70 日動能、布林通道、%b、帶寬擠壓、NATR 與廣度均只使用當日(含)以前的價格;月底產生訊號、下一個交易日換股。完全不使用財報或月營收等基本面資料,自然沒有財報公布日對齊問題。
- 風控執行頻率:廣度訊號每天都算得出來,但回測每月換股一次,只在每月最後一個交易日讀取。2015 年以來 23 次轉入 risk-off,8 次在月底前就回到 risk-on 而從未執行,其餘 15 次中位數延遲 6 個交易日、最長 14 個交易日;換股日處於 risk-off 的月份佔 13.6%。實際交易若改成每日檢查,結果會不同,本文沒有回測日頻版本。
- 權重:選股籃以反波動(1 ÷ NATR)加權、單一資產不另設上限;risk-on 時籃內權重加總為 1,risk-off 時改持 0050 佔 0.5、其餘現金。
- 周轉率:年換手約 10.0 次(選股集中 10 檔 + 月再平衡 + 風控切換),高於被動持有,成本敏感度較高,已在
sim()內扣手續費與證交稅下計算。 - 基準口徑:含息 0050 用
etl:adj_close還原價買進持有純算術計算,不含交易成本,從策略第一個淨值日 2015-02-26 起算;樣本外段兩者都從 2022 年第一個交易日起算。 - 樣本內外:研究段 2015-2021、樣本外 2022-01 至 2026-09 分開回報。參數在 2026 年 6 月定案,當時的篩選條件同時要求研究段與 2022 年以後的成績過門檻,所以 2022 年起這段嚴格來說是「選參數時看過的驗證段」;完全沒看過的資料只有 2026-06-09 之後的近四個月,結果見下面的新資料追蹤。
穩健度
檢查一套策略是否只靠某個參數湊出來,要同時看研究段與樣本外:
下面說的「過門檻」,指研究段年化 ≥ 25%、月夏普 ≥ 1.2,且樣本外年化 ≥ 15%、月夏普 ≥ 1.0,這是 2026 年 6 月定案時用的同一組標準。
- 三個選股因子與風控各自有貢獻:完整策略拿掉擠壓 %b,研究段月夏普 1.24 → 0.85;拿掉低波,研究段 1.24 → 1.05、樣本外 1.10 → 0.72;拿掉廣度風控,研究段月夏普反而升到 1.31,但全期最大回撤由 -33.4% 擴大到 -43.0%。少了任何一塊,至少有一項關鍵指標明顯變差。
- 研究段是一片高原,樣本外對動能窗敏感:固定其餘參數,一次只動一個(動能窗 60/80 日、選股 9/11 檔、risk-on 門檻 0.40/0.44、低波權重 0.30/0.40、EMA 8/12 日),10 個鄰格的研究段月夏普全部落在 1.09 到 1.31;但樣本外月夏普分散在 0.72 到 1.22,只有 6 格過門檻。最敏感的是動能窗:改成 60 日或 80 日,樣本外年化只剩 13.7% 與 14.2%、月夏普都掉到 0.72。70 日在樣本外是一個尖點,這是讀者實單前最該保留戒心的地方。
- 門檻微調沒有作用:risk-on 門檻改成 0.40 或 0.44,結果與 0.42 完全相同。廣度跨過門檻的日子會差幾天,但月底那天的狀態一樣,月頻讀取把這類微調抹平了。
- 逐年對照含息 0050:2015-2026 共 12 個年度區間中只有 4 個勝過 0050,全期的領先主要來自 2017 年(+57.7% 對 +18.1%)與 2021 年(+126.6% 對 +21.9%),詳見下方逐年表。
參數最佳化:找穩健高原,不挑單一孤峰
這套策略有兩個最值得檢查的參數:選股檔數(決定集中度)與大盤風控的 risk-on 廣度門檻(決定多早轉回進攻)。很多人最佳化的做法是把所有參數組合跑一遍,挑研究段績效最高的那一格上線,這是過度最佳化的典型陷阱:研究段最漂亮的單一峰值,往往是運氣湊出來的,換到樣本外就垮。比較穩當的做法是看色溫圖找「一片站得住的高原」。
我們對選股檔數(9/10/11/12)× risk-on 廣度門檻(0.38/0.42/0.46/0.50)做 4×4 網格,risk-off 門檻跟著移動、固定比 risk-on 低 0.15。每一格都用該設定重算選股籃與風控訊號、重跑回測,色溫填研究段月夏普:

研究段的結論是一片緩坡:16 格研究段月夏普落在 1.04 到 1.31,有 15 格在 1.10 以上,沒有突兀的孤峰。橫看選股檔數,9 檔那欄最高(1.20 到 1.31),檔數越多越低,12 檔那欄只剩 1.04 到 1.17;縱看門檻,0.42 那一列普遍最高,拉到 0.50 才明顯降溫。
把同一張網格換成看樣本外,分界就出現了:9 檔與 10 檔的 8 格樣本外月夏普全部在 1.01 到 1.16,11 檔與 12 檔的 8 格則有 6 格在 0.91 到 0.98,另 2 格剛好 1.00。換句話說,「選得越集中、成績越好」這個方向在研究段與樣本外一致,檔數放寬到 11 檔以上,樣本外月夏普最高只到 1.00。
本文預設取 10 檔、門檻 0.42/0.27:研究段月夏普 1.24、年化 28.9%,樣本外月夏普 1.10、年化 24.6%。更集中的 9 檔研究段更高(年化 31.8%、月夏普 1.31),但資料延長到 2026 年 9 月後,它的樣本外月夏普降到 1.01、年化 22.6%,掉得比 10 檔多;集中度越高,單一個月的個股風險也越大。10 檔配上較高的門檻 0.46 或 0.50,樣本外月夏普反而較高(1.16、1.15),研究段則降到 1.19、1.13,這是「研究段報酬」與「近年穩定度」之間的取捨,我們維持 6 月定案的參數,不因新資料改設定。如果你看到某個最佳化「換個參數 Sharpe 就從 0.8 跳到 1.8」,那通常是踩到過擬合的地雷,樣本外很可能打回原形。關於過擬合與參數穩健,延伸可看策略最佳化會不會過擬合。
不同大盤狀態下的表現:逐年攤開
判斷一套策略是不是只靠某一段行情湊出來,最直接的方法是把每一個年度單獨結算、和含息 0050 對照。下表的 0050 與策略從同一天起算(2015 年自 2 月 26 日起,2026 年截至 9 月 30 日):
| 年度 | 策略報酬 | 含息 0050 | 勝過 0050? |
|---|---|---|---|
| 2015(2/26 起) | +2.2% | -10.9% | 是 |
| 2016 | +6.7% | +19.6% | 否 |
| 2017 | +57.7% | +18.1% | 是 |
| 2018 | -9.3% | -4.9% | 否 |
| 2019 | +30.7% | +33.5% | 否 |
| 2020 | +22.7% | +31.1% | 否 |
| 2021 | +126.6% | +21.9% | 是 |
| 2022 | -27.2% | -21.4% | 否 |
| 2023 | +48.8% | +27.5% | 是 |
| 2024 | +47.1% | +48.6% | 否 |
| 2025 | +24.5% | +36.8% | 否 |
| 2026(截至 9/30) | +42.3% | +74.3% | 否 |
逐年看得出這套策略的個性:勝出的年份贏很多,落後的年份差距有大有小。2017、2021、2023 三年分別多賺 39.6、104.7、21.3 個百分點,是全期年化領先的主要來源;落後的 8 個年度裡,2019、2024 只差 3 個百分點以內,差距最大的是 2026 年到 9 月底(+42.3% 對 +74.3%),其次是 2016 與 2025。空頭年也擋不住:2018 年 -9.3%、2022 年 -27.2%,都比 0050 跌得更深,廣度風控能減碼,但月頻讀取躲不過連續下跌。整段只有 4 個年度勝過 0050,想買這套策略的人要有心理準備:大多數年份會覺得「不如直接買 0050」,長期領先靠的是少數幾個大年。
首發後的新資料:2026-06-09 之後
本文首發版的資料截至 2026-06-09,參數也在那時定案。從那天到 2026-09-30,策略下跌 4.4%,同期含息 0050 上漲 8.9%。分段拆開如下:
| 區間 | 策略 | 含息 0050 |
|---|---|---|
| 2026-06-09~06-30 | +7.9% | +4.2% |
| 2026 年 7 月 | -22.9% | -4.0% |
| 2026 年 8 月 | +8.5% | +3.3% |
| 2026 年 9 月 | +5.9% | +5.5% |
四段連乘就是上面的區間報酬,虧損集中在 7 月。6 月底選出的 10 檔持股在 7 月 1 日買進、8 月 3 日換股出場,10 檔全部虧損,逐檔報酬中位數 -16.9%,跌最深的同欣電(6271)-41.6%。同一個月 0050 只跌 4.0%,虧損來自策略持有的那一群強勢股同步回檔。策略淨值在 2026-07-02 創高,到 9 月底仍比高點低 15.0%。
這次虧損和風控的執行頻率直接相關。布林廣度(EMA10)在 7 月 17 日跌破 0.27、轉入 risk-off,但回測要等到 7 月 31 日的換股訊號、8 月 3 日收盤才把選股籃換成半倉 0050。從 7 月 16 日收盤到 8 月 3 日出場,策略淨值下跌 13.8%,同期 0050 跌 3.6%;7 月 30 日的低點離 7 月 16 日跌了 25.3%。之後廣度在 8 月 11 日就回到 0.42 以上,部位卻要到 9 月 1 日才換回選股籃。8 月的 +8.5% 主要來自 7 月 31 日到 8 月 3 日這一個交易日,7 月持股出場前反彈了 6.3%。研究段最差的單月是 2020 年 3 月的 -11.5%,樣本外在此之前最差的是 2022 年 9 月的 -13.7%;2026 年 7 月的 -22.9% 是研究段最差單月的兩倍、樣本外先前最差單月的 1.7 倍。
延長資料後,樣本外月夏普由 1.29 降到 1.10、年化由 27.8% 降到 24.6%,仍高於我們給這類策略設的 1.0 與 15% 門檻,因此本次屬於一般刷新:參數維持 2026 年 6 月的設定,數字全部換成新資料重跑的結果。下一次季度重跑會把 2026 年第四季補進這張表。
2026-10 更新與更正:資料延長到 2026-09-30,2026-10-12 重跑。以上一版的截止日 2026-06-09 重算,策略研究段 28.88%、樣本外 27.84%、全期 28.38% 與上一版完全相同,本次的差異全部來自新增的資料。另有五處更正:①上一版的含息 0050 從 2015-01-05 起算,但策略的第一個換股淨值日是 2015-02-26,0050 在這中間上漲 5.6%;本版改為同一天起算,以 2026-06-09 為截止日,0050 全期年化由 20.98% 變為 20.68%、研究段由 15.29% 變為 14.70%。②上一版寫「三段都勝過含息 0050」,但當時樣本外段 0050 年化 30.4% 已高於策略的 27.8%,那句話有誤。③上一版擠壓濾網段寫「研究段月夏普 0.57 提升到 0.77、樣本外 13.3%」,那組數字來自另一種組合(在擠壓且 %b > 0.8 的股票裡取 60 日動能最強 30 檔),與文中描述的測法不同,本版照文中描述重跑。④上一版寫可交易宇宙「排除 KY 股」,實際沒有排除;廣度對照圖疊的也是 6 月定案前舊版策略的淨值,本版都已改正。⑤上一版可下載的 strategy.py 宇宙條件少了均量門檻,印出的數字對不上文章;現在執行後會印出本文的三段績效、教科書用法對照、逐層的月夏普與回撤、逐年報酬,以及 7 月起的逐月報酬,數字與文中表格相同。
加上月營收 YoY 會更好嗎:基本面是選配,不在主策略內
本文的主策略是完全不含基本面的純技術策略:選股只用價格動能、布林擠壓 %b 與波動度,風控只用站上中軌的廣度,沒有任何財報或月營收輸入。這是刻意的設計:純技術訊號每日可得、無財報公布延遲與對齊問題,回測口徑乾淨、可重現性高。
常見的延伸問題是:在選股端疊一層月營收年增率(YoY)過濾,績效會不會更好?這是一個合理的研究方向,但屬於「在純技術主策略之外的選配實驗」,不納入本文主策略的數字。原因有二:其一,主策略選股只取 10 檔、集中度已高,再加營收過濾會縮小可選池,可能壓縮動能因子的選擇空間(本文未測);其二,月營收是領先指標、公布有時間落差,要正確對齊「當期(含)以前已公布」的資料才不會前視,這會把乾淨的純技術口徑複雜化。想實驗的讀者可在下載的程式碼裡,於綜合分計算前加一層 monthly_revenue 的 YoY 過濾自行對照。基本面與技術面如何分工,可延伸看技術面與基本面選股的差異與月營收動能選股策略。
三項穩健性驗證:重跑到 2026 年 10 月
這裡驗證本文的完整策略:70 日動能、擠壓狀態下的 %b、低 NATR 三個分位加總取最高 10 檔、反波動加權,股票池內站上布林中軌的比例轉空時改持半倉 0050,每月換股。我們在 2026-10-27 用本文附的 strategy.py(把 DATA_END 改成 None,finlab 2.2.20,資料截至 2026-10-27)重跑三項檢查,統一採 sim() 預設手續費 0.1425% 與證交稅 0.3%;原程式手續費三折的結果另列於成本對照表。「贏」指日夏普高於同期 0050 含息買進持有(etl:adj_close 還原價、純算術計算、不扣成本)。兩邊日夏普皆為日報酬平均除以標準差、乘上 √252,不扣無風險利率。
| 檢查 | 標準 | 結果 |
|---|---|---|
| 鄰近參數 | 布林週期(16、20、24)乘上持股檔數(8、10、12),9 組至少 7 組贏 | 0/9 組贏,不過 |
| 前後兩段 | 2015-01-30 到 2020-12-11、2020-12-14 到 2026-10-27 兩段都贏 | 前段 0.81 對 0.89,後段 1.28 對 1.24,不過 |
| 交易成本 | 原參數、sim() 預設成本 |
日夏普 1.07 對 1.08,不過 |

9 組參數的日夏普(括號內是年化報酬,粗體是原文參數):
| 持股檔數 \ 布林週期 | 16 | 20 | 24 |
|---|---|---|---|
| 12 | 0.93(年化 20.1%) | 0.91(年化 19.6%) | 0.78(年化 15.7%) |
| 10 | 0.85(年化 18.5%) | 1.07(年化 24.8%) | 0.88(年化 18.9%) |
| 8 | 0.86(年化 19.5%) | 0.99(年化 23.3%) | 0.93(年化 20.6%) |
前後兩段與全期:
| 期間 | 策略年化 | 策略日夏普 | 0050 含息年化 | 0050 日夏普 |
|---|---|---|---|---|
| 前段 2015-01-30 到 2020-12-11 | 14.5% | 0.81 | 13.5% | 0.89 |
| 後段 2020-12-14 到 2026-10-27 | 35.7% | 1.28 | 28.0% | 1.24 |
| 全期 2015-01-30 到 2026-10-27 | 24.8% | 1.07 | 20.5% | 1.08 |
前後兩段是把整段期間從中點對半切。上文的研究段與樣本外以 2022 年初為界,照這個切法,2015 到 2021 年日夏普 1.27 對 0050 的 0.96,2022 年起 0.89 對 1.22。上文多用月夏普,跟這裡的日夏普算法不同,數字不能直接比。
交易成本對照(原參數):
| 成本設定 | 年化 | 日夏普 | 最大回撤 |
|---|---|---|---|
| 不扣成本 | 32.5% | 1.34 | -31.8% |
sim() 預設:手續費 0.1425%、證交稅 0.3% |
24.8% | 1.07 | -34.7% |
| 原文設定:手續費打三折 | 27.4% | 1.16 | -33.4% |
| 0050 含息買進持有(同期) | 20.5% | 1.08 | -34.0% |
重跑到 2026-10-27,原參數年化 24.8%、日夏普 1.07、最大回撤 -34.7%;同期 0050 含息年化 20.5%、日夏普 1.08,只差 0.01,但還是輸。照原文手續費三折是日夏普 1.16,贏 0050:原參數這一格的輸贏取決於手續費有沒有打折。9 組鄰近參數全部輸,原參數剛好是 9 組裡最好的一格,布林週期或持股檔數往任一方向挪,日夏普就掉到 0.78 到 0.99。前段(2015 到 2020 年)日夏普 0.81 輸 0050 的 0.89,後段 1.28 小贏 1.24;照上文以 2022 年切開則相反,2015 到 2021 年 1.27 贏 0.96,2022 年起 0.89 輸 1.22,跟上文「2022 年起年化 24.6% 落後 0050」一致,前後段的輸贏取決於 2021 年落在哪一段。三項都不成立。上文的參數高原看的是研究段月夏普、持股檔數乘廣度門檻;這裡換成全期日夏普、布林週期乘持股檔數,原參數這一格明顯高於四周。上文的年化 27.0% 從 2015-02-26 起算、資料到 2026-09-30;這裡從第一次換股的 2015-01-30 起算,手續費三折跑到 2026-10-27 是 27.4%,換成 sim() 預設成本是 24.8%。
策略的限制與取捨
- 集中度帶來較高波動:策略只持 10 檔,全期最大回撤 -33.4% 與含息 0050 的 -34.0% 相當,但年化波動 23.8% 高於 0050 的 19.8%,單一月份可能虧兩成以上(2026 年 7 月 -22.9%)。承受得住這級波動才適合。
- 風控是月頻,月中急跌擋不住:廣度風控只在每月換股日讀取。2026 年 7 月廣度在 7/17 就轉弱,部位到 8/3 才減碼,這段期間淨值再跌 13.8%。實際操作若改成每日檢查,報酬與回撤都會不同,本文沒有回測那個版本。
- 近年落後 0050:樣本外(2022 年起)年化 24.6%,落後 0050 的 30.5%;12 個年度區間只有 4 個勝過 0050,2026 年到 9 月底策略 +42.3%、0050 +74.3%。
- 對動能窗敏感:動能窗由 70 日改成 60 或 80 日,樣本外月夏普都從 1.10 掉到 0.72。參數是在看過 2022 年後資料的情況下定案的,未來表現可能比本文樣本外段更差。
- 高周轉、成本敏感:年換手約 10.0 次,明顯高於被動持有,報酬已在
sim()內扣手續費與證交稅後計算,但實單滑價會進一步侵蝕,資金規模越大越明顯。 - 容量與崩盤型態:選股僅 10 檔、宇宙限前 300 大,大資金部署需重估流動性衝擊;資料起點 2015,未對更早期(2008/2011)的崩盤型態做滾動測試,不保證對沒見過的型態同樣有效。
用布林通道最常犯的四個錯誤
- 把「觸下軌」當無腦抄底訊號。 低 %b 同時可能是健康回檔或趨勢轉空的起點,布林通道本身分不出來。台積電那張示意圖裡,下軌附近的買點有些確實反彈、有些則是繼續破底;攤到整個股票池,觸下軌買進研究段年化只有 2.5%,樣本外回到 17.9% 也仍大幅落後 0050。下軌是「波動參考線」,不保證反彈。
- 在多頭趨勢裡用「站上上軌就賣」。 強勢股會「沿著上軌走」很久,聯發科那段 12 個月就觸發了 14 次上軌賣出訊號,每一次照做都等於把上漲部位提早砍掉、賣在起漲點。趨勢盤裡,貼上軌是強勢的證據。
- 只看研究段挑參數。 本文策略的研究段在 9 到 12 檔、門檻 0.38 到 0.50 之間是一片緩坡,看起來怎麼選都行;但同一批參數換成看樣本外,11 檔以上多數掉到 1.0 以下,動能窗改 10 天月夏普就從 1.10 掉到 0.72。挑參數時兩段都要看,研究段的高原不代表樣本外也是高原。
- 把布林通道和 KD、RSI 疊在一起用。 這些都是從同一條價格序列算出來的擺盪/波動類指標,資訊高度重疊,疊在一起很難增加新資訊(本文沒有回測這個組合)。本文的做法是搭「不同性質」的訊號:用動能因子選股、用布林廣度控風險,各司其職。各指標的分工可參考RSI、MACD、KD 比較。
這四個錯誤有一條共同主線:把一個衡量波動的指標當成抓買賣點的工具。 記住布林通道的本質是「衡量波動」,就會自然把它放到選股濾網與風控的位置,而不會拿它當進出場依據。
自己跑一次
把下面這句話交給你的 AI 助理,它會引導你安裝 FinLab Skill、抓台股資料、重現這篇的回測:
裝好之後,下載本文的 strategy.py 與 data.csv,即可在自己的環境重跑、改參數、換選股因子。strategy.py 把資料截止日釘在 2026-09-30,執行後印出本文的三段績效、教科書用法對照、逐層的月夏普與回撤、逐年報酬,以及 6 月 9 日之後的區間與逐月報酬;把 DATA_END 改成 None 就會用最新資料重跑。登入只需在程式裡寫 finlab.login(),套件會在需要資料時引導你完成登入。想延伸成更完整的量化流程,可參考量化交易總覽與程式交易是什麼。想看 RSI、KD、乖離率等指標的同款回測,可讀技術指標怎麼用才對的總覽與乖離率台股回測。
常見問題
Q:布林通道參數要設多少?20 日、2 個標準差是最好的嗎? 20 日、±2 標準差是 John Bollinger 的原始建議,也是本文用的設定。標準差倍數 k 對本文策略完全沒有影響:%b 的排序、擠壓的判斷和站上中軌的廣度,數學上都與 k 無關(推導見定義一節)。會影響結果的是週期 n,本文沒有對 n 做網格測試,只用預設的 20 日。
Q:布林通道「觸下軌一定會反彈」嗎? 不一定。觸下軌(低 %b)的股票籃在台股研究段年化只有 2.5%,因為它無法區分「健康回檔」與「趨勢轉空」;2022 年後年化 17.9%,仍大幅落後 0050 的 30.5%。把它當無腦抄底訊號,長期接近無效。
Q:布林通道可以單獨拿來當買賣訊號嗎? 不建議。觸下軌買、觸上軌賣或無條件的 %b 排名選股,在台股回測都站不住;只在擠壓股裡看 %b,研究段有改善,但樣本外沒有延續。要讓 %b 變得有用,得把它和動能、低波一起放進綜合分;站上中軌的廣度則拿來當大盤風控。布林通道適合拆成這兩個零件搭配使用。
Q:布林通道和肯特納通道(Keltner Channel)差在哪? 布林通道用標準差定義通道寬度(隨波動呼吸),肯特納通道用 ATR(平均真實波幅)。兩者都是波動通道,實務上常被一起比較,延伸可看肯特納通道與 ATR 指標。
Q:這套策略適合誰? 適合想要主動選股、能接受 -33% 等級回撤與月虧兩成的單月波動、也能忍受多數年份跑輸 0050 的人:全期年化 27.0%、月夏普 1.13,勝過含息 0050 的 21.0%、1.06,但 2022 年起年化落後 0050 約 6 個百分點。不適合受不了深度回撤、或偏好低周轉被動持有的人,那種需求直接買進持有含息 0050 更省心。
Q:為什麼要用「廣度」而不是只看大盤指數? 單一指數的中軌穿越在盤整期雜訊太大、來回甩巴掌;股票池內的廣度是橫截面的多空力道度量,加上 EMA 與雙門檻,在本文回測中把全期最大回撤由 -43.0% 收斂到 -33.4%。限制是它只在每月換股日讀取,月中急跌要等到月底才減碼。
最後更新:2026-10|回測區間:2015-02-26 ~ 2026-09-30(2026-10-12 重跑)|作者:FinLab 量化研究團隊(經量化研究員審閱)
本文僅供量化研究與教學用途,所有回測數字均由 finlab 套件在真實台股資料上產出,過去績效不代表未來表現,不構成投資建議。布林雙核心純技術策略全期最大回撤 -33.4%、2026 年 7 月單月 -22.9%,實際交易前請自行評估風險、滑價與交易容量。
FinLab AI
想建立自己的策略?
用自然語言描述你的選股想法,AI 自動驗證、回測、給你答案
免費開始

