От скользящей средней с фиксированными параметрами к адаптивной фильтрации (Часть 2): Реализация индикатора SAMA_NLMS на MQL5
Введение
Вы уже знакомы с концепцией NLMS из Части 1. Однако на практике перенос уравнения обновления из вычислительного блокнота в код MQL5 часто приводит к проблемам, существенным для трейдеров и разработчиков: модель может обучаться на формирующемся баре, становиться численно неустойчивой на данных без изменений, искажаться из-за одиночных ценовых всплесков и выдавать другие значения в реальном времени после перезапуска терминала, поскольку внутреннее состояние весов зависит от того, какая именно история была обработана. В этой части SAMA рассматривается уже не просто как формула, а как программное обеспечение для реальной эксплуатации. Здесь NLMS встроен в готовый к установке на график индикатор MQL5 с корректно организованными буферами, проверкой входных параметров, ограничением ошибки на основе ATR, адаптацией μ по коэффициенту эффективности Кауфмана, затуханием весов и их необязательной нормализацией, обязательным этапом прогрева и правилом обучения только на закрытых барах. Цель ясна: предоставить файл SAMA_NLMS.mq5, который можно скомпилировать, подключить к графику и использовать в торговых сценариях без явной нестабильности или неожиданного перерисовывания.
Раздел 1: Полный код индикатора
Создайте в MetaEditor новый файл индикатора с именем SAMA_NLMS.mq5 и вставьте в него следующий код:
//+------------------------------------------------------------------+ //| SAMA_NLMS.mq5 | //| Self-Adaptive Moving Average via NLMS Online | //+------------------------------------------------------------------+ #property description "Self-Adaptive Moving Average using Normalized LMS (NLMS) algorithm." #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 1 //--- Plot 0: SAMA Line with dynamic slope color formatting #property indicator_label1 "SAMA" #property indicator_type1 DRAW_COLOR_LINE #property indicator_color1 clrMediumSeaGreen,clrCrimson,clrSlateGray #property indicator_width1 2 #property indicator_style1 STYLE_SOLID //+------------------------------------------------------------------+ //|Enumerations for Input Transformations | //+------------------------------------------------------------------+ enum ENUM_INPUT_MODE { INPUT_PRICE = 0, // Option A: Raw Prices INPUT_DIFF = 1, // Option B: Differences (Delta) INPUT_RET = 2 // Option C: Returns (Percentage Change) }; //+------------------------------------------------------------------+ //| Input Parameters | //+------------------------------------------------------------------+ input ENUM_INPUT_MODE inp_mode = INPUT_PRICE; // Data transformation input mode input int inp_filter_length = 14; // Filter length (Adaptive weight count) input double inp_learning_rate = 0.05; // Learning rate (Base Step Size Mu) input bool inp_use_close = true; // Price: true = Close; false = Typical (H+L+C)/3 input double inp_epsilon = 1e-8; // Epsilon for numerical division safety input double inp_leak = 0.0001; // Forgetting factor / Leakage weight clamp input bool inp_use_atr_clamp = true; // Use ATR error clamping option input int inp_atr_period = 14; // ATR Period for error boundaries input double inp_error_atr_mult = 3.0; // Max allowed error multiplier (Mult * ATR) input bool inp_use_adaptive_lr = true; // Dynamic step size adjustment via ER input int inp_er_period = 10; // Efficiency Ratio window period input bool inp_normalize_weights = true; // Force adaptive weights sum to 1.0 input int inp_warmup_bars = 500; // Historical background initialization loop //+------------------------------------------------------------------+ //| Indicator Buffers | //+------------------------------------------------------------------+ double g_sama_buffer[]; // Main display buffer double g_color_buffer[]; // Derivative slope color assignment matrix //+------------------------------------------------------------------+ //| Global State Variables | //+------------------------------------------------------------------+ double g_weights[]; // Memory matrix containing adaptive weight vector int g_atr_handle = INVALID_HANDLE; // Managed calculation pointer handle for core system ATR double g_atr_buffer[]; // Direct memory block array for streaming ATR inputs //+------------------------------------------------------------------+ //| Helper: Get the raw localized price | //+------------------------------------------------------------------+ double GetSourcePrice(const double &close[], const double &high[], const double &low[], const int i) { return(inp_use_close ? close[i] : (high[i] + low[i] + close[i]) / 3.0); } //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Parameter Bounds Sanitization Checking if(inp_filter_length < 2 || inp_learning_rate <= 0.0 || inp_learning_rate > 2.0 || inp_warmup_bars < 0 || inp_er_period < 2) { Alert("SAMA_NLMS Error: Invalid configuration values detected."); return(INIT_PARAMETERS_INCORRECT); } //--- Initialize ATR Handle if required if(inp_use_atr_clamp) { g_atr_handle = iATR(_Symbol, _Period, inp_atr_period); if(g_atr_handle == INVALID_HANDLE) { Print("SAMA_NLMS: Failed to open system iATR structural handle."); return(INIT_FAILED); } } //--- Bind structural index buffer handles to terminal engine SetIndexBuffer(0, g_sama_buffer, INDICATOR_DATA); SetIndexBuffer(1, g_color_buffer, INDICATOR_COLOR_INDEX); //--- Shift processing view beyond window boundaries to hide processing artifacts PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, inp_filter_length + inp_warmup_bars + inp_er_period); //--- Allocate structural filter depth to weight vectors ArrayResize(g_weights, inp_filter_length); ArrayInitialize(g_weights, 1.0 / (double)inp_filter_length); IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("SAMA_NLMS(Len=%d, Leak=%.5f)", inp_filter_length, inp_leak)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int structural_minimum = inp_filter_length + 2; if(inp_use_adaptive_lr) structural_minimum = MathMax(structural_minimum, inp_er_period + 2); if(rates_total <= (structural_minimum + inp_warmup_bars)) return(0); //--- Linear continuous buffer optimization strategy double source[], tr_input[]; if(ArrayResize(source, rates_total) < 0 || ArrayResize(tr_input, rates_total) < 0) return(0); //--- Map transformations into contiguous execution memory cache for(int i = 0; i < rates_total; i++) { source[i] = GetSourcePrice(close, high, low, i); if(i > 0) { if(inp_mode == INPUT_PRICE) tr_input[i] = source[i]; else if(inp_mode == INPUT_DIFF) tr_input[i] = source[i] - source[i - 1]; else if(inp_mode == INPUT_RET) tr_input[i] = (source[i - 1] != 0.0) ? ((source[i] - source[i - 1]) / source[i - 1]) : 0.0; } else tr_input[i] = 0.0; } //--- Handle core execution loops state initializations int start_idx; if(prev_calculated == 0) { ArrayInitialize(g_weights, 1.0 / (double)inp_filter_length); start_idx = structural_minimum; //--- Wipe stale arrays out of drawing tracks for(int i = 0; i < start_idx; i++) { g_sama_buffer[i] = EMPTY_VALUE; g_color_buffer[i] = EMPTY_VALUE; } } else { start_idx = prev_calculated - 1; } //--- Safely retrieve ATR mapping parameters (Non-Series Normal Handling) if(inp_use_atr_clamp) { ArrayResize(g_atr_buffer, rates_total); if(CopyBuffer(g_atr_handle, 0, 0, rates_total, g_atr_buffer) <= 0) return(0); } //--- Main Core Adaptive Filtering Compute Execution for(int i = start_idx; i < rates_total; i++) { double target = tr_input[i]; //--- Step 1: Compute total vector transformation energy double energy = 0.0; for(int j = 0; j < inp_filter_length; j++) { double p = tr_input[i - 1 - j]; energy += p * p; } //--- Step 2: Extract current structural adaptation state prediction double predicted = 0.0; for(int j = 0; j < inp_filter_length; j++) { predicted += g_weights[j] * tr_input[i - 1 - j]; } //--- Step 3: Quantify dynamic estimation error deviation metric double error = target - predicted; //--- Strict ATR volatility boundary error calculation clamp if(inp_use_atr_clamp && i >= inp_atr_period) { double atr = g_atr_buffer[i]; double max_error = inp_error_atr_mult * atr; if(inp_mode == INPUT_RET && source[i - 1] != 0.0) max_error /= source[i - 1]; error = MathMin(MathMax(error, -max_error), max_error); } //--- Step 4: Perform optimization adjustment updates on completed intervals if(i < rates_total - 1) { double mu = inp_learning_rate; //--- Process Kaufman Efficiency Ratio Adaptive Engine if(inp_use_adaptive_lr && i >= inp_er_period) { double net_direction = MathAbs(source[i] - source[i - inp_er_period]); double net_volatility = 0.0; for(int k = 0; k < inp_er_period; k++) { net_volatility += MathAbs(source[i - k] - source[i - k - 1]); } double efficiency_ratio = (net_volatility > 0.0) ? (net_direction / net_volatility) : 0.0; mu *= (0.5 + efficiency_ratio); } //--- Standardized Classical NLMS normalization step double normalized_lr = mu / (inp_epsilon + energy); //--- Apply optimization weight corrections for(int j = 0; j < inp_filter_length; j++) { g_weights[j] = (1.0 - inp_leak) * g_weights[j] + (normalized_lr * error * tr_input[i - 1 - j]); } //--- Dynamic execution bounds weight normalization protection if(inp_normalize_weights) { double weight_sum = 0.0; for(int j = 0; j < inp_filter_length; j++) weight_sum += g_weights[j]; if(MathAbs(weight_sum) > 1e-12) { for(int j = 0; j < inp_filter_length; j++) g_weights[j] /= weight_sum; } } } //--- Step 5: Convert state matrix evaluations to absolute price coordinates double transformed_output = 0.0; if(inp_mode == INPUT_PRICE) transformed_output = predicted; else if(inp_mode == INPUT_DIFF) transformed_output = source[i - 1] + predicted; else if(inp_mode == INPUT_RET) transformed_output = source[i - 1] * (1.0 + predicted); //--- Sanitize anomalous computations if(!MathIsValidNumber(transformed_output)) g_sama_buffer[i] = (i > 0) ? g_sama_buffer[i - 1] : source[i]; else g_sama_buffer[i] = transformed_output; //--- Multi-Buffer dynamic derivative trend color classification if(i > structural_minimum && g_sama_buffer[i - 1] != EMPTY_VALUE) { double slope = g_sama_buffer[i] - g_sama_buffer[i - 1]; if(slope > 0.0) g_color_buffer[i] = 0.0; else if(slope < 0.0) g_color_buffer[i] = 1.0; else g_color_buffer[i] = 2.0; } else g_color_buffer[i] = 2.0; } return(rates_total); } //+------------------------------------------------------------------+
Справочник по входным параметрам
Прежде чем пошагово рассмотреть логику работы, разберём, за что отвечает каждый входной параметр и как он влияет на поведение фильтра. Используйте этот раздел как справочник по параметрам, к которому можно возвращаться при настройке индикатора для разных торговых инструментов.
| Параметр | Тип | По умолчанию | Допустимый диапазон | Практический эффект |
|---|---|---|---|---|
| inp_mode | enum | INPUT_PRICE | PRICE / DIFF / RET | Определяет, на чем будет обучаться фильтр. PRICE = исходная цена; DIFF = изменение от бара к бару (импульс); RET = процентная доходность (масштабно-инвариантная). |
| inp_filter_length | int | 14 | ≥ 2 | Количество адаптивных весов (глубина расчёта). Чем больше длина фильтра, тем сильнее сглаживание, но выше вычислительная нагрузка. SAMA сохраняет эффективность и при малой длине, поскольку адаптируется, а не увеличивает окно. |
| inp_learning_rate | double | 0,05 | (0; 2,0) | Базовый размер шага μ. Более высокое значение ускоряет отслеживание изменений, но повышает риск колебаний; μ ≤ 1,0 — безопасный диапазон, обеспечивающий быструю реакцию. |
| inp_use_close | bool | true | — | Источник цены: true = цена закрытия, false = типичная цена ((максимум + минимум + цена закрытия)/3). |
| inp_epsilon | double | 1e-8 | малое значение > 0 | Нижний порог для знаменателя при нормировке, предотвращающий деление на ноль. Имеет значение только тогда, когда энергия входного сигнала падает почти до нуля. |
| inp_leak | double | 0,0001 | (0; ~0,01) | Коэффициент забывания γ. Чем выше значение, тем быстрее веса затухают к нулю, что несколько снижает быстроту реакции, но повышает устойчивость в долгосрочной перспективе. |
| inp_use_atr_clamp | bool | true | — | Позволяет ограничить величину ошибки значением, кратным ATR, чтобы отдельный скачок не мог исказить веса. |
| inp_atr_period | int | 14 | ≥ 1 | Глубина расчёта ATR, используемого для ограничения ошибки. |
| inp_error_atr_mult | double | 3,0 | > 0 | Допустимая величина ошибки в единицах ATR, при превышении которой применяется ограничение. Чем ниже значение, тем жёстче подавление скачков. |
| inp_use_adaptive_lr | bool | true | — | На каждом баре масштабирует μ с помощью коэффициента эффективности Кауфмана. |
| inp_er_period | int | 10 | ≥ 2 | Окно расчета коэффициента эффективности. |
| inp_normalize_weights | bool | true | — | При каждом обновлении приводит сумму весов вектора к 1,0, сохраняя выходное значение в масштабе цены. Настоятельно рекомендуется использовать в режиме PRICE. |
| inp_warmup_bars | int | 500 | ≥ 0 | Количество баров, обрабатываемых без отображения значений перед началом построения линии, чтобы скрыть переходный процесс сходимости. |
Таблица 1: Справочник входных параметров
Практичный начальный набор настроек для большинства валютных пар: оставьте значения по умолчанию, но установите для inp_mode значение INPUT_RET на инструментах с сильно различающимися масштабами цен или во время сессий с низкой ликвидностью.
Раздел 2: Разбор кода — ключевые проектные решения
Оптимизированная архитектура: выполнение непосредственно в основном цикле
Все основные векторные операции выполняются непосредственно внутри основного цикла OnCalculate. Это дает два конкретных преимущества:
- Эффективность выполнения — выполнение непосредственно в основном цикле устраняет накладные расходы на вызовы функций и необходимость во внешних кольцевых буферах, снижая загрузку ЦП при высокой частоте поступления тиков.
- Прямая индексация со смещением — обращение к историческим барам с помощью простой арифметики индексов (i − 1 − j) позволяет избежать накладных расходов на сдвиг элементов массива и повышает стабильность вычислений.
Инициализация весов
Инициализация адаптивной модели с обнуленными состояниями приводит к нестабильному отслеживанию и медленной сходимости. На первом проходе (prev_calculated == 0) код инициализирует g_weights равномерным распределением весов, при котором каждому из N элементов присваивается значение 1/N. Это создает нейтральное начальное состояние, эквивалентное простой скользящей средней, устраняет артефакты прогрева и обеспечивает отображение графика без искажений, как только доступно достаточно баров для заданной глубины расчёта.
Стабильность в реальном времени и защита при многократных тиковых обновлениях
Условие if(i < rates_total - 1) обеспечивает обновление весов только на закрытых барах. Текущий формирующийся бар используется для прогнозирования, но никогда — для обучения. Такое разделение предотвращает дрейф весов внутри бара и устраняет искажение данных, вызванное быстрыми разнонаправленными тиковыми изменениями цены в пределах одной свечи: историческая линия остается воспроизводимой, а для текущего бара по-прежнему рассчитывается прогноз на основе уже сформированных весов.
Чувствительность к скорости обучения и границы устойчивости
Нормированная скорость обучения μ определяет быстроту реакции при отслеживании цены. Поскольку обновление нормируется по энергии входного сигнала, масштабная инвариантность шага сохраняется в силу самой структуры алгоритма. В режимах DIFF и RET это обеспечивает высокую согласованность между классами активов. В режиме INPUT_PRICE сохраняется некоторая чувствительность к масштабу цен, поскольку порог ограничения ошибки на основе ATR выражен в единицах цены. Тем не менее нормировка по энергии входного сигнала предотвращает численное переполнение как для инструментов с низким уровнем цены (EURUSD), так и для инструментов с высоким уровнем цены (золото, индексы).
Хотя математическая граница устойчивости NLMS по скорости обучения составляет 2,0, значение μ не выше 1,0 обеспечивает быстрое и устойчивое отслеживание цены.
Таблица 2: Анализ чувствительности к нормированной скорости обучения μ (мю).
| Значение μ | Поведение |
|---|---|
| 0,001 – 0,010 | Консервативная адаптация, плавные кривые выходного сигнала |
| 0,010 – 0,100 | Сбалансированная конфигурация — оптимальная конфигурация для стандартных рыночных режимов |
| 0,100 – 1,000 | Высокая чувствительность отслеживания, точная подстройка при значительных пробоях |
| 1,000 – 2,000 | Агрессивная адаптация, приближающаяся к теоретическому пределу |
Анализ чувствительности нормированной скорости обучения (μ). В данном руководстве реакция фильтра классифицируется по степени интенсивности — от консервативного сглаживания до агрессивного отслеживания. Благодаря динамической нормировке величины шага по энергии вектора цен алгоритм сохраняет устойчивость независимо от масштаба цен при работе с различными инструментами. С математической точки зрения граница устойчивости составляет 2,0. Задание значений выше этого предела может привести к колебаниям весов или взрыву градиента.
Раздел 3: Установка и отображение индикатора
- Откройте MetaEditor (клавиша F4 в MetaTrader 5).
- Выберите "Файл" → "Создать" → "Пользовательский индикатор".
- Назовите индикатор SAMA_NLMS, вставьте полный код и нажмите "Компилировать" (F7).
- В MetaTrader 5 откройте любой график, перейдите в меню "Вставка" → "Индикаторы" → "Пользовательские" и выберите SAMA_NLMS.
- Задайте входные параметры в диалоговом окне и нажмите "ОК".
На графике появится линия SAMA, цвет которой зависит от ее наклона. Она отображается цветом MediumSeaGreen при восходящем наклоне (восходящий тренд), цветом Crimson — при нисходящем наклоне (нисходящий тренд) и цветом SlateGray — в периоды бокового движения или переходных состояний. На первый взгляд линия будет напоминать EMA, но понаблюдайте за ее поведением при смене рыночных режимов — вы заметите, что во время сильных трендов она точнее следует за ценой, а в периоды беспорядочных колебаний ее запаздывание увеличивается.

Рис. 1: Индикатор SAMA на графике EURUSD с таймфреймом H1 демонстрирует быстрое и точное следование за ценой во время сильного восходящего тренда и плавную стабилизацию в боковом диапазоне консолидации.
Раздел 4: Практические сценарии использования
В качестве динамического фильтра тренда
Используйте SAMA для классификации рыночных режимов по структуре движения цены. Если цена находится выше линии SAMA, ищите только возможности для открытия длинных позиций. Если цена опустится ниже этой линии, сосредоточьтесь исключительно на коротких позициях. Благодаря динамической адаптации фильтр автоматически приближается к цене при стремительных трендах. При хаотичных колебаниях цены в боковом диапазоне его линия становится более горизонтальной. Такое поведение позволяет исключить ложные смены рыночного режима по сравнению с традиционными скользящими средними с фиксированным периодом.
//+------------------------------------------------------------------+ //| Example: Querying the SAMA line from a prior indicator handle | //+------------------------------------------------------------------+ double sama_value[1]; if(CopyBuffer(sama_handle, 0, 1, 1, sama_value) > 0) { if(close_price > sama_value[0]) { //--- Bullish regime: Allow long execution pathways only } else { //--- Bearish regime: Allow short execution pathways only } }
В качестве динамического ориентира поддержки и сопротивления
Веса SAMA непрерывно корректируются с учетом недавних ценовых колебаний. Благодаря этому линия индикатора естественным образом тяготеет к ценовым зонам, в которых рынок принимает текущий уровень цены. На трендовых рынках линия выступает в роли быстро реагирующей кривой поддержки или сопротивления, следующей за ценой. На боковых рынках линия располагается вблизи структурной средней цены актива.
Сочетание со скользящей средней с фиксированным периодом для получения сигналов пересечения
Вы можете формировать надежные сигналы пересечения, сочетая SAMA со стандартной простой скользящей средней (SMA) с фиксированным периодом 50. Такая комбинация двух индикаторов формирует сигналы смены тренда, устойчивые к ложным пересечениям. Основное преимущество заключается в том, что SAMA динамически регулирует свою внутреннюю скорость следования за ценой. Скорость ее следования за рынком не остается жестко фиксированной.
Раздел 5: Понимание ограничений
Ни один алгоритмический индикатор не обеспечивает безупречного решения для торговли. Архитектура SAMA_NLMS обладает определёнными математическими свойствами, которые необходимо учитывать перед началом использования:
- Сильная зависимость от траектории обучения на исторических данных: SAMA использует механизм рекурсивной онлайн-оптимизации. Точная структура матрицы весов для текущего бара полностью зависит от непрерывной последовательности исторических обновлений, обработанных с момента инициализации графика. Это создаёт важный нюанс работы индикатора, который необходимо учитывать в реальной торговле:
- Глубина истории: при загрузке графика с 5 000 баров текущие векторы весов будут немного отличаться от тех, которые получаются при загрузке графика с 50 000 баров.
- Смена таймфрейма: переключение на другой таймфрейм приводит к полной очистке памяти. Алгоритм должен с нуля сформировать историю адаптации на новом таймфрейме.
- Пересчёты в терминале: если соединение с брокером прервётся и терминал принудительно обновит данные графика, внутренняя траектория изменения весов будет пересчитана с начала доступной истории.
- Последствия для торговли и меры по снижению риска: из-за этой зависимости от траектории торговые сигналы в реальном времени могут временно расходиться с линиями индикатора при тестировании на исторических данных, если глубина истории не совпадает в точности. Для снижения этого риска в индикаторе реализован обязательный цикл инициализации, строго задаваемый параметром inp_warmup_bars. Этот параметр обязывает алгоритм обработать в фоновом режиме не менее 500 баров, прежде чем отображать значения индикатора для торговли. Этот этап прогрева в фоновом режиме стабилизирует массив весов, устраняя влияние различий в начальных условиях и обеспечивая единообразие сигналов при перезагрузках терминала.
- Чрезмерная адаптация на рынках с низким объёмом торгов: если использовать режим исходных цен (INPUT_PRICE) в праздничные часы, когда рынок неликвиден и находится в боковом движении, веса могут слишком сильно подстраиваться под незначительный структурный шум. Эта проблема возникает из-за недостаточной дисперсии исходных данных. Эту проблему можно легко устранить, переключив режим преобразования на процентную доходность (INPUT_RET).
- Зависимость от эпсилон для защиты от деления на ноль: на этапе нормировки NLMS скорость обучения делится на энергию входного сигнала. Если цена на рынке совсем перестаёт меняться, эта энергия приближается к нулю. Защита расчёта от критических ошибок деления на ноль полностью зависит от заданного вами значения эпсилон (inp_epsilon).
Раздел 6: Расширение возможностей индикатора
Фреймворк SAMA_NLMS.mq5 представляет собой отличную модульную основу для дальнейших количественных исследований:
- Альтернативные конвейеры преобразования данных: перечисление inp_mode можно расширить. Вы можете легко интегрировать сложные математические преобразования. Например, перед передачей массивов в основной фильтр можно рассчитывать логарифмическую доходность цен, выполнять Z-нормализацию или удалять тренд из ценовых рядов.
- Асимметричное штрафование ошибок: можно изменить цикл обновления весов таким образом, чтобы по-разному учитывать положительные и отрицательные ошибки. Эта настройка позволяет создать асимметричный адаптивный фильтр. Он быстрее отслеживает резкие распродажи на падающем рынке, чем постепенный рост на растущем рынке.
- Иерархии рыночных режимов на нескольких таймфреймах: в рамках одного советника можно инициализировать несколько дескрипторов SAMA для разных таймфреймов. Данная структура позволяет использовать SAMA на графике H4 для определения направления макротренда, SAMA на графике H1 для отслеживания структурных откатов и SAMA на графике M15 для определения сигналов открытия позиций.
Заключение
После выполнения этой части у вас будет работающий индикатор SAMA_NLMS.mq5: он компилируется, отображает линию с окраской в зависимости от наклона и реализует защитные меры, необходимые для практического применения. В частности, индикатор проверяет соблюдение допустимых границ входных параметров, инициализирует веса в соответствии с нейтральным априорным распределением, обновляет веса только на закрытых барах (без обучения внутри бара), ограничивает экстремальные ошибки с помощью ATR, при необходимости нормализует вектор весов, чтобы выходные значения оставались в масштабе цен, и поддерживает масштабирование скорости обучения по коэффициенту эффективности Кауфмана. Эти меры снижают риск наиболее распространённых сбоев, но не устраняют фундаментальное свойство: веса SAMA зависят от траектории. Чтобы уменьшить расхождения между сеансами работы, используйте параметр числа баров прогрева для принудительного фонового обучения (по умолчанию — 500), отдавайте предпочтение INPUT_RET для обеспечения масштабной инвариантности на низколиквидных инструментах или инструментах с существенно различающимися масштабами цен и сохраняйте μ в диапазоне консервативных и сбалансированных значений (≤ 1,0), если вам не требуется намеренно очень агрессивное отслеживание.
Контрольный список перед практическим применением: скомпилируйте и загрузите SAMA_NLMS, убедитесь, что на формирующемся баре обучение не выполняется, проверьте поведение при повторном подключении или смене таймфрейма (используйте этап прогрева) и оцените чувствительность к параметрам (inp_mode, inp_filter_length, inp_learning_rate — скорость обучения, inp_leak, inp_error_atr_mult). В заключительной части мы количественно оценим, влияют ли эти особенности адаптации на результаты торговли: создадим советник для сравнительного тестирования SAMA и SMA/EMA/KAMA при согласованных параметрах, экспортируем диагностические данные в CSV и запустим конвейер анализа на Python для сравнения с базовыми вариантами и пошагового walk-forward-тестирования на нескольких активах.
Программа, использованная в статье:
| # | Название | Тип | Описание |
|---|---|---|---|
| 1 | SAMA_NLMS.mq5 | Пользовательский индикатор | Исходный код пользовательского индикатора, реализующего механизм адаптивной фильтрации на основе нормализованного метода наименьших средних квадратов. В нём предусмотрены встроенное ограничение ошибки с помощью ATR, режимы преобразования входных данных и динамическое масштабирование скорости обучения с использованием коэффициента эффективности Кауфмана. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/23033
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.