古代打仗有一句这样的成语:“兵马未动,粮草先行”。在交易中也有一句类似的话:“量在价先”。意思是说:价格的上涨和下跌,背后都是成交量在推动,一切风吹草动,最先反应在成交量上。于是呢,就有人发明了衡量成交量的能量潮指标(On Balance Volume,OBV)。
能量潮(OBV)是上个世纪60年代由格兰维尔(Joe Granville)发明,虽然其中的算法很简单,但是在交易的“价、量、时、空”四个要素中,以“量”为切入点,得到了很多交易者的青睐。作为交易市场中的人气指标,能量潮可以很直观的反应出价格与成交量的相互关系,从而帮助交易者从更多的角度观察市场。
如上图所示,虽然能量潮是描述成交量的,但是其走势明显与成交量不同,细心的朋友可能会发现,能量潮的走势与价格走势基本上一致,也有相对高点和相对低点,只不过走势更加平滑。它是将成交量数量化,并绘制成类似于趋势线的形态。
对于交易这来说,当价格与大多数交易者的想法一致时,成交量就会变小,因为该买的人已经买了,该卖的人也已经卖了。反之,当价格与大多数交易者的想法不一致时,成交量就会变大,因为买者认为价格会继续上涨,卖者会认为价格会下跌,当他们都付诸行动时,成交量就会变大。因此能量潮反应的不仅是市场人气,还反应了多头和空头之间的力量。
另外,根据反身性原理:“想法改变了事实,事实的改变又反过来改变了想法”,也就是说当人们认为价格会继续上涨时,就会付诸行动买入,伴随而来的就是成交量增加,价格继续上涨。当人们看到价格又继续上涨时,就会认为价格可能会继续上涨,并进一步推高了价格。这个就是我们看到市场中价格涨时涨的离谱,并出现大量成交量的原因。
能量潮的计算方法其实并不复杂,如果当前K线收盘价大于上根K线收盘价,那么当前K线的能量潮就是当前K线的成交量加上上根K线的能量潮。如果当前K线收盘价小于上根K线收盘价,那么当根K线的能量潮就是上根K线能量潮减去当前的成交量。
其中:
使用能量潮的一个最基本的前提是:假设成交量的变化在价格变化之前,也就是我们在上文提到的“量在价先”。通常情况下,价格的上涨或下跌必须有成交量配合,成交量的增加和减小都时时刻刻影响这价格的变化。比如:价格的上涨或下跌一般都伴随着很大的成交量,但如果价格上涨或下跌成交量变化不大,那么这种价格波动很难持续下去。
当能量潮是向上的时候,我们可以认为资金正在涌入市场,市场交易空前活跃,未来价格可能会上涨;当能量潮是向下的时候,我们可以认为资金正在撤离市场,市场交易逐渐冷清,未来价格可能会下跌。
如何才能判断能量潮是上涨还是下跌呢?其实可以利用判断价格方向的方法来判断能量潮,在上涨和下跌的能量潮中,其走势并不是一气呵成。也有前进三步退一步的特点,在走势中,我们可以发现有波峰有波谷。那么在上涨走势中,每一个波谷都高于前面的波谷,在下跌走势中,每一个波峰都低于前面的波峰。
当然,在程序化交易中,大可不必那么复杂的识别波峰和波谷来产生信号,可以使用均线或通道线来衡量能量潮的走势,这对于新手来说,是很容易实现的。例如:均线是将一段周期的能量潮平均,如果当前能量潮大于这个平均值,说明资金对市场更加乐观,反之如果当前能量潮小于这个平均值,说明资金对市场更加没兴趣。
由上面的能量潮实战原理,我们可以试着构建一个基于能量潮的交易策略,以最简单的均线为例,通过对能量潮数值的多次平均,得出多条能量潮的移动平均线。能量潮能很好的描述成交量,但是它不能描述价格,所以这里加入一个最具代表性的指标:平均真是波动幅度(ATR),它能够很好的反应一段时间内的价格波动情况。下面是整个策略的逻辑:
通过上面的交易逻辑,我们可以在优宽量化交易平台上来构建这个策略。我们以My语言为例,首先依次打开:youquant.com > 登录 > 控制中心 > 策略库 > 新建策略 > 点击左上角下拉框选择My语言,开始编写策略,注意看下面代码中的注释。
N:=10;
OBV:=SUM(IFELSE(CLOSE>REF(CLOSE,1),VOL,IFELSE(CLOSE<REF(CLOSE,1),-VOL,0)),0);
TR:=MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW));
ATR:=MA(TR,N);
B:EMA2(OBV*ATR,N);
D:EMA2(OBV*ATR,N*2);
B>REF(B,1) && D>REF(D,1) && B>D,BK;
B<REF(B,1)
N:=10; OBV:=SUM(IFELSE(CLOSE>REF(CLOSE,1),VOL,IFELSE(CLOSE<REF(CLOSE,1),-VOL,0)),0); TR:=MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW)); ATR:=MA(TR,N); B:EMA2(OBV*ATR,N); D:EMA2(OBV*ATR,N*2); B>REF(B,1) && D>REF(D,1) && B>D,BK; B<REF(B,1) || D<REF(D,1) || B<D,SP; B<REF(B,1) && D<REF(D,1) && B<D,SK; B>REF(B,1) || D>REF(D,1) || B>D,BP; AUTOFILTER;template: strategy.tpl:40:21: executing "strategy.tpl" at <.api.GetStrategyListByName>: wrong number of args for GetStrategyListByName: want 7 got 6