EN 中文
← 回文章列表
量化 · 證偽紀錄

決定預測值的是回看視窗,不是資料

我拿 Kronos 這個開源的金融 K 線基礎模型,零樣本測台股日線。Spearman IC 跑出 +0.187、p<0.001。結果那兩個漂亮數字都是假的——一個是我沒控制掉的免費基準,一個是重疊視窗灌出來的樣本數。真正留下來的發現是:同一檔同一天只改回看長度,預測從 -0.35% 跑到 -29.70%。

2026-10-15 myps6415 shiyu-coder/Kronos
+0.187
表面 Spearman IC(p<0.001)
t=-0.98
控制住均值回歸之後
-29.70%
同一筆預測,回看 400

我為什麼還要測

十天前我才收攤一條選股線。投信買超排序、外資買超、多因子模型,三次都輸給單純抱著指數。 當時寫下的重啟條件是:除非 regime 轉向,不要再開。

所以 Kronos 出現的時候——AAAI 2026、MIT 授權、 45 家交易所、超過 120 億根 K 線預訓練、mini/small/base 權重開源——我第一個念頭是直接套用舊結論、 省下這個週末。

那個念頭是錯的,而且我很慶幸有人把它頂回來。收攤那條線測的是從法人買賣超做橫斷面排序, Kronos 是價格序列預測。不同的假設類別。一個假設的收攤條件不構成另一個假設的證據, 拿它來否決只是替偷懶找一份有紀錄的理由。

所以我真的跑了。

測試設定

Kronos-small、零樣本、台股日線。20 檔標的(我真實的持倉加候選池)、24 個時點, 合計 480 次五日預測。每一次取 20 條抽樣路徑的集成均值。所有時點都落在 2026 年 5 到 7 月, 在論文 2025 年 8 月投稿之後,盡量讓評估窗口避開模型可能背過的區間。

一個順便修正的誤判:速度從來不是問題。Intel Mac 純 CPU,單條路徑約 0.1 秒。 我事前估「一次幾十秒」,差了兩個數量級。

表面結果,看起來是贏的

  • Spearman IC +0.187,p < 0.001
  • 方向準確率 57.1%,p = 0.002
  • 20 檔全部 IC 為正

20 比 0。如果我停在這裡,這篇會是一篇完全不同的文章,模型會被接進我的指揮中心, 然後我會錯好幾個月才發現。

死因一:它賣我一個我本來就免費有的東西

預測值跟「過去五日報酬」的相關是 -0.589。Kronos 在反著近期走勢押注——而那段期間台股確實在 均值回歸。所以「跟趨勢反著做」是免費的錢,跟模型沒有關係。

要知道一個訊號有沒有加值,做法是把免費效果放進同一條迴歸裡:

過去 5 日報酬      t = -4.74    顯著
Kronos 預測        t = -0.98    不顯著,而且係數為負
      未來 5 日報酬 ~ 過去 5 日報酬 + Kronos 預測
    

控制住過去五日報酬之後,模型的增量貢獻跟零分不出來,而那一點點還指向反方向。

接著是比較難看的那個對照。基準——「反著上週押」,零參數、一行程式——方向準確率 56.7%, 模型 57.1%。一個吃了 120 億根 K 線的預訓練 transformer,跟一行程式打平。

訊號的價值只等於它多出來的那部分

任何依賴某個持續性市場效應的預測,在那個效應有賺的窗口裡都會很好看。問題從來不是 「我的指標是不是正的」,而是「把同一個押注的免費版本放進模型之後,它還是不是正的」。 如果你說不出免費基準是什麼,這個測試就還沒設計完。

死因二:480 不是我的樣本數

我有 480 次預測,然後就把它當成 n=480。它不是,有兩個各自獨立的理由:

  • 窗口重疊。 時點間隔兩天,預測期五天。相鄰的觀測共用大部分的結果期間。
  • 標的不獨立。 台股高度連動。一個小市場裡的 20 檔,離 20 次獨立抽樣差得很遠。

兩者灌水的方向一樣——都往「看起來是真的」那邊。標準做法是把每天收斂成一個橫斷面 IC, 再對那串時間序列做 t 檢定:

Kronos        t = +1.09    p = 0.287    不顯著
免費基準      t = +2.88                 顯著
      每日橫斷面 IC,對序列做 t 檢定
    

我一直在引用的 p = 0.002 是重疊樣本製造出來的。免費基準過得了這一關,模型過不了。

比測試結果更值得留下的發現

這一段是即使 Kronos 過關我也還是會在意的事。

KronosPredictor.predict() 會對整段回看視窗做 z-score 正規化再餵給模型。 所以那個視窗不只是「模型看多少歷史」——它是預測值的計價單位。 同一檔、同一天、同一組權重,只改回看長度:

回看  60   →   -0.35%
回看 120   →   +4.50%
回看 250   →  -10.08%
回看 400   →  -29.70%
      同一檔同一天,只改回看長度——實際走勢是 +2.62%
    

日線上五天預測 -29.70% 不是一個預測,是一個單位錯誤。而且模型沒有在保留: 回看 400 的時候,p10–p90 區間完全不包含實際值。它很有把握而且錯了, 這比「噪音大、區間寬」更糟,因為寬區間至少會叫你停下來。

我把溫度降到 0.6 試過,假設這是抽樣噪音。完全沒變,而這就是答案: 降溫度是把變異收窄到模型的中心信念附近,而壞掉的正是那個中心信念。

根因是 demo 跟我的資料之間的尺度落差。公開的 demo 跑 5 分 K,400 根約一天半, 視窗的標準差很小。日線上 400 根約 1.6 年,在那麼長的期間上做正規化, 標準差大到反正規化之後的輸出可以落在任何地方。

於是我的使用情境得到一個不太舒服的結論:日線上沒有任何一個設定能同時待在模型的設計範圍內 (context 512)又讓數值合理。 短視窗數值正常但丟掉歷史,長視窗用了歷史但吐出荒謬值。

正規化是介面的一部分,不是前處理細節

如果一個模型會在你指定的視窗上做正規化,那個視窗就是預測的輸入,不是前處理設定。 任何「正規化視窗可調、輸出又是真實單位」的 repo 都有這個故障模式。 抓它的測試只要一個下午:其他全部固定,掃過視窗長度,看預測值會不會跳出同一個數量級。 如果會跳,你讀到的是一個單位,不是一個訊號。

我沒有證偽的部分

證偽結果最容易被過度引用,所以讓我把範圍圍清楚。失敗的是: 零樣本 Kronos-small、台股日線、當下唯一數值合理的設定、抽樣約兩個月。

明確沒測、而且按我主觀認為「可能真的有效」排序:

  • 日內 5 分 K。 這是 demo 的主場,正規化尺度在那裡本來就是合理的。 如果它在那裡有效我不會意外,而上面所有內容都不構成它無效的證據。
  • Fine-tune。 repo 附了 finetune/,這是想繼續走下去的人最合理的下一步。
  • base / large。 我只測了 small。(large 有 499M 參數,權重閉源。)
  • 其他 regime。 兩個月只是一次 regime 抽樣。我的窗口剛好由均值回歸主導, 而那正是死因一能被偵測到的原因——在趨勢盤裡同一個檢定會長得不一樣, 我得改成控制動能才對。

那為什麼還是停了

剩下兩條活路——fine-tune、或轉日內——都是真正的工程專案。更重要的是, 兩條都把人推向短週期交易,而我實際的策略是指數核心加股利、退休級的時間尺度。 一個只在五分鐘解析度上有效的模型,不是那個策略的工具, 是一個穿著工具外衣的另一種策略。

所以重啟條件寫下來,不交給心情:先做 fine-tune 或日內,然後它必須過掉在這裡殺死它的那兩關 ——控制住反趨勢基準之後仍有增量 t 值,而且每日橫斷面 IC 序列的 t 檢定要顯著。 不准再有重疊視窗生出來的 p 值。

退場條件要在你還不想要它的時候寫

一次失敗的測試留下來最有用的東西不是結論,是那道閘門。「我們試過、不行」會在一個季度之內 退化成傳說,然後被當下最有熱情的那個人重新翻案。 「它必須過這兩個具體的檢定,就是當初殺死它的那兩個」是可重用的, 而且它擋得住我自己未來的興奮——考慮到我差點用一個不相關的先驗就否決掉這個模型, 最需要被守住的其實就是這一點。