BackTrader 中文文档(二十三)(1)https://developer.aliyun.com/article/1505434
一个 PyFolio 运行
当在Jupyter Notebook中运行时,pyfolio
的功能运行良好,包括内联绘图。这是笔记本
注意
runstrat
在此处获取[]作为参数以使用默认参数运行,并跳过由笔记本本身传递的参数
%matplotlib inline
from __future__ import (absolute_import, division, print_function, unicode_literals) import argparse import datetime import random import backtrader as bt class St(bt.Strategy): params = ( ('printout', False), ('stake', 1000), ) def __init__(self): pass def start(self): if self.p.printout: txtfields = list() txtfields.append('Len') txtfields.append('Datetime') txtfields.append('Open') txtfields.append('High') txtfields.append('Low') txtfields.append('Close') txtfields.append('Volume') txtfields.append('OpenInterest') print(','.join(txtfields)) def next(self): if self.p.printout: # Print only 1st data ... is just a check that things are running txtfields = list() txtfields.append('%04d' % len(self)) txtfields.append(self.data.datetime.datetime(0).isoformat()) txtfields.append('%.2f' % self.data0.open[0]) txtfields.append('%.2f' % self.data0.high[0]) txtfields.append('%.2f' % self.data0.low[0]) txtfields.append('%.2f' % self.data0.close[0]) txtfields.append('%.2f' % self.data0.volume[0]) txtfields.append('%.2f' % self.data0.openinterest[0]) print(','.join(txtfields)) # Data 0 for data in self.datas: toss = random.randint(1, 10) curpos = self.getposition(data) if curpos.size: if toss > 5: size = curpos.size // 2 self.sell(data=data, size=size) if self.p.printout: print('SELL {} @%{}'.format(size, data.close[0])) elif toss < 5: self.buy(data=data, size=self.p.stake) if self.p.printout: print('BUY {} @%{}'.format(self.p.stake, data.close[0])) def runstrat(args=None): args = parse_args(args) cerebro = bt.Cerebro() cerebro.broker.set_cash(args.cash) dkwargs = dict() if args.fromdate: fromdate = datetime.datetime.strptime(args.fromdate, '%Y-%m-%d') dkwargs['fromdate'] = fromdate if args.todate: todate = datetime.datetime.strptime(args.todate, '%Y-%m-%d') dkwargs['todate'] = todate data0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **dkwargs) cerebro.adddata(data0, name='Data0') data1 = bt.feeds.BacktraderCSVData(dataname=args.data1, **dkwargs) cerebro.adddata(data1, name='Data1') data2 = bt.feeds.BacktraderCSVData(dataname=args.data2, **dkwargs) cerebro.adddata(data2, name='Data2') cerebro.addstrategy(St, printout=args.printout) if not args.no_pyfolio: cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio') results = cerebro.run() if not args.no_pyfolio: strat = results[0] pyfoliozer = strat.analyzers.getbyname('pyfolio') returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items() if args.printout: print('-- RETURNS') print(returns) print('-- POSITIONS') print(positions) print('-- TRANSACTIONS') print(transactions) print('-- GROSS LEVERAGE') print(gross_lev) import pyfolio as pf pf.create_full_tear_sheet( returns, positions=positions, transactions=transactions, gross_lev=gross_lev, live_start_date='2005-05-01', round_trips=True) if args.plot: cerebro.plot(style=args.plot_style) def parse_args(args=None): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter, description='Sample for pivot point and cross plotting') parser.add_argument('--data0', required=False, default='../../datas/yhoo-1996-2015.txt', help='Data to be read in') parser.add_argument('--data1', required=False, default='../../datas/orcl-1995-2014.txt', help='Data to be read in') parser.add_argument('--data2', required=False, default='../../datas/nvda-1999-2014.txt', help='Data to be read in') parser.add_argument('--fromdate', required=False, default='2005-01-01', help='Starting date in YYYY-MM-DD format') parser.add_argument('--todate', required=False, default='2006-12-31', help='Ending date in YYYY-MM-DD format') parser.add_argument('--printout', required=False, action='store_true', help=('Print data lines')) parser.add_argument('--cash', required=False, action='store', type=float, default=50000, help=('Cash to start with')) parser.add_argument('--plot', required=False, action='store_true', help=('Plot the result')) parser.add_argument('--plot-style', required=False, action='store', default='bar', choices=['bar', 'candle', 'line'], help=('Plot style')) parser.add_argument('--no-pyfolio', required=False, action='store_true', help=('Do not do pyfolio things')) import sys aargs = args if args is not None else sys.argv[1:] return parser.parse_args(aargs)
runstrat([])
Entire data start date: 2005-01-03 Entire data end date: 2006-12-29 Out-of-Sample Months: 20 Backtest Months: 3
[-0.012 -0.025]
D:drobinWinPython-64bit-2.7.10.3python-2.7.10.amd64libsite-packagespyfolioplotting.py:1210: FutureWarning: .resample() is now a deferred operation use .resample(...).mean() instead of .resample(...) **kwargs)
<matplotlib.figure.Figure at 0x23982b70> • 1
使用示例:
$ ./pyfoliotest.py --help usage: pyfoliotest.py [-h] [--data0 DATA0] [--data1 DATA1] [--data2 DATA2] [--fromdate FROMDATE] [--todate TODATE] [--printout] [--cash CASH] [--plot] [--plot-style {bar,candle,line}] [--no-pyfolio] Sample for pivot point and cross plotting optional arguments: -h, --help show this help message and exit --data0 DATA0 Data to be read in (default: ../../datas/yhoo-1996-2015.txt) --data1 DATA1 Data to be read in (default: ../../datas/orcl-1995-2014.txt) --data2 DATA2 Data to be read in (default: ../../datas/nvda-1999-2014.txt) --fromdate FROMDATE Starting date in YYYY-MM-DD format (default: 2005-01-01) --todate TODATE Ending date in YYYY-MM-DD format (default: 2006-12-31) --printout Print data lines (default: False) --cash CASH Cash to start with (default: 50000) --plot Plot the result (default: False) --plot-style {bar,candle,line} Plot style (default: bar) --no-pyfolio Do not do pyfolio things (default: False)
体积填充
原文:
www.backtrader.com/blog/posts/2016-07-14-volume-filling/volume-filling/
到目前为止,backtrader中的默认体积填充策略一直相当简单和直接:
- 忽略体积
注意
2016 年 7 月 15 日
更正了实现中的一个错误,并更新了样本以close
该位置并在休息后重复。
下面的最后一个测试运行(以及相应的图表)来自更新样本
这基于两个前提:
- 在足够流动的市场中交易,以完全吸收buy/sell订单
- 真实的成交量匹配需要真实的世界
一个快速的示例是Fill or Kill
订单。即使是到tick分辨率并且具有足够的fill体积,backtrader经纪人也无法知道市场中有多少额外的参与者来区分订单是否会匹配以坚持Fill
部分,或者订单是否应该Kill
但是随着版本1.5.2.93
的发布,可以指定经纪人采取Volume的filler
以在执行订单时考虑Volume。此外,3 个初始填充器已经进入发布:
FixedSize
:每天使用固定的匹配大小(例如:1000 个单位),前提是当前柱状图至少有 1000 个单位FixedBarPerc
:使用总柱状图体积的百分比尝试匹配订单BarPointPerc
:在价格范围高低之间进行柱状图体积的均匀分布,并使用相应于单个价格点的体积的百分比
创建填充器
backtrader生态系统中的filler可以是符合以下签名的任何callable:
callable(order, price, ago)
其中:
order
是即将执行的订单
此对象提供了对操作目标的data
对象的访问权限,创建大小/价格、执行价格/大小/剩余大小以及其他详细信息price
,订单将以其执行ago
是在其中查找体积和价格元素的order中data
的索引
在几乎所有情况下,这将是0
(当前时间点),但在一种特殊情况下,为了涵盖Close
订单,这可能是-1
。
例如,要访问柱状图体积,请执行以下操作:
barvolume = order.data.volume[ago]`
可调用对象可以是一个函数,或者例如支持__call__
方法的类的实例,如:
class MyFiller(object): def __call__(self, order, price, ago): pass
向经纪人添加填充器
最直接的方法是使用set_filler
:
import backtrader as bt cerebro = Cerebro() cerebro.broker.set_filler(bt.broker.filler.FixedSize())
第二选择是完全替换broker
,尽管这可能只适用于已经重写部分功能的BrokerBack
的子类:
import backtrader as bt cerebro = Cerebro() filler = bt.broker.filler.FixedSize() newbroker = bt.broker.BrokerBack(filler=filler) cerebro.broker = newbroker
该样本
backtrader源代码包含一个名为volumefilling
的样本,它允许测试一些集成的fillers
(最初全部)。
该样本在源文件中使用一个默认数据样本命名为:datas/2006-volume-day-001.txt
。
例如,不使用填充器运行:
$ ./volumefilling.py --stakeperc 20.0
输出:
Len,Datetime,Open,High,Low,Close,Volume,OpenInterest 0001,2006-01-02,3602.00,3624.00,3596.00,3617.00,164794.00,1511674.00 ++ STAKE VOLUME: 32958.0 -- NOTIFY ORDER BEGIN Ref: 1 ... Alive: False -- NOTIFY ORDER END -- ORDER REMSIZE: 0.0 ++ ORDER COMPLETED at data.len: 2 0002,2006-01-03,3623.00,3665.00,3614.00,3665.00,554426.00,1501792.00 ...
因为输入相当冗长,所以大部分内容都被跳过了,但总结是:
- 看到第
1
条时,将使用20%
(–stakeperc 20.0)发出买入订单 - 如输出所示,并且根据backtrader的默认行为,订单已经在一次交易中完全匹配。没有查看成交量
注意
经纪人在示例中分配了大量的现金,以确保可以应对许多测试情况
另一个运行使用FixedSize
成交量填充器和每个条的最大1000
单位:
$ ./volumefilling.py --stakeperc 20.0 --filler FixedSize --filler-args size=1000
输出:
Len,Datetime,Open,High,Low,Close,Volume,OpenInterest 0001,2006-01-02,3602.00,3624.00,3596.00,3617.00,164794.00,1511674.00 ++ STAKE VOLUME: 32958.0 -- NOTIFY ORDER BEGIN ... -- NOTIFY ORDER END -- ORDER REMSIZE: 0.0 ++ ORDER COMPLETED at data.len: 34 0034,2006-02-16,3755.00,3774.00,3738.00,3773.00,502043.00,1662302.00 ...
现在:
- 所选的成交量保持不变,为
32958
- 在第
34
条完成执行,这似乎是合理的,因为从第2
条到第34
条…已经看到了33
个条。每条1000
单位匹配的情况下,显然需要33
个条来完成执行
这并不是一个伟大的成就,所以让我们来看看FixedBarPerc
:
$ ./volumefilling.py --stakeperc 20.0 --filler FixedBarPerc --filler-args perc=0.75
输出:
... -- NOTIFY ORDER END -- ORDER REMSIZE: 0.0 ++ ORDER COMPLETED at data.len: 11 0011,2006-01-16,3635.00,3664.00,3632.00,3660.00,273296.00,1592611.00 ...
这次:
- 跳过开始,仍然是
32958
单位的订单 - 执行使用了
0.75%
的条成交量来匹配请求。 - 完成需要从第
2
条到第11
条(10
条)
这更有趣,但让我们看看现在使用BarPointPerc
更动态的成交量分配会发生什么:
$ ./volumefilling.py --stakeperc 20.0 --filler BarPointPerc --filler-args minmov=1.0,perc=10.0
输出:
... -- NOTIFY ORDER END -- ORDER REMSIZE: 0.0 ++ ORDER COMPLETED at data.len: 22 0022,2006-01-31,3697.00,3718.00,3681.00,3704.00,749740.00,1642003.00 ...
发生的事情是:
- 同样的初始分配(跳过)到
32958
的订单大小 - 完全执行需要从
2
到22
(21 个条) - filler使用了
1.0
的minmov
(资产的最小价格变动)来在高低范围内均匀分配成交量 10%
的成交量分配给特定价格点用于订单匹配
对于任何对如何在每个条上部分匹配订单感兴趣的人来说,检查运行的完整输出可能是值得的时间。
注意
在 1.5.3.93 中修正了错误并更新示例以在中断后close
操作
现金增加到一个更多的数量,以避免保证金调用并启用绘图:
$ ./volumefilling.py --filler FixedSize --filler-args size=10000 --stakeperc 10.0 --plot --cash 500e9
而不是查看输出,因为输出非常冗长,让我们看看图表,它已经讲述了整个故事。
使用示例:
usage: volumefilling.py [-h] [--data DATA] [--cash CASH] [--filler {FixedSize,FixedBarPerc,BarPointPerc}] [--filler-args FILLER_ARGS] [--stakeperc STAKEPERC] [--opbreak OPBREAK] [--fromdate FROMDATE] [--todate TODATE] [--plot] Volume Filling Sample optional arguments: -h, --help show this help message and exit --data DATA Data to be read in (default: ../../datas/2006-volume- day-001.txt) --cash CASH Starting cash (default: 500000000.0) --filler {FixedSize,FixedBarPerc,BarPointPerc} Apply a volume filler for the execution (default: None) --filler-args FILLER_ARGS kwargs for the filler with format: arg1=val1,arg2=val2... (default: None) --stakeperc STAKEPERC Percentage of 1st bar to use for stake (default: 10.0) --opbreak OPBREAK Bars to wait for new op after completing another (default: 10) --fromdate FROMDATE, -f FROMDATE Starting date in YYYY-MM-DD format (default: None) --todate TODATE, -t TODATE Ending date in YYYY-MM-DD format (default: None) --plot Plot the result (default: False)
BackTrader 中文文档(二十三)(3)https://developer.aliyun.com/article/1505436