ADX函数系列包括函数DirMovement、DMI、DMIMinus、DMIPlus、ADX、AvgTrueRange等函数,详细的请看表1 ADX函数系列,它们是由威尔斯·怀尔德(Welles Wilder)创造出来的。
表1 ADX函数系列 ADX函数系列 | 功能 | DirMovement | 全称Directional Movement,被函数DMI、DMIMinus、DMIPlus、ADX和Volatility调用 | DMI | 计算DX指数(Directional Movement Index,动向指数) | DMICustom | 和函数DMI相同,不同的是多了三个价格输入参数 | DMIMinus | 计算-DI指数(负向指数) | DMIMinusCustom | 和函数DMIMinus相同,不同的是多了三个价格输入参数 | DMIPlus | 计算+DI指数(正向指数) | DMIPlusCustom | 和函数DMIPlus相同,不同的是多了三个价格输入参数 | ADX | 计算ADX指数(Average Directional Movement Index,平均动向指数) | ADXCustom | 和函数ADX相同,不同的是多了三个价格输入参数 | ADXClassic | 和函数ADX相同,不同的是ADXClassic对结果取整 | ADXCustomClassic | 和函数ADXCustom相同,不同的是ADXCustomClassic对结果取整 | ADXR | 计算(ADX(len)+ADX(len)[len-1])/2的值,len需要计算bar的数量 | ADXRCustom | 和函数ADXR相同,不同的是多了三个价格输入参数 | ADXRClassic | 和函数ADXR相同,不同的是ADXRClassic对结果取整 | ADXRCustomClassic | 和函数ADXRCustom相同,不同的是ADXRCustomClassic对结果取整 | Volatility | 计算平均真实波幅,使用加权平均计算平均真实波幅 | XAverageOrig | 怀尔德平滑(Wilder’s Smoothing),以1/len和1-1/len为权重的加权移动平均 | TrueHigh | 当根bar的最高价与前一根bar的收盘价,取最高值 | TrueLow | 当根bar的最低价与前一根bar的收盘价,取最低值 | TrueRange | 计算真实波幅,TrueHigh-TrueLow | XAverage | 指数移动平均函数 | TrueRangeCustom | 和TrueRange相同,不同的是多了三个价格输入参数 | AvgTrueRange | 平均真实波幅(Average True Range,简称ATR指数),使用简单平均函数计算平均真实波幅 |
表1中总共有23个MC内置的函数,大部分是通过直接或间接调用DirMovement来计算,所以我们只需要将DirMovement函数背后的原理及逻辑弄清楚,其它的函数也就会很清楚,进一步,由这些函数组合得到的指标也能很快掌握并且熟练应用。下面主要通过对ADX指数的计算来介绍DirMovement函数的逻辑,然后再介绍其它函数及相同功能函数之间的比较。 1. ADX
1.1 ADX简介 绝大多数指标的计算都是以每一日的收盘价的走势及涨跌幅的累计数计算出不同的分析数据,其不足之处在于忽略了每一日的高低价之间的波动幅度。比如某个股票的两天的收盘价可能是一样的,但是其中一天的波动幅度只有2%,而另一天的波动幅度是10%,如果仅仅考虑收盘价而忽略了每天市场的价格波动幅度,那么并不能很好的判断和分析市场行情。ADX指数的出现弥补了这一不足,它主要用于分析市场的涨跌力度,但并不反应市场涨跌的方向;ADX全称为Average Directional Movement Index,是对Directional Movement Index(动向指数,简称DX)的加权平均,而DX是市场正向波动和市场负向波动的绝对差除以市场正向波动和市场负向波动之和得到的,其中市场正向波动和市场负向波动分别由+DI和-DI指数(前面的”+“和”-“只是代表方向,并不起到数学符号的作用)衡量。当市场出现一波上涨或者下跌时,ADX指数会随之上升,在实盘操作中,常将ADX与+DI和-DI指标结合起来判断市场买卖点。 1.2 ADX指数计算逻辑 通过当根bar的最高价与前一根bar的最高价进行比较,计算得到当根bar的正向波动值+DM=max(high-high[1],0);通过前一根bar的最低价与当根bar的最低价进行比较,计算得到当根bar的负向波动值-DM=max(low[1]-low,0);但是每一根bar只允许有一个波动方向,也就是说只允许有一个波动值,不能同时存在正向波动值和负向波动值,这时,我们需要对+DM和-DM进行比较,取最大值作为当根bar的波动值,波动的方向和最大波动方向一致,另一个波动值赋值为0;举例说明,如果计算出+DM=2.3,-DM=2.1,那么+DM就是当根bar的波动值,方向是正向波动,同时-DM重新赋值为0。 在计算完当根bar的波动之后,还需要计算当根bar的真实波动幅度,真实波动幅度和之前的正向波动及负向波动不一样,真实波动幅度没有方向,只是用来衡量当根bar价格波动幅度,简称TR(True Range);它是通过max(high,close[1])-min(low,close[1])计算得到。将TR进行移动平均计算之后,可以得到Volatility和ATR,即平均真实波动幅度(Average True Range),具体使用加权平均还是指数平均因策略而异,ADX中计算的Volatility是使用XAverageOrig函数进行计算的。 对于不同的商品合约及不同的周期,每一根bar正向波动和负向波动值差异很大,为了使用统一的标准对市场进行判断分析,需要先对正向波动、负向波动及真实波动幅度进行加权移动平均计算,然后通过平均正向波动与平均真实波幅的比值得到正向指数+DI,通过平均负向波动与平均真实波幅的比值得到负向指数-DI,这里的平均计算统一使用XAverageOrig函数进行计算,平均计算使用多少根bar来计算没有统一的规定(本文以len代替)。 +DI和-DI计算出来之后,可以很容易得到DX指数、ADX指数和ADXR指数。DX=|(+DI)-(-DI)|/((+DI)+(-DI)),这里+DI和-DI都被括起来了;ADX是DX的加权移动平均;ADXR=(ADX+ADX[len-1])*0.5;下面通过DirMovement函数的代码来进一步严谨的介绍ADX指数计算的逻辑。 1.3 DirMovement函数代码
inputs: PriceValueH( numericseries ),//最高价 PriceValueL( numericseries ), //最低价 PriceValueC( numericseries ), //收盘价 Len( numericsimple ), //Len根bar oDMIPlus( numericref ), //代指+DI oDMIMinus( numericref ), //代指-DI oDMI( numericref ), //代指DX oADX( numericref ), //代指ADX oADXR( numericref ), //代指ADXR oVolty( numericref ) ; //代指Volatility {这里,类似于oDMIPlus前面有o的参数,后面的括号中都是使用numericref,这个是使用在函数的参数声明语句中,定义为传址数值,它使函数可以输出多个结果,并且传递给调用该函数的脚本;powerlanguage中这种类型的参数还有numericarrayref、stringarrayref、stringref、truefalsearrayref、truefalseref} variables: var0( 0 ), //计算每根bar的正向波动值 var1( 0 ), //计算每根bar的负向波动值 var2( 0 ), var3( 0 ), var4( 0 ), //计算len根bar的累计正向波动值 var5( 0 ), //计算len根bar的累计负向波动值 var6( 0 ), //计算len根bar的累计真实波动幅度 var7( 0 ), //正向波动值的加权移动平均 var8( 0 ), //负向波动值的加权移动平均 var9( 1 / Len ), //计算中使用的加权移动平均的权重为1/len和1-1/len var10( 0 ) ; //正向指数与负向指数之和 if CurrentBar = 1 then begin for Value1 = 0 to Len - 1 begin var0 = 0 ; var1 = 0 ; var2 = PriceValueH[Value1] - PriceValueH[ Value1 + 1 ] ; var3 = PriceValueL[ Value1 + 1 ] - PriceValueL[Value1] ; condition1 = var2 > var3 and var2 > 0 ; if condition1 then var0 = var2 {当condition1条件成立的时候,当根bar为正向波动,波动值赋给var0,var1取默认值0} else begin condition1 = var3 > var2 and var3 > 0 ; if condition1 then var1 = var3 ; {condition1被重新赋值之后,如果条件满足,当根bar为负向波动,波动值赋给var1,var0取默认值0} end; {到这里,for循环内部最大的if判断结束,下面是for循环内部其它语句} var4 = var4 + var0 ; //累加正向波动值,总共计算len次 var5 = var5 + var1 ; //累加负向波动值,总共计算len次 var6 = var6 + TrueRangeCustom( PriceValueH, PriceValueL, PriceValueC )[Value1] ; {累加真实波动幅度,总共计算len次,第len次之后,循环结束} end ; var7 = var4 / Len ; {正向波动值的平均值,第一次平均是通过简单平均计算的,之后是通过加权移动平均计算的} var8 = var5 / Len ; //负向波动值的平均值 oVolty = var6 / Len ; //真实波动幅度的平均值 end else {上面是判断当currentbar=1成立时,使用简单平均去计算平均正向波动值、平均负向波动值和平均真实波动幅度,之后else部分(即,currentbar>1时)使用加权移动平均去计算平均正向波动值、平均负向波动值和平均真实波动幅度} begin var0 = 0 ; var1 = 0 ; var2 = PriceValueH - PriceValueH[1] ; var3 = PriceValueL[1] - PriceValueL ; condition1 = var2 > var3 and var2 > 0 ; if condition1 then var0 = var2 else begin condition1 = var3 > var2 and var3 > 0 ; if condition1 then var1 = var3 ; end; var7 = var7[1] + var9 * ( var0 - var7[1] ) ; {即,var7=(1-1/len)*var7[1]+1/len*var0,权重分别为1-1/len和1/len} var8 = var8[1] + var9 * ( var1 - var8[1] ) ; oVolty = oVolty[1] + var9 * ( TrueRangeCustom( PriceValueH, PriceValueL, PriceValueC ) - oVolty[1] ) ; end ; if oVolty > 0 then begin oDMIPlus = 100 * var7 / oVolty ; oDMIMinus = 100 * var8 / oVolty ; {平均正向波动值与平均真实波动幅度的比值得到+DI,之所以乘以100,是为了使DI的值落在区间[0,100]内;平均负向波动值与平均真实波动幅度的比值得到-DI。} end else begin oDMIPlus = 0 ; oDMIMinus = 0 ; {这里当oVolty=0成立时,因为是分母为0没有意义,会导致编译出现错误,为了避免这种情况,需要在代码中进行判断,此时需要将+DI和-DI分别赋值为0} end ; var10 = oDMIPlus + oDMIMinus ; if var10 > 0 then //在代码的编写时,所有的变量做分母时都需要判断一下 oDMI = 100 * AbsValue( oDMIPlus - oDMIMinus ) / var10 {计算得到DX值} else oDMI = 0 ; condition1 = CurrentBar <= Len and CurrentBar > 0 ; {从这里之后的部分,需要计算ADX和ADXR,ADX是DX的平均计算,而DX的计算已经是基于len根bar的平均计算,所以ADX的计算是二次平均计算,是基于2*len根bar的平均计算} if condition1 then begin oADX = Cum( oDMI ) / CurrentBar ; oADXR = ( oADX + oADX[ CurrentBar - 1 ] ) * .5 ; {这里,由于currentbar<=len,即bar的数目不够,所以需要进行一次特殊的平均计算,计算ADX使用的分母是currentbar;同样,ADXR的计算也进行了特殊的计算} end else begin oADX = oADX[1] + var9 * ( oDMI - oADX[1] ) ; oADXR = ( oADX + oADX[ Len - 1 ] ) * .5 ; {对ADX进行加权移动平均计算,权重分别为1-1/len和1/len;ADXR的计算见代码} end ; DirMovement = 1 ; //这个函数的返回值没有意义,关键是传址参数的使用 1.4 DirMovement系列函数使用说明 DirMovement函数代码在上面已经介绍过了,这个函数的返回值没有意义,关键是传址参数的使用。 DMI函数内部调用了DirMovement,DMI函数的返回值就是DX指数的值;DMI(len)的参数是需要计算的bar的数目len,然后返回DX指数的值。 DMICustom函数的功能及内部的代码逻辑和DMI函数一样,不同的是多了三个价格参数,DMICustom(high,low,close,len)的参数分别是最高价、最低价、收盘价和bar的数目len,返回DX指数的值。 DMIMinus函数内部调用了DirMovement,它的返回值就是-DI指数的值;DMIMinus(len)的参数是需要计算的bar的数目len,然后返回-DI指数的值。 DMIMinusCustom函数的功能及内部的代码逻辑和DMIMinus函数完全一样,不同的是多了三个价格参数,DMIMinusCustom(high,low,close,len)的参数分别是最高价、最低价、收盘价和bar的数目len,返回-DI指数的值。 ADX函数调用了DirMovement函数;ADX(len)的参数是需要计算的bar的数目len,然后返回ADX指数的值。 ADXCustom函数的功能及内部代码逻辑和ADX函数完全一样,不同的是多了三个价格参数;ADXCustom(high,low,close,len)的参数分别是最高价、最低价、收盘价和bar的数目len,返回ADX指数的值。 ADXClassic函数功能及计算逻辑和ADX函数是一样,参数也是一样的,不同的是代码的编写不一样;ADXClassic函数调用了DMI函数来计算DX指数,然后再对DX指数使用加权移动平均来计算ADX指数的值,最后再使用intportion关键字对ADX指数取整;ADXClassic(len)的参数是需要计算的bar的数目len,然后返回ADX指数的取整值(即将小数点之后的值去除)。 ADXCustomClassic函数是ADXClassic和ADXCustom的结合,即使用了三个价格参数,然后在内部调用了DMI函数来计算DX指数,然后再对DX指数使用加权移动平均来计算ADX指数的值,最后再使用关键字intportion对ADX指数取整数值;ADXCustomClassic(high,low,close,len)的参数是最高价、最低价、收盘价和需要计算的bar的数目len。 ADXR函数调用了DirMovement函数;ADXR(len)的参数是需要计算的bar的数目len,然后返回ADXR指数的值。 ADXRCustom、ADXRClassic、ADXRCustomClassic函数的计算、使用及相互区别可以参考ADX。 XAverageOrig是加权移动平均函数;XAverageOrig(pricevalue,len)的参数分别是价格值和需要计算的bar的数目len,权重分别为1-1/len和1/len,函数返回pricevalue的加权平均值,即XAverageOrig=(1-1/len)*XAverageOrig[1]+1/len*pricevalue。 TrueHigh函数返回当根bar的最高价与前一根bar的收盘价的最高值,这个函数没有参数。 TrueLow函数返回当根bar的最低价与前一根bar的收盘价的最低值,这个函数没有参数。 TrueRange函数返回当根bar的真实波动幅度,TrueRange=TrueHigh-TrueLow,这个函数没有参数。 TrueRangeCustom函数的逻辑和TrueRange的计算逻辑是一样的,不同的是它有三个价格参数;TrueRangeCustom(high,low,close)的参数是当根bar的最高价、最低价和收盘价,返回当根bar的真实波动幅度。 Volatility的值等于XAverageOrig(TrueRange,len),这个函数的内部调用函数XAverageOrig对真实波动幅度进行加权移动平均计算;Volatility(len)的参数是需要计算的bar的数目len,返回平均真实波动幅度。 XAverage是指数移动平均函数,它是一种特殊的加权平均函数;XAverage(pricevalue,len)的参数分别是价格值和需要计算的bar的数目,返回pricevalue的指数移动平均值,即XAverage=(len-1)/(len+1)*XAverage[1]+2/(len+1)*pricevalue。 AvgTrueRange函数调用Average函数计算平均真实波动幅度,即先累加真实波动幅度,然后再除以数目;AvgTrueRange(len)的参数是需要计算的bar的数目,返回平均真实波动幅度值。 |