量化交易3-backtrader从tushare获取数据回测数据

上一章解释了backtrader的数据来源,以及要求的数据格式,本章节笔者会演示下backtrader从tushare上获取数据,然后进行回测,以达到相对自动化、实时话的要求。讲解backtrader结合tushare的文章挺多的,但是都是截取了部分的代码片段,没法直接运行,笔者本着从入门到精通的精神,整理的一份完整的可以运行的代码。

先对tushare做个简单的解释,tushare是一个提供了股票的实时行情和历史行情数据的网站,更多的功能请访问tushare的官方网站, 官网传送门:  Tushare大数据社区

本文是获取多只代码然后进行回测

先贴上代码:

import tushare as ts
import pandas as pd

import datetime  # For datetime objects
import os.path  # To manage paths
import sys  # To find out the script name (in argv[0])
# Import the backtrader platform
import backtrader as bt

class MyStrategy(bt.Strategy):
    # 策略参数
    params = dict(
        period=20,  # 均线周期
        look_back_days=30,
        printlog=False
    )
    def __init__(self):
        self.mas = dict()
        #遍历所有股票,计算20日均线
        for data in self.datas:
            self.mas[data._name] = bt.ind.SMA(data.close, period=self.p.period) 
    def next(self):
        #计算截面收益率
        rate_list=[]
        for data in self.datas:
            if len(data)>self.p.look_back_days:
                p0=data.close[0]
                pn=data.close[-self.p.look_back_days]
                rate=(p0-pn)/pn
                rate_list.append([data._name,rate])
        #股票池   
        long_list=[]
        sorted_rate=sorted(rate_list,key=lambda x:x[1],reverse=True)
        long_list=[i[0] for i in sorted_rate[:10]]
        # 得到当前的账户价值
        total_value = self.broker.getvalue()
        p_value = total_value*0.9/10
        for data in self.datas:
            #获取仓位
            pos = self.getposition(data).size
            if not pos and data._name in long_list and \
              self.mas[data._name][0]>data.close[0]:
                size=int(p_value/100/data.close[0])*100
                self.buy(data = data, size = size) 
            if pos!=0 and data._name not in long_list or \
              self.mas[data._name][0]<data.close[0]:
                self.close(data = data)                        
    def log(self, txt, dt=None,doprint=False):
        if self.params.printlog or doprint:
            dt = dt or self.datas[0].datetime.date(0)
            print(f'{dt.isoformat()},{txt}')
    #记录交易执行情况(可省略,默认不输出结果)
    def notify_order(self, order):
        # 如果order为submitted/accepted,返回空
        if order.status in [order.Submitted, order.Accepted]:
            return
        # 如果order为buy/sell executed,报告价格结果
        if order.status in [order.Completed]: 
            if order.isbuy():
                self.log(f'买入:\n价格:{order.executed.price:.2f},\
                成本:{order.executed.value:.2f},\
                手续费:{order.executed.comm:.2f}')
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log(f'卖出:\n价格:{order.executed.price:.2f},\
                成本: {order.executed.value:.2f},\
                手续费{order.executed.comm:.2f}')
            self.bar_executed = len(self) 
        # 如果指令取消/交易失败, 报告结果
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('交易失败')
        self.order = None
    #记录交易收益情况(可省略,默认不输出结果)
    def notify_trade(self,trade):
        if not trade.isclosed:
            return
        self.log(f'策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')
 
 
 
 
pro=ts.pro_api('cbb257058b7cb228769b4949437c27c27e5132e882747dc80f01a5a5')


def ts_get_daily_stock(code,start_dt,end_dt):
    start_dt = start_dt.replace("'", "", 3);
    end_dt = end_dt.replace("'", "", 3);
    #start_dt = '20190101'
    #end_dt=''
    print(code,start_dt,end_dt)
    data = pro.daily(ts_code = code,start_date = start_dt,end_date=end_dt)
    print(data)
    data['trade_date'] = pd.to_datetime(data['trade_date'])
    data=data.sort_values(by = 'trade_date')
    data.index = data['trade_date']
    data['openinterest']=0
    data['volume']=data['vol']
    data = data[
        ['open','close','high','low','volume']
        ]
    return data
    
    
    
#读取选股的结果
df=pd.read_csv('stock_alpha.csv')
df.columns=['ts_code','name','alpha','start_dt','end_dt']
min_a=df.sort_values(by='alpha')
min_a=min_a.iloc[:10,:] 

code=[]
code=min_a['ts_code']#记录alpha最小的10支股票代码

start_dts=[]
start_dts=min_a['start_dt']#记录alpha最小的10支股票代码 

end_dts=[]
end_dts=min_a['end_dt']#记录alpha最小的10支股票代码 

    
for i in range(len(code)):
    data=ts_get_daily_stock(code.iloc[i],start_dts.iloc[i],end_dts.iloc[i])#字段分别为股票代码、开始日期、结束日期
    data.to_csv(code.iloc[i]+'.csv')    
    
    
    
cerebro = bt.Cerebro()
for i in range(len(code)):#循环获取10支股票历史数据
    dataframe = pd.read_csv(code.iloc[i]+'.csv', index_col=0, parse_dates=True)
    dataframe['openinterest'] = 0
    data = bt.feeds.PandasData(dataname=dataframe,
                        fromdate = datetime.datetime(2019, 1, 1),
                        todate = datetime.datetime(2022, 3, 22)
                        )
cerebro.adddata(data)
 
#回测设置
startcash=100000.0
cerebro.broker.setcash(startcash)
# 设置佣金为千分之一
cerebro.broker.setcommission(commission=0.001)
 # 添加策略
cerebro.addstrategy(MyStrategy,printlog=True) 
cerebro.run() 
#获取回测结束后的总资金
portvalue = cerebro.broker.getvalue()
pnl = portvalue - startcash
#打印结果
print(f'总资金: {round(portvalue,2)}')
print(f'净收益: {round(pnl,2)}')

cerebro.plot()

以上的关于tushare的描述参照了 量化投资1:基于backtrader和tushare实现量化回测(简单策略) - 知乎

这位大佬的部分描述

关于tushare的描述再次不做过多的讲解,有兴趣的同学请参照tushare的官网,代码中所用到的配置股票代码的csv文件 下载路径:

链接:https://pan.baidu.com/s/1664Hta27JBxOGsxoS6iIjQ 
提取码:d7zm

以上关于使用到的python框架请自行百度学习,在此不多过多讲解
    

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大风哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值