Caractéristiques du langage mql5, subtilités et techniques - page 222

 
Maxim Kuznetsov #:

Ce n'est pas nouveau, c'est la façon dont cela a toujours fonctionné depuis la naissance.

Ce n'est que si les données sont plus grandes que __atomique__ que l'accès doit être enveloppé/protégé avec des sections critiques (ou mutex vers std::thread terminal).

Je ne connaissais pas ce comportement, et je m'attendais à un processus distinct lors de l'importation.
Je pensais que les pointeurs DLL globaux seront nouveaux, dans chaque programme MT5 chargé.
Avec ce que j'ai dû transpirer pour comprendre la logique, en me demandant pourquoi l'erreur apparaîtra en mémoire.
Mais quand j'ai trouvé la raison par la méthode try (print), alors tout le plan architectural de travail avec les DLL sera construit différemment.
Mec, tu as raison pour les mutex, je n'y avais pas pensé. Merci pour le conseil.

 
fxsaber #: ZZY C'est dommage que vous ne puissiez pas le faire par sous-domaine ou par méthode.

Oui. Bien que si la méthode n'a pas de paramètres, vous pouvez le faire :

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

Application :

#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);

  }
 

Lorsque les ordres sont exécutés partiellement, le champORDER_TIME_SETUP_MSC change.

En conséquence, DEAL_TIME_MSC peut être inférieur à ORDER_TIME_SETUP_MSC de son ordre.

 

Pourquoi ne pas utiliser une fonction de comparaison personnalisée ?

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 #:

Vous avez raison, merci ! J'ai exagéré sur un point plat. Je laisse votre variante pour le tri.


Application.


ZZY C'est dommage, par sous-domaine ou par méthode, ça ne marche pas.

Voici le QuickSort optimisé de ma bibliothèque, légèrement adapté à vos besoins.

Il peut trier des tableaux énormes sans débordement de pile (à cause de la récursion incontrôlée).

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 #:

Bonjour et merci de partager !

Ce serait parfait si cela fonctionnait. Cependant, lorsqu'il est collé dans un script .mq5 et exécuté, votre code génère malheureusement la ou les erreurs suivantes :

  • les déclarations de template ne sont pas autorisées dans les classes locales ArraySortStruct.mq5 87 4
  • (après avoir légèrement modifié votre code) : les déclarations de modèles sont autorisées uniquement dans le cadre global, l'espace de nom ou la classe ArraySortStruct.mq5 90 4 )

Pourriez-vous corriger ce problème ? Pour vous, c'est probablement facile, alors que je ne saurais pas par où commencer :-)

 
 

Lorsque vous utilisez ArrayInsert, vous pouvez économiser de la mémoire lorsque Array_Destination[] est plus petit que Array_Source[] à partir duquel les éléments sont ajoutés.

Pour ce faire, vous devez appliquer ArraySwap deux fois : avant et après ArrayInsert.


Par exemple, cela est utile lorsque l'on travaille avec de grandes archives MqlTick, etc.

 

Forum sur le trading, les systèmes de trading automatisés et les tests de stratégies de trading

Particularités du langage mql5, subtilités et techniques de travail

fxsaber, 2022.02.20 15:00

Vous avez raison, merci ! J'ai overmudryl sur une place droite. Je laisse votre variante pour le tri.

Application.

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);
}

Il y a eu une erreur dans la méthode Partition. Version corrigée.

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

Une erreur s'est glissée dans la méthode Partition. Version corrigée.

Pour le cas particulier où un champ numérique est pris pour le tri (la situation la plus courante), j'ai écrit une variante qui est plusieurs ordres de grandeur plus rapide que la précédente. Mais elle consomme deux fois plus de mémoire. Elle est pertinente pour les grands tableaux.

// Сортировка массива структур и указателей на объекты по ЧИСЛОВОМУ полю.
#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)


Application (avec mesure du temps d'exécution).

#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));
}


Résultat.

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.