量化武器库|Backtrader 精讲(下) - 订单、佣金与滑点

B站影视 日本电影 2025-09-30 15:28 1

摘要:我们已经掌握了 Backtrader 的策略编写和参数优化。但是,一个回测结果是否可信,很大程度上取决于它离真实交易有多近。在真实世界里,交易不是一瞬间完成的,它有成本、有延迟、有各种不确定性。

《量化武器库》系列专门聚焦那些能极大提升我们量化研究和实盘效率的工具,打造一个覆盖数据、回测、分析到实战的全流程工具箱。

大家好,我是木泽!

我们已经掌握了 Backtrader 的策略编写和参数优化。但是,一个回测结果是否可信,很大程度上取决于它离真实交易有多近。在真实世界里,交易不是一瞬间完成的,它有成本、有延迟、有各种不确定性。

今天,我们就来完成 Backtrader 的最后一块、也是最关键的一块拼图——深入 `Broker` 和 `Strategy` 模块,学习如何精细地模拟订单、设置交易成本(佣金和滑点)、以及监控交易过程,让我们的回测无限逼近真实!

(创作不易,感谢关注支持↑↑↑)

任何不考虑交易成本的回测都是"自欺欺人"。Backtrader 允许你非常方便地设置佣金方案。

# 在 Cerebro 中设置全局佣金cerebro.broker.setcommission( commission=0.0003, # 佣金率为 0.03% (万三) mult=10.0, # 适用于股票等价格较高的资产 (crypto常为1) margin=None # 如果是期货,可设置保证金)

滑点是指你的预期成交价和实际成交价之间的差异,在高频交易或低流动性市场中尤其明显。Backtrader 内置了多种滑点模型。

# 设置一个固定比例的滑点cerebro.broker.set_slippage_perc( perc=0.001, # 滑点率为 0.1%)# 也可以设置固定金额的滑点# cerebro.broker.set_slippage_fixed(0.01) # 每个单位滑点 0.01元

一个真实的回测,必须同时包含佣金和滑点!

很多在"裸奔"(无成本)回测中看起来收益惊人的高频策略,一旦加入合理的佣金和滑点,可能瞬间就变成了亏损策略。

除了简单的 `buy` 和 `sell` 市价单,Backtrader 支持丰富的订单类型,让你的策略逻辑更灵活。

class MyAdvancedStrategy(bt.Strategy): def next(self): if not self.position: # 以当前收盘价下方 1% 的价格挂一个限价买单 price = self.data.close[0] * 0.99 self.buy(exectype=bt.Order.Limit, price=price, size=100) else: # 创建一个止损单,当价格跌破买入价的 5% 时触发 stop_price = self.position.price * 0.95 self.sell(exectype=bt.Order.Stop, price=stop_price) # 也可以创建止盈单 take_profit_price = self.position.price * 1.10 self.sell(exectype=bt.Order.Limit, price=take_profit_price)

如何知道我们的订单是否被接受、是否成交?Backtrader 提供了 `notify_order` 和 `notify_trade` 这两个强大的"钩子"函数。

class MyLoggingStrategy(bt.Strategy): def log(self, txt, dt=None): dt = dt or self.datas[0].datetime.date(0) print(f'{dt.isoformat} {txt}') def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: return # 订单已提交/已接受,不处理 if order.status in [order.Completed]: if order.isbuy: self.log(f'BUY EXECUTED, Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}') elif order.issell: self.log(f'SELL EXECUTED, Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}') elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') def notify_trade(self, trade): if not trade.isclosed: return self.log(f'OPERATION PROFIT, GROSS {trade.pnl:.2f}, NET {trade.pnlcomm:.2f}')

`notify_order` vs `notify_trade`:

`notify_order` 关注的是单个订单的状态变化。而 `notify_trade` 关注的是一笔完整的"交易"(一买一卖构成一笔交易)的最终盈亏情况。两者结合,能让你对整个交易过程了如指掌。

恭喜!至此,我们已经完整地学习了 Backtrader 的核心功能。从策略编写、数据加载,到参数优化、成本模拟和交易监控,你已经拥有了一件功能强大的量化武器。

来源:木泽的量化笔记

相关推荐