一、模型概述
(一)Dual Thrust 策略简述
Dual Thrust,由Michael Chalek在20世纪80年代开发,曾被FutureTrust杂志评为最赚钱的策略之一。Dual Thrust系统策略十分简单,思路简明,但正所谓大道至简,该策略适用于股票、期货、外汇等多类型市场,如果配合上良好的资金管理和策略择时,可以为投资者带来长期稳定的收益。
Dual Thrust是典型的区间突破型策略,以今日开盘价加减一定比例的N周期内的价格振幅(Range),确定上下轨;
Dual Thrust对于多头和空头的触发条件,考虑了非对称的幅度,做多和做空参考的Range可以选择不同的周期数,也可以通过参数K1和K2来确定。
具体计算过程如下:
(1)N日High的最高价HH, N日Close的最低价LC;
(2)N日Close的最高价HC,N日Low的最低价LL;
(3)Range = Max(HH-LC,HC-LL)
(4)上轨(upperLine )= Open + K1*Range
(5)下轨(lowerLine )= Open + K2*Range
突破上轨做多,跌破下轨翻空。
(二)构造系统
(1)当价格向上突破上轨时,如果当时持有空仓,则先平仓,再开多仓;如果没有仓位,则直接开多仓;
(2)当价格向下突破下轨时,如果当时持有多仓,泽县平川,再开空仓;如果没有仓位,则直接开空仓;
Dual Thrust 在形式上和开盘区间突破策略类似,也是较为常见的日内交易策略之一,是以今日开盘价加减range 的一定比例确定上下轨,日内价格突破上轨时做多,价格突破下轨时做空。不同点主要体现在两方面:
(1)DualThrust在Range的设置上,引入前N 日的四个价位,使得一定时期内的Range 相对稳定;
(2)DualThrust 对于多头和空头的触发条件,考虑了非对称的幅度,做多和做空参考的Range可以选择不同的周期数,也可以通过参数Ks和Kx来确定。当Ks>Kx时,下轨距离中轴较近,容易触发空头的条件;当Ks<Kx时,上轨距离中轴较近,容易触发多头的条件。
所以在使用该策略时,既可以参考历史数据测试的最优参数,也可以从其他大周期的技术指标入手,或根据自己对后势的判断,阶段性地动态调整Ks和Kx的值。
(三)Dual Thrust的特点
(1)DualThrust策略大都是持续在市的,持续在市就是没有空仓,一旦开始交易不是空头就是多头,在一天交易结束时不平仓,如果多头趋势没了,不是平仓后持空仓,而是卖掉后再开空头,相当于两次空头。
(2)DualThrust是美国标普500股指期货10大交易系统之一(2005年前),也是唯一公布源码的策略,因此已经在海外被广为流传,国内金融人士直接将海外代码翻译使用。在股指期货推出的第一年,的确获取了高额利润。但在后期,券商和期货公司为了更好的服务客户,几乎每位客户都赠送这两套模型。随着越来越多的投资者使用这类模型,这一优秀策略寿命迅速到期,目前这些模型以及无法稳定获利。
(3)Dual thrust原策略不仅适用于日间,也适用于日内。如果将该系统用于日间交易,不得不面对的一个问题是跳空。因为系统每天的中轴是当日的开盘价,上下轨是通过中轴加减前一日的价格计算得到的幅度而得出的。假设第二天反向跳空幅度很大但是日内的价格波动不大,此刻价格无法触及反向的轨道,是无法发出反转信号的,因为随着跳空中轴也偏离前一日价格很多,上下轨跟随中轴进行了很大偏移,尽管此时的价格与前一日的差值已经很大,但是相对开盘价波动并不大。如果运气再不好一点,第三日又出现了跳空,那么亏损就非常大了。
二、策略介绍
(一)策略思路:改进Dual Thrust
在前人的基础上,我们首先通过调整Ks、Kx的值,初始策略中Ks、Kx的值均为0.7,调整后Ks、Kx为0.4,使得DualThrust策略能有一个比较理想的状态;然后加入绝对值止盈止损,不管价格上涨还是下跌,只有价格偏离交易价格超过阈值就将其平仓,使风险控制在可接受范围,避免大幅度亏损;最后加入KDJ指标,对市场趋势进行跟踪,动态调整Ks、Kx的值,当市场处于多头市场时(K>50,D>50,J>50),调整Ks为0.3使之小于Kx(值为0.4),此时容易触发多头的条件,当市场处于空头市场(K<50,D<50,J<50),调整Kx为0.3使之小于Ks(值为0.4),此时容易触发空头的条件。
(二)KDJ的计算
首先,计算周期(n日、n周等)的RSV值,即未成熟随机指标值,然后再计算K值、D值、J值等。以日KDJ数值的计算为例,其计算公式为n日RSV=(Cn-Ln)/(Hn-Ln)×100。公式中,Cn为第n日收盘价;Ln为n日内的最低价;Hn为n日内的最高价。
然后,计算K值与D值:
当日K值=2/3×前一日K值+1/3×当日RSV
当日D值=2/3×前一日D值+1/3×当日K值
若无前一日K 值与D值,则可分别用50来代替。
J值=3*当日K值-2*当日D值
最后,如果K、D、J值都大于50时,为多头市场,后市看涨;如果K、D、J值都小于50时,为空头市场,后市看跌。
三、策略检验
(一)初始设置
我们选取的数据范围是沪深300股指期货合约1分钟的收盘价格,取2013年1月4日到2015年4月30日为样本内,进行参数优化;取2015年5月4日至2016年12月31日作为回测区间。初始资金投入为40万,手续费为双边收取(开仓和平仓均要收取),取1%%(即万分之一),保证金比例为50%,每次交易数量为1手。
(二)策略评价体系
为了更好地检验该策略的效果,我们选取了一些指标作为策略的评价体系。具体如表1所示。
表1:基于KDJ指标的DualThrust策略策略评价体系
(三)策略检验结果
通过改进后的Dual Thrust策略建立的模型,得出策略实验的样本内的累计收益效果图,如图2所示。策略实验的样本内的每日收益效果图,如图3所示。
图2 样本内累计收益
图3 样本内每日收益
策略实验的样本外的累积收益效果图,如图4所示。策略实验的样本外的每日收益效果图,如图5所示。
图4样本外累计收益
图5样本外每日收益
样本内外数据在IF上的回测表现如表2所示。
表2 策略在IF上的回测表现
由样本内和样本外的指标数据对比可以看出,样本外检验的年化收益率、胜率有所下降,但交易次数下降,其中有效的交易次数增多,胜率虽然有所下降但仍然维持在50%以上,说明该模型还是能够捕捉到有效信息,总收益率还是有所上升。最大回撤率有上升,总体看来,模型在样本外的表现良好,夏普比率在保持在2以上。
四、策略总结
1、该策略品种和周期适应性都十分出色,适应于股指和商品期货等大部分交易标的;
2、该策略绝对收益率十分优秀;
3、该策略对于投资标的的流动性有较强的要求,流动性越好,策略表现越好,谨慎参与价格跳空的交易标的;
4、该策略回撤较大,需要做好严格的资金管理和风险控制;
5、该策略是非多即空的趋势跟踪策略,该属性决定了产生趋势一定会抓住,因此跑投资组合更有优势,可以抓住大部分品种的趋势行情,同时也更有利于资金管理。
最后,小编对于该策略的改进建议如下:
1、可以增加长周期过滤,减少交易次数,寻找风报比更高的交易机会;
2、增加开仓头寸管理,如通过以损定仓方式进行开仓;
3、可以增加多种离场方式,允许出现空仓期;
4、为了规避隔夜跳空风险,可以将该策略移植到日内,但应增加条件过滤交易次数。
后附策略源码:
Params
Numeric K1(0.5);
Numeric K2(0.5);
Numeric Mday(1);
Numeric Nday(1);
Numeric lots(1);
Numeric offset(0);
Vars
Numeric BuyRange(0);
Numeric SellRange(0);
Numeric BuyTrig(0);
Numeric SellTrig(0);
Numeric HH;
Numeric LL;
Numeric HC;
Numeric LC;
Numeric i_offset;
Numeric BuyPosition;
Numeric SellPosition;
Begin
i_offset =offset*MinMove*PriceScale;
HH =Highest(HighD(1),Mday);//计算一定周期内的最高价的最大值
HC =Highest(CloseD(1),Mday); //计算一定周期内的收盘价的最大值
LL =Lowest(LowD(1),Mday); //计算一定周期内的最低价的最小值
LC = Lowest(CloseD(1),Mday); //计算一定周期内的收盘价的最小值
//计算BuyRange和SellRange
If((HH - LC) >=(HC - LL))
{
SellRange= HH - LC;
}
Else
{
SellRange= HC - LL;
}
HH =Highest(HighD(1),Nday);
HC =Highest(CloseD(1),Nday);
LL =Lowest(LowD(1),Nday);
LC =Lowest(CloseD(1),Nday);
If((HH - LC) >=(HC - LL))
{
BuyRange =HH - LC;
}
Else
{
BuyRange =HC - LL;
}
//计算通道上下轨
BuyTrig =K1*BuyRange;
SellTrig =K2*SellRange;
BuyPosition =OpenD(0)+BuyTrig;
SellPosition =OpenD(0)-SellTrig;
PlotNumeric("BuyPosition",BuyPosition);
PlotNumeric("SellPosition",SellPosition);
//入场条件:突破上轨反手多,突破下轨反手空
If(MarketPosition== 0)
{
If(High>=BuyPosition)
{
Buy(lots,Max(Open,BuyPosition)+i_offset);
Return;
}
If(Low<=SellPosition)
{
SellShort(lots,Min(Open,SellPosition)-i_offset);
Return;
}
}
If(MarketPosition== -1)
{
If(High>=BuyPosition)
{
Buy(lots,Max(Open,BuyPosition)+i_offset);
Return;
}
}
If(MarketPosition== 1)
{
If(Low<=SellPosition)
{
SellShort(lots,Min(Open,SellPosition)-i_offset);
Return;
}
}
End