架構 A:財報選股架構 (Fundamental Selection Framework)¶
核心思想:先算出名單,回測只是執行。
"Calculate the list first, backtest is just execution."
📌 核心概念¶
財報選股架構的本質是「事前計算 + 事後執行」的分離設計:
這種架構最符合真實投資的思考邏輯: - 📊 月底:打開財報資料庫,篩選出符合條件的股票 - 📅 隔月初:照著名單下單
🎯 適用場景¶
✅ 最適合的情境¶
- 基本面選股:本益比、ROE、負債比等財報指標
- 季度調倉:配合財報公告週期(3/6/9/12月)
- 多條件篩選:需要同時檢查 5+ 個財務指標
- 中等規模股票池:50-200 檔股票
❌ 不適合的情境¶
- ❌ 日內交易、高頻策略
- ❌ 純技術指標(MACD、KD 等)
- ❌ 需要即時運算的因子
- ❌ 超大規模市場掃描(>500 檔)
🏗️ 架構特色¶
數據流向圖¶
graph TD
subgraph Outside["⚙️ 回測外運算 (Pre-Backtest)"]
A1[TejToolAPI.get_history_data<br/>抓取完整財報] --> A2[compute_stock 函數<br/>運算選股邏輯]
A2 --> A3[產出 Ticker List<br/>+ 換股日期]
end
subgraph Inside["🔄 回測內執行 (In-Backtest)"]
A3 --> B1[zipline.run_algorithm]
B1 --> B2{handle_data<br/>每日檢查}
B2 -->|是換股日| B3[context.state = True]
B2 -->|不是| B4[持有不動]
B3 --> B5[隔日執行<br/>order_target_percent]
end
style Outside fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
style Inside fill:#fff9c4,stroke:#f57f17,stroke-width:2px
style A2 fill:#ffccbc,stroke:#d84315,stroke-width:2px
關鍵設計理念¶
1. 避免前視偏差 (Look-ahead Bias)¶
# ❌ 錯誤:當天看到訊號就下單
if date == rebalance_date:
order_target_percent(symbol, weight)
# ✅ 正確:標記今天,隔天才下單
if date == rebalance_date:
context.state = True # 標記
context.order_tickers = compute_stock(date)
if context.state == True: # 隔天執行
for ticker in context.order_tickers:
order_target_percent(symbol(ticker), weight)
2. 數據透明化¶
所有篩選邏輯都在 compute_stock() 函數中,方便檢查和調試:
def compute_stock(date, data):
df = data[data['日期'] == date]
# 條件 1: 本益比 < 產業平均
set_1 = set(df[df['本益比'] < df['產業平均本益比']]['股票代碼'])
# 條件 2: 負債比 < 20%
set_2 = set(df[df['負債比'] < 0.2]['股票代碼'])
# 取交集
return list(set_1 & set_2)
3. 靈活的換股週期¶
# 方法 1: 固定日期(每季最後一天)
modified_day = ['2023-03-31', '2023-06-30', '2023-09-30', '2023-12-31']
# 方法 2: 動態計算(TEJ 交易日曆)
trade_days = tejapi.get('TWN/TRADEDAY_TWSE', ...)
last_days = trade_days.groupby(['year', 'quarter'])['date'].max()
📊 與其他架構的差異¶
| 特性 | 財報選股架構 | 技術指標架構 | Pipeline 架構 |
|---|---|---|---|
| 運算時機 | 回測外 | 回測內(每日) | 回測內(盤前) |
| 數據來源 | TEJ 財報 API | Zipline 歷史價格 | CustomDataset |
| 適用股票數 | 50-200 | 1-10 | 500-2000 |
| 調倉頻率 | 季度/月度 | 每日 | 每日/每週 |
| Debug 難度 | 🟢 易 | 🟢 易 | 🔴 難 |
| 執行速度 | 🟢 快 | 🟡 中 | 🟢 極快 |
| 記憶體需求 | 🟢 低 | 🟢 低 | 🔴 高 |
💡 何時選擇這個架構?¶
快速判斷檢查表¶
graph TD
A[你的策略] --> B{數據來自財報?}
B -->|Yes| C{調倉頻率?}
B -->|No| X[考慮技術指標架構]
C -->|季度/月度| D[✅ 財報選股架構]
C -->|每日| E{股票數量?}
E -->|<50檔| D
E -->|>50檔| F[考慮 Pipeline 架構]
style D fill:#c8e6c9,stroke:#388e3c,stroke-width:3px
典型使用案例¶
- ✅ 價值投資策略(低 PB、高股息)
- ✅ 成長股篩選(高 ROE、低負債)
- ✅ 品質因子組合(流動比率、毛利率)
- ✅ Dreman 逆向投資法
🎓 學習路徑¶
新手入門(3 步驟)¶
- 閱讀案例:先看
case-multifactor.md,理解完整流程 - 複製模板:前往
template.md複製骨架 - 填入邏輯:修改
compute_stock()函數
進階優化¶
- 動態換股日計算(TEJ 交易日曆)
- 風險平價配置(非等權重)
- 產業中性化處理
📚 相關資源¶
- 模板頁面:template.md
- 案例學習:
- 多因子選股 - 經典五因子策略
- 小型成長股 - 市值 + 成長因子
- Dreman 逆向投資 - 計分制篩選
- 常見問題:faq.md
⚠️ 常見陷阱¶
陷阱 1:忘記避免前視偏差¶
# ❌ 錯誤示範
if date in rebalance_dates:
tickers = compute_stock(date)
for t in tickers:
order_target_percent(symbol(t), 1/len(tickers)) # 當天就下單!
陷阱 2:日期對不上¶
陷阱 3:數據時間點錯誤¶
👉 Next Step: 前往 template.md 開始開發你的策略!