BackTrader 中文文档(二十三)(2)

简介: BackTrader 中文文档(二十三)

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的发布,可以指定经纪人采取Volumefiller以在执行订单时考虑Volume。此外,3 个初始填充器已经进入发布:

  • FixedSize:每天使用固定的匹配大小(例如:1000 个单位),前提是当前柱状图至少有 1000 个单位
  • FixedBarPerc:使用总柱状图体积的百分比尝试匹配订单
  • BarPointPerc:在价格范围高低之间进行柱状图体积的均匀分布,并使用相应于单个价格点的体积的百分比

创建填充器

backtrader生态系统中的filler可以是符合以下签名的任何callable

callable(order, price, ago)

其中:

  • order是即将执行的订单
    此对象提供了对操作目标的data对象的访问权限,创建大小/价格、执行价格/大小/剩余大小以及其他详细信息
  • price,订单将以其执行
  • ago是在其中查找体积和价格元素的orderdata的索引
    在几乎所有情况下,这将是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的订单大小
  • 完全执行需要从222(21 个条)
  • filler使用了1.0minmov(资产的最小价格变动)来在高低范围内均匀分配成交量
  • 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

相关文章
|
8月前
|
Oracle 测试技术 编译器
BackTrader 中文文档(二十三)(1)
BackTrader 中文文档(二十三)
71 0
|
8月前
|
编解码 API Windows
BackTrader 中文文档(二十三)(3)
BackTrader 中文文档(二十三)
52 0
|
8月前
BackTrader 中文文档(二十三)(4)
BackTrader 中文文档(二十三)
46 0
|
8月前
|
C++
BackTrader 中文文档(二十五)(3)
BackTrader 中文文档(二十五)
60 0
|
8月前
|
数据可视化
BackTrader 中文文档(二十五)(4)
BackTrader 中文文档(二十五)
65 0
|
8月前
|
数据可视化 API Python
BackTrader 中文文档(二十五)(1)
BackTrader 中文文档(二十五)
59 0
|
8月前
BackTrader 中文文档(二十五)(2)
BackTrader 中文文档(二十五)
43 0
|
8月前
BackTrader 中文文档(二十二)(1)
BackTrader 中文文档(二十二)
42 0
|
8月前
|
存储 Python
BackTrader 中文文档(二十二)(3)
BackTrader 中文文档(二十二)
57 0
|
8月前
|
测试技术
BackTrader 中文文档(二十二)(4)
BackTrader 中文文档(二十二)
51 0

热门文章

最新文章

下一篇
开通oss服务