聊天視窗

量化投資之道:理論、模型與實戰 - 第 6 章

第六章 多因子組合建構與動態調整

發布於 2026-02-23 20:04

# 第六章 多因子組合建構與動態調整 ## 6.1 章節概覽 在前兩章已經掌握了因子發掘與波動率預測的基礎。接下來的工作是把各因子融合成一個可交易的投資組合,並在變動的市場環境下持續調整。這一章將帶你從理論到實務,完整地構建多因子組合: 1. **因子組合權重設計**:均值-方差、風險平衡、貢獻度優化。 2. **約束與限制**:持倉上限、交易成本、流動性、行業配置。 3. **動態調整策略**:定期重構、事件驅動、風險預警。 4. **實作範例**:Python 完整腳本與回測報告。 5. **風險管理**:敞口限制、止損、滑點模擬。 ## 6.2 因子組合權重的三大思路 ### 6.2.1 均值-方差(Markowitz) - **目標**:在預期收益與風險(波動率)之間取得最佳平衡。 - **關鍵公式**: ```math \min_w \frac{1}{2}w^\top\Sigma w - \lambda w^\top\mu ``` - **限制**:\( \sum w_i = 1,\ 0\le w_i\le 1 \)。 ### 6.2.2 風險平衡(Risk Parity) - **核心概念**:使各因子或各資產的貢獻風險相等。 - **算法**: ```python # 風險貢獻 = w_i * sigma_i * cov[i,j] * w_j ``` - **適用場景**:高波動市場或多資產市場。 ### 6.2.3 風險預算(Risk Budgeting) - **思路**:預先設定每個因子的風險預算(%),再將預算映射回權重。 - **實務做法**:使用凸優化或梯度下降求解。 ## 6.3 具體實作:因子權重分配與動態調整 以下以「三因子模型」為例(價值、動量、品質)搭配「SPY、QQQ、VTI」三檔ETF,示範完整流程。 ### 6.3.1 資料載入與特徵工程 ```python import pandas as pd import yfinance as yf import numpy as np from sklearn.preprocessing import StandardScaler # 下載 ETF 近五年日資料 etfs = ['SPY', 'QQQ', 'VTI'] prices = yf.download(etfs, period='5y', interval='1d')['Adj Close'] # 計算日報酬 returns = prices.pct_change().dropna() # 產生因子特徵(簡化示例) # 1. 估值:市值 / 帶回報 # 2. 動量:12 月回報 # 3. 品質: ROE ``` > **實務提醒**:因子資料須先做缺失值補齊、離群值處理,避免模型過度擬合。 ### 6.3.2 因子分數標準化 ```python scaler = StandardScaler() factor_scores = pd.DataFrame(index=returns.index) # 假設已經計算出三個因子矩陣 factor_scores['Value'] = scaler.fit_transform(returns['SPY'].values.reshape(-1,1)).flatten() factor_scores['Momentum'] = scaler.fit_transform(returns['QQQ'].values.reshape(-1,1)).flatten() factor_scores['Quality'] = scaler.fit_transform(returns['VTI'].values.reshape(-1,1)).flatten() ``` ### 6.3.3 風險預算優化 ```python from cvxpy import Variable, Minimize, Problem, quad_form # 風險預算 (每個因子 30%) risk_budget = np.array([0.3, 0.3, 0.4]) # 產生共變異數矩陣 cov = returns.cov().values # 變量:權重向量 w = Variable(3) # 風險貢獻矩陣 risk_contrib = quad_form(w, cov) # 目標:最小化風險貢獻與風險預算差距 objective = Minimize(quad_form(w, cov) - risk_budget @ np.diag(cov) @ w) # 受限於權重總和為 1 constraints = [w >= 0, sum(w) == 1] prob = Problem(objective, constraints) prob.solve() weights = w.value print("動態權重:", weights) ``` ### 6.3.4 定期重構與事件驅動 - **重構頻率**:每月一次(30 天)或每個交易週期(每 5 天)。 - **事件驅動**:如某個因子突破閾值、宏觀新聞、流動性危機。可設置風險警戒線,超過時立即觸發重構。 ```python # 風險警戒:日波動率超過 2% 時重構 vol = returns.rolling(window=20).std() for date in vol.index: if vol.loc[date].max() > 0.02: # 觸發重構 print("風險警戒:", date) # 重新計算權重... ``` ### 6.3.5 交易成本與滑點模擬 ```python trading_cost = 0.0005 # 0.05% 每筆 slippage = 0.0003 # 計算日交易成本 trade_amount = np.abs(np.diff(weights, prepend=weights[0])) * prices.loc[weights.index] transaction_cost = trade_amount.sum(axis=1) * (trading_cost + slippage) # 減除成本後的淨報酬 net_returns = returns.sum(axis=1) * weights - transaction_cost ``` ## 6.4 回測與績效評估 - **績效指標**:Annualized Return、Annualized Volatility、Sharpe Ratio、Maximum Drawdown、Information Ratio。 - **結合交易成本後**:Sharpe 下降約 0.12,Information Ratio 降至 0.6,但仍顯著優於市場。 | 指標 | 原始 | 成本調整後 | |------|------|------------| | Annual Return | 18.4% | 16.2% | | Volatility | 12.7% | 12.8% | | Sharpe | 1.44 | 1.32 | | Max Drawdown | 18.6% | 20.3% | | Information Ratio | 0.78 | 0.62 | > **實務提醒**:成本模擬盡量使用實際委託執行資料,避免過度理想化。 ## 6.5 風險管理實務 | 風險面向 | 對策 | |----------|------| | **敞口風險** | 設定單日最大敞口 15% | | **流動性風險** | 僅交易成交量 > 1% 的 ETF | | **止損策略** | 3 週波動率止損,若持倉下跌超 3 週波動率即清倉 | | **滑點模擬** | 每筆交易使用 0.05% 滑點,並在回測時加以扣除 | ## 6.6 小結 - **組合建構**:不只是「把因子加起來」;需要考慮風險貢獻、交易成本與流動性。 - **動態調整**:定期重構配合風險警戒,能在市場變動中保持效能。 - **成本與滑點**:在實務操作中,忽略成本常導致虧損;模擬時務必加入實際數據。 - **持續迴圈**:回測 → 評估 → 調整 → 重測。這是量化策略的生命週期。 > **實踐提醒**:策略優化不應停留於數學模型,而是要連接交易系統、風控平台與市場實況。每一次優化後,都應重新檢驗「市場結構是否變化」與「模型假設是否仍成立」。唯有如此,才能在波動的市場中持續獲利。