在規格裡,20 日 Donchian 看起來無害。agent 寫了 20 根 K 線的滾動最高價,回測從 parquet 檔的第 1 列開始,前 2 週所謂的「20 日高點」其實只是既有 K 線的累積最高。到第 4 天,它就是 4 日高點。你以為自己在測的策略,並不是產出前十幾筆成交的那個。
我有一份 ETHUSDT 日線 notebook,全樣本 Sharpe 是 1.4。切掉前 20 個交易時段,它掉到 0.6。留下這 20 個、丟掉第 1 年剩下的部分,會印出 3.1。沒有人洩漏明天。策略用的是過去,只是用得不夠,而報告把那些半成品交易當成了證據。
讓視窗還在填滿時就開始交易
常見的翻車是 min_periods=1。只要你放行,Pandas 會用單一根 K 線就算滾動平均。agent 經常這樣做,因為資料框頂端出現 NaN 感覺像 bug,把它填掉單元測試就變綠。
用 2 筆報酬觀測去做 20 日已實現波動目標,部位會爆炸。2 個數字的變異數就是擲硬幣,你再取倒數,第一筆部位就是預定風險的好幾倍。對接近零的標準差做 z-score,會玩出同樣的把戲,只是多了正負號:策略看起來有個鋒利進場,視窗一旦誠實,那個進場就再也不出現。
突破更糟,因為看起來就像真規則。第 6 根 K 線上的 20 根通道,其實是 6 根通道。一開始就會出現一簇交易,常常發生在平靜區段,完整指標根本不會觸發。平靜市場會稍微漂移。窄通道就開火。權益曲線拿到一截領先起跑,後面哪一年都不會再重複。
Zero-fill 和 forward-fill 編的是另一種謊。RSI 為 0 會讀成超賣。缺失的 ATR 填成 0 會把單位部位炸開,回測就乖乖買下一整倉。我寧願讓 NaN 殺掉訂單,也不要讓 0 憑空造出一筆。
我還是會不自覺地從第 0 列開始畫圖,因為圖表左側空一個月看起來像沒畫完。空白的那一個月才是誠實的部分。
裁掉權益曲線,留下部位
這招能過 code review。你把 20 日特徵算對了,從繪製的曲線丟掉前 20 列,從 1 月 21 日開始發表。1 月 21 日的部位是 1 月 14 日開的。移動停損的高水位、加碼次數、那些燃燒過後的現金:全部走進了「乾淨」樣本。
翻車點是一份沒辦法在文中那個日期啟動的模擬策略。從空手在報告的起始日重啟,第 1 週的訂單對不上。有時回測已經在一筆交易裡,模擬系統沒有進場理由。有時模擬系統因為回看期是冷的而進場,回測卻在場外,因為隱藏的那一個月已經吃過突破。2 本開倉帳,1 個公開的起始日。
Walk-forward 的 fold 會悄悄做這件事。每個測試視窗都有一段你不畫出來的回看尾巴。跳過模擬那段尾巴,第一批測試交易又是未完成視窗的交易。模擬它、只報告測試日,則測試日的部位取決於你沒有秀出來的成交。第二種做法可以是合理的研究選擇。把該 fold 的第一個早上叫做冷啟動,而移動停損已經從尾巴活著進來,這就是 2 位研究員從同一份設定算出 2 個 Sharpe 的原因。
特徵不是「日」的時候,卻用日曆天暖身
「給它 30 天」讓特徵規格不足。5 分鐘 Donchian 上的 30 個日曆天,比 20 期回看多出數千根 K 線。需要 20 個時段的日線特徵,套上 30 天,依週末和空洞而定,要嘛過肥、要嘛過瘦。
我們某一個永續合約交易所上的資金費率 z-score,被給了 30 天暖身,因為規格寫 30 個 period,有人把 period 譯成日曆。那裡的資金費率每 8 小時印一次。30 天大約是 90 次結算。30 個 period 是 10 天。多出來的 2 個月燃燒期剛好含一週脫錨。丟掉它,實盤視窗看起來比策略真實歷史更平靜。大家怪起始日敏感度。其實是暖身把那個狀態吃掉了。
加密貨幣對上股票,同一個數字會改意義,卻沒人改參數。ETH 的 20 個「日」含星期六。20 個股票交易時段幾乎是一個日曆月。把股票 notebook 裡的 20 日回看複製到小時級永續 K 線,你得到的是名叫 20 日、實際是 20 小時的通道。第一根有效 K 線於是要嘛 20 小時後,要嘛——如果後面某個函式有重採樣——20 天後;我在同一份 agent diff 裡兩種都見過。
釘死第一個可交易時間戳
暖身是資料需求,不是額外樣本。每個特徵都要寫明它需要多少筆已完成觀測,單位就是它計算時用的單位。第一個可交易時間戳,是所有這些條件都成立、而且空手帳戶會被允許送出訂單的第一根 K 線。
| 特徵 | 規格通常怎麼寫 | 實際必須存在什麼 | 默默的替代品 |
|---|---|---|---|
| 20 日 Donchian | 20 個日高點 | 20 個完整時段 | min_periods=1 的滾動最高 |
| 30 日已實現波動 | 30 日視窗 | 30 筆收盤對收盤報酬 | 2 日變異數,取倒數變成部位 |
| 20 筆資金費率 z-score | 20 天 | 20 次資金費率結算 | 20 個日曆天(約 90 筆),或錯誤時間框架的 20 根 K 線 |
| 5 分鐘上的 14 期 RSI | 14 期 | 14 根已收盤的 5 分鐘 K 線 | 14 天,或缺口被 forward-fill 的 14 根 K 線 |
該時間戳之前的 P&L 不進績效紀錄。該時間戳之前的狀態可能仍需模擬,這樣時鐘走到第一根可交易 K 線時,移動停損或冷卻才是真的,但那些成交不進 Sharpe、不進交易次數、也不進容量計算。然後跑那個難看的檢查:在該時間戳從空手重啟,回看只作為資料存在。如果訂單變了,你就是在出貨隱藏交易。
模擬交易從同一條契約開始。每個 walk-forward 測試視窗也是。如果圖表看起來少了一個月,就讓它少著。
← 所有文章


