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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【安卓】不需要魔法使用AuthenticationApp解决Github报2FA双重验证警告的问题

如果你也收到了类似的警告信息,那就一起启用2FA吧​。 背景介绍 Github提供了四种2FA方式: AuthenticatorApp(今天要分享的就是这个)SMS/Text message: 由于SMS不支持国内手机号, 不可用Security keys: 由于该方式需要物理设备等,不好Githu…

《WebKit 技术内幕》学习之十五(6):Web前端的未来

6 Chromium OS和Chrome的Web应用 6.1 基本原理 HTML5技术已经不仅仅用来编写网页了,也可以用来实现Web应用。传统的操作系统支持本地应用,那么是否可以有专门的操作系统来支持Web应用呢?当然,现在已经有众多基于Web的操作系统&…

蓝桥杯——每日一练(简单题)

题目 153是一个非常特殊的数,它等于它的每位数字的立方和,即1531*1*15*5*53*3*3。编程求所有满足这种条件的三位十进制数。(水仙花数) 解析 一、for循环进行取值再进行判断 二、方法一使用字符串的思想进行各元素的三次方计算再…

JAVA_Set系列集合:HashSet、LinkedHashSet、TreeSet底层详解

先看看 Set 系列集合的位置: Set 系列集合的特点: 无序:存取顺序不一致 如存入张三、李四、王五。而遍历获取到的是李四, 张三, 王五 不重复:可以去除重复无索引:没有带索引的方法,所以不能使用普通for循…

mac裁剪图片

今天第一次用mac裁剪图片,记录一下过程,差点我还以为我要下载photoshop了, 首先准备好图片 裁剪的目的是把图片的标题给去掉,但是不能降低分辨率,否则直接截图就可以了 解决办法 打开原始图片(不要使用预览&#xf…

jsp项目引入apollo-并实现动态参数控制定时任务

一、基础配置&#xff1a; 1、pom引入&#xff1a; <dependency><groupId>com.ctrip.framework.apollo</groupId><artifactId>apollo-client</artifactId><version>1.8.0</version><exclusions><exclusion><artifac…

【C++杂货铺】详解类和对象 [上]

博主&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 面向对象语言的特性 &#x1f4c1; 类 &#x1f4c2; 概念 &#x1f4c2; 定义 &#x1f4c1; 访问限定符 &#x1f4c2;分类 &#x…

立创EDA/PCB使用下单助手下单

优惠券领取 首先下载嘉立创订单助手&#xff0c;在助手里面领取并使用 这里我已经领取了 打开下单助手-PCB/FPB下单 或者 上传PCB文件 下单 等待gerber就绪后&#xff0c;点击立即下单 选择该项 点击开始下单 提交订单 按规则排除错误&#xff0c;没有问题后&#x…

.NET高级面试指南专题一【委托和事件】

在C#中&#xff0c;委托&#xff08;Delegate&#xff09;和事件&#xff08;Event&#xff09;是两个重要的概念&#xff0c;它们通常用于实现事件驱动编程和回调机制。 委托定义&#xff1a; 委托是一个类&#xff0c;它定义了方法的类型&#xff0c;使得可以将方法当作另一个…

高中数学:集合

一、基本概念与关系 1、元素 2、集合 集合中元素的特性 1、确定性。2、无序性。3、互异性。 3、空集&#xff0c;用∅符号表示 4、元素与集合的关系是属于关系&#xff0c;用∈符号表示 5、集合与集合的关系是包含关系。用⊆或者⊊符号表示 子集与真子集。 A⊊B > A⊆B 反之…

windows系统中如何安装tomcat

在 Windows 系统中安装 Tomcat 通常涉及以下步骤: 1.下载 Tomcat: 访问 Apache Tomcat 官方网站。在 "Download" 部分找到适用于 Windows 的最新版本的 Tomcat。下载 Core 二进制分发版(通常是.zip文件)。 2.解压 Tomcat 压缩包: 将下载的.zip文件解压到…

Linux使用二进制包安装MySQL

目录 一、软件包下载 二、上传软件包到Linux根目录 1、使用xftp将软件包上传到根目录 2、解压缩 三、准备工作 四、初始化软件 五、设置MySQL的配置文件 六、配置启动脚本 一、软件包下载 官网下载&#xff1a;MySQL :: Download MySQL Community Server 二、上传软件…