mql5 언어의 특징, 미묘함 및 작업 방법 - 페이지 222

 
Maxim Kuznetsov # :

이것은 뉴스가 아니며 항상 태어날 때부터 그렇게 작동합니다.

데이터가 __atomic__보다 큰 경우에만 중요 섹션(또는 std::thread 터미널의 뮤텍스)으로 데이터에 액세스/보호해야 합니다.

글쎄요, 저는 그런 행동을 몰랐고, 가져올 때 별도의 과정을 예상했습니다.
로드된 각 MT5 프로그램에서 전역 DLL 포인터가 새로울 것이라고 생각했기 때문입니다.
나는 논리를 이해하는 데 땀을 흘려야했고 오류가 메모리에서 날아간 이유를 궁금해했습니다.
그러나 입력(인쇄)하여 이유를 이해했을 때 DLL 작업을 위한 전체 아키텍처 계획이 다르게 구축되었습니다.
젠장, 당신이 뮤텍스에 대해 옳았어, 당신은 그것에 대해 생각하지 않았습니다. 팁 고마워.

 
fxsaber # : PS 서브필드나 메소드가 작동하지 않는 점은 아쉽습니다.

네. 메소드에 매개변수가 없는 경우에도 다음을 수행할 수 있습니다.

 // Сортировка массива структур и указателей на объекты по методу.
#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 )

이 문제를 해결해 주시겠습니까? 당신에게는 아마도 쉬울 것 같지만 어디서부터 시작해야할지 모르겠습니다 :-)

 
이 주제와 관련이 없는 댓글은 "MQL4 및 MQL5 초보자를 위한 질문, 알고리즘 및 코드에 대한 도움말 및 토론"으로 이동되었습니다.
 

ArrayInsert를 사용할 때 Array_Destination[]이 요소가 추가되는 Array_Source[]보다 작으면 메모리를 절약할 수 있습니다.

이렇게 하려면 ArraySwap을 ArrayInsert 전과 후에 두 번 적용해야 합니다.


예를 들어, 이는 대용량 MqlTick 아카이브 등으로 작업할 때 적합합니다.

 

트레이딩, 자동매매 시스템 및 테스트 트레이딩 전략에 관한 포럼

mql5 언어의 특성, 미묘함 및 작업 기술

fxsaber, 2022.02.20 15:00

맞습니다, 감사합니다! 나는 곧은 곳에서 오버 머드릴. 나는 당신의 변형을 정렬하기 위해 떠날 것입니다.

응용 프로그램.

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.
사유: