对于 Python 学习者来说,量化交易是一个既有挑战又充满机遇的领域。今天,我要向大家介绍一个强大的量化交易框架——Nautilus Trader,它能够让我们快速构建、回测和部署交易策略。本文将通过一个简单的 MACD 策略实例,带你了解如何使用 Nautilus Trader 进行回测,从而开启你的量化交易之旅。

Nautilus Trader 是什么?

Nautilus Trader 是一个高性能的交易框架,具有以下优势:

  • 可以轻松将外部数据转换为其内部格式

  • 能够以最小的改动从回测切换到实盘交易

  • 设计为高性能架构,甚至支持高频交易

  • 适合小型到中型团队快速研发和部署交易策略

不过需要注意的是,这个框架并不适合简单策略的普通日内交易者,它更适合有一定编程基础的开发团队。

环境准备

首先,确保你使用的是 Python 3.11、3.12 或 3.13 版本,然后安装 Nautilus Trader:

pip install -U nautilus_trader

核心组件概览

在开始编写策略前,我们需要了解 Nautilus Trader 的几个核心组件:

  1. Strategy:这是你的交易逻辑所在的类,处理数据事件、订单事件和仓位状态变化。

  2. BacktestEngine:用于运行回测或实盘交易的引擎,需要以下组件:

    • Venue:在回测中模拟交易所,在实盘中代表真实交易所。

    • Data:策略消费的历史或实时数据。

    • Strategy:你的交易逻辑。

实战:构建 MACD 策略

下面,我们将构建一个基于 MACD 指标的简单策略。

1. 创建策略配置

首先导入必要的模块并创建一个策略配置类:

import datetime as dt
from nautilus_trader.config import StrategyConfig
from nautilus_trader.indicators.macd import MovingAverageConvergenceDivergence
from nautilus_trader.trading.strategy import Strategy
from nautilus_trader.model import BarType
from nautilus_trader.model import Bar
from nautilus_trader.model import Position
from nautilus_trader.model import InstrumentId
from nautilus_trader.model.enums import PriceType
from nautilus_trader.model.enums import OrderSide
from nautilus_trader.model.enums import PositionSide

class MACDStrategyConfig(StrategyConfig):
    instrument_id: InstrumentId
    bar_type_1day: BarType
    fast_period: int = 4
    slow_period: int = 8
    trading_side = 10_000
    enter_threshold: float = 0.00010

2. 实现策略类

接下来,我们创建一个 Strategy 的子类来实现我们的 MACD 策略:

# 创建 Strategy 的子类
class MACDStrategy(Strategy):
    def __init__(self, config: MACDStrategyConfig):
        super().__init__()
        self.bar_type_1day = config.bar_type_1day
        self.macd = MovingAverageConvergenceDivergence(
            fast_period = config.fast_period,
            slow_period = config.slow_period,
            price_type = PriceType.MID
        )
        self.instrument_id = config.instrument_id
        self.trade_size = Quantity.from_int(config.trading_side)
        self.position: Position | None = None
        self.enter_threshold = config.enter_threshold
        self.count_processed_bars = 0
        self.start_time = None
        self.end_time = None
    
    def on_start(self):
        # 策略启动时执行
        self.start_time = dt.datetime.now()
        self.subscribe_bars(self.bar_type_1day)
        self.log.info(f"My MACD strategy started at {self.start_time}")
    
    def on_bar(self, bar: Bar):
        # 接收到新的 K 线数据时执行
        self.count_processed_bars += 1
        self.macd.handle_bar(bar)
        if not self.macd.initialized:
            return
        self.check_for_entry()
        self.check_for_exit()
    
    def check_for_entry(self):
        # 检查是否满足入场条件
        if self.macd.value >= self.enter_threshold:
            # 如果已经有多头仓位,不做操作
            if self.position and self.position.side == PositionSide.LONG:
                return
            # 否则下单买入
            order = self.order_factory.market(
                instrument_id = self.instrument_id,
                order_side = OrderSide.BUY,
                quantity = self.trade_size
            )
            self.submit_order(order)
        elif self.macd.value < -self.enter_threshold:
            # 如果已经有空头仓位,不做操作
            if self.position and self.position.side == PositionSide.SHORT:
                return
            # 否则下单卖出
            order = self.order_factory.market(
                instrument_id = self.instrument_id,
                order_side = OrderSide.SELL,
                quantity = self.trade_size
            )
            self.submit_order(order)
    
    def check_for_exit(self):
        # 检查是否满足出场条件
        # 如果 MACD 值为正且有空头仓位,平仓
        if self.macd.value >= 0:
            if self.position and self.position.side == PositionSide.SHORT:
                self.close_position(self.position)
        # 如果 MACD 值为负且有多头仓位,平仓
        else:
            if self.position and self.position.side == PositionSide.LONG:
                self.close_position(self.position)
    
    def on_end(self):
        # 策略结束时执行
        self.end_time = dt.datetime.now()
        self.close_all_positions(instrument_id = self.config.instrument_id)
        self.unsubscribe_bars()
        self.log.info(f"My MACD strategy finnished at {self.end_time}")
        self.log.info(f"Total count of 1 day bars: {self.count_processed_bars}")

3. 设置回测引擎

3.1 定义交易品种

首先,我们需要定义要交易的金融工具(NVDA 股票):

from decimal import Decimal
from nautilus_trader.model.identifiers import InstrumentId
from nautilus_trader.model.identifiers import Symbol
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.instruments import Equity
from nautilus_trader.model.currencies import USD
from nautilus_trader.model.objects import Price, Quantity

# 创建仪器 ID
instrument_id = InstrumentId(
    symbol=Symbol("NVDA"),
    venue=Venue("NASDAQ"),
)

# 创建 NVIDIA 股票金融工具
NVDA_STOCKS_INSTRUMENT = Equity(
    instrument_id=instrument_id,
    raw_symbol=Symbol("NVDA"),
    currency=USD,
    price_precision=2,  # 价格精度为 2 位小数
    price_increment=Price.from_str("0.01"),
    lot_size=Quantity.from_int(1),  # 以整股交易
    isin="US67066G1040",  # NVIDIA 的 ISIN 标识符
    ts_event=0,  # 金融工具创建/更新的时间戳
    ts_init=0,  # 对象初始化的时间戳
)

# 指定数据分辨率(1 天 K 线)
NVDA_STOCKS_1DAY_BARTYPE = BarType.from_str(
    f"{NVDA_STOCKS_INSTRUMENT.id}-1-DAY-LAST-EXTERNAL"
)
3.2 创建引擎并添加策略
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.config import BacktestEngineConfig
from nautilus_trader.config import LoggingConfig
from nautilus_trader.config import ImportableStrategyConfig
from nautilus_trader.model import TraderId
from nautilus_trader.model import Bar

# 创建回测引擎配置
engine_config = BacktestEngineConfig(
    trader_id = TraderId("BACKTEST-NVDA1DAY-001"),
    strategies = [
        ImportableStrategyConfig(
            strategy_path = '__main__:MACDStrategy',
            config_path = '__main__:MACDStrategyConfig',
            config = {
                "instrument_id": instrument_id,
                "bar_type_1day": NVDA_STOCKS_1DAY_BARTYPE,
                "fast_period": 10,
                "slow_period": 20,
                "enter_threshold": 0.00001
            }
        )
    ],
    logging = LoggingConfig(log_level = "DEBUG"),
)

# 创建回测引擎并添加交易品种
engine = BacktestEngine(config = engine_config)
engine.add_instrument(NVDA_STOCKS_INSTRUMENT)
3.3 添加交易所
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.enums import AccountType
from nautilus_trader.model.enums import OmsType
from nautilus_trader.model.currencies import USD
from nautilus_trader.model.objects import Money

# 添加模拟交易所
engine.add_venue(
    venue=Venue("NASDAQ"),
    oms_type=OmsType.NETTING,  # 订单管理系统类型
    account_type=AccountType.MARGIN,  # 交易账户类型
    starting_balances=[Money(1_000_000, USD)],  # 初始账户余额
    base_currency=USD,  # 账户基础货币
    default_leverage=Decimal(1),  # 账户不使用杠杆
)
3.4 添加历史数据
# 从 Yahoo Finance 下载 NVDA 历史数据
import yfinance
ydata_df = yfinance.download(tickers=['NVDA'], start='2000-01-01', end='2025-01-01')
ydata_df.head()

# 将 Yahoo 数据转换为 Nautilus Trader 的内部 BarData 格式
from nautilus_trader.persistence.wranglers import BarDataWrangler
wrangler = BarDataWrangler(
    NVDA_STOCKS_1DAY_BARTYPE,
    NVDA_STOCKS_INSTRUMENT
)
nvda_1day_bars_list: list[Bar] = wrangler.process(ydata_df)

# 将数据加入引擎
engine.add_data(nvda_1day_bars_list)

4. 运行回测并查看结果

# 运行回测
engine.run()

# 查看结果
engine.trader.generate_orders_report()
engine.trader.generate_positions_report()

扩展与优化

在实际应用中,你可以根据自己的需求对上述策略进行扩展和优化:

  1. 自定义指标:除了使用内置的 MACD 指标外,Nautilus Trader 还支持创建自定义指标。

  2. 多资产交易:可以同时添加多个交易品种,实现跨资产类别的组合策略。

  3. 风险管理:增加止损、止盈和头寸管理逻辑,提高策略的健壮性。

  4. 参数优化:通过对 MACD 参数(快线、慢线周期等)进行优化,提高策略性能。

总结

Nautilus Trader 是一个功能强大的量化交易框架,适合希望构建复杂交易系统的开发者和团队。虽然学习曲线较陡,但其高性能、灵活性和可扩展性使其成为构建专业级交易系统的理想选择。

本文介绍了如何使用 Nautilus Trader 构建一个简单的 MACD 策略并进行回测,希望能够帮助你迈出量化交易的第一步。随着对框架的深入理解,你可以构建更复杂、更高效的交易策略,实现自己的量化交易目标。

如果你对 Nautilus Trader 感兴趣,建议深入阅读官方文档和示例代码,以便更好地理解和使用这个强大的工具。

参考文章

  1. Nautilus Trader 官方文档:https://nautilustrader.io/

  2. Nautilus Trader GitHub 仓库:https://github.com/nautechsystems/nautilus_trader

  3. MACD 指标详解:https://www.investopedia.com/terms/m/macd.asp

Logo

加入社区!打开量化的大门,首批课程上线啦!

更多推荐