量化交易学习(二)backtrader单均线回测

昨天介绍了怎么用掘金量化做回测,今天介绍下怎么用backtrader来做回测,backtrader 是一个在量化界大名鼎鼎的量化回测框架,功能丰富,是量化交易初学者必学的量化回测框架。目前的话我也是刚入门,只会拿它做回测,还没研究出怎么把backtrader与掘金量化结合起来用backtrader直接跑仿真和实盘。

backtrader的官网:https://www.backtrader.com/

官网安装教程:https://www.backtrader.com/docu/installation/

官方的入门教程:https://www.backtrader.com/docu/quickstart/quickstart/

接下来以单均线策略介绍下怎么用backtrader结合掘金量化的数据跑回测:

导入掘金及backtrader库:

1
2
from gm.api import *
import backtrader as bt

设置掘金token

掘金token是用来访问掘金量化平台数据的凭证,点击掘金量化右上角的系统设置就能找到了。

图片

1
2
token='xxxxxx'
set_token(token)

准备回测的数据

掘金量化有获取历史行情的接口history,具体的使用方法可以看其API文档。获取到数据后用bt.feeds.PandasData可以把它转化为backtrader的数据源。在这里我们选择的数据是沪深300ETF(510300)在2020年1月1日至2023年8月9日的数据。为啥是8月9日?因为这份代码是我那天写的。

1
2
3
4
5
6
7
gmdata = history(symbol='SHSE.510300', frequency='1d', start_time='2020-01-01 09:00:00', end_time='2023-08-09 16:00:00',
adjust=ADJUST_PREV, adjust_end_time='2023-08-09', df=True)

data=bt.feeds.PandasData(
dataname=gmdata,
datetime='eob'
)

创建一个单均线策略

backtrader中可以用类来定义一个自定义策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
class SingleMAStrategy(bt.Strategy):
# 设置均线的周期
params=(
('period',15),
)

# 打印日志的函数
def log(self,txt,dt=None):
dt=dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(),txt))

# 策略初始化,设置一些参数
def __init__(self):
# 标第的收盘价
self.dataclose = self.data.close

self.order = None
self.buyprice = None
self.buycomm = None

self.sma = bt.indicators.SimpleMovingAverage(
self.data,period=self.params.period
)

self.cross=bt.indicators.CrossOver(self.dataclose,self.sma)
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(
'买入已执行,价格为:%.2f,花费:%.2f,佣金:%.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(
'卖出已执行,价格为:%.2f,花费:%.2f,佣金:%.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))

self.bar_executed=len(self)
elif order.status in [order.Canceled,order.Margin,order.Rejected]:
self.log('Order Canceled/Margin/Rejected')

self.order = None

def notify_trade(self,trade):
if not trade.isclosed:
return

self.log('当前盈亏 %.2f ,去除佣金后的盈亏 %.2f' %
(trade.pnl,trade.pnlcomm))

# 每条k线都会执行这个函数
def next(self):
if self.order:
return
if not self.position:
# 当前价格上穿均线买入
if self.cross==1:
vol=self.broker.getvalue()/self.dataclose[0]//100*100
self.log('创建买单,%.2f' % self.dataclose[0])
self.log('vol:%.2f' % vol)
self.order =self.buy(size=vol)
else:
# 当前价格下穿均线卖出
if self.cross==-1:
self.log('创建卖单,%.2f' % self.dataclose[0])
self.order=self.sell(size=self.position.size)

主程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if __name__ == '__main__':
# 新建一个backtrader回测引擎
cerebro = bt.Cerebro()
# 加载自定义策略
cerebro.addstrategy(SingleMAStrategy)
# 加载回测数据
cerebro.adddata(data)
# 设置回测交易商现金
cerebro.broker.setcash(100000)
# 设置交易佣金比例
cerebro.broker.setcommission(commission=0.00015)

print('初始时资金持仓:%.2f' % cerebro.broker.getvalue())
cerebro.run()
print('结束时资金持仓:%.2f' % cerebro.broker.getvalue())
# 画图
cerebro.plot(iplot=False)

执行结果

我是在jupyter里跑的,在jupyter里写代码的好处是调试方便,下面贴一下执行结果:

图片
图片

初始资金为10万元,回测结束后为11万3千6百38块7毛9。赚了1万多块钱。

执行后会调用matplotlib画一幅策略运行结果图,以方便查看策略的有效性

图片

backtrader默认出的这个图虽然不太好看,但是信息量很大。接下来我将截取一部分图片来解释其含义:

图片

图中的红线表示当前帐户内的现金,蓝线表示当前证券组合的价值。没有买入证券时,红蓝线重合,只显示红线,当买入证券后红线代表的现金会减少下降,蓝线代表的证券价值还会有原来的位置,不过会随着当前行情发生变化。

图片

图中的红点和蓝点表示每次卖出时收获的净利润。红点表示净利润为负赔钱了,蓝点表示净利润为正赚钱了。

图片

主图中就是股票的走势了,黑线是股票的每日收盘价,红线是我们的15日均线,绿色箭头是买入点(在国外绿为涨红为跌与A股是反着的)红色箭头是卖出点,下方的柱子是成交量,左边坐标轴是成交量的坐标轴,右边坐标轴是股价的坐标轴。

图片

最下面的那条红线是我们计算的交叉点上穿下穿的CrossOver的值。

这一篇简单介绍了怎么用backtrader回测,backtrader相比直接用掘金量化会方便很多,而且它的图表信息量更大,更有助于我们排查策略的问题。

这一篇就到这里啦。欢迎大家点赞、转发、私信。

江达小记