Обсуждение статьи "Пакетный подход к разработке на языке MQL5 с помощью KnitPkg"

Опубликована статья Пакетный подход к разработке на языке MQL5 с помощью KnitPkg:

В статье предлагается подход, который помогает повысить надежность продуктов для MetaTrader, создаваемых на MQL, и эффективность разработки за счет повторно используемых "пакетов", которыми управляет KnitPkg — менеджер проектов для MQL5/MQL4. Пакет можно использовать как составной элемент других пакетов или как основу для конечных артефактов, запускаемых непосредственно на платформе MetaTrader, например советников, индикаторов и других программ.

Трейдеру-разработчику часто приходится сопровождать несколько проектов на языке MQL5 (советники, индикаторы, утилиты), в которых используется общий математический и служебный код. Сегодня код обычно используют повторно по старинке: копируют папки из проекта в проект и вручную редактируют директивы #include. С каждым обновлением возникает рассинхронизация версий: где-то уже есть новое исправление, а где-то остается старый файл. При этом результат сборки только средствами MetaTrader зависит от того, какие исправления уже были вручную внесены в данном терминале. На самом деле нужен способ один раз реализовать компонент в репозитории Git, управлять его версиями по SemVer и подключать к разным проектам так, чтобы установка и сборка были воспроизводимыми на любом компьютере: зависимости зафиксированы, артефакты генерируются автоматически (дерево заголовочных файлов или единый заголовочный файл), а перенос кода между проектами больше не требует редактирования путей или копирования файлов.

В этой статье представлен такой процесс разработки на языках MQL4/MQL5 с использованием пакетов KnitPkg: каждый функциональный блок оформляется как повторно используемый компонент с управлением версиями, а затем подключается к разным проектам через манифест, а не путем копирования кода. В статье мы увидим, как этот подход повышает надежность сборки, повторного использования кода в советниках и индикаторах, а также публикации, превращая разрозненные фрагменты кода в структурированные компоненты с управляемыми зависимостями.


Автор: Douglas Nascimento Rechia

Выглядит интересно, но у меня есть некоторые сомнения.

Если кто-то клонирует репозиторий Git с проектом/программой/пакетом MQL5, который должен управляться KnitPkg, он, скорее всего, получит некомпилируемые исходные коды, поскольку в репозитории отсутствуют автоматически сгенерированные файлы (такие как _flat). Не было бы целесообразно зафиксировать в Git весь необходимый автоматически сгенерированный исходный код, чтобы релиз компилировался независимо от того, как он был получен?

Не уверен, насколько удобно будет вносить изменения в зависимости, ведь мы фактически компилируем и отлаживаем автоматически сгенерированный код и не можем легко «перейти» к соответствующему источнику — может, я что-то упускаю? Например, вам нужно изменить пакет bar при работе над индикатором (если не над советником). Как бы вы это сделали?

Наконец, у меня возникают сомнения по поводу некоторых моментов в реализации примеров (вероятно, потому что это всего лишь примеры), таких как вызов new/delete при каждом тике/баре. Кроме того, например, вы делаете следующее:

int OnCalculate(const int32_t rates_total,
                const int32_t prev_calculated,
                const int32_t begin,
                const double &price[])
{
   ...
   douglasrechia::TimeSeriesArray<double> priceArray(price, prev_calculated - InpSMAPeriod - 1, rates_total-1, false);
   ...
   for (int shift=shiftStart; shift >= 0 && !IsStopped(); shift--)
   {
      SMABuffer[shift] = douglasrechia::SMA(priceArray, InpSMAPeriod, shift);
   }
   ...
}

В чём смысл передавать массив цен в конструктор priceArray (где создаётся копия части массива), а затем передавать priceArray в SMA — почему бы не передать исходный массив цен по ссылке в SMA без копирования?

Stanislav Korotky репозиторий Git с проектом/программой/пакетом MQL5, который должен управляться KnitPkg, он, скорее всего, получит исходные коды, которые не поддаются компиляции, поскольку в репозитории отсутствуют автоматически сгенерированные файлы (такие как _flat). Не было бы целесообразно зафиксировать в Git весь необходимый автоматически сгенерированный исходный код, чтобы релиз компилировался независимо от того, как он был получен?

Не уверен, насколько удобно будет вносить изменения в зависимости, поскольку мы фактически компилируем и отлаживаем автоматически сгенерированный код и не можем легко «перейти» к соответствующему источнику — может, я что-то упускаю? Например, вам нужно изменить пакет bar при работе над индикатором (если не над советником). Как бы вы это сделали?

Наконец, у меня есть сомнения по поводу некоторых моментов в реализации примеров (вероятно, потому что это всего лишь примеры), таких как вызов new/delete на каждом тике/баре. Кроме того, например, вы делаете так:

В чём смысл передавать массив цен в конструктор priceArray (где создаётся копия части массива), а затем передавать priceArray в SMA — почему бы не передать исходный массив цен по ссылке в SMA без копирования?


Здравствуйте, Станислав,

спасибо, что нашли время прочитать статью и подняли эти вопросы.

Что касается фиксации сгенерированного кода: идея KnitPkg заключается в том, что автоматически сгенерированные артефакты (плоские заголовки, разрешённые включения и т. д.) не должны находиться в репозитории Git, поскольку в этом случае вы фактически дублируете код между репозиториями и рискуете, что он перестанет синхронизироваться. Если какая-то функциональность реализована в пакете/репозитории, это и является единственным достоверным источником; пользователи объявляют зависимость (используя диапазоны SemVer) и позволяют командам `kp install` или `kp autocomplete` перегенерировать производные файлы локально. Таким образом, когда зависимость обновляется в пределах допустимого диапазона SemVer, ваш проект может без проблем перейти на новую версию, вместо того чтобы «застрять» с устаревшим сгенерированным кодом, зафиксированным в собственном репозитории. Конкретный пример обновления версий зависимостей приведён в документации здесь.

Что касается вашего вопроса о том, «насколько удобно будет вносить изменения в зависимости»: я думал об этом при разработке инструмента. KnitPkg поддерживает использование локальных зависимостей, поэтому вы можете напрямую указать проекту пакет, находящийся в локальном каталоге, изменить этот пакет и протестировать изменения в реальном проекте-потребителе во время разработки. Этот рабочий процесс более подробно описан в разделе «Локальные зависимости» документации KnitPkg: https://docs.knitpkg.dev/user-guide/local-dependencies/

Что касается price → TimeSeriesArray → SMA: цель здесь не в том, чтобы показать наиболее эффективную микрооптимизацию, а в том, чтобы продемонстрировать стандартизированный интерфейс. SMA принимает ITimeSeries (а не непосредственно TimeSeriesArray) и обращает внимание только на то, что «самый последний элемент находится по индексу 0, следующий — по индексу 1 и т. д.». TimeSeriesArray — это всего лишь одна из реализаций, использованных в примере, которая, как оказалось, копирует фрагмент массива price. Кто-то другой мог бы реализовать другой ITimeSeries, использующий структуру, более подходящую для кэширования. Суть заключается в отделении вычислений от конкретной схемы хранения; насколько умной или эффективной будет реализация ITimeSeries, становится вопросом дизайна и творческого подхода.

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

Local Dependencies¶
  • docs.knitpkg.dev
Local Dependencies¶ During development, it is often useful to test a package in a real project before publishing it to the registry. In this section, we will demonstrate how to use local dependencies by integrating the package into the project. We will implement a simple SMA-based trading strategy with the following logic: Entry condition...