mql5语言的特点、微妙之处以及技巧 - 页 222

 
Maxim Kuznetsov #:

这不是什么新鲜事,从出生开始就是这样的。

只有当数据大于__atomic__时,才应该用关键部分来包裹/保护访问(或者用mutex到终端std::线程)。

好吧,我不知道这种行为,还以为导入时有一个单独的过程。
我以为全局DLL指针将是新的,在每一个加载的MT5程序中。
,我不得不流汗去理解逻辑,想知道为什么错误会在内存中弹出。
但当我通过 try (print) 方法找出原因时,那么整个与 DLL 合作的架构计划将以不同方式建立。
伙计,你对突变的看法是对的,我没有想到这一点。谢谢你的提示。

 
fxsaber #: ZZY 很遗憾,你不能按子领域或方法来做。

是的,尽管如果该方法没有参数,你可以这样做。

// Сортировка массива структур и указателей на объекты по методу.
#define  ArraySortStruct_DefineMethod(METHOD)                                     \
namespace SortOnMethod_##METHOD                                                  \
{                                                                                \
  class SORT                                                                     \
  {                                                                              \
  private:                                                                       \
    template <typename T>                                                        \
    static void Swap( T &Array[], const int i, const int j )                     \
    {                                                                            \
      const T Temp = Array[i];                                                   \
                                                                                 \
      Array[i] = Array[j];                                                       \
      Array[j] = Temp;                                                           \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static int Partition( T &Array[], const int Start, const int End )           \
    {                                                                            \
      int Marker = Start;                                                        \
                                                                                 \
      for (int i = Start; i <= End; i++)                                         \
        if (Array[i].##METHOD() <= Array[End].##METHOD())                        \
        {                                                                        \
          SORT::Swap(Array, i, Marker);                                          \
                                                                                 \
          Marker++;                                                              \
        }                                                                        \
                                                                                 \
       return(Marker - 1);                                                       \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static void QuickSort( T &Array[], const int Start, const int End )          \
    {                                                                            \
      if (Start < End)                                                           \
      {                                                                          \
        const int Pivot = Partition(Array, Start, End);                          \
                                                                                 \
        SORT::QuickSort(Array, Start, Pivot - 1);                                \
        SORT::QuickSort(Array, Pivot + 1, End);                                  \
      }                                                                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
  public:                                                                        \
    template <typename T>                                                        \
    static void Sort( T &Array[], int Count = WHOLE_ARRAY, const int Start = 0 ) \
    {                                                                            \
      if (Count == WHOLE_ARRAY)                                                  \
        Count = ::ArraySize(Array);                                              \
                                                                                 \
      SORT::QuickSort(Array, Start, Start + Count - 1);                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
  };                                                                             \
}

#define  ArraySortStructMet(ARRAY, METHOD) SortOnMethod_##METHOD::SORT::Sort(ARRAY)

申请。

#include <fxsaber\TypeToBytes.mqh>

struct MqlRates2: public MqlRates
  {
   double            Open() {return open;}
  };

ArraySortStruct_DefineMethod(Open)

void OnStart()
  {
   MqlRates Rates[];

   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары

   MqlRates2 Rates2[];
   _ArrayCopy(Rates2, Rates);


   Print("\nСортируем Rates2 по open-цене.");
   ArraySortStructMet(Rates2, Open);
   ArrayPrint(Rates2);

  }
 

随着订单的部分执行,字段ORDER_TIME_SETUP_MSC 发生变化。

因此,DEAL_TIME_MSC 可以小于其订单的ORDER_TIME_SETUP_MSC

 

使用一个自定义的比较函数怎么样。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
typedef double(*TComparer)(MqlRates &a, MqlRates &b);

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class SORT
  {
private:
   template <typename T>
   static void       Swap(T &Array[], const int i, const int j)
     {
      const T Temp = Array[i];

      Array[i] = Array[j];
      Array[j] = Temp;

      return;
     }

   template <typename T>
   static int        Partition(T &Array[], const int Start, const int End, TComparer Compare)
     {
      int Marker = Start;

      for(int i = Start; i <= End; i++)
         if(Compare(Array[i], Array[End]) <= 0)
           {
            SORT::Swap(Array, i, Marker);

            Marker++;
           }

      return(Marker - 1);
     }

   template <typename T>
   static void       QuickSort(T &Array[], const int Start, const int End, TComparer Compare)
     {
      if(Start < End)
        {
         const int Pivot = Partition(Array, Start, End, Compare);

         SORT::QuickSort(Array, Start, Pivot - 1, Compare);
         SORT::QuickSort(Array, Pivot + 1, End, Compare);
        }

      return;
     }

public:
   template <typename T>
   static void       Sort(T &Array[], TComparer Compare, int Count = WHOLE_ARRAY, const int Start = 0)
     {
      if(Count == WHOLE_ARRAY)
         Count = ::ArraySize(Array);

      SORT::QuickSort(Array, Start, Start + Count - 1, Compare);

      return;
     }
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double compare_open(MqlRates &a, MqlRates &b)          { return a.open - b.open;     }
double compare_high(MqlRates &a, MqlRates &b)          { return a.high - b.high;     }
double compare_low(MqlRates &a, MqlRates &b)           { return a.low  - b.low;      }
double compare_close(MqlRates &a, MqlRates &b)         { return a.close - b.close;   }
double compare_time(MqlRates &a, MqlRates &b)          { return (double)(a.time - b.time); }
double compare_tick_volume(MqlRates &a, MqlRates &b)   { return (double)(a.tick_volume - b.tick_volume); }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   MqlRates Rates[];

   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates);
   ArrayPrint(Rates);

   SORT::Sort(Rates, compare_open);
   ArrayPrint(Rates);
  }
 
fxsaber #:

你是对的,谢谢你!我在一个平坦的地方做得过头了。我会留下你的变体进行分类。


应用。


ZZY 很遗憾,按子字段或方法,它不起作用。

这里是我的库中优化的QuickSort,根据你的要求稍作调整。

它可以对巨大的数组进行排序而不会出现堆栈溢出(由于不受控制的递归)。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
typedef double(*TComparer)(MqlRates &a, MqlRates &b);

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class SORT
  {
private:
   //+------------------------------------------------------------------+
   //| Swaps two variables or two array elements.                       |
   //+------------------------------------------------------------------+
   template<typename T>
   static void       Swap(T &var1, T &var2)
     {
      T temp = var1;
      var1 = var2;
      var2 = temp;
     }
   //+------------------------------------------------------------------+
   //| Insertion Sort                                                   |
   //+------------------------------------------------------------------+
   /**
    * Sort the input array in-place in ascending order.
    * Insertion sort is the fastest sort algorithm for very small
    * arrays (<10-20 elements), or when the input is almost sorted.
    */
   template<typename T>
   static void       InsertionSort(T &arr[], int lo, int hi, TComparer Compare)
     {
      for(int i = lo + 1; i <= hi; i++)
        {
         if(Compare(arr[i], arr[i - 1]) < 0)
           {
            T key = arr[i];
            int j = i - 1;
            while(j >= lo && Compare(arr[j], key) > 0)
              {
               arr[j + 1] = arr[j];
               j--;
              }
            arr[j + 1] = key;
           }
        }
     }
   //+------------------------------------------------------------------+
   //| Quick Sort (Optimized)                                           |
   //+------------------------------------------------------------------+
   /**
    * Sort the input array in-place in ascending order.
    * Generally, the fastest comparison-based sort algorithm for arrays.
    * (esp. if large size).
    * Average time complexity: O(n log n)
    * Worst-case time complexity: O(n log n)
    * Stable    : no
    *
    * Improvements:
    *
    * 1. Use insertion sort for small partitions, takes linear time O(n + I) with nearly sorted data.
    * 2. Choose pivot as the middle element, to avoid the worst case O(n^2) on already-sorted data.
    * 3. Hoare's parition scheme, which is more efficient than Lomuto's partition scheme
    *    because it does three times fewer swaps on average, and it creates efficient
    *    partitions even when all values are equal (duplicate sort keys).
    * 4. Sort small partitions using recursion and do tail recursion elimination for large partitions.
    *    This guarantees O(logn) space complexity and avoids stack overflow with huge arrays.
    */
   template<typename T>
   static void       QuickSort(T &arr[], int lo, int hi, TComparer Compare)
     {
      // Use a while loop for tail recursion elimination.
      while(lo < hi)
        {
         // Insertion sort is faster for small partitions.
         if(hi - lo < 16)
           {
            InsertionSort(arr, lo, hi, Compare);
            return;
           }

         // Pick pivot as the middle element.
         int mid = lo + (hi - lo) / 2;
         T pivot = arr[mid];

         // Hoare’s partition scheme.
         int i = lo;
         int j = hi;
         while(i <= j)
           {
            while(Compare(arr[i], pivot) < 0)
               i++;
            while(Compare(arr[j], pivot) > 0)
               j--;
            if(i <= j)
              {
               Swap(arr[i], arr[j]);
               i++;
               j--;
              }
           }
         // now, a[lo..j] <= a[i..hi]

         // Sort the small partition first using recursion and do tail recursion elimination for
         // the large partition.
         int l_size = j - lo;
         int r_size = hi - i;
         if(l_size < r_size)
           {
            if(l_size > 0)
              {
               QuickSort(arr, lo, j, Compare);
              }
            lo = i;
           }
         else
           {
            if(r_size > 0)
              {
               QuickSort(arr, i, hi, Compare);
              }
            hi = j;
           }
        }
     }

public:
   template<typename T>
   static void       Sort(T &Array[], TComparer Compare, int Count = WHOLE_ARRAY, const int Start = 0)
     {
      if(Count == WHOLE_ARRAY)
         Count = ::ArraySize(Array);

      SORT::QuickSort(Array, Start, Start + Count - 1, Compare);
     }
  };

//+------------------------------------------------------------------+
//| Compares two fields and returns a value indicating whether one   |
//| is equal to, less than, or greater than the other.               |
//+------------------------------------------------------------------+
double compare_open(MqlRates &a, MqlRates &b)          { return a.open - b.open;     }
double compare_high(MqlRates &a, MqlRates &b)          { return a.high - b.high;     }
double compare_low(MqlRates &a, MqlRates &b)           { return a.low  - b.low;      }
double compare_close(MqlRates &a, MqlRates &b)         { return a.close - b.close;   }
double compare_time(MqlRates &a, MqlRates &b)          { return (double)(a.time - b.time); }
double compare_tick_volume(MqlRates &a, MqlRates &b)   { return (double)(a.tick_volume - b.tick_volume); }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   MqlRates Rates[];

   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates);
   ArrayPrint(Rates);

   SORT::Sort(Rates, compare_open);
   ArrayPrint(Rates);

   SORT::Sort(Rates, compare_tick_volume);
   ArrayPrint(Rates);
  }
 
Bodolino #:

嗨,谢谢你的分享

如果能成功的话,这将是完美的。但是,当粘贴到一个.mq5脚本中并执行时,不幸的是,你的代码出现了以下错误。

  • 模板声明在本地类中是不允许的 ArraySortStruct.mq5 87 4
  • (在稍微 修改了你的代码后): 模板声明只允许在全局、命名空间或类的范围内进行 ArraySortStruct.mq5 90 4 )

能否请你解决这个问题?对你来说,这可能很容易,而我不知道从哪里开始 :-)

 

使用 ArrayInsert 时,如果 Array_Destination[] 小于添加元素的 Array_Source[],则可以节省内存。

为此,应在 ArrayInsert 之前和之后两次应用 ArraySwap。


例如,在处理大型 MqlTick 存档等时就需要使用 ArraySwap。

 

交易、自动交易系统和交易策略测试论坛

mql5 语言的特殊性、微妙之处和工作技巧

fxsaber, 2022.02.20 15:00

你是对的,谢谢!我在一个直的地方overmudryl。我会留下你的变体进行排序。

应用。

ArraySortStruct_Define(open)
ArraySortStruct_Define(high)
ArraySortStruct_Define(time)

void OnStart()
{
  MqlRates Rates[];
  
  CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары
  
  Print("\nБары без сортировки - как получили.");
  ArrayPrint(Rates);
  
  Print("\nСортируем по open-цене.");
  ArraySortStruct(Rates, open);
  ArrayPrint(Rates);
  
  Print("\nСортируем по high-цене.");
  ArraySortStruct(Rates, high);
  ArrayPrint(Rates);
  
  Print("\nСортируем по времени.");
  ArraySortStruct(Rates, time);
  ArrayPrint(Rates);
}

分区方法中存在错误。更正后的版本。

// Сортировка массива структур и указателей на объекты по полю.
#define  ArraySortStruct_Define(FIELD)                                            \
namespace SortOnField_##FIELD                                                    \
{                                                                                \
  class SORT                                                                     \
  {                                                                              \
  private:                                                                       \
    template <typename T>                                                        \
    static void Swap( T &Array[], const int i, const int j )                     \
    {                                                                            \
      const T Temp = Array[i];                                                   \
                                                                                 \
      Array[i] = Array[j];                                                       \
      Array[j] = Temp;                                                           \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static int Partition2 ( T &Array[], const int Start, const int End )         \
    {                                                                            \
      const T Pivot = Array[End];                                                \
      int i = (Start - 1);                                                       \
                                                                                 \
      for (int j = Start; j < End; j++)                                          \
        if (Array[j].##FIELD < Pivot.##FIELD)                                    \
          SORT::Swap(Array, ++i, j);                                             \
                                                                                 \
      SORT::Swap(Array, i + 1, End);                                             \
                                                                                 \
      return(i + 1);                                                             \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static void QuickSort( T &Array[], const int Start, const int End )          \
    {                                                                            \
      if (Start < End)                                                           \
      {                                                                          \
        const int Pivot = SORT::Partition2(Array, Start, End);                   \
                                                                                 \
        SORT::QuickSort(Array, Start, Pivot - 1);                                \
        SORT::QuickSort(Array, Pivot + 1, End);                                  \
      }                                                                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
  public:                                                                        \
    template <typename T>                                                        \
    static void Sort( T &Array[], int Count = WHOLE_ARRAY, const int Start = 0 ) \
    {                                                                            \
      if (Count == WHOLE_ARRAY)                                                  \
        Count = ::ArraySize(Array);                                              \
                                                                                 \
      SORT::QuickSort(Array, Start, Start + Count - 1);                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
  };                                                                             \
}

#define  ArraySortStruct(ARRAY, FIELD) SortOnField_##FIELD::SORT::Sort(ARRAY)
 
fxsaber #:

分区方法中存在错误。已更正版本。

针对数字字段被用于排序的特殊情况(最常见的情况),我编写了一个变体,它比之前的变体快了几个数量级。但它消耗的内存是前者的两倍。它适用于大型数组。

// Сортировка массива структур и указателей на объекты по ЧИСЛОВОМУ полю.
#define  ArraySortStruct2_Define(FIELD)                               \
namespace SortOnField_##FIELD                                        \
{                                                                    \
  class SORT2                                                        \
  {                                                                  \
  private:                                                           \
    template <typename T, typename T2>                               \
    static void Sort( T &Array[], const T2& )                        \
    {                                                                \
      T2 SortIndex[][2];                                             \
                                                                     \  
      const int Size = ::ArrayResize(SortIndex, ::ArraySize(Array)); \
                                                                     \
      for (int i = Size - 1; i >= 0; i--)                            \
      {                                                              \
        SortIndex[i][0] = (T2)Array[i].##FIELD;                      \
        SortIndex[i][1] = (T2)i;                                     \
      }                                                              \
                                                                     \
      ::ArraySort(SortIndex);                                        \
                                                                     \
      T Sort_Array[];                                                \
                                                                     \
      for (int i = ::ArrayResize(Sort_Array, Size) - 1; i >= 0; i--) \
        Sort_Array[i] = Array[(int)SortIndex[i][1]];                 \
                                                                     \
      ::ArraySwap(Sort_Array, Array);                                \
                                                                     \
      return;                                                        \
    }                                                                \
                                                                     \
  public:                                                            \
    template <typename T>                                            \
    static void Sort( T &Array[] )                                   \
    {                                                                \
      if (::ArraySize(Array))                                        \
        SORT2::Sort(Array, Array[0].##FIELD);                        \
                                                                     \
      return;                                                        \
    }                                                                \
  };                                                                 \
}

#define  ArraySortStruct2(ARRAY, FIELD) SortOnField_##FIELD::SORT2::Sort(ARRAY)


应用(测量执行时间)。

#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279
#define _BV2(A) _BV(A, 100) // Алертим все, что исполняется дольше 100 микросекунд.

struct STRUCT : public MqlTick
{
  double Num;
};

ArraySortStruct_Define(Num)
ArraySortStruct2_Define(Num)

void OnStart()
{
  STRUCT Array[];
  
  const int Size = ArrayResize(Array, 1 e5);
  
  for (int i = Size - 1; i >= 0; i--)
    Array[i].Num = Size - i;
    
//  _BV2(ArraySortStruct(Array, Num));
  _BV2(ArraySortStruct2(Array, Num));
}


结果

Alert: Bench_Stack = 0, 100 <= Time[Test9.mq5 129 in OnStart: SortOnField_Num::SORT::Sort(Array)] = 34574468 mcs.

Alert: Bench_Stack = 0, 100 <= Time[Test9.mq5 130 in OnStart: SortOnField_Num::SORT2::Sort(Array)] = 10586 mcs.