Python量化交易学习笔记(19)——连续下跌买入止盈止损卖出策略

Hedva ·
更新时间:2024-09-21
· 924 次阅读

好友提出要验证连续下跌买入止盈止损卖出策略,本文对该策略回测和实现做分析记录。

买入条件中,连续下跌定义为收盘价连续4日低于前1日的收盘价。卖出条件中,止盈率设置为10%,止损率设置为5%。回测初始资金100000元,单笔操作单位1000股,佣金千分之一,回测时间自2018年1月1日至2020年3月20日。

策略核心代码位于策略类的next方法中:

def next(self): if self.orefs: # order列表,用于存储尚未执行完成的订单 return # 有尚未执行的订单 # 尚未进场 if not self.position: # 获取近几日收盘价用于判断是否连续下跌 lastcloses = list() for i in range(self.p.p_downdays + 1): lastcloses.append(self.dataclose[-i]) # 连续N日下跌 if lastcloses == sorted(lastcloses): # 计算买入报价跑p1,止损价p2,止盈价p3 close = self.dataclose[0] p1 = close * (1.0 - self.p.limit) p2 = p1 - self.p.p_stoploss * close p3 = p1 + self.p.p_takeprofit * close # 计算订单有效期 valid1 = datetime.timedelta(self.p.limdays) valid2 = valid3 = datetime.timedelta(self.p.limdays2) # 使用bracket orders设置买入卖出 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]

这里主要应用了backtrader的bracket order,它其实并不是1个订单,而是有3个订单构成:1个买单,1个止损卖单,1个止盈卖单。2个卖单就像是把买单用括号括起来一样,因此合称为bracket order(括号订单)。我们所使用的buy_bracket方法遵循以下规则:

为了避免被分开执行,3个订单要被一起提交 2个卖单要作为买单的子订单 在买单执行前,2个卖单处于非激活状态 买单如果被取消,2个卖单也会随之被取消 买单被执行后,2个卖单均被激活 一旦两个卖单被激活,其中一个被执行或者被取消,另一个都将被自动取消。

buy_bracket方法中除了设置买入价、止损价、止盈价外,还设置了订单有效时间,如果订单在有效时间内未执行,则会过期失效。一般我们将买入有效期设置为3天以内,卖出有效期设置为较长时间,以保证股票可以卖出。

回测000001后的最终资产为102781.90元,这里交易大小仅为1000股,所用资金仅为不到20000元,提高交易量,收益还是相当可观。

在这里插入图片描述

回测000002后的最终资产为96476.14元,亏损。

在这里插入图片描述

回测601318后的最终资产为75044.50元,亏得一塌糊涂。

在这里插入图片描述
观察几张图标可以发现,我们经常可以找到很好的买点,但是会出现本来盈利的订单,最后变成亏损的情况。在挖backtrader文档的时候,发现了一个比较好的利润保护方法,将在下一篇文章中进行实现及分析,敬请期待。

友情提示:本系列学习笔记只做数据分析,记录个人学习过程,不作为交易依据,盈亏自负。

连续下跌买入止盈止损卖出策略代码:

from __future__ import (absolute_import, division, print_function, unicode_literals) import datetime # 用于datetime对象操作 import os.path # 用于管理路径 import sys # 用于在argvTo[0]中找到脚本名称 import backtrader as bt # 引入backtrader框架 # 创建策略 class St(bt.Strategy): params = dict( p_downdays = 4, # 连续下跌天数 p_stoploss = 0.05, # 止损比例 p_takeprofit = 0.1, # 止盈比例 limit=0.005, limdays=3, limdays2=1000, hold=10, usebracket=False, # use order_target_size switchp1p2=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): # 引用data[0]数据的收盘价数据 self.dataclose = self.datas[0].close sma = bt.ind.SMA(period = self.p.p_downdays + 1, plot = False) self.orefs = list() def next(self): if self.orefs: # order列表,用于存储尚未执行完成的订单 return # 有尚未执行的订单 # 尚未进场 if not self.position: # 获取近几日收盘价用于判断是否连续下跌 lastcloses = list() for i in range(self.p.p_downdays + 1): lastcloses.append(self.dataclose[-i]) # 连续N日下跌 if lastcloses == sorted(lastcloses): # 计算买入报价跑p1,止损价p2,止盈价p3 close = self.dataclose[0] p1 = close * (1.0 - self.p.limit) p2 = p1 - self.p.p_stoploss * close p3 = p1 + self.p.p_takeprofit * close # 计算订单有效期 valid1 = datetime.timedelta(self.p.limdays) valid2 = valid3 = datetime.timedelta(self.p.limdays2) # 使用bracket orders设置买入卖出 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] cerebro = bt.Cerebro() # 创建cerebro # 先找到脚本的位置,然后根据脚本与数据的相对路径关系找到数据位置 # 这样脚本从任意地方被调用,都可以正确地访问到数据 modpath = os.path.dirname(os.path.abspath(sys.argv[0])) datapath = os.path.join(modpath, '../TQDat/day/stk/000001.csv') # 创建价格数据 data = bt.feeds.GenericCSVData( dataname = datapath, fromdate = datetime.datetime(2018, 1, 1), todate = datetime.datetime(2020, 3, 31), nullvalue = 0.0, dtformat = ('%Y-%m-%d'), datetime = 0, open = 1, high = 2, low = 3, close = 4, volume = 5, openinterest = -1 ) # 在Cerebro中添加价格数据 cerebro.adddata(data) # 设置启动资金 cerebro.broker.setcash(100000.0) # 设置交易单位大小 cerebro.addsizer(bt.sizers.FixedSize, stake = 1000) # 设置佣金为千分之一 cerebro.broker.setcommission(commission=0.001) cerebro.addstrategy(St) # 添加策略 cerebro.run() # 遍历所有数据 # 打印最后结果 print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) cerebro.plot() # 绘图
作者:码农甲V



学习笔记 止盈止损 止损 学习 Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号