preview
Нейросети в трейдинге: Интеграция теории хаоса в прогнозирование временных рядов (Attraos)

Нейросети в трейдинге: Интеграция теории хаоса в прогнозирование временных рядов (Attraos)

MetaTrader 5Торговые системы | 4 марта 2025, 13:37
48 0
Dmitriy Gizlyk
Dmitriy Gizlyk

Введение

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

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

Для решения указанных задач, авторы фреймворка Attraos, предложенного в работе "Attractor Memory for Long-Term Time Series Forecasting: A Chaos Perspective", интегрируют принципы теории хаоса, рассматривая временные ряды как низкоразмерные проекции многомерных хаотических динамических систем. Такой подход позволяет учитывать скрытые нелинейные зависимости между рыночными данными и повысить точность прогнозирования. Применение методов хаотической динамики в анализе временных рядов открывает возможность выявлять устойчивые структуры в рыночных данных и учитывать их при построении прогнозных моделей.

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

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

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


Алгоритм Attraos

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

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

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

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

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

Процесс обработки данных в Attraos начинается с модуля реконструкции фазового пространства (Phase Space ReconstructionPSR), который отвечает за подбор оптимальных значений d и τ для корректного представления динамики системы. Этот этап критически важен, так как некорректно выбранные параметры могут привести к значительным искажениям реконструированного фазового портрета. После этого модуль MDMU (Multidimensional Data Management Unit) выполняет разбиение данных на неперекрывающиеся фрагменты с использованием многомерных тензоров. Этот процесс снижает вычислительную сложность, ускоряет сходимость модели и формирует динамическую память системы, фиксируя ключевые эволюционные паттерны. Благодаря такому подходу прогнозы становятся более стабильными и устойчивыми к возможной деградации данных. Дополнительно MDMU использует метод адаптивного выделения значимых элементов временного ряда, что позволяет динамически исключать неинформативные компоненты и делать акцент на ключевых факторах, оказывающих максимальное влияние на эволюцию системы.

Одним из важнейших элементов архитектуры Attraos является модуль LMA (Linear Matrix Approximation), реализующий метод линейной матричной аппроксимации. Он применяет полиномиальную проекцию для выделения основных характеристик динамики системы, используя параметризованные матрицы с диагональными структурами, которые задают "окна измерения". Это способствует точному выделению локальных особенностей динамики и адаптивной корректировке модели при изменении исходных данных. Применение диагональных матриц снижает вычислительную сложность, позволяя эффективно работать с многомерными структурами данных. Эволюция системы в этом модуле формализуется следующим выражением:

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

Для обработки динамических процессов применяется модуль DP (Discrete Projection), выполняющий дискретизацию системы с использованием комбинированных методов. В частности, применяется экспоненциальное представление матриц, обеспечивающее высокую точность при анализе последовательных данных. Этот метод гарантирует корректное приближение эволюции системы и снижает влияние накопления ошибок, что особенно важно при анализе длинных временных рядов. В рамках данного модуля реализован механизм адаптивной квантизации данных, позволяющий оптимизировать точность аппроксимации без значительного увеличения вычислительных затрат.

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

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

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



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

После рассмотрения теоретических аспектов фреймворка Attraos мы переходим к практической части нашей работы, в которой реализуем свое видение предложенных подходов средствами MQL5.

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

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

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

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

Умножение диагональной матрицы


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

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

В параметрах кернела DiagMatMult получаем указатели на 3 буфера данных. Два из них содержат исходные данные, а третий предназначен для сохранения результатов выполнения операций. Мы так же добавили возможность применения функции активации к результатам умножения матриц.

__kernel void DiagMatMult(__global const float * diag,
                          __global const float * matr,
                          __global float * result,
                          int activation)
  {
   size_t row = get_global_id(0);
   size_t col = get_local_id(1);
   size_t var = get_global_id(2);
   size_t rows = get_global_size(0);
   size_t cols = get_local_size(1);

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

   __local float local_diag[1];
   if(cols==0)
      local_diag[0] = diag[row + var * rows];
   barrier(CLK_LOCAL_MEM_FENCE);

На следующем этапе мы определим смещение в буфере произвольной матрицы до необходимого элемента.

   int shift = (row  + var * rows) * cols + col;

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

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

   float res = local_diag[0] * matr[shift];
//---
   result[shift] = Activation(res, activation);
  }

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

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

__kernel void DiagMatMultGrad(__global const float *diag,
                              __global float *grad_diag,
                              __global const float *matr,
                              __global float * grad_matr,
                              __global const float * grad_result)
  {
   size_t row = get_global_id(0);
   size_t col = get_local_id(1);
   size_t var = get_global_id(2);
   size_t rows = get_global_size(0);
   size_t cols = get_local_size(1);
   size_t vars = get_global_size(2);

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

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

   __local float local_diag[LOCAL_ARRAY_SIZE];
   if(cols==0)
      local_diag[0] = diag[row + var * rows];
   barrier(CLK_LOCAL_MEM_FENCE);

И синхронизируем работу потоков рабочей группы.

Далее определим смещение в буферах произвольной и результирующих матриц.

   int shift = (row  + var * rows) * cols + col;
//---
   float grad = grad_result[shift];
   float inp = matr[shift];

Значения необходимых элементов этих матриц сохраним в локальные переменные.

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

   grad_matr[shift] = IsNaNOrInf(local_diag[0] * grad, 0);
   barrier(CLK_LOCAL_MEM_FENCE);

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

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

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

   int loc = col % LOCAL_ARRAY_SIZE;
#pragma unroll
   for(int c = 0; c < cols; c += LOCAL_ARRAY_SIZE)
     {
      if(c <= col && (c + LOCAL_ARRAY_SIZE) > col)
        {
         if(c == 0)
            local_diag[loc] = IsNaNOrInf(grad * inp, 0);
         else
            local_diag[loc] += IsNaNOrInf(grad * inp, 0);
        }
      barrier(CLK_LOCAL_MEM_FENCE);
     }

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

Далее добавим цикл параллельного суммирования элементов локального массива.

   int count = min(LOCAL_ARRAY_SIZE, (int)cols);
   int ls = count;
#pragma unroll
   do
     {
      count = (count + 1) / 2;
      if((col + count) < ls)
        {
         local_diag[col] += local_diag[col + count];
         local_diag[col + count] = 0;
        }
      barrier(CLK_LOCAL_MEM_FENCE);
     }
   while(count > 1);

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

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

   if(col == 0)
      grad_diag[row + var * rows] = IsNaNOrInf(local_diag[0], 0);
  }

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

Алгоритм параллельного сканирования


Продолжаем работу на стороне OpenCL-программы, но переходим к реализации алгоритмов фреймворка Attraos. Нам предстоит реализовать алгоритм параллельного сканирования, который используется для эффективного обновления значений массива исходных данных X с учетом матриц коэффициентов взаимодействия A и нормирующих множителей H. Основная идея алгоритма заключается в итеративном вычислении префиксных сумм с двоичным разбиением, что снижает вычислительную сложность с O(L), характерной для последовательных методов, до O(log L).

Массив X = {x0, x1, ..., xL-1} обновляется с учетом соседних элементов по следующему рекуррентному соотношению:

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

Данный процесс мы реализуем в рамках кернела PScan. В параметрах кернела получаем указатели на 4 буфера данных. Три из которых содержат исходные данные и один для записи результатов.

__kernel void PScan(__global const float* A,
                    __global const float* X,
                    __global const float* H,
                    __global float* X_out)
  {
   const size_t idx = get_local_id(0);
   const size_t dim = get_global_id(1);
   const size_t L = get_local_size(0);
   const size_t D = get_global_size(1);

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

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

   const int num_steps = (int)log2((float)L);

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

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

   __local float local_A[1024];
   __local float local_X[1024];
   __local float local_H[1024];

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

//--- Load data to local memory
   int offset = dim + idx * D;
   local_A[idx] = A[offset];
   local_X[idx] = X[offset];
   local_H[idx] = H[offset];
   barrier(CLK_LOCAL_MEM_FENCE);

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

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

//--- Scan
#pragma unroll
   for(int step = 0; step < num_steps; step++)
     {
      int halfT = L >> (step + 1);
      if(idx < halfT)
        {
         int base = idx * 2;
         local_X[base + 1] += local_A[base + 1] * local_X[base];
         local_X[base + 1] *= local_H[base + 1];
         local_A[base + 1] *= local_A[base];
        }
      barrier(CLK_LOCAL_MEM_FENCE);
     }

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

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

//--- Save result
   X_out[offset] = local_X[idx];
  }

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

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

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

__kernel void PScan_CalcHiddenGradient(__global const float* A,
                                       __global float*  grad_A,
                                       __global const float* X,
                                       __global float*  grad_X,
                                       __global const float* H,
                                       __global float*  grad_H,
                                       __global const float* grad_X_out)
  {
   const size_t idx = get_local_id(0);
   const size_t dim = get_global_id(1);
   const size_t L = get_local_size(0);
   const size_t D = get_global_size(1);
   const int num_steps = (int)log2((float)L);

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

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

   __local float local_A[1024];
   __local float local_X[1024];
   __local float local_H[1024];
   __local float local_grad_X[1024];
   __local float local_grad_A[1024];
   __local float local_grad_H[1024];

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

//--- Load data to local memory
   int offset = idx * D + dim;
   local_A[idx] = A[offset];
   local_X[idx] = X[offset];
   local_H[idx] = H[offset];
   local_grad_X[idx] = grad_X_out[offset];
   local_grad_A[idx] = 0.0f;
   local_grad_H[idx] = 0.0f;
   barrier(CLK_LOCAL_MEM_FENCE);

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

//--- Reverse Scan (Backward)
#pragma unroll
   for(int step = num_steps - 1; step >= 0; step--)
     {
      int halfT = L >> (step + 1);
      if(idx < halfT)
        {
         int base = idx * 2;
         // Compute gradients
         float grad_next = local_grad_X[base + 1] * local_H[base + 1];
         local_grad_H[base + 1] = local_grad_X[base + 1] * local_X[base];
         local_grad_A[base + 1] = local_grad_X[base + 1] * local_X[base];
         local_grad_X[base] += local_A[base + 1] * grad_next;
        }
      barrier(CLK_LOCAL_MEM_FENCE);
     } 

В теле цикла сначала вычисляется количество активных потоков, участвующих в данной итерации (halfT). А затем, определяется градиент ошибки (grad_next), который определяется произведением текущего значения на соответствующий коэффициент нормализации H. Далее вычисляются производные по коэффициентам нормализации H и взаимодействия A, используя текущее значение X. Для корректного распространения ошибки назад, значение градиента X корректируется с учетом коэффициента взаимодействия. И обязательно синхронизируем потоки в рамках рабочей группы на каждой итерации цикла.

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

//--- Save gradients
   grad_A[offset] = local_grad_A[idx];
   grad_X[offset] = local_grad_X[idx];
   grad_H[offset] = local_grad_H[idx];
  }

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

На этом мы завершаем работу на стороне OpenCL-контекста в рамках данной реализации. С полным кодом OpenCL-программы вы можете ознакомиться во вложении.

Следующим этапом нашей работы является построение алгоритмов на стороне основной программы. Однако, мы практически исчерпали объем статьи. Поэтому сделаем небольшой перерыв и вернемся к построению фреймворка Attraos в следующей статье.


Заключение

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

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

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

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


Ссылки


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

# Имя Тип Описание
1 Research.mq5 Советник Советник сбора примеров
2 ResearchRealORL.mq5
Советник
Советник сбора примеров методом Real-ORL
3 Study.mq5 Советник Советник обучения моделей
4 Test.mq5 Советник Советник для тестирования модели
5 Trajectory.mqh Библиотека класса Структура описания состояния системы и архитектуры моделей
6 NeuroNet.mqh Библиотека класса Библиотека классов для создания нейронной сети
7 NeuroNet.cl Библиотека Библиотека кода OpenCL-программы
Прикрепленные файлы |
MQL5.zip (2509.49 KB)
Особенности написания Пользовательских Индикаторов Особенности написания Пользовательских Индикаторов
Написание пользовательских индикаторов в торговой системе MetaTrader 4
Переосмысливаем классические стратегии (Часть VI): Анализ нескольких таймфреймов Переосмысливаем классические стратегии (Часть VI): Анализ нескольких таймфреймов
В данной серии статей мы вновь рассматриваем классические стратегии, чтобы выяснить, можно ли улучшить их с помощью ИИ. В сегодняшней статье мы рассмотрим популярную стратегию анализа нескольких таймфреймов, чтобы оценить, можно ли улучшить эту стратегию с помощью ИИ.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Разрабатываем мультивалютный советник (Часть 24): Подключаем новую стратегию (I) Разрабатываем мультивалютный советник (Часть 24): Подключаем новую стратегию (I)
В данной статье рассмотрим как нам подключить новую стратегию к созданной системе автоматической оптимизации. Посмотрим, какие советники нам понадобится создать и можно ли будет обойтись без изменений файлов библиотеки Advisor или свести необходимые изменения к минимуму.