BackTrader 中文文档(十七)(3)

简介: BackTrader 中文文档(十七)

BackTrader 中文文档(十七)(2)https://developer.aliyun.com/article/1505385

示例代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import backtrader as bt
class TestSizer(bt.Sizer):
    params = dict(stake=1)
    def _getsizing(self, comminfo, cash, data, isbuy):
        dt, i = self.strategy.datetime.date(), data._id
        s = self.p.stake * (1 + (not isbuy))
        print('{} Data {} OType {} Sizing to {}'.format(
            dt, data._name, ('buy' * isbuy) or 'sell', s))
        return s
class St(bt.Strategy):
    params = dict(
        enter=[1, 3, 4],  # data ids are 1 based
        hold=[7, 10, 15],  # data ids are 1 based
        usebracket=True,
        rawbracket=True,
        pentry=0.015,
        plimits=0.03,
        valid=10,
    )
    def notify_order(self, order):
        if order.status == order.Submitted:
            return
        dt, dn = self.datetime.date(), order.data._name
        print('{} {} Order {} Status {}'.format(
            dt, dn, order.ref, order.getstatusname())
        )
        whichord = ['main', 'stop', 'limit', 'close']
        if not order.alive():  # not alive - nullify
            dorders = self.o[order.data]
            idx = dorders.index(order)
            dorders[idx] = None
            print('-- No longer alive {} Ref'.format(whichord[idx]))
            if all(x is None for x in dorders):
                dorders[:] = []  # empty list - New orders allowed
    def __init__(self):
        self.o = dict()  # orders per data (main, stop, limit, manual-close)
        self.holding = dict()  # holding periods per data
    def next(self):
        for i, d in enumerate(self.datas):
            dt, dn = self.datetime.date(), d._name
            pos = self.getposition(d).size
            print('{} {} Position {}'.format(dt, dn, pos))
            if not pos and not self.o.get(d, None):  # no market / no orders
                if dt.weekday() == self.p.enter[i]:
                    if not self.p.usebracket:
                        self.o[d] = [self.buy(data=d)]
                        print('{} {} Buy {}'.format(dt, dn, self.o[d][0].ref))
                    else:
                        p = d.close[0] * (1.0 - self.p.pentry)
                        pstp = p * (1.0 - self.p.plimits)
                        plmt = p * (1.0 + self.p.plimits)
                        valid = datetime.timedelta(self.p.valid)
                        if self.p.rawbracket:
                            o1 = self.buy(data=d, exectype=bt.Order.Limit,
                                          price=p, valid=valid, transmit=False)
                            o2 = self.sell(data=d, exectype=bt.Order.Stop,
                                           price=pstp, size=o1.size,
                                           transmit=False, parent=o1)
                            o3 = self.sell(data=d, exectype=bt.Order.Limit,
                                           price=plmt, size=o1.size,
                                           transmit=True, parent=o1)
                            self.o[d] = [o1, o2, o3]
                        else:
                            self.o[d] = self.buy_bracket(
                                data=d, price=p, stopprice=pstp,
                                limitprice=plmt, oargs=dict(valid=valid))
                        print('{} {} Main {} Stp {} Lmt {}'.format(
                            dt, dn, *(x.ref for x in self.o[d])))
                    self.holding[d] = 0
            elif pos:  # exiting can also happen after a number of days
                self.holding[d] += 1
                if self.holding[d] >= self.p.hold[i]:
                    o = self.close(data=d)
                    self.o[d].append(o)  # manual order to list of orders
                    print('{} {} Manual Close {}'.format(dt, dn, o.ref))
                    if self.p.usebracket:
                        self.cancel(self.o[d][1])  # cancel stop side
                        print('{} {} Cancel {}'.format(dt, dn, self.o[d][1]))
def runstrat(args=None):
    args = parse_args(args)
    cerebro = bt.Cerebro()
    # Data feed kwargs
    kwargs = dict()
    # 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.YahooFinanceCSVData(dataname=args.data0, **kwargs)
    cerebro.adddata(data0, name='d0')
    data1 = bt.feeds.YahooFinanceCSVData(dataname=args.data1, **kwargs)
    data1.plotinfo.plotmaster = data0
    cerebro.adddata(data1, name='d1')
    data2 = bt.feeds.YahooFinanceCSVData(dataname=args.data2, **kwargs)
    data2.plotinfo.plotmaster = data0
    cerebro.adddata(data2, name='d2')
    # Broker
    cerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))
    cerebro.broker.setcommission(commission=0.001)
    # Sizer
    # cerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))
    cerebro.addsizer(TestSizer, **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=(
            'Multiple Values and Brackets'
        )
    )
    parser.add_argument('--data0', default='../../datas/nvda-1999-2014.txt',
                        required=False, help='Data0 to read in')
    parser.add_argument('--data1', default='../../datas/yhoo-1996-2014.txt',
                        required=False, help='Data1 to read in')
    parser.add_argument('--data2', default='../../datas/orcl-1995-2014.txt',
                        required=False, help='Data1 to read in')
    # Defaults for dates
    parser.add_argument('--fromdate', required=False, default='2001-01-01',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
    parser.add_argument('--todate', required=False, default='2007-01-01',
                        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')
    return parser.parse_args(pargs)
if __name__ == '__main__':
    runstrat()
• 193

括号订单

原文:www.backtrader.com/blog/posts/2017-04-01-bracket/bracket/

发行 1.9.37.116 版本添加了 bracket 订单,提供了由回测经纪人支持的非常广泛的订单范围(MarketLimitCloseStopStopLimitStopTrailStopTrailLimitOCO

注意

这是为了 回测交互经纪人 商店而实现的

bracket 订单不是单个订单,而实际上是由 3 个订单组成的。让我们考虑长边

  • 主边 buy 订单,通常设置为 LimitStopLimit 订单
  • 低边 sell 订单,通常设置为 Stop 订单以限制损失
  • 高边 sell 订单,通常设置为 Limit 订单以获利

对于短边,相应的 sell 和 2 x buy 订单。

低/高边订单实际上确实围绕主边订单创建了一个括号。

为了加入一些逻辑,以下规则适用:

  • 为了避免它们中的任何一个被独立触发,三个订单一起提交
  • 低/高边订单标记为主边的子订单
  • 直到主边执行完毕,子订单都不活跃
  • 主边取消则低边和高边都取消
  • 主边的执行激活了低边和高边
  • 一旦活跃
  • 任何低/高边订单的执行或取消都会自动取消另一个

使用模式

创建括号订单集的两种可能性

  • 单次发行 3 个订单
  • 手动发行 3 个订单

单次发行一个括号

backtraderStrategy 中提供了两种控制 bracket 订单的新方法。

  • buy_bracketsell_bracket

注意

签名和信息在下方或在 Strategy 参考部分。

通过一条语句完整发行 3 个订单集。例如:

brackets = self.buy_bracket(limitprice=14.00, price=13.50, stopprice=13.00)

注意 stoppricelimitprice 如何包裹主 price

这应该足够了。实际的目标 data 将是 data0,而 size 将由默认大小器自动确定。当然,可以指定许多其他参数以对执行进行精细控制。

返回值是:

  • 包含 3 个订单的列表,顺序为 [main, stop, limit]

因为当发出 sell_bracket 订单时,低边和高边将被转向,参数按照惯例命名为 stoplimit

  • stop 旨在停止损失(在长操作中是低边,在短操作中是高边)
  • limit 旨在获利(在长操作中是高边,在短操作中是低边)

手动发行一个括号

这涉及生成 3 个订单并调整 transmitparent 参数。规则如下:

  • 主边订单必须首先创建,且 transmit=False
  • 低/高边订单必须具有 parent=main_side_order
  • 要创建的第一个低/高边订单必须具有 transmit=False
  • 要创建的最后一个订单(低端或高端)设置transmit=True

一个实际示例,执行上述单个命令所做的事情:

mainside = self.buy(price=13.50, exectype=bt.Order.Limit, transmit=False)
lowside  = self.sell(price=13.00, size=mainsize.size, exectype=bt.Order.Stop,
                     transmit=False, parent=mainside)
highside = self.sell(price=14.00, size=mainsize.size, exectype=bt.Order.Limit,
                     transmit=True, parent=mainside)

还有很多事情要做:

  • 跟踪mainside的顺序以指示它是其他订单的父订单
  • 控制transmit以确保只有最后一个订单触发联合传输
  • 指定执行类型
  • 为低端和高端指定size
    因为size 必须相同。如果参数没有手动指定,并且最终用户引入了一个 sizer,那么 sizer 实际上可能为订单指示一个不同的值。这就是为什么在为mainside订单设置后,必须手动添加到调用中的原因。

它的一个示例

运行下面的示例会产生以下输出(为简洁起见)

$ ./bracket.py --plot
2005-01-28: Oref 1 / Buy at 2941.11055
2005-01-28: Oref 2 / Sell Stop at 2881.99275
2005-01-28: Oref 3 / Sell Limit at 3000.22835
2005-01-31: Order ref: 1 / Type Buy / Status Submitted
2005-01-31: Order ref: 2 / Type Sell / Status Submitted
2005-01-31: Order ref: 3 / Type Sell / Status Submitted
2005-01-31: Order ref: 1 / Type Buy / Status Accepted
2005-01-31: Order ref: 2 / Type Sell / Status Accepted
2005-01-31: Order ref: 3 / Type Sell / Status Accepted
2005-02-01: Order ref: 1 / Type Buy / Status Expired
2005-02-01: Order ref: 2 / Type Sell / Status Canceled
2005-02-01: Order ref: 3 / Type Sell / Status Canceled
...
2005-08-11: Oref 16 / Buy at 3337.3892
2005-08-11: Oref 17 / Sell Stop at 3270.306
2005-08-11: Oref 18 / Sell Limit at 3404.4724
2005-08-12: Order ref: 16 / Type Buy / Status Submitted
2005-08-12: Order ref: 17 / Type Sell / Status Submitted
2005-08-12: Order ref: 18 / Type Sell / Status Submitted
2005-08-12: Order ref: 16 / Type Buy / Status Accepted
2005-08-12: Order ref: 17 / Type Sell / Status Accepted
2005-08-12: Order ref: 18 / Type Sell / Status Accepted
2005-08-12: Order ref: 16 / Type Buy / Status Completed
2005-08-18: Order ref: 17 / Type Sell / Status Completed
2005-08-18: Order ref: 18 / Type Sell / Status Canceled
...
2005-09-26: Oref 22 / Buy at 3383.92535
2005-09-26: Oref 23 / Sell Stop at 3315.90675
2005-09-26: Oref 24 / Sell Limit at 3451.94395
2005-09-27: Order ref: 22 / Type Buy / Status Submitted
2005-09-27: Order ref: 23 / Type Sell / Status Submitted
2005-09-27: Order ref: 24 / Type Sell / Status Submitted
2005-09-27: Order ref: 22 / Type Buy / Status Accepted
2005-09-27: Order ref: 23 / Type Sell / Status Accepted
2005-09-27: Order ref: 24 / Type Sell / Status Accepted
2005-09-27: Order ref: 22 / Type Buy / Status Completed
2005-10-04: Order ref: 24 / Type Sell / Status Completed
2005-10-04: Order ref: 23 / Type Sell / Status Canceled
...

显示了 3 种不同的结果:

  • 在第 1 种情况下,主订单已过期,这自动取消了其他两个订单
  • 在第 2 种情况下,主订单已完成,低端(在买入情况下为止损)已执行,限制损失
  • 在第 3 种情况下,主订单已完成,高端(限价)已执行
    这可以注意到,因为Completed的 id 分别为2224,而high方订单是最后发出的,这意味着未执行的 low side 订单的 id 为 23。

视觉上

可以立即看到,亏损交易和盈利交易都围绕着相同的数值对齐,这就是 bracketing 的目的。控制双方。

运行示例手动发出 3 个订单,但可以告诉它使用buy_bracket。让我们看看输出:

$ ./bracket.py --strat usebracket=True

产生相同的结果

一些参考

查看新的buy_bracketsell_bracket方法

def buy_bracket(self, data=None, size=None, price=None, plimit=None,
                exectype=bt.Order.Limit, valid=None, tradeid=0,
                trailamount=None, trailpercent=None, oargs={},
                stopprice=None, stopexec=bt.Order.Stop, stopargs={},
                limitprice=None, limitexec=bt.Order.Limit, limitargs={},
                **kwargs):
    '''
    Create a bracket order group (low side - buy order - high side). The
    default behavior is as follows:
      - Issue a **buy** order with execution ``Limit``
      - Issue a *low side* bracket **sell** order with execution ``Stop``
      - Issue a *high side* bracket **sell** order with execution
        ``Limit``.
    See below for the different parameters
      - ``data`` (default: ``None``)
        For which data the order has to be created. If ``None`` then the
        first data in the system, ``self.datas[0] or self.data0`` (aka
        ``self.data``) will be used
      - ``size`` (default: ``None``)
        Size to use (positive) of units of data to use for the order.
        If ``None`` the ``sizer`` instance retrieved via ``getsizer`` will
        be used to determine the size.
        **Note**: The same size is applied to all 3 orders of the bracket
      - ``price`` (default: ``None``)
        Price to use (live brokers may place restrictions on the actual
        format if it does not comply to minimum tick size requirements)
        ``None`` is valid for ``Market`` and ``Close`` orders (the market
        determines the price)
        For ``Limit``, ``Stop`` and ``StopLimit`` orders this value
        determines the trigger point (in the case of ``Limit`` the trigger
        is obviously at which price the order should be matched)
      - ``plimit`` (default: ``None``)
        Only applicable to ``StopLimit`` orders. This is the price at which
        to set the implicit *Limit* order, once the *Stop* has been
        triggered (for which ``price`` has been used)
      - ``trailamount`` (default: ``None``)
        If the order type is StopTrail or StopTrailLimit, this is an
        absolute amount which determines the distance to the price (below
        for a Sell order and above for a buy order) to keep the trailing
        stop
      - ``trailpercent`` (default: ``None``)
        If the order type is StopTrail or StopTrailLimit, this is a
        percentage amount which determines the distance to the price (below
        for a Sell order and above for a buy order) to keep the trailing
        stop (if ``trailamount`` is also specified it will be used)
      - ``exectype`` (default: ``bt.Order.Limit``)
        Possible values: (see the documentation for the method ``buy``
      - ``valid`` (default: ``None``)
        Possible values: (see the documentation for the method ``buy``
      - ``tradeid`` (default: ``0``)
        Possible values: (see the documentation for the method ``buy``
      - ``oargs`` (default: ``{}``)
        Specific keyword arguments (in a ``dict``) to pass to the main side
        order. Arguments from the default ``**kwargs`` will be applied on
        top of this.
      - ``**kwargs``: additional broker implementations may support extra
        parameters. ``backtrader`` will pass the *kwargs* down to the
        created order objects
        Possible values: (see the documentation for the method ``buy``
        **Note**: this ``kwargs`` will be applied to the 3 orders of a
        bracket. See below for specific keyword arguments for the low and
        high side orders
      - ``stopprice`` (default: ``None``)
        Specific price for the *low side* stop order
      - ``stopexec`` (default: ``bt.Order.Stop``)
        Specific execution type for the *low side* order
      - ``stopargs`` (default: ``{}``)
        Specific keyword arguments (in a ``dict``) to pass to the low side
        order. Arguments from the default ``**kwargs`` will be applied on
        top of this.
      - ``limitprice`` (default: ``None``)
        Specific price for the *high side* stop order
      - ``stopexec`` (default: ``bt.Order.Limit``)
        Specific execution type for the *high side* order
      - ``limitargs`` (default: ``{}``)
        Specific keyword arguments (in a ``dict``) to pass to the high side
        order. Arguments from the default ``**kwargs`` will be applied on
        top of this.
    Returns:
      - A list containing the 3 orders [order, stop side, limit side]
    '''
def sell_bracket(self, data=None,
                 size=None, price=None, plimit=None,
                 exectype=bt.Order.Limit, valid=None, tradeid=0,
                 trailamount=None, trailpercent=None,
                 oargs={},
                 stopprice=None, stopexec=bt.Order.Stop, stopargs={},
                 limitprice=None, limitexec=bt.Order.Limit, limitargs={},
                 **kwargs):
    '''
    Create a bracket order group (low side - buy order - high side). The
    default behavior is as follows:
      - Issue a **sell** order with execution ``Limit``
      - Issue a *high side* bracket **buy** order with execution ``Stop``
      - Issue a *low side* bracket **buy** order with execution ``Limit``.
    See ``bracket_buy`` for the meaning of the parameters
    Returns:
      - A list containing the 3 orders [order, stop side, limit side]
    '''

示例用法

$ ./bracket.py --help
usage: bracket.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE]
                  [--cerebro kwargs] [--broker kwargs] [--sizer kwargs]
                  [--strat kwargs] [--plot [kwargs]]
Sample Skeleton
optional arguments:
  -h, --help           show this help message and exit
  --data0 DATA0        Data to read in (default:
                       ../../datas/2005-2006-day-001.txt)
  --fromdate FROMDATE  Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --todate TODATE      Date[time] in YYYY-MM-DD[THH:MM:SS] format (default: )
  --cerebro kwargs     kwargs in key=value format (default: )
  --broker kwargs      kwargs in key=value format (default: )
  --sizer kwargs       kwargs in key=value format (default: )
  --strat kwargs       kwargs in key=value format (default: )
  --plot [kwargs]      kwargs in key=value format (default: )


BackTrader 中文文档(十七)(4)https://developer.aliyun.com/article/1505389

相关文章
|
1月前
|
机器学习/深度学习 人工智能 测试技术
BackTrader 中文文档(十四)(3)
BackTrader 中文文档(十四)
22 0
BackTrader 中文文档(十四)(3)
|
1月前
|
存储
BackTrader 中文文档(十四)(4)
BackTrader 中文文档(十四)
21 0
BackTrader 中文文档(十四)(4)
|
1月前
|
算法 数据可视化 程序员
BackTrader 中文文档(十四)(1)
BackTrader 中文文档(十四)
23 0
BackTrader 中文文档(十四)(1)
|
1月前
BackTrader 中文文档(十七)(4)
BackTrader 中文文档(十七)
17 0
|
1月前
BackTrader 中文文档(十七)(2)
BackTrader 中文文档(十七)
17 0
|
1月前
|
测试技术 索引
BackTrader 中文文档(十七)(1)
BackTrader 中文文档(十七)
18 0
|
1月前
|
调度
BackTrader 中文文档(十五)(2)
BackTrader 中文文档(十五)
15 0
|
1月前
|
算法 索引 Python
BackTrader 中文文档(十五)(4)
BackTrader 中文文档(十五)
18 0
|
1月前
|
编解码 算法 开发者
BackTrader 中文文档(十五)(1)
BackTrader 中文文档(十五)
20 0
|
1月前
BackTrader 中文文档(十五)(3)
BackTrader 中文文档(十五)
20 0

相关实验场景

更多