Python量化交易学习笔记(28)——backtrader的Limit订单

本文将继续对backtrader的order进行介绍,具体介绍Limit订单的使用。

选取平安银行(000001)2019年1月1日至2019年12月31日的日线数据进行回测。为了便于分析,回测过程中设置佣金为0,交易单位大小为100。

执行规则

在Limit订单创建时,会设置一个pricevalid时间,如果超过valid时间订单仍未满足执行条件,订单就会过期被取消。在valid时间内,订单会按照下面描述的价格匹配规则判断订单是否会成交。

价格匹配

Limit订单使用K线4个价格点(Open/High/Low/Close)来推断是否有比price更优的成交价格。

  • 对于买单
  1. 如果某根K线的open低于设定的price,则以open值成交。订单在这根K线的开始阶段就被执行完成。
  2. 如果某根K线的open高于设定的price,但是low低于price,也就是price在这根K线的范围内,那么订单将以price值成交。
  • 对于卖单
  1. 如果某根K线的open值高于设定的price,则以open值成交。订单在这根K线的开始阶段就被执行完成。
  2. 如果某根K线的open值低于设定的price,但是high高于price,也就是price在这根K线的范围内,那么订单将以price值成交。

示例

策略:

  • 买入条件:收盘价高于15日均线,价格在4日内,较收盘价下跌0.5%时买入
  • 卖出条件:收盘价低于15日均线,价格在4日内,较收盘价上涨0.5%时卖出
        # 检查是否持仓
        if self.position:
            # 检查是否达到卖出条件
            if self.buysell < 0:
                if self.p.valid:
                    valid = self.data.datetime.date(0) + \
                            datetime.timedelta(days=self.p.valid)
                else:
                    valid = None
                ...
                elif self.p.exectype == 'Limit':
                    price = self.data.close * (1.0 + self.p.perc1 / 100.0)
                    self.sell(exectype=bt.Order.Limit, price=price, valid=valid)
                    if self.p.valid:
                        txt = 'SELL CREATE, exectype Limit, close %.2f, price %.2f, valid: %s'
                        self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
                    else:
                        txt = 'SELL CREATE, exectype Limit, close %.2f, price %.2f'
                        self.log(txt % (self.data.close[0], price))
				...

        # 不在场内且出现买入信号        
        elif self.buysell > 0: 
            if self.p.valid:
                valid = self.data.datetime.date(0) + \
                        datetime.timedelta(days=self.p.valid)
            else:
                valid = None
            ...
            elif self.p.exectype == 'Limit':
                price = self.data.close * (1.0 - self.p.perc1 / 100.0)
                self.buy(exectype=bt.Order.Limit, price=price, valid=valid)
                if self.p.valid:
                    txt = 'BUY CREATE, exectype Limit, close %.2f, price %.2f, valid: %s'
                    self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
                else:
                    txt = 'BUY CREATE, exectype Limit, close %.2f, price %.2f'
                    self.log(txt % (self.data.close[0], price))

为了说明Limit订单可能出现的所有成交情况,在代码中使用p.perc1 = 0.5,来控制价格回撤的比例,使用p.valid = 4,来控制订单的有效期。

先来分析买单的3种情况:

1. 过期取消

将图表显示时间范围调整为2019年8月,输出图形如下:
在这里插入图片描述
上图中,红色的曲线表示15日均线。

部分输出结果为:

2019-08-08, BUY CREATE, exectype Limit, close 14.38, price 14.31, valid: 2019-08-12
2019-08-09, ORDER SUBMITTED
2019-08-09, ORDER ACCEPTED
2019-08-09, Open: 14.55, High: 14.85, Low: 14.43, Close: 14.52
2019-08-12, Open: 14.61, High: 15.12, Low: 14.60, Close: 15.12
2019-08-12, BUY EXPIRED

下面结合输出打印结果及图形进行分析。

(1) 8月8日,收盘价高于15日均线,达到了买入条件,创建Limit买单,当日收盘价为14.38,设定回踩0.5%后的价位为14.31,p.valid = 4,有效期valid至8月12日。若在截止日前价位能够达到price值14.31,订单就会成交,否则订单就会过期。

(2) 8月9日,收到买单提交通知。(8日创建的订单,在9日收到订单状态通知,是因为notify_order方法会在Strategy的next方法前被调用,即在8日的next方法中创建了买单,在9日的notify_order方法中通知订单被提交、接受。)

(3) 8月9日,收到买单接受通知。

(4) 8月9日,最低价14.43,最高价14.85,未达到设定price值14.31,因此订单未成交。

(5) 8月12日,最低价14.60,最高价15.12,未达到设定price值14.31,因此订单未成交。

(6) 8月12日,收到订单过期通知。8月12日为Limit订单设定的截止日期valid,订单未成交并过期。这里注意到,10日和11日为周末,A股没有开市,因此通过p.valid(这里为4天)设置的有效期为自然日,而非交易日。

2. 以开盘价成交

将图表显示时间范围调整为2019年7月,输出图形如下:
在这里插入图片描述

部分输出结果为:

2019-07-12, BUY CREATE, exectype Limit, close 14.12, price 14.05, valid: 2019-07-16
2019-07-15, ORDER SUBMITTED
2019-07-15, ORDER ACCEPTED
2019-07-15, Open: 14.03, High: 14.12, Low: 13.84, Close: 14.00
2019-07-15, BUY EXECUTED, Price: 14.03, Cost: 1403.00.

下面结合输出打印结果及图形进行分析。

(1) 7月12日,收盘价高于15日均线,达到了买入条件,创建Limit买单,当日收盘价为14.12,设定回踩0.5%后的价位为14.05,p.valid = 4,有效期valid至7月16日。若在截止日前价位能够达到price值14.05,订单就会成交,否则订单就会过期。

(2) 7月15日(13日和14日为周末),收到买单提交通知。

(3) 7月15日,收到买单接受通知。

(4) 7月15日,开盘价为14.03,低于了设定price值14.05,满足了买单价格匹配的规则1,将以开盘价成交。

(5) 7月15日,Limit买单以开盘价14.03成交。

3. 以设定的price成交

将图表显示时间范围调整为2019年3月,输出图形如下:
在这里插入图片描述
部分输出结果为:

2019-03-18, BUY CREATE, exectype Limit, close 12.91, price 12.85, valid: 2019-03-22
2019-03-19, ORDER SUBMITTED
2019-03-19, ORDER ACCEPTED
2019-03-19, Open: 12.92, High: 12.94, Low: 12.61, Close: 12.79
2019-03-19, BUY EXECUTED, Price: 12.85, Cost: 1284.55.

下面结合输出打印结果及图形进行分析。

(1) 3月18日,收盘价高于15日均线,达到了买入条件,创建Limit买单,当日收盘价为12.91,设定回踩0.5%后的价位为12.85,p.valid = 4,有效期valid至3月22日。若在截止日前价位能够达到price值12.85,订单就会成交,否则订单就会过期。

(2) 3月19日,收到买单提交通知。

(3) 3月19日,收到买单接受通知。

(4) 3月19日,开盘价为12.92,高于设定的price值12.85,不满足买单价格匹配的规则1;但是最低价为12.61,低于设定的price值12.85,满足买单价格匹配的规则2,因此将以设定的price值成交。

(5) 3月19日,Limit买单以设定的price值12.85成交。

再来分析卖单的3种情况:

1. 过期取消

将图表显示时间范围调整为2019年11月,输出图形如下:
在这里插入图片描述
部分输出结果为:

2019-11-08, SELL CREATE, exectype Limit, close 16.65, price 16.73, valid: 2019-11-12
2019-11-11, ORDER SUBMITTED
2019-11-11, ORDER ACCEPTED
2019-11-11, Open: 16.50, High: 16.53, Low: 16.20, Close: 16.28
2019-11-12, Open: 16.29, High: 16.37, Low: 16.16, Close: 16.33
2019-11-12, SELL EXPIRED

下面结合输出打印结果及图形进行分析。

(1) 11月8日,收盘价低于15日均线,达到了卖出条件,创建Limit卖单,当日收盘价为16.65,设定反抽0.5%后的价位为16.73,p.valid = 4,有效期valid至11月12日。若在截止日前价位能够达到price值14.73,订单就会成交,否则订单就会过期。

(2) 11月11日(9日和10日为周末),收到卖单提交通知。

(3) 11月11日,收到卖单接受通知。

(4) 11月11日,最低价16.20,最高价16.53,未达到设定price值16.73,因此订单未成交。

(5) 11月12日,最低价16.16,最高价16.37,未达到设定price值16.73,因此订单未成交。

(6) 11月12日,收到订单过期通知。11月12日为Limit订单设定的截止日期valid,订单未成交并过期。

2. 以开盘价成交

将图表显示时间范围调整为2019年7月,输出图形如下:
在这里插入图片描述
部分输出结果为:

2019-07-23, SELL CREATE, exectype Limit, close 13.76, price 13.83, valid: 2019-07-27
2019-07-24, ORDER SUBMITTED
2019-07-24, ORDER ACCEPTED
2019-07-24, Open: 13.87, High: 14.01, Low: 13.79, Close: 13.88
2019-07-24, SELL EXECUTED, Price: 13.87, Cost: 1392.00.

下面结合输出打印结果及图形进行分析。

(1) 7月23日,收盘价低于15日均线,达到了卖出条件,创建Limit卖单,当日收盘价为13.76,设定反抽0.5%后的价位为13.83,p.valid = 4,有效期valid至7月27日。若在截止日前价位能够达到price值13.83,订单就会成交,否则订单就会过期。

(2) 7月24日,收到卖单提交通知。

(3) 7月24日,收到卖单接受通知。

(4) 7月24日,开盘价为13.87,高于了设定price值13.83,满足了卖单价格匹配的规则1,将以开盘价成交。

(5) 7月24日,Limit卖单以开盘价13.87成交。

3. 以设定的price成交

将图表显示时间范围调整为2019年7月,输出图形如下:
在这里插入图片描述
部分输出结果为:

2019-07-16, SELL CREATE, exectype Limit, close 13.75, price 13.82, valid: 2019-07-20
2019-07-17, ORDER SUBMITTED
2019-07-17, ORDER ACCEPTED
2019-07-17, Open: 13.70, High: 13.81, Low: 13.61, Close: 13.69
2019-07-18, Open: 13.65, High: 13.81, Low: 13.56, Close: 13.67
2019-07-19, Open: 13.74, High: 14.08, Low: 13.68, Close: 13.99
2019-07-19, SELL EXECUTED, Price: 13.82, Cost: 1403.00.

下面结合输出打印结果及图形进行分析。

(1) 7月16日,收盘价低于15日均线,达到了卖出条件,创建Limit卖单,当日收盘价为13.75,设定反抽0.5%后的价位为13.82,p.valid = 4,有效期valid至7月20日。若在截止日前价位能够达到price值13.82,订单就会成交,否则订单就会过期。

(2) 7月17日,收到卖单提交通知。

(3) 7月17日,收到卖单接受通知。

(4) 7月17日,最低价13.61,最高价13.81,未达到设定price值13.82,因此订单未成交。

(5) 7月18日,最低价13.56,最高价13.81,未达到设定price值13.82,因此订单未成交。

(6) 7月19日,开盘价为13.74,低于设定的price值13.82,不满足卖单价格匹配的规则1;但是最高价为14.08,高于设定的price值13.82,满足卖单价格匹配的规则2,因此将以设定的price值成交。

(7) 7月19日,Limit卖单以设定的price值13.82成交。

至此,通过示例展示了Limit订单所有可能出现的情况。在示例中,使用的是A股数据,但是A股只允许做多,所以在卖单时使用Limit订单看似不太合理,会出现Limit卖单过期而被套牢的情况。

鉴于Limit订单的定位是,在给定有效期内,以给定的价位或者更好的价位成交,因此Limit订单较适合于开仓操作,在平仓时要慎用Limit订单。


博客内容只用于交流学习,不构成投资建议,盈亏自负!

个人博客:http://coderx.com.cn/(优先更新)
项目最新代码:https://gitee.com/sl/quant_from_scratch
欢迎大家转发、留言。有微信群用于学习交流,感兴趣的读者请扫码加微信!
如果认为博客对您有帮助,可以扫码进行捐赠,感谢!

微信二维码微信捐赠二维码
在这里插入图片描述在这里插入图片描述
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值