具有最小延迟的有效平均算法:在指标中使用

Nikolay Kositsin | 25 二月, 2016

简介

我认为不需要解释平滑算法对技术分析和交易系统有多么重要。几乎所有指标的代码都包含显式或隐式平均算法。如果我们更深入地了解在线交易平台和客户终端,会发现其中大部分和大多数指标使用的都是最简单的(但远远不是最有效的)平均算法。

目前已开发了更加有效的平均算法。然而,在尝试将这些函数应用于指标的过程中,由于算法极具复杂性,往往会导致程序员完全没有足够的耐心,最多只设置了一到两个指标,而这些指标始终无法正常工作。从此以后,他们往往会厌倦了朝这个方向努力。简单平均值的基本优势在于,它们可随时随地作为简单的自定义函数进行应用。


主题

在本文中,我将目标读者定义为清楚 MQL4 相当有效的平均算法的交易者,这些算法具有最小延迟性,作为相当简单的自定义函数。这些函数的使用并不比技术指标的使用复杂很多。这些函数很早以前就编写过,并且其运行效果经过很长一段时间的检验。尚未在它们中发现任何缺点、问题或计算错误。因此,我们将考虑以下算法:
- JJMASeries () - 自适应 JMA 平滑算法;
- JLiteSeries() - 无自适应算法的 JMA 平滑算法;
- JurXSeries () - 从指标 JRSX 获取的超线性平滑算法;
- ParMASeries() - 基于抛物线近似的平滑算法;
- LRMASeries () - 基于线性回归的平滑算法;

- T3Series () - 基于 Tilson 算法的平滑算法。


平滑函数的实现

这些函数表示为以下文件:JJMASeries.mqh、JLiteSeries. mqh、JurXSeries. mqh、ParMASeries.mqh、LRMASeries.mqh、T3Series.mqh。

函数调用本身完全相同,唯一的区别是一些函数没有外部变量。此类函数通常用于处理作为外部变量的自定义数组和指标数组。依我看来,这样不一定很便捷,而使用此类函数处理正常变量而非数组,则会好很多。在这种情况下,可以在一个计算周期内使用这些算法进行无限次数的平滑处理!我认为,本文没有必要提供函数的代码。只有准备基于其他算法创建类似函数的人员才对代码感兴趣。我们感兴趣的仅仅是指标代码中(即函数的实际使用中)的函数调用算法。


JJMASeries ()
我们将开始使用函数 JJMASeries() 进行学习:
double JJMASeries(int number, int din, int MaxBar, int limit, 
                  int Phase, int Length, double series, int bar,
                  int& reset)

文件 JJMASeries.mqh 包含四个函数:JJMASeries()、JJMASeriesResize()、JJMASeriesAlert() 和 JMA_ErrDescr()。此文件还包含声明为全局变量的变量。

函数 JJMASeries() 设计用于在编写任何技术指标或 Expert Advisor 时使用 JMA 算法,以用此算法替代经典的平均计算。如果“limit”参数使用了零值,则此函数无法正常使用!我为 JJMASeries 开发的所有指标都考虑到了此限制。此文件必须保存在文件夹 MetaTrader\experts\include\ 中。必须注意,如果“bar”变量值超过了 MaxBar 变量值,JJMASeries() 函数将针对此柱返回零值!因此,在一些指标计算中,此值无法显示为一项分式!JJMASeries() 还会针对后续 30 个柱返回零!

当在 Expert Advisor 使用的自定义指标中使用时,此版 JJMASeries() 支持 Expert Advisor。此外,当在完全放置在 Expert 代码的指标代码中使用时,此版 JJMASeries() 支持 Expert Advisor,保留保存的所有 DO 语句和变量!在使用 JJMASeries 对指标或 Expert Advisor 进行编码时,不建议以 nJMA... 或 dJMA... 为开头命名变量。如果认为每次调用 JJMASeries() 时自定义函数都必须具有唯一的编号,则 JJMASeries() 函数可用于其他自定义函数的内部编码。此版 JJMASeries() 用于处理与当前图表的时间序列数组相关的变量!如果此函数应用于处理在其他图表的时间序列数组上计算的变量,则计算将不正确!


输入项:
- number - 指标代码中的 JJMASeries() 函数调用的次数 (0, 1, 2, 3, ...);
- din - 参数,允许修改每个柱上的“长度”和“相位”参数。0 - 参数无法更改,任何其他值允许更改参数;
- MaxBar - 计算的柱编号的最大值。它通常为 Bars-1-period,其中“period”为柱数量,无法根据其计算出初始序列值;
- limit - 未计算的柱数量+1 或者最后一个未计算的柱的编号。它必须等于 Bars-IndicatorCounted()-1;
- Length - 平均深度;
- Phase - 参数,变化范围为 -100 到 +100 之间。它会影响瞬变过程的质量;
- series - 输入项,作为 JJMASeries() 计算的基础;
- bar - 要计算的柱的编号。此参数必须由 DO 语句将其从最大值更改为零。其最大值必须始终等于“limit”的值!


输出参数:
- JMASeries() - JMA 值。如果“bar”参数值超过了 MaxBar-30,函数 JJMASeries() 将始终返回零!
- reset - 参考返回的参数,如果函数计算中发生了错误,则返回非零值;如果计算正确,则返回 0 。此参数只能是变量,而不能是值!


函数初始化
函数初始化 在调用 JJMASeries() 函数之前,当已计算的柱数 等于 0 时,应调整此函数的内部缓冲区变量大小(在自定义指标或 Expert Advisor 的初始化块中执行此操作会更佳)。为此,需要使用具有以下参数的帮助函数 JJMASeriesResize() 调用 JJMASeries() 的变量:JJMASeriesResize(number+1); 需要将参数“number”(MaxJMA.number) 设置为等于 JJMASeries 的调用次数, 即比“number”的最大值大 1。 除调整 JJMASeries() 的缓冲区大小外, 还可以在初始化块中检查指标输入值“长度”和“相位”, 它们是 JJMASeries() 输入项,使用 JJMASeriesAlert() 检查它们是否在变化范围以内。

JJMASeriesAlert(int Number, string name, int ExternVar)

- Number - 参数,可使用两个值:0 - 用于检查输入项 ExternVar 是否在 JJMASeries() 的“长度”输入项的变化范围以内;1 - 用于检查输入项 ExternVar 是否位于 JJMASeries() 的“相位”输入项的变化范围以内;
- name - 用于给出提醒的输入项 ExternVar 的字符串名称;

- ExternVar - 指标的输入项

错误指示

正在调试时,指标或 Expert Advisor 的代码可以包含错误。要找到错误的原因,需要查看日志文件。函数 JJMASeries() 在名为 \MetaTrader\EXPERTS\LOGS\ 的文件夹的日志文件中记录所有错误。如果在调用 JJMASeries() 函数之前此函数前面的代码中就存在 MQL4 错误,此函数将在日志文件中记录错误代码和内容。如果在执行函数 JJMASeries() 的过程中 JJMASeries() 算法中出现了 MQL4 错误,此函数也将在日志文件中记录错误代码和内容。如果 JJMASeries() 函数调用“number”指定错误或者定义了错误的缓冲区变量大小 nJJMAResize.Size,将在日志文件中记录有关错误参数的消息。同时也将在日志文件中记录有关“limit”参数的错误定义的信息。

如果在执行 init() 函数的过程中调整 JJMASeries 缓冲区大小失败,函数 JJMASeriesResize() 将在日志文件中记录有关调整失败的信息。如果在通过外部 DO 语句调用 JJMASeries() 函数时违反了“bar”参数变化的正确顺序,也将在日志文件中记录此信息。必须考虑到,代码中的一些错误会导致执行过程中发生更多错误,因此,如果 JJMASeries() 函数在日志文件中即时记录了多个错误,应按照错误的发生顺序消除这些错误。在正确编码的指标中,JJMASeries() 函数仅在操作系统混乱时才会在日志文件中进行记录。例外情况是记录每次调用 init() 函数时指标或 Expert Advisor 重启期间进行的缓冲区变量调整。将使用函数 JMA_ErrDescr() 将所有 MQL4 错误记录在日志文件中,此函数用于根据使用函数 GetLastError() 所获取的代码将代码和错误内容缓存到日志文件中。

JJMASeries() 函数调用示例(买入价的双倍 JMA 平滑处理):

/*
For the indicator to operate, files 
JJMASeries.mqh 
PriceSeries.mqh 
must be placed into the directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
into the directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        J2JMA.mq4 | 
//|                       JMA code: Copyright © 2005, Jurik Research | 
//|                                         http://www.jurikres.com/ | 
//|    MQL4 JJMASeries+J2JMA: Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+   
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Magenta 
//---- INDICATOR INPUTS 
extern int Length1 = 5; // depth of the first smoothing 
extern int Length2 = 5; // depth of the second smoothing 
// the first smoothing parameter changing within the range between -100 and +100, 
//it influences the transient quality; 
extern int Phase1  = 100;
// the second smoothing parameter changing in the range between -100 and +100, 
//it influences the transient quality; 
extern int Phase2  = 100;
// indicator shifting along the time axis 
extern int Shift   = 0;
/* Choosing of prices to be used for indicator calculations 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double J2JMA[];
//---- floating points variables  
double Temp_Series; 
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh>   
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| J2JMA indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
  {  
//---- defining of the chart drawing style
   SetIndexStyle (0, DRAW_LINE); 
//---- 1 indicator buffer is used for calculations
   SetIndexBuffer(0, J2JMA);
//---- horizontal shift of the indicator line 
   SetIndexShift (0, Shift);  
//---- placing of indicator values that will not be visible in the chart
   SetIndexEmptyValue(0, 0); 
//---- name for data windows and label for subwindows 
   IndicatorShortName ("J2JMA(Length1=" + Length1 + ", Phase1=" + Phase1 +
                       ", Length2=" + Length2 + ", Phase2=" + Phase2 + 
                       ", Shift=" + Shift + ")"); 
   SetIndexLabel (0, "J2JMA"); 
//---- Setting the indicator imaging precision format
   IndicatorDigits(Digits);
//----+ Resizing of buffer variables of function JJMASeries, 
//nJMAnumber=2(two calls for function JJMASeries)
   if(JJMASeriesResize(2) != 2)
       return(-1);
//---- setting alerts for nonaccepted values of external variables
   JJMASeriesAlert (0,"Length1", Length1);
   JJMASeriesAlert (0,"Length2", Length2);
   JJMASeriesAlert (1,"Phase1", Phase1 );
   JJMASeriesAlert (1,"Phase2", Phase2 );
   PriceSeriesAlert(Input_Price_Customs);
//---- complete initialization
   return(0); 
  } 
//+------------------------------------------------------------------+   
//| J2JMA iteration function                                         | 
//+------------------------------------------------------------------+ 
int start() 
  { 
//---- Bar quantity control over sufficiency for further calculations
   if(Bars - 1 < 61)
       return(0);
//----+ Introducing of integer variables and obtaining of bars already computed
   int reset, MaxBar1, MaxBar2, counted_bars = IndicatorCounted();
//---- checking for possible errors
   if(counted_bars < 0) 
       return(-1);
//---- the last counted bar should be recalculated 
//---- (without this recalculation for counted_bars, function JJMASeries will not 
//     operate correctly!!!)
   if(counted_bars > 0) 
       counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
   int limit = Bars - counted_bars - 1; 
   MaxBar1 = Bars - 1; 
   MaxBar2 = MaxBar1 - 30;
 
//----+ INDICATOR COMPUTING BASIC LOOP 
   for(int bar = limit; bar >= 0; bar--)
     {
       // Call for function PriceSeries to get the entry price Series
       Temp_Series = PriceSeries(Input_Price_Customs, bar);
       // Two calls fro function JJMASeries numbered as 0,1. Parameters 
       //nJMA.Phase and nJMA.Length 
       //do not change at each bar (nJMA.din=0)
       //(In the second call, parameter nJMA.MaxBar is decreased by 30 since it is 
       //the repeated JMA smoothing)
       Temp_Series = JJMASeries(0,0,MaxBar1,limit,Phase1,Length1,
                                Temp_Series,bar,reset);
       // checking for errors in the preceding operation
       if(reset != 0)
           return(-1);
       Temp_Series = JJMASeries(1,0,MaxBar2,limit,Phase2,Length2,
                                Temp_Series,bar,reset);
       // checking for errors in the preceding operation
       if(reset != 0)
           return(-1);
       J2JMA[bar] = Temp_Series;
     }
//---- complete calculation of indicator values
   return(0); 
  } 
//+--------------------------------------------------------+


因此,在应用此函数的过程中可突出以下几点:
1.声明函数属于文件 JJMASeries.mqh 的一部分,同时指标代码以 #include 行开头。声明变量和四个函数:JJMASeries()、JJMASeriesResize()、JJMASeriesAlert()、JMA_ErrDescr()。
2.通过函数 JJMASeries() 使用初始化块中的函数 JJMASeriesResize() 调整缓冲区元素的大小。
3.使用初始化块中的函数 JJMASeriesAlert() 检查指标外部变量即函数 JJMASeries() 的外部变量的值是否正确。
4.调用使用带相关错误控制的 DO 语句开发的函数 JJMASeries() 自身。>


其他函数

调用其他函数的算法与上述考虑的算法非常相似,但是在函数中的外部变量数量方面存在一些差异:
JJMASeries (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JLiteSeries(int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset)
JurXSeries (int number, int din, int MaxBar, int limit,
            int Length, double series, int bar, int&reset)
T3Series   (int number, int din, int MaxBar, int limit, int Phase,
            int Length, double series, int bar, int&reset )
ParMASeries(int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset)
LRMASeries (int number, int MaxBar, int limit, int period, 
            double series, int bar, int&reset )

应注意,函数 JJMASeries() 和 JLiteSeries() 在同一个 Expert Advisor 或指标中相互不兼容!的确,具有 JJMASeries() 函数名称的同一 JMA 代码被放置在文件 JLiteSeries.mqh 中,无自适应!在 Expert Advisor 或指标中,要用函数 JLiteSeries() 替换函数 JJMASeries(),足以用 #include 替换 #include 行。文件 JLiteSeries.mqh 的函数的所有调用与文件 JJMASeries.mqh 的函数的调用相同。

其他函数与同一个指标或 Expert Advisor 代码完全兼容。在函数 ParMASeries() 和 LRMASeries() 中,外部变量“period”的值限于 501。如果需要更大的值,需要分别在文件 ParMASeries.mqh 和 LRMASeries.mqh 中更改函数 ParMASeries() 的缓冲区 dParMA.TempBuffer[][501] 和 dParMA.TEMPBUFFER[][501] 或者函数 LRMASeries() 的缓冲区 dLRMA.TempBuffer[][501] 和 dLRMA.TEMPBUFFER[][501] 的第一个(非零)参数。>


函数 JurXSeries()

下面是函数的 JurXSeries() 的调用示例(买入价的超线性平滑处理以及额外的 JMA 平滑处理):

/*
For the indicator to operate, it is necessary to place files 

JurXSeries.mqh, 
JJMASeries.mqh, 
PriceSeries.mqh,  
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
This indicator is based on the smoothing algorithm of indicator JRSX.
The final result of this indicator bear some resemblance to 
double JMA smoothing, but is less perfect since it is simpler.
 
*/
//+------------------------------------------------------------------+
//|                                                        JJurX.mq4 | 
//|                           Copyright © 2006,     Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 1 
//---- color of the indicator
#property indicator_color1 Gold
//---- INDICATOR INPUTS 
extern int JurX_Length  = 5; // depth of JurX smoothing 
extern int JJMA_Length  = 4; // depth of JJMA smoothing 
// parameter of JJMA smoothing ranging between -100 and +100 
// influences the transient quality; 
extern int JJMA_Phase   = -100;
extern int Shift        = 0;      // indicator shift along the time axis 
/* Choosing of prices underlying the indicator calculations 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer[];
//---- floating point variables  
double Price,JurX,JJurX,Error;
//+------------------------------------------------------------------+
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+
//| JJurX indicator initialization function                          | 
//+------------------------------------------------------------------+ 
int init() 
{  
//---- defining of the charting style
SetIndexStyle (0,DRAW_LINE); 
//---- 1 indicator buffer is used to calculate
SetIndexBuffer(0,Ind_Buffer);
//---- horizontal shift of the indicator line 
SetIndexShift (0, Shift); 
//---- setting indicator values that will not be visible in the chart
SetIndexEmptyValue(0,0); 
//---- name for data windows and label for subwindows 
IndicatorShortName ("JJurX( JurX_Length="+JurX_Length+", Shift="+Shift+")"); 
SetIndexLabel (0, "JJurX"); 
//---- Setting the indicator imaging precision format
IndicatorDigits(Digits);
//----+ Resizing buffer variables of function JurXSeries, 
//      nJurXnumber=2
//(To calls for function JurXSeries)
if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries,
//      nJMAnumber=1
//(One call for function JJMASeries)
if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables  
JurXSeriesAlert(0,"JurX_Length",JurX_Length); 
JJMASeriesAlert(0,"JJMA_Length",JJMA_Length); 
JJMASeriesAlert(1,"JJMA_Phase",JJMA_Phase); 
PriceSeriesAlert(Input_Price_Customs);
//---- complete initialization
return(0); 
} 
//+-----------------------------------------------------------------------------+
//| JJurX iteration function                                                    | 
//+-----------------------------------------------------------------------------+
int start() 
{ 
//---- Bar quantity control over sufficiency for further calculations
if (Bars-1<JurX_Length+32)return(0);
//----+ Introducing of integer variables and obtaining of bars already computed
int reset,MaxBar,counted_bars=IndicatorCounted();
//---- checking for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar should be recalculated 
//(without this recalculation for counted_bars, function JurXSeries will not 
// operate correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
int limit=Bars-counted_bars-1; 
determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1; 
 
//----+ INDICATOR COMPUTING BASIC LOOP 
for(int bar=limit;bar>=0;bar--)
 {
  //----+ Call for function PriceSeries to get the entry
  //      price Series
  Price=PriceSeries(Input_Price_Customs,bar);
  //----+ One call for function JurXSeries numbered as 0. 
  //Parameter nJJurX.Length does not change on each bar (nJurXdin=0)
  JurX=JurXSeries(0,0,MaxBar,limit,JurX_Length,Price,bar,reset); 
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1); 
  //----+ detection of error in calculations of parameter JurX
  //----+ the second call for function JurXSeries numbered as 1. 
  //Parameter nJJurX.Length does not change on each bar (nJurXdin=0)
  Error=JurXSeries(1,0,MaxBar,limit,JurX_Length,100,bar,reset); 
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1);
  if(Error==0)Error=100;
  JurX*=100/Error;
  //----+ Call for function JJMASeries numbered as 0. 
  //      Parameters nJMA.Phase and nJMA.Length do not change on each bar 
  //      (nJMA.din=0)
  JJurX=JJMASeries(0,0,MaxBar,limit,JJMA_Phase,JJMA_Length,JurX,bar,reset);
  //----+ checking for errors in the preceding operation
  if(reset!=0)return(-1);
  Ind_Buffer[bar]=JJurX;                 
 }
//---- complete calculation of indicator values
return(0); 
} 
//+-------------------------------------------------------------------------+

在此示例中,应注意函数 JurXSeries() 计算买入价和常数的平均值!将平均结果除以常数值,我们将获得平滑处理误差。要获得更精确的价格区间平滑结果,需要将平滑结果除以此误差值。我们的例子中执行了此操作。在下述两个例子中,分子和分母分别进行了平滑处理,因此不需要执行上述程序。其他平滑函数不会出现此类误差。

下面是函数 JJMASeries() 和 JurXSeries() 的调用示例 (CCI 模拟以及额外的 JMA 平滑处理):

/*
For the indicator to operate, it is necessary to place files 
JJMASeries.mqh
JurSeries.mqh 
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+   
//|                                                        JCCIX.mq4 |
//|                               Copyright © 2006, Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+    
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in a separate window
#property indicator_separate_window
//---- amount of indicator buffers
#property indicator_buffers  1
//---- colors of indicator
#property indicator_color1  BlueViolet
//---- parameters of the indicator horizontal levels
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- INDICATOR INPUTS 
extern int  JJMA.Length = 8;  // depth of JJMA smoothing of entry price
// depth of JurX smoothing of the obtained indicator 
extern int  JurX.Length = 8;
// parameter ranging between -100 and +100 influences 
// the smoothing transient quality
extern int  JJMA.Phase = 100;
 /* Choosing of prices underlying the indicator calculations  
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer1[];
//---- integer constans 
int    w;
//+------------------------------------------------------------------+
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+  
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+ 
//| JCCIX initialization function                                    |
//+------------------------------------------------------------------+
int init()
 {
//---- indicator drawing styles
   SetIndexStyle(0,DRAW_LINE);
//---- 1 indicator buffer is used for calculations. 
   SetIndexBuffer(0,Ind_Buffer1);
//---- setting of the indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0); 
//---- names for data windows and labels for subwindows
   SetIndexLabel(0,"JCCIX");
   IndicatorShortName("JCCIX(JJMA.Length="+JJMA.Length+", JurX.Length"+
                      JurX.Length+")");
//---- Setting imaging precision format (count of characters after decimal point) 
//to visualize the indicator values  
   IndicatorDigits(2);
//----+ Resizing buffer variables of function JurXSeries, 
//      nJurXnumber=2
//(Two calls for function JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries, 
//      nJMAnumber=1
//(One call for function JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables
   JurXSeriesAlert (0,"JurX.Length",JurX.Length);
   JJMASeriesAlert (0,"JJMA.Length",JJMA.Length);
   JJMASeriesAlert (1,"JJMA.Phase",JJMA.Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- setting the bar number, starting from which the indicator will be 
//     drawn  
   SetIndexDrawBegin(0,JurX.Length+31);
//---- coefficients initialization to compute the indicator 
   if (JurX.Length>5) w=JurX.Length-1; else w=5;
//---- initialization complete
   return(0);
  }
//+------------------------------------------------------------------------+
//|  JCommodity Channel IndexX                                             |
//+------------------------------------------------------------------------+
int start()
  {
//---- Introducing of floating point variables    
double price,Jprice,JCCIX,UPCCI,DNCCI,JUPCCIX,JDNCCIX; 
//----+ Introducing of integer variables and getting bars already computed
int reset,MaxBar,MaxBarJ,limit,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
//---- (without this recalculation for counted_bars, functions JJMASeries 
//and JurXSeries will not work correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
limit=Bars-counted_bars-1; 
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1; MaxBarJ=MaxBar-30;
//---- correction of the start calculated bar in the loop
if(limit>=MaxBar)limit=MaxBar;
 
for(int bar=limit; bar>=0; bar--)
 { 
   //----+ Call for function PriceSeries to get entry 
   //      price Series
   price=PriceSeries(Input_Price_Customs, bar);
   //+----------------------------------------------------------------
   //----+ One call for function JJMASeries numbered as 0 
   //----+ Parameters nJMA.Phase and nJMA.Length do not change within  
   //      each bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   Jprice=JJMASeries(0,0,MaxBar,limit,JJMA.Phase,JJMA.Length,price,
                     bar,reset);
   //----+ check for errors in the preceding operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+    
   UPCCI=price-Jprice;         
   DNCCI=MathAbs(UPCCI);
   //----+ Two calls for function JurXSeries numbered as 0 and 1. 
           Parameter nJJurXLength does not 
   //change within each bar (nJurXdin=0)
   //----+ check for errors in the preceding operation
   JUPCCIX=JurXSeries(0,0,MaxBarJ,limit,JurX.Length,UPCCI,bar,reset); 
   if(reset!=0)return(-1); 
   JDNCCIX=JurXSeries(1,0,MaxBarJ,limit,JurX.Length,DNCCI,bar,reset); 
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBarJ-w)JCCIX=0;
   else 
     if (JDNCCIX!=0)
       {
        JCCIX=JUPCCIX/JDNCCIX;
        if(JCCIX>1)JCCIX=1;
        if(JCCIX<-1)JCCIX=-1;
       }
     else JCCIX=0;
   Ind_Buffer1[bar]=JCCIX; 
   //----+
 }
//----
   return(0);
  }
//+-------------------------------------------------------------------+

应考虑以下事实:在使用函数 JurXSeries() 进行两次平滑处理后,将检查其中一个获得的值是否不等于零,因为它将用作为分母!

下面是函数 JJMASeries() 和 JurXSeries 的调用示例 (RSI 模拟以及额外的 JMA 平滑处理):

/*
For the indicator to operate, it is necessary to place files  
JurXSeries.mqh
JJMASeries.mqh  
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                        JJRSX.mq4 |
//|    MQL4 JJRSX: Copyright © 2006,                Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in a separate window
#property indicator_separate_window
//---- amount of indicator buffers
#property indicator_buffers  1
//---- colors of the indicator
#property indicator_color1  BlueViolet
//---- parameters of the indicator horizontal levels
#property indicator_level1  0.5
#property indicator_level2 -0.5
#property indicator_level3  0.0
#property indicator_levelcolor MediumBlue
#property indicator_levelstyle 4
//---- INDICATOR INPUTS 
extern int  Length = 8;  // depth of JurX smoothing of the indicator
// depth of JJMA smoothing of the obtained indicator
extern int  Smooth = 3;
// parameter ranging between -100 and +100, influences 
//the smoothing transient quality
extern int  Phase = 100;
/* Choosing of prices, at which the indicator is computed 
(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi Low, 12-Heiken Ashi High,  13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double Ind_Buffer[];
//---- integer variables 
int    w;  
//+------------------------------------------------------------------+  
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function JurXSeries
//----+ Introducing of function JurXSeriesResize
//----+ Introducing of function JurXSeriesAlert 
//----+ Introducing of function JurX_ErrDescr  
#include <JurXSeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+---------------------------------------------------------------------+ 
//| JJRSX initialization function                                       |
//+---------------------------------------------------------------------+ 
int init()
  {
//---- indicator drawing styles
   SetIndexStyle(0,DRAW_LINE);
//---- 1 indicator buffer is used for counting. 
   SetIndexBuffer(0,Ind_Buffer);
//---- setting the indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0); 
//---- names for data windows and labels for subwindows
   SetIndexLabel(0,"JRSX");
   IndicatorShortName("JRSX(Length="+Length+", Input_Price_Customs="+
                      Input_Price_Customs+")");
//---- Setting imaging precision format (count of characters after decimal point) 
//to visualize the indicator values  
   IndicatorDigits(2);
//----+ Resizing buffer variables of function JurXSeries,
        nJurXnumber=2
//(Two calls for function JurXSeries)
   if (JurXSeriesResize(2)!=2)return(-1);
//----+ Resizing buffer variables of function JJMASeries,
        nJMAnumber=1
//(One call for function JJMASeries)
   if (JJMASeriesResize(1)!=1)return(-1);
//---- setting alerts for nonaccepted values of external variables
   JurXSeriesAlert (0,"Length",Length);
   JJMASeriesAlert (0,"Smooth",Smooth);
   JJMASeriesAlert (1,"Phase",Phase);
   PriceSeriesAlert(Input_Price_Customs);
//---- setting the bar number, starting from which there will be drawn the
       indicator  
   SetIndexDrawBegin(0,Length+31);
//---- correction of nonaccepted value ща parameter Length
   if(Length<1)Length=1; 
//---- coefficients initialization to compute the indicator 
   if (Length>5) w=Length-1; else w=5;
//---- initialization complete
return(0);
  }
//+-----------------------------------------------------------------------------+ 
//| JJRSX iteration function                                                    |
//+-----------------------------------------------------------------------------+ 
int start()
{
//---- Introducing floating point variables 
double dPrice,dPriceA,UPJRSX,DNJRSX,JRSX,JJRSX; 
//----+ Introducing of integer variables and obtaining of bars already computed
int bar,limit,reset,MaxBar,MaxBarJ,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-2; MaxBarJ=MaxBarJ-w-1; 
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
limit=Bars-counted_bars-1; 
//----+ 
if (limit>MaxBar){limit=MaxBar;Ind_Buffer[MaxBar]=0.0;}
 
for(bar=limit;bar>=0;bar--)
  {
   //----+ two calls for function PriceSeries to get the difference
   //      between entry prices dPrice
   dPrice = PriceSeries(Input_Price_Customs, bar)-
                        PriceSeries(Input_Price_Customs, bar+1);
   //----+  
   dPriceA=MathAbs(dPrice);
   //----+ Two calls for function JurXSeries numbered as 0 and 1. 
   //      Parameter nJJurXLength 
   //does not change on each bar (nJurXdin=0) 
   //check for errors in the preceding operation
   UPJRSX=JurXSeries(0,0,MaxBar,limit,Length,dPrice, bar,reset); 
   if(reset!=0)return(-1);
   DNJRSX=JurXSeries(1,0,MaxBar,limit,Length,dPriceA,bar,reset);
   if(reset!=0)return(-1); 
   //----+
   if (bar>MaxBar-w)JRSX=0;
   else if (DNJRSX!=0){JRSX=UPJRSX/DNJRSX;
   if(JRSX>1)JRSX=1;
   if(JRSX<-1)JRSX=-1;}else JRSX=0;
   //+---------------------------------------------------------------+ 
   //----+ One call for function JJMASeries numbered as 0 
   //----+ Parameters nJMA.Phase and nJMA.Length do not change 
   //      on each bar (nJMA.din=0)
   //+---------------------------------------------------------------+   
   JJRSX=JJMASeries(0,0,MaxBarJ,limit,Phase,Smooth,JRSX,bar,reset);
   //----+ check for errors in the preceding operation
   if(reset!=0)return(-1);
   //+---------------------------------------------------------------+  
   Ind_Buffer[bar]=JJRSX;  
}
//---- complete calculation of the indicator values
return(0);
}
//+------------------------------------------------------------------+



函数 T3Series()

下面是函数 T3Series() 的调用示例(三个波林格区间以及额外的 T3 平滑处理):

/*
To work with the indicator, files 
T3Series.mqh 
PriceSeries.mqh 
must be placed in directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
in directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                          T3.6Bollinger Bands.mq4 | 
//|                        Copyright © 2006,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing of the indicator in the main window
#property indicator_chart_window 
//---- amount of indicator buffers
#property indicator_buffers 7
//---- indicator color
#property indicator_color1 Gray 
#property indicator_color2 Red
#property indicator_color3 Blue 
#property indicator_color4 Lime
#property indicator_color5 Blue
#property indicator_color6 Red
#property indicator_color7 Gray 
//---- indicator line style
#property indicator_style1 4
#property indicator_style2 2
#property indicator_style3 4
#property indicator_style4 4
#property indicator_style5 4
#property indicator_style6 2
#property indicator_style7 4
//---- INDICATOR INPUTS 
// averaging period of J2Bollinger Bands
extern int        Bands_Period = 100;
extern double Bands_Deviations = 2.0; // deviation 
extern int         MA_method = 0;   // averaging method
// smoothing depth of the obtained Moving Avereges
extern int         MA_Smooth = 20;
// smoothing depth of the obtained Bollinger Bands
extern int        Bands_Smooth = 20;
// smoothing parameter ranging between -100 and +100, 
// influences the transient quality; 
extern int    Smooth_Curvature = 100;
// indicator shift along the time axis 
extern int         Bands_Shift = 0;
//Choosing of prices, on which the indicator is calculated 
/*(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW,
11-Heiken Ashi High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.)*/
extern int Input_Price_Customs = 0;
//---- indicator buffers
double UpperBuffer3  [];
double UpperBuffer2  [];
double UpperBuffer1  [];
double T3MovingBuffer[];
double LowerBuffer1  [];
double LowerBuffer2  [];
double LowerBuffer3  [];
double Series_buffer [];
//+------------------------------------------------------------------+ 
//----+ Introducing of function T3Series 
//----+ Introducing of function T3SeriesResize 
//----+ Introducing of function T3SeriesAlert 
//----+ Introducing of function T3_ErrDescr  
#include <T3Series.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+  
//| T3.6Bollinger Bands initialization function                      | 
//+------------------------------------------------------------------+  
int init()
  {
//---- defining the chart drawing style
   SetIndexStyle(0,DRAW_LINE); 
   SetIndexStyle(1,DRAW_LINE);
   SetIndexStyle(2,DRAW_LINE);
   SetIndexStyle(3,DRAW_LINE); 
   SetIndexStyle(4,DRAW_LINE);
   SetIndexStyle(5,DRAW_LINE); 
   SetIndexStyle(6,DRAW_LINE);
//---- 4 indicator buffers are used for calculations  
   IndicatorBuffers(8);
   SetIndexBuffer(0,UpperBuffer3 );
   SetIndexBuffer(1,UpperBuffer2 );
   SetIndexBuffer(2,UpperBuffer1 );
   SetIndexBuffer(3,T3MovingBuffer);
   SetIndexBuffer(4,LowerBuffer1 );
   SetIndexBuffer(5,LowerBuffer2 );
   SetIndexBuffer(6,LowerBuffer3 );
   SetIndexBuffer(7,Series_buffer);
//---- setting up indicator values that will not be visible in the chart
   SetIndexEmptyValue(0,0);

   SetIndexEmptyValue(1,0);
   SetIndexEmptyValue(2,0);
   SetIndexEmptyValue(3,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   SetIndexEmptyValue(6,0);
//---- setting up the bar number, starting from which the indicator
//     will be drawn  
   int drawbegin=100+Bands_Shift;
   SetIndexDrawBegin(0,drawbegin);
   SetIndexDrawBegin(1,drawbegin);
   SetIndexDrawBegin(2,drawbegin);
   SetIndexDrawBegin(3,drawbegin);
   SetIndexDrawBegin(4,drawbegin);
   SetIndexDrawBegin(5,drawbegin);
   SetIndexDrawBegin(6,drawbegin);
//---- horizontal shift of the indicator lines  
   SetIndexShift (0, Bands_Shift); 
   SetIndexShift (1, Bands_Shift); 
   SetIndexShift (2, Bands_Shift); 
   SetIndexShift (3, Bands_Shift); 
   SetIndexShift (4, Bands_Shift); 
   SetIndexShift (5, Bands_Shift); 
   SetIndexShift (6, Bands_Shift); 
//---- name for data windows and labels for subwindows
   IndicatorShortName ("T3.4Bollinger Bands( Period="+Bands_Period+
        ", Deviations="+Bands_Deviations+")"); 
   SetIndexLabel (0, "Upper3 Bands");
   SetIndexLabel (1, "Upper2 Bands");
   SetIndexLabel (2, "Upper1 Bands"); 
   SetIndexLabel (4, "Lower1 Bands"); 
   SetIndexLabel (5, "Lower2 Bands"); 
   SetIndexLabel (6, "Lower3 Bands"); 
   string Moving;
   switch(MA_method)
       {
        case  0: Moving= "T3SMA";break;
        case  1: Moving= "T3EMA";break;
        case  2: Moving="T3SSMA";break;
        case  3: Moving="T3LWMA";break;
        default: Moving="T3SMA";
       }
   SetIndexLabel (3, "Moving Avereges "+Moving+" ("+Bands_Period+")");
//---- Setting imaging precision format for the indicator 
   IndicatorDigits(Digits);
//----+ Resizing of buffer variables of function T3Series, 
//nT3.number=7(Seven calls for function T3Series)
   if (Bands_Smooth<=1){if (T3SeriesResize(1)!=1)return(-1);}
   else if (T3SeriesResize(7)!=7)return(-1);
//---- setting alerts for nonaccepted values of external variables
   T3SeriesAlert(0,"MA_Smooth",MA_Smooth);
   T3SeriesAlert(0,"Bands_Period",Bands_Period);
   PriceSeriesAlert(Input_Price_Customs);
   if((MA_method<0)||(MA_method>3))
        Alert("Parameter MA_method must range between 0 and 3" 
        + " You input a nonaccepted " 
       +MA_method+ "0 will be used");
//---- correction of the nonaccepted value of parameter Bands_Period
   if(Bands_Period<1)Bands_Period=1; 
//---- initialization complete
   return(0);
  }
//+------------------------------------------------------------------------+  
//| T3.6Bollinger Bands iteration function                                 | 
//+------------------------------------------------------------------------+  
int start()
  {
//---- check for whether the amount of bars is sufficient for calculations
if(Bars-1<=Bands_Period) return(0);
//---- Introducing of floating point variables  
double deviation1,deviation2,deviation3,Temp_Series,sum,midline,
       priceswing,Resalt;
//----+ Introducing of integer variables and getting the bars already calculated
int reset,MaxBar,MaxBarBB,MaxBarBB1,bar,kk,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
// (without this recalculation for counted_bars, function T3Series will not work
// correctly!!!)
if (counted_bars>0) counted_bars--;
//---- determining of the oldest bar number, starting from which new bars
//     will be recalculated
int limit=Bars-counted_bars-1;
//---- determining of the oldest bar number, starting from which all bars
//     will be recalculated
MaxBar=Bars-1-Bands_Period; MaxBarBB=MaxBar-30-Bands_Period; 
MaxBarBB1=MaxBarBB-1;
//----+ loading of entry prices into the buffer for calculations       
for(bar=limit;bar>=0;bar--)
    Series_buffer[bar]=PriceSeries(Input_Price_Customs,bar);
//---- checking whether the bars are sufficient for calculation of Bollinger Bands 
//---- zero initialization        
if (limit>MaxBar)
     {
      for(bar=limit;bar>=MaxBar;bar--)T3MovingBuffer[bar]=0;
      limit=MaxBar;
     }
//----+ Moving Averages calculation loop
for(bar=limit;bar>=0;bar--)
     {
      //----+ Moving Averages calculation formula
      Temp_Series=iMAOnArray(Series_buffer,0,Bands_Period,0,
                             MA_method, bar);
      //----+ smoothing of the obtained Moving Averages
      //----+ call for function T3Series numbered as 0. 
      // Parameters nT3.Curvature and nT3.Length do not change on 
      // each bar (nT3.din=0)
      Resalt=T3Series(0,0,MaxBar,limit,Smooth_Curvature,MA_Smooth,
                      Temp_Series,bar,reset);
      //----+ check for error in the preceding operation
      if(reset!=0)return(-1); 
      T3MovingBuffer[bar]=Resalt; 
     }     
//---- CALCULATION of Bollinger Bands 
//---- zero initialization      
if (limit>MaxBarBB)
     {
      for(bar=limit;bar>=MaxBarBB;bar--)
       {
        UpperBuffer2[bar]=0;
        UpperBuffer1[bar]=0;
        LowerBuffer1[bar]=0;
        LowerBuffer2[bar]=0;
       }
      limit=MaxBarBB;
     }
for(bar=limit;bar>=0;bar--)
   {       
     sum=0.0;
     midline=T3MovingBuffer[bar];
     kk=bar+Bands_Period-1;
     while(kk>=bar)
      {
       priceswing=PriceSeries(Input_Price_Customs,kk)-midline;
       sum+=priceswing*priceswing;
       kk--;
      }
     deviation2=Bands_Deviations*MathSqrt(sum/Bands_Period);     
     deviation1=0.5*deviation2;
     deviation3=1.5*deviation2;
     if (Bands_Smooth>1)
      {
       //----+ calculation and T3 smoothing of Bollinger Bands      
       //----+ ------------------------------------------------------+        
       //----+ six parallel calls for function T3Series numbered 
       //      as 1, 2, 3, 4, 5, 6. 
       //----+ Parameters nT3.Length do not change on each bar 
       //      (nT3.din=0)
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(1,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation3,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer3[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(2,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation2,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+       
       Resalt=T3Series(3,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline+deviation1,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       UpperBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(4,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation1,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer1[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(5,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation2,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer2[bar]=Resalt; 
       //----+ ------------------------------------------------------+ 
       Resalt=T3Series(6,0,MaxBarBB1,limit,Smooth_Curvature,Bands_Smooth,
                       midline-deviation3,bar,reset);
       //----+ check for errors in the preceding operation
       if(reset!=0)return(-1); 
       LowerBuffer3[bar]=Resalt;        
       //----+ ------------------------------------------------------+ 
      }
     else 
      {
       //----+ calculation of Bollinger Bands without T3 smoothing 
       UpperBuffer3[bar]=midline+deviation3; 
       UpperBuffer2[bar]=midline+deviation2;
       UpperBuffer1[bar]=midline+deviation1;
       LowerBuffer1[bar]=midline-deviation1;
       LowerBuffer2[bar]=midline-deviation2;
       LowerBuffer3[bar]=midline-deviation3;
      }
      
   }
//---- complete indicator calculations
   return(0);
  }
//+-------------------------------------------------------------------+



函数 ParMASeries()
下面是函数 ParMASeries() 的调用示例(ParMA 移动以及额外的 JMA 平滑处理):
/*
Moving average ParMA calculated on parabolic 
regression with bands 
 
for the indicator to work, one should place files 
JJMASeries.mqh 
ParMASeries.mqh 
PriceSeries.mqh 
to directory: MetaTrader\experts\include\
Heiken Ashi#.mq4
to directory: MetaTrader\indicators\
*/
//+------------------------------------------------------------------+ 
//|                                                       JParMA.mq4 |
//|                       ParMA MQL4 CODE: Copyright © 2006, alexjou |
//|             JParMA Indicator: Copyright © 2006, Nikolay Kositsin |
//+------------------------------------------------------------------+ 
#property copyright "Copyright © 2006, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- drawing the indicator in the main window
#property indicator_chart_window
//---- amount of indicator buffers
#property indicator_buffers 1
//---- color of the indicator 
#property indicator_color1 Red
//---- INDICATOR INPUTS 
extern int MA_Period  = 8; // ParMA period
extern int Length = 3;   // smoothing depth 
// parameter ranging between -100 and +100, 
//it influences the transient quality; 
extern int Phase  = 100;
extern int Shift  = 0;   // indicator shift along the time axis 
//Choosing of prices, at which the indicator is calculated 
/*(0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 6-WEIGHTED,
7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi High, 12-Heiken Ashi Low, 13-Heiken Ashi Open, 
14-Heiken Ashi Close.) */
extern int Input_Price_Customs = 0;
//---- indicator buffers
double IndBuffer[];
//---- float point variables 
double JResalt, Price, Resalt;
//+------------------------------------------------------------------+  
//----+ Introducing of function JJMASeries 
//----+ Introducing of function JJMASeriesResize 
//----+ Introducing of function JJMASeriesAlert  
//----+ Introducing of function JMA_ErrDescr  
#include <JJMASeries.mqh> 
//+------------------------------------------------------------------+ 
//----+ Introducing of function ParMAMASeries 
//----+ Introducing of function ParMASeriesResize 
//----+ Introducing of function ParMASeriesAlert 
//----+ Introducing of function ParMA_ErrDescr 
#include <ParMASeries.mqh> 
//+------------------------------------------------------------------+  
//----+ Introducing of function PriceSeries
//----+ Introducing of function PriceSeriesAlert 
#include <PriceSeries.mqh>
//+------------------------------------------------------------------+   
//| JParMA initialization function                                   |
//+------------------------------------------------------------------+ 
int init()
 {
  //---- Setting imaging precision format for the indicator
  IndicatorDigits(Digits);
  //---- defining the chart drawing style
  SetIndexStyle(0, DRAW_LINE);
  //---- 1 indicator buffer is used for calculations
  SetIndexBuffer(0, IndBuffer);
  //---- horizontal shift of the indicator line 
  SetIndexShift (0, Shift); 
  //---- setting the indicator values that will not be visible in
  //     the chart
  SetIndexEmptyValue(0, 0.0); 
  //---- name for data windows and label for subwindows 
  IndicatorShortName ("JParMA( Length="+Length+", Phase="+Phase+", Shift="+Shift+")");   
  SetIndexLabel(0, "JParMA Line");
  //---- setting the bar number, starting from which there will be drawn
         indicator 
  SetIndexDrawBegin(0, MA_Period);
  //----+ Resizing buffer variables of function JJMASeries, 
  //nJMAnumber=1(One call for function JJMASeries)
  if (JJMASeriesResize(1)!=1)return(-1);
  //----+ Resizing buffer variables of function ParMASeries, 
  //nParMAnumber=1(One call for function ParMASeries)
  if (ParMASeriesResize(1)!=1)return(-1);
  //---- setting alerts for nonaccepted values of external variables
  JJMASeriesAlert (0,"Length",Length);
  JJMASeriesAlert (1,"Phase", Phase );
  ParMASeriesAlert(0,"MA_Period",MA_Period);
  PriceSeriesAlert(Input_Price_Customs);
  return(0);
 }
//+-----------------------------------------------------------------------+ 
//| JParMA iteration function                                             |
//+-----------------------------------------------------------------------+ 
int start()
 {
 //---- check whether the amount of bars is sufficient for calculations
if (Bars-1<MA_Period)return(0);
//----+ Introducing of integer variables and getting bars already counted
int reset,MaxBar,MaxBarP,bar,Limit,counted_bars=IndicatorCounted();
//---- check for possible errors
if (counted_bars<0)return(-1);
//---- the last counted bar must be recalculated 
if (counted_bars>0) counted_bars--;
//---- defining the oldest bar number, starting from which all bars 
//will be recalculated
MaxBar=Bars-1; MaxBarP=MaxBar-MA_Period;

//---- defining the oldest bar number, starting from which new bars 
//will be recalculated 
Limit=Bars-counted_bars-1; 
 
//---- Indicator calculation
for (bar=Limit; bar>=0; bar--)
   { 
    //----+ 
     Price=PriceSeries(Input_Price_Customs,bar);
     //----+ getting the initial indicator
     //----+ Call for function ParMASeries numbered as 0
     Resalt=ParMASeries(0,MaxBar,Limit,MA_Period,Price,bar,reset); 
     //----+ check for errors in the preceding operation
     if(reset!=0)return(-1);
     //----+ JMA smoothing of the obtained indicator, 
     //parameter nJMA.MaxBar is decreased by MA_Period 
     //----+ Call for function JJMASeries numbered as 0, 
     // parameters nJMA.Phase and nJMA.Length do not change on each bar
     // (nJMA.din=0)
     JResalt=JJMASeries(0,0,MaxBarP,Limit,Phase,Length,Resalt,bar,reset);
     //----+ check for errors in the preceding operation
     if(reset!=0)return(-1);
     IndBuffer[bar]=JResalt;
   }
 //----
  return(0);
 }
 
//+-------------------------------------------------------------------+

在所有指标中,通常应用的时间序列数组 Close[] 用函数 PriceSeries() 替代。其使用不应引发任何问题:

double  PriceSeries(int Input_Price_Customs, int bar)

参数 Input_Price_Customs 的范围可在 0 与 14 之间。根据此参数的值,此函数依据柱的编号返回当前图表的价格值,用作为第二个参数:0-CLOSE,1-OPEN,2-HIGH,3-LOW, 4-MEDIAN,5-TYPICAL,6-WEIGHTED,7-Heiken Ashi Close,8-SIMPL,9-TRENDFOLLOW,10-0。5*TRENDFOLLOW,11-Heiken Ashi High,12-Heiken Ashi Low,13-Heiken Ashi Open,14-Heiken Ashi Close。如果需要,可在函数示例中编写一些其他代数学表达式,以基于时间序列数组定义买入价。使用函数 PriceSeries() 的指标对优化和测试 Expert Advisor 非常有帮助。


总结

在 NK_library.zip 中,有上百个使用上述算法编写的指标。这些示例足以了解如何使用本文中介绍的函数编写任何其他指标。压缩文件中的所有指标以及这些版本的平滑函数均支持 Expert Advisor,可与它们一起使用,而不会出问题。例外情况是名称以 HTF 结尾的指标。这些指标由于其特定计算而无法与 Expert Advisor 一起使用。压缩文件的文件夹中的指标应放置在 MetaTrader 4 客户终端的程序文件夹中:\MetaTrader\EXPERTS\indicators。这些函数本身位于文件夹 INCLUDE 中的压缩文件中。该文件夹的所有内容应放置在 MetaTrader 4 客户端的程序文件夹中:\MetaTrader\EXPERTS\INCLUDE 。