2026年十月22日 · 資料

資料供應商改寫歷史資料後,我們重建了回測

資料供應商改寫歷史資料後,我們重建了回測

回測跑完 6 週後,我們用相同的程式碼、設定和日期範圍再跑一次,結果期末資產不同了。差異不算大,但足以讓 Sharpe 從 1.31 降到 1.08,也改變了看起來最好的參數組合。

策略沒有變,變的是歷史資料。供應商修訂了幾天的成交紀錄和 K 線,而我們第一次執行時沒有保存確切的輸入快照。接下來幾天,我們花時間釐清新結果究竟來自資料更正、管線錯誤,還是研究流程本身無法重現。

星期一:重新執行的結果對不上

最先讓我們起疑的是一個流動性高的現貨交易對,出現了一個小落差。原始 K 線的最高價是 62,418,重新執行時則是 62,431。起初看來無傷大雅,直到我們追查策略進場條件:觸發門檻正好落在這兩個價格之間。幾根 K 線一變,訊號就不同,幾天後的持倉也跟著改變。

我們比較每日成交筆數,發現差異從單一日期開始。接著比對供應商提供的原始資料列,發現目前收到的資料中有幾筆更正後的成交紀錄,彙總 K 線也經過修訂。當初使用的回應沒有附上變更紀錄。

這是資料常見的狀況。交易所會修復紀錄;供應商會補上缺漏、修正錯誤成交資料,也會調整彙總邏輯。3 月查詢「1 月資料」,拿到的結果可能已經不同。

星期二:我們找到遺失的收據

執行紀錄中有供應商名稱、交易代號和日期範圍,但我們沒有保存供應商的回應內容,也沒有為每個輸入分區記錄內容雜湊。換句話說,我們能證明自己送出了什麼查詢,卻無法證明供應商回傳了哪些位元組。

我們找出能找到的最舊快取檔案,並與目前的回應比對。差異不是拆股調整或時區轉換,而是一小組更正後的成交紀錄,經過 K 線建構流程後影響了結果。這排除了其中一種可能,但快取不完整,因此我們仍無法精確重建所有受影響的 K 線。

我們記錄了什麼能回答什麼問題缺少了什麼
供應商、交易代號、日期範圍這次執行提出了哪項請求回應內容
管線版本用哪份程式碼建構 K 線確切的輸入資料列
執行時間工作執行的時間當時可取得的供應商修訂版本

我們一直把「相同查詢」當成「相同資料」。這個假設讓實驗看起來比實際上更可重現。

星期三:資料更正改變了結果的解讀

我們用兩個版本的可用資料,重新重播受影響的日期。修訂後的 K 線少了 2 次進場,另有 1 次出場往後移了 1 根 K 線。這 3 筆交易解釋了 Sharpe 變化的大部分。即使在圖表上看起來整體價格序列幾乎一樣,策略仍會受到觸發點附近少數觀測值的影響。

這不代表原始結果不可信,也不代表修訂後的結果必然更好。這表示我們必須說清楚結論適用的範圍:舊結果描述的是當時使用的資料快照,重新執行的結果描述的則是供應商目前提供的歷史資料。我們不能把其中一個說成是另一個的重現。

星期四:我們更新了研究紀錄

我們開始為新的研究執行保存不可變更的輸入快照。每個分區都有內容雜湊,執行清單會記錄來源、擷取時間、結構描述版本、調整政策和轉換程式碼版本。大型資料集的實際檔案則存放在以內容定址的儲存空間中,讓相同分區可以共用,也不會覆寫舊版本。

如果儲存或授權條款不允許我們保留原始資料,就盡可能保存條款允許的完整憑證:雜湊、請求參數、來源修訂識別碼,以及少量解析後的資料列供診斷使用。雜湊無法還原資料,但能告訴我們兩次執行使用的位元組是否相同。

要讓回測可重現,必須識別輸入資料本身,光有資料 URL 還不夠。請記錄收到的內容、收到的時間,以及資料如何轉換成策略實際使用的資料列。

星期五:下次我們會省略的步驟

我們不會只比對摘要指標。Sharpe 變了,只能說明有東西變動,卻無法指出原因。先比對資料列筆數和分區雜湊,再找出第一個輸入不同的日期。接著依序比對轉換後的資料列、訊號、委託和成交。

我們也不會再默默用更正後的歷史資料取代舊資料。資料更正很有用,但舊的執行結果應該繼續對應原始輸入。新資料集應建立新的執行紀錄,並清楚標示與舊紀錄的關聯。

我們現在的實務原則很簡單:若重新執行是為了重現實驗,就固定資料快照;若是要採用更正後的歷史資料,就標記為新的實驗。這個區別花了我們幾天才學會,現在只要在執行清單中加上一行就能說清楚。

市場資料回測資料工程可重現性
← 所有文章