肯特纳通道是由Chester W. Keltner在上个世纪60年代发明的一个交易系统,其核心思想是均线理论。并且当时该系统在非常长的一段时间内,得到了令人瞩目的成绩。虽然原版的肯特纳通道系统没有刚出现时那么有效,但它的核心思想,至今都对交易界产生很深远的影响。
说起通道类策略,大家可能会想到著名的布林带(BOLL),但不一样的是肯特纳通道先是用最高价、最低价、收盘价这三者的平均值作为一个基础价格,然后再计算出这个基础价格的N周期平均值,这个平均值就是肯特纳通道的中轨。上轨就是中轨加上波动幅度的倍数,下轨就是中轨减去波动幅度的倍数。
那么,这个波动幅度怎么计算呢?也就是(最高价-最低价)的N周期平均值,再乘以一定的倍数。如此一来,你会发现它类似于布林带(BOLL),也有价格中轨,以及根据价格中轨计算出来的上下轨。不过与布林带(BOLL)相比,肯特纳通道更加平滑。
后来肯特纳通道被Linda Raschke进行了改良。Linda Raschke是美国知名的商品期货的交易员,也是LBR资产管理公司的总裁。原版的肯特纳中轨是一个普通均线,改为指数平均线。另外也把波动幅度的计算方法,改为平均真实波动幅度(ATR)。其计算公式是:
我们知道价格并不总是以趋势或震荡的方式运行,而是以趋势和震荡不完全随机交替的方式运行。那么肯特纳以通道的方式作为分界线,把趋势行情和震荡行情分开。当价格在上轨和下轨之间运行时,我们可以认为是震荡行情。当价格突破上轨,说明更强大的买压已经出现,未来价格坑你会进一步上涨。当价格突破下轨,说明已经出现更强大的卖压,未来价格可能会进一步下跌。
入场
出场
通过上面的交易逻辑,我们可以在优宽量化交易平台上来构建这个策略。我们以My语言为例,首先依次打开:youquant.com > 登录 > 控制中心 > 策略库 > 新建策略 > 点击左上角下拉框选择My语言,开始编写策略,注意看下面代码中的注释。
// 参数
MAN:=20;
ATRN:=50;
JG:=(HIGH+LOW+CLOSE)/3; // 基础价格
ZG:MA(JG,MAN); // 中轨
TRUEHIGH1:=IF(HIGH>REF(C,1),HIGH,REF(C,1));
TRUELOW1:=IF(LOW<=REF(C,1),LOW,REF(C,1));
TRUERANGE1:=IF(ISLASTBAR,H-L,TRUEHIGH1-TRUELOW1); // 计算真实波动幅度
SG:ZG+MA(TRUERANGE1,ATRN); // 上轨
XG:ZG-MA(TRUERANGE1,ATRN); // 下轨
ZG>REF(ZG,1)&&C>SG,BK; // 中轨向上,并且价格升破上轨,开多单
C<ZG,SP; // 持有多单时,价格跌破中轨,平多单
ZG<REF(ZG,1)&&C<XG,SK; // 中轨向下,并且价格跌破下轨,开空单
C>ZG,BP; // 持有空单时,价格升破中轨,平空单
AUTOFILTER; // 设置信号过滤方式
为了更接近真实的交易环境,我们在回测时采用开平仓各2跳以及2倍的手续费来压力测试,测试环境如下:
测试环境 收益明细 资金曲线 上面几张图是BitMEX交易所中XBTUSD永续合约的回测结果,在趋势行情中金肯特纳依然保持这有效性,尽管这种效率已经不是太高,但是从整体来看资金曲线是向上的,即使在2019年7月份市场走势出现回撤时,净值曲线却并没有较大的回撤。
虽然肯特纳是一种古老的交易方法,但是我们通过代码还原,并加以改进,事实证明这个策略在今天依然还有效。特别是在中低频CTA策略领域,肯特纳依然有我们值得学习的地方,那就是截断亏损,让利润奔跑!
可以说,大部分成功的交易方法,都秉持着:“亏损时亏的少一点,赚钱时赚的多一点”的交易理念,然后持之以恒的去执行这个理念。所以,作为一个长线交易策略,短期的亏损时必然要承受的成本,短期的盈利也不是我们的目标。
(*backtest start: 2019-01-01 00:00:00 end: 2019-07-27 00:00:00 period: 1h exchanges: [{"eid":"Futures_BitMEX","currency":"XBT_USD"}] args: [["MAN",20],["TradeAmount",10000,126961],["SlideTick",2,126961],["ContractType","XBTUSD",126961]] *) // 参数 MAN:=20; ATRN:=50; JG:=(HIGH+LOW+CLOSE)/3; // 基础价格 ZG^^MA(JG,MAN); // 中轨 TRUEHIGH1:=IF(HIGH>REF(C,1),HIGH,REF(C,1)); TRUELOW1:=IF(LOW<=REF(C,1),LOW,REF(C,1)); TRUERANGE1:=IF(ISLASTBAR,H-L,TRUEHIGH1-TRUELOW1); // 计算真实波动幅度 SG^^ZG+MA(TRUERANGE1,ATRN); // 上轨 XG^^ZG-MA(TRUERANGE1,ATRN); // 下轨 ZG>REF(ZG,1)&&C>SG,BK; // 中轨向上,并且价格升破上轨,开多单 C<ZG,SP; // 持有多单时,价格跌破中轨,平多单 ZG<REF(ZG,1)&&C<XG,SK; // 中轨向下,并且价格跌破下轨,开空单 C>ZG,BP; // 持有空单时,价格升破中轨,平空单 AUTOFILTER; // 设置信号过滤方式template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6