backtrader options backtesting framework

Use backtrader data for backtesting, and the data source comes from exchange crawling.

The effect is okay. I believe that you will have a deeper understanding of the application of backtrader through this framework. Including the connection of data, the addition of new indicators.

Import the framework:

__future__ import (absolute_import, division, print_function, unicode_literals)
import pymysql
from sqlalchemy import create_engine
import pandas as pd
import numpy as np
import pymssql
import datetime
import os.path
import sys
import backtrader as bt
import pandas as pd
import akshare as ak
import matplotlib
import matplotlib.pyplot as plt
from backtrader.feeds import PandasData
import datetime
from backtrader.feeds import PandasData
starttime = datetime.datetime.now()
print(starttime)

Import Data

df_read = pd.read_csv('option1.csv')
#df_read = df_read[~df_read['ts_code'].isin([0])]



date_value_list  = []

Create a policy

class BollStrategy(bt.Strategy):
    # 可配置策略参数
    params = dict(
        poneplot=False,  # 是否打印到同一张图
        pstake=1,      # 单笔交易股票数据
    )

    def __init__(self):
        self.order = None

        # for i, d in enumerate(self.datas):
        #     #跳过第一只股票data,第一只股票data作为主图数据
        #     if i == 0:
        #         if self.p.poneplot:
        #             d.plotinfo.plotmaster = self.datas[0]

    def prenext(self):
        # for i,d in enumerate(self.datas):
        # print(d._name)
        self.next()

    # 策略核心,根据条件执行买卖交易指令(必选)
    def next(self):

        # 获取当天日期
        date = self.datas[0].datetime.date(0)

        # 获取当天value
        value = self.broker.getvalue()

        # 存入列表
        date_value_list.append((date, value))
        for i,d in enumerate(self.datas):
            #self.log(f'收盘价,{self.datas[i].close[0]}')
            dt,dn = self.datetime.date(), d._name   #获取时间和股票代码
            print(self.datas[i].rt[0])
            if self.order:
                return
            pos = self.getposition(d).size
            if not pos:
                if self.datas[i].close[0] > 0:
                    self.log(d._name, 'SELL Create, %2f' %self.datas[i].close[0])
                    self.order = self.sell(d , size=self.p.pstake)

                elif self.datas[i].close[0] == 0 or self.datas[i].close[0] > pos.price * 2 or self.datas[i].rt[0] == 0 :
                    self.log(d._name, 'CLOSE Create, %2f' % self.datas[i].close[0])
                    self.order = self.close(d , size= self.p.pstake)
        #pass
        # print(self.datetime.date())
        # for i, d in enumerate(self.datas):
        #     pos = self.getposition(d)
        #     if not len(pos):
        #         if d.close[0]>0:
        #             self.sell(d,size= self.p.pstake)
        #         elif d.close[0] ==0 or d.close[0] > pos.price * 2:
        #             self.close(d,size= self.p.pstake)
        # for d in self.datas:
        #     if len(d) == 0:
        #         continue
        #     else:
        #         # 获取当天日期
        #         date = self.datetime.date()
        #         print(self.datas[0].datetime[0])
        #         #print(date)
        #         #查看持仓盈利情况
        #         for i,d in enumerate(self.datas):
        #             pos = self.getposition(d)
        #             # if self.datas[i].close[0] < 0.05:
        #             #     self.close(d,size = self.params.pstake)
        #             if len(pos):
        #                 # print('{}, 持仓:{}, 成本价:{}, 当前价:{}, 盈亏:{:.2f}'.format(
        #                 #     d._name, pos.size, pos.price, pos.adjbase, pos.size * (pos.adjbase - pos.price)),
        #                 #     file=self.log_file)
        #                 # print('{}, 持仓:{}, 成本价:{}, 当前价:{}, 盈亏:{:.2f}'.format(
        #                 #     d._name, pos.size, pos.price, pos.adjbase, pos.size * (pos.adjbase - pos.price)),
        #                 #     )
        #                 if self.datas[i].close[0] == 0:
        #                     self.close(d,size=self.params.pstake)
        #         # 获取当天value
        #         value = self.broker.getvalue()
        #
        #         # 存入列表
        #         date_value_list.append((date, value))
        #
        #         for i,d in enumerate(self.datas):
        #             #if self.datas[i].close[0] > 0.01:
        #             try:
        #                 if self.datas[i].close[0] > 0:
        #                     #print('buy',d.close[0])
        #                     self.sell(data = d, size=self.params.pstake)
        #                     #print(d._name)
        #                     #order.addinfo(ticker=d._name)
        #                     #print(d._name)
        #                 # else:
        #                 #     #print('sell',d.close[0])
        #                 #     self.close(data = d, size=self.params.pstake)
        #                 #     #order.addinfo(ticker=d._name)
        #                 #     #print(d._name)
        #             except:
        #                 pass
    #交易记录日志
    def log(self,txt,dt = None,doprint=False):
        dt = dt or self.datas[0].datetime.date(0)
        f = open("log.txt",'a')
        date = self.datas[0].datetime.date(0)
        f.write(f'{date},{txt}')
        f.write("\n")
        f.close()
        print(f'{txt}')


    # 记录交易收益情况(可省略,默认不输出结果)
    def notify_trade(self, trade):
        if not trade.isclosed:
            return
        self.log(f'策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}')

    # 订单状态变化时引擎会调用notify_order
    # 记录交易执行情况(可省略,默认不输出结果)
    def notify_order(self, order):

        #print(order.getstatusname(order.status))
        if order.status in [order.Submitted, order.Accepted]:
            return

        # 如果交易已经完成,显示成交信息
        if order.status in [order.Completed]:
            if order.isbuy() or order.issell():
                self.log(f'买入:\n价格:{order.executed.price},\
                                成本:{order.executed.value},\
                                手续费:{order.executed.comm}')
                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log(f'卖出:\n价格:{order.executed.price},\
                            成本: {order.executed.value},\
                            手续费{order.executed.comm}')
            self.bar_executed = len(self)
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('交易失败')
        self.order = None
#回测结束后输出结果(可省略,默认输出结果)
    # def stop(self):
    #     self.log('(MA均线: %2d日) 期末总资金 %.2f' %
    #              (self.params.maperiod, self.broker.getvalue()), doprint=True)

    def stop(self):
        self.log('期末总资金 %.2f' %
                 (self.broker.getvalue()), doprint=True)

Add parameters

#添加参数
class ETFOptionPandasData(PandasData):
    # 新增两条数据线
    lines = ('rt',)

    # 新增数据在dataframe中的位置,分别是第6列和第7列
    params = (('rt', 6),)

Retrieve data and put it into cerebro

cerebro = bt.Cerebro()
# 建立期权池
stk_pools = df_read['ts_code'].unique().tolist()
# 获取期权数据
for stk_code in stk_pools:

    df = df_read[df_read['ts_code'] == stk_code]
    df.index = pd.to_datetime(df['datetime'])
    #print(df.head())
    #data = ETFOptionPandasData(dataname=df)
    df = df[['ts_code', 'open', 'high', 'low', 'close', 'volume','rt']]
    #print(df.head())
    data = ETFOptionPandasData(dataname = df,datetime = -1)
    cerebro.adddata(data, name = str(stk_code))

Run the strategy and add trading parameters

cerebro.broker.setcash(10000000.0)
cerebro.broker.setcommission(commission=1.62,margin = 2000,mult= 10000 )
cerebro.addstrategy(BollStrategy)
cerebro.broker.set_coc(True)#设置以当天收盘价成交
cerebro.run()  #减少内存。此设置会自动禁止数据预加载(preload)和指标预计算(runonce),也禁止绘图plot,因为内存中数据不足以绘图了。
for d in cerebro.datas:
    d.plotinfo.plot =False
print('cash',cerebro.broker.getvalue())

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324323645&siteId=291194637