研究方法 回測引擎

第 2 章

回測引擎

我們的回測引擎由團隊自行開發,採用事件驅動架構。引擎完全按照現實中的情況模擬交易決策——每次只處理一根 K 線,絕不使用未來的資訊。

1. 事件驅動架構

引擎的核心設計原則,是策略只能看到當前 K 線及更早的數據,永遠無法看到未來的 K 線。這是由系統架構強制保證的,而非僅靠制度規範。策略程式碼在物理層面上不可能讀取前瞻數據。

處理迴圈(每根 K 線)

數據輸入

OHLCV K 線到達

指標引擎

重新計算指標

策略邏輯

評估入場/出場規則

訂單生成

建立待處理訂單

訂單執行

於下一根 K 線開盤價成交

組合更新

損益、權益曲線

按序處理

每根 K 線按時間順序逐一處理。引擎設有嚴格的游標——可讀取第 T 根及之前的所有 K 線,但第 T+1 根此時尚不存在。

結果可重現

只要數據檔案和策略參數相同,引擎每次都會得出完全一致的結果。沒有隨機性,各次運行之間也沒有浮點數誤差。

多資產支援

引擎可同時對多個標的運行策略,並遵守投資組合層面的資金限制,同時考慮跨資產相關性。

2. 信號生成

交易信號是將指標函數應用於價格序列而生成。第 T 根 K 線的所有指標值,僅使用第 T 根 K 線當時可得的數據計算,即從第 0 根至第 T 根(含)的價格。信號隨後於第 T+1 根 K 線的開盤價執行。

# 簡化的偽代碼——說明如何禁止前瞻 for T in range(warmup_period, len(bars)): current_bar = bars[T] # 只能看到這根 K 線的 OHLCV history = bars[:T+1] # 截至並包括 T 的所有 K 線 # 指標只基於 [0..T] 計算——無法存取未來的 K 線 sma_fast = mean(history.close[-20:]) sma_slow = mean(history.close[-50:]) rsi = rsi_func(history.close, period=14) # 信號出現在第 T 根 → 於第 T+1 根開盤時執行(下一次函數調用) if sma_fast > sma_slow and rsi < 70: queue_order(side='BUY', qty=position_size(), exec_bar=T+1)

支援的指標類型

  • ▸ 移動平均線(SMA、EMA、WMA、DEMA、TEMA、KAMA)
  • ▸ 動量指標(RSI、MACD、Stochastic、CCI、ROC)
  • ▸ 波動率指標(ATR、Bollinger Bands、Keltner Channels、HV)
  • ▸ 成交量指標(OBV、CMF、VWAP、Volume Profile)
  • ▸ 趨勢指標(ADX、Parabolic SAR、Ichimoku Cloud)
  • ▸ 震盪指標(Williams %R、Ultimate Oscillator、MFI)
  • ▸ 統計指標(Z-score、線性迴歸斜率、相關係數)
  • ▸ 自訂複合指標(按策略而定)

信號類型

  • ▸ 做多入場/做空入場
  • ▸ 做多出場/做空出場(明確指定)
  • ▸ 止損觸發(按價格或 ATR 倍數)
  • ▸ 止盈觸發(固定目標或追蹤式)
  • ▸ 加倉/減倉(金字塔式入場)
  • ▸ 按時間出場(固定持倉期)
  • ▸ 市況過濾(市場環境閘門)
  • ▸ 按風險出場(組合回撤門檻)

3. 成交模型

成交模型決定訂單如何成交。我們刻意採用保守假設,使結果略為低估真實表現。與其失望,不如有意外之喜。

成交參數

成交價
下一根 K 線開盤價(T+1 開盤) 避免不切實際的同一根 K 線成交
滑價
每宗交易 0.05%(預設) 對流動性充足的股票作保守估計
佣金——香港
來回 0.10% 香港零售經紀的一般收費水平
佣金——美國
來回 0.05% 美國經紀的一般收費水平
佣金——日本/歐洲
來回 0.15% 反映當地較高的成本
最小交易單位
按各交易所規定執行 不可買賣碎股
沽空
於歷史上允許沽空的情況下方可進行 套用交易所的上升報價規則
借貨成本
年化 0.5%–5%(視策略而定) 適用於沽空倉位

為何採用下一根 K 線開盤價?

大多數零售回測工具容許在產生信號的同一根 K 線上成交——這在現實中是不可能的。若均線交叉發生在第 T 根 K 線收市時,你無法以第 T 根的收市價交易,因為信號要到該 K 線收市後才能得知。

我們的規則: 信號於第 T 根 K 線收市時出現 → 訂單排隊 → 於第 T+1 根 K 線開盤時成交。這是現實中最早可執行的時間。
我們絕不會做的事: 以第 T 根 K 線的收市價、最高價或最低價成交。這些價格要到 K 線收市後才能得知——實時交易中無法以這些價格成交。

4. 倉位規模模型

倉位規模決定每宗交易分配多少資金。報告所採用的倉位模型一律在報告開首披露。不同策略會按其風險特徵採用不同的模型。

固定比例(佔權益百分比)

最常見

最廣泛使用的模型。每宗交易承擔的風險為當前帳戶權益的固定百分比。帳戶增長時,倉位按比例增大;帳戶縮減時,倉位隨之縮小。

# 公式
倉位規模 = 帳戶權益 × 風險% ÷ (入場價 – 止損價)
# 示例
帳戶:HK$100,000 | 風險:2% | 入場:HK$10 | 止損:HK$9 → 數量 = HK$2,000 ÷ HK$1 = 2,000 股

固定金額

簡單策略

無論帳戶大小,每宗交易分配固定金額。易於理解,但無法隨帳戶增長而調整。

# 公式
倉位規模 = 固定金額 ÷ 入場價
# 示例
固定:HK$10,000 | 入場:HK$10 → 數量 = 1,000 股

波動率調整(基於 ATR)

趨勢策略

倉位規模與標的近期波動率成反比調整,波動率以平均真實波幅(ATR)衡量。波動較大的標的倉位較小,波動較小的標的倉位較大。

# 公式
倉位規模 = (帳戶權益 × 風險%) ÷ (ATR(14) × ATR 倍數)
# 示例
帳戶:HK$100,000 | 風險:2% | ATR:HK$0.50 | 倍數:2 → 數量 = HK$2,000 ÷ HK$1 = 2,000 股

凱利公式(半凱利)

進階用法

凱利公式根據策略的歷史勝率及風險回報比,以長期增長最大化為目標。我們採用半凱利(公式結果的 50%)以降低波動。

# 公式
f* = (W × R – (1–W)) ÷ R → 半凱利 = f* ÷ 2
# 示例
勝率:55% | 風險回報比:2:1 → f* = (0.55×2 – 0.45)/2 = 32.5% → 半凱利 = 權益的 16.25%

5. 投資組合層面的模擬

當策略同時交易多個標的時,引擎會執行投資組合層面的限制,避免出現可同時持有無限數量交易的不切實際情況。

資金分配

每個未平倉倉位都會佔用資金。引擎會追蹤已投入的總資金,若剩餘現金低於最小倉位規模,便會拒絕新的入場。除非策略明確指定,否則不使用槓桿。

最大持倉數量

每個策略都會訂明可同時持有的最大倉位數目。達到上限後,新的入場信號會排隊等候,待現有倉位平倉後才成交。這可避免過度分散。

組合回撤止損

若整體組合回撤超過可設定的門檻(預設:25%),所有倉位將被平倉,並在冷靜期內暫停新的入場。這模擬了風險管理的紀律。

再平衡與偏離

對於多資產策略,引擎會定期將倉位權重調整回目標配置。再平衡頻率及容差範圍可按策略分別設定。

6. 支援的時間週期

引擎支援多種數據解析度。策略適用的時間週期取決於其持倉期及信號頻率。

時間週期 一般持倉期 策略類型 適用範圍
日線(收市) 5 天 – 12 個月 波段交易、持倉交易 所有市場
週線 1–6 個月 趨勢跟隨、長線 所有市場
月線 3–24 個月 宏觀策略、因子模型 所有市場
4 小時 1–5 天 短線波段 香港、美國(經由聚合)
1 小時 4–48 小時 日內波段 僅限香港、美國
15 分鐘 1–8 小時 日內交易 僅限香港、美國
5 分鐘 30 分鐘 – 4 小時 短炒策略 僅限美國(歷史數據有限)