preview
Нейросети в трейдинге: Двусторонняя адаптивная временная корреляция (BAT)

Нейросети в трейдинге: Двусторонняя адаптивная временная корреляция (BAT)

MetaTrader 5Торговые системы |
640 1
Dmitriy Gizlyk
Dmitriy Gizlyk

Введение

Торговля всегда была искусством улавливать движение. Кто-то сверяется с календарём, кто-то ищет закономерности в графиках, а кто-то полагается на интуицию, отточенную годами работы на бирже. Но любой опытный трейдер знает, что рынок живёт не кадрами, а непрерывным потоком микродвижений. Они возникают задолго до того, как проявятся в привычных свечах. Именно эти крошечные вспышки активности и формируют внутренний ритм рынка, похожий на поток событий. Там нет кадров, есть только последовательность изменений. И в этом сходстве мы находим блестящую возможность: перенести в трейдинг идеи фреймворка BAT — двусторонней адаптивной временной корреляции, созданной для анализа событийных данных, но идеально подходящей к структуре рыночных процессов.

Если рассматривать котировки как события (короткие, резкие, локальные изменения), то рынок предстает перед нами в виде последовательности импульсов. Эти импульсы образуют почти такой же разреженный, но богатый по смыслу поток, аналогичный событиям в сенсоре камеры. И здесь появляется первый сильный аргумент в пользу BAT — он умеет строить плотную картину движения из почти бессистемных, рваных сигналов. То, что трейдер видит как хаос, алгоритм превращает в непрерывное поле направлений. Он не пытается подменить рынок искусственной гладкостью, он принимает его таким, каков он есть, и извлекает из него структуру, которую человек часто недооценивает. Рынок становится похож на объект, освещённый короткими вспышками, — глаз видит лишь мгновения, а модель восстанавливает траекторию.

Однако главная сила BAT заключается не только в умении заполнять пробелы. Его двусторонняя природа, в которой движение оценивается одновременно вперёд и назад во времени, удивительно созвучна тому, как опытный трейдер изучает контекст. Задолго до принятия решения он смотрит на историю, оценивает характер прошедших импульсов, отмечает, какие уровни были значимы, где участники проявляли активность. Затем он смотрит вперёд — не на то, что уже произошло, а на то, что может произойти при текущем расположении сил. BAT действует точно так же: он строит корреляции с будущими и прошлыми сегментами потока событий. Это позволяет ему фиксировать не только факт изменения, но и его направление, устойчивость и согласованность с поведением в более широком временном горизонте.

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

Не менее важен и адаптивный характер временной выборки. Рынок не движется равномерно и не обязан подстраиваться под размеры наших свечей или таймфреймов. Бывают часы, когда объёмы едва шевелятся, и бывают минуты, когда один новостной импульс разрушает устойчивость любой статистики. В такие моменты классические модели излишне жёстко зафиксированы во времени и либо упускают важные изменения, либо создают избыточный шум. BAT решает эту проблему через адаптивный темпоральный шаг. Он автоматически подстраивает ширину временного окна под текущую динамику. Если рынок спокоен — окно расширяется, и модель собирает больше контекста. Если рынок ускоряется — окно сжимается, не позволяя крупным движениям смазываться и терять резкость. В итоге модель сохраняет чёткость и устойчивость вне зависимости от рыночного режима.

Ещё одно важное качество BAT — умение правильно агрегировать противоречивые сигналы. Рынок редко даёт однозначные подсказки. На одном уровне может возникнуть набор слабых импульсов, часть которых указывает вверх, часть — вниз. Новички пытаются сгладить такие ситуации, что делает прогноз аморфным. Опытный специалист, напротив, выделяет качественные импульсы. Отсеивает слабые и опирается только на те сигналы, которые подтверждаются несколькими временными слоями. Именно такую стратегию использует SATMA — пространственно-адаптивная временная агрегация. Она не складывает движения механически. Она анализирует согласованность направлений, плотность событий, локальные особенности и уверенность сигнала. Шумные или противоречивые признаки понижаются в весе, а те, что соответствуют общему движению, усиливаются. В итоге формируется чистая, детализированная картина — почти как если бы опытный трейдер вручную отобрал самые важные участки графика.

При этом BAT удивительно устойчив к отсутствию данных. В трейдинге периодически встречаются участки, когда ничего не происходит. Активность падает, ликвидность тонкая, движение затухает. Большинство моделей в такие моменты либо замирают, либо теряют устойчивость. BAT же может восстанавливать траекторию даже в разреженных данных, поскольку использует не бинарные события, а временные и пространственные зависимости между ними. Каждое изменение вписывается в большую картину. Даже одиночный всплеск активности может быть правильно классифицирован, если он согласован с общей динамикой. Это даёт модели качество, похожее на профессиональную интуицию — видеть значимое даже в малых деталях.

Ещё одно преимущество BAT, важное для трейдинга, заключается в умении прогнозировать будущие движения на основе только прошлых событий, без опоры на будущие кадры или заранее известный контекст. Именно это отличает сильные модели от слабых: способность работать в реальном времени, без задержек и без спойлеров. BAT профессионально справляется с этой задачей благодаря своей двунаправленной корреляции, которая формирует плотную карту направлений, включая наиболее вероятное краткосрочное продолжение движения. Это напоминает ситуацию в скальпинге. Опытный трейдер, увидев несколько последовательных всплесков, может сказать, что произойдёт в ближайшие секунды. Потому что он видит структуру этих импульсов. BAT видит то же самое, но в математическом виде.

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


Алгоритм BAT

Алгоритм фреймворка BAT строится вокруг простой, но ёмкой идеи: рынок живёт сразу в двух направлениях. Он движется вперёд, но тянет за собой собственное прошлое. Словно торговый поток, который меняет направление, но несёт инерцию старых сделок. BAT аккуратно связывает эти два слоя динамики. Он захватывает свежую информацию и одновременно перестраивает отношение модели к прошлым паттернам, подстраивая их под текущий контекст. Такой подход выглядит почти естественным для трейдера, который смотрит на последние свечи, но никогда не забывает, что рынок любит возвращаться к старым уровням.

Фреймворк BAT строится на свойствах пространственной разреженности и высокой временной плотности анализируемых данных. В рыночных терминах это похоже на ситуацию, когда цены почти не меняются на большинстве уровней книги заявок, но при этом микродвижения во времени происходят постоянно. Авторы фреймворка используют этот дисбаланс в свою пользу. BAT преобразует насыщенные во времени сигналы в плотное пространственное представление, позволяя получать более точную и устойчивую структуру движения. Благодаря этому модель не теряет динамику, но получает возможность анализировать её в удобной и компактной форме. Такой подход делает фреймворк естественным инструментом для задач, где важны и скорость реакции, и структурная целостность данных. Например, в прогнозировании резких рыночных сдвигов.

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

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

После такой подготовки данные становятся подходящими для глубокой обработки, и BAT может перейти к главной задаче — выявлению плотных пространственных зависимостей в динамике, где важны и направление, и скорость, и локальная структура сигнала. Для нас это особенно актуально. Мы переносим идеи, выросшие в области событийного зрения, в пространство финансовых рынков. Мы используем тот же принцип — преобразовать асинхронные всплески в устойчивую структуру, которую можно анализировать, прогнозировать и использовать для принятия решений. И именно такая адаптация даёт BAT уникальное преимущество: модель не просто уплотняет данные, но делает их структурированными и пригодными для поиска закономерностей, которые трудно заметить в исходном сыром потоке.

Извлечение признаков в BAT начинается с обработки двух последовательных потоков событий за смежные временные интервалы. Формально это потоки ℰ(tᵢ₋₁, tᵢ) и ℰ(tᵢ, tᵢ₊₁), которые имеют одинаковую длительность Δt. Наша задача — оценить оптический поток 𝒇tt₊₁, то есть восстановить направление и структуру движения между этими двумя отметками времени. Это соответствует задаче восстановления скрытой динамики по плотному, асинхронному информационному потоку, и во многом напоминает анализ рыночных микродвижений, когда движение цены между двумя моментами формируется неравномерно и часто неочевидно.

На первом шаге оба потока событий преобразуются во воксельные сетки 𝑽₀ и 𝑽₁, используя ранее описанную процедуру. Таким образом мы получаем две компактные трёхмерные структуры, в которых временная ось разбита на дискретные интервалы. Это упорядочивает данные и позволяет дальше работать с ними как с плотными представлениями. По сути, мы превращаем хаотичный поток событий в аккуратную матрицу сигналов, аналогично тому, как аналитик переводит разрозненные тики в структурированный баровый формат, и каждое микроизменение получает своё место и вес.

Чтобы использовать высокую временную плотность событий, BAT дробит каждую воксельную сетку на N равных групп вдоль временной оси. Каждая группа содержит B/N временных ячеек и, по сути, представляет одну долю динамики внутри исходного интервала. Такая сегментация позволяет модели рассматривать поток событий не как единый монолит, а как последовательность фаз движения, каждая из которых несёт собственные намёки на будущий сдвиг. Аналогия проста: трейдер, который оценивает свечу, редко смотрит на неё целиком. Он отслеживает фазу накопления, фазу импульса, фазу отката. Каждый кусок даёт собственный контекст и собственные риски.

Получив 2N групп (N от 𝑽₀ и N от 𝑽₁), мы подаём каждую из них в одну и ту же сеть извлечения признаков — веса полностью совместные. Этот подход подчёркивает нашу концепцию двусторонней адаптивности. Модель рассматривает каждую фазу движения симметрично, сравнивает их между собой и формирует набор состояний, которые можно сопоставлять и коррелировать. Из каждой группы сеть формирует признак 𝑭ₙ размера D×H×W. Эти признаки отражают локальные структуры движения, скрытые ритмы сигнала, мелкие аномалии и переходы между фазами. Сама сеть состоит из шести остаточных блоков подобно архитектуре RAFT, чья эффективность уже широко доказана в задачах плотного восстановления движения.

Среди всего набора временных признаков особую роль играют два: 𝑭ₙ и 𝑭₂ₙ, соответствующие последнему фрагменту второй сетки. Первый используется как опорный кадр, своего рода эталон динамики на момент tᵢ. Второй — как целевой, представляющий состояние на tᵢ₊₁. Эта пара создаёт ось сравнения, благодаря которой BAT может понять, куда сместилась структура движения. Именно здесь рождается возможность выявлять связи между прошлой и последующей фазой. То же самое, что трейдер делает, сравнивая последнюю четверть свечи с началом следующей, чтобы уловить направление нарастающего давления.

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

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

Авторы фреймворка BAT предлагают иной принцип — двустороннюю временную корреляцию (Bidirectional Temporal Correlation — BTC). Он превращает богатые во времени, но пространственно-разреженные сигналы в плотную карту движений, доступную для точной оценки. BTC состоит из двух элементов: прямой временной корреляции и обратной временной корреляции. Первый компонент сопоставляет признаки опорного состояния 𝑭ₙ с признаками будущих временных групп 𝑭ₙ₊ⱼ. Второй — сравнивает это же опорное состояние с предыдущими группами 𝑭ₙ₋ⱼ. Такая конструкция напоминает анализ свечного паттерна как вперёд, так и назад, когда оценивается не только текущий импульс, но и то, как рынок входил в него. Именно этот двусторонний контекст делает оценку стабильной.

Чтобы вычисления были корректными, модель опирается на текущую оценку оптического потока 𝒇 между моментами tᵢ и tᵢ₊₁. Предполагается, что движение между группами можно аппроксимировать линейной интерполяцией во времени. Тогда движение между соседними временными фрагментами описывается величиной:

𝒅𝒇 = 𝒇 / N

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

С целью построения карты прямой временной корреляции для каждого j от 1 до N сравниваются признаки состояния 𝑭ₙ с его будущим аналогом 𝑭ₙ₊ⱼ. При этом кадр 𝑭ₙ₊ⱼ подтягивается к опорному посредством варпинга, который использует j·𝒅𝒇 как предполагаемое смещение. Для каждого пикселя p в опорном кадре находим соответствующую точку p′ в смещённом кадре и строим небольшую локальную область радиуса r вокруг этой точки. Затем билинейно выбираем значения признаков из этой области. Получается компактная карта корреляций размером (2r+1)²×H×W.

Финансовая аналогия здесь проста. Мы как будто берём текущую цену, проецируем её вперёд на несколько микроинтервалов и затем смотрим, совпадает ли наблюдаемое движение с нашим ожиданием. Чем сильнее корреляция — тем яснее структура движения.

Обратная временная корреляция строится по тому же принципу, но идёт в прошлое. Она сравнивает опорное состояние 𝑭ₙ с предыдущими фрагментами 𝑭ₙ₋ⱼ, используя смещение −j·𝒅𝒇. Этот компонент критически важен для корректной обработки окклюзий — ситуаций, когда объект исчезает или выходит из поля зрения. В терминах трейдинга это аналог попытки обнаружить скрытую ликвидность или пропавшие объёмы. Если движение исчезает в будущем, его следы всё ещё могут быть видны в прошлом.

В результате мы получаем N карт прямой корреляции и N−1 карт обратной. Вместе они образуют плотный двусторонний временной корреляционный объём, который превращает разрозненные во времени вспышки движения в устойчивую пространственную структуру. Это позволяет BAT восстанавливать движение с высокой точностью и избегать провалов, характерных для моделей, опирающихся только на одно направление временного анализа.

Особое внимание заслуживает адаптивная стратегия временной выборки. В ранних работах радиус выборки r задавался вручную. Это похоже на фиксированную настройку глубины стакана или жёстко определённый размер окна для анализа волатильности. Решение удобное, но далеко не всегда оптимальное. Движение может ускоряться, замедляться, менять направление. Фиксированный радиус не способен подстроиться под эти изменения.

Авторы фреймворка BAT вводят обучаемый коэффициент масштабирования α, который превращает радиус в обучаемую величину:

lᵣ = α·r

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

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

Эффективная работа с временными сигналами движения имеет ключевое значение для получения плотного и точного оптического потока. Однако движение редко бывает равномерным, и прямолинейное вычисление корреляций между соседними кадрами часто даёт признаки, которые плохо согласуются с целевым кадром. Чтобы избежать этой несогласованности, вводится модуль пространственно-адаптивной временной агрегации движения (Spatially Adaptive Temporal Motion Aggregation — SATMA). Его задача — усиливать те движения, которые действительно соответствуют текущему состоянию сцены, и подавлять всё лишнее.

Перед подачей в SATMA корреляционные признаки 𝐶fwd преобразуются в признаки движения 𝑀fwd с помощью MotionEncoder, который использует как сами корреляции, так и текущий поток 𝒇. Аналогично формируются обратные признаки 𝑀bwd. Среди них 𝑀Nfwd выступает в роли опорного — это движение, непосредственно связанное с целевым кадром. Остальные признаки отражают соседние по времени движения.

Далее включается SATMA. Для каждого соседнего признака движения 𝑀 и опорного признака 𝑀N они объединяются и проходят через свёрточный слой с последующей сигмоидой, формируя пространственную карту внимания 𝐴spa. Эта карта играет роль фильтра, выделяя те области, где движение согласовано с целевым кадром, и подавляя области с шумом или несогласованными траекториями.

С целью дополнительного уточнения движения, SATMA использует деформируемое внимание. Соседний признак движения 𝑀 проектируется в запросы 𝑸, после чего компактная сеть смещений определяет разрежённые точки выборки. На их основе из опорного признака 𝑀N формируются ключи 𝑲 и значения 𝑽. Эти данные участвуют в вычислении агрегированного признака 𝑴agg.

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

Финальное объединение движений выполняется через формулу:

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

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

Авторская визуализация фреймворка BAT представлена ниже.

Авторская визуализация фреймворка BAT Spatially Adaptive Temporal Motion Aggregation (SATMA)


Реализация средствами MQL5

После того как мы подробно разобрали теоретическую основу фреймворка BAT и оценили его преимущества, самое время перейти к практической стороне проекта. Теперь нас интересует не только концепция, но и её реальное воплощение средствами MQL5. Именно здесь идеи начинают обретать форму, а абстрактные схемы превращаются в рабочие механизмы, готовые взаимодействовать с живыми рыночными потоками.

Впереди немалый объём работы. Алгоритм фремйворка BAT многослоен и, подобно вдумчивому трейдеру, который предпочитает не открывать десятки позиций одновременно, мы не будем бросаться сразу во все детали. Логичнее двигаться шаг за шагом, разделяя весь процесс на аккуратные функциональные блоки. Такой подход создаёт устойчивую структуру и снижает риск ошибок, что в конечном итоге повышает качество реализации и облегчает последующую оптимизацию.

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

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

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

Для того чтобы организовать базовую обработку данных и сформировать первичный вектор движения между двумя последовательными состояниями, начнём с простого, но крайне важного шага — создания небольшого вычислительного кернела на стороне OpenCL-программы. Он станет тем рабочим инструментом, который будет фиксировать изменения между текущим и предыдущим состоянием анализируемого массива данных, формируя тем самым аналог элементарного оптического потока.

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

__kernel void CalcFlow(__global const float* value,
                       __global float* prev_value,
                       __global float* flow
                      )
  {
   const size_t id = get_global_id(0);
   const size_t total = get_global_size(0);
//---
   const float v = IsNaNOrInf(value[id], 0);
   const float p = IsNaNOrInf(prev_value[id], 0);
   flow[id] = IsNaNOrInf(v - p, 0);
   prev_value[id] = v;
  }

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

Далее переходим к работе с основной программой и мы выстраиваем инфраструктуру, которая связывает поток вычислений OpenCL-программы с логикой нейронной сети. Именно здесь в работу вступает новый класс — CNeuronCreateFlow. Он становится тем самым интерфейсным звеном, которое управляет состояниями, вызывает вычислительное ядро, организует поток данных, но не ограничивается этим.

Главная идея блока проста, как хорошая рыночная стратегия — не тратить ресурсы на лишние вычисления и использовать информацию только там, где она действительно обновляется. Разница между двумя фиксированными историческими состояниями остаётся постоянной. Это означает, что пересчитывать её на каждой итерации модели бессмысленно.

Поэтому компонент CNeuronCreateFlow концентрируется на другом: он вычисляет только изменения между последним (текущим) состоянием и непосредственно предыдущим. Эта логика полностью отражает и идеологию BAT, и природу потока рыночных данных, который непрерывно сдвигается во времени, но сохраняет лишь один актуальный шаг изменения.

После получения очередного вектора разностей, данные отправляются в стек. Таким образом мы формируем последовательность временных сдвигов — микродинамику рынка, которая впоследствии будет преобразована в более сложные структуры: временные группы, корреляционные карты, агрегированные признаки и другие элементы алгоритма BAT.

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

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

class CNeuronCreateFlow :  public CNeuronSpikePatchStak
  {
protected:
   CNeuronBaseOCL*   cState;
   //---
   virtual bool      CalcFlow(CNeuronBaseOCL *NeuronOCL);
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override;

public:
                     CNeuronCreateFlow(void) {};
                    ~CNeuronCreateFlow(void) {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint stack_size, uint dimension,
                          uint patch_dimension, uint variables,
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   //---
   virtual int       Type(void)   override const   {  return defNeuronCreateFlow;   }
   //--- methods for working with files
   virtual bool      Load(int const file_handle) override;
   //---
   virtual void      SetOpenCL(COpenCLMy *obj)   override;
   //---
   virtual bool      Clear(void) override;
  };

Структура класса является простой и элегантной. Внутри CNeuronCreateFlow мы объявляем всего один ключевой компонент — cState. Он выполняет двойную роль: с одной стороны, хранит текущую разницу между последним и предыдущим состоянием, а с другой — содержит тензор, описывающий последнее состояние системы. Таким образом, cState одновременно является хранилищем актуальных изменений и базой для следующего шага обработки.

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

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

Инициализация нового объекта строится на прочном фундаменте родительского класса и аккуратно расширяет его функциональность, создавая рабочее пространство для хранения и обработки потоковой динамики.

bool CNeuronCreateFlow::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                             uint stack_size, uint dimension,
                             uint patch_dimension, uint variables,
                             ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronSpikePatchStak::Init(numOutputs, myIndex, open_cl, stack_size,
                                   dimension, patch_dimension, variables, optimization_type, batch))
      return false;

Сначала вызывается инициализация родительского класса. Это ключевой шаг. Здесь формируются базовые структуры для стека динамики, резервируются внутренние буферы и задаются параметры обучения. Если инициализация родителя завершилась неудачей, метод немедленно возвращает false, что защищает систему от некорректной работы.

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

   if(!cState.Init(0, 0, OpenCL, dimension * variables, optimization, iBatch))
      return false;

Последний штрих — вызов метода Clear, который очищает все внутренние буферы и гарантирует, что объект стартует с чистого состояния.

   if(!Clear())
      return false;
//---
   return true;
  }

Лишь после успешного выполнения этих шагов метод возвращает true, сигнализируя о готовности объекта к работе.

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

Алгоритм прямого прохода реализован максимально лаконично и линейно. В метод feedForward сначала вызывает CalcFlow, который, как мы уже обсуждали, вычисляет разницу между текущим и предыдущим состоянием, обновляя внутренний компонент cState. Если вычисление потока прошло неудачно, метод немедленно возвращает false, предотвращая распространение некорректных данных дальше по модели.

bool CNeuronCreateFlow::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
   if(!CalcFlow(NeuronOCL))
      return false;
//---
   return CNeuronSpikePatchStak::feedForward(cState.AsObject());
  }

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

Таким образом, метод feedForward объединяет простую, линейную операцию расчёта разницы с мощной функциональностью родителя. Прямой проход остаётся лёгким и эффективным, при этом все вычисленные изменения сразу аккуратно встроены в стек динамики модели, готовый для последующих шагов обработки.

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

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

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

Метод calcInputGradients реализует этот механизм. Сначала проверяется корректность указателя на объект исходных данных.

bool CNeuronCreateFlow::calcInputGradients(CNeuronBaseOCL *NeuronOCL)
  {
   if(!NeuronOCL)
      return false;
//---
   if(!CNeuronSpikePatchStak::calcInputGradients(cState.AsObject()))
      return false;
   if(!DeActivation(NeuronOCL.getOutput(), NeuronOCL.getGradient(),
                    cState.getGradient(), NeuronOCL.Activation()))
      return false;
//---
   return true;
  }

Затем вызывается одноименный метод родительского класса для работы со стеком эмбеддингов cState. После этого применяется DeActivation, которая корректно распределяет градиенты к объекту исходных данных с учетом его функции активации.

Таким образом, мы достигаем двух целей одновременно: сохраняем простоту архитектуры и обеспечиваем полноценную дифференцируемость. Градиенты корректно передаются к объекту исходных данных, позволяя обучать предыдущие слои модели без необходимости создания отдельного кернела обратного прохода.

Сегодня мы проделали значительную работу и заслужили короткий перерыв. Давайте дадим информации немного усвоиться, а в следующей статье, с новыми силами и свежим взглядом, мы продолжим погружение в практическую реализацию алгоритмов фреймворка BAT, шаг за шагом раскрывая его возможности и особенности.


Заключение

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

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


Ссылки


Программы, используемые в статье

# Имя Тип Описание
1 Study.mq5 Советник Советник офлайн обучения моделей
2 StudyOnline.mq5 Советник Советник онлайн обучения моделей
3 Test.mq5 Советник Советник для тестирования модели
4 Trajectory.mqh Библиотека класса Структура описания состояния системы и архитектуры моделей
5 NeuroNet.mqh Библиотека класса Библиотека классов для создания нейронной сети
6 NeuroNet.cl Библиотека Библиотека кода OpenCL-программы
Прикрепленные файлы |
MQL5.zip (3397.36 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (1)
Vladimir Sanin
Vladimir Sanin | 15 дек. 2025 в 06:12
Добрые день всем. Дмитрий, модуль из коробки не соответствует тому, чтобы повторить результаты, описанные в вашей статье. Как минимум признаки не нормализированы и дают высокую ошибку STFS. С логикой размеров лотов, тейков и стопов тоже непонятки. Модель просто учится не торговать, и тестовый модуль в результате и не торгует вообще. Может по ошибке в архиве совсем другая версия BAT?
Знакомство с языком MQL5 (Часть 17): Создание советников для разворотов тренда Знакомство с языком MQL5 (Часть 17): Создание советников для разворотов тренда
Эта статья обучает новичков тому, как создать советник на языке MQL5, который торгует на основе распознавания графических паттернов с использованием пробоев трендовых линий и разворотов. Изучив, как динамически извлекать значения трендовой линии и сравнивать их с ценовым действием, читатели смогут разрабатывать советники, способные выявлять графические паттерны, такие как восходящие и нисходящие трендовые линии, каналы, клинья, треугольники и многие другие, и торговать по ним.
Быстрая интеграция большой языковой модели и MetaTrader 5 (Часть II): Файнтьюн на реальных данных, бэктест и онлайн-торговля модели Быстрая интеграция большой языковой модели и MetaTrader 5 (Часть II): Файнтьюн на реальных данных, бэктест и онлайн-торговля модели
Статья описывает процесс файнтьюна языковой модели для трейдинга на основе реальных исторических данных из MetaTrader 5. Базовая модель, знающая лишь теоретический технический анализ, обучается на тысяче примеров реального поведения валютных пар (EURUSD, GBPUSD, USDCHF, USDCAD) за 180 дней. После обучения через Ollama модель начинает понимать специфику каждого инструмента.
Квантовые вычисления и градиентный бустинг в торговле EUR/USD Квантовые вычисления и градиентный бустинг в торговле EUR/USD
Статья описывает практическую реализацию гибридной системы алгоритмического трейдинга, объединяющей квантовые вычисления (IBM Qiskit) и градиентный бустинг (CatBoost) для предсказания движения EUR/USD на часовом таймфрейме. Система извлекает четыре уникальных квантовых признака из вероятностного распределения по 256 состояниям через восемь кубитов, которые в комбинации с классическими индикаторами и дельта-кодированием временных категорий достигают точности 62% на 15,000 свечах.
Нейросети в трейдинге: Пространственно-временная модель состояния для анализа финансовых данных (Окончание) Нейросети в трейдинге: Пространственно-временная модель состояния для анализа финансовых данных (Окончание)
Представляем адаптацию фреймворк E-STMFlow — современное решение для построения автономных торговых систем. В статье завершаем реализацию подходов, предложенных авторами фреймворка. Результаты тестирования демонстрируют стабильный рост капитала, минимальные просадки и предсказуемое распределение рисков, подтверждая практическую эффективность подхода и открывая перспективы дальнейшей оптимизации стратегии.