Обсуждение статьи "Паттерн "Репозиторий" в MQL5: Абстрагирование доступа к торговой истории для обеспечения тестируемости логики советника"

Опубликована статья Паттерн "Репозиторий" в MQL5: Абстрагирование доступа к торговой истории для обеспечения тестируемости логики советника:

Прямые вызовы API торговой истории MQL5 внутри аналитических компонентов создают скрытые зависимости от терминала, из-за которых изолированное тестирование невозможно на уровне архитектуры. В данной статье создается слой абстракции ITradeRepository с реализациями CLiveTradeRepository и CMockTradeRepository, позволяющий одному и тому же аналитическому модулю и панели кривой средств одинаково работать как с текущими данными торгового счета, так и с детерминированным набором данных в памяти. Внедрение репозитория устраняет прямую связанность с API, позволяет проводить проверку в автономном режиме и при смене источника данных ограничивает необходимые изменения одним классом реализации.

Аналитический модуль советника (EA), который напрямую вызывает функции HistorySelect(), HistoryDealGetDouble() и HistoryDealGetInteger() внутри своих методов расчёта, создаёт скрытые зависимости от состояния терминала MetaTrader 5. Например, такой метод, как CalculateWinRate(), выглядит как чистая функция. На практике для работы метода требуются активное соединение с брокером и загруженная история счета. Кроме того, требуется предварительный вызов функции HistorySelect() с указанием правильного диапазона дат. Если какое-либо из этих условий не выполняется, метод возвращает некорректные результаты, не генерируя при этом обнаруживаемой ошибки.

Такая сильная связанность создает серьезные ограничения при тестировании и сопровождении. Аналитический модуль, написанный таким образом, невозможно запустить изолированно. Для модульного тестирования CalculateWinRate() нужны работающий терминал и активное соединение. Также понадобится торговый счет с соответствующими историческими данными. Массовая проверка граничных случаев, таких как пустая история, практически неосуществима. Это вынуждает разработчика либо вручную очищать данные терминала, либо встраивать условную логику для тестирования в рабочий код.

Затраты на сопровождение нарастают по мере роста кодовой базы:

  • Изменения в API: если брокер изменяет свою схему классификации сделок, все методы расчёта, использующие функцию HistoryDealGetInteger(), необходимо обновить вручную.
  • Препятствия для переноса: перенос советника к другому брокеру или на другую архитектуру требует отделения аналитического кода от слоя доступа к данным.
  • Дублирование кода: новые модули должны либо дублировать схему извлечения данных, либо опираться на недокументированное предположение о том, что другой модуль уже инициализировал состояние истории.

Сравнение архитектур до и после применения принципа инверсии зависимостей


Автор: Ushana Kevin Iorkumbul