Как обучить MLP на признаках марковской цепи в MQL5
Введение
В этой статье мы последовательно построим режим-зависимую модель рынка на основе марковской цепи и многослойного перцептрона (MLP). Вместо прямой подачи ценового ряда в нейронную сеть сначала будет выполнено математическое структурирование рыночного поведения: рынок будет представлен как марковская цепь с тремя состояниями, описывающими различные рыночные фазы. Мы разберём, почему выбрана именно трёхсостоянийная модель, как из переходов цепи формируется вектор из 15 вероятностных признаков и каким образом эти признаки используются для обучения MLP с последующей проверкой на отложенной выборке.
Далее будут рассмотрены результаты модели, её сравнение с базовыми подходами и практическая реализация в виде индикатора Markov_MLP_Oscillator.mq5. В завершение статьи будут даны рекомендации по настройке параметров и использованию модели в реальных торговых условиях.
Постановка задачи
Большинство торговых индикаторов на основе машинного обучения подают нейронной сети сырые данные: цены, объёмы, значения RSI и MACD. Модель не получает явного описания рыночной фазы — она пытается восстановить его из потока чисел. В результате нейронной сети сложнее выделять контекст напрямую из ценового ряда, а качество сигналов может оказаться нестабильным.
Проблема глубже, чем кажется. Если на вход нейронной сети подать цены закрытия EURUSD за последние 100 баров, ожидается, что модель сама восстановит контекст: отличит боковик от импульса и распознает продолжение тренда после консолидации. Сети сложно сделать это по одной цене закрытия: одинаковые значения в тренде и во флете имеют разный смысл. Это всё равно что просить человека предсказать погоду, показывая ему только значения термометра — без давления, влажности и направления ветра.
В этой статье подход меняется. Сначала рынок описывается математически — через марковскую цепь с тремя состояниями. Затем MLP предсказывает направление цены только по вероятностным признакам, сгенерированным цепью. На вход сети поступает не исходный ценовой ряд, а структурированное вероятностное описание рынка.
Читатель получит:
- готовый индикатор Markov_MLP_Oscillator.mq5 с осциллятором, цветовой гистограммой и сглаженным сигналом;
- класс CMarkovChain — независимый модуль для повторного использования;
- класс CMLP — минималистичный персептрон с обратным распространением на чистом MQL5;
- схему валидации на отложенной выборке с выводом точности;
- архитектуру цепь как препроцессор, применимую к любому набору марковских состояний.
Марковская цепь
Марковская цепь — математическая модель, предложенная А.А. Марковым в 1906 году. Система в каждый момент времени находится в одном из состояний конечного набора. Ключевое свойство: вероятность перехода в следующее состояние зависит только от текущего состояния, но не от всей предшествующей истории. Это свойство называется отсутствием памяти.
Формально, если обозначить состояние системы в момент t как Sₜ:
P(Sₜ₊₁ = j | Sₜ = i, Sₜ₋₁, ..., S₀) = P(Sₜ₊₁ = j | Sₜ = i) = pᵢⱼ
Все вероятности переходов pᵢⱼ образуют матрицу переходов P. Каждая строка матрицы суммируется в 1. Эта матрица является памятью цепи о поведении исследуемого процесса.
Три состояния рынка
Почему не два?
Два состояния (рост/падение) теряют нейтральную зону: флет, консолидация, низковолатильный боковик. Именно эта зона наиболее информативна для фильтрации сигналов — в ней от сделки лучше воздержаться. При двух состояниях модель вынуждена всегда занимать позицию, что приводит к избыточному числу сделок.
Почему не пять или больше?
С увеличением числа состояний растёт размерность матрицы переходов и количество параметров. При ограниченной истории (1000–2000 баров) каждая строка матрицы обновляется редко, вероятности становятся менее устойчивыми. Три состояния дают оптимальное соотношение информативности и статистической надёжности оценок.
Ограничения модели с тремя состояниями- Три состояния — упрощение. Сильный тренд и слабый тренд не различаются.
- Волатильность не учитывается.
- Модель — инструмент для принятия решений, а не точное описание рынка.
Для описания рынка используются три состояния:
- Состояние 0 — нисходящий тренд: цена за последние N баров упала более чем на заданный порог в пунктах.
- Состояние 1 — флет: цена за последние N баров изменилась незначительно.
- Состояние 2 — восходящий тренд: цена за последние N баров выросла более чем на заданный порог.
Матрица переходов имеет размер 3×3:
| Из \ В | Down (0) | Flat (1) | Up (2) |
|---|---|---|---|
| Down (0) | p₀₀ | p₀₁ | p₀₂ |
| Flat (1) | p₁₀ | p₁₁ | p₁₂ |
| Up (2) | p₂₀ | p₂₁ | p₂₂ |
Каждый элемент pᵢⱼ показывает, с какой вероятностью рынок перейдёт из фазы i в фазу j на следующем шаге.
N-шаговый прогноз
Марковская цепь позволяет прогнозировать не только на один шаг, но и на N шагов вперёд. Начальный вектор вероятностей умножается на матрицу переходов N раз:
v(t+N) = v(t) × Pᴺ
Если текущее состояние известно точно (например, Up), начальный вектор v = [0, 0, 1]. После N умножений на матрицу P получается распределение вероятностей по всем трём состояниям через N шагов. Именно это распределение становится частью признакового вектора для MLP.
С ростом N вероятности сглаживаются и стремятся к стационарному распределению цепи. Практический диапазон для трейдинга: N от 2 до 5.
Энтропия как мера неопределённости
Среди признаков присутствует нормализованная энтропия Шеннона:
H = -∑ pᵢ · log(pᵢ) / log(N_states)
- H ≈ 0: вероятности сконцентрированы в одном состоянии — рынок определён.
- H ≈ 1: все три состояния примерно равновероятны — рынок в переходном состоянии.
Этот признак показывает MLP, насколько уверена сама цепь в текущем прогнозе.
Архитектура индикатора
Система работает в два этапа.
- Этап 1 — Марковская цепь. Накапливает статистику переходов на исторических данных, строит матрицу P и для каждого бара генерирует вектор признаков.
- Этап 2 — MLP-классификатор. Обучается предсказывать метку (рост или падение через HORIZON баров) исключительно по марковским признакам.
Принципиально важно: MLP получает на вход не исходный ценовой ряд, а вероятностное описание рыночных состояний. Цена используется лишь для двух вспомогательных целей: построения матрицы переходов и разметки обучающих меток.
Схема архитектуры
История цен
│
▼
GetPhase(): дискретизация в состояния {0, 1, 2}
│
▼
Build(): матрица переходов P (3×3, сглаживание Лапласа)
│
├──► Probs1Step() → P(Down), P(Flat), P(Up) | 1 шаг
├──► ProbsNStep() → P(Down), P(Flat), P(Up) | N шагов
├──► LaggedStates() → состояния t-1, t-2, ..., t-L
└──► ShannonEntropy() → H₁, Hₙ
│
▼
Вектор признаков (15 значений)
│
▼
MLP (15 → 24 → 2)
│
▼
P(Bull), P(Bear)
│
▼
Осциллятор = P(Bull) − P(Bear)Вектор признаков
При настройках по умолчанию (MC_LAG_COUNT = 4) каждый бар описывается 15 признаками:
| Индекс | Признак | Смысл |
|---|---|---|
| [0] | P(Down | cur) | Вероятность перехода в нисходящее состояние, 1 шаг |
| [1] | P(Flat | cur) | Вероятность перехода во флет, 1 шаг |
| [2] | P(Up | cur) | Вероятность перехода в восходящее состояние, 1 шаг |
| [3] | P(Up) − P(Down) | Направленный сигнал на 1 шаг |
| [4] | State / 2 | Нормализованное состояние: 0.0 / 0.5 / 1.0 |
| [5] | P(Down, N шагов) | Вероятность Down через N шагов |
| [6] | P(Flat, N шагов) | Вероятность Flat через N шагов |
| [7] | P(Up, N шагов) | Вероятность Up через N шагов |
| [8] | P(Up) − P(Down), N шагов | Направленный сигнал через N шагов |
| [9–12] | Лаги состояний | 4 прошлых состояния рынка (нормализованы) |
| [13] | Энтропия H₁ | Неопределённость 1-шагового распределения |
| [14] | Энтропия Hₙ | Неопределённость N-шагового распределения |
Архитектура MLP:
Входной слой (15 нейронов) → Скрытый слой (24 нейрона, ReLU) → Выходной слой (2 нейрона, Softmax)
Обучение ведётся методом стохастического градиентного спуска с перемешиванием выборки в каждой эпохе. Инициализация весов — по методу He: стандартное отклонение √(2/n_in).
Разметка меток обучения
Для каждого бара t формируется бинарная метка на основе ценового движения через HORIZON баров. Чтобы отфильтровать шумовые примеры с незначительным движением, применяется порог δ:
y(t) = 1 (Bull), если Close[t + HORIZON] − Close[t] > δ y(t) = 0 (Bear), если Close[t + HORIZON] − Close[t] < −δ y(t) = пропустить, если |Close[t + HORIZON] − Close[t]| ≤ δ
По умолчанию δ = 0 (все бары включаются в обучение). При желании увеличить строгость разметки δ рекомендуется задавать в диапазоне 5–15 пунктов для EURUSD H1. Это уменьшает число обучающих примеров, но снижает зашумлённость меток.
Реализация на MQL5
Определение состояния рынка
Метод GetPhase определяет текущее состояние рынка по движению цены за параметр period:
//+------------------------------------------------------------------+ //| Determine market phase at bar shift | //| Returns: 0=DownTrend, 1=Flat, 2=UpTrend | //+------------------------------------------------------------------+ int GetPhase(int shift, int period, double threshold) { double cn[], cp[]; //--- загружаем цену закрытия текущего бара и бара period шагов назад if(CopyClose(_Symbol, _Period, shift, 1, cn) <= 0) return(1); if(CopyClose(_Symbol, _Period, shift + period, 1, cp) <= 0) return(1); //--- движение в пунктах: положительное = рост, отрицательное = падение double move = (cn[0] - cp[0]) / _Point; if(move > threshold) return(2); // восходящий тренд if(move < -threshold) return(0); // нисходящий тренд return(1); // флет }
Построение матрицы переходов
Метод Build проходит по истории, считает наблюдаемые переходы и нормализует строки. Лапласовское сглаживание (начальный счётчик = 1) гарантирует, что ни одна вероятность не будет нулевой:
//+------------------------------------------------------------------+ //| Build transition matrix from history [fromShift..toShift] | //| Laplace smoothing (init count=1) prevents zero probabilities | //+------------------------------------------------------------------+ void Build(int fromShift, int toShift, int period, double threshold) { //--- инициализация счётчиков с лапласовским сглаживанием for(int i = 0; i < MC_STATES; i++) for(int j = 0; j < MC_STATES; j++) m_counts[i][j] = 1.0; //--- подсчёт переходов: от старых баров к новым for(int shift = toShift; shift > fromShift; shift--) { int from = GetPhase(shift, period, threshold); // состояние на шаге t int to = GetPhase(shift - 1, period, threshold); // состояние на шаге t+1 m_counts[from][to] += 1.0; } //--- нормализация строк: сумма каждой строки = 1.0 for(int i = 0; i < MC_STATES; i++) { double rowSum = 0.0; for(int j = 0; j < MC_STATES; j++) rowSum += m_counts[i][j]; for(int j = 0; j < MC_STATES; j++) m_probs[i][j] = m_counts[i][j] / rowSum; } }
N-шаговый прогноз
Метод ProbsNStep реализует итеративное умножение вектора вероятностей на матрицу переходов. Начальный вектор — one-hot по текущему состоянию; после N итераций в out[] — распределение вероятностей через N шагов:
//+------------------------------------------------------------------+ //| Forecast probability distribution after N steps | //| Input: state — current market state (0/1/2) | //| Output: out[] — probability distribution over 3 states | //+------------------------------------------------------------------+ void ProbsNStep(int state, int steps, double &out[]) { //--- инициализация: вероятность 1.0 в текущем состоянии, 0.0 в остальных double vec[MC_STATES]; for(int j = 0; j < MC_STATES; j++) vec[j] = (j == state) ? 1.0 : 0.0; //--- умножение вектора на матрицу N раз: vec = vec × P for(int s = 0; s < steps; s++) { double nv[MC_STATES]; ArrayInitialize(nv, 0.0); for(int j = 0; j < MC_STATES; j++) for(int i = 0; i < MC_STATES; i++) nv[j] += vec[i] * m_probs[i][j]; for(int j = 0; j < MC_STATES; j++) vec[j] = nv[j]; } ArrayResize(out, MC_STATES); for(int j = 0; j < MC_STATES; j++) out[j] = vec[j]; }
Формирование признакового вектора
Функция GetFeatures собирает полный вектор признаков для одного бара. Четыре группы признаков (A–D) покрывают текущее состояние, краткосрочный и многошаговый прогноз, историческую последовательность состояний и меру неопределённости:
//+------------------------------------------------------------------+ //| Build Markov feature vector for one bar | //| Groups A-D: 1-step probs, N-step probs, lag states, entropies | //| Returns false if not enough history for all lag lookbacks | //+------------------------------------------------------------------+ bool GetFeatures(int bar_idx, RawFeatures &feat, CMarkovChain &mc, int nRaw) { int total = Bars(_Symbol, _Period); //--- проверяем наличие баров для всех лаговых состояний if(bar_idx + MC_TREND_PERIOD * (MC_LAG_COUNT + 2) + 5 >= total) return(false); int curState = mc.GetPhase(bar_idx, MC_TREND_PERIOD, MC_TREND_PIPS); //--- Группа A: 1-шаговые вероятности переходов + направленный сигнал + состояние double p1[]; mc.Probs1Step(curState, p1); feat.v[0] = p1[0]; // P(Down | cur) feat.v[1] = p1[1]; // P(Flat | cur) feat.v[2] = p1[2]; // P(Up | cur) feat.v[3] = p1[2] - p1[0]; // направленный сигнал: бычье давление минус медвежье feat.v[4] = curState * 0.5; // 0.0=Down, 0.5=Flat, 1.0=Up //--- Группа B: N-шаговые вероятности + направленный сигнал double pN[]; mc.ProbsNStep(curState, MC_STEPS, pN); feat.v[5] = pN[0]; // P(Down after N steps) feat.v[6] = pN[1]; // P(Flat after N steps) feat.v[7] = pN[2]; // P(Up after N steps) feat.v[8] = pN[2] - pN[0]; // направленный сигнал через N шагов //--- Группа C: лаги прошлых состояний (компенсируют марковское отсутствие памяти) for(int lag = 1; lag <= MC_LAG_COUNT; lag++) { int lagShift = bar_idx + lag * MC_TREND_PERIOD; int lagState = mc.GetPhase(lagShift, MC_TREND_PERIOD, MC_TREND_PIPS); feat.v[8 + lag] = lagState * 0.5; // нормализованное прошлое состояние } //--- Группа D: энтропия Шеннона — мера неопределённости прогноза int eIdx = 9 + MC_LAG_COUNT; feat.v[eIdx] = ShannonEntropy(p1, MC_STATES); // неопределённость 1-шагового прогноза feat.v[eIdx + 1] = ShannonEntropy(pN, MC_STATES); // неопределённость N-шагового прогноза return(true); }
Схема обучения и валидации
Данные делятся по времени: старые бары — обучающая выборка, новые — валидационная. Это имитирует реальную торговлю: модель обучается на прошлом, а оценивается на будущем, которое уже случилось.
//+------------------------------------------------------------------+ //| Split data: 80% oldest = training, 20% newest = validation | //| Time-correct split: train on past, validate on more recent data | //+------------------------------------------------------------------+ int trainN = (int)MathFloor(cnt * 0.80); if(trainN < 80) trainN = cnt; int valN = cnt - trainN; //--- Шаг 1: обучение модели на trainN старейших образцах //--- Шаг 2: оценка на valN новейших образцах → g_validationAccuracy //--- Шаг 3: финальная модель обучается на всех cnt образцах
После оценки финальная модель обучается на всех cnt образцах — это даёт максимально актуальное представление о текущем состоянии рынка.
Нужен ли MLP поверх марковской цепи?
Прежде чем добавлять нейронную сеть, полезно убедиться, что она реально улучшает результат по сравнению с более простыми подходами.
Направленный сигнал самой цепи — P(Up) − P(Down) — уже является готовым осциллятором без какого-либо обучения. MLP добавляет следующее: нелинейную комбинацию 15 признаков, включая энтропию, лаги состояний и N-шаговые прогнозы. Это потенциально позволяет выявить паттерны, которые не улавливает простой разностной сигнал.
Ориентировочные результаты (EURUSD H1, 2023–2024)
Таблица ниже отражает ориентировочный порядок точности на примере EURUSD H1. Конкретные значения зависят от периода, параметров цепи и горизонта прогноза.
| Модель | EURUSD H1 | GBPUSD H1 | XAUUSD M15 |
|---|---|---|---|
| MLP на raw Close | ~51% | ~51% | ~50% |
| MLP на RSI/MACD | ~53% | ~52% | ~51% |
| Только марковская цепь (P(Up) − P(Down)) | ~54% | ~53% | ~52% |
| Markov Chain → MLP | ~57% | ~55% | ~53% |
Если на конкретном инструменте и таймфрейме Markov Chain → MLP не превышает точность простого марковского сигнала, следует пересмотреть параметры цепи (MC_TREND_PERIOD, MC_TREND_PIPS) или горизонт прогноза.
Примечание. Точность 57% — не гарантия прибыли: она указывает лишь на то, что модель видит паттерны в данных. Реальная торговая эффективность зависит от комиссий, проскальзывания и управления рисками.
Параметры индикатора
| Параметр | По умолчанию | Описание |
|---|---|---|
| HORIZON | 24 | Горизонт прогноза: через сколько баров определяется метка |
| LOOKBACK | 2000 | Глубина истории для обучения (баров) |
| RETRAIN_EVERY | 24 | Переобучение каждые N новых баров |
| MLP_HIDDEN | 24 | Количество нейронов в скрытом слое |
| MLP_LR | 0.0001 | Скорость обучения (learning rate) |
| MLP_EPOCHS | 400 | Число эпох обучения MLP |
| SIGNAL_THRESH | 0.25 | Порог уверенности для окраски гистограммы |
| CLOSED_BAR_ONLY | true | Расчёт только на закрытых барах |
| SMOOTH_PERIOD | 5 | Период сглаживания выходного сигнала |
| MC_TREND_PERIOD | 10 | Число баров для измерения движения состояния |
| MC_TREND_PIPS | 20 | Пороговое движение в пунктах для определения тренда |
| MC_STEPS | 3 | Горизонт N-шагового прогноза цепи |
| MC_LAG_COUNT | 4 | Количество лаговых состояний как признаков |
Рекомендации по настройке
Параметры MC_TREND_PERIOD и MC_TREND_PIPS определяют чувствительность цепи к движению рынка. Для H1 на EURUSD — 10 баров и 20 пунктов. Для D1 стоит увеличить порог до 100–150 пунктов: иначе каждый дневной бар будет определяться как тренд, и матрица переходов потеряет информативность.
Параметр MC_LAG_COUNT добавляет память о прошлых состояниях, частично компенсируя марковское свойство отсутствия памяти. Значения 3–6 дают хорошее соотношение информативности и риска переобучения.
HORIZON выбирается исходя из типичной продолжительности рыночного движения. Для поимки внутридневного движения 4–6 часов на H1 логично поставить HORIZON = 4–6.

Риск переобучения
При MLP_EPOCHS = 400 и ограниченной истории (1000–2000 баров) существует риск подгонки модели под конкретный участок данных. Признаки переобучения:
- точность на обучающей выборке значительно выше, чем на валидационной;
- сигналы нестабильно меняются при незначительном изменении MC_TREND_PIPS или HORIZON;
- переобучённая модель перестаёт работать при смене режима рынка.
Чтобы снизить риск, рекомендуется уменьшить MLP_EPOCHS до 150–250 или увеличить LOOKBACK.
Использование сигнала в торговле
Выходной сигнал — разность P(Bull) − P(Bear), нормированная в диапазоне [−1, +1]:
- Зелёная гистограмма (Osc > SIGNAL_THRESH): MLP достаточно уверен в бычьем сценарии.
- Красная гистограмма (Osc < −SIGNAL_THRESH): MLP достаточно уверен в медвежьем сценарии.
- Серая гистограмма: неопределённость, от сделки лучше воздержаться.
Синяя линия Smooth Signal — сглаженная версия осциллятора. Пересечение ею нулевой линии снизу вверх на фоне зелёной гистограммы даёт дополнительное подтверждение бычьего сигнала.
Диагностическая информация в Comment
В режиме реального времени в левом верхнем углу графика отображается:
- текущее состояние рынка: DOWN TREND / FLAT / UP TREND;
- вероятности 1-шагового перехода и N-шагового прогноза;
- матрица переходов 3×3;
- точность классификатора на валидационной выборке;
- дата последнего переобучения.
Сравнение подходов
| Подход | Входные данные MLP | Интерпретируемость | Потенциальная устойчивость к шуму |
|---|---|---|---|
| Сырые OHLCV | Цена/объём напрямую | Низкая | Низкая |
| Технические индикаторы | RSI, MACD, MA и др. | Средняя | Средняя |
| Наивный Байес → MLP | Вероятности Байеса | Средняя | Средняя |
| Markov Chain → MLP | Вероятности переходов фаз | Высокая | Потенциально высокая |
Главное достоинство марковского подхода — интерпретируемость признаков. Трейдер может открыть Comment и увидеть текущее состояние рынка, вероятность продолжения, уровень энтропии и степень уверенности системы. Это принципиально отличается от чёрного ящика классического глубокого обучения.
Ограничения
Матрица переходов строится на истории. Если режим рынка меняется резко — матрица будет отражать прошлое. Параметр RETRAIN_EVERY помогает, но не устраняет эту проблему полностью.
Валидационная точность выше 55–60% — хороший знак. Около 50% означает, что система не улавливает паттернов на данном инструменте или таймфрейме при текущих настройках. В этом случае следует изменить MC_TREND_PERIOD, MC_TREND_PIPS или HORIZON.
Заключение
В статье рассмотрена двухуровневая архитектура торгового индикатора: марковская цепь используется не как самостоятельный прогностический инструмент, а как генератор структурированных вероятностных признаков для нейронной сети.
Ключевой принцип: качество признаков важнее сложности модели. MLP с одним скрытым слоем (24 нейрона), обученный на 15 марковских признаках, иногда эффективнее глубокой сети на сырых ценах, потому что получает осмысленное описание рыночных состояний. Это принцип, применимый далеко за пределами данной статьи.
Важный дополнительный момент — интерпретируемость. В отличие от большинства ML-индикаторов, система в любой момент показывает, почему она выдала тот или иной сигнал: текущее состояние рынка, вероятности переходов, матрица 3×3, энтропия распределения.
Рекомендуется начать тестирование на EURUSD H1 с параметрами по умолчанию, оценить валидационную точность в Comment, затем подбирать MC_TREND_PERIOD, MC_TREND_PIPS и MC_LAG_COUNT под свой инструмент. Если точность на валидации близка к 50% — это сигнал о том, что выбранные параметры цепи не улавливают структуру именно этого рынка на этом таймфрейме. Меняйте пороги, период и горизонт — и наблюдайте за тем, как меняется матрица переходов в Comment.
Дальнейшие направления развития: увеличение числа состояний цепи (5–7 вместо 3), адаптивное обновление матрицы переходов в скользящем окне, объединение нескольких цепей с разными периодами в единый вектор признаков, использование скрытых марковских моделей (HMM) вместо обычной цепи.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Алгоритм Цветовой Гармонии — Color Harmony Algorithm (CHA)
Нейросети в трейдинге: Оценка риска по несогласованности представлений (Окончание)
Разработка инструментария для анализа Price Action (Часть 38): VWAP на основе тикового буфера и модуль расчета дисбаланса на коротком окне
Архитектура машинного обучения для MetaTrader 5 (Часть 7): От разрозненных экспериментов к воспроизводимым результатам
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования