聊天視窗

從資料到洞察:金融量化交易的系統化方法 - 第 4 章

第四章 模型構建與評估

發布於 2026-02-25 23:27

# 第四章 模型構建與評估 在量化交易中,模型是將市場信號轉化為交易決策的核心。這一章將系統性地說明 1. 監督式學習模型的類型與適用情境。 2. 無監督與半監督方法在資料缺失或非標籤環境下的運用。 3. 交叉驗證、滑動窗口與早停策略的設計。 4. 評估指標與實盤風險的綜合考量。 > **學習目標** > - 掌握主流監督學習模型的優缺點。 > - 理解滑動窗口交叉驗證對時間序列資料的重要性。 > - 能夠根據實盤條件設計適合的評估框架。 --- ## 4.1 監督式學習模型 | 模型 | 主要特徵 | 典型應用 | 優缺點 | |------|----------|----------|--------| | 線性回歸 / Lasso / Ridge | 參數可解釋性高,計算成本低 | 長期均值回歸、基本因子模型 | 受限於線性假設,易受噪聲影響 | | 決策樹 (CART) | 可處理非線性關係,易於解釋 | 事件驅動策略、分類風險 | 易過度擬合,缺乏平滑性 | | 隨機森林 / XGBoost | 高預測準確,抗過擬合 | 量化因子選擇、價格預測 | 參數調整繁瑣,計算成本較高 | | 支持向量機 (SVM) | 能處理高維度資料,核技巧 | 交易信號分類 | 訓練時間長,對噪聲敏感 | | LSTM / Transformer | 處理序列資料,捕捉長期依賴 | 預測收盤價、波動率 | 需要大量資料與GPU,難以解釋 | ### 4.1.1 線性回歸與正則化 python import pandas as pd import statsmodels.api as sm # 假設 df 為已經構造好的特徵表 X = df.drop(columns=['target']) X = sm.add_constant(X) # 加常數項 y = df['target'] model = sm.OLS(y, X).fit() print(model.summary()) - **正則化**:在特徵維度較高時,使用 Lasso(L1)或 Ridge(L2)可防止過擬合。 - **模型診斷**:檢查殘差的自相關(Durbin–Watson 指標)與多重共線性(VIF)。 ### 4.1.2 樹模型與集成方法 python from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) rf = RandomForestRegressor(n_estimators=500, max_depth=10, random_state=42) rf.fit(X_train, y_train) print('Test R^2:', rf.score(X_test, y_test)) - **特徵重要性**:利用 `feature_importances_` 確定關鍵因子。 - **過擬合防止**:調整 `max_depth`、`min_samples_leaf`、`max_features`。 ### 4.1.3 深度學習 python import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset class LSTMModel(nn.Module): def __init__(self, input_dim, hidden_dim, num_layers, output_dim): super().__init__() self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True) self.fc = nn.Linear(hidden_dim, output_dim) def forward(self, x): out, _ = self.lstm(x) out = out[:, -1, :] # 取最後時步 return self.fc(out) # 假設 train_loader 已經準備好 model = LSTMModel(input_dim=10, hidden_dim=64, num_layers=2, output_dim=1) criterion = nn.MSELoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.001) for epoch in range(50): for X_batch, y_batch in train_loader: optimizer.zero_grad() pred = model(X_batch) loss = criterion(pred, y_batch) loss.backward() optimizer.step() print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}') - **時間步長**:根據策略特性調整序列長度。 - **梯度裁剪**:防止梯度爆炸。 ## 4.2 無監督與半監督方法 | 方法 | 目的 | 範例 | |------|------|------| | 主成份分析 (PCA) | 降維、去噪 | 生成交易信號前的特徵投影 | | 聚類 (K‑means, DBSCAN) | 風格識別、策略分群 | 透過風格因子分組優化風險平衡 | | Autoencoder | 雜訊抑制、特徵學習 | 生成可解釋的深度特徵 | | Label‑Propagate | 標籤傳播 | 在缺乏交易訊號的市場區間推斷潛在買賣點 | > **實務提示**:無監督方法多用於策略探索或特徵前處理;若有部分標籤,可考慮半監督,提升模型泛化。 ## 4.3 交叉驗證與滑動窗口 ### 4.3.1 滑動窗口交叉驗證 對於時間序列資料,傳統 K‑fold 會破壞時間順序,導致資訊泄露。滑動窗口交叉驗證(Time‑Series CV)保證歷史資料只能用於訓練。 python from sklearn.model_selection import TimeSeriesSplit tscv = TimeSeriesSplit(n_splits=5, test_size=200, gap=20) for train_idx, test_idx in tscv.split(df): X_train, X_test = X.iloc[train_idx], X.iloc[test_idx] y_train, y_test = y.iloc[train_idx], y.iloc[test_idx] model.fit(X_train, y_train) print('Fold R^2:', model.score(X_test, y_test)) - **gap**:避免緊鄰資料影響。 - **test_size**:根據策略週期選擇。 ### 4.3.2 早停 (Early Stopping) 早停可防止模型在驗證集上過擬合,常見於深度學習與梯度提升。 python best_loss = float('inf') patience = 5 counter = 0 for epoch in range(200): # 訓練迴圈… val_loss = evaluate(model, val_loader) if val_loss < best_loss: best_loss = val_loss torch.save(model.state_dict(), 'best_model.pt') counter = 0 else: counter += 1 if counter >= patience: print('Early stopping at epoch', epoch) break - **patience**:容忍的退化週期數。 - **min_delta**:微小變化是否算退化。 ## 4.4 評估指標與實盤風險 | 指標 | 定義 | 為什麼重要 | |------|------|--------------| | MSE / MAE | 目標預測誤差 | 衡量回歸精度 | | R² / Adjusted R² | 解釋變異比例 | 直觀評估模型優度 | | Sharpe Ratio | 超額報酬 / 風險 | 兼顧收益與波動 | | Information Ratio | 超額報酬 / 追蹤誤差 | 檢測模型對基準的超越 | | Hit Rate | 正確交易比例 | 交易頻率高時較重要 | | Profit Factor | 總獲利 / 總虧損 | 風險承受度指標 | | Max Drawdown | 最大回撤 | 投資者承受程度 | > **實盤注意**:在計算 Sharpe / Information Ratio 時,務必使用扣除交易成本、滑點後的實際報酬。 ## 4.5 模型選擇與部署 | 選擇條件 | 推薦模型 | |----------|----------| | 資料量 < 1M | 線性回歸 + Lasso | 低成本、易調參 | | 風格多變、特徵維度高 | 隨機森林 + 特徵重要性 | 可快速迭代 | | 長期預測需求 | LSTM / Transformer | 捕捉長期依賴 | | 低頻交易 | 樹模型 + 交易成本修正 | 高解釋度 | > **部署流程**: > 1. 先在歷史資料上完成滑動窗口 CV,得到參數。 > 2. 在最新窗口上進行一次「實時」訓練,並保存模型。 > 3. 以微批次(mini‑batch)方式持續更新,確保模型與市場同步。 --- ## 4.6 案例:基於多因子回歸的日內套利模型 1. **資料**:日內 5‑分鐘價格、成交量、技術指標。 2. **特徵**:使用 PCA 先降維,選取前 5 個主成分。 3. **模型**:XGBoost 回歸,預測明日收盤價差。 4. **驗證**:TimeSeriesSplit(n_splits=10),每個測試集 300 筆。 5. **評估**:資訊比率 (IR)、最大回撤、交易成本扣除後的 Sharpe。 python import xgboost as xgb # 1. 準備資料 features = pd.read_csv('features.csv') X = features.drop(columns=['target']) y = features['target'] # 2. 滑動窗口 CV tscv = TimeSeriesSplit(n_splits=10, test_size=300, gap=50) metrics = [] for train_idx, test_idx in tscv.split(features): X_train, X_test = X.iloc[train_idx], X.iloc[test_idx] y_train, y_test = y.iloc[train_idx], y.iloc[test_idx] dtrain = xgb.DMatrix(X_train, label=y_train) dtest = xgb.DMatrix(X_test, label=y_test) params = { 'objective': 'reg:squarederror', 'eval_metric': 'rmse', 'max_depth': 8, 'learning_rate': 0.05, 'n_estimators': 400 } bst = xgb.train(params, dtrain, num_boost_round=400, early_stopping_rounds=30, evals=[(dtest, 'eval')]) preds = bst.predict(dtest) ir = np.corrcoef(preds, y_test)[0, 1] / np.std(y_test - preds) metrics.append({'rmse': bst.best_score, 'ir': ir}) print(metrics) > **結果解讀**:若 IR > 0.6 且 max drawdown < 5%,可視為可行的日內套利策略。 --- ## 4.7 小結 - **模型選擇**:需結合資料量、特徵性質、交易頻率與可解釋性需求。 - **驗證設計**:滑動窗口交叉驗證是避免資訊泄露的關鍵;早停可提升泛化。 - **評估框架**:不僅要看統計指標,還必須考慮交易成本、滑點、持倉風險。 > **實務建議**:在策略上線前,先在歷史上模擬「回測 + 前向驗證」三階段流程;確保每一步都無資訊泄露。 --- ### 延伸閱讀 - 《Python 機器學習實戰》 (黃柏軒, 2021) - 《時序資料機器學習》 (林曉雲, 2019) - 《深度學習與金融市場》 (何智仁, 2020) --- > **操作說明**:此章節已提供完整程式碼,請將其貼至 Jupyter Notebook 或 PyCharm,依據自身資料集進行參數微調與結果驗證。