本文主要包含以下三部分内容:
可以通过下面的代码在backtrader中添加日志功能:
cerebro.addwriter(bt.WriterFile, out = 'log.csv', csv = True)
日志信息将被输出到工作目录下的log.csv文件中,输出内容包括:
交易日历适用于以下场景:
print('Strategy len {} datetime {}'.format(
len(self), self.datetime.date()), end=' ')
print('Data0 len {} datetime {}'.format(
len(self.data0), self.data0.datetime.date()), end=' ')
if len(self.data1):
print('Data1 len {} datetime {}'.format(
len(self.data1), self.data1.datetime.date()))
else:
print()
当不使用交易日历时,部分输出结果为:
Strategy len 1 datetime 2019-01-02 Data0 len 1 datetime 2019-01-02
Strategy len 2 datetime 2019-01-03 Data0 len 2 datetime 2019-01-03
Strategy len 3 datetime 2019-01-04 Data0 len 3 datetime 2019-01-04
Strategy len 4 datetime 2019-01-07 Data0 len 4 datetime 2019-01-07 Data1 len 1 datetime 2019-01-04
Strategy len 5 datetime 2019-01-08 Data0 len 5 datetime 2019-01-08 Data1 len 1 datetime 2019-01-04
Strategy len 6 datetime 2019-01-09 Data0 len 6 datetime 2019-01-09 Data1 len 1 datetime 2019-01-04
Strategy len 7 datetime 2019-01-10 Data0 len 7 datetime 2019-01-10 Data1 len 1 datetime 2019-01-04
Strategy len 8 datetime 2019-01-11 Data0 len 8 datetime 2019-01-11 Data1 len 1 datetime 2019-01-04
Strategy len 9 datetime 2019-01-14 Data0 len 9 datetime 2019-01-14 Data1 len 2 datetime 2019-01-11
...
在输出的每一行中,第一个日期为策略所使用的日期,第二个日期为当前日线的日期,第三个日期为当前月线的日期。
其中,第3行1月4日为星期五,应该出现第一根周线数据,但是输出结果中却没有周线数据。第8行1月11日为周五,从1月7日至1月11日的5根日线可以合成1根周线,后面的周线数据也应该更新为1月11日,但是输出结果却是1月4日。
产生以上结果的原因是,backtrader把2019年1月1日当作了交易日,只是没有读入数据。这样1月1日至4日,再加上7日共计5根日线,就在1月7日合成了第一根周线;同样1月8日至11日,再加上14日共计5根日线,在1月14日合成了第二根周线。这显然不是想要的结果。
解决上述问题的方案是,通过继承bt.TradingCalendar定义新的日历,然后在日历中设定节假日。如以下代码所示,将2019年1月1日添加到holidays列表中,然后在cerebro添加该日历:
class AStockCalendar(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2019, 1, 1),
],
open=datetime.time(9, 30),
close=datetime.time(15, 0),
)
cerebro.addcalendar(AStockCalendar())
当使用交易日历时,部分输出结果为:
Strategy len 1 datetime 2019-01-02 Data0 len 1 datetime 2019-01-02
Strategy len 2 datetime 2019-01-03 Data0 len 2 datetime 2019-01-03
Strategy len 3 datetime 2019-01-04 Data0 len 3 datetime 2019-01-04 Data1 len 1 datetime 2019-01-04
Strategy len 4 datetime 2019-01-07 Data0 len 4 datetime 2019-01-07 Data1 len 1 datetime 2019-01-04
Strategy len 5 datetime 2019-01-08 Data0 len 5 datetime 2019-01-08 Data1 len 1 datetime 2019-01-04
Strategy len 6 datetime 2019-01-09 Data0 len 6 datetime 2019-01-09 Data1 len 1 datetime 2019-01-04
Strategy len 7 datetime 2019-01-10 Data0 len 7 datetime 2019-01-10 Data1 len 1 datetime 2019-01-04
Strategy len 8 datetime 2019-01-11 Data0 len 8 datetime 2019-01-11 Data1 len 2 datetime 2019-01-11
Strategy len 9 datetime 2019-01-14 Data0 len 9 datetime 2019-01-14 Data1 len 2 datetime 2019-01-11
...
可以看到,在1月4日(星期五)合成了第一根周线,在1月11日(星期五)合成了第二根周线,得到了正确的结果。
同样,可以把2019年的其他节假日都添加到holidays列表中,来实现整年的周线数据的正确合成。
class CustomCalendar(bt.TradingCalendar):
params = dict(
holidays=[
datetime.date(2016, 1, 1),
datetime.date(2016, 1, 18),
datetime.date(2016, 2, 15),
datetime.date(2016, 3, 25),
datetime.date(2016, 5, 30),
datetime.date(2016, 7, 4),
datetime.date(2016, 9, 5),
datetime.date(2016, 11, 24),
datetime.date(2016, 12, 26),
],
earlydays=[
(datetime.date(2016, 11, 25),
datetime.time(9, 30), datetime.time(13, ,0))
],
open=datetime.time(9, 30),
close=datetime.time(16, 0),
)
以2016年为例,日历中设定了2016年的节假日,一般每日交易时间为9:30至16:00,11月25日的交易时间为9:30至13:00。
借助于日志功能,对resample功能进行简单分析。这里以30分钟数据为数据源,使用resample来合成60分钟数据,同时加载已下载好的60分钟数据用于对比resample结果,部分代码如下:
data = load_data(stk_code, fromdate, todate, '30')
cerebro.adddata(data, name = stk_code + '_30m')
cerebro.resampledata(data, name = stk_code + '_30to60m', timeframe = bt.TimeFrame.Minutes, compression = 60)
data = load_data(stk_code, fromdate, todate, '60')
cerebro.adddata(data, name = stk_code + '_60m'
以加载2020年6月1日至4日平安银行的数据为例,使用日志功能将结果输出至log.csv中,部分结果如下: