Нейросети в трейдинге: от рыночного шума к устойчивому торговому плану (MomAD)
Введение
Торговая модель редко ошибается красиво. Чаще она ошибается мелко, часто и дорого. На одном баре модель видит продолжение движения, на следующем — локальный откат, затем снова возвращается к первоначальному сценарию. Визуально это похоже на высокую чувствительность к рынку. Но в реальной торговле такая чувствительность быстро превращается в проблему: позиция закрывается раньше времени, повторный вход происходит хуже, а часть результата уходит на спред, комиссии и проскальзывание.
Особенно болезненно это проявляется на прибыльных участках. Система правильно определяет направление, входит в позицию, но не даёт движению раскрыться. Обычная коррекция воспринимается как смена режима, и модель начинает перестраивать торговый план. Вместо удержания рабочего сценария появляется преждевременный выход. В худшем случае за ним следует контртрендовая сделка. Так система теряет дважды: сначала недобирает прибыль по сильному движению, затем получает убыток на попытке торговать против него.
Эта проблема не сводится только к качеству прогноза. Модель может хорошо описывать отдельные состояния рынка, но оставаться нестабильной во времени. Каждый новый бар запускает пересмотр решения почти с нуля. Если текущий прогноз немного отличается от предыдущего, система меняет сигнал, хотя общая рыночная картина ещё не сломалась. Для трейдера это знакомая ситуация: рынок шумит, цена дышит. Однако это ещё не означает, что торговую идею нужно немедленно отменять.
В качестве отправной точки мы рассмотрим статью «Don’t Shake the Wheel: Momentum-Aware Planning in End-to-End Autonomous Driving». В ней предложен фреймворк MomAD для повышения устойчивости планирования в системах автономного вождения. Исходная работа стабилизирует последовательные траектории автомобиля: вводит Trajectory Momentum и Perception Momentum, применяет Topological Trajectory Matching с расстоянием Хаусдорфа и дополняет планирование взаимодействием текущего Planning Query с историческим контекстом. Цель такого подхода — уменьшить резкие расхождения между соседними прогнозами и сделать поведение модели более согласованным во времени.
В данной работе мы не воспроизводим автомобильную архитектуру напрямую. Она создавалась для другой среды, других данных и другой задачи управления. Нас интересует перенос отдельных принципов MomAD в область финансовых временных рядов. Вместо траекторий автомобиля мы будем рассматривать последовательности рыночных состояний. Вместо устойчивости рулевого управления — устойчивость торгового плана. Поэтому центральный вопрос звучит иначе: может ли модель отличать настоящую смену рыночного сценария от обычного шума, не закрывать прибыльную позицию преждевременно и не переходить к контртрендовому действию без достаточных оснований?
Классический подход к торговле всегда учитывал эту разницу. Трейдер не обязан реагировать на каждое движение цены. Он оценивает контекст: сохраняется ли структура движения, насколько силён откат, есть ли признаки настоящего разворота. Иными словами, торговое решение живёт не один бар. У него есть инерция. Но это не слепое запаздывание и не механическое сглаживание сигнала. Это способность удерживать рабочий план до тех пор, пока рынок не даст достаточно веских оснований его пересмотреть.
Для нейросетевой модели такая инерция не появляется сама по себе. Если архитектура каждый раз выбирает сценарий только по текущему состоянию, она легко становится слишком нервной. Ей не хватает памяти принятого решения. Не памяти котировок вообще — с этим справляются рекуррентные блоки, механизмы внимания и различные формы контекстного кодирования. Речь о другом: модель должна помнить не только рынок, но и собственный ранее выбранный план.
В этой статье мы начнём строить механизм устойчивого торгового планирования на основе идей, предложенных в MomAD, но адаптированных к финансовым временным рядам. Его задача — не запретить модели менять решение, а заставить её делать это осмысленно. Рыночный шум не должен каждый раз разрушать рабочий сценарий. Но если рынок действительно меняет режим, система должна иметь возможность перестроиться.
Алгоритм MomAD
В статье «Don’t Shake the Wheel: Momentum-Aware Planning in End-to-End Autonomous Driving» авторы предлагают фреймворк MomAD — Momentum-Aware Driving. Его задача — сделать планирование автомобиля более устойчивым во времени. В классических End-to-End системах автономного вождения модель часто строит траекторию по текущему кадру почти изолированно. Это удобно с точки зрения архитектуры, но создаёт неприятный побочный эффект: соседние прогнозы могут заметно расходиться, даже если дорожная ситуация изменилась незначительно.
MomAD решает исходную задачу через идею Momentum-Aware Planning, то есть планирования с учётом инерции. Здесь Momentum не означает простой физический импульс в буквальном смысле. Авторы используют эту идею шире: текущее решение должно учитывать не только свежие признаки среды, но и ранее выбранную траекторию. Если новый прогноз близок к прежнему плану, нет необходимости резко менять поведение. Если расхождение становится существенным, модель получает основание перестроить траекторию.
При переносе этой идеи в трейдинг важно не спутать её с классическим ценовым импульсом. Здесь Momentum — это не индикатор направления движения и не попытка торговать тренд по самому факту его наличия. Речь идёт об инерции торгового плана. Модель должна понимать, что прежний сценарий не нужно ломать из-за каждого локального шума. Но она также не должна слепо удерживать позицию, если рынок действительно сменил режим. Поэтому задача состоит не в запаздывающем сглаживании сигнала, а в более тонком различении: где перед нами обычный откат, а где уже слом торговой гипотезы.
Архитектурно MomAD состоит из двух крупных частей. Первая отвечает за Sparse Perception — компактное представление окружающей сцены. В исходной задаче это данные с камер, дорожные агенты, элементы карты, объекты вокруг автомобиля и их динамика. Вторая часть отвечает за Momentum-Aware Planning — собственно механизм устойчивого планирования. Именно она представляет для нас основной интерес, потому что её принципы можно перенести из физического пространства дороги в пространство торговых сценариев.
В финансовой задаче аналогом Sparse Perception становится компактное описание рыночной среды. Вместо камер и дорожной карты используются рыночные признаки: котировки, объёмы, волатильность, диапазоны баров, производные метрики, состояние позиции и контекст предыдущих решений. Полная рыночная история слишком избыточна, а отдельная цена закрытия слишком бедна. Поэтому модель должна сформировать сжатое латентное представление, в котором остаётся главное: направление, структура движения, сила отката, плотность рыночных состояний, уровень неопределённости и потенциальный риск смены режима.
Ключевая идея MomAD раскрывается через два вида инерции: Trajectory Momentum и Perception Momentum. Trajectory Momentum отвечает за согласованность последовательных траекторий. Модель должна выбирать такой текущий вариант движения, который не разрушает без причины ранее выбранный путь. Perception Momentum расширяет контекст восприятия: модель использует не только текущие признаки сцены, но и исторические Planning Queries, которые несут информацию о прежнем состоянии среды и ранее построенных планах.
Для торговой системы Trajectory Momentum можно понимать как согласованность последовательных торговых сценариев. Если ранее модель выбрала сценарий продолжения роста, новый кандидат должен иметь достаточно оснований, чтобы этот сценарий отменить. Небольшой откат сам по себе не должен превращать рабочий Buy в преждевременный Sell. В свою очередь Perception Momentum можно связать с историей внутренних представлений модели: какие рыночные состояния она видела ранее, какие сценарии считала вероятными, насколько уверенным был предыдущий выбор и как менялась оценка риска.
Первым важным модулем MomAD является Topological Trajectory Matching, или TTM. На каждом шаге модель генерирует несколько возможных траекторий движения. Это мультимодальный набор кандидатов: автомобиль может продолжить движение прямо, выполнить поворот, сместиться по полосе или выбрать другой допустимый вариант поведения. Если просто взять траекторию с максимальным текущим Score, можно получить резкий скачок относительно предыдущего плана. Поэтому TTM добавляет этап согласования с историей.
В торговой задаче мультимодальность возникает естественно. Один и тот же рынок может допускать несколько рабочих гипотез: продолжение тренда, коррекцию, боковое движение, выход из позиции или разворот. Если каждый раз выбирать только сценарий с максимальной текущей оценкой, модель начнёт слишком часто перескакивать между близкими вариантами. Для трейдера это знакомая проблема: система вроде бы «видит рынок», но не даёт прибыли накопиться. Поэтому перед финальным выбором полезно проверить, насколько новый кандидат согласуется с ранее выбранным планом.
Сначала текущие траектории-кандидаты и предыдущая траектория приводятся к общей системе координат. Это необходимо, потому что автомобиль движется, и координатная система текущего момента не совпадает с координатной системой предыдущего шага. После такого преобразования модель может корректно сравнивать форму нового кандидата с ранее выбранной траекторией.
В финансах аналогичная проблема возникает из-за изменения масштаба, волатильности и рыночного режима. Нельзя просто сравнивать две ценовые линии в абсолютных значениях. Один и тот же сценарий на спокойном рынке и на рынке с повышенной волатильностью будет выглядеть по-разному. Поэтому в нашей адаптации логичнее сравнивать не сырые цены, а латентные представления, сформированные моделью. Такое пространство уже учитывает нормализацию, контекст и внутреннюю оценку состояния. Иными словами, мы сравниваем не то, где именно находится цена, а то, насколько похожа структура торговой гипотезы.
Далее для каждого кандидата рассчитывается расстояние Хаусдорфа до исторической траектории. Эта метрика сравнивает траектории как множества точек, а не как покомпонентные векторы в евклидовом расстоянии. Для каждой точки первой траектории находится ближайшая точка второй траектории. Затем берётся максимальное из таких минимальных расстояний. Аналогичная операция выполняется в обратную сторону. Итоговое расстояние Хаусдорфа определяется как максимум из двух направленных расстояний.
Формально это можно записать так:

Здесь Tkt — один из текущих кандидатов, а Tt-1 — историческая траектория. Смысл формулы прост. Мы ищем не среднее отличие двух линий, а худшее локальное расхождение между ними. Если хотя бы один участок новой траектории сильно ушёл от прежнего плана, расстояние Хаусдорфа это зафиксирует.
Для торгового сценария это особенно важно. Среднее расстояние может скрыть критическое отклонение. Например, большая часть нового сценария похожа на прежний план, но один участок резко меняет направление и фактически предполагает разворот позиции. Средняя ошибка в таком случае может выглядеть приемлемой, хотя именно этот участок несёт главный риск. Расстояние Хаусдорфа позволяет подсветить такие локальные расхождения. Оно не спрашивает, насколько сценарии похожи в среднем. Оно показывает, есть ли между ними опасный разрыв.
После расчёта расстояний модуль TTM выбирает траекторию, которая лучше всего согласуется с предыдущим планом:

Такой выбор не означает, что модель всегда обязана повторять прошлое движение. Смысл другой: среди текущих мультимодальных вариантов преимущество получает тот, который сохраняет временную согласованность. Это снижает вероятность резких скачков между соседними прогнозами и делает поведение модели устойчивее.
В торговле это можно трактовать как защиту рабочего сценария от преждевременного разрушения. Если рынок продолжает двигаться в рамках прежней гипотезы, модель не должна закрывать позицию только потому, что один из новых кандидатов получил немного более высокий локальный Score. Но если новый сценарий действительно далеко ушёл от предыдущего плана, это уже не шум, а возможный сигнал к пересмотру позиции. Таким образом, TTM становится механизмом проверки: достаточно ли новое состояние отличается от прежнего, чтобы менять торговое действие?
Однако одного TTM недостаточно. Выбранная траектория всё ещё построена на основании текущего восприятия. Если текущий кадр содержит шум, временное перекрытие объекта, ошибку детектора или неполную информацию о сцене, такой план может оказаться слишком привязанным к текущему моменту. Поэтому авторы добавляют второй ключевой модуль — Momentum Planning Interactor, или MPI.
В рыночных данных аналогичный шум возникает постоянно. Это может быть случайный всплеск волатильности, расширение спреда, новостной выброс, тонкий рынок, ложный пробой, неполная структура последнего бара или обычная микроструктурная дрожь цены. Если модель слишком доверяет текущему состоянию, она начинает переоценивать такие фрагменты и перестраивать план раньше времени. Поэтому одного сравнения текущего кандидата с прошлой траекторией мало. Нужен механизм, который подтягивает скрытый контекст предыдущих решений.
MPI работает уже не столько с геометрией траектории, сколько с Planning Query. После того как TTM выбрал наиболее согласованный кандидат, соответствующий ему Planning Query используется как запрос к историческим Planning Queries. Через Cross-Attention текущий запрос взаимодействует с представлениями прошлых планов. Иными словами, модель не просто спрашивает: какая траектория сейчас ближе к прежней? Она дополнительно проверяет, что в предыдущих планах и контексте восприятия может уточнить текущее решение.
Если перенести это на трейдинг, Planning Query можно понимать как скрытое представление текущего торгового намерения. В нём может быть зашита не только форма прогнозной траектории, но и оценка силы сценария, риск разворота, положение относительно недавнего диапазона, степень неопределённости и контекст открытой позиции. Исторические Planning Queries тогда становятся памятью прошлых торговых гипотез. Через механизм внимания текущий сценарий может сопоставляться не с одним последним решением, а с более широкой историей того, как модель пришла к текущему плану.
Внутри MPI исторические Planning Queries сначала обрабатываются с учётом их Score. Это важно: не все прошлые варианты одинаково полезны. Затем они проходят через механизм, моделирующий временную эволюцию запросов. После этого текущий выбранный Query взаимодействует с историческими представлениями через механизм внимания. На выходе получается уточнённый Planning Query, который несёт не только информацию текущего кадра, но и память предыдущего планирования.
Для финансовых временных рядов такая логика особенно важна. Не каждый прошлый прогноз заслуживает доверия. Если предыдущий сценарий имел низкую оценку, высокую неопределённость или быстро был опровергнут рынком, его влияние должно быть ограничено. Напротив, если несколько последовательных состояний подтверждали один и тот же план, модель получает больше оснований не менять решение из-за локального отката. Так исторический контекст помогает отличать устойчивую торговую идею от случайного набора краткосрочных сигналов.
Далее уточнённый Query поступает в Planning Head, который повторно генерирует траектории и их оценки. В этом месте MomAD делает важный шаг: финальный выбор строится на текущем мультимодальном Score, обогащённом историческим контекстом. Благодаря этому модель получает более широкий взгляд на ситуацию и меньше зависит от случайного шума в отдельном кадре.
В торговой системе аналогичный подход позволяет перейти от одиночного сигнала к планированию поведения позиции. Модель должна оценивать не только вопрос что открыть сейчас? Но и более важный вопрос: что делать с уже выбранным сценарием?. Удерживать позицию, частично выйти, полностью закрыться, перевернуться или остаться вне рынка — это разные управленческие решения. Их нельзя сводить к одному локальному прогнозу следующего бара.
Третьим важным элементом MomAD является Robust Instance Denoising. Поскольку исходная система работает с визуальными признаками, объектами и картой сцены, ошибки восприятия могут напрямую испортить планирование. Авторы добавляют контролируемые возмущения в признаки во время обучения и используют облегчённый блок Encoder–Decoder Transformer для восстановления устойчивого представления. В результате модель учится отличать значимую информацию от шумовых искажений. На этапе вывода это помогает ей строить более плавные и стабильные траектории даже при неполном или зашумлённом восприятии.
В трейдинге шумоподавление имеет не меньшую ценность. Рыночные данные не являются чистым отражением истинного состояния рынка. В них есть случайные тики, расширения спреда, гэпы, выбросы ликвидности, ложные импульсы и режимные переходы. Поэтому при переносе идей MomAD важно думать не только о согласовании готовых сценариев, но и об устойчивости самих латентных представлений. Если скрытое состояние модели слишком чувствительно к мелким искажениям входных данных, расстояние между сценариями будет отражать не смену рыночной гипотезы, а обычный шум.
Алгоритм MomAD состоит из последовательных шагов: (1) формирование компактного Sparse-представления; (2) генерация мультимодальных траекторий в Planning Head; (3) согласование кандидатов с предыдущим планом в TTM по расстоянию Хаусдорфа; (4) уточнение Planning Query в MPI через исторические запросы; (5) повторная генерация и финальный выбор траектории.
В финансовой интерпретации эта последовательность выглядит так. Сначала модель получает рыночные признаки и формирует латентное состояние. Затем строит несколько возможных торговых сценариев. После этого каждый текущий кандидат сравнивается с ранее выбранным планом. Сценарий, который лучше согласуется с историей и при этом сохраняет достаточную текущую оценку, получает преимущество. Далее скрытое представление этого сценария уточняется через исторический контекст. На выходе система выбирает не просто новый сигнал, а более устойчивый план управления позицией.
Для нашей задачи особенно важны три вывода. Во-первых, MomAD показывает, что устойчивость последовательных решений нельзя считать второстепенной характеристикой. Модель может быть точной на отдельных шагах, но если её прогнозы плохо согласованы во времени, такая точность не превращается в хорошее управление. Во-вторых, текущий сценарий лучше сравнивать с предыдущим планом не простым точечным расстоянием, а метрикой, способной оценить форму всей траектории. Поэтому расстояние Хаусдорфа становится центральным элементом TTM. В-третьих, устойчивость плана усиливается не только через сравнение траекторий, но и через использование исторических запросов, которые хранят скрытый контекст прошлых решений.
При переносе этих идей в трейдинг мы не будем воспроизводить MomAD буквально. У нас нет камер, дорожной карты и физических координат автомобиля. Но у нас есть другая последовательная среда, где решение также не должно дёргаться без причины. Торговая модель на каждом шаге формирует представление рынка и несколько возможных сценариев дальнейшего поведения. Если каждый новый бар заставляет её заново выбирать между Buy, Sell, Hold или Exit, система становится слишком чувствительной к шуму. Поэтому идея Momentum-Aware Planning здесь приобретает другой, но очень прикладной смысл: модель должна сравнивать текущий торговый сценарий с ранее выбранным планом и менять его только при достаточном расхождении.
Дальше мы используем эту идею не в пространстве физических координат, а в латентном пространстве модели. Вместо траекторий автомобиля будем рассматривать последовательности латентных векторов. Вместо устойчивости рулевого управления — устойчивость торгового плана. Первым практическим шагом станет реализация расстояния Хаусдорфа на стороне OpenCL, чтобы получить вычислительный блок для сравнения текущего кандидата с предыдущим сценарием.

Реализация средствами MQL5
После рассмотрения общего алгоритма MomAD перейдём к практической части. В рамках этой статьи мы не будем сразу строить полный модуль устойчивого планирования. Иначе пришлось бы одновременно решать несколько задач: генерировать сценарии, хранить исторический план, выбирать кандидата, подавлять шум и интегрировать всё это в верхний уровень модели. Начнём с базового вычислительного элемента — оценки расстояния между двумя последовательностями латентных представлений.
Такой выбор не случаен. Именно расстояние между текущим кандидатом и ранее выбранным сценарием позволяет оценить, насколько новая гипотеза отклоняется от прежнего торгового плана. Если отличие невелико, модель может сохранить прежнее решение и не разрушать позицию из-за обычного рыночного шума. Если расстояние становится значительным, появляется основание пересмотреть сценарий. Поэтому на первом этапе нам нужен быстрый и достаточно универсальный блок, который позже можно будет использовать и в механизме выбора, и при анализе устойчивости модели.
Начнём с локального расстояния между латентными состояниями. В классическом расстоянии Хаусдорфа сравниваются множества точек траектории. В нашей задаче каждая такая точка — не цена, а латентный вектор. Поэтому сначала нужно измерить расхождение между двумя векторами: точкой предыдущего плана и точкой текущего кандидата.
Для каждой пары латентных векторов рассчитываем абсолютные отклонения по всем координатам. Затем выбираем top-k крупнейших расхождений и применяем к ним Sparse-Softmax. На выходе получаем сглаженную оценку максимального отклонения. Она сохраняет контрастность, потому что основное внимание уделяется наиболее различающимся координатам. Но при этом она мягче жёсткого максимума, так как учитывает не одну координату, а несколько наиболее значимых.
__kernel void SparseSoftmaxHausdorff(__global const float *plan, __global const float *decis, __global float *output, __global float *top_index, const int dimension, const int top_k ) { const int d = get_local_id(0); const int plan_id = get_global_id(1); const int decis_id = get_global_id(2); const int total_decis = get_global_size(2); const int pair = plan_id * total_decis + decis_id; //--- __local float values[LOCAL_ARRAY_SIZE]; __local float top_values[LOCAL_ARRAY_SIZE]; __local int top_indices[LOCAL_ARRAY_SIZE];
На вход OpenCL-ядро получает два буфера: plan и decis. В буфере plan хранится набор латентных состояний кандидатов текущего плана. В буфере decis находится история ранее принятых решений. В рамках одной рабочей группы ядро рассматривает пару векторов: один из plan, второй из decis. Идентификатор plan_id выбирает кандидата, decis_id — состояние из истории решений. Пара этих индексов формирует позицию pair в выходной матрице расстояний.
Локальный индекс d отвечает за координату латентного пространства. Каждый рабочий элемент внутри локальной группы рассчитывает абсолютное отклонение по своей координате. Полученное значение записывается в локальный массив values. После барьера все координатные отклонения доступны внутри рабочей группы.
float value = 0.0f; if(d < dimension) { const float diff = plan[plan_id * dimension + d] - decis[decis_id * dimension + d]; value = IsNaNOrInf(fabs(diff), 0.0f); } values[d] = value; BarrierLoc;
Дальнейший выбор top-k выполняется уже в локальном массиве. Это дешевле и хорошо подходит для латентных векторов умеренной размерности. Нулевой локальный поток последовательно выбирает top-k крупнейших отклонений. Он проходит по всем координатам, пропускает уже выбранные индексы и каждый раз находит следующую максимальную компоненту. При равенстве значений выбирается меньший индекс координаты. Благодаря этому результат остаётся детерминированным: одинаковые значения не приводят к случайному выбору разных координат при разных запусках.
if(d == 0) { const int actual_top = min(top_k, dimension); for(int k = 0; k < actual_top; k++) { float best = MIN_VALUE; int best_id = -1; for(int i = 0; i < dimension; i++) { int used = false; for(int p = 0; p < k; p++) { if(top_indices[p] == i) { used = true; break; } } if(used) continue; const float candidate = values[i]; if(candidate > best || (candidate == best && (best_id < 0 || i < best_id))) { best = candidate; best_id = i; } } top_values[k] = IsNaNOrInf(best, 0.0f); top_indices[k] = best_id; }
После выбора крупнейших координат применяется Sparse-Softmax.
//--- sparse softmax on selected dimensions float max_value = top_values[0]; for(int k = 1; k < actual_top; k++) max_value = fmax(max_value, top_values[k]); float sum_exp = 0.0f; float result = 0.0f; for(int k = 0; k < actual_top; k++) { const float weight = IsNaNOrInf(exp(top_values[k] - max_value), 0.0f); sum_exp += weight; result += weight * top_values[k]; } result = (sum_exp > 0.0f ? result / sum_exp : 0.0f); output[pair] = IsNaNOrInf(result, 0.0f); for(int k = 0; k < actual_top; k++) top_index[pair * top_k + k] = (float)top_indices[k]; } }
Сначала определяется максимальное значение среди выбранных компонент. Затем для каждой координаты рассчитывается экспоненциальный вес, а выходное значение формируется как взвешенное среднее выбранных отклонений. Вычитание максимума используется для численной устойчивости.
По смыслу это мягкий аналог максимума по наиболее значимым координатам. Если одна координата резко доминирует, результат будет близок к её значению. Если несколько координат имеют сопоставимые отклонения, они вместе повлияют на итоговую оценку. В финансовом контексте это полезно: смена сценария редко выражается в одном единственном признаке. Чаще одновременно меняется несколько компонент: направление, волатильность, плотность состояния, риск отката или вероятность продолжения движения.
Выходной буфер output содержит матрицу попарных расстояний между точками предыдущего плана и точками текущего кандидата. Отдельно сохраняется буфер top_index. В него записываются индексы координат, попавших в top-k для каждой пары векторов. Этот буфер нужен не для прямого прохода, а для обратного. Поскольку прямой проход использует только выбранные координаты, градиент также должен передаваться только через них. Сохранив индексы, мы избегаем повторного поиска top-k при распространении ошибки и обеспечиваем согласованность прямого и обратного проходов.
Далее рассмотрим ядро обратного прохода.
__kernel void SparseSoftmaxHausdorffGrad(__global const float *plan, __global float *grad_plan, __global const float *decis, __global float *grad_decis, __global const float *grad_out, __global const float *top_index, const int dimension, const int count_plan, const int count_decis, const int top_k ) { const int d = get_global_id(0); const int id = get_global_id(1); const int side = get_global_id(2); //--- if(d >= dimension) return;
Обратный проход получает исходные буферы plan и decis, градиент выходной матрицы grad_out, сохранённые индексы top_index и записывает результат в буферы grad_plan и grad_decis. В отличие от прямого прохода, здесь используется трёхмерное глобальное пространство задач без организации локальных групп. Первое измерение отвечает за координату латентного вектора, второе — за индекс вектора, третье — за сторону распространения градиента.
При side = 0 рассчитывается градиент по буферу plan. Для выбранной точки плана ядро проходит по всем историческим состояниям, потому что одна и та же точка участвует в нескольких попарных сравнениях. При side = 1 аналогично рассчитывается градиент по буферу decis: выбранное историческое состояние сопоставляется со всеми точками текущего плана.
Внутри каждого попарного сравнения ядро повторно восстанавливает значения по сохранённым top-k координатам. Для них снова вычисляются абсолютные отклонения, максимальное значение, сумма экспонент и выходное значение out_value. Это нужно для корректного расчёта производной Sparse-Softmax-агрегации.
float result = 0.0f; if(side == 0) { if(id >= count_plan) return; for(int decis_id = 0; decis_id < count_decis; decis_id++) { const int pair = id * count_decis + decis_id; const int shift = pair * top_k; float max_value = MIN_VALUE; for(int k = 0; k < top_k; k++) { const int top_d = (int)(top_index[shift + k] + 0.001f); const float diff = plan[id * dimension + top_d] - decis[decis_id * dimension + top_d]; const float value = IsNaNOrInf(fabs(diff), 0.0f); max_value = fmax(max_value, value); } float sum_exp = 0.0f; float out_value = 0.0f; for(int k = 0; k < top_k; k++) { const int top_d = (int)(top_index[shift + k] + 0.001f); const float diff = plan[id * dimension + top_d] - decis[decis_id * dimension + top_d]; const float value = IsNaNOrInf(fabs(diff), 0.0f); const float exp_value = IsNaNOrInf(exp(value - max_value), 0.0f); sum_exp += exp_value; out_value += exp_value * value; } if(sum_exp <= 0.0f) continue; out_value /= sum_exp; const float grad = grad_out[pair];
Прямой проход фактически считает взвешенную сумму этих отклонений. Производная такой суммы по выбранной компоненте содержит множитель weight · (1.0f + value − out_value). Далее учитывается знак разности между plan и decis. По plan градиент добавляется с плюсом, по decis — с противоположным знаком.
for(int k = 0; k < top_k; k++) { const int top_d = (int)(top_index[shift + k] + 0.001f); if(top_d != d) continue; const float diff = plan[id * dimension + d] - decis[decis_id * dimension + d]; const float value = IsNaNOrInf(fabs(diff), 0.0f); const float weight = IsNaNOrInf(exp(value - max_value) / sum_exp, 0.0f); const float sgn = (diff > 0.0f ? 1.0f : (diff < 0.0f ? -1.0f : 0.0f)); result += grad * weight * (1.0f + value - out_value) * sgn; } } grad_plan[id * dimension + d] = IsNaNOrInf(result, 0.0f); }
Такой обратный проход решает две задачи. Во-первых, он сохраняет контрастность: градиент передаётся только через координаты, где расхождение между сценариями оказалось наиболее значимым. Во-вторых, он остаётся мягче жёсткого максимума: внутри выбранного top-k несколько координат получают разные веса, а не обнуляются полностью. Для торговой модели это важно. Мы хотим, чтобы обучение усиливало различимость сценариев, но не превращалось в рваную реакцию на одну случайную координату латентного пространства.
С практической точки зрения этот блок можно рассматривать как дифференцируемую основу будущего расстояния Хаусдорфа в латентном пространстве. Сейчас он формирует матрицу попарных расстояний между точками двух сценариев. Уже на этом уровне мы получаем главное: способ оценить, какие латентные состояния действительно расходятся и какие координаты отвечают за этот разрыв.
Именно поэтому реализация сохраняет не только итоговое значение, но и индексы выбранных координат. Для анализа торговой системы это полезно само по себе. Если модель резко меняет план, мы можем посмотреть, какие компоненты латентного пространства внесли основной вклад в расхождение. В дальнейшем это поможет диагностировать, что именно стало причиной пересмотра сценария: изменение направления, рост волатильности, ослабление тренда, локальный выброс или повышение неопределённости.
Предложенные ядра пока не выполняют финальный выбор торгового сценария. Они решают первую и наиболее важную вычислительную задачу: измеряют сглаженное максимальное расхождение между латентными состояниями, сохраняют активные координаты и обеспечивают обратный проход для обучения.
Заключение
В этой статье мы формализовали проблему, хорошо знакомую при построении нейросетевых торговых систем: модель может неплохо оценивать отдельные рыночные состояния, но слишком часто менять решение. Такая нестабильность не даёт прибыльному сценарию раскрыться, провоцирует преждевременные выходы, повторные входы по худшей цене и контртрендовые сделки на обычных рыночных откатах. В результате часть потенциальной прибыли теряется из-за слабой преемственности торгового плана.
В качестве возможного направления решения мы рассмотрели идеи фреймворка MomAD, предложенного авторами для задач автономного вождения. Нас интересовала не прямая копия автомобильной архитектуры, а сам принцип: текущее решение должно учитывать ранее выбранный план и не разрушать его без достаточных оснований. Мы разобрали теоретическую основу подхода, обсудили роль Momentum-Aware Planning, Topological Trajectory Matching, расстояния Хаусдорфа и перенесли эту логику в финансовый контекст. Вместо физических траекторий автомобиля предложено сравнивать латентные представления торговых сценариев, поскольку именно они лучше отражают внутреннюю структуру рыночной гипотезы.
Практическая часть стала первым шагом к реализации такого механизма средствами MQL5 и OpenCL. Мы построили базовый вычислительный блок, который оценивает расхождение между латентными состояниями через Sparse-Softmax, сохраняет наиболее значимые координаты и поддерживает обратный проход для обучения. Это ещё не полный механизм выбора торгового плана, но уже его важная основа. В следующей статье мы продолжим адаптацию MomAD к финансовым задачам.
Ссылки
Программы, используемые в статье
| # | Имя | Тип | Описание |
|---|---|---|---|
| 1 | Study.mq5 | Советник | Советник офлайн-обучения моделей |
| 2 | StudyOnline.mq5 | Советник | Советник онлайн-обучения моделей |
| 3 | Test.mq5 | Советник | Советник для тестирования модели |
| 4 | Trajectory.mqh | Библиотека класса | Структура описания состояния системы и архитектуры моделей |
| 5 | NeuroNet.mqh | Библиотека класса | Библиотека классов для создания нейронной сети |
| 6 | NeuroNet.cl | Библиотека | Библиотека кода OpenCL-программы |
Проект представлен на forge.mql5.io/dng.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Торговые инструменты MQL5 (Часть 24): Улучшение восприятия глубины с помощью 3D-кривых, режима панорамирования и навигации через виджет ViewCube
Инжиниринг признаков для машинного обучения (Часть 2): Реализация дробного дифференцирования с фиксированным окном в MQL5
Архитектура машинного обучения для MetaTrader 5 (Часть 15): Как калибровать уровни тейк-профита и стоп-лосса по синтетическим данным
Моделирование рынка: Первые шаги на SQL в MQL5 (V)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования