Поиск торгового преимущества (Часть 1): Использование дискретного преобразования Фурье (ДПФ) и импульсной нейронной сети (SNN) в торговом роботе
Введение
Можно утверждать, что современные торговые системы страдают от переизбытка данных или чрезмерной зависимости от коррелирующих и запаздывающих индикаторов. Поэтому для получения торгового преимущества в этой серии исследований предлагается разнообразная библиотека сочетаний специализированных алгоритмов и нейронных сетей. Начнём с необычного гибридного сочетания: декодера циклов на основе дискретного преобразования Фурье (ДПФ), который мы объединяем с основанной на биологической модели интегрирования и срабатывания с утечкой (LIF) импульсной нейронной сетью (SNN). Наша цель — выделить скрытые частоты рыночных колебаний.
Сочетание преобразования Фурье и SNN
Такое сочетание преобразования Фурье и импульсной нейронной сети (SNN) призвано обеспечить нам торговое преимущество, основанное на менее коррелированных сигналах за счёт спектрального разложения и подтверждения с учётом временного фактора. Традиционные индикаторы часто запаздывают из-за использования фиксированных окон исторических данных, тогда как модуль Фурье действует как декодер циклов: он динамически анализирует исторические значения цен или индикаторов, чтобы выделить волну с доминирующей частотой. Таким образом, данная система способна преобразовывать такие индикаторы, как MACD и RSI, в прогнозные волновые функции, которые выявляют ключевые точки разворота ещё до того, как они станут визуально заметными.
SNN определяет момент исполнения торговых операций, дополнительно учитывая показатели времени и рыночного давления. Вместо немедленной генерации шумных торговых сигналов с использованием статических весов входные данные рассматриваются как синаптическая стимуляция, повышающая мембранный потенциал цифровой модели нейрона. Этот мембранный потенциал затухает, когда импульс движения ослабевает, но накапливается, когда несколько рыночных переменных согласованно изменяются на протяжении последовательных баров. Таким образом, сделка инициируется только тогда, когда накопленное "напряжение" превышает строго заданный порог, вызывая импульс, который запускает исполнение торговой операции. Это гарантирует, что циклические развороты подтверждаются устойчивым импульсом движения, прежде чем будет задействован капитал.
Идеальные условия для этой пары
Торговые системы неизбежно дают сбои при смене рыночных режимов — например, при переходе от трендового рынка к боковому. Это подчеркивает, насколько важно иметь разнообразный набор специально разработанных стратегий. Гибридная система, сочетающая преобразование Фурье и импульсную нейронную сеть (SNN), ориентирована прежде всего на переходные фазы рынка. Для этого преобразование Фурье определяет длину доминирующего цикла, позволяя отфильтровывать ложные разворотные колебания, а импульсная нейронная сеть (SNN) предотвращает чрезмерную реакцию на краткосрочные резкие скачки цены, требуя подтверждения в течение нескольких баров: сигнал на вход должен оставаться действительным к моменту исполнения торговой операции, когда накопится достаточное "напряжение".
Описание алгоритма и сети
Аргументы в пользу данного сочетания
Обычные модели, сочетающие скользящие средние и, скажем, классические нейронные сети, могут быть несколько неустойчивыми и излишне чувствительными к изменениям. В отличие от них, сочетание дискретного преобразования Фурье (ДПФ) и импульсной нейронной сети (SNN) призвано обеспечить баланс между математической точностью и подтверждением сигналов во времени. Если представить рынок в виде бурного океана, то ДПФ будет играть роль гидролокатора подводной лодки, игнорирующего штормы на поверхности, чтобы точно выявлять скрытые ритмичные приливные волны на большой глубине. SNN, в свою очередь, будет играть роль дисциплинированного командира, управляющего торпедной стрельбой: он терпеливо ожидает очередного сигнала гидролокатора, с каждым из которых нарастает внутреннее давление. По мере накопления этого давления сделка инициируется лишь тогда, когда превышен строго заданный порог.
Математические формулы
Чтобы подробно разобрать устройство и принцип работы нашего гибридного торгового модуля, стоит перейти от метафор к математическим уравнениям, описывающим работу алгоритма и нейронной сети. Эта гибридная модель опирается на две основные формулы: дискретное преобразование Фурье (ДПФ) для спектрального разложения и дифференциальную аппроксимацию модели интегрирования и срабатывания с утечкой (LIF) для нейронных вычислений с учетом времени.
Спектральный модуль:
Мы рассматриваем скользящее окно исторических данных о рыночных ценах как конечный дискретный временной ряд, представленный вектором x[n] длины N, где n — дискретный индекс времени, или номер бара (n = 0, 1,... N-1). Дискретное преобразование Фурье переводит этот пространственный вектор цен в спектр X[k] в частотной области, где каждый комплексный коэффициент соответствует определенному индексу гармонической частоты k:

Где:
- X[k] — k-й комплексный частотный коэффициент (результат отражает фазу и амплитуду k-й гармоники).
- k — дискретный индекс частоты (k = 0, 1, …, N-1), соответствующий исследуемой циклической гармонике.
- Сумма от {n=0} до {n=N-1} обозначает дискретное суммирование по индексу в пределах всего скользящего окна исторических данных.
- N — размер окна, то есть общее число преобразуемых точек исторических данных.
- n — дискретный временной индекс (n = 0, 1, …, N-1), обозначающий каждую свечу в исторических данных.
- x[n] — значение входного сигнала в точке с индексом n (исходная цена, значение линии MACD или линии RSI на соответствующем баре).
- j — мнимая единица, определяемая как квадратный корень из −1 (часто обозначается как i).
- e — число Эйлера (приблизительно 2,71828), основание натурального логарифма, используемое для описания комплексного экспоненциального роста.
- 2π/N — это шаг угловой частоты, который нормализует геометрическое распределение циклов волны.
Применив формулу Эйлера, мы можем разложить это комплексное уравнение на действительную и мнимую части в декартовой форме и последовательно вычислить их с помощью дискретных сумм.


Где:
- Re(X[k]) — действительная часть k-го комплексного частотного коэффициента.
- Im(X[k]) — мнимая часть $k$-го комплексного частотного коэффициента.
- Сумма от {n=0} до {n=N-1} обозначает дискретное суммирование результатов вычислений для каждого бара по всей исторической выборке.
- N — общая длина выборки (фиксированное число, передаваемое в алгоритм).
- n — дискретный индекс положения (n = 0, 1, …, N-1), определяющий конкретную позицию в окне исторических данных.
- x[n] — значение входного сигнала в точке с индексом n (исходная цена либо значение MACD или RSI).
- k — индекс дискретной частоты (k = 1, 2, …, (N/2)−1) для рассчитываемой частоты циклической волны.
- (2π k n)/N — это угловой фазовый аргумент, который определяет геометрическую точку на окружности, соответствующую бару n при частоте k.
- − (знак минус) — это принятое в математике обозначение, используемое при суммировании мнимых составляющих для согласования фаз в соответствии с формулой Эйлера.
Для каждой частотной составляющей с индексом k модуль, или амплитуда A[k], отражает выраженность соответствующего цикла в окне исторических ценовых данных и вычисляется по теореме Пифагора следующим образом:
![]()
Фазовый угол φ[k], определяющий текущее смещение волны относительно начала отсчёта времени, вычисляется с помощью следующей формулы арктангенса с двумя аргументами:
![]()
После того как модуль переберёт все частоты вплоть до предела Найквиста (N/2), мы можем выделить доминирующую частотную составляющую k_dom с максимальной амплитудой A[k]. Непрерывная математическая проекция доминирующей волны на временной массив скользящего окна рассчитывается для прогнозирования текущего состояния цикла y_pred по следующему выражению:

Где:
- y_pred — это непрерывное прогнозное значение цикла, нормированное строго в пределах диапазона [-1,0; 1,0] и отражающее теоретическое положение рыночной волны.
- phi[k_dom] — это угол фазового сдвига выделенной доминирующей циклической частотной составляющей, полученный с помощью функции MathArctan2. Он задаёт истинное начальное положение волны относительно временной шкалы исторических данных.
- k_dom — это индекс гармоники доминирующей частоты с максимальной спектральной амплитудой, найденной при переборе частот в ходе суммирования Фурье.
Это позволяет нормировать итоговое значение цикла в пределах диапазона [-1,0; 1,0], где −1,0 и 1,0 соответствуют абсолютному минимуму и максимуму цикла.
Нейросетевой модуль:
Импульсная нейронная сеть (SNN) основана на алгоритмической адаптации биологически обоснованной модели нейрона — модели интегрирования и срабатывания с утечкой (LIF). В то время как обычные нейроны сопоставляют входные сигналы непосредственно с выходными посредством статической функции активации, нейрон LIF обрабатывает входные сигналы так, как если бы они представляли собой временные электрические заряды, изменяющие его зависимую от времени внутреннюю переменную состояния, которую мы называем мембранным потенциалом (V_m). В непрерывном времени динамика мембранного потенциала описывается линейным дифференциальным уравнением первого порядка:
![]()
Где:
- tau_m — это мембранная постоянная времени (измеряется в миллисекундах, tau_m = R × C_m); она определяет, как быстро внутреннее напряжение вследствие пассивной утечки возвращается к исходному потенциалу покоя.
- V_m(t) — зависимый от времени мембранный потенциал нейрона в момент времени t. Он отражает накопленное внутреннее электрическое напряжение.
- dV_m(t)/dt — первая производная мембранного потенциала по времени. Она характеризует мгновенную скорость изменения напряжения.
- Знак минус задаёт направление утечки и обеспечивает естественное затухание мембранного потенциала при отсутствии входных токов.
- R — общее сопротивление мембраны, которое характеризует степень физического влияния поступающих пресинаптических электрических токов на внутренний потенциал.
- I(t) — изменяющийся во времени суммарный пресинаптический входной ток в момент времени t (или массивы, передаваемые из индикаторов и модуля Фурье).
В нашей алгоритмической реализации с дискретным временем (каждый шаг соответствует новому бару) мы приближенно моделируем эту непрерывную утечку с помощью дискретного коэффициента утечки gamma. Этот коэффициент gamma находится в диапазоне [0, 1] и регулируется входным параметром "InpSnnDecay". Наше правило обновления мембранных потенциалов нейронов "Покупка" и "Продажа" (V_buy и V_sell) формулируется следующим образом:

Где:
- V_m[t] — текущий мембранный потенциал нейрона в данный момент времени или на баре t.
- V_m[t-1] — мембранный потенциал нейрона на непосредственно предшествующем временном шаге (t-1). Он выступает в качестве исходного состояния памяти.
- gamma — это дискретный коэффициент утечки ("InpSnnDecay"). Он принимает значения в диапазоне [0, 1] и задает долю напряжения, теряемую за один бар.
- (1 - gamma) — это наш множитель сохранения, определяющий долю мембранного потенциала предыдущего шага, которая сохраняется на текущем шаге.
- Сумма от {i=1} до {i=M} — оператор дискретного суммирования по всем M различным входным сигналам (M=3 в полной версии нашей гибридной модели).
- M — общее число независимых источников пресинаптических входных сигналов, подаваемых в сеть.
- w_i — статический синаптический вес, присвоенный входному каналу i (например, w_1 = 0.6, w_2 = 0.4, w_3 = 0.5). Этот вес определяет силу воздействия входного сигнала на мембранный потенциал.
- S_i[t] — нормированное значение пресинаптического входного сигнала от канала i на баре t.
Нейрон сравнивает это накопленное внутреннее напряжение со строго заданным порогом срабатывания (V_th), который мы регулируем с помощью входного параметра "InpSnnThreshold". Ступенчатая функция активации, формирующая постсинаптический импульс H[t], используемый для принятия решений, определяется следующим образом:

Важно отметить, что при возникновении постсинаптического импульса (H[t] = 1) нейрон инициирует мгновенный сброс. Это приведет к сбросу его внутреннего состояния до исходного значения, чтобы предотвратить возникновение неуправляемых циклов положительной обратной связи. Таким образом, этот сброс описывается приведенным ниже уравнением.
![]()
Вся эта математическая модель превращает простые массивы исторических числовых данных в слаженную систему, способную измерять структурные рыночные циклы и одновременно фильтровать сигналы по степени уверенности нейронной сети, формируемой во времени.
Реализация на MQL5
Переход от теории и исследований к практическому применению предполагает тщательную реализацию нашей модели спектрального и нейронного модулей с соблюдением строгого синтаксиса MQL5. Далее следует подробный построчный анализ пользовательского советника. Мы не просто приводим код: мы анализируем его структуру с учетом гибридной архитектуры, объединяющей ДПФ и SNN, и пытаемся объяснить, как он преобразует необработанные рыночные данные в исполнение торговых операций на основе сигналов с высокой степенью уверенности.
Настройка среды
Можно утверждать, что надежность большинства торговых роботов во многом определяется тем, как они управляют своим внутренним состоянием. Мы разрабатываем торгового робота, а не советника, поскольку последний, если он написан на языке MQL5, может использовать встроенные базовые классы MQL5, содержащиеся в файлах "Expert.mqh" и "ExpertBase.mqh". Большую часть работы мы выполняем "с нуля". Мы сознательно избегаем порой громоздкой и негибкой структуры, которую может задавать фреймворк CExpert. Этот фреймворк порой может скрывать детали непосредственного выполнения кода, необходимые для нашей собственной нейронной обработки. Вместо этого мы выбираем гибридную процедурную архитектуру, в которой встроенные классы "CTrade" и "CSymbolInfo" используются исключительно для исполнения торговых операций и обеспечения стабильности. Мы сохраняем полный контроль над циклом функции "OnTick()". В основе нашего торгового робота лежит перечисление "EMode". Оно играет роль своего рода нейронного коммутатора. Оно позволяет пользователю работать с компонентами алгоритма по отдельности, прежде чем использовать гибридную систему.
//--- Enums for EA Operation Modes enum EMode { MODE_FOURIER_PRICE = 0, // 1. Fourier Transform on Raw Price Cycles MODE_FOURIER_MACD = 1, // 2. Fourier Transform on MACD Turning Points MODE_FOURIER_RSI = 2, // 3. Fourier Transform on RSI Turning Points MODE_FOURIER_COMBINED = 4, // 4. Combined Fourier (Price + MACD + RSI) MODE_PRICE_ACTION_SNN = 5, // 5. Pure Price Action & Candlestick via SNN MODE_INDICATOR_PATTERN = 6, // 6. Indicator Pattern Recognition (Divergences) via SNN MODE_HYBRID_FULL = 7 // 7. Full Hybrid (Fourier Cycle Filtering + SNN Setup) };
Переключая режимы во время тестирования, разработчик может определить, вызвано ли ухудшение кривой эквити ошибкой расчета фазы цикла модулем Фурье или неверной интерпретацией импульса движения сетью SNN. В функции "OnInit()" мы инициализируем наш класс "ExtTrade", задавая важные параметры безопасности, такие как проскальзывание и магический номер; последний позволяет гибко управлять не только позициями торгового робота, но и позициями, открытыми вручную. Важно отметить, что цикл выполнения в функции "OnTick()" начинается со строгого временного барьера: <code: if(timeCurrentBar == timeLastBar) return;/>. Поскольку преобразование Фурье и дискретная сеть LIF рассчитывают структурные сдвиги на основе данных за завершенные периоды, выполнение этих ресурсоемких вычислений на каждом микротике создавало бы значительную избыточную вычислительную нагрузку и приводило бы к ложным импульсам нейронов.
Выбор индикатора
Прежде чем рассмотреть подробности работы двух модулей, кратко остановимся на обосновании пресинаптического моделирования, результаты которого подаются на вход нейронной сети. Почему мы используем осцилляторы MACD и RSI? Модуль Фурье определяет, "когда" может произойти разворот цикла, но не измеряет силу рыночного движения, стоящую за каждым таким разворотом. В идеале для подтверждения волновой структуры следует использовать дополнительные показатели. Индекс относительной силы (RSI) выбран потому, что его значения ограничены диапазоном [0, 100]. Он отслеживает крайнее истощение ценового движения. Когда цикл, определяемый модулем Фурье, входит в область минимума, значение RSI в зоне перепроданности дает нам подтверждение по положению цены. Индикатор схождения/расхождения скользящих средних (MACD) также выбран потому, что диапазон его значений по своей природе не ограничен. Измеряя производную импульса движения — ускорение или замедление тренда, — мы можем рассчитывать дивергенции. Речь идет о расстоянии между линией MACD и нулевой линией. В результате мы получаем необработанную оценку скорости движения с учетом направления.
Таким образом, волна основной частоты (Фурье) в сочетании с ограниченным показателем истощения движения (RSI) и неограниченным показателем скорости (MACD) образует некоррелированную триаду. Если все три показателя согласуются, математическая вероятность успешного разворота становится значительно выше, чем при использовании только одного показателя.
Алгоритм преобразования Фурье
Наша функция CalculateFourierTurningPoint() — это модуль, выполняющий роль сонара в данной системе. Она выполняет разложение скользящего массива исторических данных, чтобы выявить "доминирующую частоту", определяющую преобладающую динамику цены.
//+------------------------------------------------------------------+ //| Mathematical Engine: Discrete Fourier Transform (DFT) | //+------------------------------------------------------------------+ double CalculateFourierTurningPoint(double &data[]) { int N = ArraySize(data); if(N == 0) return 0.0;
Для работы этой функции требуется массив входных данных размером N, заданным входным параметром "InpFourierWindow". С математической точки зрения N должно быть степенью числа 2 (например, 32, 256, 512…), чтобы избежать спектральной утечки и обеспечить стабильную дискретную обработку. Нулевое значение не допускается.
double max_amplitude = 0.0; double dominant_phase = 0.0; int dominant_k = 1;
Затем мы инициализируем переменные для отслеживания результатов. Основная задача модуля — найти частотный индекс k, которому соответствует наибольшая амплитуда и, следовательно, наиболее выраженный доминирующий цикл в массиве данных.
for(int k = 1; k < N / 2; k++) { double real = 0.0; double imag = 0.0;
Внешний цикл проходит по всему диапазону частот. Мы начинаем с k = 1, чтобы намеренно пропустить постоянную составляющую k = 0, которая соответствует среднему уровню данных и не дает информации о циклах. Перебор заканчивается на N/2 — пределе Найквиста; анализ частот с индексами, превышающими половину размера окна, привел бы к наложению спектров и искажению данных.
for(int n = 0; n < N; n++) { double angle = 2.0 * M_PI * k * n / N; real += data[n] * MathCos(angle); imag -= data[n] * MathSin(angle); }
Внутренний цикл приведенной выше реализации дискретного преобразования Фурье (ДПФ) реализует формулу Эйлера. Для каждой частоты k мы перебираем все бары n в окне исторических данных. Затем мы умножаем значения цены data[n] на косинус и синус соответствующего угла, чтобы разложить сигнал на действительную и мнимую векторные составляющие.
double amplitude = MathSqrt(real * real + imag * imag); if(amplitude > max_amplitude) { max_amplitude = amplitude; dominant_phase = MathArctan2(imag, real); dominant_k = k; } }
Применяя теорему Пифагора к действительной и мнимой векторным составляющим, мы можем вычислить амплитуду, то есть силу составляющей сигнала с частотой k. Если эта амплитуда оказывается наибольшей, мы фиксируем результат. Важно отметить, что мы используем выражение "MathArctan(imag, real)" для вычисления "dominant_phase" — точного геометрического сдвига, который показывает, где в данный момент находится цикл относительно своей начальной точки.
return MathSin(dominant_phase + (2.0 * M_PI * dominant_k * (N - 1) / N)); }
Наконец, мы восстанавливаем волну, проецируя доминирующую частоту "dominant_k" на самый последний бар "(N - 1)" и добавляя фазовый сдвиг "dominant_phase". К полученному результату мы применяем функцию синуса. Это позволяет нормализовать выходное значение строго в диапазоне от −1,0 до 1,0, где границы соответствуют абсолютному минимуму и абсолютному максимуму цикла.
Импульсная нейронная сеть (SNN)
Если преобразование Фурье, реализованное в функции "CalculateFourierTurningPoint()", — это наш гидролокатор, то функция "EvaluateSpikingNeuralNetwork()" — наш командир торпедной установки. Эта функция моделирует изменение мембранного потенциала во времени.
//+------------------------------------------------------------------+ //| AI Engine: Leaky Integrate-and-Fire Spiking Neuron Model | //+------------------------------------------------------------------+ int EvaluateSpikingNeuralNetwork(double inputSignal1, double inputSignal2, double inputSignal3) { static double w1 = 0.6, w2 = 0.4, w3 = 0.5; static double membranePotentialBuy = 0.0; static double membranePotentialSell = 0.0;
Самым важным ключевым словом здесь является "static". Поскольку мы определяем мембранные потенциалы как статические переменные, их значения сохраняются и после завершения очередного вызова "OnTick()". Так в сети реализуется явная память. Переменные "w1", "w2" и "w3" определяют синаптические веса. Эти веса определяют, насколько сильно сеть отдаёт предпочтение волне Фурье (w1) по сравнению с дополнительными индикаторами.
membranePotentialBuy *= (1.0 - InpSnnDecay); membranePotentialSell *= (1.0 - InpSnnDecay);
Описанное выше соответствует механизму утечки в сети LIF. Перед оценкой новых данных сеть "забывает" часть своей прежней уверенности в соответствии со значением входного параметра "InpSnnDecay". При коэффициенте утечки 0.2 мембранный потенциал уменьшается на 20 % на каждом ценовом баре. Это не позволяет сети инициировать сделку на основе уже утратившего актуальность импульса движения.
if(inputSignal1 > 0) membranePotentialBuy += inputSignal1 * w1; else membranePotentialSell += MathAbs(inputSignal1) * w1;
Далее сеть обрабатывает входные данные. Когда значение "inputSignal1" (цикл Фурье) выше нуля (то есть цикл движется к пику), оно повышает мембранный потенциал нейрона "Buy". Если же это значение отрицательно, его абсолютная величина возбуждает нейрон "Sell". Мы умножаем входное значение на его вес "w1". То же самое мы повторяем для "inputSignal2" и "inputSignal3".
bool buySpike = (membranePotentialBuy >= InpSnnThreshold); bool sellSpike = (membranePotentialSell >= InpSnnThreshold); if(buySpike && !sellSpike) { membranePotentialBuy = 0.0; return 1; } if(sellSpike && !buySpike) { membranePotentialSell = 0.0; return -1; } return 0; }
Эта сеть самостоятельно контролирует напряжение. Она определяет, превысил ли накопленный потенциал уровень, заданный входным параметром "InpSnnThreshold". При возникновении импульса "buySpike" сеть немедленно возвращает значение "1" (сигнал на покупку), после чего мембранный потенциал принудительно сбрасывается до 0.0. Такой сброс по аналогии с биологическим нейроном обеспечивает отправку торговым роботом лишь одного четкого ордера при каждом структурном согласовании сигналов. Это предотвращает неконтролируемое выставление сетки ордеров при устойчивых трендах.
Соединение модулей
Можно сказать, что истинный потенциал этой модели раскрывается при вызове функции "ExecuteHybridFull()". Эта функция объединяет математическое выделение составляющих с помощью преобразования Фурье с подтверждением сигнала во времени, которое обеспечивает импульсная нейронная сеть (SNN)
//+------------------------------------------------------------------+ //| Generates a hybrid trading signal | //| Uses Fourier and RSI rules or an optional SNN with MACD input | //| Returns: 1 = buy, -1 = sell, 0 = no signal | //+------------------------------------------------------------------+ int ExecuteHybridFull() { double closePrices[]; ArrayResize(closePrices, InpFourierWindow); if(CopyClose(_Symbol, _Period, 0, InpFourierWindow, closePrices) < InpFourierWindow) return 0; double fourierPriceSignal = CalculateFourierTurningPoint(closePrices);
Сначала мы получаем необработанные ценовые данные и передаем их в наш модуль Фурье. Теперь параметр "fourierPriceSignal" будет содержать значение от -1,0 до 1,0, отражающее фазу выделенной частотной составляющей рыночного сигнала.
double rsiValues[], macdValues[]; ArrayResize(rsiValues, 5); ArrayResize(macdValues, 5); if(CopyBuffer(hRSI, 0, 0, 5, rsiValues) < 5) return 0; if(CopyBuffer(hMACD, MAIN_LINE, 0, 5, macdValues) < 5) return 0; double rsiMomentum = rsiValues[0] - rsiValues[4]; double macdMomentum = macdValues[0] - macdValues[4];
После этого мы получаем короткие массивы значений наших технических индикаторов за 5 баров. Вычитая прошлое значение "[4]" из текущего значения "[0]", мы вычисляем фактический вектор скорости, представленный величинами "rsiMomentum" и "macdMomentum".
if(InpUseSNN) { return EvaluateSpikingNeuralNetwork(fourierPriceSignal, rsiMomentum, macdMomentum); }
В завершение мы подаем эти три различные рассчитанные характеристики на вход нашей импульсной нейронной сети (SNN). Таким образом, чисто математический фазовый сдвиг, ограниченный пространственный импульс движения и неограниченная скорость объединяются, постепенно накапливая "нейронное давление".
Исполнение торговых операций и управление состоянием
Формирование качественного сигнала не принесет пользы, если логика исполнения торговых операций ненадежна. Поскольку речь идет о торговом роботе, а не о советнике MQL5, в котором эта логика определяется классами библиотеки MQL5, наша функция "ManagePositions()" играет ключевую роль. Она служит практическим связующим звеном между нашей импульсной нейронной сетью (SNN) и сервером брокера. Используя объекты "CTrade" и "CSymbolInfo" из стандартной библиотеки, мы можем обойтись без использования структур данных "MqlTradeRequest".
//+------------------------------------------------------------------+ //| Position management using CTrade class | //+------------------------------------------------------------------+ void ManagePositions(int signalType) { ExtSymbolInfo.RefreshRates(); bool hasOpenPosition = false; int totalPositions = PositionsTotal();
В этой функции мы начинаем с вызова метода "ExtSymbolInfo.RefreshRates()". Это крайне важный этап, который обеспечивает надлежащую синхронизацию наших цен "бид" и "аск" с сервером, что должно предотвратить отклонение ордеров из-за проскальзывания.
for(int i = totalPositions - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket != 0 && PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber) { long type = PositionGetInteger(POSITION_TYPE); //--- If signal is opposite to position type, close it if((type == POSITION_TYPE_BUY && signalType == -1) || (type == POSITION_TYPE_SELL && signalType == 1)) { ExtTrade.PositionClose(ticket, InpSlippage); ExtTrade.PrintResult(); } else { //--- Position aligns with signal; no action needed hasOpenPosition = true; } } }
Наш механизм управления состоянием, описанный выше, выполняет обратный проход по всем открытым позициям. При этом отбираются только позиции по символу текущего графика "_Symbol" с заданным магическим номером "InpMagicNumber". Если при наличии длинной позиции сеть SNN выдает импульс −1 (продажа), торговый робот использует метод "ExtTrade.PositionClose()" для закрытия этой позиции. Это динамический разворот, поскольку система опирается преимущественно на циклический характер волны Фурье, а не на статические, жестко заданные стоп-лоссы.
if(!hasOpenPosition) { if(signalType == 1) { double price = NormalizeDouble(ExtSymbolInfo.Ask(), ExtSymbolInfo.Digits()); if(!ExtTrade.Buy(InpLotSize, _Symbol, price, 0.0, 0.0)) { PrintFormat("Buy failed. Ask=%G error=%d", price, GetLastError()); } } else if(signalType == -1) { double price = NormalizeDouble(ExtSymbolInfo.Bid(), ExtSymbolInfo.Digits()); if(!ExtTrade.Sell(InpLotSize, _Symbol, price, 0.0, 0.0)) { PrintFormat("Sell failed. Bid=%G error=%d", price, GetLastError()); } } } }
Когда нет конфликтующих сделок, класс "CTrade" управляет открытием позиций, автоматически применяя заданные значения стандартного отклонения и размера лота.
Среда для первоначального тестирования
Тестирование нашей гибридной модели в тестере стратегий MetaTrader 5 требует терпения: было бы опрометчиво задавать параметры наугад в надежде, что какой-нибудь набор сработает и обеспечит линейный рост кривой эквити. Наша система должна быть тщательно настроена с учетом конкретного режима волатильности выбранного актива. Поэтому при формировании матрицы оптимизации основное внимание уделяется взаимосвязи частотного разрешения преобразования Фурье ("InpFourierWindow") и биологической памяти сети ("InpSnnDecay"). Для тестирования с оптимизацией мы выбираем валютную пару GBPJPY на двухчасовом таймфрейме. Мы проводим оптимизацию в период с 01.01.2025 по 01.01.2026. Затем мы проводим форвардное тестирование за период с 01.01.2026 по 01.05.2026. Ключевыми параметрами, которые мы настраиваем, являются "InpFourierWindow", "InpSnnThreshold" и "InpSnnDecay".
Такая сетка параметров позволяет трейдеру охватить весь спектр — от быстрых сетей с высокой реактивностью (низкий порог и сильное затухание) до систем, фильтрующих тренды с высокой уверенностью (высокие пороги и слабое затухание). Это гарантирует, что в ходе тестового прогона сеть будет готова к работе в условиях трех основных рыночных режимов: бычьего тренда, медвежьей фазы и периода консолидации.
Анализ результатов тестирования после оптимизации
Оптимальные значения входных параметров, полученные в ходе оптимизации, обеспечили прибыльный результат форвардного тестирования. Оптимальные настройки предусматривали окно преобразования Фурье длиной 90 баров и сильное затухание мембранного потенциала нейрона — на 82 %, благодаря чему система немедленно отфильтровывала шум, синхронизируя срабатывание с импульсом движения.


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

Эта весьма строгая логика ограничила число сделок до 56 и обеспечила долю прибыльных сделок 62,5 % и прибыль в размере 41 305,70 на счете с начальным капиталом 10 000 долларов. Эта гибридная модель, при настройке которой мы выбирали, использовать ли сеть в качестве дополнительного фильтра, также обеспечила профит-фактор 1,64 и просадку по средствам, не превышавшую 7,57 %.
Резюме

Заключение:
Результаты 16-месячного тестирования в определенной степени подтверждают торговое преимущество нашей модели Fourier-SNN. Как всегда, рекомендуется провести дополнительное тестирование на других торговых инструментах и за более длительные периоды. Однако, пропуская данные о циклических колебаниях через временной фильтр, гибридный модуль, по-видимому, смог отфильтровать локальный рыночный шум. В будущих вариантах этой модели можно исследовать динамическую синаптическую пластичность, зависящую от времени импульсов (STDP), для адаптивной настройки весов; переход на быстрое преобразование Фурье по основанию 2 для снижения вычислительных затрат до O(N log N); а также затухание мембранного потенциала с учетом волатильности.
| имя | Описание |
|---|---|
| 01 Fourier SNN RSI MACD.mq5 | Торговый робот, реализующий модель |
| i.set | Входные параметры для оптимизации при тестировании |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/23426
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Форма ценового ряда: Введение в топологический анализ данных и вложение Такенса в MQL5
Интерактивное управление зонами спроса и предложения на MQL5 (Часть I): От ручной работы к автоматизации жизненного цикла
Адаптивное сглаживание цен в MQL5: фильтр Калмана с оценкой шума без внешних библиотек
Пользовательские инструменты отладки и профилирования для разработки на MQL5 (Часть II): Профилирование советников и тестирование торговой логики
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования