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 upclose = self.data.close[0]p1 = close * (1.0 - self.p.limit)p2 = p1 - 0.02 * closep3 = p1 + 0.02 * closevalid1 = datetime.timedelta(self.p.limdays)valid2 = valid3 = datetime.timedelta(self.p.limdays2)if self.p.switchp1p2:p1, p2 = p2, p1valid1, valid2 = valid2, valid1if 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 datetimeimport backtrader as btclass 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_sizeswitchp1p2=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 nothingif not self.position:if self.cross > 0.0: # crossing upclose = self.data.close[0]p1 = close * (1.0 - self.p.limit)p2 = p1 - 0.02 * closep3 = p1 + 0.02 * closevalid1 = datetime.timedelta(self.p.limdays)valid2 = valid3 = datetime.timedelta(self.p.limdays2)if self.p.switchp1p2:p1, p2 = p2, p1valid1, valid2 = valid2, valid1if 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 marketif (len(self) - self.holdstart) >= self.p.hold:pass # do nothing in this casedef runstrat(args=None):args = parse_args(args)cerebro = bt.Cerebro()# Data feed kwargskwargs = dict()# Parse from/to-datedtfmt, 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 feeddata0 = bt.feeds.BacktraderCSVData(dataname=args.data0, **kwargs)cerebro.adddata(data0)# Brokercerebro.broker = bt.brokers.BackBroker(**eval('dict(' + args.broker + ')'))# Sizercerebro.addsizer(bt.sizers.FixedSize, **eval('dict(' + args.sizer + ')'))# Strategycerebro.addstrategy(St, **eval('dict(' + args.strat + ')'))# Executecerebro.run(**eval('dict(' + args.cerebro + ')'))if args.plot: # Plot if requested tocerebro.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 datesparser.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()
相关文章:
Backtrader 文档学习-Bracket Orders
Backtrader 文档学习-Bracket Orders 1. 概述 组合订单类型是一个非常宽泛的订单类别,只要brokder支持的订单类型都可以, 包括(Market, Limit, Close, Stop, StopLimit, StopTrail, StopTrailLimit, OCO)。 该功能用于回测,交互broker Brac…...
Python编程 从入门到实践(项目二:数据可视化)
本篇为实践项目二:数据可视化。 配合文章python编程入门学习,代码附文末。 项目二:数据可视化 1.生成数据1.1 安装Matplotlib1.2 绘制简单的折线图1.2.1 修改标签文字和线条粗细1.2.2 校正图形1.2.3 使用内置样式1.2.4 使用scatter()绘制散点…...
Linux版本下载Centos操作
目录 一、Centos7 二、下载Centos7镜像 三、下载Centos7 买了个硬件安装裸机(一堆硬件) 把安装盘放到虚拟机里面,给机器加电 配置设置 编辑 网络配置 开启网络功能 四、安装linux客户端 Xshell是什么 Xshell使用(连接…...
Offer必备算法_二分查找_八道力扣OJ题详解(由易到难)
目录 二分查找算法原理 ①力扣704. 二分查找 解析代码 ②力扣34. 在排序数组中查找元素的第一个和最后一个位置 解析代码 ③力扣69. x 的平方根 解析代码 ④力扣35. 搜索插入位置 解析代码 ⑤力扣852. 山脉数组的峰顶索引 解析代码 ⑥力扣162. 寻找峰值 解析代码…...
SpringBoot对Bean的管理
Bean扫描 Spring中使用标签扫描或者注解 Springboot中没有使用标签或者注解它是怎么扫描的我的controlelr,service等等 核心在于springboot启动类中的SpringBootApplication注解 此注解其实是一个组合注解 它组合了一个ComponentScan注解,相当于在启…...
体验 AutoGen Studio - 微软推出的友好多智能体协作框架
体验 AutoGen Studio - 微软推出的友好多智能体协作框架 - 知乎 最近分别体验了CrewAI、MetaGPT v0.6、Autogen Studio,了解了AI Agent 相关的知识。 它们的区别 可能有人要问:AutoGen我知道,那Autogen Studio是什么? https://g…...
超简单的正则表达式从入门到精通
正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。 概念 正则表达式是对字…...
webpack常用配置
1.webpack概念 本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 …...
nodejs学习计划--(六)包管理工具
包管理工具 1. 介绍 包是什么 『包』英文单词是 package ,代表了一组特定功能的源码集合包管理工具 管理『包』的应用软件,可以对「包」进行 下载安装 , 更新 , 删除 , 上传 等操作 借助包管理工具,可以快…...
数字地球开放平台农作物长势监测解决方案
数字地球开放平台农作物长势监测解决方案 利用遥感技术进行产量预测是一种高效而准确的方法,通过监测植被的生长状况、土地利用、气象等因素,可以为农业决策提供有力支持。数字地球开放平台拥有200颗卫星,为您提供一站式卫星遥感服务。 农情监…...
react hooks 的useState:
React 的 useState Hook 是一种用于在函数组件中管理状态的机制。它可以让函数组件具有类似于类组件的状态管理能力。 useState Hook 接收一个初始值作为参数,并返回一个包含状态值和更新状态值的数组。 import { useState } from react;const [state, setState] …...
编程那么难,为什么不弄一个大众一学就会的计算机语言呢?
大家好!今天要和大家聊聊一个有趣的想法: 想象一下,如果编程变得像拼乐高积木一样简单,那将是多么美妙的事情啊!不需要费尽心思去学习繁杂的语法规则和复杂的逻辑,只需要将代码块像积木一样拼接起来&#x…...
论文阅读2---多线激光lidar内参标定原理
前言:该论文介绍多线激光lidar的标定内参的原理,有兴趣的,可研读原论文。 1、标定参数 rotCorrection:旋转修正角,每束激光的方位角偏移(与当前旋转角度的偏移,正值表示激光束逆时针旋转&…...
Ubuntu 22.04 apt 安装 ros1 ros Noetic Ninjemys
众所周知 ros2还有很多功能没有移植,而ros1官方不再支持 ubuntu 20.04 之后的版本。另一方面Ubuntu 22.04 更新了很多对新硬件的驱动,有更好的兼容性和体验,这就变的很纠结。 如果想在 22.04 使用最新版本的 ros noetic 只有自己编译一个办法…...
单片机学习笔记---矩阵键盘
目录 矩阵键盘的介绍 独立按键和矩阵按键的相同之处: 矩阵按键的扫描 代码演示 代码模块化移植 Keil自定义模板步骤: 代码编写 矩阵键盘就是开发板上右下角的这个模块 这一节的代码是基于上一节讲的LCD1602液晶显示屏驱动代码进行的 矩阵键盘的介…...
第八篇 交叉编译华为云Iot SDK到Orangepi3B
本篇主要内容: 一、交叉编译华为云Iot SDK依赖1.宿主机安装交叉编译工具链(1)选择下载交叉编译工具链(2)解压、添加环境变量、重启2.交叉编译依赖库(0) 准备工作(1) 交叉…...
软件工程测试2
1.【单选】“数据流的分解一般达到2层数据流就截止”的说法是否正确 A. 正确 B. 错误 答案:B 2.【单选】 在类图中,哪种关系表达总体与局部的关系 A. 泛化 B. 实现 C. 聚合 D. 依赖 答案:C 3.【多选】从UML时序图中我们能够得到(…...
31.【TypeScript 教程】混入(Mixins)
TypeScript 混入(Mixins) 混入(Mixins)是面向对象编程中的一个比较重要的概念。本节将会通过一个实例逐步介绍混入是如何在 TypeScript 中使用的。 1. 解释 在 TypeScript 中,可以根据不同的功能定义多个可复用的类,它们将作为 …...
C语言常见面试题:什么是联合体,联合体的作用是什么?
联合体(union)是一种特殊的数据类型,它可以在同一块内存单元中存储不同的数据类型。联合体的作用在于能够节省内存空间,并且可以用来实现数据的共享和交换。 联合体的定义方式是在C语言中通过关键字union来定义,例如&…...
Nginx进阶篇【五】
Nginx进阶篇【五】 八、Nginx实现服务器端集群搭建8.1.Nginx与Tomcat部署8.1.1.环境准备(Tomcat)8.1.1.1.浏览器访问:8.1.1.2.获取动态资源的链接地址:8.1.1.3.在Centos上准备一个Tomcat作为后台web服务器8.1.1.4.准备一个web项目,将其打包为war8.1.1.5.启动tomcat进…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
