{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# backtrader教程\n",
"\n",
"**by Zoe**\n",
"\n",
"
\n",
"
\n",
"
\n",
"\n",
"backtrader是基于Python的量化框架平台,内置了talib指标库、analyzer分析库等功能,具有回测速度快、易用性高以及扩展性好等特点。相较于网上已有教程,本教程从数据至分析进行了全面的介绍,着重阐述了数据清洗以及框架调整等部分,点出了backtrader的某些不足并提供了解决方法。\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from datetime import datetime\n",
"import backtrader as bt\n",
"import tushare as ts\n",
"import pandas as pd\n",
"from backtrader.feeds import PandasData"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 数据加载\n",
"### 1.1. data collecting\n",
"\n",
"backtrader支持Yahoo等online的数据源和本地数据源。大家也可以自己造轮子,接wind,tushare等。\n",
"backtrader要求至少含有7列数据,包括datetime,open,high,low,close,volume,openinterest。本文把datetime设为了index。\n",
"\n",
"本文拉前复权数据,前复权就是从后往前复权,所以复权后最近的价格保持一致。至于后复权,vice versa。有些数据源的前复权机制会有负数的存在,这是因为计算复权的时候是价格减去了分红,而不是用的累计复权因子,https://xueqiu.com/3488649239/62074848 这篇文章已经介绍得很详细,本文就不抛砖引玉了。注意:在用累计因子的情况下,前后复权的选择不影响收益率。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# tushare\n",
"def get_single_kdata(code, start='2020-01-01', end='2021-08-18', index=False):\n",
" df = ts.get_k_data(code, autype='qfq', start=start, end=end, index=index)\n",
" df['date'] = pd.to_datetime(df['date'])\n",
" df['openinterest'] = 0\n",
" return df[['date', 'open', 'high', 'low', 'close', 'volume', 'openinterest']]\n",
"\n",
"# # yahoo\n",
"# def get_single_kdata(code, start='2020-01-01', end='2021-08-18'):\n",
"# df = bt.feeds.YahooFinanceData(\n",
"# dataname='AAPL',\n",
"# fromdate=datetime.strptime(start,'%Y-%m-%d'),\n",
"# todate=datetime.strptime(end,'%Y-%m-%d'),\n",
"# adjclose=True,\n",
"# adjvolume=True)\n",
"# return df"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" date open high low close volume openinterest\n",
"0 2020-01-02 16.65 16.95 16.55 16.87 1530231.0 0\n",
"1 2020-01-03 16.94 17.31 16.92 17.18 1116194.0 0\n",
"2 2020-01-06 17.01 17.34 16.91 17.07 862083.0 0\n",
"3 2020-01-07 17.13 17.28 16.95 17.15 728607.0 0\n",
"4 2020-01-08 17.00 17.05 16.63 16.66 847824.0 0\n"
]
}
],
"source": [
"secu_lst = ['600000','000001']\n",
"kdata = {}\n",
"for secu in secu_lst:\n",
" kdata[secu] = get_single_kdata(secu)\n",
" \n",
"print(kdata['000001'].head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对于一个策略,股票池常常是不断变化的,不可能只有一个起点和终点。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" date open high low close volume openinterest\n",
"0 2020-02-03 13.99 14.70 13.99 13.99 2259194.0 0\n",
"1 2020-02-04 14.05 14.66 14.02 14.60 1706172.0 0\n",
"2 2020-02-05 14.59 14.89 14.32 14.63 1491380.0 0\n",
"3 2020-02-06 14.81 14.87 14.51 14.77 1185815.0 0\n",
"4 2020-02-07 14.60 14.69 14.41 14.62 924852.0 0\n"
]
}
],
"source": [
"# 如果你想要的不同的start和end\n",
"# 自己定义\n",
"secu_lst = {'600000':{'start':'2020-01-01','end':'2020-07-18'},\n",
" '000001':{'start':'2020-02-01','end':'2020-08-18'}}\n",
"kdata = {}\n",
"for secu in secu_lst.keys():\n",
" kdata[secu] = get_single_kdata(secu, secu_lst[secu]['start'], secu_lst[secu]['end']).reset_index(drop=True)\n",
" \n",
"print(kdata['000001'].head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1.2. data cleansing and processing\n",
"\n",
"上述股票的日期并没有对齐,造成开始停止日不同的原因还有股池的筛选条件、新股上市、股票停牌等。而backtrader的运作机制next()需要all data都满足最小周期,否则需要调用prenext()。本文建议一个更简单的方法,补充数据使所有股票拥有同样的周期,并同时标注停牌日。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"start: 2020-01-01, end 2020-08-18\n",
"start: 2020-01-02 00:00:00, end 2020-08-18 00:00:00\n"
]
}
],
"source": [
"# 先拿大盘trading_dates\n",
"benchmark_start = min(secu_lst.values(), key=lambda x : x['start'])['start']\n",
"benchmark_end = max(secu_lst.values(), key=lambda x : x['end'])['end']\n",
"print(f\"start: {benchmark_start}, end {benchmark_end}\")\n",
"\n",
"benchmark = '399905' # 中证500\n",
"kdata['benchmark'] = get_single_kdata(benchmark, benchmark_start, benchmark_end, index=True) \n",
"trading_dates = kdata['benchmark']['date'].tolist()\n",
"print(f\"start: {trading_dates[0]}, end {trading_dates[-1]}\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"000001\n",
" open high low close volume openinterest suspend\n",
"date \n",
"2020-01-02 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-03 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-06 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-07 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-08 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"... ... ... ... ... ... ... ...\n",
"2020-08-12 14.21 14.50 14.15 14.38 1596812.0 0.0 0\n",
"2020-08-13 14.40 14.46 14.14 14.18 837262.0 0.0 0\n",
"2020-08-14 14.10 14.51 14.06 14.47 1103216.0 0.0 0\n",
"2020-08-17 14.60 15.35 14.55 15.19 3268028.0 0.0 0\n",
"2020-08-18 15.20 15.30 14.91 15.15 1350261.0 0.0 0\n",
"\n",
"[152 rows x 7 columns]\n",
"600000\n",
" open high low close volume openinterest suspend\n",
"date \n",
"2020-01-02 12.47 12.64 12.45 12.47 516290.0 0.0 0\n",
"2020-01-03 12.57 12.63 12.47 12.60 380188.0 0.0 0\n",
"2020-01-06 12.52 12.65 12.42 12.46 410011.0 0.0 0\n",
"2020-01-07 12.51 12.60 12.46 12.50 284214.0 0.0 0\n",
"2020-01-08 12.41 12.45 12.25 12.32 352405.0 0.0 0\n",
"... ... ... ... ... ... ... ...\n",
"2020-08-12 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-13 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-14 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-17 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-18 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"\n",
"[152 rows x 7 columns]\n"
]
}
],
"source": [
"for secu in set(kdata.keys())-set(['benchmark']):\n",
" print(secu)\n",
" secu_kdata = kdata['benchmark'][['date']].merge(kdata[secu],how='left')\n",
" secu_kdata['suspend'] = 0 \n",
" secu_kdata.loc[secu_kdata['open'].isnull(), 'suspend'] = 1 # 标记为停盘日\n",
" secu_kdata.set_index(['date'], inplace = True) # 设date为index\n",
" end = secu_lst[secu]['end']\n",
" secu_kdata.fillna(method='ffill',inplace = True) # start后的数据用前日数据进行补充\n",
" secu_kdata.fillna(value = 0,inplace = True) #start前的数据用0补充\n",
" secu_kdata.loc[(secu_kdata.index > end), 'suspend'] = 1\n",
" print(secu_kdata)\n",
" kdata[secu] = secu_kdata"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"股票池的筛选也同理,补充数据就ok,但要注意,end是剔除日的后一根bar的日期。\n",
"整理成一个class会更清晰一点"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"class GetKdatas(object):\n",
" def __init__(self, secu_lst, benchmark='000001'):\n",
" \"\"\"\n",
" :parameter secu_lst: a dict contained stocks with starts and ends\n",
" :parameter benchmark: the name of benchmark\n",
" \"\"\"\n",
" self.secu_lst = secu_lst\n",
" self.benchmark = benchmark\n",
"\n",
" @staticmethod\n",
" def get_single_kdata(code, start='2020-01-01', end='2021-08-18', index=False):\n",
" df = ts.get_k_data(code, autype='qfq', start=start, end=end, index=index)\n",
" df['date'] = pd.to_datetime(df['date'])\n",
" df['openinterest'] = 0\n",
" return df[['date', 'open', 'high', 'low', 'close', 'volume', 'openinterest']]\n",
"\n",
" def get_all_kdata(self):\n",
" kdata = {}\n",
" for secu in set(self.secu_lst):\n",
" secu_kdata = self.get_single_kdata(secu, self.secu_lst[secu]['start'], self.secu_lst[secu]['end'])\n",
" kdata[secu] = secu_kdata.reset_index(drop=True)\n",
" return kdata\n",
"\n",
" def merge_period(self):\n",
" all_kdata = self.get_all_kdata()\n",
" benchmark_start = min(self.secu_lst.values(), key=lambda x: x['start'])['start']\n",
" benchmark_end = max(self.secu_lst.values(), key=lambda x: x['end'])['end']\n",
" all_kdata['benchmark'] = self.get_single_kdata(self.benchmark, benchmark_start, benchmark_end,True)\n",
"\n",
" for secu in set(all_kdata.keys()) - set(['benchmark']):\n",
" secu_kdata = all_kdata['benchmark'][['date']].merge(all_kdata[secu], how='left')\n",
" secu_kdata['suspend'] = 0\n",
" secu_kdata.loc[secu_kdata['open'].isnull(), 'suspend'] = 1 # 标记为停盘日\n",
" secu_kdata.set_index(['date'], inplace=True) # 设date为index\n",
" end = secu_lst[secu]['end']\n",
" secu_kdata.fillna(method='ffill', inplace=True) # start后的数据用前日数据进行补充\n",
" secu_kdata.fillna(value=0, inplace=True) # start前的数据用0补充\n",
" secu_kdata.loc[(secu_kdata.index > end), 'suspend'] = 1\n",
" all_kdata[secu] = secu_kdata\n",
"\n",
" _ = all_kdata.pop('benchmark')\n",
" return all_kdata"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'000001': open high low close volume openinterest suspend\n",
"date \n",
"2020-01-02 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-03 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-06 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-07 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"2020-01-08 0.00 0.00 0.00 0.00 0.0 0.0 1\n",
"... ... ... ... ... ... ... ...\n",
"2020-08-12 14.21 14.50 14.15 14.38 1596812.0 0.0 0\n",
"2020-08-13 14.40 14.46 14.14 14.18 837262.0 0.0 0\n",
"2020-08-14 14.10 14.51 14.06 14.47 1103216.0 0.0 0\n",
"2020-08-17 14.60 15.35 14.55 15.19 3268028.0 0.0 0\n",
"2020-08-18 15.20 15.30 14.91 15.15 1350261.0 0.0 0\n",
"\n",
"[152 rows x 7 columns], '600000': open high low close volume openinterest suspend\n",
"date \n",
"2020-01-02 12.47 12.64 12.45 12.47 516290.0 0.0 0\n",
"2020-01-03 12.57 12.63 12.47 12.60 380188.0 0.0 0\n",
"2020-01-06 12.52 12.65 12.42 12.46 410011.0 0.0 0\n",
"2020-01-07 12.51 12.60 12.46 12.50 284214.0 0.0 0\n",
"2020-01-08 12.41 12.45 12.25 12.32 352405.0 0.0 0\n",
"... ... ... ... ... ... ... ...\n",
"2020-08-12 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-13 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-14 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-17 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"2020-08-18 11.37 11.39 11.17 11.27 686395.0 0.0 1\n",
"\n",
"[152 rows x 7 columns]}\n"
]
}
],
"source": [
"secu_lst = {'600000': {'start': '2020-01-01', 'end': '2020-07-18'},\n",
" '000001': {'start': '2020-02-01', 'end': '2020-08-18'}}\n",
"\n",
"kdata = GetKdatas(secu_lst).merge_period()\n",
"print(kdata)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"### 1.3. data feeding\n",
"\n",
"接下来就是放入数据,backtrader默认仅datetime,open,high,low,close,volume,openinterest这7列。\n",
"
\n",
"默认顺序为open (default: 1) , high (default: 2), low (default: 3), close (default: 4), volume (default: 5), openinterest (default: 6)。\n",
"
\n",
"一定,一定要记得在add时加入*name=secu*,不然回溯股票的代码很麻烦"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"cerebro = bt.Cerebro()\n",
"for secu in set(kdata.keys())-set(['benchmark']):\n",
" df = PandasData(dataname=kdata[secu], fromdate=kdata[secu].index[0],todate=kdata[secu].index[-1])\n",
" cerebro.adddata(df, name=secu) \n",
"\n",
"# 如果是本地csv,如果你的column是和默认一样的,那从datetime开始都不用写,否则必须指明\n",
"# data = btfeeds.GenericCSVData(\n",
"# dataname='mydata.csv',\n",
"# fromdate=benchmark_start,\n",
"# todate=benchmark_end,\n",
"# dtformat=('%Y-%m-%d'),\n",
"# datetime=0,\n",
"# high=1,\n",
"# low=2,\n",
"# open=3,\n",
"# close=4,\n",
"# volume=5,\n",
"# openinterest=-1\n",
"# )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**如果你要增添其他的指标,可以根据以下模块。注意放入数据的时候是PandasData_Extend。如果是load本地文件,就把PandasData换成GenericCSVData,序号从序列8开始。"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"class PandasData_Extend(PandasData):\n",
" # Add a 'suspend' line to the inherited ones from the base class\n",
" lines = ('suspend',)\n",
" # 现在是(open,0), ... , (openinterest,5)这6列,所以增加1\n",
" # add the parameter to the parameters inherited from the base class\n",
" params = (('suspend', 6),)\n",
" \n",
" # 如果是csv文档,openinterest 在 GenericCSVData index是7,所以1\n",
" # params = (('suspend', 8),)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 框架介绍\n",
"### 2.1. 初始资金、买卖佣金设置\n",
"\n",
"初始资金默认10000,但众所周知,初始金额的大小会影响整个策略收益。如果过小,会买不进某些大盘股。如果过大,会导致小盘股的买入划价增加很多,甚至无法购买预期数量的小盘股,因此需要设置初始资金。"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"初始资金1000000\n"
]
}
],
"source": [
"cerebro = bt.Cerebro()\n",
"# 设置初始资本为1 million\n",
"startcash = 10**6\n",
"cerebro.broker.setcash(startcash)\n",
"print(f\"初始资金{cerebro.broker.getvalue()}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"费率也是一大问题,券商佣金最低收五元,沪市过户费最低收一元。不要小看这些费率,当你做高频交易的时候,你的利润可能大都被这些费率吃掉了。\n",
"
\n",
"本文为简略,过户费没有进行对市场的判断。如需,加上判断即可。"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"class CommInfoPro(bt.CommInfoBase):\n",
"\n",
" params = (\n",
" ('stamp_duty', 0.001), # 印花税率\n",
" ('stamp_duty_fe', 1), # 最低印花税\n",
" ('commission', 0.001), # 佣金率\n",
" ('commission_fee', 5), # 最低佣金费\n",
" ('stocklike', True), # 股票\n",
" ('commtype', bt.CommInfoBase.COMM_PERC), # 按比例收\n",
" )\n",
"\n",
" def _getcommission(self, size, price, pseudoexec):\n",
" '''\n",
" If size is greater than 0, this indicates a long / buying of shares.\n",
" If size is less than 0, it idicates a short / selling of shares.\n",
" '''\n",
"\n",
" if size > 0: # 买入,不考虑印花税\n",
" return max(size * price * self.p.commission, self.p.commission_fee)\n",
" elif size < 0: # 卖出,考虑印花税\n",
" return max(size * price * (self.p.stamp_duty + self.p.commission), self.p.stamp_duty_fe)\n",
" else:\n",
" return 0 # just in case for some reason the size is 0.\n",
"\n",
" \n",
"cerebro.broker.addcommissioninfo(CommInfoPro())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.2. 下单函数调整\n",
"众所周知,A股市以每手100股成交的,所以order size必须为100的整数倍。因此我们在计算的时候也应该注意这一点。一种方法是在backtrader内部修改order函数,在计算amount的时候downcast,因为jupyter不好展示这一步骤。本文通过在order的时候计算这一amount来解决。\n",
"\n",
"注意:都往下约,保持现金充足"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"400\n",
"500\n"
]
}
],
"source": [
"# 原有\n",
"#self.buy(data, amount)\n",
"#self.sell(data, amount)\n",
"\n",
"#改为\n",
"def downcast(amount, lot):\n",
" return abs(amount//lot*lot)\n",
"\n",
"print(downcast(418,100))\n",
"print(downcast(-418,100))\n",
"#self.buy(data, downcast(amount, lot))\n",
"#self.sell(data, downcast(amount, lot))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.3. 增加股票信息\n",
"\n",
"backtrader把股票名设为了data._name,本文不建议通过这种方式进行抽取。最好是在linseries.py里加入装饰器@property\n",
"
"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"# in linseries.py\n",
"# @property\n",
"# def name(self):\n",
"# return self._name"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.4 data和line的介绍\n",
"\n",
"line是backtrader的核心,是储存数据的重要形式。多条line组成lines,包括在data feed模块放入的open(开盘价)、close(收盘价)等6条line。可以把line看成是一条时间线,0代表当下的数据,-1代表前一根bar的数据,-2代表前两根bar的数据;同样,1代表后一根bar的数据,2代表后两根bar的数据,以此内推。\n",
"\n",
"data是line的集合,是line的展现形式。data代表单个个股(商品、债券等)的数据,包括open、close等lines,而多个data组成list形式的datas。在取某只股票的data时,可以通过self.datas[x]或者self.datax,x代表该股票被放入的顺序号(从0开始),也可以通过self.datasbyname[data._name]取得。\n",
"\n",
"backtrader也提供了指标的不同提取方式。以data0的close举例,包括:self.data0.close[0],self.data0_close[0],self.data0_0[0](第二个0代表close的顺序号0)。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. 策略回测\n",
"### 3.1. 单只股票\n",
"接下来就开始单只股票的回测示范。本策略逻辑收盘价>20日均线就买入,否则卖出。\n",
"由于指标简单,可以在init里直接,计算节省时间。否则需要在next里每次进行计算\n",
"1. self.params.your_param等价于self.params.maperiod\n",
"2. self.datas是list格式,因为仅单只股票,所有长度为1。self.datas[0]代表的是这只股票的数据\n",
"\n",
"\n",
"在backtrader的order属性里,也是不包含股票的name。一种方法是修改order的class,本文从简,将name作为参数传入。\n",
"
\n",
"在买入卖出时,可以根据以下常用方法\n",
"1. self.order_target_percent(secu_data, target_pct, name=secu)\n",
"2. self.order_target_value(secu_data, target_val, name=secu)\n",
"3. self.buy(secu_data, order_amount, name=secu)\n",
"4. self.sell(secu_data, order_amount, name=secu)\n",
"\n",
"注意:本策略是以日为单位运行,以第二日开盘价作为交割价。backtrader的运行机制是以购买的资金/今日收盘价,得到购买数量后第二日开盘买入。所以买卖时为避免第二日开盘价与今日收盘价的差价,不能以全仓买入。 且在最后一天不做任何下单买卖。\n",
"
\n",
"注意:股票剔除是当下bar做出的决定,但是在后一根bar,也就是end_date进行的买卖。所以一定要放入后一根bar的开盘数据作为交割价,不然有未来函数。在策略购买卖中,需要规范在股票剔除日(end_date)必须卖出。"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"初始资金1000000\n",
"2020-02-06, 1000000.00元\n",
"2020-02-07, 1000000.00元\n",
"2020-02-10, 1000000.00元\n",
"2020-02-11, 1000000.00元\n",
"2020-02-12, 1000000.00元\n",
"2020-02-13, 1000000.00元\n",
"2020-02-14, 1000000.00元\n",
"2020-02-17, 1000000.00元\n",
"2020-02-18, 1000000.00元\n",
"2020-02-19, 1000000.00元\n",
"2020-02-20, 1000000.00元\n",
"2020-02-20, 买600000, price:11.23, amout: 87200.0\n",
"2020-02-21, 买入600000, 成交量87200.0,成交价11.23\n",
"2020-02-21, 1006094.21元\n",
"2020-02-21, 卖600000, price:11.30, pct: 0\n",
"2020-02-24, 卖出600000, 成交量-87200.0,成交价11.23\n",
"2020-02-24, 999989.21元\n",
"2020-02-24, 买600000, price:11.16, amout: 87800.0\n",
"2020-02-25, 买入600000, 成交量87800.0,成交价11.07\n",
"2020-02-25, 1001735.49元\n",
"2020-02-25, 卖600000, price:11.09, pct: 0\n",
"2020-02-26, 卖出600000, 成交量-87800.0,成交价11.01\n",
"2020-02-26, 994710.49元\n",
"2020-02-26, 买600000, price:11.20, amout: 87000.0\n",
"2020-02-27, 买入600000, 成交量87000.0,成交价11.20\n",
"2020-02-27, 995570.74元\n",
"2020-02-27, 卖600000, price:11.21, pct: 0\n",
"2020-02-28, 卖出600000, 成交量-87000.0,成交价11.11\n",
"2020-02-28, 986869.74元\n",
"2020-03-02, 986869.74元\n",
"2020-03-02, 买600000, price:11.04, amout: 87600.0\n",
"2020-03-03, 买入600000, 成交量87600.0,成交价11.13\n",
"2020-03-03, 980727.99元\n",
"2020-03-03, 卖600000, price:11.06, pct: 0\n",
"2020-03-04, 卖出600000, 成交量-87600.0,成交价11.01\n",
"2020-03-04, 976346.99元\n",
"2020-03-04, 买600000, price:11.03, amout: 86700.0\n",
"2020-03-05, 买入600000, 成交量86700.0,成交价11.08\n",
"2020-03-05, 997145.39元\n",
"2020-03-05, 卖600000, price:11.32, pct: 0\n",
"2020-03-06, 卖出600000, 成交量-86700.0,成交价11.23\n",
"2020-03-06, 989341.39元\n",
"2020-03-06, 买600000, price:11.12, amout: 87100.0\n",
"2020-03-09, 买入600000, 成交量87100.0,成交价11.00\n",
"2020-03-09, 970169.81元\n",
"2020-03-10, 978008.81元\n",
"2020-03-11, 969298.81元\n",
"2020-03-12, 957975.81元\n",
"2020-03-13, 963201.81元\n",
"2020-03-16, 946652.81元\n",
"2020-03-17, 939684.81元\n",
"2020-03-18, 920522.81元\n",
"2020-03-19, 897005.81元\n",
"2020-03-20, 910070.81元\n",
"2020-03-23, 888295.81元\n",
"2020-03-24, 907457.81元\n",
"2020-03-25, 915296.81元\n",
"2020-03-26, 922264.81元\n",
"2020-03-27, 923135.81元\n",
"2020-03-30, 926619.81元\n",
"2020-03-31, 915296.81元\n",
"2020-04-01, 910070.81元\n",
"2020-04-02, 919651.81元\n",
"2020-04-03, 915296.81元\n",
"2020-04-07, 926619.81元\n",
"2020-04-08, 923135.81元\n",
"2020-04-09, 919651.81元\n",
"2020-04-10, 920522.81元\n",
"2020-04-10, 卖600000, price:10.21, pct: 0\n",
"2020-04-13, 卖出600000, 成交量-87100.0,成交价10.15\n",
"2020-04-13, 915295.81元\n",
"2020-04-14, 915295.81元\n",
"2020-04-14, 买600000, price:10.25, amout: 87500.0\n",
"2020-04-15, 买入600000, 成交量87500.0,成交价10.20\n",
"2020-04-15, 913536.88元\n",
"2020-04-15, 卖600000, price:10.18, pct: 0\n",
"2020-04-16, 卖出600000, 成交量-87500.0,成交价10.10\n",
"2020-04-16, 906535.88元\n",
"2020-04-16, 买600000, price:10.16, amout: 87400.0\n",
"2020-04-17, 买入600000, 成交量87400.0,成交价10.18\n",
"2020-04-17, 908274.98元\n",
"2020-04-17, 卖600000, price:10.20, pct: 0\n",
"2020-04-20, 卖出600000, 成交量-87400.0,成交价10.15\n",
"2020-04-20, 903903.98元\n",
"2020-04-21, 903903.98元\n",
"2020-04-22, 903903.98元\n",
"2020-04-23, 903903.98元\n",
"2020-04-24, 903903.98元\n",
"2020-04-27, 903903.98元\n",
"2020-04-27, 买600000, price:10.34, amout: 85600.0\n",
"2020-04-28, 买入600000, 成交量85600.0,成交价10.36\n",
"2020-04-28, 901327.12元\n",
"2020-04-28, 卖600000, price:10.33, pct: 0\n",
"2020-04-29, 卖出600000, 成交量-85600.0,成交价10.35\n",
"2020-04-29, 903038.12元\n",
"2020-04-29, 买600000, price:10.61, amout: 83400.0\n",
"2020-04-30, 买入600000, 成交量83400.0,成交价10.58\n",
"2020-04-30, 907199.29元\n",
"2020-04-30, 卖600000, price:10.63, pct: 0\n",
"2020-05-06, 卖出600000, 成交量-83400.0,成交价10.44\n",
"2020-05-06, 891352.29元\n",
"2020-05-06, 买600000, price:10.46, amout: 83500.0\n",
"2020-05-07, 买入600000, 成交量83500.0,成交价10.45\n",
"2020-05-07, 886333.57元\n",
"2020-05-07, 卖600000, price:10.39, pct: 0\n",
"2020-05-08, 卖出600000, 成交量-83500.0,成交价10.44\n",
"2020-05-08, 890507.57元\n",
"2020-05-08, 买600000, price:10.44, amout: 83500.0\n",
"2020-05-11, 买入600000, 成交量83500.0,成交价10.44\n",
"2020-05-11, 889663.85元\n",
"2020-05-11, 卖600000, price:10.43, pct: 0\n",
"2020-05-12, 卖出600000, 成交量-83500.0,成交价10.44\n",
"2020-05-12, 890497.85元\n",
"2020-05-12, 买600000, price:10.34, amout: 84300.0\n",
"2020-05-13, 买入600000, 成交量84300.0,成交价10.31\n",
"2020-05-13, 896390.16元\n",
"2020-05-13, 卖600000, price:10.38, pct: 0\n",
"2020-05-14, 卖出600000, 成交量-84300.0,成交价10.32\n",
"2020-05-14, 891331.16元\n",
"2020-05-14, 买600000, price:10.30, amout: 84800.0\n",
"2020-05-15, 买入600000, 成交量84800.0,成交价10.36\n",
"2020-05-15, 884538.37元\n",
"2020-05-18, 887930.37元\n",
"2020-05-18, 卖600000, price:10.32, pct: 0\n",
"2020-05-19, 卖出600000, 成交量-84800.0,成交价10.45\n",
"2020-05-19, 898953.37元\n",
"2020-05-19, 买600000, price:10.35, amout: 85100.0\n",
"2020-05-20, 买入600000, 成交量85100.0,成交价10.37\n",
"2020-05-20, 902348.55元\n",
"2020-05-20, 卖600000, price:10.41, pct: 0\n",
"2020-05-21, 卖出600000, 成交量-85100.0,成交价10.44\n",
"2020-05-21, 904900.55元\n",
"2020-05-21, 买600000, price:10.33, amout: 85800.0\n",
"2020-05-22, 买入600000, 成交量85800.0,成交价10.30\n",
"2020-05-22, 891163.71元\n",
"2020-05-25, 902317.71元\n",
"2020-05-26, 902317.71元\n",
"2020-05-27, 909181.71元\n",
"2020-05-28, 924625.71元\n",
"2020-05-28, 卖600000, price:10.53, pct: 0\n",
"2020-05-29, 卖出600000, 成交量-85800.0,成交价10.45\n",
"2020-05-29, 917760.71元\n",
"2020-05-29, 买600000, price:10.57, amout: 85000.0\n",
"2020-06-01, 买入600000, 成交量85000.0,成交价10.63\n",
"2020-06-01, 919451.68元\n",
"2020-06-01, 卖600000, price:10.65, pct: 0\n",
"2020-06-02, 卖出600000, 成交量-85000.0,成交价10.58\n",
"2020-06-02, 913500.68元\n",
"2020-06-02, 买600000, price:10.68, amout: 83800.0\n",
"2020-06-03, 买入600000, 成交量83800.0,成交价10.75\n",
"2020-06-03, 909301.67元\n",
"2020-06-03, 卖600000, price:10.70, pct: 0\n",
"2020-06-04, 卖出600000, 成交量-83800.0,成交价10.80\n",
"2020-06-04, 917680.67元\n",
"2020-06-04, 买600000, price:10.64, amout: 84500.0\n",
"2020-06-05, 买入600000, 成交量84500.0,成交价10.68\n",
"2020-06-05, 916826.64元\n",
"2020-06-05, 卖600000, price:10.67, pct: 0\n",
"2020-06-08, 卖出600000, 成交量-84500.0,成交价10.64\n",
"2020-06-08, 914290.64元\n",
"2020-06-08, 买600000, price:10.61, amout: 84400.0\n",
"2020-06-09, 买入600000, 成交量84400.0,成交价10.62\n",
"2020-06-09, 919345.68元\n",
"2020-06-09, 卖600000, price:10.68, pct: 0\n",
"2020-06-10, 卖出600000, 成交量-84400.0,成交价10.71\n",
"2020-06-10, 921876.68元\n",
"2020-06-10, 买600000, price:10.58, amout: 85300.0\n",
"2020-06-11, 买入600000, 成交量85300.0,成交价10.58\n",
"2020-06-11, 913337.65元\n",
"2020-06-11, 卖600000, price:10.48, pct: 0\n",
"2020-06-12, 卖出600000, 成交量-85300.0,成交价10.58\n",
"2020-06-12, 921866.65元\n",
"2020-06-12, 买600000, price:10.55, amout: 85600.0\n",
"2020-06-15, 买入600000, 成交量85600.0,成交价10.41\n",
"2020-06-15, 916721.74元\n",
"2020-06-16, 925281.74元\n",
"2020-06-17, 926993.74元\n",
"2020-06-18, 929561.74元\n",
"2020-06-19, 938977.74元\n",
"2020-06-19, 卖600000, price:10.61, pct: 0\n",
"2020-06-22, 卖出600000, 成交量-85600.0,成交价10.57\n",
"2020-06-22, 935552.74元\n",
"2020-06-22, 买600000, price:10.55, amout: 86900.0\n",
"2020-06-23, 买入600000, 成交量86900.0,成交价10.51\n",
"2020-06-23, 932936.61元\n",
"2020-06-24, 943364.61元\n",
"2020-06-24, 卖600000, price:10.60, pct: 0\n",
"2020-06-29, 卖出600000, 成交量-86900.0,成交价10.63\n",
"2020-06-29, 945970.61元\n",
"2020-06-29, 买600000, price:10.57, amout: 87700.0\n",
"2020-06-30, 买入600000, 成交量87700.0,成交价10.59\n",
"2020-06-30, 945084.32元\n",
"2020-06-30, 卖600000, price:10.58, pct: 0\n",
"2020-07-01, 卖出600000, 成交量-87700.0,成交价10.59\n",
"2020-07-01, 945960.32元\n",
"2020-07-01, 买600000, price:10.74, amout: 86300.0\n",
"2020-07-02, 买入600000, 成交量86300.0,成交价10.73\n",
"2020-07-02, 973567.06元\n",
"2020-07-02, 卖600000, price:11.05, pct: 0\n",
"2020-07-03, 卖出600000, 成交量-86300.0,成交价11.08\n",
"2020-07-03, 976155.06元\n",
"2020-07-03, 买600000, price:11.19, amout: 85400.0\n",
"2020-07-06, 买入600000, 成交量85400.0,成交价11.30\n",
"2020-07-06, 1053005.41元\n",
"2020-07-06, 卖600000, price:12.20, pct: 0\n",
"2020-07-07, 卖出600000, 成交量-85400.0,成交价12.45\n",
"2020-07-07, 1074354.41元\n",
"2020-07-07, 买600000, price:12.11, amout: 86900.0\n",
"2020-07-08, 买入600000, 成交量86900.0,成交价12.17\n",
"2020-07-08, 1071736.84元\n",
"2020-07-08, 卖600000, price:12.14, pct: 0\n",
"2020-07-09, 卖出600000, 成交量-86900.0,成交价12.26\n",
"2020-07-09, 1082163.84元\n",
"2020-07-09, 买600000, price:11.99, amout: 88400.0\n",
"2020-07-10, 买入600000, 成交量88400.0,成交价11.98\n",
"2020-07-10, 1048561.25元\n",
"2020-07-10, 卖600000, price:11.60, pct: 0\n",
"2020-07-13, 卖出600000, 成交量-88400.0,成交价11.60\n",
"2020-07-13, 1048560.25元\n",
"2020-07-13, 买600000, price:11.66, amout: 88100.0\n",
"2020-07-14, 买入600000, 成交量88100.0,成交价11.61\n",
"2020-07-14, 1028287.02元\n",
"2020-07-14, 卖600000, price:11.38, pct: 0\n",
"2020-07-15, 卖出600000, 成交量-88100.0,成交价11.47\n",
"2020-07-15, 1036215.02元\n",
"2020-07-15, 买600000, price:11.18, amout: 90800.0\n",
"2020-07-16, 买入600000, 成交量90800.0,成交价11.25\n",
"2020-07-16, 1031664.80元\n",
"2020-07-16, 卖600000, price:11.20, pct: 0\n",
"2020-07-17, 卖出600000, 成交量-90800.0,成交价11.37\n",
"结束资金: 1047099.8\n"
]
}
],
"source": [
"class single_strategy(bt.Strategy):\n",
" # 全局设定交易策略的参数\n",
" params = (\n",
" ('maperiod', 20),\n",
" )\n",
"\n",
" def __init__(self):\n",
" # 初始化交易指令\n",
" self.order = None\n",
"\n",
" # 添加移动均线指标,内置了talib模块\n",
" self.sma = bt.ind.SMA(self.datas[0], period=self.params.maperiod)\n",
"\n",
" # 可以不要,但如果你数据未对齐,需要在这里检验\n",
" def prenext(self):\n",
" pass\n",
" \n",
" def downcast(amount, lot):\n",
" return abs(amount//lot*lot)\n",
" \n",
" \n",
" def next(self):\n",
" if self.order: # 检查是否有指令等待执行,如果有就不执行这根bar\n",
" return\n",
" \n",
" # 回测最后一天不进行买卖\n",
" if self.datas[0].datetime.date(0) == end_date:\n",
" return \n",
" \n",
" # 拿这根bar时期的所有资产价值(如果按日K数据放入,即代表今日的资产价值)\n",
" self.log(\"%.2f元\" % self.broker.getvalue()) \n",
" if not self.position: # 没有持仓\n",
" \n",
" # 执行买入条件判断:收盘价格上涨突破20日均线;\n",
" # 不要在股票剔除日前一天进行买入\n",
" if self.datas[0].close > self.sma and data.datetime.date(1) < end_date:\n",
" # 永远不要满仓买入某只股票\n",
" order_value = self.broker.getvalue()*0.98\n",
" order_amount = downcast(order_value/self.datas[0].close[0], 100)\n",
" self.order = self.buy(self.datas[0], size=order_amount, name=self.datas[0]._name)\n",
" self.log(f\"买{self.datas[0]._name}, price:{self.datas[0].close[0]:.2f}, amout: {order_amount}\")\n",
" # self.order = self.order_target_percent(self.datas[0], 0.98, name=self.datas[0]._name)\n",
" # self.log(f\"买{self.datas[0]._name}, price:{self.datas[0].close[0]:.2f}, pct: 0.98\")\n",
" else:\n",
" \n",
" # 执行卖出条件判断:收盘价格跌破20日均线,或者股票剔除\n",
" if self.datas[0].close > self.sma or data.datetime.date(1) >= end_date:\n",
" # 执行卖出\n",
" self.order = self.order_target_percent(self.datas[0], 0, name=self.datas[0]._name)\n",
" self.log(f\"卖{self.datas[0]._name}, price:{self.datas[0].close[0]:.2f}, pct: 0\")\n",
"\n",
" def log(self, txt, dt=None):\n",
" ''' 输出日志'''\n",
" dt = dt or self.datas[0].datetime.date(0) # 拿现在的日期\n",
" print('%s, %s' % (dt.isoformat(), txt))\n",
"\n",
" def notify_order(self, order):\n",
" if order.status in [order.Submitted, order.Accepted]:\n",
" # Buy/Sell order submitted/accepted to/by broker - Nothing to do\n",
" return\n",
"\n",
" # Check if an order has been completed\n",
" # Attention: broker could reject order if not enough cash\n",
" if order.status in [order.Completed, order.Canceled, order.Margin]:\n",
" if order.isbuy():\n",
" self.log(f\"\"\"买入{order.info['name']}, 成交量{order.executed.size},成交价{order.executed.price:.2f}\"\"\")\n",
" elif order.issell():\n",
" self.log(f\"\"\"卖出{order.info['name']}, 成交量{order.executed.size},成交价{order.executed.price:.2f}\"\"\")\n",
" self.bar_executed = len(self)\n",
"\n",
" # Write down: no pending order\n",
" self.order = None\n",
"\n",
"\n",
"cerebro = bt.Cerebro()\n",
"cerebro.addstrategy(single_strategy)\n",
"secu_lst = {'600000': {'start': '2020-01-01', 'end': '2020-07-18'}}\n",
"df = GetKdatas(secu_lst).merge_period()['600000']\n",
"data = PandasData_Extend(dataname=df, fromdate=df.index[0], todate=df.index[-1])\n",
"cerebro.adddata(data, name='600000')\n",
"end_date = df.index[-1] # 股票剔除日\n",
"\n",
"# 设置初始资本为1 million\n",
"startcash = 10**6\n",
"cerebro.broker.setcash(startcash)\n",
"print(f\"初始资金{cerebro.broker.getvalue()}\")\n",
"# 设置交易手续费\n",
"cerebro.broker.addcommissioninfo(CommInfoPro())\n",
"# 运行回测系统\n",
"cerebro.run()\n",
"# 获取回测结束后的总资金\n",
"portvalue = cerebro.broker.getvalue()\n",
"# 打印结果\n",
"print(f'结束资金: {round(portvalue, 2)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.2. 多只股票\n",
"策略逻辑和上面的相同。\n",
"计算均线的时候用了dict循环计算每只股票的指标。\n",
"1. self.getdatanames()按顺序返回所有股票的名称list\n",
"2. self.getdatabyname(secu_name):返回该股票的data"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"初始资金1000000\n",
"2020-02-06, 1000000.00, []\n",
"2020-02-06, 买000001, price:14.77, amout: 32400.0\n",
"2020-02-07, 买入000001, 成交量32400.0,成交价14.60\n",
"2020-02-07, 1000643.00, [('000001', 32400.0)]\n",
"2020-02-10, 996755.00, [('000001', 32400.0)]\n",
"2020-02-11, 1006151.00, [('000001', 32400.0)]\n",
"2020-02-12, 1005503.00, [('000001', 32400.0)]\n",
"2020-02-13, 1001615.00, [('000001', 32400.0)]\n",
"2020-02-14, 1013927.00, [('000001', 32400.0)]\n",
"2020-02-17, 1024943.00, [('000001', 32400.0)]\n",
"2020-02-18, 1019435.00, [('000001', 32400.0)]\n",
"2020-02-19, 1020731.00, [('000001', 32400.0)]\n",
"2020-02-20, 1032071.00, [('000001', 32400.0)]\n",
"2020-02-20, 买600000, price:11.23, amout: 44100.0\n",
"2020-02-21, 买入600000, 成交量44100.0,成交价11.23\n",
"2020-02-21, 1034829.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-24, 1017315.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-25, 1008072.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-26, 1011303.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-27, 1015632.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-28, 979992.00, [('000001', 32400.0), ('600000', 44100.0)]\n",
"2020-02-28, 卖000001, price:14.50, pct: 0\n",
"2020-02-28, 卖600000, price:10.85, pct: 0\n",
"2020-03-02, 卖出000001, 成交量-32400.0,成交价14.55\n",
"2020-03-02, 卖出600000, 成交量-44100.0,成交价10.95\n",
"2020-03-02, 986020.00, []\n",
"2020-03-02, 买600000, price:11.04, amout: 42800.0\n",
"2020-03-03, 买入600000, 成交量42800.0,成交价11.13\n",
"2020-03-03, 983019.00, [('600000', 42800.0)]\n",
"2020-03-04, 981735.00, [('600000', 42800.0)]\n",
"2020-03-05, 994147.00, [('600000', 42800.0)]\n",
"2020-03-05, 买000001, price:15.39, amout: 31000.0\n",
"2020-03-06, 买入000001, 成交量31000.0,成交价15.18\n",
"2020-03-06, 980932.00, [('600000', 42800.0), ('000001', 31000.0)]\n",
"2020-03-09, 948400.00, [('600000', 42800.0), ('000001', 31000.0)]\n",
"2020-03-09, 卖600000, price:10.78, pct: 0\n",
"2020-03-09, 卖000001, price:14.45, pct: 0\n",
"2020-03-10, 卖出600000, 成交量-42800.0,成交价10.71\n",
"2020-03-10, 卖出000001, 成交量-31000.0,成交价14.38\n",
"2020-03-10, 943232.00, []\n",
"2020-03-11, 943232.00, []\n",
"2020-03-12, 943232.00, []\n",
"2020-03-13, 943232.00, []\n",
"2020-03-16, 943232.00, []\n",
"2020-03-17, 943232.00, []\n",
"2020-03-18, 943232.00, []\n",
"2020-03-19, 943232.00, []\n",
"2020-03-20, 943232.00, []\n",
"2020-03-23, 943232.00, []\n",
"2020-03-24, 943232.00, []\n",
"2020-03-25, 943232.00, []\n",
"2020-03-26, 943232.00, []\n",
"2020-03-27, 943232.00, []\n",
"2020-03-30, 943232.00, []\n",
"2020-03-31, 943232.00, []\n",
"2020-04-01, 943232.00, []\n",
"2020-04-02, 943232.00, []\n",
"2020-04-03, 943232.00, []\n",
"2020-04-07, 943232.00, []\n",
"2020-04-08, 943232.00, []\n",
"2020-04-09, 943232.00, []\n",
"2020-04-10, 943232.00, []\n",
"2020-04-10, 买600000, price:10.21, amout: 44300.0\n",
"2020-04-13, 买入600000, 成交量44300.0,成交价10.15\n",
"2020-04-13, 941455.00, [('600000', 44300.0)]\n",
"2020-04-14, 947657.00, [('600000', 44300.0)]\n",
"2020-04-14, 买000001, price:12.86, amout: 35300.0\n",
"2020-04-15, 买入000001, 成交量35300.0,成交价12.86\n",
"2020-04-15, 944904.00, [('600000', 44300.0), ('000001', 35300.0)]\n",
"2020-04-16, 937311.00, [('600000', 44300.0), ('000001', 35300.0)]\n",
"2020-04-16, 卖000001, price:12.68, pct: 0\n",
"2020-04-17, 卖出000001, 成交量-35300.0,成交价12.77\n",
"2020-04-17, 942259.00, [('600000', 44300.0)]\n",
"2020-04-17, 买000001, price:12.89, amout: 35000.0\n",
"2020-04-20, 买入000001, 成交量35000.0,成交价12.86\n",
"2020-04-20, 942817.00, [('600000', 44300.0), ('000001', 35000.0)]\n",
"2020-04-20, 卖600000, price:10.11, pct: 0\n",
"2020-04-21, 卖出600000, 成交量-44300.0,成交价10.07\n",
"2020-04-21, 957144.00, [('000001', 35000.0)]\n",
"2020-04-22, 949444.00, [('000001', 35000.0)]\n",
"2020-04-23, 949444.00, [('000001', 35000.0)]\n",
"2020-04-24, 949794.00, [('000001', 35000.0)]\n",
"2020-04-27, 958894.00, [('000001', 35000.0)]\n",
"2020-04-27, 买600000, price:10.34, amout: 44500.0\n",
"2020-04-28, 买入600000, 成交量44500.0,成交价10.36\n",
"2020-04-28, 958254.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-04-29, 988214.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-04-30, 985954.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-06, 972789.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-07, 966874.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-08, 978199.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-11, 979504.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-12, 968149.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-13, 964329.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-14, 949219.00, [('000001', 35000.0), ('600000', 44500.0)]\n",
"2020-05-14, 卖000001, price:13.30, pct: 0\n",
"2020-05-15, 卖出000001, 成交量-35000.0,成交价13.39\n",
"2020-05-15, 951478.00, [('600000', 44500.0)]\n",
"2020-05-18, 953258.00, [('600000', 44500.0)]\n",
"2020-05-19, 954593.00, [('600000', 44500.0)]\n",
"2020-05-20, 957263.00, [('600000', 44500.0)]\n",
"2020-05-21, 953703.00, [('600000', 44500.0)]\n",
"2020-05-22, 945248.00, [('600000', 44500.0)]\n",
"2020-05-25, 951033.00, [('600000', 44500.0)]\n",
"2020-05-26, 951033.00, [('600000', 44500.0)]\n",
"2020-05-27, 954593.00, [('600000', 44500.0)]\n",
"2020-05-28, 962603.00, [('600000', 44500.0)]\n",
"2020-05-29, 964383.00, [('600000', 44500.0)]\n",
"2020-06-01, 967943.00, [('600000', 44500.0)]\n",
"2020-06-02, 969278.00, [('600000', 44500.0)]\n",
"2020-06-02, 买000001, price:13.55, amout: 34300.0\n",
"2020-06-03, 买入000001, 成交量34300.0,成交价13.64\n",
"2020-06-03, 966733.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-04, 965092.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-05, 967113.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-08, 965472.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-09, 970302.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-10, 959678.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-11, 941165.00, [('600000', 44500.0), ('000001', 34300.0)]\n",
"2020-06-11, 卖000001, price:13.08, pct: 0\n",
"2020-06-12, 卖出000001, 成交量-34300.0,成交价12.90\n",
"2020-06-12, 938105.00, [('600000', 44500.0)]\n",
"2020-06-15, 929205.00, [('600000', 44500.0)]\n",
"2020-06-16, 933655.00, [('600000', 44500.0)]\n",
"2020-06-17, 934545.00, [('600000', 44500.0)]\n",
"2020-06-18, 935880.00, [('600000', 44500.0)]\n",
"2020-06-19, 940775.00, [('600000', 44500.0)]\n",
"2020-06-22, 938105.00, [('600000', 44500.0)]\n",
"2020-06-23, 934990.00, [('600000', 44500.0)]\n",
"2020-06-24, 940330.00, [('600000', 44500.0)]\n",
"2020-06-29, 938995.00, [('600000', 44500.0)]\n",
"2020-06-30, 939440.00, [('600000', 44500.0)]\n",
"2020-07-01, 946560.00, [('600000', 44500.0)]\n",
"2020-07-01, 买000001, price:13.12, amout: 34600.0\n",
"2020-07-02, 买入000001, 成交量34600.0,成交价13.08\n",
"2020-07-02, 972460.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-03, 1007062.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-06, 1101485.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-07, 1090560.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-08, 1101583.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-09, 1086950.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-10, 1046413.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-13, 1050121.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-14, 1030395.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-15, 1007309.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-16, 1004047.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-17, 1006816.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-20, 1038355.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-21, 1030941.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-22, 1031733.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-23, 983183.00, [('600000', 44500.0), ('000001', 34600.0)]\n",
"2020-07-23, 卖600000, price:10.84, pct: 0\n",
"2020-07-23, 卖000001, price:14.01, pct: 0\n",
"2020-07-24, 卖出600000, 成交量-44500.0,成交价10.78\n",
"2020-07-24, 卖出000001, 成交量-34600.0,成交价13.97\n",
"2020-07-24, 979127.00, []\n",
"2020-07-27, 979127.00, []\n",
"2020-07-28, 979127.00, []\n",
"2020-07-29, 979127.00, []\n",
"2020-07-30, 979127.00, []\n",
"2020-07-31, 979127.00, []\n",
"2020-08-03, 979127.00, []\n",
"2020-08-04, 979127.00, []\n",
"2020-08-05, 979127.00, []\n",
"2020-08-06, 979127.00, []\n",
"2020-08-07, 979127.00, []\n",
"2020-08-10, 979127.00, []\n",
"2020-08-10, 买000001, price:13.95, amout: 33600.0\n",
"2020-08-11, 买入000001, 成交量33600.0,成交价13.97\n",
"2020-08-11, 984498.00, [('000001', 33600.0)]\n",
"2020-08-12, 992898.00, [('000001', 33600.0)]\n",
"2020-08-13, 986178.00, [('000001', 33600.0)]\n",
"2020-08-14, 995922.00, [('000001', 33600.0)]\n",
"2020-08-17, 1020114.00, [('000001', 33600.0)]\n",
"2020-08-17, 买600000, price:10.84, amout: 45100.0\n",
"2020-08-18, 买入600000, 成交量45100.0,成交价10.85\n",
"2020-08-18, 1011549.00, [('000001', 33600.0), ('600000', 45100.0)]\n",
"2020-08-19, 1004908.00, [('000001', 33600.0), ('600000', 45100.0)]\n",
"2020-08-20, 982811.00, [('000001', 33600.0), ('600000', 45100.0)]\n",
"2020-08-20, 卖600000, price:10.47, pct: 0\n",
"2020-08-21, 卖出600000, 成交量-45100.0,成交价10.56\n",
"2020-08-21, 982165.00, [('000001', 33600.0)]\n",
"2020-08-24, 982501.00, [('000001', 33600.0)]\n",
"2020-08-25, 987205.00, [('000001', 33600.0)]\n",
"2020-08-26, 979477.00, [('000001', 33600.0)]\n",
"2020-08-27, 982501.00, [('000001', 33600.0)]\n",
"2020-08-28, 1005013.00, [('000001', 33600.0)]\n",
"2020-08-31, 1003333.00, [('000001', 33600.0)]\n",
"2020-09-01, 1005349.00, [('000001', 33600.0)]\n",
"2020-09-02, 1011397.00, [('000001', 33600.0)]\n",
"2020-09-03, 997285.00, [('000001', 33600.0)]\n",
"2020-09-04, 999301.00, [('000001', 33600.0)]\n",
"2020-09-07, 998629.00, [('000001', 33600.0)]\n",
"2020-09-08, 1015093.00, [('000001', 33600.0)]\n",
"2020-09-09, 1007701.00, [('000001', 33600.0)]\n",
"2020-09-10, 1012069.00, [('000001', 33600.0)]\n",
"2020-09-11, 1000981.00, [('000001', 33600.0)]\n",
"2020-09-14, 1010725.00, [('000001', 33600.0)]\n",
"2020-09-15, 1012405.00, [('000001', 33600.0)]\n",
"2020-09-16, 1015429.00, [('000001', 33600.0)]\n",
"2020-09-17, 1019797.00, [('000001', 33600.0)]\n",
"2020-09-18, 1036597.00, [('000001', 33600.0)]\n",
"2020-09-21, 1029541.00, [('000001', 33600.0)]\n",
"2020-09-22, 1019797.00, [('000001', 33600.0)]\n",
"2020-09-23, 1021813.00, [('000001', 33600.0)]\n",
"2020-09-24, 1004677.00, [('000001', 33600.0)]\n",
"2020-09-25, 1007029.00, [('000001', 33600.0)]\n",
"2020-09-28, 1011061.00, [('000001', 33600.0)]\n",
"2020-09-29, 993925.00, [('000001', 33600.0)]\n",
"2020-09-30, 1006357.00, [('000001', 33600.0)]\n",
"2020-10-09, 1006693.00, [('000001', 33600.0)]\n",
"2020-10-12, 1030885.00, [('000001', 33600.0)]\n",
"2020-10-13, 1036261.00, [('000001', 33600.0)]\n",
"2020-10-14, 1035253.00, [('000001', 33600.0)]\n",
"2020-10-15, 1053061.00, [('000001', 33600.0)]\n",
"2020-10-16, 1071205.00, [('000001', 33600.0)]\n",
"2020-10-16, 买600000, price:9.72, amout: 52800.0\n",
"2020-10-19, 买入600000, 成交量0,成交价0.00\n",
"2020-10-19, 1083973.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-20, 1085989.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-20, 卖600000, price:9.58, pct: 0\n",
"2020-10-21, 1098421.00, [('000001', 33600.0)]\n",
"2020-10-21, 买600000, price:9.70, amout: 54300.0\n",
"2020-10-22, 买入600000, 成交量0,成交价0.00\n",
"2020-10-22, 1086661.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-23, 1105813.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-26, 1091365.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-27, 1093381.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-10-27, 卖600000, price:9.48, pct: 0\n",
"2020-10-28, 1089013.00, [('000001', 33600.0)]\n",
"2020-10-29, 1093717.00, [('000001', 33600.0)]\n",
"2020-10-30, 1093045.00, [('000001', 33600.0)]\n",
"2020-11-02, 1089013.00, [('000001', 33600.0)]\n",
"2020-11-03, 1100101.00, [('000001', 33600.0)]\n",
"2020-11-04, 1112197.00, [('000001', 33600.0)]\n",
"2020-11-05, 1091365.00, [('000001', 33600.0)]\n",
"2020-11-06, 1089349.00, [('000001', 33600.0)]\n",
"2020-11-09, 1096069.00, [('000001', 33600.0)]\n",
"2020-11-10, 1105141.00, [('000001', 33600.0)]\n",
"2020-11-11, 1095061.00, [('000001', 33600.0)]\n",
"2020-11-11, 买600000, price:9.56, amout: 54900.0\n",
"2020-11-12, 买入600000, 成交量0,成交价0.00\n",
"2020-11-12, 1090021.00, [('000001', 33600.0), ('600000', 0.0)]\n",
"2020-11-12, 卖000001, price:17.66, pct: 0\n",
"2020-11-12, 卖600000, price:9.43, pct: 0\n",
"2020-11-13, 卖出000001, 成交量-33600.0,成交价17.42\n",
"2020-11-13, 1081956.00, []\n",
"2020-11-16, 1081956.00, []\n",
"2020-11-17, 1081956.00, []\n",
"2020-11-17, 买000001, price:17.83, amout: 29100.0\n",
"2020-11-17, 买600000, price:9.53, amout: 54400.0\n",
"2020-11-18, 买入000001, 成交量29100.0,成交价17.78\n",
"2020-11-18, 买入600000, 成交量54400.0,成交价9.53\n",
"2020-11-18, 1110981.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-19, 1124506.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-20, 1120989.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-23, 1155617.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-24, 1145331.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-25, 1134425.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-26, 1156477.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-27, 1174265.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-11-30, 1167813.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-01, 1189890.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-02, 1174948.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-03, 1171785.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-04, 1160993.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-07, 1139852.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-08, 1133488.64, [('000001', 29100.0), ('600000', 54400.0)]\n",
"2020-12-08, 卖000001, price:18.71, pct: 0\n",
"2020-12-09, 卖出000001, 成交量-29100.0,成交价18.79\n",
"2020-12-09, 1132007.64, [('600000', 54400.0)]\n",
"2020-12-10, 1127111.64, [('600000', 54400.0)]\n",
"2020-12-11, 1120583.64, [('600000', 54400.0)]\n",
"2020-12-14, 1123303.64, [('600000', 54400.0)]\n",
"2020-12-15, 1121127.64, [('600000', 54400.0)]\n",
"2020-12-16, 1117863.64, [('600000', 54400.0)]\n",
"2020-12-17, 1124391.64, [('600000', 54400.0)]\n",
"2020-12-18, 1123847.64, [('600000', 54400.0)]\n",
"2020-12-21, 1123303.64, [('600000', 54400.0)]\n",
"2020-12-22, 1115687.64, [('600000', 54400.0)]\n",
"2020-12-23, 1112423.64, [('600000', 54400.0)]\n",
"2020-12-24, 1112423.64, [('600000', 54400.0)]\n",
"2020-12-25, 1114055.64, [('600000', 54400.0)]\n",
"2020-12-28, 1113511.64, [('600000', 54400.0)]\n",
"2020-12-28, 买000001, price:18.85, amout: 28300.0\n",
"2020-12-29, 买入000001, 成交量28300.0,成交价18.87\n",
"2020-12-29, 1119820.30, [('600000', 54400.0), ('000001', 28300.0)]\n",
"2020-12-29, 卖600000, price:9.53, pct: 0\n",
"2020-12-30, 卖出600000, 成交量-54400.0,成交价9.52\n",
"2020-12-30, 1120124.30, [('000001', 28300.0)]\n",
"2020-12-31, 1124086.30, [('000001', 28300.0)]\n",
"2021-01-04, 1103144.30, [('000001', 28300.0)]\n",
"2021-01-05, 1090975.30, [('000001', 28300.0)]\n",
"2021-01-06, 1130312.30, [('000001', 28300.0)]\n",
"2021-01-06, 买600000, price:9.82, amout: 55200.0\n",
"2021-01-07, 买入600000, 成交量55200.0,成交价9.83\n",
"2021-01-07, 1138824.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-08, 1138513.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-11, 1145784.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-12, 1168298.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-13, 1163120.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-14, 1149777.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-15, 1176026.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-18, 1232968.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-19, 1227196.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-20, 1220939.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-21, 1213595.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-22, 1197999.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-25, 1207153.88, [('000001', 28300.0), ('600000', 55200.0)]\n",
"2021-01-25, 卖600000, price:9.72, pct: 0\n",
"2021-01-26, 卖出600000, 成交量-55200.0,成交价9.69\n",
"2021-01-26, 1202100.88, [('000001', 28300.0)]\n",
"2021-01-27, 1222193.88, [('000001', 28300.0)]\n",
"2021-01-28, 1214552.88, [('000001', 28300.0)]\n",
"2021-01-29, 1222476.88, [('000001', 28300.0)]\n",
"2021-01-29, 买600000, price:9.96, amout: 58900.0\n",
"2021-02-01, 买入600000, 成交量0,成交价0.00\n",
"2021-02-01, 1263794.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-02, 1227853.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-03, 1275114.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-04, 1265209.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-05, 1274548.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-08, 1270869.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-09, 1264643.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-10, 1243135.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-18, 1256719.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-19, 1243984.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-22, 1202383.88, [('000001', 28300.0), ('600000', 0.0)]\n",
"2021-02-22, 卖000001, price:22.38, pct: 0\n",
"2021-02-23, 卖出000001, 成交量-28300.0,成交价22.38\n",
"2021-02-23, 1202382.88, [('600000', 0.0)]\n",
"2021-02-24, 1202382.88, [('600000', 0.0)]\n",
"2021-02-25, 1202382.88, [('600000', 0.0)]\n",
"2021-02-26, 1202382.88, [('600000', 0.0)]\n",
"2021-03-01, 1202382.88, [('600000', 0.0)]\n",
"2021-03-02, 1202382.88, [('600000', 0.0)]\n",
"2021-03-03, 1202382.88, [('600000', 0.0)]\n",
"2021-03-04, 1202382.88, [('600000', 0.0)]\n",
"2021-03-05, 1202382.88, [('600000', 0.0)]\n",
"2021-03-08, 1202382.88, [('600000', 0.0)]\n",
"2021-03-09, 1202382.88, [('600000', 0.0)]\n",
"2021-03-10, 1202382.88, [('600000', 0.0)]\n",
"2021-03-11, 1202382.88, [('600000', 0.0)]\n",
"2021-03-12, 1202382.88, [('600000', 0.0)]\n",
"2021-03-15, 1202382.88, [('600000', 0.0)]\n",
"2021-03-16, 1202382.88, [('600000', 0.0)]\n",
"2021-03-17, 1202382.88, [('600000', 0.0)]\n",
"2021-03-18, 1202382.88, [('600000', 0.0)]\n",
"2021-03-19, 1202382.88, [('600000', 0.0)]\n",
"2021-03-22, 1202382.88, [('600000', 0.0)]\n",
"2021-03-23, 1202382.88, [('600000', 0.0)]\n",
"2021-03-24, 1202382.88, [('600000', 0.0)]\n",
"2021-03-25, 1202382.88, [('600000', 0.0)]\n",
"2021-03-26, 1202382.88, [('600000', 0.0)]\n",
"2021-03-29, 1202382.88, [('600000', 0.0)]\n",
"2021-03-29, 买000001, price:21.49, amout: 26800.0\n",
"2021-03-30, 买入000001, 成交量26800.0,成交价21.38\n",
"2021-03-30, 1217117.15, [('600000', 0.0), ('000001', 26800.0)]\n",
"2021-03-31, 1219261.15, [('600000', 0.0), ('000001', 26800.0)]\n",
"2021-04-01, 1213097.15, [('600000', 0.0), ('000001', 26800.0)]\n",
"2021-04-02, 1205593.15, [('600000', 0.0), ('000001', 26800.0)]\n",
"2021-04-02, 卖600000, price:10.76, pct: 0\n",
"2021-04-06, 1210417.15, [('000001', 26800.0)]\n",
"2021-04-07, 1209345.15, [('000001', 26800.0)]\n",
"2021-04-08, 1207201.15, [('000001', 26800.0)]\n",
"2021-04-09, 1200233.15, [('000001', 26800.0)]\n",
"2021-04-12, 1184153.15, [('000001', 26800.0)]\n",
"2021-04-13, 1186297.15, [('000001', 26800.0)]\n",
"2021-04-14, 1183349.15, [('000001', 26800.0)]\n",
"2021-04-15, 1175041.15, [('000001', 26800.0)]\n",
"2021-04-16, 1172361.15, [('000001', 26800.0)]\n",
"2021-04-19, 1196213.15, [('000001', 26800.0)]\n",
"2021-04-20, 1210685.15, [('000001', 26800.0)]\n",
"2021-04-21, 1246061.15, [('000001', 26800.0)]\n",
"2021-04-22, 1245257.15, [('000001', 26800.0)]\n",
"2021-04-23, 1253565.15, [('000001', 26800.0)]\n",
"2021-04-26, 1244185.15, [('000001', 26800.0)]\n",
"2021-04-27, 1244185.15, [('000001', 26800.0)]\n",
"2021-04-28, 1255173.15, [('000001', 26800.0)]\n",
"2021-04-29, 1261605.15, [('000001', 26800.0)]\n",
"2021-04-30, 1253565.15, [('000001', 26800.0)]\n",
"2021-05-06, 1259193.15, [('000001', 26800.0)]\n",
"2021-05-07, 1273933.15, [('000001', 26800.0)]\n",
"2021-05-10, 1268841.15, [('000001', 26800.0)]\n",
"2021-05-11, 1259997.15, [('000001', 26800.0)]\n",
"2021-05-12, 1260533.15, [('000001', 26800.0)]\n",
"2021-05-13, 1247669.15, [('000001', 26800.0)]\n",
"2021-05-14, 1254369.15, [('000001', 26800.0)]\n",
"2021-05-17, 1261873.15, [('000001', 26800.0)]\n",
"2021-05-18, 1269913.15, [('000001', 26800.0)]\n",
"2021-05-19, 1261873.15, [('000001', 26800.0)]\n",
"2021-05-20, 1267769.15, [('000001', 26800.0)]\n",
"2021-05-21, 1258925.15, [('000001', 26800.0)]\n",
"2021-05-24, 1258657.15, [('000001', 26800.0)]\n",
"2021-05-25, 1288673.15, [('000001', 26800.0)]\n",
"2021-05-25, 买600000, price:10.32, amout: 59900.0\n",
"2021-05-26, 买入600000, 成交量59900.0,成交价10.31\n",
"2021-05-26, 1302050.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-05-27, 1292560.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-05-28, 1288382.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-05-31, 1275550.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-06-01, 1263254.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-06-02, 1264247.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-06-03, 1261630.97, [('000001', 26800.0), ('600000', 59900.0)]\n",
"2021-06-03, 卖000001, price:23.77, pct: 0\n",
"2021-06-04, 卖出000001, 成交量-26800.0,成交价23.99\n",
"2021-06-04, 1267525.97, [('600000', 59900.0)]\n",
"2021-06-04, 买000001, price:24.54, amout: 24700.0\n",
"2021-06-07, 买入000001, 成交量24700.0,成交价24.48\n",
"2021-06-07, 1263073.92, [('600000', 59900.0), ('000001', 24700.0)]\n",
"2021-06-08, 1273546.92, [('600000', 59900.0), ('000001', 24700.0)]\n",
"2021-06-09, 1270520.92, [('600000', 59900.0), ('000001', 24700.0)]\n",
"2021-06-09, 卖600000, price:10.21, pct: 0\n",
"2021-06-10, 卖出600000, 成交量-59900.0,成交价10.21\n",
"2021-06-10, 1259404.92, [('000001', 24700.0)]\n",
"2021-06-10, 买600000, price:10.23, amout: 59000.0\n",
"2021-06-11, 买入600000, 成交量59000.0,成交价10.24\n",
"2021-06-11, 1234767.88, [('000001', 24700.0), ('600000', 59000.0)]\n",
"2021-06-11, 卖000001, price:23.37, pct: 0\n",
"2021-06-11, 卖600000, price:10.17, pct: 0\n",
"2021-06-15, 卖出000001, 成交量-24700.0,成交价23.35\n",
"2021-06-15, 卖出600000, 成交量-59000.0,成交价10.15\n",
"2021-06-15, 1233091.88, []\n",
"2021-06-16, 1233091.88, []\n",
"2021-06-17, 1233091.88, []\n",
"2021-06-18, 1233091.88, []\n",
"2021-06-21, 1233091.88, []\n",
"2021-06-22, 1233091.88, []\n",
"2021-06-23, 1233091.88, []\n",
"2021-06-24, 1233091.88, []\n",
"2021-06-25, 1233091.88, []\n",
"2021-06-28, 1233091.88, []\n",
"2021-06-29, 1233091.88, []\n",
"2021-06-30, 1233091.88, []\n",
"2021-07-01, 1233091.88, []\n",
"2021-07-02, 1233091.88, []\n",
"2021-07-05, 1233091.88, []\n",
"2021-07-06, 1233091.88, []\n",
"2021-07-07, 1233091.88, []\n",
"2021-07-08, 1233091.88, []\n",
"2021-07-09, 1233091.88, []\n",
"2021-07-12, 1233091.88, []\n",
"2021-07-13, 1233091.88, []\n",
"2021-07-14, 1233091.88, []\n",
"2021-07-15, 1233091.88, []\n",
"2021-07-16, 1233091.88, []\n",
"2021-07-16, 买600000, price:9.98, amout: 59300.0\n",
"2021-07-19, 买入600000, 成交量59300.0,成交价9.98\n",
"2021-07-19, 1234864.96, [('600000', 59300.0)]\n",
"2021-07-20, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-21, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-22, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-23, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-26, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-27, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-28, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-29, 1233678.96, [('600000', 59300.0)]\n",
"2021-07-30, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-02, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-03, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-04, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-05, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-06, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-09, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-10, 1233678.96, [('600000', 59300.0)]\n",
"2021-08-10, 买000001, price:19.73, amout: 30000.0\n",
"2021-08-11, 买入000001, 成交量30000.0,成交价19.99\n",
"2021-08-11, 1228272.97, [('600000', 59300.0), ('000001', 30000.0)]\n",
"2021-08-11, 卖600000, price:9.99, pct: 0\n",
"2021-08-12, 卖出600000, 成交量-59300.0,成交价10.01\n",
"2021-08-12, 1231857.97, [('000001', 30000.0)]\n",
"2021-08-13, 1231857.97, [('000001', 30000.0)]\n",
"2021-08-16, 1233657.97, [('000001', 30000.0)]\n",
"2021-08-17, 1225257.97, [('000001', 30000.0)]\n",
"结束资金: 1253757.97\n"
]
}
],
"source": [
"class multi_strategy(bt.Strategy):\n",
" # 全局设定交易策略的参数\n",
" params = (\n",
" ('maperiod', 20),\n",
" )\n",
"\n",
" def __init__(self):\n",
" # 初始化交易指令\n",
" self.order = None\n",
" self.buy_lst = []\n",
"\n",
" # 添加移动均线指标,内置了talib模块\n",
" # 循环计算每只股票的指标\n",
" self.sma = {x: bt.ind.SMA(self.getdatabyname(x), period=self.p.maperiod) for x in self.getdatanames()}\n",
"\n",
" def prenext(self):\n",
" pass\n",
" \n",
" \n",
" def downcast(self, amount, lot):\n",
" return abs(amount//lot*lot)\n",
" \n",
" \n",
" def next(self):\n",
" if self.order: # 检查是否有指令等待执行,\n",
" return\n",
"\n",
" # 回测最后一天不进行买卖\n",
" if self.datas[0].datetime.date(0) == end_date:\n",
" return \n",
" \n",
" # 检查是否持仓\n",
" self.log(f'{self.broker.getvalue():.2f}, {[(x, self.getpositionbyname(x).size) for x in self.buy_lst]}')\n",
" if len(self.buy_lst) < 2: # 没有持仓\n",
" for secu in set(self.getdatanames()) - set(self.buy_lst):\n",
" data = self.getdatabyname(secu)\n",
" # 执行买入条件判断:收盘价格上涨突破20日均线\n",
" # 不要在股票剔除日前一天进行买入\n",
" if data.close > self.sma[secu] and \\\n",
" data.datetime.date(1) < pd.Timestamp(secu_lst[secu]['end']):\n",
" # 执行买入\n",
" order_value = self.broker.getvalue()*0.48\n",
" order_amount = self.downcast(order_value/data.close[0], 100)\n",
" self.order = self.buy(data, size=order_amount, name=secu)\n",
" self.log(f\"买{secu}, price:{data.close[0]:.2f}, amout: {order_amount}\")\n",
" self.buy_lst.append(secu)\n",
" elif self.position:\n",
" now_lst = []\n",
" for secu in self.buy_lst:\n",
" data = self.getdatabyname(secu)\n",
" # 执行卖出条件判断:收盘价格跌破20日均线,或者股票剔除\n",
" if (data.close < self.sma[secu]) or \\\n",
" (data.datetime.date(1) >= pd.Timestamp(secu_lst[secu]['end'])):\n",
" # 执行卖出\n",
" self.order = self.order_target_percent(data, 0, name=secu)\n",
" # 也可以用 self.sell(data, size = self.getposition(data).size)\n",
" # or self.sell(data, size = self.getpositionbyname(secu).size)\n",
" self.log(f\"卖{secu}, price:{data.close[0]:.2f}, pct: 0\")\n",
" continue\n",
" now_lst.append(secu)\n",
" self.buy_lst = now_lst.copy()\n",
"\n",
" def log(self, txt, dt=None):\n",
" ''' 输出日志'''\n",
" dt = dt or self.datas[0].datetime.date(0)\n",
" print('%s, %s' % (dt.isoformat(), txt))\n",
"\n",
" def notify_order(self, order):\n",
" if order.status in [order.Submitted, order.Accepted]:\n",
" # Buy/Sell order submitted/accepted to/by broker - Nothing to do\n",
" return\n",
"\n",
" # Check if an order has been completed\n",
" # Attention: broker could reject order if not enough cash\n",
" if order.status in [order.Completed, order.Canceled, order.Margin]:\n",
" if order.isbuy():\n",
" self.log(f\"\"\"买入{order.info['name']}, 成交量{order.executed.size},成交价{order.executed.price:.2f}\"\"\")\n",
" elif order.issell():\n",
" self.log(f\"\"\"卖出{order.info['name']}, 成交量{order.executed.size},成交价{order.executed.price:.2f}\"\"\")\n",
" self.bar_executed = len(self)\n",
"\n",
" # Write down: no pending order\n",
" self.order = None\n",
"\n",
" \n",
"secu_lst = {'600000': {'start': '2020-01-01', 'end': '2021-07-20'},\n",
" '000001': {'start': '2020-02-01', 'end': '2021-08-18'}}\n",
"# 拿对齐的数据\n",
"kdata = GetKdatas(secu_lst).merge_period()\n",
"kdata = dict(sorted(kdata.items()))\n",
"\n",
"# 开始回测\n",
"cerebro = bt.Cerebro()\n",
"cerebro.addstrategy(multi_strategy)\n",
"\n",
"for secu in kdata.keys():\n",
" df = kdata[secu]\n",
" data = PandasData_Extend(dataname=df, fromdate=df.index[0], todate=df.index[-1])\n",
" cerebro.adddata(data, name=secu)\n",
"end_date = df.index[-1]\n",
"\n",
"# 设置初始资本为1 million\n",
"startcash = 10**6\n",
"cerebro.broker.setcash(startcash)\n",
"print(f\"初始资金{cerebro.broker.getvalue()}\")\n",
"# 设置交易手续费\n",
"cerebro.broker.addcommissioninfo(CommInfoPro())\n",
"\n",
"# 加入指标\n",
"cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='_sharpe')\n",
"cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='_annrtn')\n",
"cerebro.addanalyzer(bt.analyzers.DrawDown, _name='_dd')\n",
"cerebro.addanalyzer(bt.analyzers.PyFolio, _name='_pyfolio')\n",
"# 运行回测系统\n",
"thestrats = cerebro.run()\n",
"# 获取回测结束后的总资金\n",
"portvalue = cerebro.broker.getvalue()\n",
"# 打印结果\n",
"print(f'结束资金: {round(portvalue, 2)}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. 策略评估\n",
"下图较为详细得展示了各个买入点和卖出点,方便我们进行买入卖出点的直观判断"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support. ' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('