English 中文 Español Deutsch 日本語 Português
preview
Магия временных торговых интервалов с инструментом Frames Analyzer

Магия временных торговых интервалов с инструментом Frames Analyzer

MetaTrader 5Тестер | 8 ноября 2022, 09:36
1 828 5
Anatoli Kazharski
Anatoli Kazharski

Содержание


Введение

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

Что такое Frames Analyzer? Это подключаемая библиотека к любому торговому эксперту для анализа фреймов оптимизации во время оптимизации параметров в тестере, а также вне тестера посредством чтения MQD-файла или базы данных, которая создаётся сразу после оптимизации параметров.

Это эксклюзивная разработка, которая ранее нигде не была продемонстрирована в таком виде, хоть и была почти полностью реализована больше трёх лет назад. Впервые заложенная идея была подробно сформулирована и реализована в коде активным участником MQL-сообщества fxsaber.

Некоторые промежуточные реализации приложений для анализа фреймов оптимизации были освещены в некоторых моих статьях:

Совместив все эти идеи, был получен довольно интересный и информативный инструмент, который будет подробно освещён в этой статье.


Описание инструмента

Модуль содержит встроенный графический интерфейс, созданный с помощью библиотеки EasyAndFastGUI v2.0, который не требует дополнительного написания кода. Необходимо подключение к нескольким главным функциям MQL-приложения (будет показано ниже).

Графический интерфейс состоит из нескольких разделов. Рассмотрим их далее.


Вкладка Frames

Элементы:

  • Кнопка Open DB для открытия базы данных, в котором содержатся фреймы оптимизации. Эта кнопка появляется только в приложении Frames Analyzer, то есть вне тестера этот эксперт будет работать в режиме чтения DB-файла, который создаётся экспертом после оптимизации параметров. 
  • Кнопка Open MQD-file для открытия MQD-файла, в котором содержатся фреймы оптимизации. Эта кнопка появляется только в приложении Frames Analyzer, то есть вне тестера этот эксперт будет работать в режиме чтения MQD-файла, который создаётся тестером после оптимизации параметров (будет устранена в версии для продажи).
  • Поле ввода Curves total для указания кол-ва отображаемых балансов на графике одновременно.
  • Кнопка Replay frames для запуска повторного проигрывания фреймов.
  • График балансов (Optimization result).
  • График всех результатов (Profit/Loss).

Если модуль Frames Analyzer подключен к эксперту как библиотека, то во время оптимизации параметров в тестере будет открываться график с экспертом Frames Analyzer, и можно будет сразу наблюдать все промежуточные результаты (балансы). 

Визуализация результатов во время оптимизации параметров

Визуализация результатов во время оптимизации параметров


Вкладка Results

В верхней части две таблицы:

  • Кнопка Add to favorites для добавления результатов в избранное.
  • Поле ввода Removed intervals для указания количества исключаемых интервалов с убыточными сериями.
  • Комбобокс с выпадающим списком Criterion для отбора результатов по указанному критерию:
    • Profit - из общего количества (и в других критериях тоже) выбираются 100 результатов по максимальному балансу.
    • Trades - выбираются 100 результатов по максимальному количеству сделок.
    • DD (drawdown) - выбираются 100 результатов по минимальной просадке.
    • RF (recovery factor) - выбираются 100 результатов по максимальному фактору восстановления.
    • Такие же критерии с префиксом BI_ имеют такой же смысл, но уже после исключения убыточных серий сделок.
  • Таблица с сотней лучших результатов по максимальному балансу. Ячейки колонок относящиеся к улучшенным результатам (с префиксом BI_) закрашены другим цветом, чтобы быстро отличать их визуально (см. скриншот ниже). Ячейки столбцов с внешними параметрами также выделены своим цветом, чтобы быстро определять их визуально.
  • Таблица с результатами после удаления из торговой истории убыточных периодов со всеми промежуточными результатами.

Когда курсор мыши находится над той или иной таблицей, переключение строк можно осуществлять клавишами: UP, DOWN, PAGE UP, PAGE DOWN, HOME, END. Клавиши LEFT и RIGHT помогут быстро перемещаться в таблицах от начала в конец по горизонтали.

В нижней части находится область с двумя вкладками: Balances, Top 100 results. Рассмотрим их далее.


Вкладка Balances

Здесь расположены два графика:

  • Слева график с исходным балансом и со всеми промежуточными улучшенными результатами после удаления убыточных серий сделок. Таким образом можно увидеть, как изменяется график баланса после исключения очередной убыточной серии.
  • Справа график с улучшенным итоговым результатом баланса (который на левом графике самый лучший) и всеми балансами для каждого торгового периода отдельно.

Выделяя строки в таблицах, графики тоже будут обновляться.

Итоговые балансы результатов и улучшенные балансы после удаления убыточных интервалов

Итоговые балансы результатов и улучшенные балансы после удаления убыточных интервалов


Вкладка Top 100 results

Здесь также расположены два графика:

  • Слева график 100 лучших результатов по профиту.
  • Справа график 100 лучших результатов по указанному критерию: Profit, Trades, DD, RF, BI_Profit, BI_Trades, BI_DD, BI_RF.

Выделение строк в таблицах будет обновлять результаты в графиках. Например, ниже показано, какой выделен результат слева (чёрная кривая баланса) и какой получился результат после исключения убыточных серий сделок на графике справа.

100 лучших итоговых и улучшенных балансов после удаления убыточных интервалов

100 лучших итоговых и улучшенных балансов после удаления убыточных интервалов

Также можно указать количество удаляемых из истории убыточных интервалов для улучшения результата.

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

Как уже упоминалось выше, можно сохранить понравившиеся результаты в таблицу избранных результатов. Для этого нужно воспользоваться кнопкой Add to favorites. Добавленные результаты подсвечиваются другим цветом в общей таблице результатов.

Результаты добавленные в избранное подсвечиваются другим цветом

Результаты добавленные в избранное подсвечиваются другим цветом


Вкладка Favorites

На этой вкладке также две таблицы и два графика. Смысл всех показателей такой же, как и на вкладке Results. Отличие только в том, что эти избранные результаты можно сохранить в файлы (наборы сетов для эксперта) и в базу данных. Здесь, кроме таблиц и графиков, в верхней части окна расположены такие кнопки:

  • Delete selected - удаление выделенного результата из избранного в таблице слева и из базы данных.
  • Delete all - удаление всех результатов из избранного в таблице слева и из базы данных.
  • Save parameters - сохранение параметров в файл и в базу данных.

Данные и графики избранных результатов

Данные и графики избранных результатов

Нажав на кнопку Save parameters все избранные результаты сохраняются:

  • в базу данных в таблицу FAVORITE_RESULTS
  • в файлы в каталоге MQL5/Files/Reports/FramesA/[CURRENT_TIME], если в режиме чтения MQD-файла
  • MQL5/Files/Reports/[CURRENT_TIME] [EXPERT_NAME], если в режиме FRAME_MODE (сразу после оптимизации)

Все результаты сохраняются в отдельные папки, где в качестве названия папки - номер прохода. Это будет set-файл с внешними параметрами эксперта и несколько скриншотов таблиц и графиков, которые рассматривались выше. В качестве префикса в имени всех файлов - номер прохода:

  • 422462.set - это set-файл с внешними параметрами эксперта.
  • 422462_balance_sub_bi.png - скриншот баланса после исключения всех временных интервалов с убыточными сериями сделок, а также все балансы отдельно для каждого оставшегося временного интервала.
  • 422462_balances_bi.png - скриншот всех балансов после исключения всех временных интервалов с убыточными сериями сделок.
  • 422462_bi_table.png - скриншот таблицы со всеми итоговыми результатами после исключения всех временных интервалов с убыточными сериями сделок.
  • 422462_gui.png - полный скриншот графического интерфейса.

Пример set-файла с параметрами эксперта:

; this file contains last used input parameters for testing/optimizing FA expert advisor
; Experts\Advisors\ExpertMACD.ex5
;
Inp_Expert_Title=ExpertMACD||0.0||0.0||0.0||N
Inp_Signal_MACD_PeriodFast=15||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSlow=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSignal=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_TakeProfit=270||30.0||5.0||300.0||Y
Inp_Signal_MACD_StopLoss=115||20.0||5.0||200.0||Y


База данных результатов оптимизации

Как уже упоминалось выше, инструмент Frames Analyzer сразу после оптимизации параметров в тестере сохраняет все результаты оптимизации в базу данных. И не только их! После каждой оптимизации параметров создаётся новая база данных в локальном каталоге терминала MQL5/Files/DB. Имя базы данных состоит из текущего времени в момент создания и имени эксперта: [CURRENT_TIME] [EXPERT_NAME].db.

Всего создаётся три таблицы:

Талица OPTIMIZATION_RESULTS, в которой будут храниться следующие данные (столбцы):

  • Pass - номер прохода.
  • Profit - полученная прибыль.
  • Trades - количество трейдов.
  • PF - профит фактор (Profit factor).
  • DD - просадка.
  • RF - фактор восстановления (Recovery factor).
  • Столбцы со всеми внешними параметрами эксперта:
    • Параметр 1
    • Параметр 2
    • и т.д.
  • Deals - история сделок, по которым вычисляются балансы для каждого прохода.

Таблица с данными всех проходов оптимизации

Таблица с данными всех проходов оптимизации

Таблица EXPERT_PARAMETERS. Здесь содержатся внешние параметры эксперта, а также его имя и путь к каталогу, где он находился во время оптимизации параметров. В этой таблице два столбца:

  • Parameter - название параметра
  • Value - значение параметра.

Ниже приведён пример для эксперта ExpertMACD из штатной поставки терминала. Для внешних параметров (INPUT_n) в столбце Value сохраняется имя внешнего параметра и оптимизационные параметры (через разделитель ||), которые использовались для этой оптимизации.

Таблица с данными эксперта

Таблица с данными эксперта

В эту таблицу в дальнейшем можно добавлять также и какие-нибудь другие параметры необходимые для работы эксперта.

Таблица FAVORITE_RESULTS. В эту таблицу сохраняются избранные результаты оптимизации. Здесь всего три столбца:

  • FavoriteID - идентификатор позиции.
  • Pass - номер прохода, по которому можно получить все данные в таблице OPTIMIZATION_RESULTS.
  • RemovedIntervals - удалённые временные интервалы, во время которых предполагается не торговать в реальной торговле.

Таблица избранных результатов оптимизации с удалёнными временными интервалами

Таблица избранных результатов оптимизации с удалёнными временными интервалами

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


Как пользоваться инструментом Frames Analyzer?

Сначала Вам нужно загрузить Frames Analyzer к себе на компьютер на этой странице. Если вы сейчас запустите этого эксперта у себя в терминале, то все графики и таблицы у Frames Analyzer будут пусты. Ничего удивительного, ведь этому инструменту нужны результаты оптимизации, для работы с которыми он и предназначен. Если Вам не терпится попробовать его в работе, то Вы можете прямо сейчас загрузить в конце статьи файл базы данных с результатами оптимизации, который я подготовил для Вас. Поместите этот файл в каталог MQL5/Files/DB и теперь можно его загрузить через графический интефейс эксперта Frames Analyzer. На вкладке Frames нажмите на кнопку Open DB. Откроется диалоговое окно для выбора файла базы данных, как показано ниже. У меня в данном случае в этом каталоге уже есть несколько файлов баз данных.

Выбор файла базы данных в диалоговом окне

Выбор файла базы данных в диалоговом окне

Но для того, чтобы Frames Analyzer сохранял результаты оптимизации Вашего эксперта нужно его подключить в виде библиотеки в коде Вашего эксперта. Это совсем просто сделать и далее приведён подробный пример.

Загрузив Frames Analyzer на свой компьютер он будет в каталоге MQL5/Experts/Market. Тогда Вы можете подключить его к главному файлу (*.mq5) своего эксперта следующим образом:

#import "..\Experts\Market\FramesA.ex5"
  void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
  void OnTesterEvent(void);
  void OnTesterInitEvent(void);
  void OnTesterPassEvent(void);
  void OnTesterDeinitEvent(void);
#import

Как видно выше, из эксперта Frames Analyzer нужно импортировать несколько функций. Они нужны для обработки событий в работе графического интерфейса, а также для сбора данных во время оптимизации параметров эксперта в тестере. Всё, что Вам осталось сделать это вызвать эти функции в аналогичных функциях в эксперте, как это показано ниже:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
  FramesA::OnEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| Обработчик события окончания тестирования                        |
//+------------------------------------------------------------------+
double OnTester(void) {
  FramesA::OnTesterEvent();
  return(0.0);
}
//+------------------------------------------------------------------+
//| TesterInit function                                              |
//+------------------------------------------------------------------+
void OnTesterInit(void) {
  FramesA::OnTesterInitEvent();
}
//+------------------------------------------------------------------+
//| TesterPass function                                              |
//+------------------------------------------------------------------+
void OnTesterPass(void) {
  FramesA::OnTesterPassEvent();
}
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit(void) {
  FramesA::OnTesterDeinitEvent();
}
//+------------------------------------------------------------------+

Всё очень просто, не так ли?

Кстати, если Вы используете в своих проектах библиотеку EasyAndFastGUI v2.0 для создания графических интерфейсов, которая используется в инструменте Frames Analyzer, то ничего не нужно делать дополнительно для того, чтобы они работали вместе в одном MQL-приложении. Frames Analyzer встроенный в Вашего эксперта работает отдельно во фрейм-режиме (FRAME_MODE) и никак не будет мешать работе графического интерфейса Вашего приложения.

У Вас вообще может не быть библиотеки EasyAndFastGUI v2.0 и Frames Analyzer будет работать в любом случае.

Пример эксперта ExpertMACD из штатной поставки с уже подключенным модулем Frames Analyzer Вы можете скачать в конце статьи.


Применение удалённых интервалов в торговых экспертах

Итак. У Вас есть инструмент Frames Analyzer. Вы подключили его к своему торговому эксперту, провели оптимизацию параметров и теперь у Вас есть база данных с результатами всех проходов, для которых есть значения всех внешних параметров. А в отдельной таблице Вы сохранили избранные результаты оптимизации с удалёнными временными интервалами, которые теперь можно применить к своей торговой стратегии.

Давайте рассмотрим пример, как это можно реализовать.

Допустим, Вы хотите реализовать выбор временных торговых диапазонов через графический интерфейс пользователя. Неплохо было бы, чтобы в графическом интерфейсе был элемент, который наглядно визуализирует удалённые временные интервалы, во время которых не рекомендуется торговать. Если Вы счастливый обладатель библиотеки для создания продвинутых графических интерфейсов EasyAndFastGUI 2.0, то у Вас уже есть такая возможность. В одном из последних обновлений был добавлен ещё один уникальный элемент - CTimeRanges, который позволяет Вам работать с временными интервалами. Далее создадим графический интерфейс с этим элементом и рассмотрим его подробнее.

Графический интерфейс будет состоять из таких элементов:

  • Форма для элементов управления - CWindow.
  • Кнопка для открытия файла базы данных - CButton.
  • Выпадающий список с номерами проходов из таблицы избранных результатов оптимизации - CComboBox.
  • Временная шкала, на которой отображаются интервалы не рекомендуемые для торговли - CTimeRanges.

Чтобы создать такой графический интерфейс нужно всего лишь несколько строчек кода:

void CApp::CreateGUI(void) {

//--- Form
  m_window1.ResizeMode(true);
  m_window1.ThemeButtonIsUsed(true);
  CCoreCreate::CreateWindow(m_window1, "TIME TRADE RANGES", 1, 1, 350, 100, true, true, true, true);
  
//--- Button
  CCoreCreate::CreateButton(m_button1, m_window1, 0, "Open DB...", 10, 30, 100);
  
//--- Combobox
  string items1[] = {"12345", "19876", "45678", "23456", "67890"};
  CCoreCreate::CreateCombobox(m_combobox1, m_window1, 0, "Passes: ", 120, 30, 135, 90, items1, 103, 0);
  
//--- Time ranges
  string time_ranges[] = {
    "00:45:00 - 01:20:01",
    "08:55:00 - 09:25:01",
    "12:55:00 - 13:50:01",
    "15:30:00 - 17:39:59",
    "20:10:00 - 21:05:00"
  };
  m_time_ranges1.SetTimeRanges(time_ranges);
  m_time_ranges1.AutoXResizeMode(true);
  m_time_ranges1.AutoXResizeRightOffset(5);
  CCoreCreate::CreateTimeRanges(m_time_ranges1, m_window1, 0, 5, 60, 390);
}

В примере выше показано, как вы можете установить временные интервалы в элемент TimeRanges, во время которых торговать не нужно.

Запустив MQL-приложение с таким графическим интерфейсом Вы увидите на графике такой результат:

Демонстрация элемента TimeRanges из библиотеки EasyAndFastGUI v2.0

Демонстрация элемента TimeRanges из библиотеки EasyAndFastGUI v2.0

На скриншоте выше показан элемент графического интерфейса, который представляет из себя внутридневную временную шкалу. Это динамический элемент, который может автоматически подстраиваться под ширину родительского элемента (в данном случае формы). Штрих-пунктирной линией отмечено текущее время, около которой показывается текстовая метка с текущим временем. Если курсор мыши навести на временную шкалу, то под курсором мыши будет отрисовываться вертикальная сплошная линия с текстовой меткой того времени, на который указывает курсор. 

Получилось довольно информативно, но и это ещё не всё! Если кликнуть на шкале, то элемент сгенерирует пользовательское событие с идентификатором ON_CLICK_TIME_RANGE, которое можно обработать в своём MQL-приложении. В dparam-параметре будет содержаться количество секунд прошедших с начала суток, а в sparam-параметре будет содержаться удалённый временной диапазон либо пустая строка, если ни один из установленных диапазонов не попал под курсор во время клика. Кроме этого можно включить режим, когда элемент TimeRanges можно кликом раскрыть на весь график.

Вот код, который позволяет перехватить и обработать это событие:

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_TIME_RANGE) {
    
    if(m_time_ranges1.Id() == lparam) {
      Print(__FUNCTION__, " > pressed time: ", ::TimeToString((datetime)dparam, TIME_MINUTES|TIME_SECONDS), "; pressed time range: ", sparam);
      
      string time_ranges[];
      m_time_ranges1.GetTimeRanges(time_ranges);
      
      ArrayPrint(time_ranges);
      return;
    }
    return;
  }
}

Как видно в листинге кода выше, сначала проверяется id события и если это пользовательское событие ON_CLICK_TIME_RANGE, то далее проверяем идентификатор элемента, который передаётся в событии в lparam-параметре. Далее выводим полученные данные в журнал. Для примера также показано, как получить установленные интервалы в элементе с помощью метода CTimeRanges::GetTimeRanges() и тоже выводим полученный массив в журнал.

В логах экспертов (вкладка Experts) Вы увидите примерно такие записи:

CApp::OnEvent > pressed time: 16:34:54; pressed time range: 15:30:00 - 17:39:59
"00:45:00-01:20:01" "08:55:00-09:25:01" "12:55:00-13:50:01" "15:30:00-17:39:59" "20:10:00-21:05:00"

Следующий пример показывает, как получить массив номеров проходов из таблицы избранных результатов (FAVORITE_RESULTS) в базе данных.

void CApp::GetPassNumbersOfFavoriteResults(const string db_filename, ulong &passes[]) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " open failed with code: ", ::GetLastError());
    return;
  }
  
  string command = "SELECT (Pass) FROM FAVORITE_RESULTS;";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return;
  }

  for(int i = 0; ::DatabaseRead(db_query); i++) {
    int pass_number;
    ::ResetLastError();
    if(::DatabaseColumnInteger(db_query, 0, pass_number)) {
      int prev_size = ::ArraySize(passes);
      ::ArrayResize(passes, prev_size + 1);
      passes[prev_size] = (ulong)pass_number;
    } 
    else {
      ::Print(__FUNCTION__, " > DatabaseColumnInteger() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
}

После того, как мы получили номера проходов мы можем получать удалённые интервалы, указывая номер прохода с помощью метода GetFavoriteRemovedIntervalsByPassNumber():

string CApp::GetFavoriteRemovedIntervalsByPassNumber(const ulong pass_number) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(m_db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " open failed with code: ", ::GetLastError());
    return(NULL);
  }
  
  string command = "SELECT (RemovedIntervals) FROM FAVORITE_RESULTS WHERE Pass=" + (string)pass_number + ";";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return(NULL);
  }
  
  string time_ranges = "";
  
  if(::DatabaseRead(db_query)) {
    ::ResetLastError();
    if(!::DatabaseColumnText(db_query, 0, time_ranges)) {
      ::Print(__FUNCTION__, " > DatabaseColumnText() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
  
  return(time_ranges);
}

Нажимая на кнопку Open DB... для открытия файла с базой данных, вызывается метод OnClickOpenDB(), в котором программа открывает диалоговое окно для выбора файла в директории MQL5/Files/DB. Если файл выбран, то его сохраняется для дальнейшего использования в других методах. Затем с помощью метода GetPassNumbersOfFavoriteResults(), код которого был приведён в предыдущем листинге, получаем в массив номера проходов из таблицы избранных результатов. Добавляем эти данные в выпадающий список и выбираем первый пункт.

bool CApp::OnClickOpenDB(const int id) {

  if(m_button1.Id() != id) {
    return(false);
  }

  string filenames[];
  string folder = "DB";
  string filter = "DB files (*.db)|*.db|SQLite files (*.sqlite)|*.sqlite|All files (*.*)|*.*";
  if(::FileSelectDialog("Select database file to upload", folder, filter,
                        FSD_FILE_MUST_EXIST, filenames) > 0) {
    
    int filenames_total = ::ArraySize(filenames);
    if(filenames_total < 1) {
      return(false);
    }
    
    m_db_filename = filenames[0];
    
    ::Print(__FUNCTION__, " > m_db_filename: ", m_db_filename);
    
    ulong passes[];
    GetPassNumbersOfFavoriteResults(m_db_filename, passes);
    
    ::ArrayPrint(passes);
    
    CListView *list_view = m_combobox1.GetListViewPointer();
    
    int passes_total = ::ArraySize(passes);
    if(passes_total > 0) {
      list_view.Clear();
      for(int i = 0; i < passes_total; i++) {
        list_view.AddItem(i, (string)passes[i]);
      }
      m_combobox1.SelectItem(0);
      m_combobox1.GetButtonPointer().Update(true);
      list_view.Update(true);
    }
  }
  return(true);
}

Выбирая в выпадающем списке номер прохода будем получать относящиеся к нему удалённые интервалы в методе SetTimeRange(), сохраняя их в глобальном массиве и устанавливая в графический элемент типа CTimeRanges.

void CApp::SetTimeRange(void) {

  CListView *list_view = m_combobox1.GetListViewPointer();
  
  int   index       = list_view.SelectedItemIndex();
  ulong pass_number = (int)list_view.GetValue(index);
  
  string removed_intervals = GetFavoriteRemovedIntervalsByPassNumber(pass_number);
  
  ::ArrayFree(m_time_ranges_str);
  ::StringSplit(removed_intervals, ::StringGetCharacter("|", 0), m_time_ranges_str);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    ::StringReplace(m_time_ranges_str[i], " - ", "-");
  }
  
  ::ArrayPrint(m_time_ranges_str);
  
  m_time_ranges1.SetTimeRanges(m_time_ranges_str);
  m_time_ranges1.Update();
}

Далее нам понадобится структура для хранения временных диапазонов. Если Вы используете библиотеку EasyAndFastGUI 2.0, то такая структура (TimeRange) уже есть в файле элемента CTimeRanges:

struct TimeRange {
  MqlDateTime start;
  MqlDateTime end;
};

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

Так как в строковом виде удалённые временные диапазоны уже сохраняются в методе SetTimeRange(), то теперь нам нужно получить их в массив структур, чтобы с ними было удобно работать в дальнейшем. Для этого нужно использовать метод GetTimeRanges():

void CApp::GetTimeRanges(TimeRange &ranges[]) {
  
  ::ArrayFree(ranges);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    
    string tr[];
    ::StringSplit(m_time_ranges_str[i], ::StringGetCharacter("-", 0), tr);
  
    int size = ::ArraySize(ranges);
    ::ArrayResize(ranges, size + 1);
    
    MqlDateTime start, end;
    ::TimeToStruct(::StringToTime(tr[0]), start);
    ::TimeToStruct(::StringToTime(tr[1]), end);
    
    datetime time1 = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time2 = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    ::TimeToStruct(time1, ranges[size].start);
    ::TimeToStruct(time2, ranges[size].end);
  }
}

Для примера эти методы могут использоваться вот так при обработке соответствующих событий (сокращённый вариант класса приложения):

class CApp : public CCoreCreate {
 private:
  TimeRange         m_time_ranges[];
  string            m_time_ranges_str[];
  
...

  virtual void      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

  void              SetTimeRange(void);
  void              GetTimeRanges(TimeRange &ranges[]);
  
  int               HourSeconds(const int hour)     { return(hour * 60 * 60); }
  int               MinuteSeconds(const int minute) { return(minute * 60);    }
};

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_BUTTON) {
    if(OnClickOpenDB((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
  
  if(id == CHARTEVENT_CUSTOM + ON_CLICK_COMBOBOX_ITEM) {
    if(OnSelectPass((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
}

Теперь можно написать метод CheckTradeTime() для проверки условий торговать только в разрешённое время:

bool CApp::CheckTradeTime(void) {

  bool     is_trade_time = true;
  datetime current_time  = ::TimeCurrent();
  
  MqlDateTime time;
  ::TimeToStruct(current_time, time);
  
  int ranges_total = ::ArraySize(m_time_ranges);
  for(int i = 0; i < ranges_total; i++) {
  
    MqlDateTime start = m_time_ranges[i].start;
    MqlDateTime end   = m_time_ranges[i].end;
    
    datetime time_c = HourSeconds(time.hour) + MinuteSeconds(time.min) + time.sec;
    datetime time_s = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time_e = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    
    if(time_c >= time_s && time_c <= time_e) {
      is_trade_time = false;
      break;
    }
  }
  return(is_trade_time);
}

Всё, что нужно сделать сейчас, это установить вызов метода CheckTradeTime(), например, в функции OnTick():

  if(CheckTradeTime()) {
    Print(__FUNCTION__, " > trade time!");
  }

Вы можете скачать в конце статьи готовое приложение с демонстрацией того, что было описано выше.

Демонстрация получения исключенных временных интервалов из торговли

Демонстрация получения исключенных временных интервалов из торговли


Заключение

Давайте подведём итоги.

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

Что такое Frames Analyzer? Это подключаемый модуль к любому торговому эксперту для анализа фреймов оптимизации во время оптимизации параметров в тестере стратегий, а также вне тестера посредством чтения MQD-файла или базы данных, которая создаётся сразу после оптимизации параметров. Вы сможете делиться этими результатами оптимизации с другими пользователями, у которых есть "Frames Analyzer", чтобы обсудить полученные результаты оптимизации вместе.

"Frames Analyzer" позволяет Вам просматривать 100 лучших результатов оптимизации одновременно в виде графиков. Эти 100 лучших результатов можно получить, применяя различные критерии: Profit, Trades, Drawdown, Profit Factor, Recovery Factor. Более того, в инструмент "Frames Analyzer" встроен модуль Best Intervals для определения убыточных временных интервалов, который отключает их из истории сделок, чтобы посмотреть, какой бы получился результат, если бы торговля не велась в эти периоды.

Все понравившиеся результаты можно сохранить в базу данных, а также в виде готовых set-файлов с внешними параметрами эксперта. Удалённые временные интервалы также сохраняются в базу данных. Таким образом, Вы можете применить их в своей торговле, чтобы улучшить результат, попробовав таким образом максимизировать прибыль. "Frames Analyzer" оставит только те временные интервалы для торговли, которые статистически показали себя максимально безопасными!


Прикрепленные файлы |
MQL5.zip (5327.07 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (5)
fxsaber
fxsaber | 8 нояб. 2022 в 10:19

Спасибо Автору за замечательный инструмент!


Очень кратко на простом языке о некоторых возможностях из статьи.

  • Сохраняются все проходы оптимизации. Поэтому мгновенно можно подробно посмотреть любой проход.
  • Автоматически формируется подсказка об "уязвимостях" ТС. И демонстрируется  (со всем деталями и визуализациями) результат устранения этих "слабых звеньев".
Anatoli Kazharski
Anatoli Kazharski | 8 нояб. 2022 в 16:13
fxsaber #:

Спасибо Автору за замечательный инструмент!

Очень кратко на простом языке о некоторых возможностях из статьи.

  • Сохраняются все проходы оптимизации. Поэтому мгновенно можно подробно посмотреть любой проход.
  • Автоматически формируется подсказка об "уязвимостях" ТС. И демонстрируется  (со всем деталями и визуализациями) результат устранения этих "слабых звеньев".

Спасибо и Вам! Без вашего участия конечно же этого инструмента вообще бы не было. Разработка такого приложения оказалась довольно трудоёмким процессом. 

Если дополнять список плюсов данного подхода, то сюда также можно добавить и это:

  • Исключение из внешних параметров эксперта тех параметров, которые относятся к временным диапазонам. В вашей реализации всё это делается уже после оптимизации и практически мгновенно.
Matija Bensa
Matija Bensa | 19 нояб. 2022 в 15:09
I want to test your your Frames Analyzer but can't manage to run the demo. After installation I move it to the chart and press demo but nothing happens. What should I do?
Anatoli Kazharski
Anatoli Kazharski | 19 нояб. 2022 в 22:02
Matija Bensa #:
I want to test your your Frames Analyzer but can't manage to run the demo. After installation I move it to the chart and press demo but nothing happens. What should I do?
I'm glad you liked the idea too!

Unfortunately, at the moment in the market as demo-versions are only available to download trading experts, because they can be tested in the tester.

Utilities such as Frames Analyzer cannot be downloaded and tested as a demo version.

But it is a good idea and I will think about how to implement it. Perhaps it will be a demo with limited functionality.
Anatoli Kazharski
Anatoli Kazharski | 22 нояб. 2022 в 19:40

Опубликовано обновление (v3.1):

  • В графический интерфейс добавлен элемент для визуализации исключенных из торговли временных диапазонов.
  • Исправление мелких багов по сообщениям пользователей инструмента.


Нейросети — это просто (Часть 32): Распределенное Q-обучение Нейросети — это просто (Часть 32): Распределенное Q-обучение
В одной из статей данной серии мы с вами уже познакомились с методом Q-обучения. Данный метод усредняет вознаграждения за каждое действие. В 2017 году были представлены сразу 2 работы, в которых большего успеха добиваются при изучении функции распределения вознаграждения. Давайте рассмотрим возможность использования подобной технологии для решения наших задач.
Машинное обучение и Data Science. Нейросети (Часть 02): архитектура нейронных сетей с прямой связью Машинное обучение и Data Science. Нейросети (Часть 02): архитектура нейронных сетей с прямой связью
В предыдущей статье мы начали изучать нейросети с прямой связью, однако остались неразобранными некоторые моменты. Один из них — проектирование архитектуры. Поэтому в этой статье мы рассмотрим, как спроектировать гибкую нейронную сеть с учетом входных данных, количества скрытых слоев и узлов для каждой сети.
Возможности Мастера MQL5, которые вам нужно знать (Часть 3): Энтропия Шеннона Возможности Мастера MQL5, которые вам нужно знать (Часть 3): Энтропия Шеннона
Современный трейдер почти всегда находится в поиске новых идей. Он постоянно пробует новые стратегии, модифицирует их и отбрасывает те, что не оправдали себя. В этой серии статей я постараюсь доказать, что Мастер MQL5 является настоящей опорой трейдера.
DoEasy. Элементы управления (Часть 25): WinForms-объект "Tooltip" DoEasy. Элементы управления (Часть 25): WinForms-объект "Tooltip"
В статье начнём разработку элемента управления Tooltip ("всплывающая подсказка") и начнём создание новых графических примитивов для библиотеки. Естественно, не у каждого элемента есть всплывающая подсказка, но возможность её задать для него есть у каждого графического объекта.