← 返回文章列表
August 3, 2026
5 分鐘閱讀

整合方法:結合弱學習者以獲得穩健的 Alpha

整合方法:結合弱學習者以獲得穩健的 Alpha
#machine-learning
#ensemble
#bagging
#stacking
#alpha

大多數有關交易集合的文章都認為模型越多越好。那是錯誤的軸。整體誤差分解為三項,在交易中只有其中一項是具有約束力的約束。

本文是關於這個術語的,以及本部落格其餘部分未涵蓋的它的兩個後果:堆疊為明確的訊號組合層,以及組合許多訊號是否實際上會在交易到達市場之前降低成交量。

實際綁定的術語:偏差-方差-協方差

對於迴歸係綜 NN 模型,平均預測的預期平方誤差 fˉ\bar{f} 分解為:

E[(fˉy)2]=bias2+1Nvariance+(11N)covarianceE\left[\left(\bar{f} - y\right)^2\right] = \overline{\text{bias}^2} + \frac{1}{N}\overline{\text{variance}} + \left(1 - \frac{1}{N}\right)\overline{\text{covariance}}

三個術語,三個槓桿:

  • Bagging 透過將引導樣本平均來攻擊變異數項。
  • Boosting 透過迭代修正殘差來攻擊偏差項。
  • 堆疊透過學習組合權重而不是假設相等來攻擊協方差項。
  • 增加 NN 僅縮小方差貢獻。它對協方差毫無作用—— (11/N)(1 - 1/N) 係數已經是 0.99 N=100N = 100

最後一點就是整個論點。在交易中,模型是在相同的工具、相同的歷史上針對目標進行訓練的,這些目標本身就是相同價格序列的幾乎相同的轉換。他們的錯誤並不接近獨立。因此,協方差項很大,而方差項已經用盡,這意味著模型數量幾乎什麼也買不到,而結構差異卻可以買到一切。

這個主張的具體、可證偽的形式是:添加第 101 棵梯度增強樹應該比添加一個結構不同的模型對集成度量的移動要小——LSTM、不相交特徵域上的線性模型,任何具有不同歸納偏差的模型。邊緣樹幾乎與書中已有的樹共線;結構上不同的模型則不然。

相關性(而不是模型計數)決定了整體的有效廣度 - 推導、按資產類別加密測量的相關因子以及針對真實貨幣對數據的模擬位於信號相關性:要監控多少對

不要將集合多樣性減少到一個數字。 緊縮夏普比率 計算五個有效-NN 真實 640 個單元網格上的估計器(平均相關性、參與率、PCA-95%、Kaiser、Cheverud-Nyholt)顯示它們跨越 NeffN_{\text{eff}} 從 1.6 到 370,並認為該範圍(而不是任何單點估計)是可交付的。檢舉樂隊。

堆疊作為訊號組合層

bagging 和 boosting 在其他地方都有很好的介紹。 Spread Modeling with Machine Learning 提供了梯度提升設定、傾斜目標的損失選擇、SHAP 重要性發現、特徵分類法以及帶有激發間隙的前向視窗重疊的清除前向分割。從那裡開始;本節假設它。

沒有涵蓋的是上面的等級:元學習器將基本模型預測作為其輸入特徵並學習如何組合它們。

  • 0 級(基礎學習者): 根據原始特徵產生預測的多種模型。
  • 1 級(元學習器): 一個模型,用於學習何時信任哪些基礎學習器。

確保這種安全性的機制是折疊元功能。元學習器絕不能看到基於基礎模型訓練資料進行的基礎模型預測——這些預測有樂觀偏差,無法在即時交易中生存,元學習器將相應地對它們進行加權。

import numpy as np
import pandas as pd
from sklearn.base import clone
from sklearn.model_selection import TimeSeriesSplit


class TradingStackingEnsemble:
    """
    Two-level stacking ensemble for return prediction.

    Level 0: base learners, each on its own feature domain
    Level 1: meta-learner trained on out-of-fold base predictions
    """

    def __init__(self, base_models: list, meta_model, n_splits: int = 5):
        self.base_models = base_models  # list of (name, model, feature_cols)
        self.meta_model = meta_model
        self.n_splits = n_splits
        self.fitted_base_models_ = {}

    def _generate_meta_features(
        self,
        X: pd.DataFrame,
        y: pd.Series
    ) -> pd.DataFrame:
        """Out-of-fold predictions from each base model."""
        tscv = TimeSeriesSplit(n_splits=self.n_splits)
        meta_features = pd.DataFrame(index=X.index)

        for name, model, feature_cols in self.base_models:
            oof_preds = pd.Series(np.nan, index=X.index)

            for train_idx, val_idx in tscv.split(X):
                X_train = X.iloc[train_idx][feature_cols]
                y_train = y.iloc[train_idx]
                X_val = X.iloc[val_idx][feature_cols]

                fold_model = clone(model)
                fold_model.fit(X_train, y_train)

                if hasattr(fold_model, 'predict_proba'):
                    oof_preds.iloc[val_idx] = fold_model.predict_proba(X_val)[:, 1]
                else:
                    oof_preds.iloc[val_idx] = fold_model.predict(X_val)

            meta_features[name] = oof_preds

        return meta_features.dropna()

    def fit(self, X: pd.DataFrame, y: pd.Series):
        meta_features = self._generate_meta_features(X, y)
        y_meta = y.loc[meta_features.index]

        self.meta_model.fit(meta_features, y_meta)

        for name, model, feature_cols in self.base_models:
            model.fit(X[feature_cols], y)
            self.fitted_base_models_[name] = model

        return self

    def predict(self, X: pd.DataFrame) -> np.ndarray:
        meta_features = pd.DataFrame()

        for name, model, feature_cols in self.base_models:
            fitted = self.fitted_base_models_[name]
            if hasattr(fitted, 'predict_proba'):
                meta_features[name] = fitted.predict_proba(X[feature_cols])[:, 1]
            else:
                meta_features[name] = fitted.predict(X[feature_cols])

        return self.meta_model.predict(meta_features)

這裡的分裂規則不是可選的,也不是新穎的——使用淨化的、禁運的前進,並在相信這些數字之前了解每類洩漏在膨脹的夏普中的價值。兩者都已被測量:前瞻偏差分類法量化了受控模擬器中的執行、指示器和標準化洩漏,而前行優化涵蓋了錨定視窗與滾動視窗、CPCV、清除滾動視窗、CP退化。

三個設計決策是專門針對堆疊的,值得一提。

**元學習器簡單性。 ** 使用線性模型-嶺、套索、邏輯迴歸。基礎學習器處理非線性;元學習器僅處理組合。複雜基礎學習器之上的複雜元學習器會出現二階過度擬合,而組合層的 L1 正則化具有將僅產生噪聲的基礎模型歸零的有用副作用。

**硬標籤上的機率輸出。 ** predict_proba 攜帶類別標籤丟棄的置信訊息,並讓元學習器更重視置信基礎預測。

**特徵域劃分。 **這是槓桿率最高的多樣性槓桿,它直接來自協方差參數:無論演算法如何,看到相同特徵的模型都會產生相關錯誤。

FEATURE_GROUPS = {
    'momentum': ['ret_5d', 'ret_10d', 'ret_21d', 'ret_63d'],
    'volatility': ['vol_21d', 'vol_ratio', 'vol_skew', 'garch_vol'],
    'volume': ['volume_ratio', 'obv_slope', 'vwap_dist', 'adv_ratio'],
    'mean_reversion': ['dist_from_ma21', 'dist_from_ma63', 'rsi_14', 'bb_pct'],
    'microstructure': ['bid_ask_spread', 'kyle_lambda', 'amihud_illiq'],
    'fundamental': ['ep_ratio', 'bp_ratio', 'roe', 'accruals'],
}

base_models = []
for domain, features in FEATURE_GROUPS.items():
    model = GradientBoostingClassifier(
        n_estimators=200, max_depth=3,
        learning_rate=0.05, subsample=0.7
    )
    base_models.append((domain, model, features))

每個基礎模型都成為領域專家:動量模型在不受音量噪音幹擾的情況下學習動量模式,元學習器學習在哪種條件下值得信任哪個專家。

關於最後一條的兩個警告。首先,狀態條件加權是一個已解決並已發布的問題 - 使用 HMM 進行狀態檢測 透過 Forward/Viterbi/Baum-Welch 正確導出狀態,並將它們作為特徵提供給下游集成,並且動態組合策略涵蓋了狀態加權平均值迴歸與動量的報告結果。不要用臨時的動量標誌代理來替代其中任何一個。其次,根據樣本內的表現進行選擇,導致獲勝者無法生存;通用機制和 CSCV 防禦是在回測過度擬合的機率 中測量的。堆疊只是該問題的一個較小的例子。

對於加權返回流而不是模型預測,不要重新推導均值方差。 12種投資組合最佳化演算法,比較 與 HRP、HERC、GHRP、MHRP、Black-Litterman、NCO、MVO、風險平價和等權重競賽,並提供測量結果和開源程式碼; SLSQP 均值方差實現;並且 1/N 難以擊敗的結果已經在 HRP/CVaR 投資組合管道 中針對 HRP 和 CVaR 進行了測試。

淨額營業額:值得檢驗的說法

這是 alpha-library 參數的一部分,本部落格的執行成本群集目前未涵蓋。

當 Alpha #4,721 在同一重新平衡中說「買入 MSFT」而 Alpha #8,392 說「賣出 MSFT」時,這些交易會在內部交叉。只有淨頭寸到達市場。據稱,只要有足夠的訊號,預期總營業額的很大一部分就會在產生價差、費用或市場影響之前取消——這意味著一個整體的運作成本比其各個組成部分的總和更便宜,而不僅僅是更穩定。

這是與級聯策略編排 已經處理的機制不同的機制。 Cascade解決了slot級別的衝突:同對、相反方向被禁止並通過分數解決,跨對驅逐通過優先隊列進行,文章通過經驗證明了由於時間重疊和資金限制,每個策略的PnL不能簡單地求和。淨額結算是關於總頭寸與淨額頭寸的算術減少交易數量本身。

偽造的成本也很低:當組合組件訊號時,計算實際填充的總營業額與淨營業額,然後透過現有成本機制進行定價 - maker-taker 費用和回扣實作缺口和 TCA實作缺口和 TCA滑點成本模型

關於規模的註釋,因為阿爾法庫框架邀請它。 WorldQuant 報告已經製作了一個非常大的 alpha 庫,並且 Kakushadze 的 101 Formulaic Alphas記錄各個訊號的形狀。但工業規模的阿爾法採礦也是可以想像到的最大的多重測試機器,本部落格對此的立場已經確定:規模搜索 KK 必須與預期的最佳搜尋規模相比進行縮減。 縮減的夏普比率 顯示 640 個單元格的網格已經突破了樸素的顯著性測試,而誠實的負數 顯示了約 37,000 次試驗DSR 0.00。庫大小並不是優勢的證據。這是您必須支付的分母。

將其放在一起

Raw Data
  |
  v
Feature Engineering
  |
  v
Feature Subsets (partitioned by domain -> decorrelated errors)
  |
  +---> Base Model 1: RF on momentum features
  +---> Base Model 2: GBM on volatility features
  +---> Base Model 3: LSTM on price sequences
  +---> Base Model 4: Lasso on fundamental features
  +---> Base Model 5: XGBoost on microstructure features
  |
  v
Out-of-Fold Predictions (purged walk-forward)
  |
  v
Meta-Learner (Ridge)
  |
  v
Combined Signal -> Net Position -> Execution
  |
  v
DSR >= 0.95 and PBO <= 0.2 gate, or it does not ship

最後一個盒子不是裝飾品。堆疊起來 KK 基本模型是尺寸的選擇過程 KK,而一篇不洩氣的合奏文章是站不住腳的。

要點

  1. **結構差異勝過模型計數。 ** 協方差項不會隨著 NN。加入第六棵相關樹並不是多樣化;而是多樣化。新增不同的模型類別或不相交的特徵域是。
  2. **報告有效-NN 帶,而不是點。 ** 五個估計器,五個答案,有時相差兩個數量級。
  3. **保持元學習器線性。 ** 組合層的複雜性幾乎總是過度擬合,並且那裡的 L1 確實有用的自動模型選擇。
  4. **不合規或什麼都沒有。 **接受過樣本內基礎預測訓練的元學習器會以高置信度學習錯誤的權重。
  5. **縮小整體本身。 ** 堆疊是一種搜尋。定價就像一個。

進一步閱讀:

免責宣告:本文提供的資訊僅用於教育和參考目的,不構成財務、投資或交易建議。加密貨幣交易涉及重大損失風險。

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

緊跟市場步伐

訂閱我們的時事通訊,獲取獨家 AI 交易見解、市場分析和平台更新。

我們尊重您的隱私。您可以隨時退訂。