量化交易学习(八)backtrader回测补全均线

在跑回测的过程中,我发现了一个比较容易被忽视的一个坑:均线在回测的时间段是不全的。

如图所示,图中红色的线是90日均线,回测的时间范围是2020-01-01 08:00:00 至 2024-01-01 16:00:00,可以看到图中最开始的一段走势中都没有红线,直到2020-05-18 那天才出现红线。

图片

均线在2020年5月18日才出现,这会导致我们的策略在2020年5月18号前都失效!下图是运行回测时的买卖结果,可以看到最早的买单是在2020年6月1日创建的:

图片
那怎样才能解决这个问题呢?

首先来看看为什么会出现这个问题。在单均线策略中,我们采用的指标是90日均线,它需要90根日k线才能计算出来,因此,在回测开始的前90个交易日里没有足够的数据计算出90日均线。

知道了问题的原因,那也就好解决了,我们人为地加上90天k线的数据不就可以了,

接下来我来说一下我的解决方法:

量化交易学习(三)backtrader使用掘金量化实时数据源 这篇文章中的代码为基础,首先在初始化函数中,加上获取历史数据的代码,获取完历史数据后把它们直接通过管道传给backtrader,为了简单起见,我直接加上了前一年的k线数据:

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
def init(context):  
parent_conn, child_conn = Pipe()
context.parent_conn = parent_conn
p = Process(target=backtrader, args=(child_conn,))
p.start()
# 获取回测开始前一年的数据,
# 采用定点复权的方式,adjust指定前复权,adjust_end_time指定复权时间点为回测结束的时间
gmdata = history(symbol='SHSE.510300', frequency='1d', start_time='2019-01-01 09:00:00',
end_time='2020-01-01 16:00:00',
adjust=ADJUST_PREV, adjust_end_time='2024-01-01', df=True)
# 遍历数据,用管道把数据推送给backtrader
for idx,row in gmdata.iterrows():
bar = {
'symbol': row['symbol'],
'frequency': row['frequency'],
'open': row['open'],
'high': row['high'],
'low': row['low'],
'close': row['close'],
'volume': row['volume'],
'amount': row['amount'],
'pre_close': row['pre_close'],
'position': row['position'],
'bob': row['bob'],
'eob': row['eob']
}
context.parent_conn.send(bar)
# 历史数据推送完后,再订阅股票数据
subscribe(symbols='SHSE.510300', frequency='1d')

策略也要相应进行修改:

因为k线添加了回测开始时间前一年的数据,如果直接跑回测的话会把这段时间也算作回测时间,应该让策略跳过这段时间,给策略添加一个新的参数start_date,用于标记策略开始运行的时间,在next函数中,如果当前k线的结束时间小于start_date则跳过执行。

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
class SingleMAStrategy(bt.Strategy):  
# 设置均线的周期
params = (
('period', 15),
('start_date',None),
)

def __init__(self):
...
self.start_date=datetime.strptime(self.p.start_date, '%Y-%m-%d %H:%M:%S') if self.p.start_date is not None else None

def next(self):
if self.start_date is not None and self.start_date>bt.utils.num2date( self.data.datetime[0]):
return
...
```
在backtrader函数中,修改添加策略相关的代码:
```py
def backtrader(conn):
cerebro = bt.Cerebro()

cerebro.addstrategy(SingleMAStrategy,
period=90,
start_date='2020-01-01 09:00:00')
...

跑完后的图像如下:
图片

可以看到回测开始前多了一段股价图,下方的CrossOver是股价与均线交叉信号。回测开始前虽然有信号,但没有触发交易,回测开始后,交易正常触发,说明均线已经被补齐,回测结果正确了。

图片

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

江达小记