分享

backtrader量化平台教程(二)第一个可用的策略...

 昵称806630 2021-06-14

第一个可用的策略

指数基金的收益率怎么样?

写一个实用的策略,验证指数基金的收益情况。

获取回测数据

我们从证券宝baostock免费获取中证500(000905)指数数据。

这里我们写了一个工具get_daily_data2.py,具体代码见下文:

使用前需要pip安装baostock,pandas,click这三个python库。

$ python get_daily_data2.py --code sh.000905
login success!
login respond error_code:0
login respond  error_msg:success
query_history_k_data_plus respond error_code:0
query_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 objects
import backtrader as bt
import backtrader.feeds as btfeed
import math


class BSCSVData(btfeed.GenericCSVData):
    params = (
        ("fromdate", datetime.datetime(2010, 1, 1)),
        ("todate", datetime.datetime(2019, 12, 31)),
        ('dtformat', ('%Y-%m-%d')),
        ('openinterest', -1)
    )


# Create a Stratey
class 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.00
Final Portfolio Value: 1161006.90
Total 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 bs
import pandas as pd
import 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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多