English Deutsch 日本語
preview
Пакетный подход к разработке на языке MQL5 с помощью KnitPkg

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

MetaTrader 5 — Интеграция |
65 2
Douglas Nascimento Rechia
Douglas Nascimento Rechia

Введение

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

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


Что такое KnitPkg

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

  • хранению только метаданных в центральном реестре, тогда как исходный код остается в обычных репозиториях Git;
  • поддержке зависимостей с семантическим версионированием (^, ~, * и т.д.), позволяющей точно указать требуемую версию пакета;
  • созданию lock-файла для воспроизводимых сборок;
  • поддержке двух режимов установки — include (классическое дерево заголовочных файлов) и flat (единый сгенерированный заголовочный файл, удобный для распространения кода в Маркете MQL5).

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

В этом разделе мы приводим краткий обзор ключевых идей, лежащих в основе KnitPkg. Более подробное описание см. в документации KnitPkg и на главной странице KnitPkg.

1. Манифест. Манифест — это "мозг" репозитория проекта KnitPkg: он сообщает KnitPkg, что представляет собой этот репозиторий, как собирать проект и какие зависимости ему нужны. Манифест хранится в формате YAML в файле с именем knitpkg.yaml или knitpkg.yml. Также поддерживается формат JSON; в этом случае имя файла — knitpkg.json.

2. Проекты и пакеты. Проект — это стандартный "контейнер": индикатор, советник, скрипт, библиотека, сервис или даже репозиторий тестов. В проектах KnitPkg исходный код обычно хранится в каталоге src/, а KnitPkg автоматически генерирует артефакты зависимостей (дерево заголовочных файлов либо единый заголовочный файл) в каталоге knitpkg/.

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

Одиночные и составные пакеты. В KnitPkg пакеты бывают двух типов:

  • одиночный пакет — автономный пакет, не объявляющий зависимостей;
  • составной пакет — пакет, который зависит от одного или нескольких других пакетов (напрямую или косвенно).

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

  • вспомогательного заголовочного файла для разработки (autocomplete.mqh);
  • директив @knitpkg:include, которые KnitPkg при установке преобразует в реальные директивы #include во время выполнения команды kp install.

KnitPkg предоставляет специальные команды для генерации заголовочного файла autocomplete.mqh и проверки корректности директив, чтобы пакет правильно устанавливался при использовании в других проектах.

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

Благодаря KnitPkg хорошо спроектированный пакет можно использовать несколькими способами независимо от стиля реализации:

  1. Прямой вызов кода через зависимости KnitPkg, объявленные в манифесте.
  2. Через библиотеку на языке MQL: библиотека инкапсулирует функциональность пакета и предоставляет к ней доступ. Библиотека также создается как проект KnitPkg.
  3. Через индикатор на языке MQL: индикатор может использовать пакет для вычислений, а затем предоставлять результаты через свои буферы. Индикатор отображает данные на графике (выступая в роли "представления" для пакета), а также предоставляет информацию (результат вычисления), которую могут использовать другие советники. Таким образом, любой советник может через индикатор получить результат вычисления, выполненного компонентом, — так же, как при использовании нативной функции.

Подводя итог, перечислим преимущества реализации пакетов с помощью KnitPkg:

  • каждый функциональный блок реализуется один раз в репозитории Git с управлением версиями по SemVer;
  • пакет можно повторно использовать в любом проекте столько раз, сколько потребуется, без дублирования кода;
  • пакет можно повторно использовать в наиболее удобной для конкретной задачи форме (прямой вызов кода, индикатор или библиотека).

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

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

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

4. Реестр. KnitPkg состоит из двух частей:
  • CLI — инструмент командной строки, который вы запускаете локально и с которым взаимодействуете напрямую (например, kp install);
  • реестр — веб-служба, которая хранит метаданные, извлеченные из манифестов проектов, и предоставляет их CLI.

Реестр позволяет CLI надежно находить проекты и разрешать зависимости, тогда как исходный код по-прежнему хранится в репозиториях Git. Он хранит метаданные манифестов проектов, управляемых KnitPkg. CLI использует реестр для поиска общедоступных проектов и получения сведений о них, выбора конкретной версии зависимости из заданного диапазона и определения точной ревизии исходного кода (коммита), соответствующей выбранной версии. Репозитории Git могут размещаться на MQL5Forge, GitHub, GitLab или Bitbucket.

Все зарегистрированные проекты также можно просматривать через веб-интерфейс реестра, который упрощает разработчикам и трейдерам поиск нужных пакетов, советников и индикаторов.


Практический пример — создание повторно используемых пакетов с помощью KnitPkg

Основная цель этого практического примера — реализовать один расчет (SMA) и повторно использовать его в трех разных артефактах: пакете, индикаторе и советнике. Торговые правила намеренно просты; основное внимание уделяется тому, как один и тот же компонент объявляется, получает версию, устанавливается и повторно используется без копирования кода.
  • Итоговый исполняемый артефакт — это советник, который открывает длинную позицию по сигналу двух скользящих средних: когда краткосрочная SMA (sma1) пересекает долгосрочную SMA (sma2) снизу вверх. В качестве фильтра используется третья SMA (sma3): вход в рынок разрешается только при выполнении условия Close > sma1 > sma2 > sma3. Позицию следует закрыть, когда sma1 пересекает sma2 сверху вниз. Советник должен использовать как можно меньше ресурсов процессора.
  • Для работы советника мы создадим индикатор KnitPkgSMA, который рассчитывает простую скользящую среднюю для текущего графика. SMA следует (пере)рассчитывать только при появлении нового бара, а не на каждом тике.
  • Код для расчета SMA следует разместить в пакете, чтобы его можно было использовать повторно.
  • Пакет SMA должен принимать обобщенный интерфейс, представляющий временной ряд (TimeSeries), где индекс 0 всегда соответствует последнему значению цены (индекс работает как "сдвиг").
  • Пакет, содержащий реализацию SMA (а в будущем и других индикаторов), должен быть пригоден для повторного использования как индикатором KnitPkgSMA, так и любым другим пакетом или проектом.
  • Чтобы эффективно использовать SMA повторно в советнике, необходимо предусмотреть стандартный способ проверки появления нового бара на каждом тике.
  • Если советнику требуется доступ к данным OHLCV, он также должен получать их через стандартный интерфейс временных рядов (индекс 0 — для последних значений).
Далее мы последовательно пройдем конкретные, проверяемые шаги от исходной проблемы копирования кода до работающего решения в MetaTrader 5. Сначала мы определим целевые артефакты (пакеты, индикатор, советник) и ограничения на их сборку. Затем мы опишем каждый из них в манифесте knitpkg.yaml, указав зависимости с версиями по SemVer, поручим KnitPkg установить и подключить эти зависимости (в режиме Include или Flat) и, наконец, проверим результат с помощью модульных тестов и команды kp checkinstall. В итоге мы получим воспроизводимую связку "пакет → индикатор → советник", в которой один и тот же компонент используется в разных проектах без копирования кода или ручного редактирования путей в директивах #include.

Целевые артефакты пакетов. Для выполнения поставленных требований были созданы следующие пакеты:

  • @douglasrechia/bar — содержит интерфейсы для TimeSeries и баров OHLCV, а также средства обнаружения появления нового бара на каждом тике. См. Git-репозиторий пакета bar.
  • @douglasrechia/calc — пакет calc, созданный на основе пакета bar и содержащий реализацию SMA; в будущем в него будут добавлены и другие индикаторы. См. Git-репозиторий пакета calc.

Примечание 1. В KnitPkg проект обозначается как @<organization>/<repository_name>, где organization и repository_name берутся из двух последних элементов URL Git-репозитория и приводятся к нижнему регистру.

Примечание 2. Чтобы содержание статьи по-прежнему соответствовало коду, даже если репозитории со временем изменятся (появятся новые коммиты), ссылки ведут на коммит, соответствующий последней версии пакетов на момент написания статьи.

1. Изучение пакета bar. В соответствии с соглашением KnitPkg заголовочные файлы пакета bar находятся в каталоге knitpkg/include/<organization>/<project_name>, в данном случае — knitpkg/include/douglasrechia/bar/.
Добавлять код в knitpkg/include/ разрешается только для проектов типа package; для всех остальных типов проектов содержимое каталога knitpkg/ нельзя редактировать вручную.
Заголовочные файлы в knitpkg/include/douglasrechia/bar/ содержат классы и интерфейсы для TimeSeries, Bar (средство доступа к данным OHLCV по принципу временного ряда) и BarWatcher (для обнаружения нового бара на каждом тике). Читателям рекомендуется ознакомиться с репозиторием и изучить код.

В репозитории bar манифест knitpkg.yaml выглядит следующим образом:

target: mql5
type: package
organization: douglasrechia
name: bar
version: 1.1.0
version_description: New constructor for TimeSeriesArray

# Search fields
description: Simple, fast and reliable bar access with time series and new bar detection.
keywords: [ "bar", "array", "timeseries", "demo", "showcase" ]
author: Douglas Rechia
license: MIT

compile:
  - tests/UnitTestsBarArray.mq5
  - tests/UnitTestsBarMqlRates.mq5
  - tests/UnitTestsTimeSeries.mq5

В MetaTrader пакет фактически создается как проект типа Script. Скомпилированные скрипты модульных тестов показывают, соответствует ли результат ожидаемому. Теперь загрузим этот пакет и запустим его модульные тесты.

2. Загрузка и запуск модульных тестов пакета bar. Предполагается, что вы уже выполнили инструкции по установке KnitPkg и установили MetaTrader с нуля в каталог `C:\Program Files\MetaTrader 5`.

Откройте MetaTrader и выберите Файл > Открыть каталог данных. Затем щелкните правой кнопкой мыши в окне папки и выберите Открыть в Терминале:

Open Data folder in Terminal

Теперь должно появиться окно терминала, открытого в папке данных MetaTrader:

Terminal in Data folder

Чтобы загрузить исходный код пакета bar и скомпилировать его непосредственно в среде MetaTrader, выполните следующую команду:

kp get mql5 @douglasrechia/bar -v 1.1.0

Примечание: параметр -v для kp get необязателен; здесь явно задана версия 1.1.0, чтобы описание в статье соответствовало версии кода пакета. Если параметр -v не указан, команда kp get выбирает последнюю стабильную версию.

Ниже показано, как выглядит окно терминала после выполнения команды kp get:

Terminal after kp get bar

Таким образом, мы получаем не только локальную копию исходного кода пакета bar версии 1.1.0, но и бинарные файлы модульных тестов, скомпилированные из этого кода. Вернитесь в MetaTrader и обновите раздел "Скрипты" в окне "Навигатор". Вы увидите тестовые скрипты в папке "Скрипты/bar/bin/". Запустите скрипты UnitTestsBarArray, UnitTestsBarMqlRates и UnitTestsTimeSeries (просто дважды щелкните по каждому из них). Результаты тестирования можно посмотреть на вкладке "Эксперты" в панели "Инструменты":

Unit tests results

Вы можете открыть и изучить проект bar, который был загружен в каталог "Скрипты/bar". Обратите внимание, что это репозиторий с управлением версиями в Git.

Bar project in terminal

Также обратите внимание на файл манифеста knitpkg.yaml и заголовочные файлы в каталоге knitpkg/include/douglasrechia/bar/, которые будут экспортированы в любые проекты, использующие этот пакет.

Примечание: для просмотра файлов YAML и других исходных файлов, написанных не на языке MQL, используйте Windows Explorer и удобный вам редактор; рекомендуется VS Code. Для редактирования кода на языке MQL рекомендуется использовать MetaEditor.

Команда get: что происходит "под капотом". При выполнении команды kp get интерфейс командной строки KnitPkg обращается к реестру, чтобы получить последнюю стабильную версию запрошенного пакета (некоторые другие команды действуют аналогичным образом). Реестр возвращает URL репозитория Git и хеш коммита для этой версии. Затем команда kp get клонирует репозиторий с фиксацией на коммите с указанным хешем. Поэтому приведенный выше вывод git status показывает, что репозиторий находится в состоянии detached HEAD. Более подробные сведения см. в справке по kp get.

Пакет bar — одиночный пакет без зависимостей. Теперь перейдем к пакету calc — здесь все становится интереснее.

Этап 1 — пакет установлен без копирования кода. На этом этапе в вашей среде MetaTrader 5 доступна версия 1.1.0 пакета @douglasrechia/bar, и модульные тесты подтверждают, что он работает должным образом. В этой же среде ведется активная разработка пакета: создаются ветки разработки, исправляются ошибки, реализуются новые функции, фиксируются изменения и в итоге создается новая ревизия пакета — без изменения проектов, зависящих от bar.

3. Пакет calc — пример составного пакета. Как мы уже знаем, в пакете calc реализуется расчет SMA. Однако пакет calc будет использовать @douglasrechia/bar как зависимость: интерфейс TimeSeries передается в качестве аргумента функции расчета скользящей средней. Преимущество заключается в том, что функция SMA не зависит от конкретной реализации TimeSeries. Не имеет значения, реализован ли TimeSeries на основе простого массива или какой-либо другой структуры данных. Функции SMA достаточно выполнять расчет, исходя из того, что последний по времени элемент временного ряда находится на позиции 0, предыдущий — на позиции 1 и т.д.

Теперь повторим этот процесс. Выполните следующую команду, чтобы загрузить пакет calc версии 1.0.1:

kp get mql5 @douglasrechia/calc -v 1.0.1

В качестве упражнения вернитесь в MetaTrader и обновите раздел "Скрипты" в окне "Навигатор". Вы увидите тестовые скрипты в папке "Скрипты/bar/bin/". Запустите тесты и посмотрите результаты на вкладке "Эксперты" в панели "Инструменты".

Теперь рассмотрим проект calc и некоторые особенности его кода. Сначала рассмотрим манифест knitpkg.yaml проекта calc. Здесь появляется кое-что новое: в разделе dependencies указана зависимость calc от @douglasrechia/bar:

target: mql5
type: package

organization: douglasrechia
name: calc
version: 1.0.1
version_description: 'ATR fix'

description: Common indicators built on @douglasrechia/bar (SMA, ATR, etc)
keywords: [ "indicator", "sma", "atr", "showcase" ]
author: Douglas Rechia
license: MIT

dependencies:
  '@douglasrechia/bar': ^1.0.0

compile:
  - tests/UnitTestSMA.mq5
  - tests/UnitTestATR.mq5

Рассмотрим исходный код функции SMA в файле knitpkg/include/douglasrechia/calc/Calc.mqh. Ниже мы отметим несколько важных моментов, касающихся этого заголовочного файла, а также особенности составных пакетов.

Директива #include для autocomplete.mqh. В файле Calc.mqh именно директива #include для autocomplete.mqh позволяет создавать составной пакет "без лишних сложностей".

//...............

//------------------------------------------------------------------
// Development autocomplete — resolves dependencies and enables
// MetaEditor IntelliSense; automatically neutralized by KnitPkg 
// installer.
// Run `kp autocomplete` to regenerate.
//------------------------------------------------------------------
#include "../../../autocomplete/autocomplete.mqh"


//------------------------------------------------------------------
// KnitPkg include directives — used by KnitPkg installer at the time 
// this package is installed as a dependency into another KnitPkg 
// project.
//------------------------------------------------------------------
/* @knitpkg:include "douglasrechia/bar/TimeSeries.mqh" */
/* @knitpkg:include "douglasrechia/bar/Bar.mqh" */

namespace douglasrechia
{
//...............

Интересно, что файл autocomplete.mqh отсутствует в Git-репозитории. Команда kp autocomplete генерирует этот заголовочный файл по пути knitpkg/autocomplete/autocomplete.mqh. Команда kp get (которую мы использовали выше) автоматически вызывает kp autocomplete в ходе выполнения, поэтому команда get смогла автоматически скомпилировать пакет и его модульные тесты.

Как работает autocomplete. Посмотрите содержимое файла autocomplete.mqh в локально установленном пакете calc (этого заголовочного файла вы не найдете в репозитории; там его нет):

//+------------------------------------------------------------------+
//| autocomplete.mqh                                                 |
//| Generated by `kp autocomplete` — DO NOT EDIT                     |
//+------------------------------------------------------------------+
#include "knitpkg/include/douglasrechia/bar/Bar.mqh"
#include "knitpkg/include/douglasrechia/bar/BarArray.mqh"
#include "knitpkg/include/douglasrechia/bar/BarMqlRates.mqh"
#include "knitpkg/include/douglasrechia/bar/BarTimeSeries.mqh"
#include "knitpkg/include/douglasrechia/bar/BarWatcher.mqh"
#include "knitpkg/include/douglasrechia/bar/TimeSeries.mqh"
#include "knitpkg/include/douglasrechia/bar/TimeSeriesArray.mqh"

Обратите внимание, что заголовочные файлы пакета bar теперь находятся в каталоге knitpkg/autocomplete/knitpkg/include/douglasrechia/bar (только локально). Благодаря этому файл autocomplete.mqh обеспечивает работу IntelliSense в MetaEditor при редактировании Calc.mqh, а также позволяет компилировать модульные тесты. Эти заголовочные файлы создаются или подбираются при выполнении команды kp autocomplete, которая выполняет git clone (или fetch) в каталоге .knitpkg/cache/ для зависимостей, объявленных в манифесте. Это позволяет удобно разрабатывать пакеты, зависящие от других пакетов.

В составном пакете автоматически сгенерированный файл autocomplete.mqh — не просто удобное дополнение, а стандартное средство обеспечения компиляции в MetaEditor и работы IntelliSense. При этом разрешением и установкой самих зависимостей по-прежнему занимается KnitPkg. Без этого шага авторы пакетов неизбежно вернулись бы к ручному управлению директивами #include, а вместе с ним — к тем самым проблемам рассинхронизации версий и копирования кода, которые KnitPkg призван устранить.

Примечание: содержимое каталога knitpkg/autocomplete/ генерируется автоматически, и его нельзя редактировать.

Пространство имен (только для языка MQL5). В языке MQL5 код пакета рекомендуется помещать в пространство имен с тем же именем, что и у организации (в языке MQL4 пространства имен недоступны). Это позволяет избежать конфликтов имен при использовании пакетов разных организаций. Использование пространств имен вместе с соглашением о размещении заголовочных файлов в knitpkg/include/<organization>/<project name> гарантирует отсутствие конфликтов и предотвращает перезапись заголовочных файлов при построении их дерева.

Функция SMA. SMA — это функция, которая принимает в качестве аргумента временной ряд TimeSeries (интерфейс ITimeSeries) и возвращает среднее значение для заданных периода (количества элементов, по которым рассчитывается среднее) и сдвига (позиции расчета среднего в TimeSeries, где 0 соответствует последнему по времени значению, 1 — предыдущему и т.д.).

double SMA(douglasrechia::ITimeSeries<double> &series, int period, int shift = 0)
{
   if(series.Size() < (period + shift))
      return 0.0;

   double sum = 0.0;
   for(int i = shift; i < shift + period; i++)
      sum += series.ValueAtShift(i);

   return sum / period;
}

Как уже упоминалось, преимущество реализации SMA именно здесь, в пакете, а не в коде индикатора, заключается в возможности использовать этот код в любом другом проекте.

Подготовка составного пакета к установке: @knitpkg:include. Обратите внимание на следующие директивы в файле Calc.mqh:

/* @knitpkg:include "douglasrechia/bar/TimeSeries.mqh" */
/* @knitpkg:include "douglasrechia/bar/Bar.mqh" */

На первый взгляд это похоже на закомментированный код, который компилятор проигнорирует. Однако для KnitPkg эти директивы, заключенные между маркерами комментария /* и */, имеют особое значение: они указывают на внешние для calc заголовочные файлы, от которых зависит Calc.mqh. Оба заголовочных файла подключены в autocomplete.mqh, поэтому на этапе разработки MetaEditor может корректно компилировать Calc.mqh и скрипты модульных тестов.

Когда calc используется как зависимость в других проектах, файл Calc.mqh преобразуется: директива #include для autocomplete.mqh отключается, а директивы @knitpkg:include заменяются подключениями соответствующих внешних заголовочных файлов. Автор пакета обязан поддерживать директивы @knitpkg:include в актуальном состоянии, чтобы они указывали только на заголовочные файлы с определениями символов, используемых в данном заголовочном файле.

Чтобы помочь разработчикам проверять корректность этих директив, KnitPkg предоставляет команду kp checkinstall. Эта команда подготавливает разрабатываемый пакет в каталоге knitpkg/autocomplete/include/, в данном случае — knitpkg/autocomplete/knitpkg/include/douglasrechia/calc (да, в пути есть небольшое повторение). Локально вы можете увидеть, как будет выглядеть Calc.mqh после установки пакета в качестве зависимости (этой версии файла в репозитории нет и не будет):

//------------------------------------------------------------------
// Development autocomplete — resolves dependencies and enables
// MetaEditor IntelliSense; automatically neutralized by KnitPkg
// installer.
// Run `kp autocomplete` to regenerate.
//------------------------------------------------------------------
// #include "../../../autocomplete/autocomplete.mqh" /*** ← disabled by KnitPkg install (dev helper) ***/

//------------------------------------------------------------------
// KnitPkg include directives — used by KnitPkg installer at the time
// this package is installed as a dependency into another KnitPkg
// project.
//------------------------------------------------------------------
#include "../bar/TimeSeries.mqh" /*** ← dependency added by KnitPkg ***/
#include "../bar/Bar.mqh"       /*** ← dependency added by KnitPkg ***/

Команда kp checkinstall выполняется в составе kp get , поэтому этот файл уже сгенерирован, если вы загрузили проект с помощью kp get. На практике автор пакета может запускать kp checkinstall при каждом изменении директив @knitpkg:include или когда хочет убедиться, что пакет правильно установится в других проектах.

Вместе директивы @knitpkg:include и команда kp checkinstall обеспечивают этап проверки в процессе разработки. В процессе разработки они позволяют удобно работать с файлом autocomplete.mqh и IntelliSense в MetaEditor; при установке KnitPkg переписывает эти директивы в фактические директивы #include, указывающие на нужные заголовочные файлы зависимостей. Так обеспечивается связь между локальной разработкой и надежной установкой в другие проекты: не требуется вручную редактировать пути в директивах #include, а пропуск заголовочных файлов не остается незамеченным.

Этап 2 — общая логика проверена, составной пакет готов к повторному использованию. Пакет calc установлен, его модульные тесты скомпилированы и успешно пройдены. Логика SMA реализована один раз в протестированном компоненте на основе @douglasrechia/bar. Поскольку calc — составной пакет, его директивы @knitpkg:include также проверены с помощью kp checkinstall. Это подтверждает, что при использовании calc в качестве зависимости его заголовочные файлы будут корректно преобразованы и подключат установленные заголовочные файлы пакета bar. В результате пакет @douglasrechia/calc готов к использованию в других проектах (индикаторах, советниках, библиотеках): достаточно объявить его в их манифестах knitpkg.yaml, без ручной настройки путей в директивах #include или дублирования кода.

4. Индикатор sma. Теперь, когда все компоненты готовы, объединим их и посмотрим, как собирается индикатор. Для начала загрузим @douglasrechia/sma версии 1.0.1:

kp get mql5 @douglasrechia/sma -v 1.0.1

Примечание. В предыдущих разделах мы запускали kp get для проектов bar и calc по отдельности, чтобы вы могли изучить их независимо друг от друга. Это не требуется для использования индикатора SMA. Достаточно выполнить команду kp get mql5 @douglasrechia/sma: KnitPkg автоматически разрешит и загрузит все необходимые зависимости (включая bar и calc) без каких-либо предварительных действий.

Ниже показано, как выглядит окно терминала после выполнения команды kp get:

Terminal after sma get

На изображении выше в дереве разрешения зависимостей показаны выбранные и загруженные версии обоих пакетов — bar и calc. Рассмотрим манифест проекта sma:

target: mql5
type: indicator

organization: douglasrechia
name: sma
version: 1.0.1
version_description: Dependencies updated

# Registry search fields
description: KnitPkg for Metatrader - SMA Indicator Demo
keywords: [ "indicator", "sma", "showcase" ]
author: Douglas Rechia
license: MIT

# Include mode resolution
include_mode: flat

# File to be flattened with all the dependencies for this project
entrypoints:
  - src/KnitPkgSMA.mqh

compile:
  - src/KnitPkgSMA.mq5

# Dependencies of the project
dependencies:
  '@douglasrechia/calc': ^1.0.0

Обратите внимание на самые важные части манифеста, выделенные выше; мы их прокомментируем.

  • dependencies — sma зависит от @douglasrechia/calc. Хотя в качестве прямой зависимости объявлен только пакет calc, KnitPkg также подбирает и загружает bar как косвенную зависимость sma, поскольку calc зависит от bar.
  • include_mode: flat — sma использует режим Flat, при этом файл src/KnitPkgSMA.mqh объявлен точкой входа. Это означает, что все зависимости индикатора SMA будут объединены в единый заголовочный файл knitpkg/flat/KnitPkgSMA_flat.mqh. Ниже приведен фрагмент файла src/KnitPkgSMA.mqh:

/* @knitpkg:include "douglasrechia/calc/Calc.mqh" */
/* @knitpkg:include "douglasrechia/bar/TimeSeriesArray.mqh" */

Заголовочный файл, объявленный как точка входа (в данном случае src/KnitPkgSMA.mqh), используется только в режиме Flat и всегда должен содержать директивы @knitpkg:include, которые ссылаются на внешние заголовочные файлы, необходимые проекту.

Теперь рассмотрим основной исходный файл индикатора src/KnitPkgSMA.mq5. Ниже приведен его фрагмент:

// .....................
#include "../knitpkg/flat/KnitPkgSMA_flat.mqh"
// .....................
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t rates_total,
                const int32_t prev_calculated,
                const int32_t begin,
                const double &price[])
  {
//---
   if (rates_total < InpSMAPeriod)
      return(0);
   if (prev_calculated >= rates_total)
      return rates_total;

   douglasrechia::TimeSeriesArray<double> priceArray(price, prev_calculated - InpSMAPeriod - 1, rates_total-1, false);

   // The following loop recalculates the SMA for the most recent bars.
   // This is necessary because the current bar's data can change with each tick
   // until its formation is complete. The `shiftStart` variable determines
   // the initial index for recalculation, ensuring that the SMA is accurately
   // updated for the latest bar and any preceding bars affected by recent data changes.
   int shiftStart = rates_total-prev_calculated;
   if (shiftStart >= rates_total)
      shiftStart--;
   for (int shift=shiftStart; shift >= 0 && !IsStopped(); shift--)
   {
      SMABuffer[shift] = douglasrechia::SMA(priceArray, InpSMAPeriod, shift);
   }
   return(rates_total);
  }

Обратите внимание, что мы используем стандартную директиву #include языка MQL, указывающую на единый заголовочный файл ../knitpkg/flat/KnitPkgSMA_flat.mqh. Единый заголовочный файл автоматически генерируется KnitPkg на основе точки входа и подобранных зависимостей на этапе kp install, поэтому в репозитории его нет (команда kp install также выполняется в составе kp get).

Теперь должно быть понятно, в чем преимущество использования пакетов: конкретная реализация расчета SMA не включена непосредственно в код индикатора. В результате код индикатора значительно упрощается: достаточно вызвать функцию из пакета calc и передать ей временной ряд (TimeSeries), построенный на основе массива цен, полученного в OnCalculate().

Если ранее вы выполнили kp get для загрузки sma, вернитесь в MetaTrader, обновите список индикаторов в окне "Навигатор" и добавьте на текущий график индикатор из Индикаторы/sma/bin/KnitPkgSMA:

KnitPkgSMA indicator

Этап 3 — сгенерирован пригодный для повторного использования артефакт режима Flat и скомпилирован индикатор. После запуска kp get KnitPkg генерирует единый заголовочный файл knitpkg/flat/KnitPkgSMA_flat.mqh на основе точки входа и подобранных для нее зависимостей, а затем успешно компилирует индикатор. Это подтверждает, что пакет @douglasrechia/calc был корректно использован для расчета SMA. Пакет calc, использованный здесь индикатором, можно повторно использовать и в любом другом проекте — советнике, другом индикаторе или библиотеке — без копирования единого исходного файла.

5. Советник expertdemo. Теперь перейдем к последнему компоненту — демонстрационному советнику, реализующему систему на основе пересечения скользящих средних. Загрузите советник expertdemo версии 2.0.1:

kp get mql5 @douglasrechia/expertdemo -v 2.0.1

Для начала разберем наиболее важные части его манифеста. Советник expertdemo зависит от @douglasrechia/bar (который вам уже знаком) и @douglasrechia/barhelper. Чтобы статья не получилась слишком объемной, мы не будем углубляться в детали работы barhelper. Читателю достаточно знать, что barhelper предоставляет функцию NewTimeSeriesFromIndicator. Эта функция возвращает конкретную реализацию ITimeSeries со значениями, рассчитанными любым индикатором и сохраненными в его выходном буфере (в зависимости от потребностей это может быть весь буфер или только его часть).

Это необходимо, поскольку expertdemo использует индикатор KnitPkgSMA, а не функцию SMA из пакета calc. Внимательный читатель заметит, что в манифесте expertdemo пакет calc не указан. Это иллюстрирует разные способы использования функциональности пакета: поскольку индикатор KnitPkgSMA создан на основе calc, советник expertdemo зависит не напрямую от calc, а от индикатора, созданного с его помощью. Интересно, правда?

Советник expertdemo также использует режим Flat, поэтому внешние заголовочные файлы, необходимые проекту, должны быть указаны в файле точки входа src/KnitPkgExpertDemo.mqh.

Наконец перейдем к основному исходному файлу src/KnitPkgExpertDemo.mq5. Ниже приведен его фрагмент:

//................................

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   barWatcher = new douglasrechia::BarWatcher();
   myBar = new douglasrechia::BarMqlRates();
//--- Validate that sma1.period < sma2.period < sma3.period
   if(!(sma1period < sma2period && sma2period < sma3period))
     {
      Print("Invalid moving average periods");
      return(INIT_FAILED);
     }
//--- Handlers for SMA indicators calculated at three different periods
   sma1handle = iCustom(_Symbol, _Period, "sma/bin/KnitPkgSMA", sma1period);
   sma2handle = iCustom(_Symbol, _Period, "sma/bin/KnitPkgSMA", sma2period);
   sma3handle = iCustom(_Symbol, _Period, "sma/bin/KnitPkgSMA", sma3period);
   if(sma1handle == INVALID_HANDLE || sma2handle == INVALID_HANDLE || sma3handle == INVALID_HANDLE)
     {
      Print("Could not initialize KnitPkgSMA indicator");
      return(INIT_FAILED);
     }
//---
   return(INIT_SUCCEEDED);
  }

//...............................

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   barWatcher.Update();
   if(barWatcher.IsFirstTick())
     {
      Print("Hello world! This is KnitPkg's debut EA. I'm mostly here for show, but hey, looking good is half the battle! ;-)");
     }
   else
      if(barWatcher.IsNewBar())
        {
         OnNewBar();
        }
  }

//+------------------------------------------------------------------+
//| OnNewBar — called when a new bar is formed                       |
//+------------------------------------------------------------------+
void OnNewBar()
  {
//--- Get latest 5 bars data
   myBar.Refresh(5);

//--- Get the 5 most recent values of SMA into the TimeSeries.
//--- Do it for the three SMAs.
   douglasrechia::TimeSeriesArray<double>* sma1 =
      douglasrechia::NewTimeSeriesFromIndicator(sma1handle, 0, 0, 5);

   douglasrechia::TimeSeriesArray<double>* sma2 =
      douglasrechia::NewTimeSeriesFromIndicator(sma2handle, 0, 0, 5);

   douglasrechia::TimeSeriesArray<double>* sma3 =
      douglasrechia::NewTimeSeriesFromIndicator(sma3handle, 0, 0, 5);

   if(sma1 != NULL && sma2 != NULL && sma3 != NULL)
     {
      if(!positionInfo.Select(_Symbol))
        {
         //--- No position. Check filter conditions.
         if(!filterEnabled || (myBar.Close(1) > sma1.ValueAtShift(1) &&
                               sma1.ValueAtShift(1) > sma2.ValueAtShift(1) &&
                               sma2.ValueAtShift(1) > sma3.ValueAtShift(1)))
           {
            //--- Open position if Short term sma1 crosses up Mid term sma2
            if(douglasrechia::CrossUp(sma1, sma2, 1))
              {
               Print(StringFormat("[%s] Let's do it", TimeToString(myBar.Time(0))));
               trade.Buy(1);
              }
           }
        }
      else
        {
         //--- Position is found. Close it if Short term sma1 crosses down Mid term sma2.
         if(douglasrechia::CrossUp(sma2, sma1, 1))
           {
            Print(StringFormat("[%s] Time to go", TimeToString(myBar.Time(0))));
            trade.PositionClose(_Symbol);
           }
        }
     }
   else
     {
      Print("ERROR: could not get TimeSeries from indicators buffers.");
     }

   if(sma1 != NULL)
      delete sma1;
   if(sma2 != NULL)
      delete sma2;
   if(sma3 != NULL)
      delete sma3;
  }

Код советника чистый и понятный благодаря использованию функций с высоким уровнем абстракции. В обработчике событий OnInit() создаются глобальные объекты barWatcher и myBar. Хэндлы трех SMA инициализируются с использованием точных путей, подготовленных командой kp get для индикатора KnitPkgSMA.

Примечание. Для работы expertdemo двоичный файл KnitPkgSMA.ex5 должен находиться по пути, указанному в вызове функции iCustom в OnInit(). Поэтому перед запуском expertdemo пользователю необходимо один раз выполнить команду kp get mql5 @douglasrechia/sma.

В обработчике событий OnTick() для обнаружения нового бара используется объект BarWatcher из пакета @douglasrechia/bar; при появлении нового бара вызывается OnNewBar().

Основная логика советника реализована в OnNewBar(). С помощью функции NewTimeSeriesFromIndicator из пакета @douglasrechia/barhelper советник легко получает последние пять значений каждого индикатора SMA (на практике достаточно было бы и трех). Затем с помощью функции CrossUp (также реализованной в barhelper) советник открывает или закрывает позицию в зависимости от того, пересекает ли краткосрочная SMA среднесрочную SMA.

Для проверки позиций и совершения сделок используются классы CTrade и CPositionInfo из Стандартной библиотеки языка MQL. Важно отметить, что KnitPkg полностью совместим со Стандартной библиотекой языка MQL и не накладывает ограничений на ее использование (напротив, Стандартная библиотека — это зрелая высококачественная библиотека, которую мы рекомендуем использовать).

Этап 4 — связка "пакет → индикатор → советник" работает без копирования кода. Советник expertdemo теперь использует логику SMA через индикатор KnitPkgSMA, который, в свою очередь, построен на основе пакетов bar и calc. Исходные файлы не копировались между проектами, а пути в директивах #include не редактировались вручную: все связи описаны в манифестах knitpkg.yaml, а KnitPkg автоматически настраивает их, обеспечивая воспроизводимость установки.


Заключение

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

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

  • четкое представление об устройстве KnitPkg: реестр хранит метаданные, Git-репозитории остаются эталонным источником исходного кода, а семантическое версионирование (^, ~, *) обеспечивает контролируемые обновления;
  • понимание роли манифеста (knitpkg.yaml): в нем сосредоточены идентификационные данные проекта, цели сборки и зависимости, благодаря чему сборки становятся воспроизводимыми;
  • практическую схему установки: понимание различий между режимом include (классическое дерево заголовочных файлов) и режимом flat (единый сгенерированный заголовочный файл, удобный для распространения через Маркет MQL5);
  • понимание того, как работают составные пакеты: при разработке используется autocomplete.mqh, а при установке KnitPkg преобразует директивы @knitpkg:include в фактические директивы #include;
  • понимание важности модульных тестов в разработке на языке MQL: тесты компилируются вместе с проектом и помогают убедиться, что новые версии пакетов не нарушают работу зависящих от них советников или индикаторов.

Практический пример объединяет эти идеи: одна реализация SMA оформляется как пакет, повторно используется индикатором, а затем через него — советником, который для повышения эффективности отслеживает появление нового бара. Это дает практическую схему построения пригодных для повторного использования связок "пакет → индикатор/библиотека → советник" и сокращения копирования кода при разработке на языке MQL.

Приложения

Исходный код всех проектов, показанных в этой статье, доступен в Git-репозиториях, ссылки на которые приведены по всему тексту. В приведенных ниже приложениях находятся файлы, автоматически сгенерированные KnitPkg при выполнении команды kp get, которая неявно запускает процессы команд kp autocomplete, kp checkinstall и kp install. Эти файлы не хранятся в Git, но читатели могут воспроизвести их локально, выполнив те же команды kp get, которые описаны в статье.

Имя файла Описание
autocomplete.mqh Вспомогательный файл для автодополнения, сгенерированный для пакета calc при выполнении kp get (knitpkg/autocomplete/autocomplete.mqh).
Calc.mqh Заголовочный файл пакета calc с подготовленными подключениями зависимостей, сгенерированный и проверенный при выполнении kp get / kp checkinstall (knitpkg/autocomplete/knitpkg/include/douglasrechia/calc/Calc.mqh).
KnitPkgSMA_flat.mqh Единый заголовочный файл индикатора SMA, сгенерированный в проекте sma при выполнении kp get / kp install (knitpkg/flat/KnitPkgSMA_flat.mqh).


Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21429

Прикрепленные файлы |
autocomplete.mqh (0.7 KB)
Calc.mqh (3.41 KB)
KnitPkgSMA_flat.mqh (11.68 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
Stanislav Korotky
Stanislav Korotky | 6 мар. 2026 в 15:31

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

Если кто-то клонирует репозиторий 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 без копирования?

Douglas Nascimento Rechia
Douglas Nascimento Rechia | 6 мар. 2026 в 16:33
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 — будь то по рабочему процессу или по примеру кода, — поэтому не стесняйтесь оспаривать или развивать любые из этих идей.

Пошаговая реализация локальной системы стоп-лоссов на MQL5 Пошаговая реализация локальной системы стоп-лоссов на MQL5
В этой статье показано, как создать локальную систему стоп-лоссов в советнике MQL5, которая поддерживает уровни стоп-лосса на стороне терминала. В ней подробно рассматривается логика выполнения, обработчики событий, входные данные и объектно-ориентированный подход с использованием объектов CTrade, CPositionInfo, CHashMap/CHashSet, а также графических объектов. Вам предстоит реализовать одновременное отслеживание нескольких позиций, перемещаемые стоп-уровни, визуальные разделители и метки, а также функции очистки и разрыва соединения для создания практичного инструмента управления рисками.
От новичка до эксперта: Расширение стратегии на основе ликвидности с помощью трендовых фильтров От новичка до эксперта: Расширение стратегии на основе ликвидности с помощью трендовых фильтров
В статье стратегия на основе ликвидности дополняется простым трендовым фильтром: торговать от зон ликвидности только в направлении тренда, определяемого EMA(50). В ней объясняются правила фильтрации, представлен пригодный для повторного использования класс TrendFilter.mqh и показана его интеграция в советник на языке MQL5, а также сравниваются результаты тестирования исходной стратегии и стратегии с фильтром. Читатели получают четкий ориентир по направлению торговли, возможность сократить избыточную торговлю в контртрендовых фазах и готовые к использованию файлы исходного кода.
Память между перезапусками: Сохранение состояния советника с помощью двоичных файлов в MQL5 Память между перезапусками: Сохранение состояния советника с помощью двоичных файлов в MQL5
В статье представлена структурированная программная основа MQL5 для сериализации внутреннего состояния советника в локальные двоичные файлы. Она предотвращает сброс данных при перезапусках платформы, надёжно сохраняя непосредственно на диск хранящиеся в оперативной памяти показатели, такие как количество сделок и множители. Данная архитектура представляет собой более надёжную альтернативу глобальным переменным терминала для обеспечения непрерывности состояния.
Количественный анализ совместной рекуррентности (JRQA) в MQL5: Выявление одновременной рекуррентности в двух временных рядах Количественный анализ совместной рекуррентности (JRQA) в MQL5: Выявление одновременной рекуррентности в двух временных рядах
Мы расширяем библиотеку RQA для MetaTrader 5, добавляя JRQA, который определяет моменты, когда два временных ряда одновременно возвращаются к своим прежним состояниям. В статье рассматриваются матрица совместной рекуррентности, двенадцать метрик JRQA (включая TREND и COMPLEXITY), конфигурация с двумя эпсилонами, а также механизм скользящего окна с ускорением через OpenCL и автоматическим переходом на CPU. Практический индикатор строит графики JRR, JDET, JLAM, JENTR и JTREND для любой пары финансовых инструментов с выравниванием временных меток и нормализацией.