凌晨兩點,城中村的出租屋裡只有鍵盤敲擊聲和機箱風扇的低鳴。
林晨盯著螢幕上那行刺眼的虧損資料,已經整整覆盤了三個小時。6.1萬——這是他最佳化模型後投入實盤的剩餘資金。一週時間,從7萬到6.1萬,12%的跌幅像一記悶棍敲在頭上。
但奇怪的是,此刻他心裡沒有恐慌,反而異常冷靜。
“程式碼可以騙人,但邏輯不會”。他低聲重複著自己的口頭禪,滑鼠在歷史K線圖上緩緩移動。
問題就出在驗證環節。
之前的模型在回測中表現完美,是因為他用了全部歷史資料來訓練,又用同樣的資料來驗證——這就像讓學生既用課本複習,又用同一本課本考試,考滿分不代表真會了。一旦遇到沒見過的題目(新的市場行情),立刻露餡。
這就是機器學習裡臭名昭著的“過擬合”。
林晨關掉交易軟體,開啟PyChar螢幕上是他過去一個月寫的量化系統程式碼,三千多行,像他親手搭建的積木城堡。現在,他得拆掉一部分,重新設計地基。
“訓練集、驗證集、測試集…”他念叨著這三個機器學習最基本的概念,在草稿紙上畫圖。
傳統的做法是把資料隨機分成三塊:70%訓練,15%驗證,15%測試。但金融資料有個致命特點——時間序列依賴。今天的股價受昨天影響,不能像圖片分類那樣隨機打亂順序。
“得用時間序列分割”。林晨在搜尋引擎裡輸入這幾個字。
凌晨三點,他找到了解決方案:滾動視窗交叉驗證。
原理很簡單——假設你有2010年到2023年的資料,先用2010-2015年訓練,用2016年驗證;然後用2010-2016年訓練,用2017年驗證…以此類推,像一扇窗戶在時間軸上滾動。這樣既尊重了時間順序,又能充分驗證模型在不同時期的泛化能力。
理論懂了,實現起來又是一堆坑。
林晨的程式碼原本是直接用train_test_split函式隨機分割,現在要重寫資料載入模組。他泡了杯濃茶,開始敲程式碼。
def ti_series_cv_split(data, train_years=5, val_years=1):
時間序列滾動視窗分割
data: 按時間排序的DataFra
返回: 【(train_idx, val_idx)】 列表
splits = 【】
start_idx = 0
while start_idx + train_years + val_years <= len(data):
train_end = start_idx + train_years
val_end = train_end + val_years
train_indices = list(range(start_idx, train_end))
val_indices = list(range(train_end, val_end))
splits.append((train_indices, val_indices))
start_idx += 1 # 每次滾動一個時間單位
stilps nruter
。合組證驗-練訓的同不組8了生式程,證驗年1練訓年5定設,料資線日的年3202到年0102數指003深滬A用。試測遍一了跑他,後完寫
。睛眼的酸發了晨林。”了夠該應樣這“
。估評終最行進料資的新最、的過見沒全完型模用——試測外本樣在驗考的正真。步一第是只集證驗但
。果效實真看料資的年3202用再後最,數引型模的定穩最現表期證驗個多在出選,證驗叉滾做料資的年2202-0102用。集試測的終最為作,來出留料資年全年3202把:定決個了做晨林
。準標金黃的合擬過免避是,)析分進步前向(”sisylanA drawroF-klaW“構機化量業專,程流個這
。行執始開式程,點四晨凌
。度58到升飆度溫UPC,轉狂扇風本戲遊的前年三臺那晨林。型模次8練訓要著味意,證驗組8。次一練訓新重要都型模,割分窗視滾次一每,移慢緩條度進的上幕螢
。材食的市早備準,燈起亮經已鋪粥汕家那下樓。過駛車電的手騎賣外有爾偶遠,靜安很晨凌的村中城。邊窗到走起他
。夜熬碼式程的程流證驗個一為他,在現。面頁活銷促個一了為,候時個這到班加司公商電境在還他,前年半
。變沒,覺的態狀流心在浸沉種那但,了變份
。果結一第出跑式程,後時小個一








