Caratteristiche del linguaggio mql5, sottigliezze e tecniche - pagina 222

 
Maxim Kuznetsov #:

Questo non è niente di nuovo, è il modo in cui ha sempre funzionato dalla nascita.

Solo se i dati sono più grandi di __atomic__ l'accesso dovrebbe essere avvolto/protetto con sezioni critiche (o mutex al terminale std::thread)

Beh, non conoscevo questo comportamento e mi aspettavo un processo separato durante l'importazione.
Ho pensato che i puntatori DLL globali saranno nuovi, in ogni programma MT5 caricato.
Con quello che ho dovuto sudare per capire la logica, chiedendomi perché l'errore apparirà in memoria.
Ma quando ho capito la ragione con il metodo try (print), allora l'intero piano architettonico di lavorare con la DLL sarà costruito diversamente.
Amico, hai ragione sui mutex, non ci avevo pensato. Grazie per il suggerimento.

 
fxsaber #: ZZY È un peccato che non si possa fare per sottocampo o per metodo.

Sì, anche se se il metodo non ha parametri, è possibile farlo:

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

Applicazione:

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

  }
 

Con l'esecuzione parziale degli ordini il campoORDER_TIME_SETUP_MSC cambia.

Di conseguenza, DEAL_TIME_MSC può essere inferiore a ORDER_TIME_SETUP_MSC del suo ordine.

 

Che ne dite di usare una funzione di confronto personalizzata:

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

Hai ragione, grazie! Ho esagerato su un punto piatto. Lascio la tua variante per l'ordinamento.


Applicazione.


ZZY È un peccato che, per sottocampo o metodo, non funzioni.

Ecco il QuickSort ottimizzato dalla mia libreria, leggermente adattato alle tue esigenze.

Può ordinare array enormi senza overflow dello stack (a causa della ricorsione incontrollata).

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

Ciao e grazie per aver condiviso!

Questo sarebbe perfetto se funzionasse. Tuttavia, quando incollato in uno script .mq5 ed eseguito purtroppo il tuo codice lancia il seguente errore:

  • le dichiarazioni di template non sono consentite nelle classi locali ArraySortStruct.mq5 87 4
  • (dopo aver modificato leggermente il tuo codice): le dichiarazioni di template sono permesse solo nello scopo globale, nello spazio dei nomi o nella classe ArraySortStruct.mq5 90 4 )

Potresti per favore sistemare questo? Per te è probabilmente facile, mentre io non saprei da dove cominciare :-)

 
I commenti non correlati a questo argomento sono stati spostati in "Domande dei principianti in MQL4 e MQL5, aiuto e discussione su algoritmi e codici".
 

Quando si utilizza ArrayInsert, è possibile risparmiare memoria se Array_Destination[] è più piccolo di Array_Source[] da cui vengono aggiunti gli elementi.

A tal fine, è necessario applicare ArraySwap due volte: prima e dopo ArrayInsert.


Ad esempio, questo è importante quando si lavora con archivi MqlTick di grandi dimensioni, ecc.

 

Forum sul trading, sui sistemi di trading automatizzati e sulla verifica delle strategie di trading

Peculiarità del linguaggio mql5, sottigliezze e tecniche di lavoro

fxsaber, 2022.02.20 15:00

Hai ragione, grazie! Ho overmudryl su un posto dritto. Lascerò la vostra variante per l'ordinamento.

Applicazione.

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

C'era un errore nel metodo di partizione. Versione corretta.

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

C'era un errore nel metodo di partizione. Versione corretta.

Per il caso speciale in cui un campo numerico viene preso per l'ordinamento (la situazione più comune), ho scritto una variante che è di diversi ordini di grandezza più veloce della precedente. Ma consuma il doppio della memoria. È importante per gli array di grandi dimensioni.

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


Applicazione (con misurazione del tempo di esecuzione).

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


Risultato.

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.