№ 003互動
打造神經進化交易戰隊:從賭徒到股神
讓一群隨機的交易機器人在 2024 年的蘋果股價上競爭、繁殖、突變,三十代之後報酬率 +43%,買進持有只有 +34%。親手訓練一支,再看清楚這個數字為什麼不算數。
- 發布
- 更新
- 閱讀時間
- 4 分鐘
先講結論:下面這個儀器可以在幾秒內訓練出一支交易機器人。練滿三十代,它在 2024 年的蘋果股價上賺 +43% 左右,而同一年買進之後什麼都不做只有 +34%。
這個數字是真的,但它不代表機器人會交易。這篇文章有一半在講它是怎麼練出來的,另一半在講為什麼你不該相信它。先自己練一支。
AAPL
2024 年 1 月 2 日 – 12 月 31 日,每日收盤價
▲ 買▼ 賣
設定參數後按「開始訓練」。每一代都會讓整個族群把這一年交易一遍。
訓練完全在你的瀏覽器裡執行,結果會存在瀏覽器裡,下次回來還在。
它是怎麼練出來的
這裡沒有梯度,也沒有反向傳播。原因很實際:「這一年賺了多少」不是一個可以微分的目標,市場上也沒有「正確的買賣點」可以拿來當標準答案。所以改用演化:
- 隨機產生 50 個機器人。
- 讓每一個在這一年的股價上交易一遍,用年底的報酬率打分數。
- 留下成績最好的幾個,讓牠們兩兩混合權重、加上一點隨機突變,生出下一代;另外再補幾個全新的隨機個體,免得整個族群卡在同一種做法上。
- 重複。
每個機器人的大腦是一個 30 → 24 → 3 的小網路。輸入是過去 30 天每天的漲跌幅(百分比),輸出三個分數,分別代表「不動」「買」「賣」,取最高的那個:
export function observe(closes: number[], day: number): Float32Array {
const out = new Float32Array(WINDOW); // WINDOW = 30
for (let i = 0; i < WINDOW; i++) {
const t = day - (WINDOW - 1) + i;
if (t >= 1) out[i] = ((closes[t] - closes[t - 1]) / closes[t - 1]) * 100;
}
return out;
}儀器上的三個參數對應的就是上面的步驟:世代數是重複幾次,族群大小是每一代有幾個機器人,突變率是每個權重被隨機改動的機率。按下訓練,進化曲線一代一代往上爬,最後停在買進持有那條虛線上方九個百分點左右。
看起來牠們越來越懂這個市場。
它到底學到了什麼
我用六組不同的隨機種子各訓練了三十代(族群 50、突變率 15%,全部是儀器的預設值;只練 20 代的話是 +41.5% 到 +43.8%)。 報酬率全部落在 +42.9% 到 +43.9%,而且贏家做的事幾乎一樣:大部分的買入集中在股價還低的上半年(全年最低點是 4 月 19 日的 165 美元),到年底幾乎滿倉,中間再做幾十次小幅的高賣低買,其中八到九成是賺錢的。
2024 年蘋果整年上漲了 35%。在這種行情裡,任何「趁便宜買滿、抱到年底」的策略都會贏過「一月二日就用 185 美元買滿」。
再回頭看進化曲線的起點。六組種子的第一代,也就是完全沒有演化過的 50 個亂數機器人裡最好的那一個,已經是 +39% 到 +41%,全部在虛線上面。我另外產生了 2,000 個亂數機器人:13% 贏過買進持有,最好的一個 +41%。三十代的演化只在這上面多擠出三個百分點左右。亂猜就能贏過的基準線,說明的是這一年的行情和這套規則,不是機器人。
六組種子收斂到同一個做法,乍看像是「它找到了規律」。比較合理的解釋正好相反:這一年只有一個明顯的低點,通往高分的路都經過那裡。
同一個錯誤的三種樣子
- 過度擬合。 演化會在歷史資料裡找到任何能提高分數的模式,不管那個模式有沒有意義。上面的 +43% 就是一個活生生的例子。
- 只見過一種行情。 這裡只有一檔股票、一個多頭年,所以機器人養成的習慣是「買滿之後就抱著」。換成一個下跌的年份,同樣的習慣會賠得很慘。
- 沒見過的事不可能學到。 突發的新聞、政策變化、流動性消失,訓練資料裡沒發生過,機器人就沒有任何應對。
要讓這個實驗誠實一點,至少要做三件事:把資料切成訓練期和測試期,只在測試期上報成績;加入交易成本;在多檔股票、多種行情上評分。這一頁一件都沒做,所以它的數字只能拿來說明問題,不能拿來下單。
這一頁的機器人最會的,是在一段已經知道結局的歷史裡找到最好的劇本。
這篇文章最初於 2025 年 4 月發表在我的舊站。搬到這本筆記時互動元件用 TypeScript 整個重寫了;2026 年 9 月又重寫了文字,把原本放在文末的結論搬到了開頭。