Возможности Мастера MQL5, которые вам нужно знать (Часть 89): Использование побитовой векторизации с перцептронными классификаторами
Введение
Логика входа, используемая в алгоритмах, часто становится ограничением в системах торговли в реальном времени. С каждым новым тиком или баром советник может выполнять десятки обращений к значениям с плавающей точкой и итераций цикла, до 64 обращений к историческим данным, чтобы сформировать контекст по OHLC-данным, заполнить буферы индикаторов и подготовить входы для машинного обучения. На спокойном рынке такие издержки могут быть приемлемыми. Однако при всплесках объема и активности тиков они превращаются в измеримую задержку: ордера отправляются позже, исполняются хуже, а проскальзывание увеличивается. Инженерная задача проста: перестроить путь входа так, чтобы контекст из 64 баров считывался и оценивался почти мгновенно, без затратных массивов double и матричных вычислений перед принятием решения.
Для этого используется CSignalBitwisePerceptron – компактный класс сигнала MQL5, векторизующий 64 периода в одно 64-битное машинное слово. Фильтр на основе битовой карты со сложностью O(1) обеспечивает сверхбыстрое сопоставление паттернов, а легковесный перцептронный фильтр выполняет скалярное произведение по битам на аппаратном уровне. Такое сочетание сводит к минимуму вычисления с плавающей точкой, предоставляет один настраиваемый параметр уверенности m_threshold для баланса между частотой и точностью, а по результатам форвардных тестов способно снижать просадку при почти нулевой задержке исполнения.
Постановка задачи
Для некоторых стратегий алгоритмическая логика входа в стремлении к торговле с нулевой задержкой может стать скрытой причиной снижения эффективности. Типичные советники используют буферы индикаторов и исторические массивы цен, например скользящих средних или осцилляторов, для определения входа в рынок. На низком уровне это требует сбора, буферизации и перебора больших массивов чисел с плавающей точкой двойной точности. Если алгоритму требуется проанализировать последние 64 минуты данных M1 для выявления торгового сигнала, обычная логика может заставить процессор перебирать 64 отдельных индексных позиции при каждом новом ценовом баре или тике.
В периоды рыночной волатильности, когда реальный и тиковый объемы очень высоки, повторный перебор массива может существенно увеличить вычислительную нагрузку. Советник вынужден тратить дополнительные вычислительные циклы, лишь считывая историческое состояние рынка. Это задерживает фактическое исполнение сделок и часто приводит к неблагоприятному проскальзыванию.
Задержка может увеличиваться при интеграции моделей машинного обучения в логику входа. Многие советники передают в нейронные сети несжатые входные данные с плавающей точкой, например FP32 на GPU, или сырые числовые данные на CPU. В большинстве случаев достаточно FP16 для GPU и INT8 для CPU. Обработка 64 отдельных значений float входным слоем ИИ на каждом тике вынуждает советник одновременно работать с большим объемом памяти и выполнять матричные умножения.
Это ограничение редко связано с самой торговой стратегией; скорее, оно вызвано неэффективной структурой данных. Из-за объема вычислений с плавающей точкой система может перегружаться еще до принятия решения о покупке или продаже. Для устранения вычислительных задержек необходимо принципиально изменить способ интерпретации исторических данных.
Нельзя и далее полагаться на высокоуровневые циклы и массивы с плавающей точкой. Решение состоит в отказе от этих структур и преобразовании исходных рыночных данных в машиночитаемый двоичный формат на аппаратном уровне. Переход от больших массивов double к побитовой векторизации дает нейронной сети сверхлегкий формат данных с мгновенным доступом, сокращая вычислительную нагрузку почти до нуля.
Код
Чтобы понять, как достигается почти нулевая задержка, рассмотрим внутренние механизмы пользовательского класса сигнала. В отличие от типичных классов, создаваемых Мастером MQL5 на основе CExpertSignal и зависящих от буферов MA, MACD или RSI, этот подход использует только исходные ценовые ряды. В конструкторе класса настраивается прямое подключение путем переопределения инициализации стандартного ценового ряда:
m_used_series = USE_SERIES_HIGH + USE_SERIES_LOW + USE_SERIES_OPEN + USE_SERIES_CLOSE;
Благодаря этому советник обходит промежуточные расчеты индикаторов и получает исходные рыночные данные непосредственно из памяти. Однако основное сокращение задержки достигается за счет способа обработки этих данных.
Метод GetVectorizedState
Основным ограничением в стандартной алгоритмической торговле является перебор массивов. Когда советнику нужно прочитать последние 64 периода рыночных данных, обычный подход предполагает перебор массива из 64 чисел с плавающей точкой двойной точности на каждом входящем тике. Данный метод устраняет эту неэффективность следующим образом:
//+------------------------------------------------------------------+ //| Bitwise Vectorization: Pack 64 periods into a uint64 | //+------------------------------------------------------------------+ ulong CSignalBitwisePerceptron::GetVectorizedState(int start_index) { ulong state = 0; //--- Loop through the last 64 bars. //--- If Close > Open (Bullish), set the bit to 1. Else, leave as 0. for(int i = 0; i < 64; i++) { if(Close(start_index + i) > Open(start_index + i)) { //--- Shift 1 by 'i' positions and perform bitwise OR state |= ((ulong)1 << i); } } return(state); }
Вместо хранения исходных значений OHLC типа float цикл проверяет базовое двоичное условие для каждого бара. Закрылся ли бар выше цены открытия? Эта проверка сводит сложную свечу к двоичному состоянию: 1 для бычьего бара и 0 для медвежьего. На больших таймфреймах такое упрощение может быть оправданным, поскольку нейтральные бары встречаются реже. Однако нейтральные и медвежьи бары здесь фактически не различаются, что может быть проблемой на малых таймфреймах.
Задержка уменьшается применением на следующей строке побитового оператора OR с присваиванием:
state |= ((ulong)1 << i);
Если свеча бычья, алгоритм берет двоичную 1 и сдвигает ее влево на i позиций. Единица записывается в соответствующую битовую позицию переменной state. Поскольку state объявлена как беззнаковое 64-битное целое число, она содержит ровно 64 доступных бита. За один быстрый проход 64 минуты рыночной истории сжимаются в одно машинное слово.
Метод PerceptronInference
После преобразования состояния рынка в векторный формат его оценивает нейронная сеть. Обработка моделей машинного обучения внутри советника часто требует затратных библиотек матричного умножения, способных занять потоки процессора. Этот метод позволяет избежать этого, выполняя скалярное произведение на аппаратном уровне:
//+------------------------------------------------------------------+ //| Perceptron Inference: Hardware-level dot product calculation | //+------------------------------------------------------------------+ double CSignalBitwisePerceptron::PerceptronInference(ulong state) { double sum = m_bias; //--- Iterate through the 64-bit integer for(int i = 0; i < 64; i++) { //--- Use bitwise AND to check if the i-th bit is set to 1 if((state & ((ulong)1 << i)) != 0) { //--- If bit is 1, add the corresponding weight to the sum sum += m_weights[i]; } } return(sum); }
Перцептрон принимает упакованное 64-битное целое значение state и инициализирует sum значением смещения (bias) сети. Чтобы определить, нужно ли добавить к сумме конкретный синаптический вес, метод использует побитовую маску AND:
(state & ((ulong)1 << i)) != 0;
Эта операция немедленно проверяет i-й бит упакованного векторизованного состояния. Если бит активен, то есть соответствует бычьему бару, тогда условие истинно, а соответствующий предварительно обученный вес добавляется к общей сумме активации:
sum += m_weights[i];
Сложные математические библиотеки не требуются. Это непосредственное выполнение инструкций процессора. Сохраняя данные в двоичном формате до момента инференса, перцептрон может оценивать составные комбинации паттернов в последовательности из 64 баров при почти нулевой вычислительной нагрузке.
Алгоритм и нейронная сеть
После сжатия исторических данных в 64-битное целое число советник принимает решение о торговле. Традиционно классы сигналов MQL5 принимают это решение линейно, в рамках однослойного процесса. Например, проверяется, находится ли RSI выше или ниже статического уровня. Однако для достижения высокочастотного исполнения в стратегиях, чувствительных к задержкам, здесь также используется двухуровневая архитектура проверки, как и в предыдущей статье. Таким образом, используется алгоритмический фильтр первого уровня и фильтр на основе нейронной сети, выполняющий окончательный отбор сигналов.
Последовательность выполнения
Процесс выполнения начинается в момент, когда движок MQL5 запрашивает оценку рынка. Первым действием в условиях Long и Short является вызов рассмотренного выше метода структурирования данных.
ulong current_state = GetVectorizedState(idx); В этот момент советник обрабатывает весь рыночный контекст из 64 баров, сохраненный в переменной current_state. Это состояние проходит через два отдельных фильтра.
Слой 1
Первый из них – слой защиты от неудачных сделок. Он полностью алгоритмический и использует m_map как таблицу поиска двоичных сигнатур исторических бычьих и медвежьих ценовых паттернов. Вместо дерева if/else для проверки соответствия текущего состояния рынка бычьему или медвежьему состоянию используется побитовая операция:
if(!(m_map & (1 << current_state)))
Математическая логика этого решения обеспечивает вычислительное преимущество. Алгоритм берет двоичную 1 и сдвигает ее влево на целочисленное значение current_state. Поскольку current_state – большое 64-битное число, операция сдвига битов фактически действует как сверхбыстрая хеш-функция, отображающая текущую структуру рынка в определенную уникальную битовую позицию. Затем система использует побитовый оператор AND (&) для сравнения этой уникальной позиции с оптимизированной хеш-таблицей m_map. Если оператор NOT делает условие истинным, текущая последовательность из 64 баров соответствует бычьему (либо медвежьему) паттерну из m_map. Функция, проверяющая условия для коротких позиций, работает по обратной логике по сравнению с бычьей. Это совпадение подтверждается присвоением веса 100%:
result = m_pattern_0;
Проверка сложной структуры из 64 баров по оптимизированной карте входных паттернов выполняется со сложностью O(1). Это практически не нагружает процессор и действует как высокоскоростной алгоритмический фильтр.
Слой 2
Алгоритмический фильтр по умолчанию работает быстро, однако может быть слишком жестким. Он ищет только точные совпадения. Однако финансовые рынки скорее динамичны, чем статичны. Настройки m_map, работающие сегодня, могут потребовать небольших корректировок для будущих рыночных условий. Жесткий алгоритмический фильтр неизбежно отбросит такие вариации, упуская потенциально удачные торговые сигналы. Здесь второй слой нейронной сети добавляет потенциально полезную гибкость. После проверки карты выполняется нейронный инференс:
double activation = PerceptronInference(current_state); Этот перцептрон выполняет оценку по точному 64-битному слову. Вместо поиска строгого совпадения хэша вычисляется скалярное произведение активных битов и предварительно обученных синаптических весов. Нейронный фильтр также использует ключевое условие:
if(activation > m_threshold && m_threshold > 0.0)
В этой строке входной параметр m_threshold служит динамическим регулятором уверенности. Когда сумма активации превышает этот порог, нейронная сеть подтверждает сделку, считая текущее состояние рынка торговым сигналом с высокой вероятностью. В результате присваивается значение 100%, как и при работе только алгоритма. Если результат уже равен 100, перед повторным присваиванием он делится пополам:
result /= 2; if(IS_PATTERN_USAGE(0)) result = m_pattern_0;
Составные комбинации и отдельные паттерны
При использовании нейронной сети в автоматизированных системах важно понимать, что именно она оценивает. Традиционная логика входа советника обычно сосредоточена на изолированных локальных свечных паттернах, например паттерне поглощения, доджи и т.д. Такой подход можно считать слишком узким взглядом на рынок.
Передавая в сеть весь вектор current_state, мы оцениваем не отдельную свечу, а составную комбинацию паттернов в окне из 64 ценовых баров. Перцептрон может распознать, что хотя последние три минуты ценового движения похожи на стандартный бычий пробой, контекст предыдущих 61 бара указывает на ловушку ликвидности.
Массив m_weights позволяет назначать разную степень важности историческим периодам внутри анализируемого контекста – в данном случае окна из 64 баров. Регулируя m_threshold, разработчик напрямую определяет, насколько строго сеть оценивает составные данные.
Более высокий порог требует более сильного математического совпадения с благоприятным историческим контекстом перед разрешением входа. По сути, это отфильтровывает торговые сигналы уровня B и сохраняет капитал только для тех сценариев, в которых полный контекст из 64 баров соответствует оптимальному состоянию обученной модели.
Таким образом, сочетание этих двух фильтров в пользовательском классе сигнала CSignalBitwisePerceptron теоретически должно объединить преимущества обоих подходов. В итоге m_map алгоритма обеспечивает почти мгновенное сопоставление паттернов, а m_threshold перцептрона служит контекстным фильтром, отсеивающим ложноположительные сигналы, возникающие при высокоскоростной обработке.
Анализ результатов тестирования
Далее подход тестируется с помощью форвардного тестирования. Для проверки архитектуры сначала определяются прибыльные пороги входа и выхода. Затем они оцениваются с помощью форвардного тестирования на вневыборочных данных. Тестирование EURUSD проводится на таймфрейме H4 с 01.01.2025 по 01.05.2026. Период оптимизации – 2025 год, а период форвардного тестирования – с 01.01.2026 по 01.05.2026.
Были протестированы: 1) только алгоритмический фильтр; 2) алгоритмический фильтр вместе с нейронным. Тестовая среда в обоих запусках была одинаковой, чтобы изолировать возможное влияние слоя нейронной сети. Первый отчет приведен ниже:
В первом запуске, представляющем собой форвардный тест советника только с фильтром первого уровня – алгоритмом, – нейронная сеть была отключена. При значении порога активации перцептрона 0.0 система полностью использовала алгоритмическую проверку хеша первого слоя m_map. Если 64-битная последовательность совпадала с картой, сделка открывалась немедленно без участия нейронной сети.
Результаты демонстрируют высокую, ничем не ограниченную агрессивность чисто алгоритмического сопоставления паттернов. Советник совершил 11 сделок, получив чистую прибыль 528,03 доллара США при начальном балансе 10 000 долларов США и профит-факторе 1,19. Однако более подробный анализ распределения сделок выявляет жесткость алгоритмического фильтра. Все 11 сделок были длинными, при этом не было выявлено ни одной возможности для короткой позиции. Для рынка Forex за 4-месячный период это нежелательно.
Кроме того, хотя валовая прибыль была достаточно значительной, она достигнута ценой существенного риска. Просадка средств счета по результатам теста составила 18,66%, или 2 379,77 доллара США. Эта просадка почти в шесть раз превысила чистую прибыль. Таким образом, хотя алгоритм быстро находит точный паттерн, ему не хватает контекстной оценки для отсева торговых сигналов, формально соответствующих последовательности, но возникающих при ухудшении рыночных условий. Второй отчет приведен ниже:
Во втором форвардном тесте после оптимизации использовалась полная архитектура. При увеличении m_threshold до положительного значения, перцептрон должен оценить составную комбинацию последовательности из 64 ценовых баров и достичь заданного взвешенного значения, прежде чем разрешить сделку.
Статистические изменения становятся заметны сразу. Общее число сделок снизилось с 11 до 10. В результате чистая прибыль составила 299,30 доллара США, а профит-фактор немного снизился до 1,13. На первый взгляд это может показаться ухудшением, однако определяющим показателем может быть доходность с учетом риска, а не чистая прибыль.
Анализ журнала исполнения показывает влияние перцептрона. Нейронный фильтр отсеял две длинные сделки, которые исходный алгоритм открыл без дополнительной проверки. Это сократило потенциальные убытки. Кроме того, сеть выявила и открыла высокоприбыльную короткую сделку, в отличие от алгоритма, открывавшего только длинные сделки. Главное, что, отфильтровав составные паттерны с низкой вероятностью, перцептрон снизил просадку средств счета с 18,66% до 16,75%. Однако сумма этой просадки в долларах США по-прежнему значительна.
Компромисс в машинном обучении
Сравнение интересно тем, что ни одна версия системы не превосходит другую во всех случаях: они оптимизированы для разных целей. Базовый движок битовых паттернов более агрессивен. Он реагирует на каждое корректное совпадение в m_map, повышая частоту сделок и немного увеличивая общую прибыль, но одновременно подвергая счет более крупным просадкам.
Добавление перцептрона меняет роль системы. Нейронный слой не генерирует новые сигналы, а фильтрует существующие, оценивая сходство текущей структуры рынка с историческими условиями, в которых паттерн ранее работал хорошо. Это сокращает число сделок и исключает многие слабые торговые сигналы, формально соответствующие двоичной последовательности, но возникающие в нестабильных рыночных условиях.
Форвардные тесты ясно отражают эти изменения. Чистый алгоритм торговал чаще и обеспечил немного более высокую валовую прибыль, тогда как гибридная версия сформировала более плавную кривую капитала и снизила просадку с 18,66% до 16,75%.
На практике это основной компромисс: максимизация рыночной экспозиции или повышение избирательности. Перцептрон не заменяет основной алгоритм – он определяет, когда алгоритму следует воздержаться от входа в рынок.
Заключение
Перестроение логики входа с нуля на основе побитовой векторизации и двухэтапного принятия решений может дать шаблон, который можно использовать в реализации CExpertSignal. На практике для этого требуется реализовать GetVectorizedState (64 бара в одном ulong) и второй фильтр – activation > m_threshold. m_threshold используется для настройки баланса между точностью и полнотой; в журнале фиксируются задержка принятия решения и экономические показатели.
Мы свели контрольные точки к следующим пунктам:
- функциональное соответствие – 64-битное кодирование должно соответствовать заданным правилам баров, с учетом нейтральных баров на малых таймфреймах;
- производительность – измеряется время CPU на тик до и после векторизации;
- экономические показатели – алгоритм и нейронная сеть сравниваются в форвардном тестировании на вневыборочных данных по метрикам отчета Тестера стратегий.
Результаты могут означать, что концептуальное преимущество – почти нулевая задержка – способно привести к проверяемым инженерным улучшениям, которые можно настраивать и воспроизводить.
| имя | описание |
|---|---|
| wz_89.mq5 | Советник, собранный Мастером MQL5 |
| SignalBitwisePerceptron.mqh | Пользовательский класс сигнала, используемый при сборке советника Мастером MQL5 |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/22499
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Изучение стандартной библиотеки MQL5 (Часть 8): Ведение журнала сделок гибридной системы с помощью CFileTxt
Нейросети в трейдинге: Долговременная память торговых сценариев (Окончание)
Неопределённость как модель (Часть 8): Обобщение МНК
Возможности Мастера MQL5, которые вам нужно знать (Часть 88): Использование фильтра Блума с пользовательским классом трейлинга
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования

