本文目錄
回測績效曲線漂亮到像印鈔機,一上實盤卻完全不是那麼回事——這是許多人在做 Python 交易策略 時共同的困惑。很多人在網路上抓一段程式碼,跑出亮眼的回測結果就急著投入真金白銀,卻忽略了回測與實盤之間存在一道巨大的鴻溝。這篇文章不談「我賺了多少」,而是提供一套可執行的 Python 交易策略驗證框架,從資料處理、回測程式碼、樣本外驗證到模擬倉與小部位實盤,帶你一步步拆解策略到底能不能用。
免責聲明:本文所有數字均為「假設情境/示範用途,非真實交易結果」。實際績效會因市場條件、資料來源、參數設定與交易成本而異。本文僅供程式教學與研究,不構成任何個股投資建議。
Python 交易策略回測第一步:資料品質決定回測的可信度
做回測前,最大的坑往往不是策略邏輯,而是資料品質。常見的錯誤是:從免費 API 抓到的日 K 線裡有缺值,程式直接補前一天收盤價,導致回測出來的最大回撤被嚴重低估。這種資料問題不會報錯,但會讓你的回測結果完全失真。
建議用以下三個步驟檢查資料:
1. 資料來源:台股可用證交所公開資訊觀測站的原始資料,或付費訂閱如 TEJ、CMoney 的資料庫,至少確保股價有做除權息還原。
2. 缺值檢查:用 pandas 檢查缺失與重複,不要無腦 ffill()。
3. 交易成本設定:台股手續費為 0.1425%(多數券商有折扣),證交稅 0.3%,來回一趟約吃掉 0.5% 左右的報酬。若策略平均每次進出賺不到 1%,交易成本會把獲利吃光。滑點建議抓 0.1%~0.2% 作為保守估計。
以下是一段可獨立執行的資料品質檢查範例:
import pandas as pd
import numpy as np
假設 df 是你從 API 抓下來的日K,index 為日期,含 'close' 欄位
這裡用隨機資料示範,實際使用請替換為你的資料來源
np.random.seed(0)
dates = pd.date_range("2019-01-01", "2026-12-31″, freq="B")
df = pd.DataFrame({"close": np.random.uniform(100, 200, size=len(dates))}, index=dates)
1. 檢查缺值
missing = df["close"].isna().sum()
print(f"缺值筆數:{missing}")
2. 檢查是否為交易日(與台股行事曆比對,示範用工作日近似)
expected_days = pd.bdate_range(df.index.min(), df.index.max())
missing_days = expected_days.difference(df.index)
print(f"缺少的交易日數:{len(missing_days)}")
3. 檢查極端跳動(單日漲跌超過 10% 在台股多為異常)
pct = df["close"].pct_change()
outliers = pct[pct.abs() > 0.10]
print(f"單日漲跌超過 10% 的筆數:{len(outliers)}")
提醒:缺值直接
ffill()是回測常見的錯誤。若真的需要填補,建議先確認缺值原因(停牌?資料漏抓?),並在回測報告中揭露填補比例。
台股 Python 策略範例:均線突破策略的程式碼骨架
講理論太空泛,直接給你一段可執行的策略骨架。以下示範「20 日均線突破進場 + 5 日均線出場」策略,使用 backtrader 撰寫。請注意,這裡的邏輯是教學示範,不是投資建議。
需先安裝:pip install backtrader pandas
import backtrader as bt
import pandas as pd
import numpy as np
class MA_Cross_Strategy(bt.Strategy):
params = (
("entry_ma", 20), # 進場均線
("exit_ma", 5), # 出場均線
("hold_days", 15), # 最長持有天數
("risk_pct", 0.02), # 單筆風險佔總資金比例
)
def __init__(self):
self.entry_line = bt.indicators.SMA(self.data.close, period=self.p.entry_ma)
self.exit_line = bt.indicators.SMA(self.data.close, period=self.p.exit_ma)
self.bar_count = 0
def next(self):
if not self.position:
# 進場:收盤價站上 entry_ma,且前一根 K 棒尚未站上
if (self.data.close[0] > self.entry_line[0]
and self.data.close[-1] <= self.entry_line[-1]):
size = int(self.broker.getcash() * self.p.risk_pct / self.data.close[0])
if size > 0:
self.buy(size=size)
self.bar_count = 0
else:
self.bar_count += 1
# 出場:跌破 exit_ma,或持有滿 hold_days
if (self.data.close[0] < self.exit_line[0]
or self.bar_count >= self.p.hold_days):
self.close()
if __name__ == "__main__":
cerebro = bt.Cerebro()
cerebro.addstrategy(MA_Cross_Strategy)
# 讀入你的 OHLCV 資料(示範用隨機資料,實際請替換)
np.random.seed(1)
dates = pd.date_range("2019-01-01", "2026-12-31″, freq="B")
price = 100 + np.cumsum(np.random.normal(0, 1, len(dates)))
demo = pd.DataFrame({
"open": price, "high": price * 1.01,
"low": price * 0.99, "close": price,
"volume": np.random.randint(1000, 5000, len(dates)),
}, index=dates)
data = bt.feeds.PandasData(dataname=demo)
cerebro.adddata(data)
cerebro.broker.setcash(1_000_000)
cerebro.broker.setcommission(commission=0.001425) # 台股手續費
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name="sharpe")
cerebro.addanalyzer(bt.analyzers.DrawDown, _name="dd")
results = cerebro.run()
strat = results[0]
print("期末資產:", cerebro.broker.getvalue())
print("Sharpe:", strat.analyzers.sharpe.get_analysis())
print("最大回撤:", strat.analyzers.dd.get_analysis())
關於回測框架的選擇:backtrader 上手容易、社群資源多;vectorbt 主打向量化運算,適合大量參數掃描。兩者定位不同,建議先確認自己的需求再選。至於網路上常見的「某某框架快幾十倍」效能宣稱,由於測試環境、資料量與硬體規格差異極大,讀者若要比較,請務必自行在相同條件下實測,不要直接採信。
關於 TradingView 與 Pine Script:Pine Script 與 Python 語法完全不同,無法自動轉換,需要人工將策略邏輯重新改寫成 Pine Script 語法。它的價值在於把訊號視覺化到圖表上做交叉確認,而不是「一鍵轉換」。若你需要這類視覺化工具,可參考 TradingView。
交易策略績效驗證:3 個關鍵指標比單看報酬率更重要
光看年化報酬率是不夠的。以下三個指標缺一不可,且都建議用假設情境理解,而非拿別人的數字當標準:
1. 夏普比率(Sharpe Ratio)
衡量每承擔一單位風險能換到多少報酬。常見的經驗法則是:低於 1 通常不值得實盤,1~2 之間算可接受,超過 2 已經相當優秀——但同時也要懷疑是否過度擬合。這是通則,不是保證。
2. 最大回撤(Max Drawdown)
這是決定你能不能「撐住」策略的關鍵。常見的錯誤是只看報酬曲線往上衝,卻忽略中間有一段連續虧損 20% 的區間。捫心自問:如果帳戶真的跌了 20%,你還敢照著策略執行嗎?業界常見的風控原則是把最大回撤控制在 25% 以內,超過就要重新檢視部位大小。
3. 蒙地卡羅模擬(Monte Carlo Simulation)
單一次回測結果有很大的隨機成分。做法是把交易順序打亂重跑多次,觀察報酬分佈的 5% 分位數(最壞情況)與中位數的差距。若差距過大,代表策略對交易順序很敏感,穩定性存疑。
以下是一段可執行的蒙地卡羅示範:
import numpy as np
假設 trades 是每筆交易的報酬率序列(示範用隨機資料)
np.random.seed(42)
trades = np.random.normal(0.005, 0.03, size=100)
n_sim = 1000
final_returns = []
for _ in range(n_sim):
shuffled = np.random.permutation(trades)
final_returns.append(np.prod(1 + shuffled) – 1)
final_returns = np.array(final_returns)
print(f"中位數報酬:{np.median(final_returns):.2%}")
print(f"5% 分位數(最壞情況):{np.percentile(final_returns, 5):.2%}")
樣本外測試(Out-of-sample Testing):務必把資料切成「樣本內(優化參數用)」與「樣本外(驗證用)」兩段,時間不可重疊。例如用 2019~2022 優化,用 2023~2026 驗證,中間不保留重疊區間。若樣本外績效衰退超過 30%,這組參數大概率是過度擬合。
Python 策略回測轉實盤流程:3 個常見地雷與防範
以下三個地雷是量化交易社團裡最常被討論的錯誤類型,不是「我親自踩過」的個人經歷,而是通用提醒。
地雷一:未來函數(Look-ahead Bias)
新手最容易犯、也最致命的錯誤。例如用「當日收盤價」判斷進場訊號,但收盤價要等收盤才知道,你不可能用當天收盤價在當天下單。這會讓回測績效虛高。
防範建議:訊號判斷用「前一根 K 棒」的資料,並明確設定「隔日開盤價」進出場,符合實際交易時序。
地雷二:過度優化參數(Overfitting)
把均線天數、出場條件、停損點位一路調整到回測報酬最大化,這組參數往往只是完美貼合過去那段資料,換一段時間測試績效就會大幅衰退。
防範建議:參數數量控制在 3 個以內,並做樣本外測試與滾動窗口測試(Walk-forward Analysis)。若同一組參數在不同時間區間表現差異懸殊,代表不可靠。
地雷三:忽略流動性與市場衝擊成本
有些中小型股回測績效看起來很穩定,但日均成交量可能只有數百張。若你真的下單數十張,光是自己的買單就會推高價格,回測系統完全沒考慮這種市場衝擊成本。
防範建議:篩選標的時設定「日均成交量」門檻(例如 2000 張以上),並用實際委託單簿深度確認流動性,資金部位放大後更要留意。
除了這三個地雷,轉實盤前建議先用「模擬倉」跑一段時間(常見做法是 1~3 個月),觀察程式下單與風控機制是否正常,再決定是否投入真實資金。這階段可用 TradingView 做圖表視覺化與訊號交叉驗證——但請記得,Pine Script 需要手動改寫,不是自動轉換。
量化交易策略勝率評估:期望值才是核心
很多人被「勝率」迷惑,覺得勝率越高策略越強,其實這是誤解。真正該看的是期望值:
期望值 = (勝率 × 平均獲利) − (敗率 × 平均虧損)
假設範例:假設某策略勝率 47%、平均獲利 3.2%、平均虧損 1.8%,則:
(47% × 3.2%) − (53% × 1.8%) = 1.504% − 0.954% = +0.55%
也就是說,這個策略每次交易的期望報酬是 +0.55%。雖然勝率不到五成,但長期執行下來仍有正期望值。這只是示範計算方式,不是任何真實策略的績效。
另外也要看「連續虧損次數」,這直接影響心理承受度與資金控管。常見的部位控管原則是:單筆交易風險不超過總資金的 2%,這樣即使連續虧損 10 次,帳戶也只會縮水約 20%,還有翻身機會。
常見問題 FAQ
Python 交易策略回測與實盤績效落差通常會有多大?
這取決於策略類型、交易頻率與市場環境,沒有通用數字。常見的落差來源包括:交易成本、滑點、未來函數、以及市場流動性變化。若你的策略落差明顯偏大,建議先檢查是否有過度優化或未來函數問題。
新手學 Python 交易策略需要多強的程式基礎?
不需要工程師等級。會基本 Python 語法(迴圈、條件判斷、函式)加上會用 pandas 處理資料就可以開始。從其他語言(如 Excel VBA)轉過來的人,通常數個月密集學習就能寫出簡單的均線策略回測。
回測資料要抓多長的時間才夠?
建議至少涵蓋一次完整的多頭與空頭循環。台股一般建議抓 7~10 年,這樣才能測試策略在不同市場環境下的表現,避免只在單一牛市行情下測出漂亮數字卻經不起空頭考驗。
做完回測後,多久可以正式轉實盤?
常見做法是:先跑一段時間模擬倉,確認下單邏輯與風控機制正常後,再用小部位(例如總資金的 5%~10%)實盤測試,觀察真實滑點與心理壓力承受度,最後才逐步加碼。整個流程通常需要數個月才會比較踏實。
結論:策略能不能用,靠的是驗證框架而非感覺
Python 交易策略驗證這條路沒有捷徑。唯一能確認策略是否站得住腳的方法,就是紮實走過「回測 → 樣本外驗證 → 模擬倉 → 小部位實盤」這四個階段,每一步都用數字說話,而不是憑感覺或一廂情願地相信回測曲線。
本文提供的程式碼骨架與檢查清單都可以直接照抄執行,請自行替換資料來源與參數。再次提醒:本文所有數字均為示範用途,非真實交易結果,也不構成任何個股投資建議。
如果你想開始動手驗證自己的策略,建議先從圖表訊號視覺化做起。可參考 TradingView 的視覺化工具,並手動將 Python 邏輯改寫成 Pine Script 語法做交叉確認——動手做,才是檢驗策略最誠實的方式。
外部參考來源: