Backtrader 文档学习-Order OCO orders
主要是可以使用订单组的管理策略,使用订单组策略,则一组订单中,有一个符合条件的订单成交,订单组中其他的订单就自动被取消。
1.概述
V1.9.36.116 版本交互式代理支持StopTrail、StopTrailLimit和OCO。
- OCO始终将组中的第一个order指定为参数OCO
- 代理模拟和IB代理具有相同的行为。指定:price作为初始停止触发价格(也指定trailamount),然后plimit作为初始限制价格。两者之间的差异将决定极限偏移量(极限价格与停止触发价格之间的距离)。
IB代理(Introducing Broker)是外汇行业中一个特殊的群体,主要充当销售角色,负责拓展外汇交易商市场并获取更多客户。
IB代理的职责是为外汇交易商拓展市场,并从交易商那里获得一定的返佣作为销售的佣金。在服务外汇平台的第三方工作人员中,也有被称为IB代理的,职责是为平台发展客户,以赚取交易者点差中的佣金为收入来源。
使用模式尽量保持用户友好,如果策略中的逻辑已决定发布订单的时候了,则可以这样使用OCO:
def next(self):...o1 = self.buy(...)...o2 = self.buy(..., oco=o1)...o3 = self.buy(..., oco=o1) # or even oco=o2, o2 is already in o1 group
第一个order o1将类似于组长。通过用oco命名参数指定o1,o2和o3成为OCO组的一部分。请注意,代码片段中的注释表明,通过指定O2(O2已经是组的一部分),o3也可以成为组的一部分。
随着order组的形成,将发生以下情况:
如果该组中的任何订单被执行、取消或过期,其他订单将被取消 。
理解:订单组中,只能有一个订单成交。
2.示例
现金额度到50000,因为资产价值达到4000,3个order,其中1给订单至少需要12000(broker的默认值为10000)
标准的SMA交叉策略,该示例执行以下操作:
- 当快速均线向上穿过慢速均线时,发出3个order
- order1是限价订单,将在限制天内到期(策略的参数),用收盘价降低1个百分点作为限价
- order2是限价订单,到期时间更长,限价更低。
- order3是更进一步降低限价的限价单
order3 is a Limit order which further reduces the limit price
因此order2和order3不会执行,因为:
- order1如首先执行,将触发其他订单的取消
或者 - order1将到期,也将触发其他订单的取消
系统保留3个订单的参考ID,只有在notify_order中显示三个ID为已完成、已取消、保证金或过期时,才会发出新的order 。
在持有某些bar的头寸后,就简单退出。
(1)程序
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,switchp1p2=False, # switch prices of order1 and order2oco1oco2=False, # False - use order1 as oco for order3, else order2do_oco=True, # use oco or not)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()def next(self):if self.orefs:return # pending orders do nothingif not self.position:if self.cross > 0.0: # crossing upp1 = self.data.close[0] * (1.0 - self.p.limit)p2 = self.data.close[0] * (1.0 - 2 * 2 * self.p.limit)p3 = self.data.close[0] * (1.0 - 3 * 3 * self.p.limit)if self.p.switchp1p2:p1, p2 = p2, p1o1 = self.buy(exectype=bt.Order.Limit, price=p1,valid=datetime.timedelta(self.p.limdays))print('{}: Oref {} / Buy at {}'.format(self.datetime.date(), o1.ref, p1))oco2 = o1 if self.p.do_oco else Noneo2 = self.buy(exectype=bt.Order.Limit, price=p2,valid=datetime.timedelta(self.p.limdays2),oco=oco2)print('{}: Oref {} / Buy at {}'.format(self.datetime.date(), o2.ref, p2))if self.p.do_oco:oco3 = o1 if not self.p.oco1oco2 else oco2else:oco3 = Noneo3 = self.buy(exectype=bt.Order.Limit, price=p3,valid=datetime.timedelta(self.p.limdays2),oco=oco3)print('{}: Oref {} / Buy at {}'.format(self.datetime.date(), o3.ref, p3))self.orefs = [o1.ref, o2.ref, o3.ref]else: # in the marketif (len(self) - self.holdstart) >= self.p.hold:self.close()def 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()
(2)oco=True
-
第一批order订单发出,order1过期,order2和order3同时取消,如前面说明的一样。
-
order1的有效期是3天,28日触发下单,30日无数据,31日order提交并接受,2月1日order1过期。
-
6月23日一批3个订单触发。订单49完成,订单50和订单51立即取消 。
python ./oco.py --broker cash=50000 --plot
2005-01-28: Oref 1 / Buy at 2941.11055
2005-01-28: Oref 2 / Buy at 2896.7722
2005-01-28: Oref 3 / Buy at 2822.87495
2005-01-31: Order ref: 1 / Type Buy / Status Submitted
2005-01-31: Order ref: 2 / Type Buy / Status Submitted
2005-01-31: Order ref: 3 / Type Buy / Status Submitted
2005-01-31: Order ref: 1 / Type Buy / Status Accepted
2005-01-31: Order ref: 2 / Type Buy / Status Accepted
2005-01-31: Order ref: 3 / Type Buy / Status Accepted
2005-02-01: Order ref: 1 / Type Buy / Status Expired
2005-02-01: Order ref: 3 / Type Buy / Status Canceled
2005-02-01: Order ref: 2 / Type Buy / Status Canceled
2005-03-03: Oref 4 / Buy at 3062.71945
2005-03-03: Oref 5 / Buy at 3016.5478000000003
2005-03-03: Oref 6 / Buy at 2939.59505
2005-03-04: Order ref: 4 / Type Buy / Status Submitted
2005-03-04: Order ref: 5 / Type Buy / Status Submitted
2005-03-04: Order ref: 6 / Type Buy / Status Submitted
2005-03-04: Order ref: 4 / Type Buy / Status Accepted
2005-03-04: Order ref: 5 / Type Buy / Status Accepted
2005-03-04: Order ref: 6 / Type Buy / Status Accepted
2005-03-07: Order ref: 4 / Type Buy / Status Expired
2005-03-07: Order ref: 6 / Type Buy / Status Canceled
2005-03-07: Order ref: 5 / Type Buy / Status Canceled
2005-03-31: Oref 7 / Buy at 3040.45135
2005-03-31: Oref 8 / Buy at 2994.6154
2005-03-31: Oref 9 / Buy at 2918.22215
... ...
2006-06-23: Oref 49 / Buy at 3532.39925
2006-06-23: Oref 50 / Buy at 3479.147
2006-06-23: Oref 51 / Buy at 3390.39325
2006-06-26: Order ref: 49 / Type Buy / Status Submitted
2006-06-26: Order ref: 50 / Type Buy / Status Submitted
2006-06-26: Order ref: 51 / Type Buy / Status Submitted
2006-06-26: Order ref: 49 / Type Buy / Status Accepted
2006-06-26: Order ref: 50 / Type Buy / Status Accepted
2006-06-26: Order ref: 51 / Type Buy / Status Accepted
2006-06-26: Order ref: 49 / Type Buy / Status Completed
2006-06-26: Order ref: 51 / Type Buy / Status Canceled
2006-06-26: Order ref: 50 / Type Buy / Status Canceled
(3)oco=False
不使用OCO的效果:
python ./oco.py --strat do_oco=False --broker cash=50000
2005-01-28: Oref 1 / Buy at 2941.11055
2005-01-28: Oref 2 / Buy at 2896.7722
2005-01-28: Oref 3 / Buy at 2822.87495
2005-01-31: Order ref: 1 / Type Buy / Status Submitted
2005-01-31: Order ref: 2 / Type Buy / Status Submitted
2005-01-31: Order ref: 3 / Type Buy / Status Submitted
2005-01-31: Order ref: 1 / Type Buy / Status Accepted
2005-01-31: Order ref: 2 / Type Buy / Status Accepted
2005-01-31: Order ref: 3 / Type Buy / Status Accepted
2005-02-01: Order ref: 1 / Type Buy / Status Expired
仅此而已,没有订单执行,也不太需要图表
The batch of orders is issued
order1过期,但是由于策略的参数do_oco=False,order2和order3不属于oco组 ,没有出现取消的状态。
Orders 2 and 3 are therefore not cancelled and because the default expiration delta is 1000 days later, they never expire with the available data for the sample (2 years of data)
order2和order3不会被取消,因为默认的到期是1000天后,它们永远不会因样本的可用数据(2年的数据)而到期 。
系统永远不能触发order2和order3。
3.Help
python ./oco.py --help
usage: oco.py [-h] [--data0 DATA0] [--fromdate FROMDATE] [--todate TODATE][--cerebro kwargs] [--broker kwargs] [--sizer kwargs][--strat kwargs] [--plot [kwargs]]Sample Skeletonoptional 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: )