第四階段:進階擴展

模組 17:進階主題序列化、核心底層、期權定價 — 為專家準備的最後拼圖

一、高效序列化 (Serialization)

NautilusTrader 對性能的極致追求不僅體現在計算上,也體現在數據存儲和傳輸上。框架支持多種序列化格式:

格式特點適用場景Nautilus 用途
msgspec (JSON)極快、人類可讀配置文件、API 接口config.py 中的配置對象
Parquet / Arrow列式存儲、壓縮率極高海量歷史數據DataCatalog、行情數據存儲
MessagePack二進制 JSON、緊湊即時通訊Redis 消息總線傳輸
💡 為什麼不用 Python 的 pickle?

❌ pickle:慢、不安全(可執行任意代碼)、跨語言支持差。

✅ msgspec / Arrow:比 pickle 快 10-100 倍,且支持 Rust/C++ 互操作,完美契合 Nautilus 的 Rust 內核。

二、系統核心 (System Kernel)

Module 02 介紹過架構,這裡我們深入 kernel.py 的啟動流程:

sequenceDiagram
                        participant User
                        participant Node as TradingNode
                        participant Kernel
                        participant Engines

                        User->>Node: node.run()
                        Node->>Kernel: kernel.run()
                        Kernel->>Engines: 1. 啟動所有 Engines (Data/Exec/Risk)
                        Kernel->>Engines: 2. 連接適配器 (Connect)
                        Kernel->>Engines: 3. 初始化緩存 (Initialize Cache)
                        Kernel->>Engines: 4. 恢復狀態 (Load State)
                        Kernel->>Engines: 5. 啟動策略 (Start Strategies)
                        Note over Kernel: 進入事件循環 (Event Loop)
                        User->>Node: node.stop()
                        Kernel->>Engines: 6. 停止策略
                        Kernel->>Engines: 7. 保存狀態
                        Kernel->>Engines: 8. 斷開連接
                        Kernel->>Engines: 9. 關閉引擎
圖 1:Kernel 的完整生命週期

三、Tick Scheme — 最小跳動規則

不同交易所對價格和數量有嚴格的限制。TickScheme 類負責處理這些規則:

from nautilus_trader.model.instruments import Instrument
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.model.objects import Price, Quantity

# 獲取品種的 Tick Scheme
instrument: Instrument = ...
tick_scheme = instrument.tick_scheme

# 1. 價格調整(Rounding)
raw_price = Price.from_str("100.123456")
valid_price = tick_scheme.round_price(raw_price)
# 結果可能是 100.12 (如果 tick size 是 0.01)

# 2. 數量調整
raw_qty = Quantity.from_str("0.001234")
valid_qty = tick_scheme.round_quantity(raw_qty)
# 結果可能是 0.001 (如果 step size 是 0.001)

# 3. 檢查是否有效
if not tick_scheme.is_valid_price(raw_price):
    print("價格無效!請修正")
⚠️ 實盤拒單常見原因

很多「Invalid Order」錯誤都是因為價格或數量沒有符合 Tick Scheme。NautilusTrader 的 OrderFactory 通常會自動處理這些,但如果你手動構建訂單,務必使用 round_price / round_quantity。

四、Greeks — 期權定價

NautilusTrader 內置了 Black-Scholes 模型用於計算期權的理論價格和 Greeks:

from nautilus_trader.model.greeks import calculate_greeks
from nautilus_trader.model.enums import OptionType

# 計算 Greeks
greeks = calculate_greeks(
    price_underlying=100.0,
    price_strike=105.0,
    time_to_expiry=30/365,   # 年化時間
    risk_free_rate=0.05,     # 無風險利率 5%
    volatility=0.20,         # 波動率 20%
    option_type=OptionType.CALL,
)

print(f"Delta: {greeks.delta}")
print(f"Gamma: {greeks.gamma}")
print(f"Theta: {greeks.theta}")
print(f"Vega:  {greeks.vega}")
print(f"Rho:   {greeks.rho}")

五、Custom Data Types — 自定義數據流

除了標準的 Bar 和 Quote,你還可以定義自己的數據類型(如鏈上數據、社交情緒數據):

1. 定義數據類

from dataclasses import dataclass
from nautilus_trader.model.data import Data

@dataclass(frozen=True)
class SentimentData(Data):
    sentiment_score: float
    source: str

    @property
    def ts_event(self) -> int:
        return self._ts_event

    @property
    def ts_init(self) -> int:
        return self._ts_init

2. 在策略中訂閱

class SentimentStrategy(Strategy):
    def on_start(self):
        # 訂閱自定義數據類型
        self.subscribe_data(
            data_type=SentimentData,
            instrument_id=self.instrument_id,
        )

    def on_data(self, data: Data):
        if isinstance(data, SentimentData):
            self.log.info(f"收到情緒數據: {data.sentiment_score}")
            if data.sentiment_score > 0.8:
                self.buy()

六、互動練習

🧠 練習 1:Tick Size 陷阱

某品種 tick_size = 0.5。你計算出的掛單價格是 100.2。直接下單會發生什麼?你應該如何修正?

直接下單後果:

  • ❌ 交易所會拒絕訂單(REJECTED),錯誤信息可能是 “Invalid Price Precision” 或 “Price not multiple of tick size”。

修正方法:

  • ✅ 使用 tick_scheme.round_price(Price(100.2))
    結果會是 100.0 (向下取整) 或 100.5 (向上取整),取決於 rounding 規則。

在策略中:

price = self.instrument.tick_scheme.round_price(calculated_price)
self.order_factory.limit(...)
🧠 練習 2:Kernel 啟動順序

為什麼 Kernel 必須先 “Connect” 再 “Load State” 最後才 “Start Strategies”?

  1. Connect (連接適配器):
    必須先連上交易所/數據源,才能接收後續的數據。
  2. Load State (恢復狀態):
    必須在策略啟動前恢復之前的持倉和訂單。如果在策略啟動後才恢復,策略可能會根據錯誤的(空的)狀態做出交易決策。
  3. Start Strategies (啟動策略):
    最後一步。確保所有連接就緒、狀態已恢復、緩存已預熱,策略一旦啟動就能立即處理實時數據,不會因為狀態缺失而出錯。
🧠 練習 3:自定義數據應用

你想用「Google 搜索趨勢」來做 BTC 交易。請描述需要的組件。

架構設計:

  1. 數據類型 (Data Type):
    定義 GoogleTrendData(keyword, index, ts_event)
  2. 數據適配器 (Data Client):
    • 寫一個 CustomDataClient,定期調用 Google Trends API
    • 將 API 返回的 JSON 轉換為 GoogleTrendData 對象
    • 發送到 MessageBus
  3. 策略 (Strategy):
    • subscribe_data(GoogleTrendData)
    • 在 on_data 中處理:
      if index > 80: buy()
      elif index < 20: sell()

七、Phase 2 總結

恭喜完成 Phase 2!你現在已經掌握了 NautilusTrader 的深層機制:

🎉 你學會了什麼
  1. 配置系統:如何精確控制系統的每一個參數
  2. 實盤穩健性:用對帳、重試、控制器打造不倒翁系統
  3. 資金與風控:精確計算每一分錢,設置多層風控網
  4. 底層機制:序列化、內核流程、Greeks、自定義數據擴展