前言:
backtrader多股回测,大体功能就是一边下载tushare股票数据,一边均线金叉死叉回测,现在A股估计都不止4000多只股票了,运行起来一个字就是慢,没有进行选股筛选,就是一个策略全部股票进行回测,先放出代码进行记录,后面再优化下,看下能不能加快下速度。
from __future__ import (absolute_import, division, print_function,
unicode_literals)
import os
import datetime
import pandas as pd
import backtrader as bt
import tushare as ts
import numpy as np
os.chdir('D:/stock_backtrader//')
# 创建策略类
class TestStrategy(bt.Strategy):
# 设置简单均线周期,以备后面调用
params = (
('maperiod21', 21),
('maperiod55', 55)
)
def log(self, txt, dt=None):
# 日记记录输出
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def __init__(self):
# 初始化数据参数
# 设置当前收盘价为dataclose
self.dataclose = self.datas[0].close
self.order = None
self.buyprice = None
self.buycomm = None
# 添加简单均线
self.sma21 = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.maperiod21)
self.sma55 = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.maperiod55)
bt.indicators.ExponentialMovingAverage(self.datas[0], period=25)
bt.indicators.WeightedMovingAverage(self.datas[0], period=25,
subplot=True)
bt.indicators.StochasticSlow(self.datas[0])
bt.indicators.MACDHisto(self.datas[0])
rsi = bt.indicators.RSI(self.datas[0])
bt.indicators.SmoothedMovingAverage(rsi, period=10)
bt.indicators.ATR(self.datas[0], plot=True)
def notify_order(self, order):
if order.status in [order.Submitted, order.Accepted]:
# 如果有订单提交或者已经接受的订单,返回退出
return
# 主要是检查有没有成交的订单,如果有则日志记录输出价格,金额,手续费。注意,如果资金不足是不会成交订单的
if order.status in [order.Completed]:
if order.isbuy():
self.log(
'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else: # Sell
self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
(order.executed.price,
order.executed.value,
order.executed.comm))
# len(self)是指获取截至当前数据一共有多少根bar
# 以下代码就是指当交易发生时立刻记录下了当天有多少根bar
# 如果要表示当成交后过了5天卖,则可以这样写 if len(self) >= (self.bar_executed + 5):
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log('Order Canceled/Margin/Rejected')
self.order = None
def notify_trade(self, trade):
if not trade.isclosed: # 如果交易还没有关闭,则退出不输出显示盈利跟手续费
return
self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
(trade.pnl, trade.pnlcomm))
def next(self):
# 输出显示收盘价
self.log('Close, %.2f' % self.dataclose[0])
# 检查是否有订单发送当中,如果有则不再发送第二个订单
if self.order:
return
# 检查是否已经有仓位
if not self.position:
# 如果没有则可以执行一下策略了
if self.sma21[0] > self.sma55[0]:
# 记录输出买入价格
self.log('BUY CREATE, %.2f' % self.dataclose[0])
# 跟踪已经创建好的订单避免重复第二次交易
self.order = self.buy()
else:
if self.sma21[0] < self.sma55[0]:
self.log('SELL CREATE, %.2f' % self.dataclose[0])
self.order = self.sell()
if __name__ == '__main__':
# 创建策略容器
cerebro = bt.Cerebro()
# 添加自定义的策略TestStrategy
cerebro.addstrategy(TestStrategy)
pro = ts.pro_api('要到tushare官网注册个账户然后将token复制到这里,可以的话请帮个忙用文章末我分享的链接注册,谢谢')
df = pro.daily(start_date='20190101', end_date='20200828')
stock_list = df.ts_code.values
for i in stock_list:
df = pro.daily(ts_code=i, start_date='20160101', end_date='20200901')
df['trade_date'] = pd.to_datetime(df['trade_date'])
df = df.drop(['change', 'pre_close', 'pct_chg', 'amount'], axis=1)
df = df.rename(columns={'vol': 'volume'})
df.set_index('trade_date', inplace=True) # 设置索引覆盖原来的数据
df = df.sort_index(ascending=True) # 将时间顺序升序,符合时间序列
df.to_csv(str(i) + '.csv', index=True, encoding='gbk')
dataframe = df
for stock in os.listdir():
dataframe = pd.read_csv(stock, index_col=0, parse_dates=True)
dataframe['openinterest'] = 0
data = bt.feeds.PandasData(dataname=dataframe,
fromdate=datetime.datetime(2019, 1, 1),
todate=datetime.datetime(2020, 8, 20)
)
# 添加数据
cerebro.adddata(data)
# 设置资金
cerebro.broker.setcash(10000.0)
# 设置每笔交易交易的股票数量
cerebro.addsizer(bt.sizers.FixedSize, stake=100)
# 设置手续费
cerebro.broker.setcommission(commission=0.01)
# 输出初始资金
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='SharpeRatio')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='DW')
thestrats = cerebro.run()
thestrat = thestrats[0]
print('夏普比率:', thestrat.analyzers.SharpeRatio.get_analysis())
print('回撤指标:', thestrat.analyzers.DW.get_analysis())
# 运行策略
# cerebro.run()
# 输出结果
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
#cerebro.plot()
tushare注册链接:link