BackTrader 中文文档(十三)(1)https://developer.aliyun.com/article/1505343
示例代码(tcal-intra.py)
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse import datetime import backtrader as bt class NYSE_2016(bt.TradingCalendar): params = dict( holidays=[ datetime.date(2016, 1, 1), datetime.date(2016, 1, 18), datetime.date(2016, 2, 15), datetime.date(2016, 3, 25), datetime.date(2016, 5, 30), datetime.date(2016, 7, 4), datetime.date(2016, 9, 5), datetime.date(2016, 11, 24), datetime.date(2016, 12, 26), ], earlydays=[ (datetime.date(2016, 11, 25), datetime.time(9, 30), datetime.time(13, 1)) ], open=datetime.time(9, 30), close=datetime.time(16, 0), ) class St(bt.Strategy): params = dict( ) def __init__(self): pass def prenext(self): self.next() def next(self): print('Strategy len {} datetime {}'.format( len(self), self.datetime.datetime()), end=' ') print('Data0 len {} datetime {}'.format( len(self.data0), self.data0.datetime.datetime()), end=' ') if len(self.data1): print('Data1 len {} datetime {}'.format( len(self.data1), self.data1.datetime.datetime())) else: print() def runstrat(args=None): args = parse_args(args) cerebro = bt.Cerebro() # Data feed kwargs # kwargs = dict(tz='US/Eastern') # import pytz # tz = tzinput = pytz.timezone('Europe/Berlin') tzinput = 'Europe/Berlin' # tz = tzinput tz = 'US/Eastern' kwargs = dict(tzinput=tzinput, tz=tz) # Parse from/to-date dtfmt, tmfmt = '%Y-%m-%d', 'T%H:%M:%S' for a, d in ((getattr(args, x), x) for x in ['fromdate', 'todate']): if a: strpfmt = dtfmt + tmfmt * ('T' in a) kwargs[d] = datetime.datetime.strptime(a, strpfmt) # Data feed data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs) cerebro.adddata(data0) d1 = cerebro.resampledata(data0, timeframe=getattr(bt.TimeFrame, args.timeframe)) # d1.plotinfo.plotmaster = data0 # d1.plotinfo.sameaxis = False if args.pandascal: cerebro.addcalendar(args.pandascal) elif args.owncal: cerebro.addcalendar(NYSE_2016()) # or NYSE_2016() to pass an instance # Broker cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')')) # Sizer cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')')) # Strategy cerebro.addstrategy(St, **eval('dict(' + args.strat + ')')) # Execute cerebro.run(**eval('dict(' + args.cerebro + ')')) if args.plot: # Plot if requested to cerebro.plot(**eval('dict(' + args.plot + ')')) def parse_args(pargs=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description=( 'Trading Calendar Sample' ) ) parser.add_argument('--data0', default='yhoo-2016-11.csv', required=False, help='Data to read in') # Defaults for dates parser.add_argument('--fromdate', required=False, default='2016-01-01', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--todate', required=False, default='2016-12-31', help='Date[time] in YYYY-MM-DD[THH:MM:SS] format') parser.add_argument('--cerebro', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--broker', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--sizer', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--strat', required=False, default='', metavar='kwargs', help='kwargs in key=value format') parser.add_argument('--plot', required=False, default='', nargs='?', const='{}', metavar='kwargs', help='kwargs in key=value format') pgroup = parser.add_mutually_exclusive_group(required=False) pgroup.add_argument('--pandascal', required=False, action='store', default='', help='Name of trading calendar to use') pgroup.add_argument('--owncal', required=False, action='store_true', help='Apply custom NYSE 2016 calendar') parser.add_argument('--timeframe', required=False, action='store', default='Days', choices=['Days'], help='Timeframe to resample to') return parser.parse_args(pargs) if __name__ == '__main__': runstrat()
自动化回测
原文:
www.backtrader.com/docu/automated-bt-run/automated-bt-run/
到目前为止,所有的backtrader
示例和工作样本都是从头开始创建一个主要的Python模块,该模块加载数据、策略、观察器,并准备好现金和佣金方案。
算法交易的一个目标之一是交易的自动化,鉴于 backtrader 是一个用于检查交易算法的回测平台(因此是一个算法交易平台),自动化使用 backtrader 是一个明显的目标。
当安装backtrader
时,它提供了两个脚本/可执行文件形式的入口点,可以自动化大多数任务:
bt-run-py
一个使用下一项中的代码库的脚本
和
btrun
(可执行文件)
打包过程中由setuptools
创建的入口点。在理论上,在 Windows 下不会出现“路径/文件未找到”的错误。
下面的描述同样适用于这两个工具。
btrun
允许最终用户:
- 说出必须加载的数据源
- 设置加载数据的格式
- 指定数据的日期范围
- 向 Cerebro 传递参数
- 禁用标准观察器
- 这是在“Cerebro”参数实现之前的一个原始额外开关。因此,如果向 cerebro 传递关于标准观察器的参数,这将被忽略(参数
stdstats
到 Cerebro) - 加载一个或多个观察器(例如:
DrawDown
)从内置的或来自 Python 模块 - 为经纪人设置现金和佣金方案参数(佣金、保证金、倍数)
- 启用绘图,控制图表的数量和数据呈现的样式
- 向系统添加一个带参数的写入器
最后应该是核心能力是什么:
- 加载一个策略(内置的或来自 Python 模块)
- 向加载的策略传递参数
请参阅下面关于脚本的使用。
应用用户定义的策略
让我们考虑以下策略:
- 简单加载一个 SimpleMovingAverage(默认周期为 15)
- 打印输出
- 存储在一个名为
mymod.py
的文件中
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import backtrader.indicators as btind class MyTest(bt.Strategy): params = (('period', 15),) def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.data.datetime[0] if isinstance(dt, float): dt = bt.num2date(dt) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): sma = btind.SMA(period=self.p.period) def next(self): ltxt = '%d, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f' self.log(ltxt % (len(self), self.data.open[0], self.data.high[0], self.data.low[0], self.data.close[0], self.data.volume[0], self.data.openinterest[0]))
使用通常的测试样本执行策略很容易:
btrun --csvformat btcsv \ --data ../../datas/2006-day-001.txt \ --strategy mymod.py
图表输出
控制台输出:
2006-01-20T23:59:59+00:00, 15, 3593.16, 3612.37, 3550.80, 3550.80, 0.00, 0.00 2006-01-23T23:59:59+00:00, 16, 3550.24, 3550.24, 3515.07, 3544.31, 0.00, 0.00 2006-01-24T23:59:59+00:00, 17, 3544.78, 3553.16, 3526.37, 3532.68, 0.00, 0.00 2006-01-25T23:59:59+00:00, 18, 3532.72, 3578.00, 3532.72, 3578.00, 0.00, 0.00 ... ... 2006-12-22T23:59:59+00:00, 252, 4109.86, 4109.86, 4072.62, 4073.50, 0.00, 0.00 2006-12-27T23:59:59+00:00, 253, 4079.70, 4134.86, 4079.70, 4134.86, 0.00, 0.00 2006-12-28T23:59:59+00:00, 254, 4137.44, 4142.06, 4125.14, 4130.66, 0.00, 0.00 2006-12-29T23:59:59+00:00, 255, 4130.12, 4142.01, 4119.94, 4119.94, 0.00, 0.00
相同的策略,但:
- 将参数
period
设置为 50
命令行:
btrun --csvformat btcsv \ --data ../../datas/2006-day-001.txt \ --plot \ --strategy mymod.py:period=50
图表输出。
注意
如果没有给出.py
扩展名,bt-run 将会添加它。
使用内置策略
backtrader
将逐渐包含样例(教科书)策略。与 bt-run.py
脚本一起,一个标准的简单移动平均线交叉策略已经包含在内。这个名称:
SMA_CrossOver
- 参数
fast
(默认10
)快速移动平均线的周期slow
(默认30
)慢速移动平均线的周期
如果快速移动平均线上穿过快速移动平均线,则策略买入,如果它以前已经买入,则在快速移动平均线下穿过慢速移动平均线时卖出。
代码
from __future__ import (absolute_import, division, print_function, unicode_literals) import backtrader as bt import backtrader.indicators as btind class SMA_CrossOver(bt.Strategy): params = (('fast', 10), ('slow', 30)) def __init__(self): sma_fast = btind.SMA(period=self.p.fast) sma_slow = btind.SMA(period=self.p.slow) self.buysig = btind.CrossOver(sma_fast, sma_slow) def next(self): if self.position.size: if self.buysig < 0: self.sell() elif self.buysig > 0: self.buy()
标准执行:
btrun --csvformat btcsv \ --data ../../datas/2006-day-001.txt \ --plot \ --strategy :SMA_CrossOver
请注意 :
。加载策略的标准表示法(见下文)是:
module:stragegy:kwargs
使用以下规则:
- 如果存在模块和/或策略,则将使用该策略
- 如果模块存在但未指定策略,则将返回模块中找到的第 1 个策略
- 如果没有指定模块,则假定“strategy”是指 backtrader 包中的策略
- 如果存在模块和/或策略,并且存在 kwargs,则将其传递给相应的策略
注意
相同的表示法和规则适用于 --observer
、--analyzer
和 --indicator
选项
显然,适用于相应的对象类型
输出
最后一个例子,添加佣金方案,现金和更改参数:
btrun --csvformat btcsv \ --data ../../datas/2006-day-001.txt \ --plot \ --cash 20000 \ --commission 2.0 \ --mult 10 \ --margin 2000 \ --strategy :SMA_CrossOver:fast=5,slow=20
输出
我们已经对策略进行了回测:
- 更改移动平均周期
- 设置新的起始现金
- 为类似期货的工具设置佣金方案
请注意每个柱状图中现金的连续变化,因为现金会根据类似期货的工具的每日变化进行调整
BackTrader 中文文档(十三)(3)https://developer.aliyun.com/article/1505346