Backtrader来啦:交易篇(下)

量化投资与机器学习公众号 独家撰写

公众号为全网读者带来Backtrader系列自推出第一期以来,受到了众多读者的喜爱与点赞,QIML也会继续把这个系列做好。

让那些割韭菜的课程都随风而去吧!!!

公众号将为大家多维度、多策略、多场景来讲述Backtrader在量化投资领域的实践应用。同时,我们对每段代码都做了解读说明,愿你在Quant的道路上学有所获!

预定系列

此系列将由浅入深,每期1~2周,大家敬请期待!

前言

上期,交易篇(上)重点介绍“交易条件”的设置和管理:初始资金、滑点、交易税费、成交量限制、交易时机等。今天的交易篇(下)将接着介绍交易相关的剩余内容:“交易函数”、“交易订单”、“交易执行”。对于“交易结算“, 主要在回测中可能会涉及到的使用场景就是在每笔交易发生前或发生后查询当前可用资金、总资产、持仓量、持仓成本、交易盈亏等信息,具体查询方式可以参考交易篇(上)中的资金管理和持仓查询部分的内容。

Order 中的交易订单

不同的订单类型,下单时需要配置的参数会存在区别,所以在介绍交易函数之前,先介绍 Broker 能够识别和处理的各种订单类型,这样更有利于理解交易函数中各个参数的用途。Backtrader 支持许多不同类型的交易订单,用以满足不同的交易需求,不同类型的订单的成交逻辑存在差异。

Order.Market

  • 市价单,以当时市场价格成交的订单,不需要自己设定价格。市价单能被快速达成交易,防止踏空,尽快止损/止盈;

  • 按下一个 Bar (即生成订单的那个交易日的下一个交易日)的开盘价来执行成交;

  • 例:self.buy(exectype=bt.Order.Market) 。

Order.Close

  • 和 Order.Market 类似,也是市价单,只是成交价格不一样;

  • 按下一个 Bar 的收盘价来执行成交;

  • 例:self.buy(exectype=bt.Order.Close) 。

Order.Limit

  • 限价单,需要指定成交价格,只有达到指定价格(limit Price)或有更好价格时才会执行,即以指定价或低于指点价买入,以指点价或更高指定价卖出;

  • 在订单生成后,会通过比较 limit Price 与之后 Bar 的 open\high\low\close 行情数据来判断订单是否成交。如果下一个 Bar 的 open 触及到指定价格 limit Price,就以 open 价成交,订单在这个 Bar 的开始阶段就被执行完成;如果下一个 Bar 的 open 未触及到指定价格 limit Price,但是 limit Price 位于这个 bar 的价格区间内 (即 low ~  high),就以 limit Price 成交;

  • 例:self.buy(exectype=bt.Order.Limit, price=price, valid=valid) 。

Order.Stop

  • 止损单,需要指定止损价格(Stop Price),一旦股价突破止损价格,将会以市价单的方式成交;

  • 在订单生成后,也是通过比较 Stop Price 与之后 Bar 的 open\high\low\close 行情数据来判断订单是否成交。如果下一个 Bar 的 open 触及到指定价格 limit Price,就以 open 价成交;如果下一个 Bar 的 open 未触及到指定价格 Stop Price,但是 Stop Price 位于这个 bar 的价格区间内 (即 low ~ high),就以 Stop Price 成交;

  • 例:self.buy(exectype=bt.Order.Stop, price=price, valid=valid) 。

Order.StopLimit

  • 止损限价单,需要指定止损价格(Stop price)和限价(Limit Price),一旦股价达到设置的止损价格,将以限价单的方式下单;

  • 在下一个 Bar,按 Order.Stop 的逻辑触发订单,然后以 Order.Limit 的逻辑执行订单;

  • 例:self.buy(exectype=bt.Order.StopLimit, price=price, valid=valid, plimit=plimit)。

Order.StopTrail

  • 跟踪止损订单,是一种止损价格会自动调整的止损单,调整范围通过设置止损价格和市场价格之间的差价来确定。差价即可以用金额 trailamount 表示,也可以用市价的百分比 trailpercent  表示;

  • 如果是通过 buy 下达了买入指令,就会“卖出”一个跟踪止损单,在市场价格上升时,止损价格会随之上升;若股价触及止损价格时,会以市价单的形式执行订单;若市场价格下降或保持不变,止损价格会保持不变;

  • 如果是通过 sell 下达卖出指令,就会“买入”一个跟踪止损单,在市场价格下降时,止损价格会随之下降;若股价触及止损价格时,会以市价单的形式执行订单;但是当市场价格上升时,止损价格会保持不变;

  • 例:self.buy(exectype=bt.Order.StopTrail, price=xxx, trailamount=xxx)。

Order.StopTrailLimit

  • 跟踪止损限价单,是一种止损价格会自动调整的止损限价单,订单中的限价 Limit Price 不会发生变动,止损价会发生变动,变动逻辑与上面介绍的跟踪止损订单一致;

  • 例:self.buy(exectype=bt.Order.StopTrailLimit, plimit=xxx, trailamount=xxx) 。

虽然订单的类型多种多样,但考虑到国内交易所的现状,我们在回测中使用比较多的还是市价单和限价单。

Strategy 中的交易函数

在 Strategy 的策略逻辑中,一旦满足交易条件,就会通过交易函数下达交易指令,Strategy 提供的交易函数主要分为 2 类:常规下单函数、目标下单函数,常规下单函数需要自行确定买卖方向,而目标下单函数会根据交易目标自动确定买卖方向。除此之外,如果多个订单之间有关联,还支持生成一篮子关联订单和取消关联订单。

常规下单函数

Strategy 中的常规下单函数主要有 3 个:买入 buy() 、卖出 sell()、平仓 close() ,它们的调用方式非常简单,大家也经常在案例中看到,交易函数会返回订单 Order 实例,通常会赋值给对象self.order :

class TestStrategy(bt.Strategy):
    def next(self):
        self.order = self.buy( ...) # 买入、做多 long
        self.order = self.sell(...) # 卖出、做空 short
        self.order = self.close(...) # 平仓 cover

调用的 buy、sell、close 方法中支持设置的参数有:

  • data(默认: None):用于指定给哪个数据集(即哪个证券)创建订单,默认为 None,表示给第 1 个数据集(self.datas[0] 、self.data0 对应的证券)创建订单。

  • size(默认: None):订单委托数量(正数),默认为 None,表示会自动通过 getsizer 获取 sizer 。

  • price(默认: None):订单委托价, None 表示不指定具体的委托价,而是由市场决定最终的成交价,适用于市价单;对于限价单、止损单和止损限价单,price 就是触发订单执行的那个价格 。

  • plimit(默认: None):仅适用于 StopLimit 订单,用于指定 StopLimit 订单的限价 Limit Price 为多少。

  • exectype (默认: None):执行的订单类型,None 表示按市价单执行,可选的类型有:

    • 1. Order.Market  市价单,回测时将以下一个 bar 的开盘价执行的市价单 ;

    • 2. Order.Close  市价单,回测时将以下一个 bar 的收盘价执行的市价单;

    • 3. Order.Limit  限价单;

    • 4. Order.Stop  止损单;

    • 5. Order.StopLimit  止损现价单;

    • 6. Order.StopTrail  跟踪止损订单;

    • 7. Order.StopTrailLimit  跟踪止损限价单。

  • valid(默认: None):订单有效期,可选取值有:

    • 1. None 表示订单在完成成交或被撤销之前一直都有效(aka Good till cancel or match);

    • 2. datetime实例、date 实例、数值形式的日期,表示订单在设置的 date 之前有效,date 之后会被撤销(aka good till date);

    • 3. Order.DAY 、0 、imedelta(),表示订单当日有效,未成交的订单将在当日收盘后被自动撤销(aka day order)。

  • tradeid(默认: None):当同一资产出现重复交易的时候,通知订单状态更改时,tradeid 会被传递给 Strategy。

  • **kwargs:通过传入其他参数,生成特定类型的订单 。

目标下单函数

目标下单函数包括按目标数量下单、按目标金额下单、按目标百分比下单,这些下单函数会根据设置的目标来选择买卖方向:

class TestStrategy(bt.Strategy):   def next(self):      # 按目标数量下单      self.order = self.order_target_size(target=size)      # 按目标金额下单      self.order = self.order_target_value(target=value)      # 按目标百分比下单      self.order = self.order_target_percent(target=percent)
  • order_target_size:按目标数量下单,按“多退少补”的原则,让证券的持仓数量等于设定的目标数量 target :

    • 如果目标数量 target 大于当前持仓数量,则会发出买入订单,补足持仓量,例如:

      • 当前持仓量 size=0, 目标持仓量 target=7 -> 买入订单,买入数量 size=7-0=7;

      • 当前持仓量 size=3, 目标持仓量 target=7 -> 买入订单,买入数量 size=7-3=4;

      • 当前持仓量 size=-3, 目标持仓量 target=7 -> 买入订单,买入数量 size=7-(-3)=10。

    • 如果目标数量 target 小于当前持仓数量,则会发出卖出订单,减少持仓量,例如:

      • 当前持仓量 size=0,目标持仓量 target=-7 -> 卖出订单,卖出数量 size=0-(-7)=7;

      • 当前持仓量 size=3, 目标持仓量 target=-7 -> 卖出订单,卖出数量 size=3-(-7)=10;

      • 当前持仓量 size=-3, 目标持仓量 target=-7 -> 卖出订单,卖出数量 size=-3-(-7)=4。

  • order_target_value:按目标金额下单,通过比较目标金额与当前持仓额和持仓方向,确定最终买卖买卖方向:(持仓量默认使用当前 Bar 的 close 进行计算,然后以下一根 bar 的开盘价进行交易)

    • 如果当前持有的是空单(size<0):

      • 若目标金额 target > 当前持仓额 ->  卖出;

      • 若目标金额 target < 当前持仓额 -> 买入。

    • 如果当前无持仓或持有的是多单(size>=0):

      • 若目标金额 target > 当前持仓额 ->  买入;

      • 若目标金额 target < 当前持仓额 ->  卖出。

  • order_target_percent:按目标百分比下单,订单生成逻辑同 order_target_value,目标金额 = 目标百分比 * 当前账户的总资产。

取消订单

交易函数用于生成订单,返回 Order 对象,如果想要取消生成的订单,就可以通过 cancel() 方法来取消:

  • 通过 cancel() 来取消订单 :self.cancel(order);

  • 通过 Broker 来取消订单 :self.broker.cancel(order) 。

订单组合

注:这里的订单组合并不是同时对多个标的进行交易,而是对某一笔交易同时发出多个指令,以满足在不同市场情况时触发对应的指令。

前面介绍的交易函数生成的都是单个订单,而且订单之间并没有什么联系,而此处介绍的交易函数 buy_bracket() 和 sell_bracket() 会一次性生成 3 个自定义类型的订单:主订单 main order、针对主订单的止损单 stop order、针对主订单的止盈单 limit order 。

buy_bracket()

buy_bracket() 用于long side 的交易场景,买入证券后,在价格下跌时,希望通过止损单卖出证券,限制损失;在价格上升时,希望通过限价单卖出证券,及时获利,通过 buy_bracket() 可以同时提交上述 3 个订单,而无需繁琐的调用 3 次常规交易函数。

# 函数可用参数
buy_bracket(# 主订单的参数
            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):......

# 调用示例
brackets = self.buy_bracket(price=13.50,
                            limitprice=14.00,
                            stopprice=13.00)
# 主订单以 13.5 的价格买入 self.data0 数据集对应的标的
# 当价格超过 14.00 时,会触发止盈单,卖出标的
# 当价格跌破 13.00 时,会触发止损单,卖出标的

从 buy_bracket 的可用参数可知:

  • data=None,默认是对 data0 数据集对应的证券标的进行交易;

  • 主订单:为买入单,默认为 Order.Limit  限价单,可通过参数 price 设定成交价,也可通过参数  plimit 设置指定价 limit;主订单通常设置为 Order.Limit  限价单 或 Order.StopLimit 止损限价单;

  • 止损单:为卖出单,用于及时止损,默认为 Order.Stop 止损单,可通过参数 stopprice 设置止损价,参数 stopargs 中还可设置止损单相关的其他参数;

  • 止盈单:为卖出单,用于及时止盈,默认为 Order.Limit 限价单,可通过参数 limitprice 设置指定价格,参数 limitargs 中还可设置限价单相关的其他参数。

sell_bracket()

sell_bracket() 用于short side 的交易场景,卖出证券做空后,在价格上升时,希望通过止损单买入证券,限制损失;在价格下降时,希望通过限价单买入证券,及时获利,sell_bracket() 也是一次同时提交上述 3 个订单 。

# 函数可用参数sell_bracket(# 主订单设置             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):

# 调用示例brackets = self.sell_bracket(price=13.50,                             limitprice=13.00,                             stopprice=14.00)# 主订单以 13.5 的价格卖出 self.data0 数据集对应的标的# 当价格跌破 13.00 时,会触发止盈单,买入标的,获得套利收益# 当价格超过 14.00 时,会触发止损单,买入标的,及时止损

sell_bracket 的可用参数与 buy_bracket 的类似,只是 sell_bracket 中的主订单为 卖出单、止损单和止盈单为 买入单。

执行逻辑

一篮子订单中的三个订单是一块提交的,但执行顺序有主有次、有先有后:

  • 只当在主订单执行后,止损单和止盈单才会被激活,而且是同时激活;

  • 如果主订单被取消,止盈单和止损单也会被取消;

  • 在止盈单和止损单激活之后,如果取消两者中的任意一个,那另外一个也会被取消。

OCO订单

OCO 是“aka One Cancel Others”的缩写,OCO 针对的是多个相互关联的订单,一个订单的执行、取消或到期(对应的订单状态有:Completed、Cancelled、Margin、Expired),就会自动取消其他与其相关联的订单。可以将 OCO 看做是订单的属性或特征,通过下单函数中的“oco”参数来设置,例如:

# 案例1
def next(self):
   ...
   o1 = self.buy(...)
   ...
   o2 = self.buy(..., oco=o1)
   ...
   o3 = self.buy(..., oco=o1)

# 案例 2
def next(self):
   ...
   o1 = self.buy(...)
   ...
   o2 = self.buy(..., oco=o1)
   ...
   o3 = self.buy(..., oco=o2)

  • 案例 1 中,生成的 o1 与 o2 是一组关联订单,其中 o1 是主订单,它的执行情况将会决定 o2 的生死存亡,如果 o1 被执行、取消或到期,就会自动取消订单 o2; o1 与 o3 也是一组关联订单,情况与o1 - o2 组类似;

  • 案例 2 中,订单 o1 关联着订单 o2,订单 o2 关联着订单 o3,虽然是 2 组关联订单,实质上o1、o2、o3 是一组订单,因为 o1 以 o2 为媒介,影响 o2 的同时,也影响了 o3 。

Broker 中的交易执行

Broker 在执行交易时,会根据执行流程给订单赋予不同的状态,不同阶段的订单状态可以通过Strategy 中定义 notify_order() 方法来捕获,从而进行自定义的处理,从下达交易指令到订单执行结束,订单可能会依次呈现如下状态:

  • Order.Created:订单已被创建;
  • Order.Submitted:订单已被传递给经纪商 Broker;
  • Order.Accepted:订单已被经纪商接收;
  • Order.Partial:订单已被部分成交;
  • Order.Complete:订单已成交;
  • Order.Rejected:订单已被经纪商拒绝;
  • Order.Margin:执行该订单需要追加保证金,并且先前接受的订单已从系统中删除;
  • Order.Cancelled (or Order.Canceled):确认订单已经被撤销;
  • Order.Expired:订单已到期,其已经从系统中删除 。

上述状态的排列顺序依次为:

['Created'、'Submitted'、'Accepted'、'Partial'、'Completed'、'Canceled'、'Expired'、'Margin'、'Rejected'],而 order.status 的取值对应上述专题的位置索引,如order.status==4,对应 'Completed' 状态 。

总结

Backtrader《交易篇》到此就介绍完了~ 大家实际应用中,可以结合策略需求,设置相应的“交易条件”;下单时,根据所需的订单执行逻辑,确定订单类型,然后选择相应的“交易函数”,配置该类订单所需的参数;当然,也可以通过 notify 函数追踪订单状态和订单信息。

(0)

相关推荐

  • (9条消息) backtrader量化平台教程(二)第一个可用的策略

    第一个可用的策略 指数基金的收益率怎么样? 写一个实用的策略,验证指数基金的收益情况. 获取回测数据 我们从证券宝baostock免费获取中证500(000905)指数数据. 这里我们写了一个工具ge ...

  • python模拟登陆之下载

    好长时间没有更新博客了,哈哈. 今天公司给了这么一个需求,现在我们需要去淘宝获取上一天的订单号,然后再根据订单号去另一个接口去获取订单详情,然后再给我展示到web! 中间涉及到的技术点有: 模拟登陆 ...

  • (9条消息) Backtrader量化平台教程

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040) 无意中发现了一个巨牛的人工智能教程,忍不住分享一下给 ...

  • 什么是条件交易?

    条件交易即美股标准订单中的止损/止盈限价单,需要输入一个固定的止损/止盈价格(触发价):一旦达到触发价,将会以设置的订单价格和数量发送到市场上(相当于自动提交一个美股限价单) [可下单时间]任何时间 ...

  • 「手把手教你」入门量化回测最强神器backtrader(三)

    「手把手教你」入门量化回测最强神器backtrader(三)

  • (9条消息) Backtrader量化平台教程(四)SSA策略实际案例

    AD:(本人录制的backtrader视频课程,大家多多支持哦~ https://edu.csdn.net/course/detail/9040) 无意中发现了一个巨牛的人工智能教程,忍不住分享一下给 ...

  • 水浒精灵传——梁山108将前世...地煞篇 下

    72位地煞星 「地煞星」七十二员: (二) 地隐星 转世白花蛇杨春 地异星 转世白面郎君郑天寿 地理星 转世九尾龟陶宗旺 地俊星 转世铁扇子宋清 地乐星 转世铁叫子乐和 地捷星 转世花项虎龚旺 地速星 ...

  • 肥料知识大全(完整篇下),建议收藏

    肥料购买.储藏和真假鉴别 45.什么叫做最小养分律? 最小养分率是德国化学家李比西提出来的.他曾说过:如果土壤中某一种必需养分不足,或者缺乏的时候,即使其他养分都存在,这种土壤仍将成为不毛之地.也就是 ...

  • 主流SCI期刊点评(10)(细胞生物学篇-下)

    近十年来Cell Press和NPG集团频发新刊,分流了大量的稿源,因此很多老牌杂志的日子都不太好过.本篇将特别介绍细胞生物学领域的两个老牌期刊,虽然其影响因子都已经江河日下,但"瘦死的骆驼 ...

  • 168-170(太阳篇下)

    168.附子泻心汤 再过来呢,一百七十条.心下痞,胃里面痞,而复恶寒,胃里面很难过,但是有点,又怕冷,胃寒掉了.汗出者,这个时候哈,病人只要,记得哈,只要病人说恶寒,怕冷,那有流汗,这就代表,告诉诸位 ...

  • 《范金琢玉——耀州窑历代陶瓷精品展》北宋篇下

    <范金琢玉--耀州窑历代陶瓷精品展>北宋篇下 佳展回顾 耀州窑是我国历史名窑之一,以烧造青瓷闻名于世,被誉为中国古代北方青瓷的代表.窑场以陕西省铜川市黄堡镇"十里窑场" ...

  • 132-135(太阳篇下)

    三.辨太阳病脉证并治法下篇  132.太阳病误吐伤中胃冷的变证 <上篇>.<中篇>呢,基本上,原则是发表,然后再攻里,还有发表尽量要用药,不要用其他的方式哈.不要自己去想出来. ...

  • TI 视界|欧易 OKEx: 统一交易账户下的投资组合策略

    要点总结 数字资产市场已经逐渐走向成熟,以期货.期权为代表的数字资产衍生品市场已经具备相应的规模.投资者可以建立多品种的投资策略实现对冲市场风险.构建投资组合需要不同种类衍生品的相互配合,全面的保证金 ...

  • 投资、投机、赌博、交易(下)

    多年以来,习惯了人们将在金融市场中的投机行为称作是赌博,即便是那些普通人一般称其为投资的股票买卖行为,在一轮股市大的翻转下跌以后,也同样不能幸免的经常会被盖上赌博的帽子,对此早已司空见惯.究其就里,不 ...

  • 家装必备干货-热水器选购指南(电热篇·下)

    上篇说到电热选购需要关注的两个关键点,即加热方式和水箱容量,但这只是满足了我们最基本的洗浴需求.那下篇我们就来聊一下其他几个需要各位关注以便进行综合考量的功能卖点. 三.安全防护 电热水器是靠电加热的 ...