preview
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (MDC-модуль)

Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (MDC-модуль)

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

Введение

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

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

Архитектура фреймворка выстроена вокруг нескольких ключевых компонентов, которые работают последовательно. На вход модель получает последовательность событий — упорядоченные фрагменты рыночной активности, отражающие локальную динамику. На первом этапе данные проходят через Adaptive Density Module (ADM), который регулирует плотность событий в зависимости от местных условий. В рыночных данных плотность событий часто меняется: во время спокойных периодов их может быть мало, а в моменты резких движений — много. ADM корректирует эти различия, обеспечивая модель правильным входом независимо от того, насколько плотными или разреженными являются данные.

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

Адаптированные эмбеддинги подаются в Multi-Scale Feature Correlation (MSFC). Этот модуль отвечает за сопоставление признаков на разных пространственных масштабах и временных горизонтах, формируя устойчивые корреляции между локальными и глобальными паттернами движения. MSFC позволяет модели учитывать, как мелкие локальные изменения взаимодействуют с крупными движениями, что особенно важно для динамических, непостоянных потоков событий.

Далее, на основе скоррелированных признаков, осуществляется Meshflow Estimation. Здесь формируется направленное поле движения (MeshFlow), отражающее крупномасштабное смещение и глобальные закономерности движения. MeshFlow служит основой для последующих прогнозов, превращая поток разрозненных событий в структурированное представление движения, пригодное для анализа и принятия торговых решений.

Завершается процесс блоком Confidence‑induced Detail Completion (CDC), который восстанавливает локальные детали движения, сохраняя чёткие границы и обеспечивая точность в микроскопических изменениях.

Особенно важной частью архитектуры является Adaptive Density Module (ADM). В реальных рыночных данных события не всегда поступают равномерно — периоды высокой активности сменяются фазами затишья. В то время как в высокочастотных данных события часто идут с высокой плотностью, в моменты низкой активности данные становятся разреженными. Это создаёт сложности для любых моделей, работающих с такими потоками, ведь без должной адаптации они либо теряют важные моменты, либо начинают реагировать на случайный шум.

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

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

В практической части предыдущей статьи мы начали работу по построению отдельных компонентов ADM. И сегодня продолжаем начатую работу. 


Модуль согласования признаков

Adaptive Density Module (ADM) решает задачу адаптации плотности событийного потока под изменчивые условия данных. ADM состоит из двух субмодулей:

  • Multi-Density Changer (MDC),
  • Multi-Density Selector (MDS).

MDC отвечает за глобальную корректировку плотности анализируемых представлений событий на нескольких масштабах, а MDS выбирает оптимальную пиксельную плотность для последующего расчёта оптического потока.

MDC использует Encoder‑Decoder архитектуру с тремя уровнями. На вход подаются объединённые представления событий, которые затем проходят через три блока кодирования для извлечения признаков на разных масштабах. После этого три блока декодирования восстанавливают информацию, а два блока слияния признаков обеспечивают интеграцию многомасштабной информации. В итоге MDC формирует набор многомасштабных представлений.

Модуль согласования признаков (Feature Alignment ModuleFAM) встроен в MDC и отвечает за согласование признаков с разных масштабов. Он обеспечивает, чтобы локальные микроимпульсы и крупные тенденции движения корректно интегрировались в многомасштабные представления, формируя устойчивую основу для последующих блоков.

В нашей реализации новый класс CNeuronSpikeFAM реализует спайковую версию Feature Alignment Module (FAM) и играет ключевую роль в подготовке данных для последующих блоков анализа движения. Его основная задача — выравнивать и согласовывать признаки, полученные с разных масштабов, формируя цельное и структурированное представление информации о движении событий. Спайковая природа модуля позволяет модели работать с потоками событий так же, как нейроны в мозге реагируют на последовательность импульсов, фиксируя резкие изменения и мгновенные всплески активности. На практике это означает, что модель одновременно учитывает микроизменения и крупные тренды, что критично для финансового рынка. Ведь каждое колебание объёма или резкий скачок цены могут иметь значение для прогнозирования.

Для реализации этой функциональности объект объединяет несколько компонентов. Базовый блок cProduct используется для первичной обработки анализируемых признаки и подготавливает их для последующей трансформации. Нелинейную активацию обеспечивает cActivation, позволяя модулю гибко реагировать на импульсы событий. Основной центр работы FAM лежит в многомасштабном сверточном блоке cConv, который извлекает признаки на разных масштабах и согласует их в единую структуру, создавая спайковую репрезентацию. Именно здесь формируется согласованная картина движения. Локальные микроимпульсы и глобальные тенденции объединяются в цельное представление, что даёт точность при построении MeshFlow.

За первичную инициализацию внутренних компонентов модуля отвечает метод Init. Именно он подготавливает все элементы FAM к работе с потоками событий и формирует основу для корректного выравнивания признаков.

bool CNeuronSpikeFAM::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                           uint window, uint units_count, uint variables,
                           ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronBatchNormOCL::Init(numOutputs, myIndex, open_cl, window * units_count * variables,
                                                                            batch, optimization_type))
      return false;
   activation = None;

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

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

   if(!cProduct.Init(0, 0, OpenCL, Neurons(), optimization, iBatch))
      return false;
   cProduct.SetActivationFunction(None);

Затем инициализируется блок активации cActivation, который обеспечит спайковую трансформацию признаков, реагируя на мгновенные импульсы событийного потока.

   if(!cActivation.Init(0, 1, OpenCL, Neurons(), optimization, iBatch))
      return false;

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

   uint windows[] = {3 * window};
   if(!cConv.Init(0, 2, OpenCL, windows, window, window, units_count, variables, optimization, iBatch))
      return false;
   cConv.SetActivationFunction(None);
//---
   return true;
  }

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

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

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

bool CNeuronSpikeFAM::feedForward(CNeuronBaseOCL *NeuronOCL, CBufferFloat *SecondInput)
  {
   if(!NeuronOCL || !SecondInput)
      return false;

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

Затем выполняется поэлементное умножение двух потоков признаков — основного и дополнительного. Это позволяет модели одновременно учитывать разные источники информации и корректно сопоставлять локальные импульсы и глобальные тенденции.

   if(!ElementMult(NeuronOCL.getOutput(), SecondInput, cProduct.getOutput()))
      return false;

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

   if(!cActivation.FeedForward(cProduct.AsObject()))
      return false;

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

   if(!cConv.FeedForward(cActivation.AsObject()))
      return false;

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

   if(!CNeuronBatchNormOCL::feedForward(cConv.AsObject()))
      return false;

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

   if(!SumAndNormilize(NeuronOCL.getOutput(), Output, Output, GetWindow(), true, 0, 0, 0, 1))
      return false;
//---
   return true;
  }

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

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


Модуль Multi-Density Changer

После того как построение спайкового FAM завершено, и получено согласованное многомасштабное представление признаков, мы поднимаемся на уровень выше в иерархии ADM и переходим к построению Multi-Density Changer (MDC). Если FAM заботился о точности и согласованности локальных и глобальных признаков, то MDC отвечает за глобальную адаптацию плотности событий. Этот модуль корректирует анализируемые представления на нескольких масштабах, подстраивая их под изменчивую активность рынка.

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

Архитектура MDC построена по принципу Encoder‑Decoder с тремя уровнями, где три блока кодирования извлекают признаки разных масштабов, а три блока декодирования вместе с блоками слияния признаков формируют многомасштабное, согласованное представление. Все операции выполняются эффективно, с минимальной нагрузкой на вычислительные ресурсы, что позволяет обрабатывать потоки событий в реальном времени.

Для построения функционала Multi-Density Changer (MDC) в рамках данного проекта мы создаём новый класс CNeuronSpikeMDC. Этот объект поднимает обработку данных на следующий уровень после спайкового FAM, чтобы модель могла эффективно реагировать на динамику рынка.

class CNeuronSpikeMDC   :  public CNeuronBatchNormOCL
  {
protected:
   CLayer            cSCMs;
   CLayer            cFAMs;
   CLayer            cAFFs;
   CLayer            cProjects;
   CLayer            cProjectsOut;
   CLayer            cFeatExtracts;
   CNeuronBaseOCL    cConcatOut;
      //---
   virtual bool      feedForward(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      updateInputWeights(CNeuronBaseOCL *NeuronOCL) override;
   virtual bool      calcInputGradients(CNeuronBaseOCL *NeuronOCL) override;

public:
                     CNeuronSpikeMDC(void) {};
                    ~CNeuronSpikeMDC(void) {};
   //---
   virtual bool      Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                          uint window, uint window_out,
                          uint units_count, uint variables,
                          ENUM_OPTIMIZATION optimization_type, uint batch);
   //---
   virtual int       Type(void) override const  {  return defNeuronSpikeMDC;   }
   //--- methods for working with files
   virtual bool      Save(int const file_handle) override;
   virtual bool      Load(int const file_handle) override;
   //---
   virtual void      SetOpenCL(COpenCLMy *obj)   override;
   //---
   virtual bool      WeightsUpdate(CNeuronBaseOCL *source, float tau) override;
   //---
   virtual void      SetActivationFunction(ENUM_ACTIVATION value) override { };
   virtual void      TrainMode(bool flag) override;
   virtual bool      Clear(void) override;
  };

Внутри класса реализована последовательность слоёв и компонентов, которые совместно обеспечивают работу модуля.

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

Массив cFAMs отвечает за интеграцию Feature Alignment Module (FAM), спайковой версии модуля выравнивания признаков. Его задача — обеспечить согласование признаков, полученных с разных масштабов, создавая структурированное, многомасштабное представление. Это позволяет создавать адаптированное к плотности событий представление, где каждая деталь имеет своё значение и вносит вклад в точность прогнозирования движения цены.

Модули cAFFs отвечают за адаптивное объединение признаков, аккуратно связывая данные с разных масштабов и создавая согласованное представление. Благодаря этому, модель видит целостную картину рынка: локальные импульсы и глобальные тенденции интегрируются, не теряя своей значимости.

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

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

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

bool CNeuronSpikeMDC::Init(uint numOutputs, uint myIndex, COpenCLMy *open_cl,
                           uint window, uint window_out,
                           uint units_count, uint variables,
                           ENUM_OPTIMIZATION optimization_type, uint batch)
  {
   if(!CNeuronBatchNormOCL::Init(numOutputs, myIndex, open_cl, 3 * window_out * units_count * variables,
                                 batch, optimization_type))
      return false;

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

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

   cSCMs.Clear();
   cFAMs.Clear();
   cAFFs.Clear();
   cProjects.Clear();
   cProjectsOut.Clear();
   cFeatExtracts.Clear();
   cSCMs.SetOpenCL(OpenCL);
   cFAMs.SetOpenCL(OpenCL);
   cAFFs.SetOpenCL(OpenCL);
   cProjects.SetOpenCL(OpenCL);
   cProjectsOut.SetOpenCL(OpenCL);
   cFeatExtracts.SetOpenCL(OpenCL);

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

   CNeuronSpikeConvBlock*           conv = NULL;
   CNeuronMultiWindowsConvWPadOCL*  pad_conv = NULL;
   CNeuronSpikeSCM*                 scm = NULL;
   CNeuronSpikeFAM*                 fam = NULL;
   CNeuronBaseOCL*                  neuron = NULL;
   uint index = 0;
   uint windows[1];
//---
   if(!cConcatOut.Init(numOutputs, myIndex, open_cl, Neurons(), optimization, iBatch))
      return false;
//---
   index++;
   windows[0] = 3 * window;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, window, window_out, units_count, variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(SoftPlus);

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

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

   index++;
   windows[0] = 3 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 2 * window_out, 2 * window_out,
                     (units_count + 1) / 2, variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(SoftPlus);
   uint u = pad_conv.GetUnits();
   index++;
   windows[0] = 6 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 4 * window_out, 4 * window_out,
                               (u + 1) / 2, variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(SoftPlus);

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

   u = pad_conv.GetUnits();
   index++;
   windows[0] = 16 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 8 * window_out, 16 * window_out,
                                          u, variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(SoftPlus);
   u *= 2;
   index++;
   windows[0] = 8 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 4 * window_out, 8 * window_out, u,
                                               variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(SoftPlus);
   u *= 2;
   index++;
   windows[0] = 3 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, window_out, window_out, units_count,
                                                 variables, optimization, iBatch) ||
      !cFeatExtracts.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(None);

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

Блоки проекции данных cProjects и cProjectsOut подготавливают признаки, упорядочивая и приводя их к единому формату для последующего объединения. Затем блок Adaptive Feature Fusion (cAFFs) аккуратно сливает эти данные, обеспечивая гармоничный баланс между различными масштабами и источниками информации. Благодаря этому модель одновременно учитывает локальные микро-импульсы и глобальные тенденции, формируя целостное и адаптированное представление рынка.

   index++;
   neuron = new CNeuronBaseOCL();
   if(!neuron ||
      !neuron.Init(0, index, OpenCL, 4 * window_out * units_count * variables,
                                                      optimization, iBatch) ||
      !cProjects.Add(neuron))
     {
      DeleteObj(neuron)
      return false;
     }
   neuron.SetActivationFunction(None);
   index++;
   conv = new CNeuronSpikeConvBlock();
   if(!conv ||
      !conv.Init(0, index, OpenCL, 4 * window_out, 4 * window_out, 2 * window_out,
                                  units_count, variables, optimization, iBatch) ||
      !cProjects.Add(conv))
     {
      DeleteObj(conv)
      return false;
     }
   index++;
   neuron = new CNeuronBaseOCL();
   if(!neuron ||
      !neuron.Init(0, index, OpenCL, 2 * window_out * units_count * variables,
                                                      optimization, iBatch) ||
      !cProjects.Add(neuron))
     {
      DeleteObj(neuron)
      return false;
     }
   neuron.SetActivationFunction(None);
   index++;
   conv = new CNeuronSpikeConvBlock();
   if(!conv ||
      !conv.Init(0, index, OpenCL, 2 * window_out, 2 * window_out, window_out,
                               units_count, variables, optimization, iBatch) ||
      !cProjects.Add(conv))
     {
      DeleteObj(conv)
      return false;
     }

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

   index++;
   windows[0] = 12 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 4 * window_out, window_out,
                           units_count, variables, optimization, iBatch) ||
      !cProjectsOut.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(None);
   index++;
   windows[0] = 6 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 2 * window_out, window_out,
                           units_count, variables, optimization, iBatch) ||
      !cProjectsOut.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(None);
//---
   index++;
   neuron = new CNeuronBaseOCL();
   if(!neuron ||
      !neuron.Init(0, index, OpenCL, 7 * window_out * units_count * variables,
                                                      optimization, iBatch) ||
      !cAFFs.Add(neuron))
     {
      DeleteObj(neuron)
      return false;
     }
   neuron.SetActivationFunction(None);
   index++;
   conv = new CNeuronSpikeConvBlock();
   if(!conv ||
      !conv.Init(0, index, OpenCL, 7 * window_out, 7 * window_out, window_out,
                              units_count, variables, optimization, iBatch) ||
      !cAFFs.Add(conv))
     {
      DeleteObj(conv)
      return false;
     }
   index++;
   windows[0] = 3 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, window_out, window_out, units_count,
                                                 variables, optimization, iBatch) ||
      !cAFFs.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(None);
   index++;
   conv = new CNeuronSpikeConvBlock();
   if(!conv ||
      !conv.Init(0, index, OpenCL, 14 * window_out, 14 * window_out, 2 * window_out,
                          (units_count + 1) / 2, variables, optimization, iBatch) ||
      !cAFFs.Add(conv))
     {
      DeleteObj(conv)
      return false;
     }
   index++;
   windows[0] = 6 * window_out;
   pad_conv = new CNeuronMultiWindowsConvWPadOCL();
   if(!pad_conv ||
      !pad_conv.Init(0, index, OpenCL, windows, 2 * window_out, 2 * window_out,
                         (units_count + 1) / 2, variables, optimization, iBatch) ||
      !cAFFs.Add(pad_conv))
     {
      DeleteObj(pad_conv)
      return false;
     }
   pad_conv.SetActivationFunction(None);



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

   index++;
   fam = new CNeuronSpikeFAM();
   if(!fam ||
      !fam.Init(0, index, OpenCL, 4 * window_out, units_count, variables, optimization, iBatch) ||
      !cFAMs.Add(fam))
     {
      DeleteObj(fam)
      return false;
     }
   index++;
   fam = new CNeuronSpikeFAM();
   if(!fam ||
      !fam.Init(0, index, OpenCL, 2 * window_out, units_count, variables, optimization, iBatch) ||
      !cFAMs.Add(fam))
     {
      DeleteObj(fam)
      return false;
     }



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

   index++;
   scm = new CNeuronSpikeSCM();
   if(!scm ||
      !scm.Init(0, index, OpenCL, 2 * window, 2 * window_out, (units_count + 1) / 2,
                                                 variables, optimization, iBatch) ||
      !cSCMs.Add(scm))
     {
      DeleteObj(scm)
      return false;
     }
   u = scm.GetUnits();
   index++;
   scm = new CNeuronSpikeSCM();
   if(!scm ||
      !scm.Init(0, index, OpenCL, 4 * window, 4 * window_out, (u + 1) / 2, variables,
                                                             optimization, iBatch) ||
      !cSCMs.Add(scm))
     {
      DeleteObj(scm)
      return false;
     }
//---
   return true;
  }

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

В результате метод инициализации формирует полностью подготовленный Multi-Density Changer, где все компоненты настроены, взаимосвязаны и готовы к прямому проходу данных.

Метод feedForward реализует основной путь обработки данных в модуле Multi-Density Changer. Его задача — последовательно преобразовать анализируемый поток событий в структурированное многомасштабное представление. Каждая операция здесь имеет чёткую функциональную роль, обеспечивая баланс между локальными микроимпульсами и глобальными трендами.

bool CNeuronSpikeMDC::feedForward(CNeuronBaseOCL *NeuronOCL)
  {
   CNeuronBaseOCL* prev = NeuronOCL;
   CNeuronBaseOCL* curr = NULL;
   for(int i = 0; i < cSCMs.Total(); i++)
     {
      curr = cSCMs[i];
      if(!curr ||
         !curr.FeedForward(prev))
         return false;
      prev = curr;
     }

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

Следующим шагом данные поступают в первый блок извлечения признаков cFeatExtracts. Здесь происходит расширение пространства признаков и параллельное уменьшение длины последовательности.

   if(!cFeatExtracts[0] ||
      !cFeatExtracts[0].FeedForward(NeuronOCL))
      return false;
   if(!cFeatExtracts[1] ||
      !cFeatExtracts[1].FeedForward(cFeatExtracts[0]))
      return false;

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

После первичного извлечения признаков данные проходят через Feature Alignment Module (FAM). Спайковый FAM выравнивает признаки разных масштабов, объединяя локальные импульсы и глобальные тренды.

   if(!cFAMs[1] ||
      !cFAMs[1].FeedForward(cFeatExtracts[1], cSCMs[0].getOutput()))
      return false;

Каждый FAM-блок получает два потока: извлечения признаков и масштабированные каналы SCM. Это позволяет синхронизировать локальные события с общей структурой рынка, чтобы ни один критический сигнал не был потерян.

   if(!cFeatExtracts[2] ||
      !cFeatExtracts[2].FeedForward(cFAMs[1]))
      return false;
   if(!cFAMs[0] ||
      !cFAMs[0].FeedForward(cFeatExtracts[2], cSCMs[1].getOutput()))
      return false;



Далее данные поступают в блок Adaptive Feature Fusion (AFF), где признаки с разных уровней аккуратно объединяются. Здесь происходит несколько важных операций одновременно: информация с разных масштабов адаптивно суммируется, значимые сигналы усиливаются, а шумовые и второстепенные колебания подавляются. Для трейдера это означает, что модель формирует чёткую и согласованную картину рынка, где локальные микроимпульсы, резкие изменения объёма и глобальные тенденции интегрируются в единое представление.

//--- AAFF
   CNeuronSpikeConvBlock* conv = cAFFs[1];
   if(!conv)
      return false;
   uint units = conv.GetUnits() * conv.GetVariables();
   uint window1 = cFeatExtracts[0].Neurons() / units;
   uint window2 = cFAMs[1].Neurons() / units;
   uint window3 = cFAMs[0].Neurons() / units;
   prev = cAFFs[0];
   if(!prev ||
      !Concat(cFeatExtracts[0].getOutput(), cFAMs[1].getOutput(), cFAMs[0].getOutput(),
              prev.getOutput(), window1, window2, window3, units))
      return false;
   for(int i = 1; i < cAFFs.Total(); i += 2)
     {
      conv = cAFFs[i];
      curr = cAFFs[i + 1];
      if(!conv ||
         !conv.FeedForward(prev))
         return false;
      if(!curr ||
         !curr.FeedForward(conv))
         return false;
     }



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

//---
   prev = cProjectsOut[0];
   curr = cFeatExtracts[3];
   if(!prev ||
      !prev.FeedForward(cFAMs[0]))
      return false;
   if(!curr ||
      !curr.FeedForward(cFAMs[0]))
      return false;
//---
   window1 = curr.Neurons() / units;
   window2 = cAFFs[4].Neurons() / units;
   prev = cProjects[0];
   if(!prev ||
      !Concat(curr.getOutput(), cAFFs[4].getOutput(), prev.getOutput(),
              window1, window2, units))
      return false;
   if(!cProjects[1] ||
      !cProjects[1].FeedForward(prev))
      return false;
   if(!cProjectsOut[1] ||
      !cProjectsOut[1].FeedForward(cProjects[1]))
      return false;

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

   if(!cFeatExtracts[4] ||
      !cFeatExtracts[4].FeedForward(cProjects[1]))
      return false;
//---
   window1 = cFeatExtracts[4].Neurons() / units;
   window2 = cAFFs[2].Neurons() / units;
   prev = cProjects[2];
   if(!prev ||
      !Concat(cFeatExtracts[4].getOutput(), cAFFs[2].getOutput(), prev.getOutput(),
              window1, window2, units))
      return false;
   if(!cProjects[3] ||
      !cProjects[3].FeedForward(prev))
      return false;
   if(!cFeatExtracts[5] ||
      !cFeatExtracts[5].FeedForward(cProjects[3]))
      return false;



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

   window1 = cProjectsOut[0].Neurons() / units;
   window2 = cProjectsOut[1].Neurons() / units;
   window3 = cFeatExtracts[5].Neurons() / units;
//---
   if(!Concat(cProjectsOut[0].getOutput(), cProjectsOut[1].getOutput(), cFeatExtracts[5].getOutput(),
              cConcatOut.getOutput(), window1, window2, window3, units))
      return false;
   window1 = NeuronOCL.Neurons() / units;
   if(!SumVecMatrix(NeuronOCL.getOutput(), cConcatOut.getOutput(), cConcatOut.getOutput(),
                    window1, units, 0, 0, 0, 1))
      return false;
   if(!CNeuronBatchNormOCL::feedForward(cConcatOut.AsObject()))
      return false;
//---
   return true;
  }



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

Благодаря последовательной работе блоков SCM, FAM, FeatExtracts, AFF и проекционных слоев, система не просто фиксирует события, а создает целостную картину рынка, где видны краткосрочные всплески активности и долгосрочные тенденции. Такой подход повышает точность прогнозов, снижает риск ложных сигналов и позволяет стратегии оперативно реагировать на любые изменения рынка. В итоге MDC становится инструментом, который помогает трейдеру видеть рынок комплексно, оценивать актуальные сигналы и принимать более уверенные и информированные торговые решения.

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


Заключение

В рамках статьи мы подробно рассмотрели реализацию ключевых компонентов фреймворка EEMFlow средствами MQL5, показав, как его архитектура позволяет эффективно обрабатывать поток рыночных событий. Каждый элемент — от масштабирования каналов в SCM и локального выравнивания признаков в FAM, до адаптивного объединения в AFF и финальной агрегации в проекционных слоях — вносит свой вклад в создание структурированного и многомасштабного представления рынка.

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

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


Ссылки


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

# Имя Тип Описание
1 Study.mq5 Советник Советник офлайн обучения моделей
2 StudyOnline.mq5 Советник Советник онлайн обучения моделей
3 Test.mq5 Советник Советник для тестирования модели
4 Trajectory.mqh Библиотека класса Структура описания состояния системы и архитектуры моделей
5 NeuroNet.mqh Библиотека класса Библиотека классов для создания нейронной сети
6 NeuroNet.cl Библиотека Библиотека кода OpenCL-программы
Прикрепленные файлы |
MQL5.zip (3428.7 KB)
Торговый инструментарий MQL5 (Часть 8): Внедрение и использование EX5-библиотеки для управления историей в коде Торговый инструментарий MQL5 (Часть 8): Внедрение и использование EX5-библиотеки для управления историей в коде
В заключительной статье этой серии вы узнаете, как легко импортировать и применять EX5-библиотеку для управления историей (History Manager) в исходном коде MQL5 для обработки истории сделок в вашем аккаунте MetaTrader 5. С помощью простых вызовов функций в MQL5, занимающих всего одну строку кода, вы сможете эффективно управлять своими торговыми данными и анализировать их. Кроме того, вы научитесь создавать различные скрипты для анализа истории сделок и разрабатывать советник на основе ценовых показателей в качестве практических примеров использования. Используемый в качестве примера советник применяет данные о ценах и библиотеку History Manager EX5 для принятия обоснованных торговых решений, корректировки объемов сделок и реализации стратегий восстановления на основе ранее закрытых сделок.
Объединяем LLM, CatBoost и квантовые вычисления в единую торговую систему Объединяем LLM, CatBoost и квантовые вычисления в единую торговую систему
В статье предлагается синтез новых технологий для преодоления ограничений классических индикаторов в аналитике рыночных данных. Показано, как языковые модели и квантовое кодирование могут выявлять скрытые рыночные паттерны, которые традиционные методики упускают. Эксперимент подтверждает ценность новых технологий и предлагает обновлённую методологию анализа, соответствующую современному уровню вычислительных инноваций.
Выборочные методы марковских цепей Монте-Карло. Алгоритм HMC Выборочные методы марковских цепей Монте-Карло. Алгоритм HMC
В статье исследуется гамильтонов алгоритм Монте-Карло (HMC) — золотой стандарт сэмплирования из сложных многомерных распределений. Представлена полноценная реализация HMC на языке MQL5, которая включает адаптивную настройку матрицы масс, поиск моды апостериорного распределения (MAP) с помощью метода оптимизации L-BFGS и комплексной диагностикой.
Реализация механизма безубыточности в MQL5 (Часть 1): Базовый класс и режим безубытка по фиксированным пунктам Реализация механизма безубыточности в MQL5 (Часть 1): Базовый класс и режим безубытка по фиксированным пунктам
В данной статье рассматривается применение механизма безубыточности (breakeven) в автоматизированных стратегиях на языке MQL5. Начнем с простого объяснения, что такое режим безубытка, как он реализуется и каковы его возможные вариации. Далее эта функциональность интегрируется в советника Order Blocks, созданного нами в последней статье об управлении рисками. Для оценки эффективности проведем два бэктеста при определенных условиях: один с применением механизма безубыточности и другой — без.