python tushare backtrader stock backtest double moving average strategy

Foreword:
After learning some machine learning knowledge, I found that I did not have a backtest framework. I found a short-term learning material and decided to use backtrader. As for the platforms of Jukuan Umi, it seems that they are not so free to use. Learn the backtrader, straighten out the knowledge you have learned after learning, and then organize a framework that fits your own use. The more you learn, the more chaotic you are. You have to re-examine your needs. The following are some notes of my learning backtrader, mainly to use the data of tushaer directly, there is no need to convert the local CSV data first, it is convenient and fast, the code is as follows:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import datetime
import pandas as pd
import backtrader as bt
import tushare as ts
import numpy as np

# 创建策略类
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)

    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复制到这里,可以的话请帮个忙用文章末我分享的链接注册,谢谢')
    stock_code = '000001.SZ'
    df = pro.daily(ts_code=stock_code, start_date='20200101', end_date='20200828')
    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)  # 将时间顺序升序,符合时间序列

    dataframe = df
    dataframe['openinterest'] = 0
    data = bt.feeds.PandasData(dataname=dataframe,
                               fromdate=datetime.datetime(2020, 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.run()
    # 输出结果
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    cerebro.plot()

Tushare registration link: link

Guess you like

Origin blog.csdn.net/Wilburzzz/article/details/108337972