(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)

相关推荐