返回目錄
A
量化投資策略:理論到實踐的全景指南 - 第 5 章
第5章 機器學習在交易中的應用
發布於 2026-03-03 06:02
# 第5章 機器學習在交易中的應用
本章聚焦於**機器學習**(ML)在量化交易中的實際運用。\n
從監督式學習(回歸、分類、特徵工程)到無監督式學習(聚類、PCA),再到強化學習(RL)與自動交易系統,我們將逐步剖析理論基礎、實務實作與風險控制,並提供完整的程式碼範例與部署建議。
---
## 5.1 監督式學習
監督式學習的核心是「有標籤」資料:\n- **特徵(X)**:代表市場狀態的數值或向量。\n- **目標(y)**:預測的值(回歸)或類別(分類)。\n
### 5.1.1 回歸
| 目的 | 典型模型 | 評估指標 |
|------|----------|----------|
| 價格預測 | Linear Regression, RandomForestRegressor, XGBoostRegressor | MAE / RMSE |
| 波動率預測 | ARIMA + ML, GARCH + ML | RMSE, MAPE |
#### 範例:使用 XGBoost 進行日內價格回歸
python
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import TimeSeriesSplit, cross_val_score
# 讀取 OHLCV 資料
price_df = pd.read_csv('data/stock_A_daily.csv', parse_dates=['date'], index_col='date')
# 特徵工程:技術指標
price_df['MA_5'] = price_df['close'].rolling(5).mean()
price_df['MA_20'] = price_df['close'].rolling(20).mean()
price_df['RSI'] = ta.momentum.RSIIndicator(price_df['close'], window=14).rsi()
price_df['vol_change'] = price_df['volume'].pct_change()
price_df.dropna(inplace=True)
X = price_df[['MA_5', 'MA_20', 'RSI', 'vol_change']]
y = price_df['close'].shift(-1).dropna()
X = X.iloc[:-1]
model = xgb.XGBRegressor(n_estimators=500, learning_rate=0.05, max_depth=4)
tscv = TimeSeriesSplit(n_splits=5)
rmse_scores = -cross_val_score(model, X, y, cv=tscv, scoring='neg_root_mean_squared_error')
print('RMSE (10% CV):', rmse_scores.mean())
### 5.1.2 分類
| 目的 | 典型模型 | 評估指標 |
|------|----------|----------|
| 方向預測 | Logistic Regression, SVM, Gradient Boosting, LSTM | Accuracy, F1, ROC‑AUC |
| 事件預測 | RandomForestClassifier, CatBoost, XGBoost | Precision, Recall |
#### 範例:方向預測(漲跌)
python
import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
# 讀取資料
df = pd.read_csv('data/stock_A_daily.csv', parse_dates=['date'], index_col='date')
# 產生目標:1 為漲,0 為跌
prev_close = df['close'].shift(1)
df['target'] = (df['close'] > prev_close).astype(int)
# 特徵:技術指標
for window in [5, 10, 20]:
df[f'MA_{window}'] = df['close'].rolling(window).mean()
df[f'RSI_{window}'] = ta.momentum.RSIIndicator(df['close'], window=window).rsi()
df[f'Stdev_{window}'] = df['close'].rolling(window).std()
# 填補缺失
df.dropna(inplace=True)
X = df[[f'MA_{w}' for w in [5,10,20]] + [f'RSI_{w}' for w in [5,10,20]] + [f'Stdev_{w}' for w in [5,10,20]]]
y = df['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
clf = RandomForestClassifier(n_estimators=300, max_depth=8, random_state=42)
clf.fit(X_train, y_train)
pred = clf.predict(X_test)
print(classification_report(y_test, pred))
### 5.1.3 特徵工程
| 步驟 | 目的 | 常用技術 |
|------|------|-----------|
| 缺失處理 | 防止模型崩潰 | 均值/中位數/插值 |
| 標準化 | 促進收斂 | StandardScaler, MinMaxScaler |
| 交互項 | 捕捉非線性關係 | PolynomialFeatures, InteractionTerm |
| 變數選擇 | 降維 + 提升穩定性 | Lasso, Ridge, Tree‑based feature importance |
| 時間序列特徵 | 捕捉趨勢 | Lag features, rolling aggregates |
> **實務提示**:對於時間序列,**不要**在訓練資料中使用未來資訊(Look‑ahead Bias)。
---
## 5.2 無監督式學習
無監督式學習不需要目標變數,常用於 **市場分段、異常偵測** 或 **特徵降維**。
### 5.2.1 聚類(Clustering)
| 方法 | 適用場景 | 優點 |
|------|----------|------|
| K‑Means | 股票群組、資產分級 | 直觀、快速 |
| DBSCAN | 异常偵測、密度聚類 | 免需指定 k |
| GMM | 需求概率分布 | 可輸出成分隱含概率 |
#### 範例:使用 K‑Means 進行股票風格分類
python
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
# 讀取多支股票的因子資料
factors = pd.read_csv('data/factors.csv')
# 因子:市值、ROE、PE、PB、Beta
X = factors[['market_cap', 'roe', 'pe', 'pb', 'beta']]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
kmeans = KMeans(n_clusters=4, random_state=42)
labels = kmeans.fit_predict(X_scaled)
factors['style_cluster'] = labels
print(factors.groupby('style_cluster').mean())
### 5.2.2 主成分分析(PCA)
| 目的 | 優點 |
|------|------|
| 降維 | 降低維度、消除多重共線 |
| 特徵提取 | 抽取最具信息量的組合 |
| 噪聲抑制 | 去除高頻噪音 |
#### 範例:對日內行情進行 PCA
python
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
# 讀取日內 5 分鐘資料
df = pd.read_csv('data/stock_A_intraday.csv')
# 取收盤價、成交量、波動幅度
X = df[['close', 'volume', 'high_low_diff']]
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
pca = PCA(n_components=2)
principal = pca.fit_transform(X_scaled)
print('Explained variance:', pca.explained_variance_ratio_)
---
## 5.3 強化學習與自動交易系統
強化學習(RL)適合**動態決策**問題:在不斷變化的市場中學習最佳行動策略。\n典型架構:
- **Agent**:策略模型(如 DQN、PPO)。\n- **Environment**:市場模擬器(帶有交易成本、滑點)。\n- **Reward**:日常收益、風險調整後的獎勵。\n
### 5.3.1 RL 基礎
| 參數 | 含義 |
|------|------|
| State | 當前市場狀態(價格、技術指標、持倉)。 |
| Action | 交易指令(買、賣、持有或多頭、空頭幅度)。 |
| Reward | 交易收益(扣除手續費、滑點)。 |
| Policy | 取樣行動的機率分佈(π)。 |
| Value | 估計未來獲得獎勵的價值(V)。 |
#### 範例:簡易 DQN 訓練流程(伪代码)
python
import numpy as np
import gym
import torch
import torch.nn as nn
import torch.optim as optim
# 1. 建立環境
class StockEnv(gym.Env):
def __init__(self, data, window_size):
self.data = data
self.window_size = window_size
self.action_space = gym.spaces.Discrete(3) # 0: sell, 1: hold, 2: buy
self.observation_space = gym.spaces.Box(low=-np.inf, high=np.inf, shape=(window_size, 5))
self.reset()
def reset(self):
self.idx = self.window_size
return self._get_state()
def step(self, action):
reward = self._calculate_reward(action)
self.idx += 1
done = self.idx >= len(self.data) - 1
return self._get_state(), reward, done, {}
# ... (implement _get_state, _calculate_reward) ...
# 2. 建立 Q‑network
class QNet(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.fc = nn.Sequential(
nn.Linear(state_dim, 128), nn.ReLU(),
nn.Linear(128, 64), nn.ReLU(),
nn.Linear(64, action_dim)
)
def forward(self, x):
return self.fc(x)
# 3. 訓練迴圈
env = StockEnv(data, window_size=20)
q_net = QNet(state_dim=20*5, action_dim=3)
optimizer = optim.Adam(q_net.parameters(), lr=1e-3)
criterion = nn.MSELoss()
for episode in range(200):
state = env.reset()
total_reward = 0
done = False
while not done:
state_tensor = torch.FloatTensor(state).unsqueeze(0)
q_values = q_net(state_tensor)
action = torch.argmax(q_values).item() # ε‑greedy 可自行加入
next_state, reward, done, _ = env.step(action)
# 計算 TD 目標
next_q = q_net(torch.FloatTensor(next_state).unsqueeze(0)).max(1)[0].detach()
target = reward + 0.99 * next_q
loss = criterion(q_values[0, action], target)
optimizer.zero_grad(); loss.backward(); optimizer.step()
state = next_state
total_reward += reward
print(f'Episode {episode}, Total Reward: {total_reward}')
> **部署建議**:將已訓練模型封裝成 REST API,利用 **Docker** + **Kubernetes** 進行水平擴展,確保實時低延遲。\n> **風險控制**:在策略部署前,務必將策略塞進「沙盒」環境,進行「walk‑forward」回測與「風險因子測試」。
### 5.3.2 自動交易系統框架
| 組件 | 作用 |
|------|------|
| 資料源 | 市場行情、基本面、新聞情緒 |
| 資料倉儲 | Time‑Series DB(如 kdb+, InfluxDB) |
| 計算層 | 風險模型、策略回測、模型評估 |
| 執行層 | 交易接口(FIX、REST、WebSocket) |
| 監控層 | 風險監控、性能監控、合規報告 |
#### 案例:使用 Zipline + Catalyst 進行自動化交易
python
# zipline_backtest.py
from zipline.api import (order_target_percent, record, symbol, get_datetime)
import pandas as pd
def initialize(context):
context.security = symbol('AAPL')
context.target = 0.5
def handle_data(context, data):
price = data.current(context.security, 'price')
# 簡單均線交叉策略
sma_short = data.history(context.security, 'price', bar_count=20, frequency='1d').mean()
sma_long = data.history(context.security, 'price', bar_count=50, frequency='1d').mean()
if sma_short > sma_long:
order_target_percent(context.security, context.target)
else:
order_target_percent(context.security, -context.target)
record(price=price)
if __name__ == '__main__':
start = pd.Timestamp('2015-01-01', tz='utc')
end = pd.Timestamp('2020-12-31', tz='utc')
from zipline import run_algorithm
run_algorithm(start=start, end=end, initialize=initialize,
capital_base=100000, handle_data=handle_data)
---
## 5.4 風險與效能考量
| 觀點 | 建議 |
|------|------|
| **過擬合** | 使用時間序列 CV、早停、參數正則化 |
| **資料偏差** | 避免回測期間的資料泄露,加入交易成本、滑點 |
| **計算成本** | 將模型分層:特徵工程(CPU)、模型推論(GPU) |
| **監控** | 監控策略收益、持倉、滑點、回撤;實時報警 |
| **合規** | 日誌完整、交易行為可審計;遵守交易所規範 |
---
## 5.5 小結
- **監督式學習** 主要解決「價格/波動率預測」與「方向判斷」;重點是高品質特徵與嚴謹的評估。\n- **無監督式學習** 可協助市場分段、異常偵測與特徵降維,減少模型輸入維度。\n- **強化學習** 適用於需動態調整頭寸的策略,關鍵是構建真實且公平的環境、設計合理的 reward。\n- **部署** 必須考慮 **延遲、可擴展性** 與 **風險控制**;使用 Docker、K8s、API Gateway 可實現高可用。\n- **風險與效能** 的持續監控是長期成功的關鍵,策略須在真實交易前經過多層驗證與風險限額檢查。
> **提示**:在實際交易前,先在「沙盒」環境進行「walk‑forward」回測,再逐步擴大投資規模;任何機器學習模型都可能隨市場演化而失效,持續更新與重訓是必要的。