Новая версия платформы MetaTrader 5 build 3490: мобильная версия веб-терминала и новые методы матриц в MQL5 - страница 12

 

Сломались текстовые метки!!!! OBJ_TEXT

билд 3484 (грузиться как бета)

При сдвиге графика, метка привязанная к цене и времени, не смещается!!!!

 

Кстати, в вебтерминале изменение масштаба нажатием на "+" или "-" имеет больше градаций, чем в приложении МТ5. А нельзя ли так же сделать и в приложении?

Спасибо.

 
Alexandr Gavrilin #:

Сломались текстовые метки!!!! OBJ_TEXT

При сдвиге графика, метка привязанная к цене и времени, не смещается!!!!

Уже исправили, будет в сегодняшем релизе.

 
fxsaber #:

Обмен кусками памяти.

Так нельзя сделать :))

 
Aliaksandr Hryshyn #:

Так нельзя сделать :))

Бессмысленное сообщение.

 
fxsaber #:

Просьба подумать о возможности добавления штатной сортировки структур по числовым полям, подобно этому.

Только при этом игнорировать возможные операторы присваивания. Т.е. делать сортировку на уровне памяти, как это сделано с ArraySwap для массивов.

Строка для поиска: Uluchshenie 050.

Если произовдительность - главный критерий, то, как вариант, можно не использовать стандартную функцию ArraySort(), а написать свою.
Используя эту функцию как шаблон, можно создавать специализированные функции, в которых уже можно сортировать по втутренним параметрам объекта.
Сейчас набросал функцию сортировки по первому попавшемуся методу слияния, и неожиданно для себя эта функция работает быстрее штатной  ArraySort() на процентов 15-20%
Прикрепляю два примера
Первый пример (MySort.mq5) использует функцию сортировки 
void MergeSort(T &arr[]) и сравнивает по производительности с методом  ArraySort(). Массив из 1000000 элементов формируется из цены Ask последних 1000000 тиков.

2022.11.04 22:37:26.957 MySort (EURUSD,D1)      Время сортировки массива double через MergeSort() = 47448 миллисекунд
2022.11.04 22:37:27.016 MySort (EURUSD,D1)      Время сортировки массива double через ArraySort() = 58758 миллисекунд
2022.11.04 22:37:27.017 MySort (EURUSD,D1)      Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:37:27.017 MySort (EURUSD,D1)      =========================================
2022.11.04 22:37:28.669 MySort (EURUSD,D1)      Время сортировки массива double через MergeSort() = 45376 миллисекунд
2022.11.04 22:37:28.729 MySort (EURUSD,D1)      Время сортировки массива double через ArraySort() = 59705 миллисекунд
2022.11.04 22:37:28.730 MySort (EURUSD,D1)      Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:37:28.730 MySort (EURUSD,D1)      =========================================
2022.11.04 22:37:29.944 MySort (EURUSD,D1)      Время сортировки массива double через MergeSort() = 44518 миллисекунд
2022.11.04 22:37:30.002 MySort (EURUSD,D1)      Время сортировки массива double через ArraySort() = 58098 миллисекунд
2022.11.04 22:37:30.003 MySort (EURUSD,D1)      Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:37:30.003 MySort (EURUSD,D1)      =========================================
2022.11.04 22:37:30.886 MySort (EURUSD,D1)      Время сортировки массива double через MergeSort() = 46512 миллисекунд
2022.11.04 22:37:30.943 MySort (EURUSD,D1)      Время сортировки массива double через ArraySort() = 56832 миллисекунд
2022.11.04 22:37:30.944 MySort (EURUSD,D1)      Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:37:30.944 MySort (EURUSD,D1)      =========================================


Второй пример (МуSortMqlTick.mq5) уже использует функцию void MergeSortMqlTickByAsk(MqlTick &arr[]) и сортирует массив MqlTick по цене Ask:

2022.11.04 22:44:46.208 MySortMqlTick (EURUSD,D1)       Время получения массива double Ask и его сортировки через ArraySort() = 62151 миллисекунд
2022.11.04 22:44:46.302 MySortMqlTick (EURUSD,D1)       Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 94540 миллисекунд
2022.11.04 22:44:46.306 MySortMqlTick (EURUSD,D1)       Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:44:46.306 MySortMqlTick (EURUSD,D1)       =========================================
2022.11.04 22:44:48.708 MySortMqlTick (EURUSD,D1)       Время получения массива double Ask и его сортировки через ArraySort() = 60994 миллисекунд
2022.11.04 22:44:48.807 MySortMqlTick (EURUSD,D1)       Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 99209 миллисекунд
2022.11.04 22:44:48.812 MySortMqlTick (EURUSD,D1)       Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:44:48.812 MySortMqlTick (EURUSD,D1)       =========================================
2022.11.04 22:44:50.047 MySortMqlTick (EURUSD,D1)       Время получения массива double Ask и его сортировки через ArraySort() = 58985 миллисекунд
2022.11.04 22:44:50.145 MySortMqlTick (EURUSD,D1)       Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 98517 миллисекунд
2022.11.04 22:44:50.149 MySortMqlTick (EURUSD,D1)       Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:44:50.149 MySortMqlTick (EURUSD,D1)       =========================================
2022.11.04 22:44:51.451 MySortMqlTick (EURUSD,D1)       Время получения массива double Ask и его сортировки через ArraySort() = 59751 миллисекунд
2022.11.04 22:44:51.551 MySortMqlTick (EURUSD,D1)       Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 99585 миллисекунд
2022.11.04 22:44:51.555 MySortMqlTick (EURUSD,D1)       Колличество несоответствий в двух отсортированных массивов = 0
2022.11.04 22:44:51.555 MySortMqlTick (EURUSD,D1)       =========================================


Если честно, то я не понимаю зачем при сортировке массива сложных объектов, необходимо их свопить.
Мне кажется более разумнее с точки зрения производительности сам массив объектов не трогать, а формировать массив индексов, который представляет собой последовательность индексов к элементам массива объектов, упорядоченных по заданному критерию.

ЗЫ Функция получилась раздутой, т.к. не нашел способа создать несколько переменных, которые ссылаются на один массив в памяти. Может кто подскажет? Возможно туплю. Загонять массив в объект структуры или класса не хочется. Неужели нет вариантов? Тогда ужас! 
Файлы:
MySort.mq5  11 kb
 
Nikolai Semko #:

Мне кажется более разумнее с точки зрения производительности сам массив объектов не трогать, а формировать массив индексов, который представляет собой последовательность индексов к элементам массива объектов, упорядоченных по заданному критерию.

Есть подобная функция MathOrder(), правда только для целых и вещественных массивов. Было бы неплохо иметь более полный аналог функции order() из языка R, который может принимать в аргументах произвольное количество массивов. Ну и конечно, чтобы можно было подавать массивы структур.

 

Сортировка согласно подсказке Алексея:

Это изменение кода Николая MySortMqlTick.mq5, убрал лишнее, мой код между ///////////

#define SIZE_ARR 1000000

#include <Math\\Stat\\Math.mqh>

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   double C[];
   ArrayResize(C,SIZE_ARR);
   MqlTick ticks[];
   CopyTicks(_Symbol,ticks,COPY_TICKS_ALL,0, SIZE_ARR);
   ulong t = GetMicrosecondCount();
   for(int i = 0; i< SIZE_ARR; i++)
     {
      C[i] = ticks[i].ask;
     }
   ArraySort(C);
   t = GetMicrosecondCount() - t;
   Print("Время получения массива double Ask и его сортировки через ArraySort() = " + string(t) + " миллисекунд");
   
   t = GetMicrosecondCount();
////////////////////////////
   int pos_from[];
   double data_sort[];
   MqlTick ticks1[];

   ArrayResize(pos_from,SIZE_ARR);
   ArrayResize(data_sort,SIZE_ARR);
   ArrayResize(ticks1,SIZE_ARR);

   for(int i1=0; i1<SIZE_ARR; i1++)
     {
      pos_from[i1]=i1;
      data_sort[i1]=ticks[i1].ask;
     }
   MathQuickSortAscending(data_sort,pos_from,0,SIZE_ARR-1);

   for(int i1=0; i1<SIZE_ARR; i1++)
     {
      ticks1[i1]=ticks[pos_from[i1]];
     }
   ArraySwap(ticks,ticks1);
   
   //MergeSortMqlTickByAsk(ticks);
////////////////////////

   t = GetMicrosecondCount() - t;
   Print("Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = " + string(t) + " миллисекунд");


   int sum = 0;
   for(int i = 0; i< SIZE_ARR; i++)
     {
      if(ticks[i].ask != C[i])
         sum++;
     }
   Print("Колличество несоответствий в двух отсортированных массивов = " + string(sum));
   Print("=========================================");
  }

Результаты в сравнении:

2022.11.05 12:01:05.611 MySort (EURUSD,M1)      Время сортировки массива double через MergeSort() = 49903 миллисекунд
2022.11.05 12:01:05.668 MySort (EURUSD,M1)      Время сортировки массива double через ArraySort() = 57713 миллисекунд
2022.11.05 12:01:05.669 MySort (EURUSD,M1)      Колличество несоответствий в двух отсортированных массивов = 0
2022.11.05 12:01:05.669 MySort (EURUSD,M1)      =========================================
2022.11.05 12:01:08.456 MySortMqlTick (EURUSD,M1)       Время получения массива double Ask и его сортировки через ArraySort() = 60547 миллисекунд
2022.11.05 12:01:08.559 MySortMqlTick (EURUSD,M1)       Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 102920 миллисекунд
2022.11.05 12:01:08.561 MySortMqlTick (EURUSD,M1)       Колличество несоответствий в двух отсортированных массивов = 0
2022.11.05 12:01:08.561 MySortMqlTick (EURUSD,M1)       =========================================
2022.11.05 12:01:12.207 MySortMqlTick_1 (EURUSD,M1)     Время получения массива double Ask и его сортировки через ArraySort() = 60108 миллисекунд
2022.11.05 12:01:12.267 MySortMqlTick_1 (EURUSD,M1)     Время сортировки массива MqlTick по Ask через MergeSortMqlTickByAsk() = 59641 миллисекунд
2022.11.05 12:01:12.269 MySortMqlTick_1 (EURUSD,M1)     Колличество несоответствий в двух отсортированных массивов = 0
2022.11.05 12:01:12.269 MySortMqlTick_1 (EURUSD,M1)     =========================================

Это основной принцип сортировки структур, который уменьшает количество перемещений данных в памяти, это основная оптимизация

 

Так как тема о вчерашнем обновлении терминала самоликвидировалась пока я писал сообщение, то спрошу тут.

Итак, в последнем обновлении появилась возможность выбирать устройства для работы с OpenCL в терминале, в частности разрешать их продавать в клауд и использовать для оптимизации на локальных компьютерах и в своей сети, в связи с этим вопросы:

1. Как программе на MQL5 принудительно указать, какое устройство использовать для вычислений?

2. Как привязать устройство к конкретному агенты? Ведь очевидно, что при оптимизации только один агент будет рационально использовать устройство, в противном случае будет большая очередь.

3. Как в клауде рассчитывается стоимость устройства - на скринах видел там на порядок другой оценочный коэффициент?

4. Как в клауде выбрать агентов с нужным мне устройством - ведь у карт разная архитектура, и возможно, что мне достаточно старого и дешёвого поколения для вычислений, так как в моих задачах прирост будет минимален.

И тут же спрошу, если при отправке кода на исполнение в OpenCL через стандартный класс указать число задач в локальной группе более 10 то вычисления не происходят - возвращается массив с нулями, при этом этот показатель влияет на точность расчетов, что как то не логично.

Какое там значение ставиться по умолчанию, зависит ли оно как то от архитектуры самой карты?

bool  Execute( 
   const int   kernel_index,           // индекс кернела 
   const int   work_dim,               // размерность пространства задач  
   const uint  &work_offset[],         // начальное смещение в пространстве задач  
   const uint  &work_size[],           // общее количество задач  
   const uint  &local_work_size[]      // количество задач в локальной группе  
   );
 
Nikolai Semko #:

Если произовдительность - главный критерий, то, как вариант, можно не использовать стандартную функцию ArraySort(), а написать свою.

Дополню Ваш конструктив.
// Сравнение скоростей сортировки числовых массивов.

template <typename T>
int FillArray( T &Array[], const uint Amount = 1e6 )
{
  MqlTick Ticks[];

  const int Size = ArrayResize(Array, CopyTicks(_Symbol, Ticks, COPY_TICKS_ALL, 0, Amount));
  
  for (int i = Size - 1; i >= 0; i--)
    Array[i] = (T)(Ticks[i].ask * 1e5);
    
  return(Size);
}

#include <RadixSort.mqh> // https://www.mql5.com/en/code/38763
#include <QuickSort.mqh> // https://www.mql5.com/ru/code/37405

#define OnStart OnStart2
  #include <..\Scripts\MySort.mq5> // https://www.mql5.com/ru/forum/434546/page12#comment_43054925
#undef OnStart

#include <fxsaber\Benchmark\Benchmark.mqh> // https://www.mql5.com/ru/code/31279
#define _C(A) _BV(A, 1);
#define PRINT(A) Print(#A + " = " + (string)(A))


template <typename T>
void Sort_Bench()
{
  T Array[];
  FillArray(Array);

  T Array_ArraySort[];
  T Array_RadixSort[];
  T Array_QuickSort[];
  T Array_MergeSort[];
  
  ArrayCopy(Array_ArraySort, Array);
  ArrayCopy(Array_RadixSort, Array);
  ArrayCopy(Array_QuickSort, Array);
  ArrayCopy(Array_MergeSort, Array);

  _C(ArraySort(Array_ArraySort));
  _C(RadixSort(Array_RadixSort));
  _C(QuickSort(Array_QuickSort));
  _C(MergeSort(Array_MergeSort));
  
  PRINT(ArrayCompare(Array_ArraySort, Array_RadixSort));
  PRINT(ArrayCompare(Array_ArraySort, Array_QuickSort));
  PRINT(ArrayCompare(Array_ArraySort, Array_MergeSort));
}

void OnStart()
{
  Sort_Bench<double>();
  Sort_Bench<int>();
}


Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 44 in "void OnStart()"::Sort_Bench<double>: ArraySort(Array_ArraySort)] = 69085 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 45 in "void OnStart()"::Sort_Bench<double>: RadixSort(Array_RadixSort)] = 18158 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 46 in "void OnStart()"::Sort_Bench<double>: QuickSort(Array_QuickSort)] = 84767 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 47 in "void OnStart()"::Sort_Bench<double>: MergeSort(Array_MergeSort)] = 72574 mcs.
ArrayCompare(Array_ArraySort,Array_RadixSort) = 0
ArrayCompare(Array_ArraySort,Array_QuickSort) = 0
ArrayCompare(Array_ArraySort,Array_MergeSort) = 0

Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 44 in "void OnStart()"::Sort_Bench<int>: ArraySort(Array_ArraySort)] = 60303 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 45 in "void OnStart()"::Sort_Bench<int>: RadixSort(Array_RadixSort)] = 9732 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 46 in "void OnStart()"::Sort_Bench<int>: QuickSort(Array_QuickSort)] = 79765 mcs.
Alert: Bench_Stack = 0, 1 <= Time[Test9.mq5 47 in "void OnStart()"::Sort_Bench<int>: MergeSort(Array_MergeSort)] = 67721 mcs.
ArrayCompare(Array_ArraySort,Array_RadixSort) = 0
ArrayCompare(Array_ArraySort,Array_QuickSort) = 0
ArrayCompare(Array_ArraySort,Array_MergeSort) = 0

Radix уверенно опережает.

Причина обращения: