MQL4 如何使数组不同?

MQL4 How to make an array distinct?

我需要将 MagicNumbers 挑选到一个数组中,然后使数组不同(有多个订单组,每个订单组都有唯一的 MagicNumbers )。但是有问题。我的代码是:

      int xxx = OrdersTotal();
      int magics[xxx];                               // here is an error:
                                                     //      invalid index value
      for ( int i = OrdersTotal() - 1; i >= 0; i-- ){

         if ( OrderSelect( i, SELECT_BY_POS ) ){

              magics[i] = OrderMagicNumber();        // choosing magics
              ArrayResize( magics,
                           ArraySize( magics ) + 1,
                           0
                           );
         }
      }

      ArraySort( magics );                           // making distinct
      int sorted[];
      int x = 0;
      for ( int i = 0; i < OrdersTotal() - 1; i++ ){ // duplicates = 0

         if ( magics[i] != magics[i+1] ){

              sorted[x] = magics[i];
              Print( "Sorted array: " + DoubleToStr( sorted[x] ) );
              x = x + 1;
         }
      }

如何选择不同的 MagicNumbers 到数组中?

MQL4 array-alike 对象和特殊数组函数的概念

首先要说的是,MQL4 数组检测并不像乍看起来那么微不足道。


是什么导致了以上报错?

Compile-time 数组大小的声明(int xxx,取决于 a-priori 未知的 OrdersTotal() 实际结果,在 run-time epoch too ), 应通过
数组的静态pre-allocation来解决,比如说int magicsARRAY[10000];,它允许编译器预分配内存并决定在 run-time 中的正确 array-handling (可以实现自己的 stack-mechanics 不溢出指向数组 tail-cell [参考下面的警告] )

可以将数组声明为variable-sized数组通过 int magicsARRAY[]; 用于编译器阶段,并允许 run-time re-allocate 具有 context-aware ArrayResize(...); 功能的实际大小 on-demand.

公平地说,high-performance / low-latency 代码 中的 良好实践 应避免和防止每一个run-time.

期间的内存 re-allocation

接下来,在管家服务上,将 MagNUMs 变成一个数组

如果内存(ArrayResize())re-allocation在运行时间里很贵,更多的都是dbPOOL体操 ( OrderSelect() + 以下所有 OP).

请记住,您的 Expert Advisor 代码已输入并执行 当且仅当 有一个market-event(价格刚刚变动),在任何其他情况下都没有。所以你的代码是被动的,(响应价格变动)所以你不能在职责上多花一微秒,这是可以避免的。

因此专业代码将静态数组维护为MagNUM-hash-tables,只是为了避免blind-re-iterations通过dbPOOL。如果你 运行 Strategy Tester 很多,你一定已经知道, re-iterate dbPOOL 优化过程中的 OPs batch-processing 以及优化问题 运行s 的速度,如果你有零-dbPOOL OPs。

所以最好的方法是在 OrderSend() 实例化中保持 MagNUM-s,在交易头寸的整个 life-cycle 中,并使用数组函数而不是 OrderSelect() + OrderMagicNumber() 循环。


数组在 MQL4 中可能非常有害且危险

如果试图访问数组范围之外的单元格,执行子系统将产生严重错误并且程序将停止。这是 Live-Trading 引擎永远不会遭受的!

试试这个代码。它将创建一个数组,循环遍历“历史”选项卡中的所有订单,检查订单的 MagicNumber 是否存在于数组中。如果不存在,则将其添加到数组中。您将以一组独特的 MagicNumbers 结束。

//+------------------------------------------------------------------+
//|                                                  UniqueMagic.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, joseph dot lee at fs dot com dot my"
#property link      "https://www.facebook.com/joseph.fhlee"
#property strict
void OnTick() {
   int vaiMagicNumbers[];  //Array containing list of MagicNumbers

   //Loop through all the Orders (in History tab)
   for(int viIndex=OrdersTotal()-1; viIndex>=0; viIndex--) {
      if(OrderSelect(viIndex, SELECT_BY_POS, MODE_HISTORY) ){
         //Check if the selected Order (in History tab) already exists in the array
         if(  fniGetElementIndex( vaiMagicNumbers, OrderMagicNumber() ) == -1 ) {
            //If not exists, then increase the array by 1, and add the MagicNumber into the array
            ArrayResize(vaiMagicNumbers, ArrayRange(vaiMagicNumbers,0)+1);
            vaiMagicNumbers[ArrayRange(vaiMagicNumbers,0)-1] = OrderMagicNumber();
         }
      }
   };
   Comment( ArrayRange(vaiMagicNumbers,0) ); //Show the number of unique MagicNumbers in the History tab.
}

//Function to return the index (position) of viValue within a given array
int fniGetElementIndex( int &vaiArray[], int viValue ) {
   int   viElementCount = ArrayRange(vaiArray, 0); //Get the total number of elements within that array.
   int   viFoundAt = -1;                           //The element index where viValue is found within the array.

   //Loop through every element in vaiArray
   for(int viElement=0; viElement<viElementCount; viElement++) {
      if( vaiArray[viElement] == viValue ) {
         //If the element value is the same as viValue, then FOUND, break the for loop.
         viFoundAt = viElement;
         break;
      }
   }
   return( viFoundAt );
}