环形数组(循环队列)

2019-04-23


经常在处理指标数据时,我们会碰到要采集一批数据,然后新数据来了之后,要在第0个数据更新,原来第0个到第N-1个数据ArrayCopy到第1到N个。这意味着总有内存读写操作,尽管CPU很快。

之前曾想如果形成环形数组,首尾相连,新来的数据不再存放在第0个位置,而是最后一个位置,同时用一个指针指向这个位置,下次新数据来时,转移到最老的N-1的位置。

后来发现这个想法在各个算法书里早有了,今天尝试把FX Pro Bot进行改写成功了,积累的经验如下。

首先,FX Pro Bot需要2个环形数组,一个是5元素的fast,一个是250元素的slow,我定义一个结构体,

struct LPA//环形数组
{
   int id;
   double data[];
   double sum;
};
LPA fa,sa;

其中,id当做指针,总是指向环形数组的尾巴,data[]用来存储数据,是个动态的,sum是我们要根据这个环形数组后续处理的计算值,这里是计算累加值。

   ArrayResize(fa.data,Favg);
   ArrayResize(sa.data,Savg);

通过ArrayResize限定结构体内部data成不同的元素个数,这种搞法居然也有效。

经过研究发现,在OnTick()主体里面不能搞太复杂,所以有必要在OnInit()里进行一次5元素和250元素的全面计算,这样只需要一次运算就ok了,避免在OnTick()主体里反复运算。

fa.id=Favg;sa.id=Savg;
fa.sum=0.0;sa.sum=0.0;
   int i;
   for(i = 0; i <Favg; i++) 
   {
      fa.data[i]= Close[1+i] - Open[1+i];
      fa.sum += fa.data[i];
   }
   for(i = 0; i <Savg; i++) 
   {
      sa.data[i]= MathAbs(Close[1+i+Offs] - Open[1+i+Offs]);
      sa.sum += sa.data[i];
   } 
   bt=Time[1];

其中,fa.id和sa.id要赋值大数而不是0,这是因为,在初始化中,是按0,1,2...N这样顺序赋值的(符合MT4的时间序列),在后面的EA主体里面,则是按倒序方式。

另外通过bt=Time[1];完成与后面主体的隔离,避免衔接错误。

下面在主体OnTick()里面就相当简单了,全是加减法操作,不涉及乘除法了,所以算法效率提升可不是一点点儿。

if(Time[1] != bt) 
   { 
      bt = Time[1];
      fa.id--;//新值要赋值给环形数组的尾巴
      if(fa.id<0)fa.id += Favg;//如果减过头了,重新开始
      fa.sum -= fa.data[fa.id];//先减
      fa.data[fa.id] = Close[1] - Open[1];//更新新值
      fa.sum += fa.data[fa.id];//后加,至此新值计算完毕
      //---慢速计算同理
      sa.id--;
      if(sa.id<0)sa.id += Savg;
      sa.sum -= sa.data[sa.id];
      sa.data[sa.id] = MathAbs(Close[1+ Offs] - Open[1+ Offs]);
      sa.sum += sa.data[sa.id];
     //---最后获取最终结果
      cA = (fa.sum/Favg)/(sa.sum/Savg); 
      Print("cA=",DoubleToStr(cA,2));
   } 



微信公众号:天泓评测


本博客所有文章如无特别注明均为原创。作者:天泓评测
分享到:更多

相关推荐

发表评论

路人甲 表情
Ctrl+Enter快速提交

网友评论(0)