Нейросети в трейдинге: разностное моделирование рыночной микроструктуры (EDCFlow)
Введение
Финансовый рынок дышит, сжимается, взрывается импульсами и замирает в ожидании. Именно в этих переходах скрыта основная информация о будущем движении. Большинство алгоритмов анализа и прогнозирования традиционно рассматривают рынок как последовательность состояний, связанных между собой степенью сходства. Они ищут корреляцию, измеряют согласованность, оценивают, насколько текущее состояние похоже на предыдущее. В этом есть логика, но есть и ограничение. Ведь рынок ломается там, где становится другим.
Предложенный в работе "EDCFlow: Exploring Temporally Dense Difference Maps for Event-based Optical Flow Estimation" фреймворк разностного моделирования рыночной микроструктуры исходит из этого наблюдения. Он сохраняет корреляцию как источник устойчивого представления движения, но дополняет её темпорально плотной картой разностей между соседними состояниями потока. Таким образом, анализ строится сразу в двух плоскостях. Сходство состояний формирует контекст, а их отличия выявляют момент изменения динамики. Такой подход усиливает импульсы и фиксирует локальные изменения структуры движения, не дожидаясь накопления статистики. Разностное представление позволяет реагировать на изменения быстрее, чем при использовании только корреляционных методов.
Если представить рынок как поток, то классические корреляционные методы изучают форму волны. Разностной подход фиксирует её изломы, ускорение, смену направления и резкие изменения плотности движения. Это принципиально иной взгляд на динамику. Именно он лежит в основе EDCFlow. Он не заменяет привычные методы, а усиливает их, обеспечивая более полное и информативное представление движения рынка.
Традиционные потоковые модели рассматривают рынок как последовательность состояний, между которыми ищется соответствие. Это похоже на сопоставление двух снимков графика и оценку их похожести. Хорошо работает в устойчивых режимах, когда движение плавное. Но начинает запаздывать при появлении импульсов, резких сдвигов ликвидности и смене рыночного режима. Разностное дополнение позволяет фиксировать эти изменения сразу, сохраняя важную информацию о микроструктуре рынка.
Важным преимуществом фреймворка является его фокус на микродвижениях. Речь идет не о направлении цены в привычном смысле, а о характере движения. Быстро или вязко. Рывком или серией мелких шагов. Согласованно или с внутренними противоречиями. Разностный анализ фиксирует эти нюансы напрямую, усиливая импульсы, делая их заметными и реагируя на их зарождение. Это особенно важно в краткосрочных и внутридневных стратегиях, где запаздывание даже на несколько баров снижает эффективность.
EDCFlow выступает как слой представления рыночной динамики. Инфраструктура, которая показывает рынок таким, какой он есть. Это похоже на переход от привычного свечного графика к потоку сделок. Свечи удобны и привычны, но скрывают важные детали. В то же время поток отражает реальную динамику. Разностный фреймворк выполняет аналогичную задачу для моделей на основе нейросетей.
Разностное дополнение к корреляции также повышает устойчивость к смене рыночных режимов. Корреляция предполагает повторяемость паттернов, тогда как карта разностей фиксирует момент изменения. Это снижает риск слепоты алгоритмов в переходных фазах, когда большинство стратегий перестают работать. При этом фреймворк остаётся гибким. Его можно использовать как входной слой для классических нейросетей и рекуррентных моделей, усиливая любые алгоритмы за счёт более информативного представления рынка.
С позиции практики трейдинга этот подход близок к интуиции опытного трейдера. Трейдер держит в голове общую картину рынка (аналог корреляции), но принимает решение, ориентируясь на отклонения и нетипичные движения (аналог разности). EDCFlow формализует эту интуицию, делая её доступной алгоритмам. При этом сохраняется вычислительная эффективность. Отказ от громоздких корреляционных конструкций не требуется. Карта разностей лишь дополняет их, повышая чувствительность модели к импульсным движениям и минимизируя задержки.
Алгоритм EDCFlow
В фреймворка EDCFlow лежит представление событийного потока, где каждое событие кодируется с указанием координаты, временной метки и направления изменения. Это позволяет формализовать поток данных и представить его в виде пространственно-временной массив. Каждое событие в этом массиве вносит вклад не только в ближайший временной интервал, но и распределяется между соседними временными слотами, что обеспечивает темпоральную плотность представления и позволяет учитывать мельчайшие изменения рыночной динамики.
Основная задача заключается в оценке плотного потока — то есть прогнозирования изменений состояний с текущего момента на следующий. Для этого авторы фреймворка предлагают рассматривать два последовательных сегмента событий — текущий сегмент и предыдущий как эталон. Предыдущий сегмент создаёт контекст, позволяя модели ориентироваться в структуре потока. А текущий фиксирует актуальные изменения, которые необходимо проанализировать. Такой подход обеспечивает баланс между устойчивым контекстом рынка и чувствительностью к мгновенным изменениям.
Архитектура EDCFlow построена вокруг трёх ключевых этапов. Первый — извлечение признаков. Энкодер признаков формирует двухуровневое представление данных, позволяя выявлять отличия между состояниями на высоком разрешении и одновременно строить агрегированное представление низкого разрешения для глобального анализа потока. Энкодер контекста добавляет дополнительную информацию об общей структуре данных, аналогично тому, как трейдер оценивает общую картину через текущую глубину рынка и динамику объемов.
Второй этап — кодирование движения. На низком разрешении сохраняются корреляционные признаки, которые кодируются через поиск соответствий и пространственно-временное кодирование. После чего масштабируются и объединяются с временно плотными изменениями, которые фиксируются через слой многомасштабных разностей. Это позволяет модели улавливать мгновенные импульсы. Два этих взаимодополняющих представления движения объединяются через слой внимания, который адаптивно распределяет значимость корреляции и разностной информации. Такой механизм делает модель чувствительной к микродвижениям, но при этом сохраняет общую структуру потока.
Третий этап — обновление потока. Резидуальный поток декодируется с помощью GRU, который уточняет текущие оценки движения на основе объединённых признаков. Процесс кодирования движения и обновления потока выполняется итеративно, что позволяет постепенно уточнять прогноз и учитывать последовательность событий на всех уровнях.
Точная фиксация временной динамики рынка является ключевым этапом работы модели. Авторы фреймворка делят анализируемый сегмент потока событий на несколько последовательных временных окон. Каждое окно фиксирует локальные изменения, а предыдущий сегмент используется в качестве эталона. В итоге формируется последовательность из нескольких временных блоков, каждый из которых несёт уникальную информацию о развитии рынка. Такая структура позволяет модели видеть эволюцию признаков на протяжении нескольких последовательных интервалов.
Для каждого временного блока создаётся структурированное представление потока. Каждое событие распределяется по двум ближайшим временным слотам, обеспечивая плотное покрытие. Это создаёт пространственно-временное представление потока, где каждая микроскопическая деталь фиксируется и может быть использована для анализа. В результате модель получает высокую чувствительность к импульсам, резким изменениям ликвидности и внезапным сдвигам структуры рынка, что особенно важно для краткосрочных и внутридневных стратегий.
Далее применяется Энкодер с общими весами, который извлекает признаки в двух уровнях разрешения. Высокое разрешение фиксирует локальные, тонкие изменения — кратковременные всплески цены или объёма. Мелкие, но значимые колебания. Низкое разрешение формирует более сглаженное, глобальное представление потока, которое отражает общую тенденцию рынка. Такая двухуровневая архитектура позволяет модели одновременно учитывать как микродвижения, так и макроструктуру рынка, создавая баланс между чувствительностью к шуму и сохранением глобальной согласованности.
Для экономии вычислительных ресурсов и памяти формируется 4D-тензор корреляций признаков в низком разрешении, который сопоставляет признаки первого и последнего временного окна сегмента. Этот тензор выполняет роль карты соответствий между различными моментами потока, позволяя выявлять устойчивые связи между сегментами рынка и обеспечивая точность поиска соответствий. В финансовом контексте это означает, что модель видит, как локальные изменения соотносятся с общей динамикой рынка. И может идентифицировать закономерности, которые не заметны при простом усреднении данных.
Контекстный энкодер, построенный по аналогичной архитектуре, добавляет информацию о глобальной структуре потока. Он фиксирует стабильные элементы рынка и формирует основу для последующих обновлений прогнозного потока. Таким образом, модель одновременно смотрит вдаль, оценивая общую картину, и смотрит вблизи, фиксируя каждое изменение.
Для точного прогнозирования движения авторы фреймворка используют карты разностей высокого разрешения и объём корреляции низкого разрешения, объединённые в единое представление. Такой подход позволяет оценивать динамику потока максимально эффективно и обеспечивать высокую точность при прогнозировании краткосрочных изменений. Архитектура построена как итеративная схема: на каждой итерации уточняется текущая оценка движения, сужается область поиска и усиливается чувствительность к локальным импульсам.
Корреляционный энкодер играет ключевую роль в улавливании долгосрочных зависимостей потока. Карты разностей фиксируют мгновенные изменения между соседними временными окнами, но не дают прямого соответствия между отдалёнными сегментами. Коэффициенты корреляции на низком разрешении решает эту проблему. Они фиксируют связи между началом и концом сегмента рынка, позволяя модели выявлять устойчивые закономерности. На практике это реализуется через построение матриц корреляций для каждого временного окна с последующим масштабированием на высокий уровень разрешения и кодированием признаков через свёрточные блоки. Такой механизм позволяет быстро и эффективно учитывать локальные и глобальные зависимости.
Многомасштабное кодирование временных разностей позволяет фиксировать непрерывные движения рынка с высокой детализацией. Для этого признаки каждого временного окна выравниваются относительно эталонного сегмента с помощью текущей оценки потока. В малых временных интервалах движение можно считать линейным, что упрощает расчёт плотных карт разностей. После вычисления разностей применяется уменьшение размерности каналов, что снижает нагрузку на память и ускоряет вычисления. А также добавляется пространственная фильтрация, которая сглаживает границы и подчёркивает важные изменения.
Для обработки движений различной скорости применяется многомасштабная стратегия выборки. Быстрые изменения фиксируются на коротких интервалах, медленные — на более длинных. Для каждого масштаба формируется последовательность карт разностей, которая затем проходит через 3D-свёртки, восстанавливающие пространственно-временные признаки и восстанавливающие каналы для дальнейшей обработки. Такой подход позволяет учитывать разнообразие рыночных паттернов и ускоряет интеграцию данных в последующие модули.
Адаптивное объединение через внимание обеспечивает эффективное сочетание корреляционных и разностных признаков. Корреляция задаёт стабильную структуру движения рынка, карты разностей фиксируют локальные импульсы и резкие изменения. Через механизмы внимания признаки объединяются в единое представление движения, где модель сама определяет, на что следует обратить больше внимания. Это особенно важно для внутридневного или высокочастотного анализа, когда импульсы и шум могут сменять друг друга с высокой скоростью.
Итеративное обновление потока выполняется через GRU. Он получает на вход контекстные признаки и объединённые признаки движения, вычисляет резидуальный поток и уточняет текущую оценку движения рынка. Итеративное выполнение кодирования и обновления потока позволяет модели постепенно повышать точность прогнозирования, учитывая глобальные тенденции и локальные импульсы. Каждая итерация сужает область поиска, делая модель более точной и чувствительной к изменениям в реальном времени.
На практике это реализуется как последовательный вычислительный pipeline. Признаки каждого временного окна формируются через энкодеры, создаются карты разностей и тензор корреляций. Признаки объединяются через слой внимания и подаются в GRU для расчёта резидуального потока. Итеративное уточнение позволяет плавно интегрировать информацию о локальных изменениях и глобальной структуре потока, создавая адаптивное и информативное представление рынка. Такой подход даёт возможность напрямую использовать результаты для построения торговых сигналов, оценки краткосрочных изменений и формирования прогнозов движения цены.
Авторская визуализация фреймворка EDCFlow представлена ниже.

Реализация средствами MQL5
После детального разбора теоретических основ фреймворка EDCFlow логично перейти от абстракций к практике. И следующим шагом становится прикладная реализация одного из вариантов организации предложенных подходов средствами MQL5. Здесь теория перестаёт быть красивой схемой и превращается в рабочий механизм, способный обрабатывать реальный поток рыночных событий.
Мы сознательно идём не по пути прямого копирования архитектуры, а адаптируем её для решения наших задач. Это инженерный компромисс, знакомый каждому трейдеру: сохранить суть, отбросить лишнее и усилить то, что действительно даёт преимущество. В результате EDCFlow трансформируется из академического фреймворка в прикладную модель анализа рыночной микроструктуры, пригодную для оптимизации и дальнейшего включения в торговую систему.
Процесс вычисления разностей
Начинать практическую реализацию разумно с организации базовых процессов. Именно здесь закладывается фундамент всей дальнейшей работы. Ключевым нововведением фреймворка EDCFlow является использование разностей состояний с различным смещением по временной оси. По сути, мы анализируем не только то, где находится рынок, но и как именно он к этому состоянию пришёл. С какой скоростью. В каком ритме. И с какими промежуточными изменениями.
Такой подход почти автоматически приводит к большому числу однотипных операций. Разности считаются для разных временных окон, с разными лагами, на одних и тех же массивах данных. Это напоминает работу трейдера, который одновременно смотрит на несколько таймфреймов. Логика одна, данных много, а вычислений ещё больше. В классической CPU-реализации подобная нагрузка быстро становится узким местом. Особенно если мы говорим не о постфактум-анализе, а о работе с живым рынком.
А мы как раз планируем использовать модель в режиме реального времени. Это принципиальный момент. Здесь нет права на долгие раздумья и тяжёлые циклы. Решения должны приниматься быстро, а вычисления — укладываться в жёсткие временные рамки. Следовательно, нам необходимы решения с минимальными затратами времени на обработку большого массива элементарных операций.
В этом контексте использование GPU выглядит не просто логичным, а практически безальтернативным. Графический процессор идеально подходит для параллельного выполнения однотипных вычислений, таких как расчёт разностей, корреляций и промежуточных признаков. То, что на CPU выполняется последовательно и долго, на GPU превращается в поток простых, независимых операций, обрабатываемых одновременно.
Для реализации разностного анализа на стороне GPU мы создаем новый кернел на стороне нашей OpenCL-программы. Именно здесь идея разностей состояний с различным временным смещением впервые получает материальное воплощение в коде. Кернел DilatedDifference становится рабочей лошадкой всей архитектуры, выполняя массовые, однотипные и потому идеально параллелизуемые операции.
__kernel void DilatedDifference(__global const float* feature, __global const int* shifts, __global float* differences ) { const size_t main = get_global_id(0); const size_t sh = get_global_id(1); const size_t d = get_global_id(2); const size_t units = get_global_size(0); const size_t total_shifts = get_global_size(1); const size_t dimension = get_global_size(2);
Логика кернела построена предельно прямолинейно. Каждому вычислительному потоку соответствует конкретное состояние рынка, конкретное смещение по времени и конкретное измерение признакового пространства. Такой трёхмерный индекс позволяет одновременно обрабатывать все комбинации состояний, лагов и признаков без вложенных циклов. GPU здесь работает в своей стихии, выполняя тысячи простых операций вычитания параллельно, без лишних проверок и задержек.
Массив feature содержит исходные признаки состояния рынка, уже подготовленные на предыдущем этапе. Массив shifts задаёт временные смещения, фактически определяя, какие состояния будут сравниваться между собой. Это и есть ключевой элемент разностного подхода. Мы не просто сравниваем соседние моменты времени, а можем задавать произвольную структуру лагов, адаптированную под текущую задачу и характер рынка.
Перед вычислением разности выполняется базовая проверка корректности индекса. Если смещённое состояние выходит за допустимые границы, результат принудительно обнуляется. Это простое решение избавляет от лишних ветвлений в основной логике и делает поведение кернела предсказуемым.
const int slave = shifts[sh]; if(slave < 0 || slave >= units) { differences[RCtoFlat(main, d, units, dimension, sh)] = 0; return; }
Далее значения признаков извлекаются из глобальной памяти, с дополнительной защитой от некорректных чисел. В условиях реального рынка такие проверки не роскошь, а необходимость.
float value_main = IsNaNOrInf(feature[RCtoFlat(main, d, units, dimension, 0)], 0); float value_slave = IsNaNOrInf(feature[RCtoFlat(slave, d, units, dimension, 0)], 0);
Само вычисление разности предельно прозрачно. Из значения текущего состояния вычитается значение состояния со смещением. Никакой магии. Только чистая математика. Именно эта простота и даёт силу подходу. На выходе формируется плотный массив разностей, где каждая ячейка отражает изменение конкретного признака между двумя моментами рынка с заданным временным лагом.
float result = value_main - value_slave; //--- differences[RCtoFlat(main, d, units, dimension, sh)] = result; }
Важно отметить, что такой кернел масштабируется почти линейно. Добавление новых смещений или увеличение размерности признаков не меняет структуру кода, а лишь расширяет сетку вычислений. Это критично для работы в реальном времени, когда количество анализируемых лагов может адаптироваться под рыночную фазу.
В итоге DilatedDifference становится фундаментальным строительным блоком всей реализации EDCFlow. Он переводит концепцию разностного моделирования из теоретической плоскости в практическую. Рынок здесь уже не рассматривается как статическая последовательность состояний. Он превращается в динамическое поле изменений, где каждое движение, каждый сдвиг и каждый импульс получают количественное выражение — быстро, параллельно и с минимальными задержками.
Однако здесь важно сделать принципиальное уточнение. Несмотря на то что сам алгоритм вычисления разностей не содержит обучаемых параметров, это вовсе не освобождает нас от необходимости организовать корректное обратное распространение ошибки. Мы используем разности не как внешний аналитический индикатор, а как внутренний элемент обучаемой модели. А значит, каждый такой оператор обязан быть дифференцируемым и корректно встраиваться в общий граф вычислений. Рынок, как известно, ошибок не прощает.
Именно для этого создается отдельный OpenCL-кернел DilatedDifferenceGrad, отвечающий за распространение градиентов обратно к исходным признакам. Его задача — аккуратно и эффективно собрать вклад каждого временного смещения в общий градиент состояния. По сути, мы решаем обратную задачу. Если в прямом проходе каждое состояние влияло на множество разностей, то в обратном проходе каждая разность должна вернуть свой вклад всем задействованным состояниям.
__kernel void DilatedDifferenceGrad(__global const float* feature, __global float* feature_gr, __global const int* shifts, __global const float* differences_gr, const int total_shifts ) { const size_t id = get_global_id(0); const size_t loc = get_local_id(1); const size_t d = get_global_id(2); const size_t units = get_global_size(0); const size_t total_loc = get_local_size(1); const size_t dimension = get_global_size(2); //--- __local float temp[LOCAL_ARRAY_SIZE];
Логика кернела отражает эту идею предельно чётко. Для каждого состояния и каждого измерения признакового пространства мы последовательно просматриваем все заданные смещения. Если текущее состояние выступало в роли основного, его градиент увеличивается. Если оно оказывалось смещённым, градиент уменьшается. Это прямое следствие определения разности, без каких-либо эвристик или упрощений. Математика здесь строга, как бухгалтерский баланс: всё, что было вычтено, должно быть возвращено обратно с правильным знаком.
float result = 0.0f; for(int sh = loc; sh < total_shifts; sh += total_loc) { const int offset = shifts[sh]; int slave = id + offset; if(slave >= 0 && slave < units) { // id — main result += IsNaNOrInf(differences_gr[RCtoFlat(id, d, units, dimension, sh)], 0.0f); // id — slave result -= IsNaNOrInf(differences_gr[RCtoFlat(slave, d, units, dimension, sh)], 0.0f); } }
Особое внимание уделено производительности. Градиенты по смещениям аккумулируются с использованием локальной памяти и редукции внутри рабочей группы. Это позволяет избежать атомарных операций и лишних обращений к глобальной памяти, что критично для работы в реальном времени. Такой подход хорошо масштабируется и сохраняет стабильную скорость даже при увеличении числа временных лагов и размерности признаков.
result = LocalSum(result, 1, temp); if(loc == 0) feature_gr[RCtoFlat(id, d, units, dimension, 0)] = result; }
Важно и то, что этот кернел полностью симметричен прямому проходу. Он не вводит новых предположений и не нарушает структуру вычислительного графа. Это делает модель устойчивой к обучению и позволяет без ограничений встраивать разностные слои в более сложные архитектуры — с рекуррентными блоками, механизмами внимания и итеративным обновлением состояния.
В итоге мы получаем важный практический результат. Разностный анализ в EDCFlow остаётся простым по своей сути, но при этом становится полноценным участником процесса обучения. Он не просто вычисляет изменения рынка, а активно формирует градиентное поле, влияя на настройку всей модели. Это именно тот случай, когда строгая математика, грамотная инженерия и здравый трейдерский смысл сходятся в одной точке.
Depth-Wise свертка
Следующий момент, на который имеет смысл обратить особое внимание, связан с выбором авторами фреймворка механизма DW-3DConvs, то есть трёхмерных свёрток с разделением по каналам. На первый взгляд это может показаться второстепенной технической деталью, однако именно здесь проходит граница между архитектурой, пригодной для офлайн-экспериментов, и моделью, способной работать с рынком в режиме реального времени.
Трёхмерная свёртка принципиально расширяет классический подход. Она учитывает не только пространственные измерения признаков, но и временную ось. В терминах финансового рынка это означает, что модель перестаёт анализировать изолированные срезы данных и начинает работать с последовательностью состояний. Цена, объём и производные признаки воспринимаются как непрерывный поток, где важна не только величина, но и динамика изменения. Именно такой взгляд соответствует идеологии EDCFlow, в которой движение рынка описывается через эволюцию состояний, а не через набор статических значений.
Разделение по каналам, заложенное в Depth-Wise подходе, решает сразу несколько практических задач. Свёртка применяется к каждому каналу признаков независимо, без их преждевременного смешивания. Это резко снижает количество параметров и вычислительных операций. Но, что гораздо важнее, позволяет сохранить локальные особенности сигнала. Для трейдинга это критично. Рынок редко движется усреднённо. Решения принимаются на границе, в тонких сдвигах, которые легко потерять при агрессивной агрегации признаков.
Авторы фреймворка справедливо отмечают, что простое суммирование или конкатенация разностных карт признаков приводит либо к потере деталей, либо к резкому росту вычислительной сложности. В первом случае модель теряет чувствительность к локальным импульсам. Во втором — становится слишком тяжёлой для практического применения. DW-3DConvs позволяют найти баланс между этими крайностями. Они эффективно агрегируют многомасштабные признаки движения, сохраняя пространственно-временную структуру потока и не перегружая вычислительный контур.
В рамках нашей работы Depth-Wise подход реализуем в рамках самостоятельного объекта, встроенного в общий конвейер модели. Для этого мы вводим новый класс CNeuronSpikeDepthWiseConv, который наследуется от спайкового сверточного блока и органично вписывается в существующую иерархию нейронных компонентов.
class CNeuronSpikeDepthWiseConv : public CNeuronSpikeConvBlock { protected: CNeuronTransposeVRCOCL cTranspose[2]; CNeuronMultiWindowsConvWPadOCL cDepthConv; CNeuronBatchNormOCL cNorm; //--- virtual bool feedForward(CNeuronBaseOCL *NeuronOCL) override; virtual bool updateInputWeights(CNeuronBaseOCL *NeuronOCL) override; virtual bool calcInputGradients(CNeuronBaseOCL *NeuronOCL) override; public: CNeuronSpikeDepthWiseConv(void) {}; ~CNeuronSpikeDepthWiseConv(void) {}; //--- virtual bool Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint chanels_in, uint chanels_out, uint depth_window, uint depth_step, uint units, uint variables, ENUM_OPTIMIZATION optimization_type, uint batch); //--- virtual int Type(void) override const { return defNeuronSpikeDepthWiseConv; } //--- methods for working with files virtual bool Save(int const file_handle) override; virtual bool Load(int const file_handle) override; //--- virtual bool WeightsUpdate(CNeuronBaseOCL *source, float tau) override; //--- virtual void SetActivationFunction(ENUM_ACTIVATION value) override { }; virtual void SetOpenCL(COpenCLMy *obj) override; virtual void TrainMode(bool flag) override; };
Структура класса напрямую отражает логику DW-3DConvs, адаптированную под потоковую обработку рыночных данных. На входе и выходе используются транспонирующие блоки, которые приводят данные к удобному для глубинной свёртки формату и обратно. Это важный момент. В Depth-Wise архитектуре порядок измерений имеет критическое значение, и явное управление представлением тензоров позволяет избежать скрытых преобразований и лишних копирований данных.
Центральным элементом является объект cDepthConv, отвечающий за свёртку по временному измерению в паддингом. Именно здесь реализуется идея независимой обработки каналов признаков. Каждый канал анализируется в своём временном контексте, без преждевременного смешивания с другими признаками. Для финансовых потоков это означает, что модель может отдельно отслеживать динамику цены, объёма или производных характеристик, сохраняя их индивидуальную структуру движения.
Метод инициализации задаёт ключевые параметры блока и, по сути, формирует его внутреннюю архитектуру. Именно здесь абстрактное понятие Depth-Wise превращается в конкретную вычислительную схему.
bool CNeuronSpikeDepthWiseConv::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl, uint chanels_in, uint chanels_out, uint depth_window, uint depth_step, uint units, uint variables, ENUM_OPTIMIZATION optimization_type, uint batch) { if(!CNeuronSpikeConvBlock::Init(numOutputs, myIndex, open_cl, chanels_in, chanels_in, chanels_out, units, variables, optimization_type, batch)) return false;
Первым шагом управление передается родительскому классу. Это позволяет сразу встроить новый объект в общий конвейер модели и унаследовать всю необходимую инфраструктуру. Важно, что число входных и выходных каналов на этом этапе фиксируется таким образом, чтобы Depth-Wise операция не нарушала согласованность размерностей. Мы сознательно сохраняем симметрию каналов, подчёркивая независимую обработку каждого признака.
Далее последовательно инициализируются два транспонирующих блока. Первый из них подготавливает данные к глубинной свёртке, переупорядочивая измерения.
uint index = 0; if(!cTranspose[0].Init(0, index, OpenCL, variables, units * depth_step, chanels_in, optimization, iBatch)) return false; cTranspose[0].SetActivationFunction(None);
Это чисто технический, но принципиально важный момент. В Depth-Wise архитектуре неверное расположение измерений неминуемо приводит либо к потере производительности, либо к искажению смысла вычислений.
Второй транспонирующий блок выполняет обратное преобразование, возвращая данные в формат, ожидаемый остальной частью модели.
index++; if(!cTranspose[1].Init(0, index, OpenCL, variables, chanels_in, units, optimization, iBatch)) return false; cTranspose[1].SetActivationFunction(None); index++;
Оба блока работают без функций активации, поскольку их задача — исключительно корректное представление данных, без внесения нелинейностей.
Центральным элементом инициализации становится настройка объекта cDepthConv. Здесь задаётся размер временного окна и шаг по глубине, определяющие, какие именно фрагменты временного потока будут агрегироваться.
uint windows[] = { depth_window }; if(!cDepthConv.Init(0, index, OpenCL, windows, depth_step, 1, units, chanels_in * variables, optimization, iBatch)) return false; cDepthConv.SetActivationFunction(None); index++;
Каждый канал обрабатывается независимо, но при этом учитывается временная структура данных. В контексте финансовых рынков это означает, что модель анализирует эволюцию каждого признака в заданном временном интервале, не смешивая его с другими каналами на данном этапе. Такая изоляция особенно ценна при работе с разностными признаками, где важно сохранить форму локального движения.
После свёртки следует инициализация блока нормализации. Его роль трудно переоценить. Разностные и временные признаки обладают высокой изменчивостью, и без нормализации обучение быстро становится нестабильным. Включение нормализации прямо в Depth-Wise блок позволяет стабилизировать распределение активаций и обеспечить корректное распространение градиентов на последующих этапах обучения. Это решение продиктовано практикой, а не теорией, и напрямую влияет на устойчивость модели при работе с реальными рыночными данными.
if(!cNorm.Init(0, index, OpenCL, cDepthConv.Neurons(), iBatch, optimization)) return false; //--- return true; }
В результате метод инициализации формирует законченный, самодостаточный модуль. Он точно знает, сколько каналов обрабатывать, с каким временным окном работать.
За организацию прямого прохода отвечает метод feedForward, и его структура наглядно отражает философию всего блока. Никакой магии, только строгая последовательность преобразований, где каждый этап выполняет свою, чётко очерченную роль.
bool CNeuronSpikeDepthWiseConv::feedForward(CNeuronBaseOCL *NeuronOCL) { if(!cTranspose[0].FeedForward(NeuronOCL)) return false;
Прямой проход начинается с первого транспонирования. Блок cTranspose[0] получает указатель на объект исходных данных и приводит их к формату, удобному для глубинной временной свёртки. Это похоже на аккуратную подготовку рабочего стола перед анализом графика: всё разложено по местам, ничего лишнего, никакой спешки.
Далее управление передаётся объекту cDepthConv. Именно здесь происходит ключевая операция Depth-Wise свёртки. Каждый канал обрабатывается независимо, но с учётом временного контекста. Модель не смешивает признаки раньше времени, а внимательно отслеживает, как каждый из них эволюционирует внутри заданного временного окна.
if(!cDepthConv.FeedForward(cTranspose[0].AsObject())) return false;
После выполнения свёртки данные снова приводятся в стандартное представление при помощи второго транспонирующего блока cTranspose[1]. Это обратный шаг, возвращающий результат в форму, совместимую с остальной архитектурой модели.
if(!cTranspose[1].FeedForward(cDepthConv.AsObject())) return false;
Формально операция проста, но концептуально она замыкает локальный контур обработки Depth-Wise блока, делая его прозрачным для внешних компонентов.
Следующим этапом идёт нормализация, которая стабилизирует распределение признаков, сглаживает резкие выбросы и выравнивает масштаб. В условиях рыночных данных, где всплески волатильности — не исключение, а норма, этот шаг играет роль амортизатора. Он снижает чувствительность модели к шуму, не подавляя при этом полезные движения.
if(!cNorm.FeedForward(cTranspose[1].AsObject())) return false;
Завершается прямой проход смешивание каналов. Depth-Wise свёртка принципиально работает в одиночку. Каждый канал обрабатывается независимо. Это сознательный и оправданный шаг. Мы сначала даём модели возможность аккуратно, без взаимных искажений, извлечь локальную временную динамику каждого признака. Классический, осторожный подход. Сначала понять каждый инструмент, а уже потом собирать ансамбль.
Но рынок — система взаимосвязанная. И на этом этапе наступает время синтеза. Вызов одноименного метода родительского класса выполняет роль точки сборки. Здесь временная динамика перестаёт быть набором изолированных откликов и превращается в совместное пространство признаков. Каналы начинают разговаривать друг с другом. Аккуратно, без хаоса, под контролем обучаемых параметров.
if(!CNeuronSpikeConvBlock::feedForward(cNorm.AsObject())) return false; //--- return true; }
В итоге метод прямого прохода выглядит компактным, почти аскетичным. Но за этой лаконичностью скрыта выверенная инженерная логика. Каждый шаг оправдан. Каждый вызов стоит на своём месте. Алгоритм хорошо масштабируется, легко отлаживается и, что особенно важно, сохраняет интерпретируемость обработки временных признаков.
Объект CNeuronSpikeDepthWiseConv становится практическим воплощением идей DW-3DConvs. Он сохраняет ключевые преимущества подхода — эффективность, сохранение деталей движения и масштабируемость. И при этом вписывается в строгую архитектурную дисциплину торговой модели.
Заключение
Фреймворк EDCFlow представляет собой принципиально новый взгляд на анализ рыночной микроструктуры. Его основное преимущество заключается в том, что он не ограничивается традиционной корреляцией состояний. Дополняет её картой разностей, позволяя выявлять тонкие динамические изменения рынка, которые традиционные подходы часто упускают. Это особенно важно для проведения анализа в режиме реального времени, где каждая доля секунды и каждое изменение объёма могут иметь критическое значение.
Архитектура фреймворка тщательно продумана и обеспечивает баланс между точностью и вычислительной эффективностью. Использование разностных признаков совместно с корреляцией создаёт более насыщенное и информативное представление о движении рынка, а depth-wise свёртки позволяют аккуратно агрегировать многомасштабные признаки, не теряя локальные детали.
На данном этапе мы лишь заложили фундамент для построения будущей модели, к работе над которой мы вернемся уже в следующей статье.
Ссылки
- EDCFlow: Exploring Temporally Dense Difference Maps for Event-based Optical Flow Estimation
- Другие статьи серии
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | Study.mq5 | Советник | Советник офлайн обучения моделей |
| 2 | StudyOnline.mq5 | Советник | Советник онлайн обучения моделей |
| 3 | Test.mq5 | Советник | Советник для тестирования модели |
| 4 | Trajectory.mqh | Библиотека класса | Структура описания состояния системы и архитектуры моделей |
| 5 | NeuroNet.mqh | Библиотека класса | Библиотека классов для создания нейронной сети |
| 6 | NeuroNet.cl | Библиотека | Библиотека кода OpenCL-программы |
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Знакомство с языком MQL5 (Часть 22): Создание советника для торговли по паттерну 5-0
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (Окончание)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования