文章裡的每個數字,以及它從哪裡來
方法寫到足以讓你自己把帳算一遍,或用相同的公開與授權資料重建一份等價的研究。
資料與標的池
兩個面板,都是 15 分鐘與一小時 K 線,期間從 2021 年 1 月到 2026 年 7 月。加密貨幣是幣安 USDT 保證金永續合約的 OHLCV,附上逐合約逐月實測的報價價差,以及每一筆資金費率事件在其結算時間戳上的紀錄。股票是經分割調整的合併 K 線,只納入正規交易時段內符合 NBBO 資格的成交,排除零股與場外成交回報,以永久證券識別碼而不是股票代號作為鍵值,並帶有每根 K 線實測的時間加權 NBBO 價差。
標的池在 2022 年 12 月 31 日固定,只依 2022 年 10 月到 12 月的流動性決定,每個市場取流動性最高的十檔。MATIC 在 2024 年 9 月停止交易,之後就讓它缺席,而不是找替代品,因為事後挑選的替代品會用到「哪些合約活了下來」的資訊。
| 市場 | 標的 |
|---|---|
| 加密貨幣 | BTCUSDT, ETHUSDT, DOGEUSDT, XRPUSDT, BNBUSDT, SOLUSDT, MATICUSDT, LTCUSDT, CHZUSDT, ETCUSDT |
| 股票 | TSLA, AAPL, NVDA, AMZN, MSFT, AMD, META, GOOGL, NFLX, XOM |
規則庫
十四個家族,每個三十組參數,共 420 條規則。對每個家族,生成器先列舉下表的網格,丟掉無效與重複的設定,再以種子 20260804 取出 30 組空間填充的設定。規則庫以標準形式序列化並計算雜湊,只要雜湊不同,每一個 runner 都會拒絕啟動。
| 家族 | 第 t 根 K 線收盤時的訊號 | 網格 |
|---|---|---|
| 趨勢追蹤 | 站在移動趨勢的那一側,前提是趨勢強度越過門檻 | 回看 12, 24, 48, 96;強度 0, 0.5, 1 個波動單位;持有 1, 2, 4, 8, 16 |
| 均值回歸 | 反向操作相對於滾動均值的標準化偏離 | 回看 12, 24, 48, 96;進場 z 0.5, 1, 1.5, 2;持有 1, 2, 4, 8 |
| 突破 | 收盤價突破先前滾動收盤價的極值 | 回看 6 到 96;緩衝 0, 5, 10 bp;持有 1, 2, 4, 8 |
| 動能 | 落後累積報酬的正負號,強度須高於門檻 | 回看 3 到 96;強度 0, 0.25, 0.5, 1 個波動單位;持有 1, 2, 4, 8 |
| 波動擴張 | 短期波動超過長期波動時,跟隨短期方向 | 短期 6, 12;長期 24, 48, 96;比值 1.25, 1.5, 2;方向 1, 3;持有 1, 2, 4 |
| 波動收縮 | 壓縮期間跟隨短期方向 | 短期 6, 12;長期 24, 48, 96;比值 0.4, 0.6, 0.8;方向 1, 3;持有 1, 2, 4 |
| 均線交叉 | 已完成 K 線上的快/慢 EMA 交叉 | 快線 3 到 24;慢線 12 到 96,快線短於慢線;持有 1 到 16 |
| 通道突破 | 收盤價突破均值加減 ATR 通道 | 回看 12 到 96;寬度 0.5, 1, 1.5, 2 ATR;持有 1, 2, 4, 8 |
| RSI 反轉 | 超賣買進,超買賣出 | RSI 6, 14, 28;界線 20/80, 30/70, 40/60;持有 1, 2, 4, 8 |
| Bollinger 反轉 | 反向操作收在通道外的收盤價 | 回看 12, 20, 48, 96;寬度 1 到 2.5 個標準差;持有 1, 2, 4, 8 |
| Donchian 突破 | 收盤價突破先前的高低點通道 | 回看 12 到 96;持有 1 到 16;可選一根 K 線的確認 |
| 成交量確認 | 只有在標準化成交量越過比值時才做動能 | 動能 3 到 24;成交量回看 12 到 96;比值 1, 1.5, 2;持有 1, 2, 4, 8 |
| 開盤區間突破 | 突破交易日最初幾根 K 線的區間 | 區間 1, 2, 4 根 K 線;緩衝 0, 5, 10 bp;最晚進場為當日的 0.5, 0.75;持有 1, 2, 4 |
| 時間型 | 固定的時段區塊與方向 | 時段比例 0, 0.25, 0.5, 0.75;做多或做空;星期遮罩;持有 1, 2, 4, 8 |
訊號是一次進場轉換:規則第一次進入做多或做空狀態時觸發,停留在同一狀態的後續 K 線不算新訊號。在每個 24 個月的訓練視窗內,一條規則只有在完成的交易少於 120 筆、交易的標的少於 5 個,或產生的訊號集合與一條編號較小的規則完全相同時,才會被剔除,從來不會用任何獲利統計量來剔除規則。
有七組波動擴張設定從未交易,因為在那些視窗長度下,它們要求的短期對長期波動比值根本達不到;而重複檢查在比較訊號時不看持有期,所以只差在持有多久的規則,會併成編號最小的那一條。平均而言,420 條規則中每個視窗有 392 到 396 條符合資格。
執行
決策在第 t 根 K 線完成之後做出。部位在第 t+1 根 K 線的開盤價進場,在持有的第 h 根 K 線收盤時出場,h 是規則以觀察到的 K 線根數計的持有期。沒有停損也沒有目標價,因此一根 K 線高點與低點的先後順序永遠不會決定出場。
每一組「規則-標的」最多持有一個候選部位,在部位未平倉期間到來的訊號會被忽略;模型跳過一筆交易,也不會因此產生替補交易。
entry = signal_idx + 1 exit = signal_idx + hold # close of the hold-th held bar gross_bps = direction * log(close[exit] / open[entry]) * 1e4 net_bps = gross_bps - spread_bps - fee_bps - slippage_bps + funding_bps
特徵
六十二個價格與成交量特徵,在第 t 根 K 線上、只用各標的自己的歷史計算:1 到 24 根 K 線的落後報酬與動能、高低區間、K 線實體與影線的比例、收盤到開盤的跳空、波動、與均線的距離、在區間中的位置,以及 6 到 96 根 K 線的高低點距離,加上標準化成交量。另外再加七個:趨勢強度(24 根 K 線均線距離的絕對值除以 24 根 K 線的波動)、以正弦與餘弦成對表示的時段位置與星期、交易日剩餘的 K 線根數,以及第 t 根 K 線收盤價的對數。
規則本身提供:以 one-hot 向量表示的家族、依網格位置縮放的參數與缺漏參數旗標、訊號的方向與強度、預定持有期,以及距離上一個訊號的 K 線根數。近期表現是這條規則在該標的上最近 20 筆已完成交易的平均、總和、勝場與敗場,以及它跨標的最近 100 筆已完成交易的平均、勝場與敗場,只計入在決策 K 線當下或之前已經出場的交易。
# strategy-level trailing 100: only trades that have already exited count
for p in trades_sorted_by_entry:
while exits[cursor].exit_ts <= p.signal_ts:
ring.push(exits[cursor].net_bps); cursor += 1
p.recent_100_mean = ring.mean()執行資料(下一根 K 線的開盤價、每一個成本欄位與資金費率)存放在每一列上,並從模型矩陣中移除。時段位置與剩餘 K 線根數使用當日的 K 線數量,因此在有缺漏 K 線的日子裡會反映出缺口;依格子不同,這些日子承載了 0.002% 到 0.33% 的交易,把它們剔除後,最好的帳戶從 +0.748% 變成 +0.761%。
在訓練視窗內進場、卻在視窗之後才出場的交易,會同時從訓練集與樣本外集合中排除,所以它也不會進入那 20 筆交易的歷史,這讓該歷史稍微過時一點,但永遠不會超前於決策。
模型與搜尋
三個家族,每個都分別針對淨報酬目標與獲利目標擬合,各有 30 組固定設定。迴歸目標在訓練資料的 0.5% 與 99.5% 分位數處截斷並標準化。失敗、輸出為常數與未收斂的設定都計入那 30 組,且不能被選中。
| 家族 | 實作 | 30 組設定的網格範圍 |
|---|---|---|
| 線性 | 純 L2 用 Ridge,其餘用 elastic net;獲利目標用 logistic elastic net | alpha 0.0001 到 0.03;L1 比例 0 到 1 |
| 提升樹 | LightGBM,150 棵樹,不做列或欄抽樣 | 深度 2 到 6;葉節點 4 到 31;學習率 0.0054 到 0.091;最小子節點 104 到 4,645;L2 0.0014 到 68 |
| 神經網路 | GELU MLP,6 個 epoch,批次 8,192 | 深度 1 到 3;寬度 16 到 128;學習率 0.0001 到 0.0028;權重衰減 1.5e-7 到 0.0094 |
在每個視窗內,訓練列依時間順序以 80/20 切成內層訓練與驗證,切分點之前移除 16 根 K 線的時鐘時間。淨報酬模型依驗證集上的 Spearman rank IC 選擇,獲利模型依驗證集上的 ROC AUC 選擇,平手時取設定編號較小者。勝出的設定用完整 24 個月重新擬合,其前處理也只在這些資料列上擬合。
Walk-forward
四十三個每月樣本外視窗,從 2023 年 1 月到 2026 年 7 月,四個「市場-時間框架」格子各一套,共 172 個視窗。每個視窗恰好以前 24 個日曆月訓練,只使用進場與出場都落在其中的交易,然後對下一個日曆月進場的每一筆合格交易預測一次。每個市場、時間框架、家族與目標各一個模型,合併所有規則與標的。
for cell in ["equity_1h", "equity_15m", "crypto_1h", "crypto_15m"]:
for month in months("2023-01", "2026-07"):
is_rows = trades(entry >= month - 24M, exit < month, eligible_rules(month))
oos_rows = trades(month <= entry < month + 1M, eligible_rules(month))
for family in ("linear", "gbt", "mlp"):
for target in ("net_return", "profit"):
best = select(family, target, is_rows, n_configs=30) # 80/20 inner split
model = refit(best, is_rows)
oos_rows[f"pred_{family}_{target}"] = model.predict(oos_rows)總計從 30,960 組嘗試過的設定中選出 1,032 個模型,其中 30,394 組擬合成功,並在 39,908,684 筆候選交易上產生 239,452,104 個樣本外預測。
交易策略
每一組「規則-標的」都拿到相同的基礎權重 w0 = 1 / (S × 10),其中 S 是該視窗內合格規則的數量,因此每個訊號都做永遠不會超過 100% 的總曝險。
baseline w = w0
simple filter w = w0 if at least 2 of { vol_24, trend_strength_24, vol_norm_24 }
exceed the instrument's median over the 24 training months
ML filter w = w0 if prediction > 0 bp (net return) or > 0.5 (profit)
ML sizing q = rank of prediction in the window's sorted validation predictions
w = w0 * (0.25 + 1.5 * q)
ML ranking at each signal timestamp keep ceil(20%) of the new signals, at least one,
by prediction; w = w0 * min(5, n_candidates / n_kept)簡單過濾條件的中位數取自訓練視窗中不重複的市場 K 線,而不是交易列,所以一根帶有許多訊號的 K 線不會被重複計算。一個過濾在某個月一筆交易都沒做,那個月就持有現金。
成本
| 市場 | 價差 | 每次成交手續費 | 每次成交滑價 | 資金費率 |
|---|---|---|---|---|
| 加密貨幣 | 進場付實測價差的一半,出場再付一半 | 5 bp | 2 bp | 從進場 K 線到出場 K 線之間的每一筆實際事件,帶正負號 |
| 股票 | 進場付每根 K 線實測價差的一半,出場再付一半 | 0.5 bp | 0 | 無 |
資金費率為正時多單被扣款、空單收款,而資金費率事件歸屬於包含它的那根 K 線,所以在結算 K 線開盤進場的交易要付那次結算。與手續費相比,資金費率一直很小:每個加密貨幣一小時訊號都做,整段期間資金費率淨額是資本的 -0.28%,手續費則付了 174.59%。每一種策略的成本都相同,這就是為什麼文章裡每筆交易的成本柱幾乎不動,而毛利柱會動。
統計推論與結論門檻
經濟數字來自串接起來的樣本外帳本,以及一條不重疊的每日報酬序列,損益在每筆交易出場時入帳。文章報告的是每日報酬的加總,因為複利會讓每一個加密貨幣帳戶都卡在 -100% 附近;登記的淨報酬門檻則使用複利序列。
每個對照都是一種策略在每日序列上減去其比較對象。不確定性用配對 bootstrap 估計,以整週為單位重新抽樣,10,000 次複製,種子 20260804;Benjamini-Hochberg 校正施加在全部 144 個對照上:4 個格子、18 種模型策略與 2 個比較對象,不通過的也包括在內。
weeks = daily_delta.groupby(week) # week-clustered resampling
boot = [weeks.sample(n_weeks, replace=True).sum() for _ in range(10_000)]
p = two_sided(boot)
q = benjamini_hochberg(p_all_144)
# rotation null: same timestamps, same instrument, same count, same exposure budget
for r in range(1_000):
shifted = circular_shift(scores, offset=nonzero, within=(cell, month, instrument))
null[r] = net_of_policy(select(shifted))
passes_rotation = policy_net > quantile(null, 0.95)一個對照在七道門檻全部成立時才獲得認定:淨報酬高於比較對象、每單位平均總曝險的淨報酬高於比較對象、q 低於 0.05、43 個月中贏下超過一半、月報酬風險比大於 1、刪掉最好的那個月之後仍保有正的領先,以及結果高於輪轉虛無對照的第 95 百分位。當一個策略每個月都贏時,報酬風險比沒有定義,這道門檻就不通過;有十二個對照處於這種情況,六個在股票 15 分鐘 K 線,六個在加密貨幣一小時 K 線。
一般性結論需要在兩個市場、兩種時間框架,以及三個模型家族中至少兩個,都有獲認定的結果。文章中針對單一帳戶引用的絕對週數字,來自另一次以週為叢集、對各帳戶自身週損益做的 bootstrap。
檢核
在任何樣本外數字出現之前,面板層級的測試組就確認了:截斷未來之後,先前的每個特徵、訊號與交易都不變(最大差異 0.0);刻意植入的目標洩漏會把驗證 IC 從 0.017 拉到 0.9999;沒有任何成本或資金費率欄位進入模型矩陣;資金費率按事件時間計算,費率為正時多單被扣款;已知的股票分割都有調整;下一根 K 線的目標對齊誤差在 1.7e-6 bp 以內。一個 Python 參考實作在 50,000 根真實 BTCUSDT K 線上,以每個家族各一組設定,與編譯後的訊號引擎在 57,648 筆交易上完全一致。
執行之後,39,908,684 列樣本外候選資料每一列都和來源面板核對過:進場在訊號後一根 K 線、恰好在持有期後出場、進場價等於面板開盤價且出場價等於面板收盤價、毛報酬、價差、手續費、滑價與資金費率都從原始輸入重新計算、淨額恆等式成立、進場落在評分月份內,以及價格特徵等於訊號 K 線收盤價的對數。每一個過濾、部位大小、排序與簡單過濾條件的權重,都從儲存的預測值與訓練期中位數重建,而全部 92 個策略帳戶的合併總額,重建後的誤差在 5.3e-15 以內。
股票價差是隨研究一起凍結的逐 K 線數值。用之後重新抓取的同一批價差為每一筆股票交易重新計價,沒有任何策略的變動超過資本的 0.0024,也沒有任何正負號改變。bootstrap p 值、BH q 值與輪轉虛無對照的超越次數,也都能從每日序列完全重現。
雜湊值
| 產出物 | SHA-256 |
|---|---|
| 規則庫 | 501f04df5537f881709027e8755eade85d7ca667acb0051d1fcd4b9dc18bb14a |
| 模型網格 | 6c6d89b6cfd435ce875876820443405f5d383956a5673ea38f5d2d410b490e47 |
| 交易策略 | df469ad083dde73c7be52ed5d33ad4d434faa684a74e7777c200b6d5b988bf1d |
| 特徵 | eedebd594bfa8aa9c56fb282e7d065eef06c99b63a0d07f974668a526862cc02 |
| 合併設定 | 6fc808d41d71d9930b17eb81a0b6b0d2189ba9b7e084896e70c61a3020c94f0f |
| 分析設定 | 1e3af923775cf8fca30f2c28da0ecab7803320454cfafd15e9101a33d53b5735 |
| 分析實作 | 86f433e42fe14560425f6da690754e5b603509b4b9581bba56d6bd1bd447fb3b |
文章圖表畫出的每一個數字,都在 一個 JSON 檔裡。完整的流程,從訊號產生、walk-forward 擬合到稽核腳本,可來信索取: daniel@daru.finance。

