[量化實戰] 我如何把一支虧損程式,改造成 10 年大賺的策略?(打破「拉回買進」的迷思)
前言:
你是不是也聽過這句投資金句:「人棄我取,拉回就是買點」?
我曾經也是這麼想的。為了實踐這個真理,我寫了一支 Python 程式專挑「便宜貨」。
結果?在台股近年的大牛市裡,它竟然績效慘輸大盤。
這篇文章記錄了我如何修正邏輯錯誤、計入真實交易成本,最終驗證出 「動能策略 (Momentum)」 才是台股獲利關鍵的完整過程。
一、 慘痛的起點:想撿便宜,卻撿到破爛
一開始,我的策略邏輯非常「散戶直覺」,我想要買在「相對低點」:
- 便宜才買: 等 RSI < 45(相對弱勢區)才進場。
- 安全第一: 股價跌破 20日均線(月線) 才接。
我以為我在等百貨公司週年慶打折,結果回測數據狠狠打了我的臉。
📉 失敗的績效表 (2023-2025 AI 牛市)
| 策略版本 | 表現 | 評語 |
|---|---|---|
| 0050 (大盤) | 大漲 | 隨便買都賺 |
| 我的撿便宜策略 | 虧損 / 小賺 | 大盤漲我不漲,大盤跌我跟著跌 |
💡 為什麼會失敗?
我看著數據才發現一個殘酷真相:真正的飆股(如台積電、緯創),在主升段時 RSI 根本不會掉到 45 以下。
我的程式一直在等「回檔」,結果只撿到了那些「真的出問題」的弱勢股。
二、 觀念翻轉:加入「瘋狗流」 (Momentum)
我不甘心。我去翻了學術論文和 FinLab 的研究,發現台股有一個特性:「強者恆強」。
於是我做了一個瘋狂的決定:把邏輯 180 度反過來。
💻 關鍵程式碼修改
我把「拉回買」的程式碼刪掉,改成「追高買」。請看這段關鍵的 Python 修改:
# ❌ 舊邏輯:想買便宜 (失敗)
# cond_weak = rsi_14 < 45 # 等待相對弱勢回檔
# ✅ 新邏輯:瘋狗流動能 (成功)
# 1. 營收要好 (基本面保護)
# 修正:確保使用月資料計算 YoY,並 Lag 45天避免未來視
rev_yoy = (monthly_revenue / monthly_revenue.shift(12)) - 1.0
cond_fund = rev_yoy.shift(2) > 0.25 # 確保數據已公告
# 2. 股價要創新高 (確認趨勢)
# 修正:不看月線,改看季線等級的創高
cond_strong = price >= price.rolling(60).max()
# 3. RSI 要強勢 (確認人氣)
cond_momentum = rsi_14 > 55 # 追逐動能強勢股!
這個改動違反了所有直覺:「這不是追高嗎?」
沒錯,這就叫動能交易。我把它丟進去跑了 10 年長週期回測 (2015-2025)。
三、 真實回測:加入成本後的真相
為了不讓自己被「快樂表」騙了,我在回測中加入了真實世界的摩擦成本。這點非常重要,因為頻繁換股會吃掉大量獲利。
- 交易成本設定: 單趟完整交易成本約 0.585%。
- 買進手續費:0.1425%
- 賣出手續費:0.1425% + 證交稅 0.3%
- 策略換股頻率: 每月檢查一次訊號 (Strategy Rotation)。
- 數據來源: 使用還原股價 (Adjusted Close),包含股息再投入。
📊 10 年回測總體檢 (2015-2025)

| 比較項目 | 0050 (含息總報酬) | 新策略 (純粹動能) | 結果 |
|---|---|---|---|
| 總報酬率 | 約 350%~400% | 約 600% 🚀 | 勝 |
| 獲利來源 | 權值股 (台積電) | 中小型飆股 (國巨/緯創) | 抓到黑天鵝 |
我發現,這套策略抓到了 2018 年的被動元件狂潮,和 2023 年的 AI 狂潮。它不預測高點,它只是黏著趨勢走。
四、 光鮮亮麗背後的代價:-56% 的回撤
但在你決定 All-in 之前,請先看這張「死亡清單」。
量化交易最誠實的地方,就是它會告訴你「最痛會有多痛」。
⚠️ 歷史壓力測試 (Stress Test)
| 年份 | 事件 | 0050 跌幅 | 本策略跌幅 | 你的帳戶 (1000萬) |
|---|---|---|---|---|
| 2022 | 美國暴力升息 | -21% (加權指數) | -40% | 剩 600 萬 |
| 2018Q4 | 貿易戰 | -15% | -35% | 剩 650 萬 |
| 最大回撤 | 歷史極值 | 約 -30% | -56.8% 💀 | 剩 430 萬 |
💡 補充說明:為什麼空頭跌這麼慘?
動能策略在空頭市場的表現符合學術研究預期。根據《東吳會計學報》的研究指出:
「在空頭市場,不管採用何種策略投資者都會損失,動能策略的優勢在於多頭時能獲取更高獲利。」
簡單來說,這個策略的虧損是「正常特性」而非 Bug,因此我們必須搭配資產配置來降低風險。
問問你自己: 當你的 1000 萬變成 430 萬的時候,你還敢讓程式繼續跑嗎?
99% 的人會在這時候停用程式,倒在黎明前。
五、 最終解法:核心衛星配置 (Core-Satellite)
為了讓這套策略從「理論」變成「實戰」,我使用了法人級的「資產配置」技巧。我把資金分成兩份,並設定「季度再平衡 (Rebalance)」機制,避免過度交易。
- 70% 資金 (核心): 買 0050 (保命用,承受較低波動)。
- 30% 資金 (衛星): 跑這套 動能策略 (衝績效用)。
🏆 季度再平衡規則
我們不頻繁調整,而是每季(3、6、9、12月底)檢查一次:
- 觸發條件: 當實際配置偏離目標 ±5% 時才調整。
- 調整方式: 賣出超配的動能股,買入落後的 0050,強制「高割離席」。
💰 投資組合最終績效

| 投資方式 | 總報酬率 | 最大回撤 (風險) | 性價比 (CP值) |
|---|---|---|---|
| 100% 買 0050 | 基準 | -30% | 普通 |
| 100% 動能策略 | 最高 | -57% (太危險) | 高風險高報酬 |
| 70% 0050 + 30% 動能 | 優於 0050 👑 | -36% (可接受) | 最高! |
✨ 結論: 透過配置,我們用「稍微多一點點的風險(-30% -> -36%)」,換取了顯著優於大盤的超額報酬,這就是資產配置的魔法。
六、 附錄:完整 Python 策略代碼 (選股邏輯)
如果你也想在自己的電腦上運行這套策略,這是核心選股邏輯的程式碼片段:
import pandas as pd
import numpy as np
# === 重要提醒 ===
# 1. calculate_rsi() 函數需自行實作或使用 TA-Lib
# 2. 月營收資料 (monthly_rev_df) 需要從 TEJ 或 FinLab 等資料庫取得
# 3. 此處僅為選股邏輯,完整回測需包含資金管理、滑價計算等框架
# ================
def strategy_logic(price_df, monthly_rev_df):
"""
price_df: 日頻率股價
monthly_rev_df: 月頻率營收
"""
# 1. 處理營收資料 (月頻率)
# 修正:shift(12) 針對月資料,代表與去年同期比較
rev_yoy = (monthly_rev_df / monthly_rev_df.shift(12)) - 1.0
# 修正:將月資料對齊回日資料,並 Lag 45天避免未來視
rev_yoy_daily = rev_yoy.reindex(price_df.index, method='ffill').shift(45)
# 2. 定義技術指標
# 修正:創 60 日新高 (季線等級強勢)
is_breakout = price_df >= price_df.rolling(60).max()
# RSI 指標 (需自定義函數)
rsi = calculate_rsi(price_df, 14)
# === 選股條件 ===
cond_fund = rev_yoy_daily > 0.25 # 基本面火藥
cond_strong = is_breakout # 點火
cond_momentum = rsi > 55 # 助燃 (強勢動能)
buy_signal = cond_fund & cond_strong & cond_momentum
# === 排名機制 ===
# 只買最強的 Top 5 (RSI 越高越好)
rank = rsi.where(buy_signal).rank(axis=1, ascending=False)
return rank <= 5