您好,登录后才能下订单哦!
这篇文章给大家分享的是有关python如何实现动态阶梯突破策略的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
什么是突破策略
我们知道,期货市场的价格以趋势和震荡交替的方式演变,如果我们只使用一种方法抓住趋势,就能赚到趋势行情的钱。那么,用什么方式来抓住趋势呢?比较简单的一种方法就是用突破策略。通过设置价格的上下轨,或者支撑位、压力位,当价格超过上轨,我们认为行情即将启动,开仓做多,反之亦然。
市面上有很多不同种类的突破策略,大致可以分为:形态突破(包括:双肩型、头肩型、颈线、趋势线等等)、指标突破(均线、KDJ、ATR等等)、通道突破(新高和新低、支撑线和阻力线)、量能突破(成交量、能量潮)。其中在量化交易中,最常用的是:指标突破和通道突破。
突破策略理论
在逻辑学中,有一个“充分不必要条件”的概念,也就是说:如果有A不一定有B,但如果有B就必定有A。那么B就是A的充分而不必要的条件,即充分不必要条件,A是B的必要不充分条件。所以站在结果的角度讲,价格突破关键点位后未必形成趋势,但趋势上涨或下跌必然会突破其间的关键价格位置。
另外,从突破的原因上讲,市场涨跌取决于买卖双方实力对比。当价位冲破上一时段的最高点时,在上一时段任何价位做空头的人都无一例外被套牢,它当中肯定有一部分要认赔平仓出局,反过来又给升势推波助澜。相反,当行情跌破上一时段的最低价时,在上一时段任何一点做多头的统统都出现浮动亏损,其中一定有部分要止损作平仓卖出,正好对跌势落井下石。
策略逻辑
阶梯策略,这是一个比较土的名字,因为其在图表上的外形类似台阶而得名,最初的灵感来自于阶梯止损。相信有过实盘经验的人应该深有体会:当市场进行横向整理或者摇摆不定的时候,对交叉类系统的打击很大,往往会买在高点,卖在低点。如果行情一直持续,则会出现连续亏损,连续的亏损信号将对交易者造成严重的心理负担和资金回撤压力。如下图:
通过利用,通道技术则可以过滤或者减少价格反复缠绕,减少部分虚假信号,对于降低无效交易有巨大帮助。本策略并非传统的通道策略。而是根据前期最高价和最低价,反向建立自适应通道。这里提到的自适应是指回溯日期会根据我们的逻辑进行调整,具体来说本策略是由市场波动的变动率来变化。
大部分通道策略的组成是由两个因子决定,第一个就是中轨,然后再根据中轨算出通道宽度,即上下轨。比如常见的布林带通道( BollingerBand ),先是由一条均线当中心线,而通道宽度是由标准差所决定。阶梯策略的通道并不是以中轨得来,与之相反的是:先根据市场波动率计算出通道上下轨,然后再根据通道宽度算出中轨。
另外,在判定最高点和最低点的 K 线条数取决于我们愿意给交易多少变化空间,我们用来越多的 K 线条数来确定上下轨,我们给予程序化交易的变化空间越大,相应的,在触发止损前盈利回撤的幅度也会越大。使用越近的高点或低点,止损被触发的速度也越快。想让通道窄一点就设定小一点,想让通道宽一点就设定大一点。
设置通道
上轨:如果当根K线最低价小于上根K线最低价,上轨就等于前N根K线最高价的最高价
下轨:如果当根K线最高价大于上根K线最高价,下轨就等于前N根K线最低价的最低价
中轨:上轨和下轨的平均值
入场条件
多头入场:如果当前没有持仓,并且价格大于上轨,买入开仓。
空头入场:如果当前没有持仓,并且价格小于下轨,卖出开仓。
出场条件
多头出场:如果当前持有多单,并且价格小于中轨,卖出平仓。
空头出场:如果当前持有空单,兵器价格大于中轨,买入平仓。
为了避免过度拟合,在设计策略的时候,只给定了一个参数。虽然仅有一个参数,但却不失策略在市场中的灵活性。不仅如此,阶梯策略既能适应国内外商品期货,还可以应用于 A 股 ETF ,包括外盘 ETF 和反向杠杆 ETF,以及外汇市场。当然只是适应部分品种,从全品种统计来看,这是一个普适性比较强的策略。
策略编写
根据上面的策略逻辑,我们可以在发明者量化交易平台上实现交易策略。依次打开:fmz.com > 登录 > 控制中心 > 策略库 > 新建策略 > 点击右上角下拉菜单选择Python语言,开始编写策略,注意看下面代码中的注释。
第1步:编写策略框架
这个在之前的章节已经学习过,一个是onTick函数,另一个是main函数,其中在main函数中无限循环执行onTick函数,如下:
def onTick(): pass def main(): while True: onTick() Sleep(1000)
第2步:定义全局变量
首先定义策略中的上轨、下轨,因为我们的策略中上轨、下轨时是根据一定的条件来计算的,也就是说:当前的最高价大于前面K线的最高价时,才重新计算下轨;当前的最低价小于前面K线的最低价时,才重新计算上轨。所以我们必须把上轨和下轨变量定义在onTick主函数外面。
up_line = 0 # 上轨 under_line = 0 # 下轨 mp = 0 # 用于控制虚拟持仓
另外,我们还需要定义全局变量虚拟持仓mp,策略运行之初默认是空仓mp=0,当开多单后把虚拟持仓重置为mp=1,当开空单后把虚拟持仓重置为,mp=-1,当平多单或空单后把虚拟持仓重置为mp=0。这样我们在判断构建逻辑获取仓位时,只需要判断mp的值就可以了。
第3步:计算上轨、下轨、中轨
因为在计算这些数据之前,肯定要先获取历史的K线基础数据,这些基础数据的获取方式也很简单,首先订阅期货品种,然后调用发明者量化API中的GetRecords方法。接着因为在计算上轨和下轨的时候需要用到talib库中的Highest和Lowest方法,这两个方法都要传入周期参数,但如果K线数据不够的时候,就不能正常计算其值,所以在这里就要判断K线数据的长度,如果K线的长度不足以计算其值时,就直接返回跳过。
接着,我们分别获取当前K线和上根K线的最高价和最低价,通过对比当前K线最高价与上根K线最高价来定义下轨的值,如果当前的最高价大于前面K线的最高价时,就重新计算下轨;同理如果当前的最低价小于前面K线的最低价时,就重新计算上轨。最后上轨和下轨的平均值就是中轨。
exchange.SetContractType("rb000") # 订阅期货品种 bars = exchange.GetRecords() # 获取K线数组 if len(bars) < cycle_length + 1: # 如果K线数组的长度太小,所以直接返回 return close0 = bars[len(bars) - 1].Close; # 获取当根K线收盘价 high0 = bars[len(bars) - 1].High; # 获取当根K线最高价 high2 = bars[len(bars) - 2].High; # 获取上根K线最高价 low0 = bars[len(bars) - 1].Low; # 获取当根K线最低价 low1 = bars[len(bars) - 2].Low; # 获取上根K线最低价 highs = TA.Highest(bars, cycle_length, 'High'); # 获取前cycle_length根K线最高价的最高价 lows = TA.Lowest(bars, cycle_length, 'Low'); # 获取前cycle_length根K线最低价的最低价 global up_line, under_line, mp # 使用全局变量 if high0 > high2: # 如果当根K线最高价大于上根K线最高价 under_line = lows # 把下轨重新赋值为:前cycle_length根K线最低价的最低价 if low0 < low1: # 如果当根K线最低价小于上根K线最低价 up_line = highs # 把上轨重新赋值为:前cycle_length根K线最高价的最高价 middle_line = (lows + highs) / 2; # 计算中轨的值
这里有一个地方需要注意,可能细心的朋友已经发现了,我们在计算上轨和下轨的时候,用到了talib库中的Highest和Lowest函数,因为在发明者量化软件中已经内置了这两个常用的函数,所以我们不需要像前几节那样在策略开头导入talib库,并且在使用内置函数的时候,其写法也略有不同,具体可以查看下方的代码。
第4步:下单交易
有了上轨、下轨、中轨的值,就可以配合当前的最新价格开平仓交易了,我们可以回过头再看下之前设计的交易逻辑:如果当前没有持仓,并且价格大于上轨 * 1.05,买入开仓。如果当前没有持仓,并且价格小于下轨 * 0.95,卖出开仓。如果当前持有多单,并且价格小于中轨,卖出平仓。如果当前持有空单,兵器价格大于中轨,买入平仓。
if mp == 0 and close0 > up_line: # 如果当前空仓,并且最新价大于上轨 exchange.SetDirection("buy") # 设置交易方向和类型 exchange.Buy(close0, 1) # 开多单 mp = 1 # 设置虚拟持仓的值,即有多单 if mp == 0 and close0 < under_line: # 如果当前空仓,并且最新价小于下轨 exchange.SetDirection("sell") # 设置交易方向和类型 exchange.Sell(close0 - 1, 1) # 开空单 mp = -1 # 设置虚拟持仓的值,即有空单 if mp > 0 and close0 < middle_line: # 如果当前持有多单,并且最新价小于中轨 exchange.SetDirection("closebuy") # 设置交易方向和类型 exchange.Sell(close0 - 1, 1) # 平多单 mp = 0 # 设置虚拟持仓的值,即空仓 if mp < 0 and close0 > middle_line: # 如果当前持有空单,并且最新价大于中轨 exchange.SetDirection("closesell") # 设置交易方向和类型 exchange.Buy(close0, 1) # 平空单 mp = 0 # 设置虚拟持仓的值,即空仓
下单交易使用if语句,如果条件为真,就先设置交易方向和类型,即:开多、开空、平多、平空。然后调用发明者量化软件中的Buy或Sell下单函数,最后下单之后重置虚拟持仓的状态。
完整策略代码
'''backtest start: 2015-02-22 00:00:00 end: 2019-10-29 00:00:00 period: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES"}] ''' # 外部参数 cycle_length = 100 # 定义全局变量 up_line = 0 # 上轨 under_line = 0 # 下轨 mp = 0 # 用于控制虚拟持仓 def onTick(): exchange.SetContractType("rb000") # 订阅期货品种 bars = exchange.GetRecords() # 获取K线数组 if len(bars) < cycle_length + 1: # 如果K线数组的长度太小,所以直接返回 return close0 = bars[len(bars) - 1].Close; # 获取当根K线收盘价 high0 = bars[len(bars) - 1].High; # 获取当根K线最高价 high2 = bars[len(bars) - 2].High; # 获取上根K线最高价 low0 = bars[len(bars) - 1].Low; # 获取当根K线最低价 low1 = bars[len(bars) - 2].Low; # 获取上根K线最低价 highs = TA.Highest(bars, cycle_length, 'High'); # 获取前cycle_length根K线最高价的最高价 lows = TA.Lowest(bars, cycle_length, 'Low'); # 获取前cycle_length根K线最低价的最低价 global up_line, under_line, mp # 使用全局变量 if high0 > high2: # 如果当根K线最高价大于上根K线最高价 under_line = lows # 把下轨重新赋值为:前cycle_length根K线最低价的最低价 if low0 < low1: # 如果当根K线最低价小于上根K线最低价 up_line = highs # 把上轨重新赋值为:前cycle_length根K线最高价的最高价 middle_line = (lows + highs) / 2; # 计算中轨的值 if mp == 0 and close0 > up_line: # 如果当前空仓,并且最新价大于上轨 exchange.SetDirection("buy") # 设置交易方向和类型 exchange.Buy(close0, 1) # 开多单 mp = 1 # 设置虚拟持仓的值,即有多单 if mp == 0 and close0 < under_line: # 如果当前空仓,并且最新价小于下轨 exchange.SetDirection("sell") # 设置交易方向和类型 exchange.Sell(close0 - 1, 1) # 开空单 mp = -1 # 设置虚拟持仓的值,即有空单 if mp > 0 and close0 < middle_line: # 如果当前持有多单,并且最新价小于中轨 exchange.SetDirection("closebuy") # 设置交易方向和类型 exchange.Sell(close0 - 1, 1) # 平多单 mp = 0 # 设置虚拟持仓的值,即空仓 if mp < 0 and close0 > middle_line: # 如果当前持有空单,并且最新价大于中轨 exchange.SetDirection("closesell") # 设置交易方向和类型 exchange.Buy(close0, 1) # 平空单 mp = 0 # 设置虚拟持仓的值,即空仓 def main(): while True: onTick() Sleep(1000)
感谢各位的阅读!关于“python如何实现动态阶梯突破策略”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。