BackTrader 中文文档(八)(4)

简介: BackTrader 中文文档(八)

BackTrader 中文文档(八)(3)https://developer.aliyun.com/article/1505281

括号订单

原文:www.backtrader.com/docu/order-creation-execution/bracket/bracket/

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

注意

这是为了 回测交互式经纪人 存储而实现的

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

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

对应的 sell 和 2 x buy 订单用于短侧。

低/高侧订单实际上会围绕主要侧订单创建一个括号。

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

  • 3 个订单一起提交,以避免它们中的任何一个独立触发
  • 低/高侧订单被标记为主要侧的子订单
  • 子订单在主要侧执行前不活动
  • 取消主要侧会同时取消低侧和高侧
  • 主要侧的执行会激活低侧和高侧
  • 一旦激活
  • 任何一侧订单的执行或取消都会自动取消另一侧订单

使用模式

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

  • 单独发出 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
  • 要创建的第 1 个低/高侧订单必须具有 transmit=False
  • 最后创建的订单(无论是低端还是高端)设置transmit=True

执行上面单个命令的实际示例:

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

还有很多工作要做的地方:

  • 跟踪mainside订单以指示它是其他订单的父订单
  • 控制transmit以确保只有最后一个订单触发联合传输
  • 指定执行类型
  • 为低端和高端指定size
    因为size必须相同。如果未手动指定参数并且最终用户已引入调整器,则调整器实际上可以指示订单的不同值。这就是为什么在为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 种不同的结果:

  • 在第一种情况下,主要的副作用已经过期,这自动取消了其他两个
  • 在第二种情况下,主要的副作用已经完成,低(在购买情况下停止)被执行以限制损失
  • 在第三种情况下,主要的副作用已经完成,而高侧(限制)被执行
    这可以注意到,因为已完成的 ids 是2224端订单最后被发出,这意味着未执行的低端订单的 id 为 23。

视觉上

可以立即看到,失败的交易围绕着相同的值以及成功的交易,这就是背书的目的。控制两侧。

正在运行的示例手动发出了 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 bracket 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 bracket 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: )

样本代码

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)
import argparse
import datetime
import backtrader as bt
class St(bt.Strategy):
    params = dict(
        ma=bt.ind.SMA,
        p1=5,
        p2=15,
        limit=0.005,
        limdays=3,
        limdays2=1000,
        hold=10,
        usebracket=False,  # use order_target_size
        switchp1p2=False,  # switch prices of order1 and order2
    )
    def notify_order(self, order):
        print('{}: Order ref: {} / Type {} / Status {}'.format(
            self.data.datetime.date(0),
            order.ref, 'Buy' * order.isbuy() or 'Sell',
            order.getstatusname()))
        if order.status == order.Completed:
            self.holdstart = len(self)
        if not order.alive() and order.ref in self.orefs:
            self.orefs.remove(order.ref)
    def __init__(self):
        ma1, ma2 = self.p.ma(period=self.p.p1), self.p.ma(period=self.p.p2)
        self.cross = bt.ind.CrossOver(ma1, ma2)
        self.orefs = list()
        if self.p.usebracket:
            print('-' * 5, 'Using buy_bracket')
    def next(self):
        if self.orefs:
            return  # pending orders do nothing
        if not self.position:
            if self.cross > 0.0:  # crossing up
                close = self.data.close[0]
                p1 = close * (1.0 - self.p.limit)
                p2 = p1 - 0.02 * close
                p3 = p1 + 0.02 * close
                valid1 = datetime.timedelta(self.p.limdays)
                valid2 = valid3 = datetime.timedelta(self.p.limdays2)
                if self.p.switchp1p2:
                    p1, p2 = p2, p1
                    valid1, valid2 = valid2, valid1
                if not self.p.usebracket:
                    o1 = self.buy(exectype=bt.Order.Limit,
                                  price=p1,
                                  valid=valid1,
                                  transmit=False)
                    print('{}: Oref {} / Buy at {}'.format(
                        self.datetime.date(), o1.ref, p1))
                    o2 = self.sell(exectype=bt.Order.Stop,
                                   price=p2,
                                   valid=valid2,
                                   parent=o1,
                                   transmit=False)
                    print('{}: Oref {} / Sell Stop at {}'.format(
                        self.datetime.date(), o2.ref, p2))
                    o3 = self.sell(exectype=bt.Order.Limit,
                                   price=p3,
                                   valid=valid3,
                                   parent=o1,
                                   transmit=True)
                    print('{}: Oref {} / Sell Limit at {}'.format(
                        self.datetime.date(), o3.ref, p3))
                    self.orefs = [o1.ref, o2.ref, o3.ref]
                else:
                    os = self.buy_bracket(
                        price=p1, valid=valid1,
                        stopprice=p2, stopargs=dict(valid=valid2),
                        limitprice=p3, limitargs=dict(valid=valid3),)
                    self.orefs = [o.ref for o in os]
        else:  # in the market
            if (len(self) - self.holdstart) >= self.p.hold:
                pass  # do nothing in this case
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.BacktraderCSVData(dataname=args.data0, **kwargs)
    cerebro.adddata(data0)
    # 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=(
            'Sample Skeleton'
        )
    )
    parser.add_argument('--data0', default='../../datas/2005-2006-day-001.txt',
                        required=False, help='Data to read in')
    # Defaults for dates
    parser.add_argument('--fromdate', required=False, default='',
                        help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
    parser.add_argument('--todate', required=False, default='',
                        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()


相关文章
|
5月前
|
C++ 索引
BackTrader 中文文档(七)(3)
BackTrader 中文文档(七)
32 3
|
5月前
BackTrader 中文文档(七)(2)
BackTrader 中文文档(七)
35 3
|
5月前
BackTrader 中文文档(八)(2)
BackTrader 中文文档(八)
40 0
BackTrader 中文文档(八)(2)
|
5月前
|
Python
BackTrader 中文文档(十)(3)
BackTrader 中文文档(十)
93 0
|
5月前
|
存储 Python
BackTrader 中文文档(八)(1)
BackTrader 中文文档(八)
43 0
|
5月前
|
编解码 C++ 索引
BackTrader 中文文档(九)(3)
BackTrader 中文文档(九)
92 0
|
5月前
|
存储 索引
BackTrader 中文文档(十)(4)
BackTrader 中文文档(十)
41 0
|
5月前
|
Python
BackTrader 中文文档(七)(1)
BackTrader 中文文档(七)
67 0
|
5月前
|
测试技术
BackTrader 中文文档(九)(1)
BackTrader 中文文档(九)
58 0
|
5月前
|
索引
BackTrader 中文文档(九)(2)
BackTrader 中文文档(九)
92 0