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

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

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

执行规则

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

价格匹配

Stop订单使用K线4个价格点(Open/High/Low/Close)来判断是否有效突破设定的price值。

  • 对于买单
  1. 如果某根K线的open高于设定的price,则立刻以open值成交。对于空头来说,若已持有做空的仓位,价格较设定的price持续走高,这时要及时平仓止损(stop a loss),因此这类订单成为Stop订单。
  2. 如果某根K线的open低于设定的price,但是high高于price,也就是price在这根K线的范围内,那么订单将以price值成交。
  • 对于卖单
  1. 如果某根K线的open值低于设定的price,则以open值成交。
  2. 如果某根K线的open值高于设定的price,但是low低于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 == 'Stop':
                    price = self.data.close * (1.0 - self.p.perc1 / 100.0)
                    self.sell(exectype=bt.Order.Stop, price=price, valid=valid)
                    if self.p.valid:
                        txt = 'SELL CREATE, exectype Stop, close %.2f, price %.2f, valid: %s'
                        self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
                    else:
                        txt = 'SELL CREATE, exectype Stop, 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 == 'Stop':
                price = self.data.close * (1.0 + self.p.perc1 / 100.0)
                self.buy(exectype=bt.Order.Stop, price=price, valid=valid)
                if self.p.valid:
                    txt = 'BUY CREATE, exectype Stop, close %.2f, price %.2f, valid: %s'
                    self.log(txt % (self.data.close[0], price, valid.strftime('%Y-%m-%d')))
                else:
                    txt = 'BUY CREATE, exectype Stop, close %.2f, price %.2f'
                    self.log(txt % (self.data.close[0], price))

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

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

1. 过期取消

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

部分输出结果为:

2019-03-18, BUY CREATE, exectype Stop, close 12.91, price 12.97, 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-20, Open: 12.68, High: 12.88, Low: 12.62, Close: 12.75
2019-03-21, Open: 12.77, High: 12.80, Low: 12.58, Close: 12.69
2019-03-22, Open: 12.69, High: 12.74, Low: 12.50, Close: 12.59
2019-03-22, BUY EXPIRED

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

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

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

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

(4) 3月19日,最低价12.61,最高价12.94,未达到设定price值12.97,因此订单未成交。

(5) 3月20日,最低价12.62,最高价12.88,未达到设定price值12.97,因此订单未成交。

(6) 3月21日,最低价12.58,最高价12.80,未达到设定price值12.97,因此订单未成交。

(7) 3月22日,最低价12.50,最高价12.74,未达到设定price值12.97,因此订单未成交。

(8) 3月22日,收到订单过期通知。3月22日为Stop订单设定的截止日期valid,订单未成交并过期。

2. 以开盘价成交

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

部分输出结果为:

2019-09-05, BUY CREATE, exectype Stop, close 14.58, price 14.65, valid: 2019-09-09
2019-09-06, ORDER SUBMITTED
2019-09-06, ORDER ACCEPTED
2019-09-06, Open: 14.71, High: 14.81, Low: 14.62, Close: 14.81
2019-09-06, BUY EXECUTED, Price: 14.71, Cost: 1471.00.

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

(1) 9月5日,收盘价高于15日均线,达到了买入条件,创建Stop买单,当日收盘价为14.58,设定上涨突破0.5%后的价位为14.65,p.valid = 4,有效期valid至9月9日。若在截止日期前价位能够达到price值14.65,订单就会成交,否则订单就会过期。

(2) 9月6日,收到买单提交通知。

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

(4) 9月6日,开盘价为14.71,高于了设定price值14.65,满足了买单价格匹配的规则1,将以开盘价成交。

(5) 9月6日,Stop买单以开盘价14.71成交。

3. 以设定的price成交

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

2019-06-10, BUY CREATE, exectype Stop, close 12.34, price 12.40, valid: 2019-06-14
2019-06-11, ORDER SUBMITTED
2019-06-11, ORDER ACCEPTED
2019-06-11, Open: 12.34, High: 12.72, Low: 12.30, Close: 12.65
2019-06-11, BUY EXECUTED, Price: 12.40, Cost: 1240.17.

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

(1) 6月10日,收盘价高于15日均线,达到了买入条件,创建Stop买单,当日收盘价为12.34,设定上涨突破0.5%后的价位为12.40,p.valid = 4,有效期valid至6月14日。若在截止日期前价位能够达到price值12.40,订单就会成交,否则订单就会过期。

(2) 6月11日,收到买单提交通知。

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

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

(5) 6月11日,Stop买单以设定的price值12.40成交。

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

1. 过期取消

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

2019-09-17, SELL CREATE, exectype Stop, close 14.24, price 14.17, valid: 2019-09-21
2019-09-18, ORDER SUBMITTED
2019-09-18, ORDER ACCEPTED
2019-09-18, Open: 14.24, High: 14.48, Low: 14.24, Close: 14.41
2019-09-19, Open: 14.48, High: 14.89, Low: 14.48, Close: 14.84
2019-09-20, Open: 14.95, High: 15.40, Low: 14.93, Close: 15.34
2019-09-23, Open: 15.34, High: 15.47, Low: 15.18, Close: 15.38
2019-09-23, SELL EXPIRED

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

(1) 9月17日,收盘价低于15日均线,达到了卖出条件,创建Stop卖单,当日收盘价为14.24,设定向下跌破0.5%后的价位为14.17,p.valid = 4,有效期valid至9月21日。若在截止日期前价位能够达到price值14.17,订单就会成交,否则订单就会过期。

(2) 9月18日,收到卖单提交通知。

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

(4) 9月18日,最低价14.24,最高价14.48,未达到设定price值14.17,因此订单未成交。

(5) 9月19日,最低价14.48,最高价14.89,未达到设定price值14.17,因此订单未成交。

(6) 9月20日,最低价14.93,最高价15.40,未达到设定price值14.17,因此订单未成交。

(7) 9月23日(21日和22日为周末),最低价15.18,最高价15.47,未达到设定price值14.17。

(8) 9月23日,收到订单过期通知。9月21日为Stop订单设定的截止日期valid,订单未成交并过期。经测试,这里即使23日的价格范围达到的设定price值14.17,订单也会过期。即,若截止日期当日未开市,则在后续开市日期内,即使满足了价格匹配规则,订单也会过期失效。

2. 以开盘价成交

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

2019-08-02, SELL CREATE, exectype Stop, close 13.74, price 13.67, valid: 2019-08-06
2019-08-05, ORDER SUBMITTED
2019-08-05, ORDER ACCEPTED
2019-08-05, Open: 13.60, High: 13.64, Low: 13.27, Close: 13.35
2019-08-05, SELL EXECUTED, Price: 13.60, Cost: 1394.94.

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

(1) 8月2日,收盘价低于15日均线,达到了卖出条件,创建Stop卖单,当日收盘价为13.74,设定向下跌破0.5%后的价位为13.67,p.valid = 4,有效期valid至8月6日。若在截止日期前价位能够达到price值13.67,订单就会成交,否则订单就会过期。

(2) 8月5日(3日和4日为周末),收到卖单提交通知。

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

(4) 8月5日,开盘价为13.60,低于了设定price值13.67,满足了卖单价格匹配的规则1,将以开盘价成交。

(5) 8月5日,Stop卖单以开盘价13.60成交。

3. 以设定的price成交

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

2019-07-08, SELL CREATE, exectype Stop, close 13.59, price 13.52, valid: 2019-07-12
2019-07-09, ORDER SUBMITTED
2019-07-09, ORDER ACCEPTED
2019-07-09, Open: 13.63, High: 13.71, Low: 13.44, Close: 13.59
2019-07-09, SELL EXECUTED, Price: 13.52, Cost: 1240.17.

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

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

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

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

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

(5) 7月9日,Stop卖单以设定的price值13.52成交。

至此,通过示例展示了Stop订单所有可能出现的情况。

Stop订单的用法可以总结为:突破关键点开仓,跌破关键点平仓。

为了便于相互交流学习,新建了微信群,感兴趣的读者请加微信。
在这里插入图片描述

Guess you like

Origin blog.csdn.net/m0_46603114/article/details/106148701