(9条消息) backtrader量化平台教程(二)第一个可用的策略
第一个可用的策略
指数基金的收益率怎么样?
写一个实用的策略,验证指数基金的收益情况。
获取回测数据
我们从证券宝baostock免费获取中证500(000905)指数数据。
这里我们写了一个工具get_daily_data2.py,具体代码见下文:
使用前需要pip安装baostock,pandas,click这三个python库。
$ python get_daily_data2.py --code sh.000905login success!login respond error_code:0login respond error_msg:successquery_history_k_data_plus respond error_code:0query_history_k_data_plus respond error_msg:success
加载数据
首先我们继承GenericCSVData定义了自己的CSV读取函数。
class BSCSVData(btfeed.GenericCSVData): params = ( ("fromdate", datetime.datetime(2010, 1, 1)), ("todate", datetime.datetime(2019, 12, 31)), ('dtformat', ('%Y-%m-%d')), ('openinterest', -1) )
这里我们主要定义了起始结束时间,时间的格式。
GenericCSVData默认会读取datetime,open,high,low,close,volume,openinterest这些line,并定义了这些数据在CSV文件中对应的列号。
data = BSCSVData(dataname="./datas/{0}".format(filename))
如果我们的CSV数据中,没有某指标,需要设置该指标为-1。
如果我们的CSV数据中包含了PE指标,并且我们想加载进来,也可以通过这种方式定义。
('pe', 7)
数据读取后,在backtrader加载数据很简单,使用adddata函数。
cerebro.adddata(data)
设置现金总额
在backtrader中可以设置初始投入金额:
cerebro.broker.set_cash(1000000.0)
实现策略(买入并持有指数基金)
我们继承bt.Strategy,定制自己的策略。
策略中重要的函数是next,函数next在每个时间点,都会被框架自动调用。
我们的策略很简单,如果发现当前是空仓,就把资金全部投入到目标标的,然后一只持有到天长地久。
购买使用的buy这个方法,这个方法实际上参数很多,可以指定数量购买,可以指定价格购买等方式。
init函数中的dataclose是引用回测数据中收盘价这条line。
总结
从我们回测持有中证500指数10年的情况看,总收益率只有15%,年收益率在1.5%左右。
甚至跑输余额宝这样的现金理财。
有兴趣的话,你也可以尝试评估下沪深300,上证50这样的指数。
回测的完整代码
#!/usr/bin/env python# -*- coding: utf-8; py-indent-offset:4 -*-from __future__ import (absolute_import, division, print_function, unicode_literals)import datetime # For datetime objectsimport backtrader as btimport backtrader.feeds as btfeedimport mathclass BSCSVData(btfeed.GenericCSVData): params = ( ("fromdate", datetime.datetime(2010, 1, 1)), ("todate", datetime.datetime(2019, 12, 31)), ('dtformat', ('%Y-%m-%d')), ('openinterest', -1) )# Create a Strateyclass TestStrategy(bt.Strategy): def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close def next(self): # self.log('Close, %.2f' % self.dataclose[0]) if not self.position: self.buy(size=math.floor(self.broker.get_cash() / self.dataclose[0]))if __name__ == '__main__': filename = 'bs_sh.000905.csv' cerebro = bt.Cerebro() # 加载自定义策略 cerebro.addstrategy(TestStrategy) # 设置金额为一百万 cerebro.broker.set_cash(1000000.0) # 加载历史数据 data = BSCSVData(dataname="./datas/{0}".format(filename)) cerebro.adddata(data) print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.run() print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # 计算总回报率和年度回报率 return_all = cerebro.broker.getvalue()/1000000.0 print('Total ROI: {0}%, Annual ROI{1}%'.format( round((return_all - 1.0) * 100, 2), round((pow(return_all, 1.0 / 10) - 1.0) * 100, 2) ))
执行结果如下:
Starting Portfolio Value: 1000000.00Final Portfolio Value: 1161006.90Total ROI: 16.1%, Annual ROI1.5%Process finished with exit code 0
获取数据的完整代码
#!/usr/bin/env python# -*- coding: utf-8; py-indent-offset:4 -*-""" 从baostock获取daily数据到datas目录下的csv文件当中,文件名如:bs_sh.000001.csv """import baostock as bsimport pandas as pdimport click@click.command()@click.option("--code", default="sh.600000", help="baostock股票/指数代码,如sh.600000")@click.option("--start", default="2010-01-01", help="开始日期, 格式如:2010-01-01")@click.option("--end", default="2020-03-01", help="结束日期, 格式如:2010-01-01")@click.option("--adj", default="1", help="复权类型(只针对股票):3: 未复权 2:前复权 1:后复权 , 默认1")def get_data(code, start, end, adj): lg = bs.login() print('login respond error_code:' + lg.error_code) print('login respond error_msg:' + lg.error_msg) rs = bs.query_history_k_data_plus(code, 'date,open,high,low,close,volume', start_date=start, end_date=end, frequency='d', adjustflag=adj) print('query_history_k_data_plus respond error_code:' + rs.error_code) print('query_history_k_data_plus respond error_msg:' + rs.error_msg) # 打印结果集 data_list = [] while (rs.error_code == '0') & rs.next(): # 获取一条记录,将记录合并在一起 data_list.append(rs.get_row_data()) data = pd.DataFrame(data_list, columns=rs.fields) columns = ['date', 'open', 'high', 'low', 'close', 'volume'] data.to_csv("./datas/bs_{0}.csv".format(code), sep=',', index=False, columns=columns)if __name__ == "__main__": get_data()
赞 (0)