Backtrader-Broker05
本系列是使用Backtrader在量化领域的学习与实践,着重介绍Backtrader的使用。Backtrader 中几个核心组件:
- Cerebro:BackTrader的基石,所有的操作都是基于Cerebro的。
- Feed:将运行策略所需的基础数据加载到Cerebro中,一般为K线数据。
- Indicator:BackTader自带的指标,并集成了talib中的指标。我们也可以选择继承一个Indicator实现自己的指标。
- Strategy:交易策略。这里是整个过程中最复杂的部分,需要我们计算买入/卖出信号。
- Analyzer:分析器,以图形和风险收益等指标对交易策略的回测结果进行分析评价。
- Order:订单,记录了与当前订单相关的所有数据。
- Trader:交易,记录了与当前交易相关的所有数据。
- Position:持仓,记录了与当前持仓相关的所有数据。
- Broker:可以理解成经纪人,整个策略的初始资金、交易费率、滑点等参数需要通过Broker进行设置。
- Observer:观察者,对数据进行监控观察,比如资金曲线等等。
- Plotting:可视化组件
本次介绍Backtrader中Broker模块,其是Backtrader核心模块之一, Broker模拟经纪商交易系统相关功能。
在使用Backtrader时,结合量化策略编写过程通常会考虑:
- Broker是什么?它在回测时有什么作用?
- Broker经纪商模块,在资金管理、滑点管理等基础参数上,在回测中如何使用?
- Broker在交易撮合上都支持哪些模式?
- …
Broker 经纪商模块
Broker模拟经纪商交易系统相关功能,支持不同订单类型、对交易进行“验资验券”,并模拟交易所进行交易撮合。最常见的有初始资金、交易税费、滑点、期货保证金比率等。
在 Backtrader 中,从数据准备、策略编制、策略回测到绩效分析,整个回测流程各个模块相互协调,从交易流程大致如下:
- step1:设置交易条件:初始资金、交易税费、滑点、成交量限制等;
- step2:在 Strategy 策略逻辑中下达交易指令 buy、sell、close,或取消交易 cancel;
- step3:Order 模块会解读交易订单,解读的信息将交由经纪商 Broker 模块处理;
- step4:经纪商 Broker 会根据订单信息检查订单并确定是否接收订单;
- step5:经纪商 Broker 接收订单后,会按订单要求撮合成交 trade,并进行成交结算;
- step6:Order 模块返回经纪商 Broker 中的订单执行结果。
在backtrader中做策略回测,在策略运行前,Broker实现账户资金、份额等信息初始化;在回测过程中,接受订单Order发出的信息,并进行模拟撮合操作,同时实时更新账户资金、份额信息。
Broker 支持的订单类型
- Order.Market 按下一个 Bar (即生成订单的那个交易日的下一个交易日)的开盘价来执行成交;
- Order.Close 按下一个 Bar 的收盘价来执行成交
- Order.Limit 限价单,需要指定成交价格,只有达到指定价格(limit Price)或有更好价格时才会执行,即以指定价或低于指点价买入,以指点价或更高指定价卖出;
- Order.Stop 止损单,需要指定止损价格(Stop Price),一旦股价突破止损价格,将会以市价单的方式成交;
- Order.StopLimit 止损限价单,需要指定止损价格(Stop price)和限价(Limit Price),一旦股价达到设置的止损价格,将以限价单的方式下单
- Order.StopTrail 跟踪止损订单,是一种止损价格会自动调整的止损单,调整范围通过设置止损价格和市场价格之间的差价来确定
- Order.StopTrailLimit 跟踪止损限价单,是一种止损价格会自动调整的止损限价单,订单中的限价 Limit Price 不会发生变动,止损价会发生变动,变动逻辑与上面介绍的跟踪止损订单一致;
Broker 如何管理参数
通过使用Broker实现初始资金、手续费、滑点等管理,通过2中方式实现:
- 方法1:通过创建backtrader.brokers.BackBroker()实例 ,将该实例赋值与cerebro.broker;
# samples/cheat-on-open/cheat-on-open.py
cerebro.broker = bt.brokers.BackBroker()
# 各参数初始值为:
# params = (
# ('cash', 10000.0),
# ('checksubmit', True),
# ('eosbar', False),
# ('filler', None),
# # slippage options
# ('slip_perc', 0.0),
# ('slip_fixed', 0.0),
# ('slip_open', False),
# ('slip_match', True),
# ('slip_limit', True),
# ('slip_out', False),
# ('coc', False),
# ('coo', False),
# ('int2pnl', True),
# ('shortcash', True),
# ('fundstartval', 100.0),
# ('fundmode', False),)
- 方法2:通过broker中的“set_xxx"方法赋值或修改参数,可通过"get_xxx"方法查看设置参数的值;
# samples/slippage/slippage.py
cerebro.broker.set_slippage_fixed(args.slip_fixed,
slip_open=args.slip_open,
slip_match=not args.no_slip_match,
slip_out=args.slip_out)
Broker 资金与持仓如何管理
在backtrader中,每次订单Order执行完后将更新持仓与金额。
如何了解,策略回测资金情况?
- 在策略执行前,可以通过set_cash(或setcash)对资金进行初始化;在策略执行过程中,可调用add_cash(cash)调整资金(cash 为正数表示增加资金;cash 为负数表示减少资金)。
- 在执行过程中通过get_cash()(或getcash)查看持有资金。
如何了解,策略回测持仓情况?
- 通过getposition(data) 查看当前标的持仓数据;
Broker ”滑点“ 提升成交率
在实盘和回测中,为提高在”预期“价格成交概率,通常会取个价格范围,比如:计划价格2.00元买入, 实际买入价格:2.02元。
在backtrader中,提供了百分比滑点和固定滑点:
-
百分比滑点
假设perc=n%:- 若计划买入价格为x,实际成交买入价格:x * (1 + n% )
- 若计划卖出价格为x,实际成家卖出价格:x * (1 - n%)
BackBroker.set_slippage_perc(perc, slip_open=True, slip_limit=True, slip_match=True, slip_out=False)
-
固定滑点
假设fixed=n:- 若计划买入价格为x,实际成交买入价格:x + n
- 若计划卖出价格为x,实际成家卖出价格:x - n
BackBroker.set_slippage_fixed(fixed, slip_open=True, slip_limit=True, slip_match=True, slip_out=False)
在backtrader中,不同的订单类型中slippage是如何工作的呢?
-
Close 不支持该订单类型
-
Market 支持该订单类型
在Market订单类型(即以开票价成交)下,需设置slip_open = True。需要注意的是通过BackBroker() 实例化broker,其默认值为False,而通过方式2,即set_slippage_perc和set_slipage_fixed 其默认值为True。 -
Limit 需要根据参数设置情况而定
- 如果匹配价格是开盘价,则根据参数 slip_open 应用滑点。如果适用,价格永远不会低于要求的限价;
- 如果匹配价格不是限价,则滑点将应用于最高价/最低价。在这种情况下,slip_mlimit适用于决定在超过上限的情况下是否会进行匹配
-
Stop 支持该订单类型
执行逻辑同Market订单类型逻辑 -
StopLimit 需要根据参数设置情况而定
执行逻辑同Limit订单类型逻辑
Broker 中的 ”Cheating 交易“
Backtrader 默认是 “当日收盘后下单,次日以开盘价成交”,这种模式在回测过程中能有效避免使用未来数据。
Backtrader 还提供了一些 cheating 式的交易时机模式:Cheat-On-Open 和 Cheat-On-Close。
- Cheat-On-Open 是“当日下单,当日以开盘价成交”模式
- Cheat-On-Close 是“当日下单,当日以收盘价成交”模式
cerebro = bt.Cerebro(cheat_on_open=True)
Broker 中的 成交量限制
通过 Backtrader 中的 fillers 模块来限制实际成交量,fillers 会告诉 Broker 在各个成交时间点应该成交多少量,一共有 3 种形式:
- 形式1:bt.broker.fillers.FixedSize(size)
- 形式2:bt.broker.fillers.FixedBarPerc(perc)
- 形式3:bt.broker.fillers.BarPointPerc(minmov=0.01,perc=100.0)
在 Broker 中使用Filler同样有两种方式:
- 方式一:通过broker中‘set_filler"进行设置
import backtrader as bt
cerebro = Cerebro()
cerebro.broker.set_filler(bt.broker.fillers.FixedSize())
- 方式二:通过创建backtrader.broker.BrokerBack(filler=filler)实例,赋值与broker
import backtrader as bt
cerebro = Cerebro()
filler = bt.broker.fillers.FixedSize()
newbroker = bt.broker.BrokerBack(filler=filler)
cerebro.broker = newbroker
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib
plt.rcParams['figure.figsize'] = 15, 15
daily_price = pd.read_csv("./data/daily_price.csv", parse_dates=['datetime'])
# 筛选 600466.SH 和 603228.SH 2只股票的数据集
data1 = daily_price.query(f"sec_code=='600466.SH'").set_index('datetime').drop(columns=['sec_code'])
data2 = daily_price.query(f"sec_code=='603228.SH'").set_index('datetime').drop(columns=['sec_code'])