先进的自适应指标理论及在 MQL5 中的实施

26 十二月 2013, 07:25
1
3 353

测量循环周期

Ehlers 先生为 DeltaPhase 变量增加了几个限制：结果不能为负，且 DeltaPhase 局限于 <0.1, 1.1> 弧度（意味着 6 柱到 63 柱之间的周期）。看起来根据真实数据测得的 DeltaPhase 噪音非常大，因此需要平滑。

循环周期指标

```//+------------------------------------------------------------------+
//|                                                  CyclePeriod.mq5 |
//|                                               http://Investeo.pl |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window

#property description "CyclePeriod 指标 - John F. Ehlers 在"
#property description " \"股票和期货的控制分析\"一书中介绍"

#property indicator_buffers 2
#property indicator_plots 2
#property indicator_width1 1
#property indicator_width2 1
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "Cycle"
#property indicator_label2  "Trigger Line"

#define Price(i) ((high[i]+low[i])/2.0)

double Smooth[];
double Cycle[];
double Trigger[];
//double Price[];
double Q1[]; // 积分组件
double I1[]; // 同相组件
double DeltaPhase[];
double InstPeriod[];
double CyclePeriod[];

input double InpAlpha=0.07; // alpha
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
ArraySetAsSeries(Cycle,true);
ArraySetAsSeries(CyclePeriod,true);
ArraySetAsSeries(Trigger,true);
ArraySetAsSeries(Smooth,true);
//ArraySetAsSeries(Price,true);

SetIndexBuffer(0,CyclePeriod,INDICATOR_DATA);
SetIndexBuffer(1,Trigger,INDICATOR_DATA);

PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);

return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
{
//---
long tickCnt[1];
int i;
int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
if(ticks!=1) return(rates_total);
double DC, MedianDelta;

Comment(tickCnt[0]);

if(prev_calculated==0 || tickCnt[0]==1)
{
//--- 最近计数的柱将被重新计数
int nLimit=rates_total-prev_calculated-1; // 计算起点索引

ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);

ArrayResize(Smooth,Bars(_Symbol,_Period));
ArrayResize(Cycle,Bars(_Symbol,_Period));
//ArrayResize(Price,Bars(_Symbol,_Period));
ArrayResize(CyclePeriod,Bars(_Symbol,_Period));
ArrayResize(InstPeriod,Bars(_Symbol,_Period));
ArrayResize(Q1,Bars(_Symbol,_Period));
ArrayResize(I1,Bars(_Symbol,_Period));
ArrayResize(DeltaPhase,Bars(_Symbol,_Period));

if (nLimit>rates_total-7) // 为最近的柱做调整
nLimit=rates_total-7;

for(i=nLimit;i>=0 && !IsStopped();i--)
{
Smooth[i] = (Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0;

if (i<rates_total-7)
{
Cycle[i] = (1.0-0.5*InpAlpha) * (1.0-0.5*InpAlpha) * (Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2])
+2.0*(1.0-InpAlpha)*Cycle[i+1]-(1.0-InpAlpha)*(1.0-InpAlpha)*Cycle[i+2];

} else
{
Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0;
}

Q1[i] = (0.0962*Cycle[i]+0.5769*Cycle[i+2]-0.5769*Cycle[i+4]-0.0962*Cycle[i+6])*(0.5+0.08*InstPeriod[i+1]);
I1[i] = Cycle[i+3];

if (Q1[i]!=0.0 && Q1[i+1]!=0.0)
DeltaPhase[i] = (I1[i]/Q1[i]-I1[i+1]/Q1[i+1])/(1.0+I1[i]*I1[i+1]/(Q1[i]*Q1[i+1]));
if (DeltaPhase[i] < 0.1)
DeltaPhase[i] = 0.1;
if (DeltaPhase[i] > 0.9)
DeltaPhase[i] = 0.9;

MedianDelta = Median(DeltaPhase, i, 5);

if (MedianDelta == 0.0)
DC = 15.0;
else
DC = (6.28318/MedianDelta) + 0.5;

InstPeriod[i] = 0.33 * DC + 0.67 * InstPeriod[i+1];
CyclePeriod[i] = 0.15 * InstPeriod[i] + 0.85 * CyclePeriod[i+1];
Trigger[i] = CyclePeriod[i+1];
}
}
//--- 返回 prev_calculated 值用于下次调用
return(rates_total);
}
//+------------------------------------------------------------------+

double Median(double& arr[], int idx, int m_len)
{
double MedianArr[];
int copied;
double result = 0.0;

ArraySetAsSeries(MedianArr, true);
ArrayResize(MedianArr, m_len);

copied = ArrayCopy(MedianArr, arr, 0, idx, m_len);
if (copied == m_len)
{
ArraySort(MedianArr);
if (m_len %2 == 0)
result = (MedianArr[m_len/2] + MedianArr[(m_len/2)+1])/2.0;
else
result = MedianArr[m_len / 2];

}
else Print(__FILE__+__FUNCTION__+"中值错误 - 复制元素数目错误.");
return result;
}
```

循环周期指标

```//+------------------------------------------------------------------+
//|                                                   CyberCycle.mq5 |
//|                                               http://Investeo.pl |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window

#property description "CyberCycle 指标 - 由 John F. Ehlers 在"
#property description " \"股票和期货的控制分析\"一书中介绍"
#property description "本指标可以免费下载."

#property indicator_buffers 2
#property indicator_plots 2
#property indicator_width1 1
#property indicator_width2 1
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "Cycle"
#property indicator_label2  "Trigger Line"

#define Price(i) ((high[i]+low[i])/2.0)

double Smooth[];
double Cycle[];
double Trigger[];

input double InpAlpha=0.07; // alpha
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
ArraySetAsSeries(Cycle,true);
ArraySetAsSeries(Trigger,true);
ArraySetAsSeries(Smooth,true);

SetIndexBuffer(0,Cycle,INDICATOR_DATA);
SetIndexBuffer(1,Trigger,INDICATOR_DATA);

PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);

return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
{
//---
long tickCnt[1];
int i;
int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
if(ticks!=1) return(rates_total);

Comment(tickCnt[0]);

if(prev_calculated==0 || tickCnt[0]==1)
{
//--- 最近计数的柱将被重新计数
int nLimit=rates_total-prev_calculated-1; // 计算起点索引

ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);

ArrayResize(Smooth,Bars(_Symbol,_Period));
ArrayResize(Cycle,Bars(_Symbol,_Period));

if(nLimit>rates_total-4) // 为最新的柱做调整
nLimit=rates_total-4;

for(i=nLimit;i>=0 && !IsStopped();i--)
{
Smooth[i]=(Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0;

if(i<rates_total-5)
{
Cycle[i]=(1.0-0.5*InpAlpha) *(1.0-0.5*InpAlpha) *(Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2])
+2.0*(1.0-InpAlpha)*Cycle[i+1]-(1.0-InpAlpha)*(1.0-InpAlpha)*Cycle[i+2];
}
else
{
Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0;
}

//Print(__FILE__+__FUNCTION__+" 接收数值: ",rCnt);
Trigger[i]=Cycle[i+1];
}
}
//--- 返回 prev_calculated 值用于下次调用
return(rates_total);
}
//+------------------------------------------------------------------+

```

自适应周期性指标

```hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha);
if(hCyclePeriod==INVALID_HANDLE)
{
Print("CyclePeriod 指标不可用!");
return(-1);
}
```

然后再于 OnCalculate() 函数内读取它：

```int copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod);
if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
alpha1 = 2.0/(CyclePeriod[0]+1.0);
```

```//+------------------------------------------------------------------+
//|                                               http://Investeo.pl |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window

#property description "自适应 CyberCycle 指标 - 由 John F. Ehlers 在"
#property description " \"股票和期货的控制分析\"一书中介绍"
#property description "本指标可以免费下载."

#property indicator_buffers 2
#property indicator_plots 2
#property indicator_width1 1
#property indicator_width2 1
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "Cycle"
#property indicator_label2  "Trigger Line"

#define Price(i) ((high[i]+low[i])/2.0)

double Smooth[];
double Cycle[];
double Trigger[];

int hCyclePeriod;

input double InpAlpha=0.07; // 循环周期的 alpha
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
ArraySetAsSeries(Cycle,true);
ArraySetAsSeries(Trigger,true);
ArraySetAsSeries(Smooth,true);

SetIndexBuffer(0,Cycle,INDICATOR_DATA);
SetIndexBuffer(1,Trigger,INDICATOR_DATA);

PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);

hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha);
if(hCyclePeriod==INVALID_HANDLE)
{
Print("CyclePeriod 指标不可用!");
return(-1);
}
return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
{
//---
long tickCnt[1];
int i;
int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
if(ticks!=1) return(rates_total);
double CyclePeriod[1],alpha1;

Comment(tickCnt[0]);

if(prev_calculated==0 || tickCnt[0]==1)
{
//--- 最近计数的柱将被重新计数
int nLimit=rates_total-prev_calculated-1; // 计算起点索引

ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);

ArrayResize(Smooth,Bars(_Symbol,_Period));
ArrayResize(Cycle,Bars(_Symbol,_Period));

if(nLimit>rates_total-4) // 为最新的柱做调整
nLimit=rates_total-4;

for(i=nLimit;i>=0 && !IsStopped();i--)
{
Smooth[i]=(Price(i)+2*Price(i+1)+2*Price(i+2)+Price(i+3))/6.0;
int copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
alpha1 = 2.0/(CyclePeriod[0]+1.0);
//Print(alpha1);
//Print(CyclePeriod[0]);
if(i>=0)
{
Cycle[i]=(1.0-0.5*alpha1) *(1.0-0.5*alpha1) *(Smooth[i]-2.0*Smooth[i+1]+Smooth[i+2])
+2.0*(1.0-alpha1)*Cycle[i+1]-(1.0-alpha1)*(1.0-alpha1)*Cycle[i+2];

//Print("Smooth["+IntegerToString(i)+"]="+DoubleToString(Smooth[i])+" Cycle["+IntegerToString(i)+"]="+DoubleToString(Cycle[i]));
}
else
{
Cycle[i]=(Price(i)-2.0*Price(i+1)+Price(i+2))/4.0;
}

//Print(__FILE__+__FUNCTION__+" 接收数值: ",rCnt);
Trigger[i]=Cycle[i+1];
}
}
//--- 返回 prev_calculated 值用于下次调用
return(rates_total);
}
//+------------------------------------------------------------------+

```

请参见随附屏幕截图中的指标。

重心指标

```//+------------------------------------------------------------------+
//|                                              CenterOfGravity.mq5 |
//|                                               http://Investeo.pl |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window

#property description "重心指标 - 由 John F. Ehlers 在"
#property description " \"股票和期货的控制分析\"一书中介绍"
#property description "本指标可以免费下载."

#property indicator_buffers 2
#property indicator_plots 2
#property indicator_width1 1
#property indicator_width2 1
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "Cycle"
#property indicator_label2  "Trigger Line"

#define Price(i) ((high[i]+low[i])/2.0)

double Smooth[];
double Cycle[];
double Trigger[];

input double InpAlpha=0.07; // alpha
input int InpCGLength=10; //重心指标窗口尺寸

//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
ArraySetAsSeries(Cycle,true);
ArraySetAsSeries(Trigger,true);
ArraySetAsSeries(Smooth,true);

SetIndexBuffer(0,Cycle,INDICATOR_DATA);
SetIndexBuffer(1,Trigger,INDICATOR_DATA);

PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);

return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
{
//---
long tickCnt[1];
int i;
double Num, Denom; // 重心指标 的分子和分母
int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
if(ticks!=1) return(rates_total);

Comment(tickCnt[0]);

if(prev_calculated==0 || tickCnt[0]==1)
{
//--- 最近计数的柱将被重新计数
int nLimit=rates_total-prev_calculated-1; // 计算起点索引

ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);

ArrayResize(Smooth,Bars(_Symbol,_Period));
ArrayResize(Cycle,Bars(_Symbol,_Period));

if(nLimit>rates_total-InpCGLength) // 为最近的柱做调整
nLimit=rates_total-InpCGLength;

for(i=nLimit;i>=0 && !IsStopped();i--)
{
Num = 0.0;
Denom = 0.0;
for (int count=0; count<InpCGLength; count++)
{
Num += (1.0+count)*Price(i+count);
Denom += Price(i+count);
}
if (Denom != 0.0)
Cycle[i] = -Num/Denom+(InpCGLength+1.0)/2.0;
else
Cycle[i] = 0.0;

//Print(__FILE__+__FUNCTION__+" 接收数值: ",rCnt);
Trigger[i]=Cycle[i+1];
}
}
//--- 返回 prev_calculated 值用于下次调用
return(rates_total);
}
//+------------------------------------------------------------------+
```

自适应重心指标

```copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
CG_len = floor(CyclePeriod[0]/2.0);
```

```//+------------------------------------------------------------------+
//|                                               http://Investeo.pl |
//+------------------------------------------------------------------+
#property version   "1.00"
#property indicator_separate_window

#property description "自适应重心指标 - 由 John F. Ehlers 在"
#property description " \"股票和期货的控制分析\"一书中介绍"
#property description "本指标可以免费下载."

#property indicator_buffers 2
#property indicator_plots 2
#property indicator_width1 1
#property indicator_width2 1
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "Cycle"
#property indicator_label2  "Trigger Line"

#define Price(i) ((high[i]+low[i])/2.0)

double Smooth[];
double Cycle[];
double Trigger[];

int hCyclePeriod;

input double InpAlpha=0.07; // alpha
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
ArraySetAsSeries(Cycle,true);
ArraySetAsSeries(Trigger,true);
ArraySetAsSeries(Smooth,true);

SetIndexBuffer(0,Cycle,INDICATOR_DATA);
SetIndexBuffer(1,Trigger,INDICATOR_DATA);

PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0);

hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha);
if(hCyclePeriod==INVALID_HANDLE)
{
Print("CyclePeriod 指标不可用!");
return(-1);
}

return(0);
}
//+------------------------------------------------------------------+
//| 自定义指标迭代函数                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
{
//---
long tickCnt[1];
int i, copied;
double Num,Denom; // 重心指标的分子和分母
double CG_len;
int ticks=CopyTickVolume(Symbol(), 0, 0, 1, tickCnt);
if(ticks!=1) return(rates_total);
double CyclePeriod[1];

Comment(tickCnt[0]);

if(prev_calculated==0 || tickCnt[0]==1)
{
//--- 最近计数的柱将被重新计数
int nLimit=rates_total-prev_calculated-1; // 计算起点索引

ArraySetAsSeries(high,true);
ArraySetAsSeries(low,true);

ArrayResize(Smooth,Bars(_Symbol,_Period));
ArrayResize(Cycle,Bars(_Symbol,_Period));

copied=CopyBuffer(hCyclePeriod,0,0,1,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}

if(nLimit>rates_total-int(CyclePeriod[0])-2) // 为最近的柱做调整
nLimit=rates_total-int(CyclePeriod[0])-2;

for(i=nLimit;i>=0 && !IsStopped();i--)
{
copied=CopyBuffer(hCyclePeriod,0,i,1,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
CG_len = floor(CyclePeriod[0]/2.0);
//Print("CG_len="+DoubleToString(CG_len));

Num=0.0;
Denom=0.0;
for(int count=0; count<int(CG_len); count++)
{
Num+=(1.0+count)*Price(i+count);
Denom+=Price(i+count);
}
if(Denom!=0.0)
Cycle[i]=-Num/Denom+(CG_len+1.0)/2.0;
else
Cycle[i]=0.0;

//Print(__FILE__+__FUNCTION__+" 接收数值: ",rCnt);
Trigger[i]=Cycle[i+1];
}
}
//--- 返回 prev_calculated 值用于下次调用
return(rates_total);
}
//+------------------------------------------------------------------+
```

RVI 指标

RVI 代表的是相对能量指数 (Relative Vigor Index)。此指标背后的理念是：牛市中价格倾向于收盘价高于开盘价，而熊市中则倾向于收盘价低于开盘价。

```//+------------------------------------------------------------------+
//|                                                          RVI.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "2009, MetaQuotes Software Corp."
#property description "相对能量指数 (RVI)"
//--- 指标设置
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label1  "RVI"
#property indicator_label2  "Signal"
//--- 输入参数
input int InpRVIPeriod=10; // 周期数
//--- 指标缓冲区
double    ExtRVIBuffer[];
double    ExtSignalBuffer[];
//---
#define TRIANGLE_PERIOD  3
#define AVERAGE_PERIOD   (TRIANGLE_PERIOD*2)
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
void OnInit()
{
//--- 指标缓冲区映射
SetIndexBuffer(0,ExtRVIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA);
IndicatorSetInteger(INDICATOR_DIGITS,3);
//--- 设置需要绘出的第一个柱的索引
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+TRIANGLE_PERIOD);
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+AVERAGE_PERIOD);
//--- 数据窗口名称以及指标子窗口标签
IndicatorSetString(INDICATOR_SHORTNAME,"RVI("+string(InpRVIPeriod)+")");
PlotIndexSetString(0,PLOT_LABEL,"RVI("+string(InpRVIPeriod)+")");
PlotIndexSetString(1,PLOT_LABEL,"Signal("+string(InpRVIPeriod)+")");
//--- 初始化完成
}
//+------------------------------------------------------------------+
//| 相对能量指数                                                       |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,
const datetime &Time[],
const double &Open[],
const double &High[],
const double &Low[],
const double &Close[],
const long &TickVolume[],
const long &Volume[],
{
int    i,j,nLimit;
double dValueUp,dValueDown,dNum,dDeNum;
//--- 检查柱数
if(rates_total<=InpRVIPeriod+AVERAGE_PERIOD+2) return(0); // 退出返回0
//--- 检查可能的错误
if(prev_calculated<0) return(0); // 退出返回0
//--- 最近计数的柱将要重新计数
nLimit=InpRVIPeriod+2;
if(prev_calculated>InpRVIPeriod+TRIANGLE_PERIOD+2)
nLimit=prev_calculated-1;
//--- 为没有计算的柱设置空值
if(prev_calculated==0)
{
for(i=0;i<InpRVIPeriod+TRIANGLE_PERIOD;i++) ExtRVIBuffer[i]=0.0;
for(i=0;i<InpRVIPeriod+AVERAGE_PERIOD;i++)  ExtSignalBuffer[i]=0.0;
}
//--- RVI 在第一个缓冲区做计数
for(i=nLimit;i<rates_total && !IsStopped();i++)
{
dNum=0.0;
dDeNum=0.0;
for(j=i;j>i-InpRVIPeriod;j--)
{
dValueUp=Close[j]-Open[j]+2*(Close[j-1]-Open[j-1])+2*(Close[j-2]-Open[j-2])+Close[j-3]-Open[j-3];
dValueDown=High[j]-Low[j]+2*(High[j-1]-Low[j-1])+2*(High[j-2]-Low[j-2])+High[j-3]-Low[j-3];
dNum+=dValueUp;
dDeNum+=dValueDown;
}
if(dDeNum!=0.0)
ExtRVIBuffer[i]=dNum/dDeNum;
else
ExtRVIBuffer[i]=dNum;
}
//--- 信号线在第二个缓冲区做计数
nLimit=InpRVIPeriod+TRIANGLE_PERIOD+2;
if(prev_calculated>InpRVIPeriod+AVERAGE_PERIOD+2)
nLimit=prev_calculated-1;
for(i=nLimit;i<rates_total && !IsStopped();i++)
ExtSignalBuffer[i]=(ExtRVIBuffer[i]+2*ExtRVIBuffer[i-1]+2*ExtRVIBuffer[i-2]+ExtRVIBuffer[i-3])/AVERAGE_PERIOD;

//--- OnCalculate 完成. 返回新的prev_calculated.
return(rates_total);
}
//+------------------------------------------------------------------+

```

自适应 RVI 指标

```copied=CopyBuffer(hCyclePeriod,0,0,4,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
```

```//+------------------------------------------------------------------+
//|                        Based on RVI by MetaQuotes Software Corp. |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "2009, MetaQuotes Software Corp."
//--- 指标设置
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE
#property indicator_color1  Green
#property indicator_color2  Red
#property indicator_label2  "Signal"

#define Price(i) ((high[i]+low[i])/2.0)

//--- 输入参数
input int InpRVIPeriod=10; // 初始  RVI 周期数
//--- 指标缓冲区
double    ExtRVIBuffer[];
double    ExtSignalBuffer[];
//---
int hCyclePeriod;
input double InpAlpha=0.07; // 循环周期的 alpha

#define TRIANGLE_PERIOD  3
#define AVERAGE_PERIOD   (TRIANGLE_PERIOD*2)
//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
{
//--- 指标缓冲区映射
SetIndexBuffer(0,ExtRVIBuffer,INDICATOR_DATA);
SetIndexBuffer(1,ExtSignalBuffer,INDICATOR_DATA);
IndicatorSetInteger(INDICATOR_DIGITS,3);
hCyclePeriod=iCustom(NULL,0,"CyclePeriod",InpAlpha);
if(hCyclePeriod==INVALID_HANDLE)
{
Print("CyclePeriod 指标不可用!");
return(-1);
}

//--- 设置需要绘出的第一个柱的索引
PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+TRIANGLE_PERIOD);
PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,(InpRVIPeriod-1)+AVERAGE_PERIOD);
//--- 数据窗口名称以及指标子窗口标签
PlotIndexSetString(1,PLOT_LABEL,"Signal");
//--- 初始化完成
return 0;
}
//+------------------------------------------------------------------+
//| 相对能量指数                                                       |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,const int prev_calculated,
const datetime &Time[],
const double &Open[],
const double &High[],
const double &Low[],
const double &Close[],
const long &TickVolume[],
const long &Volume[],
{
int    i,j,nLimit;
double dValueUp,dValueDown,dNum,dDeNum;
double CyclePeriod[4];
int copied;

copied=CopyBuffer(hCyclePeriod,0,0,4,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
//--- 检查柱数
//--- 检查可能的错误
if(prev_calculated<0) return(0); // 退出返回0
//--- 最近计数的柱将要重新计数
nLimit=prev_calculated-1;
//--- 为没有计算的柱设置空值
if(prev_calculated==0)
{
}
//--- RVI 在第一个缓冲区做计数
for(i=nLimit;i<rates_total && !IsStopped();i++)
{
copied=CopyBuffer(hCyclePeriod,0,rates_total-i-1,4,CyclePeriod);

if(copied<=0)
{
Print("失败: 无法从 CyclePeriod 指标中取得数据.");
return -1;
}
dNum=0.0;
dDeNum=0.0;
{
//Print("rates_total="+IntegerToString(rates_total)+" nLimit="+IntegerToString(nLimit)+
dValueUp=Close[j]-Open[j]+2*(Close[j-1]-Open[j-1])+2*(Close[j-2]-Open[j-2])+Close[j-3]-Open[j-3];
dValueDown=High[j]-Low[j]+2*(High[j-1]-Low[j-1])+2*(High[j-2]-Low[j-2])+High[j-3]-Low[j-3];
dNum+=dValueUp;
dDeNum+=dValueDown;
}
if(dDeNum!=0.0)
ExtRVIBuffer[i]=dNum/dDeNum;
else
ExtRVIBuffer[i]=dNum;
}
//--- 信号线在第二个缓冲区做计数
nLimit=prev_calculated-1;
for(i=nLimit;i<rates_total && !IsStopped();i++)
ExtSignalBuffer[i]=(ExtRVIBuffer[i]+2*ExtRVIBuffer[i-1]+2*ExtRVIBuffer[i-2]+ExtRVIBuffer[i-3])/AVERAGE_PERIOD;

//--- OnCalculate 完成. 返回新的prev_calculated.
return(rates_total);
}
//+------------------------------------------------------------------+
```

总结

cybercycle.mq5 (7.72 KB)
cycleperiod.mq5 (11.59 KB)

| 26 12月 2013 在 16:21