Советники: Программирование на MQL5 для трейдеров — исходные коды из книги. Часть 6 - страница 2

 
Stanislav Korotky #:
Ордера, сделки, позиции никак не связаны с таймфреймами. Вы либо что-то не поняли, либо ваша формулировка неверна.
Извините, наверное, я перепутал слова. Под"таймфреймом" я подразумеваю "диапазон дат". Скажем, я хочу выбрать сделки/ордера, заключенные в заданном диапазоне дат, например, сделки с 2025-10-01 00:00:00 по 2025-10-22 23:59:59.
 
pauldic #:
Извините, я думаю, что мой выбор слова путает под"временными рамками" я имею в виду "диапазон дат". Скажем, я хочу выбрать сделки/заказы, заключенные в заданном диапазоне дат, например, сделки с 2025-10-01 00:00:00 по 2025-10-22 23:59:59.

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

input datetime SubrangeFrom = 0;
input datetime SubrangeTo = 0;

...

{
   HistorySelect(SubrangeFrom, SubrangeTo);
   // ... код фильтра идет здесь как есть
}

Если по какой-то причине вы хотите выбрать (более узкий) поддиапазон в рамках глобального диапазона, который вы применили с помощью HistorySelect, то вы все равно можете сделать это в коде фильтрации следующим образом:

{
      // некоторые из них здесь

      // HistorySelect(0, LONG_MAX);
      // HistorySelectByPosition(PositionID);
      ...
      DealTuple deals[];
      if(SubrangeFrom != SubrangeTo && SubrangeFrom < SubrangeTo)
      {
         filter.let(DEAL_TIME, SubrangeFrom - 1, IS::GREATER).let(DEAL_TIME, SubrangeTo + 1, IS::LESS);
      }
      filter.let(DEAL_POSITION_ID, PositionID).select(deals, true);
      ...
}

Выделенная желтым строка задает 2 условия для диапазона времени [SubrangeFrom, SubrangeTo], используя дополнительные квалификаторы IS::GREATER и IS::LESS (по умолчанию они не указываются в других вызовах let(), и тогда IS::EQUAL обычно используется для полей с одним значением).

Я знаю только одну причину применения подфильтра по диапазону дат - это время установки ордеров (ORDER_TIME_SETUP), потому что HistorySelect применяется к другому свойству ордеров - времени исполнения ордера (ORDER_TIME_DONE). Также может быть интересно отфильтровать поддиапазон активных ордеров (не в истории), если их много.

В качестве отправной точки можно посмотреть пример скрипта MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5.
 
Stanislav Korotky #:

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

Если по какой-то причине вы хотите выбрать (более узкий) поддиапазон в рамках глобального диапазона, который вы применили с помощью HistorySelect, то вы все равно можете сделать это в коде фильтрации следующим образом:

Выделенная желтым строка задает 2 условия для диапазона дат [SubrangeFrom, SubrangeTo], используя дополнительные квалификаторы IS::GREATER и IS::LESS (по умолчанию они не указываются в других вызовах let(), а IS::EQUAL обычно используется для полей с одним значением).

Я знаю только одну причину применения подфильтра по диапазону дат - это время установки ордеров (ORDER_TIME_SETUP), потому что HistorySelect применяется к другому свойству ордеров - времени исполнения ордера (ORDER_TIME_DONE). Также может быть интересно отфильтровать поддиапазон активных ордеров (не в истории), если их много.

В качестве отправной точки можно посмотреть пример скрипта MQL5/Scripts/MQL5Book/p6/TradeHistoryPrint.mq5.
@StanislavKorotky Еще раз спасибо... Это отличная отправная точка для меня, и я начну работать с ней.
 

Багфикс MQL5/Include/MQL5Book/TradeUtils.mqh.

   bool Equal(const double v1, const double v2)
   {
      return v1 == v2 || fabs(v1 - v2) < DBL_EPSILON * fmax(1.0, fmax(fabs(v1), fabs(v2)));
   }
Файлы:
TradeUtils.mqh  12 kb
 
pauldic #:

При вставке кода используйтекнопку CODE (Alt-S).

Модератор отформатировал некорректно вставленный код. Обычно такой код удаляется.

@StanislavKorotky Пожалуйста, не могли бы вы помочь разобраться с этой ошибкой, я считаю, что она началась после обновления MT5, потому что я знал, что код работает в предыдущие месяцы без каких-либо изменений.

преобразование параметра типа 'long[][2]' в 'string[][] &' не разрешено SymbolFilter.mqh 199 20

преобразование параметров типа 'double[][2]' в 'string[][] &' недопустимо TradeFilter.mqh 332 20
преобразование параметров типа 'long[][2]' в 'string[][] &' недопустимо TradeFilter.mqh 163 17


Я подозреваю, что приведенный ниже код поможет воспроизвести проблему:


Привет @Paul Dick

Попробуйте использовать этот https://www.mql5.com/ru/code/57233 для сортировки массивов.

Introsort (Introspective sort) using Function Pointers
Introsort (Introspective sort) using Function Pointers
  • 2025.03.18
  • www.mql5.com
A hybrid sorting algorithm that provide fast performance for sorting arrays of simple types, structures or object pointers.
 

Прикладываю обновленную версию файла расчета кастом-критерия оптимизации на основе R2 - RSquared.mqh, в которой поправлен расчет для случая переменных лотов.

Значительно улучшено качество оценки - судя по таблице результатов оптимизации получилась комбинация параметров фактора восстановления и шарпа.

Пример использования.

double OnTester()
{
   HistorySelect(0, LONG_MAX);
   
   #define STAT_PROPS 5
   
   const ENUM_DEAL_PROPERTY_DOUBLE props[STAT_PROPS] =
   {
      DEAL_PROFIT, DEAL_SWAP, DEAL_COMMISSION, DEAL_FEE, DEAL_VOLUME
   };
   double expenses[][STAT_PROPS];
   ulong tickets[]; // used here only to match 'select' prototype, but helpful for debug
   
   DealFilter filter;
   filter.let(DEAL_TYPE, (1 << DEAL_TYPE_BUY) | (1 << DEAL_TYPE_SELL), IS::OR_BITWISE)
      .let(DEAL_ENTRY, (1 << DEAL_ENTRY_OUT) | (1 << DEAL_ENTRY_INOUT) | (1 << DEAL_ENTRY_OUT_BY), IS::OR_BITWISE)
      .select(props, tickets, expenses);

   const int n = ArraySize(tickets);
   
   double balance[];
   double volumes[]; // take trade volumes into account for using R2 criterion
   
   ArrayResize(balance, n + 1);
   balance[0] = 0;
   ArrayResize(volumes, n + 1);
   volumes[0] = 0;
   
   for(int i = 0; i < n; ++i)
   {
      double result = 0;
      for(int j = 0; j < STAT_PROPS - 1; ++j)
      {
         result += expenses[i][j];
      }
      // use volumes as a model - more investments - more returns expected
      volumes[i + 1] = expenses[i][STAT_PROPS - 1] + volumes[i];
      balance[i + 1] = result + balance[i];
   }
   
   const double r2 = RSquaredTest(balance, volumes);
   
   #undef STAT_PROPS
   
   return r2 * 100;
}
Файлы:
RSquared.mqh  4 kb
 

Я недавно изучал Frame и протестировал ваш код, FrameTransfer.mq5. Эта строка выдает ошибку в текущем компиляторе MT5. Пожалуйста, проверьте: #property tester_set "FrameTransfer.set" (недопустимое расширение файла tester set, '*.set' ожидается FrameTransfer.mq5)

Для успешной компиляции его нужно изменить следующим образом: #property tester_set "\\Presets\\FrameTransfer.set"

Даже `#property tester_set "/Presets/FrameTransfer.set"` будет неудачным.

Возможно, вы могли бы изменить описание в книге алгоритмов:


 
hini #:

Я недавно изучал Frame и протестировал ваш код, FrameTransfer.mq5. Эта строка выдает ошибку в текущем компиляторе MT5. Пожалуйста, проверьте: #property tester_set "FrameTransfer.set" (недопустимое расширение файла tester set, '*.set' ожидается FrameTransfer.mq5)

Для успешной компиляции его нужно изменить следующим образом: #property tester_set "\\Presets\\FrameTransfer.set"

Даже `#property tester_set "/Presets/FrameTransfer.set"` будет неудачным.

Возможно, вы могли бы изменить описание в книге алгоритмов:


Это очевидный баг компилятора - он выдает ошибку: "invalid tester set file extension, '*.set' expected" на код:

#property tester_set "FrameTransfer.set"

в котором файл имеет требуемое расширение. Путь размещения файла ни при чем.

Баг уже давний, как минимум с 2024 года. Почему MQ не чешется его исправлять - я не знаю.

Что касается правок книги, то в данном случае они не нужны, но в любом случае книга теперь полностью в ведении MQ.

 
Stanislav Korotky контролем MQ.
Подтверждаю и сообщаю. Посмотрим, будет ли это исправлено.
 
Stanislav Korotky #:

Это очевидная ошибка компилятора - он выдает ошибку: "invalid tester set file extension, '*.set' expected" в коде:

Спасибо, исправлено!

Чтобы не менять версию MetaEditor, добавьте ноль в конце имени файла: "myset.set\0"