模組 11:策略開發完全指南從零開始寫你的第一個交易策略
NautilusTrader 的策略開發遵循一個簡單的模式: 繼承基類 → 實現回調 → 填入邏輯。這個模組會教你從零開始寫出完整的交易策略。
❌ 如果自己從零寫交易邏輯:你需要自己處理數據訂閱、訂單管理、持倉追蹤、日誌記錄、風控對接… 至少 2000 行代碼才能做到 Strategy 基類免費給你的功能。
✅ 用 Strategy 基類:你只需要關心「什麼時候買、什麼時候賣」。其餘的基礎設施(緩存、消息總線、訂單工廠、Portfolio 查詢)全部自動注入。
一、Strategy 基類 — 你的策略框架
所有策略都繼承自 Strategy 基類。它提供了完整的「腳手架」,你只需要填入交易邏輯:
flowchart LR
subgraph lifecycle["🔄 策略生命週期"]
direction TB
init["__init__<br/>初始化配置和指標"]
start["on_start()<br/>訂閱數據、初始化邏輯"]
running["運行中"]
stop["on_stop()<br/>清理資源、平倉"]
init --> start --> running --> stop
end
subgraph callbacks["📡 事件回調 (運行中)"]
direction TB
on_bar["on_bar(bar)"]
on_quote["on_quote_tick(tick)"]
on_trade["on_trade_tick(tick)"]
on_filled["on_order_filled(event)"]
end
running ==> callbacks
style lifecycle fill:#0f1419,stroke:#4fc3f7,stroke-width:1px
style callbacks fill:#0f1419,stroke:#ab47bc,stroke-width:1px
二、策略模板 — 最小可運行策略
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.config import StrategyConfig
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.model.data import Bar, BarType
class MyStrategyConfig(StrategyConfig, frozen=True):
"""策略配置 — 所有可調參數放這裡"""
instrument_id: InstrumentId
bar_type: BarType
fast_ema_period: int = 10
slow_ema_period: int = 20
class MyStrategy(Strategy):
"""你的策略 — 填入交易邏輯"""
def __init__(self, config: MyStrategyConfig):
super().__init__(config)
# 保存配置
self.instrument_id = config.instrument_id
self.bar_type = config.bar_type
# 初始化指標
self.fast_ema = ExponentialMovingAverage(config.fast_ema_period)
self.slow_ema = ExponentialMovingAverage(config.slow_ema_period)
def on_start(self):
"""策略啟動時調用 — 訂閱數據"""
# 訂閱 K 線數據
self.subscribe_bars(self.bar_type)
# 記錄日誌
self.log.info("策略已啟動")
def on_bar(self, bar: Bar):
"""收到新 K 線時調用 — 核心交易邏輯"""
# 更新指標
self.fast_ema.update_raw(bar.close.as_double())
self.slow_ema.update_raw(bar.close.as_double())
# 等指標準備好
if not self.fast_ema.initialized:
return
# ===== 交易邏輯 =====
# 快線上穿慢線 → 買入
if self.fast_ema.value > self.slow_ema.value:
if self.portfolio.is_flat(self.instrument_id):
self._buy()
# 快線下穿慢線 → 賣出
elif self.fast_ema.value < self.slow_ema.value:
if self.portfolio.is_net_long(self.instrument_id):
self._sell()
def _buy(self):
"""建立多頭持倉"""
order = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=Quantity.from_str("0.01"),
)
self.submit_order(order)
def _sell(self):
"""平掉多頭持倉"""
order = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.SELL,
quantity=Quantity.from_str("0.01"),
)
self.submit_order(order)
def on_order_filled(self, event):
"""訂單成交回調"""
self.log.info(f"訂單成交: {event}")
def on_stop(self):
"""策略停止時調用 — 清理"""
self.cancel_all_orders(self.instrument_id)
self.close_all_positions(self.instrument_id)
self.log.info("策略已停止")
不到 80 行代碼,你就擁有了一個完整的 EMA 交叉策略:有配置、有指標、有交易邏輯、有風控(透過全局 RiskEngine)。同樣的代碼可以直接用在回測和實盤中。
三、核心回調方法一覽
| 回調方法 | 觸發時機 | 常用操作 |
|---|---|---|
on_start() | 策略啟動 | 訂閱數據、載入歷史指標值 |
on_stop() | 策略停止 | 取消訂單、平倉 |
on_bar(bar) | 收到新 K 線 | 更新指標、判斷開平倉 |
on_quote_tick(tick) | 收到新報價 | 觀察買賣價差 |
on_trade_tick(tick) | 收到新成交 | 觀察成交量和方向 |
on_order_filled(event) | 訂單成交 | 記錄日誌、調整持倉 |
on_order_rejected(event) | 訂單被拒 | 記錄錯誤、重試 |
on_order_canceled(event) | 訂單被取消 | 清理掛單記錄 |
on_position_opened(event) | 新持倉建立 | 設置止損 |
on_position_closed(event) | 持倉關閉 | 記錄盈虧 |
on_event(event) | 任何事件 | 通用事件處理 |
四、指標系統
NautilusTrader 內建了豐富的技術指標:
| 類別 | 指標 |
|---|---|
| 趨勢 | EMA, SMA, WMA, DEMA, TEMA, KAMA, HMA |
| 動量 | RSI, MACD, Stochastic, CCI, ROC, Williams %R |
| 波動率 | ATR, Bollinger Bands, Keltner Channel, Donchian |
| 成交量 | OBV, VWAP, MFI, AD |
| 統計 | Standard Deviation, Variance, Linear Regression |
# 使用指標的三步曲
# 1. __init__ 中建立
self.rsi = RelativeStrengthIndex(period=14)
# 2. on_bar 中更新
self.rsi.update_raw(bar.close.as_double())
# 3. 讀取值
if self.rsi.initialized and self.rsi.value > 70:
# RSI 超買 → 考慮賣出
pass四B、Actor vs Strategy — 什麼時候該用哪個?
❌ 如果把所有邏輯都塞進 Strategy:你的策略會變成「超級大類」,既做數據處理又做交易決策。難以測試、難以複用。
✅ 用 Actor + Strategy:Actor 負責「觀察和計算」(如生成信號),Strategy 負責「交易」。它們之間用 MessageBus 通訊,完全解耦。
| 特性 | Actor | Strategy |
|---|---|---|
| 能訂閱數據 | ✅ | ✅ |
| 能下單 | ❌ | ✅ |
| 有 order_factory | ❌ | ✅ |
| 有 portfolio 訪問 | ✅(唯讀) | ✅ |
| 典型用途 | 信號生成、數據處理、監控 | 交易邏輯、訂單管理 |
"""Actor → Strategy 協作範例:信號生成器 + 交易執行器"""
from nautilus_trader.common.actor import Actor
from nautilus_trader.common.signal import Signal
class SignalGenerator(Actor):
"""Actor:只生成信號,不做交易"""
def on_bar(self, bar: Bar):
rsi = self._calculate_rsi(bar)
if rsi < 30:
# 發布「建議買入」信號到 MessageBus
self.publish_signal(name="BUY", value=rsi)
elif rsi > 70:
self.publish_signal(name="SELL", value=rsi)
class TradeExecutor(Strategy):
"""Strategy:接收信號並執行交易"""
def on_start(self):
self.subscribe_signal(name="BUY")
self.subscribe_signal(name="SELL")
def on_signal(self, signal: Signal):
if signal.name == "BUY" and self.portfolio.is_flat(self.instrument_id):
self._buy()
elif signal.name == "SELL" and self.portfolio.is_net_long(self.instrument_id):
self._sell()四C、OrderFactory — 進階下單模式
self.order_factory 是你在策略中下單的唯一工具。它能創建所有 9 種訂單,這裡展示最實用的幾個模式:
模式 1:Bracket Order(括號訂單 = 入場 + 止損 + 止盈)
"""一次下三個訂單:市價入場 + 止損 + 止盈"""
from nautilus_trader.model.orders import OrderList
def _open_position_with_bracket(self):
# OrderList 把三個訂單綁在一起
bracket = self.order_factory.bracket(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=Quantity.from_str("0.01"),
# 入場用市價單
entry_trigger_price=None, # 市價入場
# 止損設在入場價下方 2%
sl_trigger_price=Price.from_str("49000.00"),
# 止盈設在入場價上方 4%
tp_price=Price.from_str("52000.00"),
)
# 一次提交整個 bracket
self.submit_order_list(bracket)
# 當入場單成交後,止損和止盈自動啟動
# 當止損或止盈任一觸發,另一個自動取消(OCO)模式 2:Trailing Stop(移動止損)
"""用 ATR 動態計算止損距離"""
def _set_trailing_stop(self):
atr_value = self.atr.value # ATR 指標的當前值
order = self.order_factory.trailing_stop_market(
instrument_id=self.instrument_id,
order_side=OrderSide.SELL, # 賣出止損
quantity=Quantity.from_str("0.01"),
# 止損距離 = 2 倍 ATR
trailing_offset=Decimal(str(atr_value * 2)),
trailing_offset_type=TrailingOffsetType.PRICE,
trigger_type=TriggerType.LAST_TRADE,
)
self.submit_order(order)
# 價格上漲時,止損價跟著上移
# 價格下跌超過 2×ATR 時,觸發止損五、官方範例策略解讀
NautilusTrader 附帶了 17 個官方範例策略,涵蓋各種交易模式。以下是精選的 5 個最有學習價值的:
ema_cross.py
EMA 交叉策略
最基礎的趨勢跟蹤策略。快 EMA 上穿慢 EMA 做多,反之做空。學習策略基本結構的最佳起點。
ema_cross_bracket.py
EMA 交叉 + 括號訂單
在 EMA 交叉基礎上加入止損止盈(Bracket Order),展示條件單組合的使用。
ema_cross_trailing_stop.py
移動止損策略
使用 ATR 指標動態計算止損距離,展示如何用移動止損鎖定利潤。
orderbook_imbalance.py
訂單簿失衡策略
基於訂單簿買賣壓力失衡做交易。展示如何使用 Level 2 數據。
market_maker.py
做市商策略
在買賣兩側掛單賺取價差。展示高頻交易和庫存管理的基本邏輯。
六、策略開發最佳實踐
配置分離
所有可調參數放在 StrategyConfig 中,不要硬編碼在策略內。方便回測時進行參數優化。
等待指標初始化
在 on_bar() 中,必須檢查 indicator.initialized,否則前幾根 K 線的指標值是不準確的。
記錄充分日誌
用 self.log.info() 記錄關鍵決策點。回測時可以回顧每一個交易決策的原因。
on_stop() 清理
策略停止時務必取消所有掛單和平倉。避免殘留訂單在沒有監控的情況下執行。
檢查持倉再下單
下單前先用 self.portfolio.is_flat() 檢查持倉狀態,避免重複加倉。
使用訂單工廠
始終用 self.order_factory 創建訂單,它會自動生成唯一的 ClientOrderId 和正確的 StrategyId。
七、互動練習
設計一個基於 RSI 的策略:RSI > 70 時賣出(超買),RSI < 30 時買入(超賣)。列出你需要的回調方法和邏輯流程。
需要的結構:
__init__: 建立 RSI 指標(period=14)on_start: 訂閱 K 線數據on_bar:- 更新 RSI:
self.rsi.update_raw(bar.close.as_double()) - 檢查初始化:
if not self.rsi.initialized: return - RSI < 30 且無持倉 →
self._buy() - RSI > 70 且有多頭持倉 →
self._sell()
- 更新 RSI:
on_order_filled: 記錄成交日誌on_stop: 取消所有訂單、平倉
💡 額外加分:
- 加入 ATR 計算止損距離
- RSI 從超賣區回升(穿過 30)時才買入
- 設置最大持倉限制
以下策略代碼有 3 個錯誤,你能找到嗎?
class BuggyStrategy(Strategy):
def __init__(self, config):
self.ema = ExponentialMovingAverage(20) # 🤔 錯誤 1
def on_start(self):
self.subscribe_bars(self.config.bar_type)
def on_bar(self, bar: Bar):
self.ema.update_raw(bar.close) # 🤔 錯誤 2
if self.ema.value > bar.close.as_double():
self._buy()
def _buy(self):
order = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=Quantity.from_str("0.01"),
)
self.submit_order(order) # 🤔 錯誤 3(邏輯問題)❌ 錯誤 1: 缺少 super().__init__(config)
- 沒有初始化父類,
self.cache,self.log等全部不可用 - ✅ 正確: 加上
super().__init__(config)
❌ 錯誤 2: bar.close 是 Price 對象,不是 float
update_raw()需要float- ✅ 正確:
self.ema.update_raw(bar.close.as_double())
(這個寫對了一半:as_double()需要加括號)
❌ 錯誤 3: 沒有檢查持倉狀態就下單
- 每根 K 線都會觸發買入,越買越多
- ✅ 正確: 先檢查
if self.portfolio.is_flat(self.instrument_id)
以下場景,你應該用 Actor 還是 Strategy?
- 你想持續監控 BTC 和 ETH 的價差,當價差超過閾值時記錄日誌
- 你想根據 RSI 信號自動買賣
- 你想從外部 API 獲取情緒數據並廣播到系統中
- 你想做一個統計套利策略,同時在兩個品種上下單
- Actor ← 只是觀察和記錄,不需要下單
- Strategy ← 需要下單
- Actor ← 數據處理和廣播,不涉及交易
- Strategy ← 需要在多個品種上下單
需要下單 → Strategy
不需要下單 → Actor
八、本模組重點回顧
- Strategy 基類提供完整的框架,你只需填入邏輯
- 生命週期:init → on_start → 運行(回調)→ on_stop
- 事件回調:on_bar、on_quote_tick、on_order_filled 等
- 指標系統:30+ 內建指標,三步使用
- 最佳實踐:配置分離、等待初始化、記錄日誌、停止時清理
- 官方範例:從 ema_cross.py 開始學習