Backtrader 文档学习-Bracket Orders

Backtrader 文档学习-Bracket Orders

1. 概述

组合订单类型是一个非常宽泛的订单类别,只要brokder支持的订单类型都可以,
包括(Market, Limit, Close, Stop, StopLimit, StopTrail, StopTrailLimit, OCO)。

该功能用于回测,交互broker

Bracket订单不是单个订单,而是由3个订单组成,考虑多头情况。

  • 一个主要的买入订单,通常设置为限价或止损限价订单。
  • 一个低位卖出订单,通常设置为止损单以限制损失。(止损单)
  • 一个高位卖出订单,通常设置为限价单以获利。(止盈单)

相反如果是空头情况,有相应的卖出和2个买入订单。
低/高位订单实际上在主订单周围创建了一个bracket。
从逻辑上讲,以下规则适用:

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

2.使用模式

创建Bracket订单集有两种可能性 :

  • 单次触发3个订单
  • 手动触发3个订单
(1) 单次触发Bracket订单

要控制bracket订单,backtrader在
strategy
中提供了2个新的方法:
buy_bracket 和 sell_bracket
下面一条语句返回一个包含3个订单组合

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

注意上面参数 stopprice 和 limitprice 如何环绕在 price 周围。
实际成交的数据默认是data0,成交数量由默认的sizer自动计算得到。除了可以指定这两个参数,也可以指定其他参数,执行精细控制。

因为当发出sell_bracket订单时,低端和高端将被转向,参数的命名遵循常规stop 和 limit 。

  • 代码返回list,list中包含3个订单[main, stop, limit]。
  • 因为当生成一个sell_bracket订单,low和high会环绕在price两边,参数的命名遵循stop和 limit的约定。
  • stop意味着止损(低的一侧是买入,高的一侧是卖出)
  • limit意味着止盈(高的一侧是买入,低的一侧是卖出)
(2)手工触发Backet订单

涉及到3个订单的生成,通过transmit和parent参数实现。规则:

  • 主端订单必须首先创建,并且传入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=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)
  • 保持跟踪主侧订单,标识它是其他订单的父订单
  • 控制传输,以确保只有最后一个订单会被联合触发
  • 定义执行类型
  • 定义低位和高位的size

由于size必须相同。如果没有手工指定参数,最终用户引入了sizer,那么sizer实际上可以为订单指示不同的值。这就是为什么必须先设置主侧订单后手动添加到调用中。

3. 示例

交易核心代码

o1 exectype=bt.Order.Limit 主单
o2 exectype=bt.Order.Stop 止损单
o3 exectype=bt.Order.Limit 止盈单

            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]

python ./bracket.py --plot

(1)主侧订单过期
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-02-01 1号买单过期,2/3号订单取消。

(2)止损单执行
2005-08-11: Oref 16 / Buy at 3337.3891999999996
2005-08-11: Oref 17 / Sell Stop at 3270.3059999999996
2005-08-11: Oref 18 / Sell Limit at 3404.4723999999997
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-08-12 ,16号主单完成,17号止损单完成,18日止盈单取消

(3)止盈单执行
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

第三个案例中,主侧订单已完成,高位(限价)被执行,能够注意到,因为完成的id是22和24,高侧订单是最后一个发出的,这意味着未执行的低侧订单id是23。
2005-09-27,22号主单完成,23号止损单取消,24号止盈单完成。

(4)图示

在这里插入图片描述
It can be immediately seen that the losing trades align around the same value and winning trades too, which is the purpose of the backeting. Controlling both sides.

能够立刻看到,亏损交易都在同一个值附近,赢利交易也是如此,这就是backeting的目的。控制双侧,即控制止损,控制盈利。

(5)用参数usebracket=True
python  ./bracket.py --strat usebracket=True --plot

相同的结果。
图示:
在这里插入图片描述

4. 完整代码

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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/358485.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VBA语言専攻介绍(更新)

VBA语言専攻简介 我给VBA的定义:VBA是个人小型自动化处理的有效工具。我这里专注VBA,垂直度非常高,并和多个国际VBA网站(英语系和德语系)有互动及技术互通。您来到这里,就是进入到了一个绚烂的VBA世界&…

vue-computed 计算属性

一、computed 计算属性 在Vue应用中&#xff0c;在模板中双向绑定一些数据或者表达式&#xff0c;但是表达式如果过长&#xff0c;或者逻辑更为复杂 时&#xff0c;就会变得臃肿甚至难以维护和阅读&#xff0c;例如&#xff1a; <div>写在双括号中的表达式太长了,不利于阅…

【数据结构:顺序表】

文章目录 线性表顺序表1.1 顺序表结构的定义1.2 初始化顺序表1.3 检查顺序表空间1.4 打印1.5 尾插1.6 头插1.7 尾删1.8 头删1.9 查找1.10 指定位置插入1.11 删除指定位置数据1.12 销毁顺序表 数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在一…

​如何在Shopee平台上进行品牌选品

在如今竞争激烈的电商市场上&#xff0c;建立一个成功的品牌对于卖家来说至关重要。Shopee作为一个知名的电商平台&#xff0c;为卖家提供了广阔的销售机会。然而&#xff0c;在Shopee平台上进行品牌选品并不是一件容易的事情。卖家需要遵循一些策略&#xff0c;以确保选品能够…

uniapp如何添加多个表单数组?

目录 一、实现思路 二、实现步骤 ①view部分展示 ②JavaScript 内容 ③css中样式展示 三、效果展示 四、小结 注意事项 总结模板&#xff1a; 一、实现思路 1.在 data 中定义一个数组&#xff0c;用于存储表单项的数据 2.在模板中使用 v-for 指令渲染表单项 3.在 methods 中…

vue实现跳转传参查询

vue实现跳转传参查询&#xff1a; 应用场景&#xff1a;外部链接携参跳转目标页时,避免多次输入查询信息查询 目标需求&#xff1a;登录及非登录状态均可跳转自动查询 避坑指南&#xff1a;token失效时需要重新缓存及路由导航缓存判断 简单实现&#xff1a;缓存信息&#xff0c…

2024年,AI 掀起数据与分析市场的新风暴

2024 年伊始&#xff0c;Kyligence 联合创始人兼 CEO 韩卿在其公司内部的飞书订阅号发表了多篇 Rethink Data & Analytics 的内部信&#xff0c;分享了对数据与分析行业的一些战略思考&#xff0c;尤其是 AI 带来的各种变化和革命&#xff0c;是如何深刻地影响这个行业乃至…

jupyter出现问题ModuleNotFoundError: No module named ‘exceptiongroup‘

今天使用pyg的jupyter环境发现这个环境没法用, 所以只能把这个kernel给重删了然后再装&#xff0c;操作记录如下 查看kernel jupyter kernelspec list注意不是jupyter kernel --list 需要加关键字spec, 删除kernel jupyter kernelspec remove pyg当重新安装这个kernel时可能…

macos Android平台签名证书(.keystore)

一、申请appid的使用说明&#xff08;有appid的请忽略申请appid&#xff09; 创建应用 申请的appid在源码视图填写后会自动生成一个对应的包名 ⚠️注意&#xff1a;申请appid的时候应用名称和项目名称保持一致。 二、 Android如何使用自用证书进行打包 1.找到安装jdk的路径…

【学习笔记】vue3的watch

尚硅谷Vue2.0Vue3.0全套教程丨vuejs从入门到精通 课程 P152节 笔记&#xff1a; 情况一&#xff1a;监视ref所定义的一个响应式数据 情况二&#xff1a;监视ref所定义的多个响应式数据 这两种情况比较简单&#xff0c;正常写就ok&#xff1a; 情况三&#xff1a;监视reactive所…

Qt|QPushButton控件讲解

前提 按钮分为了四种状态&#xff1a;常态、聚焦、按下、禁用 前一段时间更新了MFC框架下CButton的自绘。因为MFC框架下的按钮限制性很高&#xff0c;所以只能由自绘实现各种风格&#xff0c;但是QT框架完美的解决了这个问题&#xff0c;我们只需要了解如何调用&#xff0c;就…

MySQL-窗口函数

介绍&#xff1a; MSQL8.0新增窗口函数商口函数又被称为开窗函数&#xff0c;与Oracle窗口函数类似&#xff0c;属于MysaL的一大特点 非聚合窗口函数是相对于聚函数来说的。聚合函数是对一组数据计算后返回单个值(即分组)&#xff0c;非聚合函数一次只会处理一行数据。窗口聚…

buffer/cache导致内存不足的案例分析

目录 一、项目简介 二、问题分析 三、问题处理 什么是buffer/cache&#xff1f; buffer/cache 需要注意的一些特点 如何进行手动 buffer/cache 回收 手动 buffer/cache 回收可能出现的问题 如何让系统自动回收buffer/cache vm.min_free_kbytes 四、参考文献 一、项目…

亚信安慧AntDB:AntDB-M元数据锁(八)

5.6 死锁检测 图4-死锁等待 每个线程在进入锁等待前&#xff0c;都会先进行死锁检测&#xff0c;避免陷入死锁等待。在检测前&#xff0c;会先将自己获取到的unobtrusive锁进行物化&#xff0c;即将锁放入锁的授予列表中&#xff0c;以便死锁检测能区分锁的归属线程。然后设置…

Proto文件如何生成JavaProto对象?

首先安装好Protocol Buffer的编译器 Protocol Buffer: version:2.6.1 link: 链接直达 根据电脑环境进行下载&#xff0c;Widnwos 32/64位就选择win32是没问题的&#xff0c;楼主亲测 1.proto文件编写 Person.proto public class Person {String name;int id;String email…

【高阶数据结构】AVL树

文章目录 前言1. 什么是二叉搜索树2. 什么是AVL树3. AVL树节点的定义4. AVL树的插入4.1 新节点插入较高右子树的右侧4.2 新节点插入较高左子树的左侧4.3 新节点插入较高左子树的右侧4.4 新节点插入较高右子树的左侧插入操作完整代码插入操作总结 AVL树的验证AVL树的删除AVL树性…

git push后,如何撤销git log上的错误注释

修改了本地的代码&#xff0c;执行了下面的操作&#xff0c;提交之后&#xff0c;怎么样修改 git add ********(文件名)//git add 添加修改文件名之后 git commit //git commit 在当前分支提交&#xff0c;编写提交注释 git push //git push 提交修…

虹科干货 | 如何使用nProbe Cento构建100 Gbit NetFlow 传感器

本文是一份全面的指南&#xff0c;解释了如何使用nProbe Cento构建一个高效的100 Gbit NetFlow传感器。旨在帮助大家充分利用NetFlow技术&#xff0c;以监控和分析高速网络流量。 当需要监控分布式网络&#xff0c;了解流经上行链路或关键网段的网络流量时&#xff0c;NetFlow…

ES实战回顾

1、你用的集群节点情况&#xff1f; 一个ES集群&#xff0c;18个节点&#xff0c;其中3个主节点&#xff0c;15个数据节点&#xff0c;500G左右的索引数据量&#xff0c;没有单独的协调节点&#xff0c;它的每个节点都可以充当协调功能&#xff1b; 2、你们常用的索引有哪些&a…

【游戏服务器部署】幻兽帕鲁服务器一键部署保姆级教程,游戏私服还是自己搭建的香

在帕鲁的世界&#xff0c;你可以选择与神奇的生物「帕鲁」一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。帕鲁可以进行战斗、繁殖、协助你做农活&#xff0c;也可以为你在工厂工作。你也可以将它们进行售卖&#xff0c;或肢解后食用。—幻兽帕鲁 想要…