Индикатор средней цены входа маркет-мейкера
Введение: можно ли оценить цену маркет-мейкера по обычному графику
Валютный рынок внебиржевой: единого стакана и единой ленты сделок на нём нет. Ликвидность предоставляют банки, брокеры и специализированные поставщики, и каждый из них принимает встречный поток и накапливает нетто-позицию. Чем дальше эта позиция от текущей цены, тем сильнее меняется поведение такого участника: он смещает котировки, расширяет спред, хеджирует риск или, наоборот, охотнее принимает встречный поток.
В академической микроструктуре давно описано, что поставщик ликвидности управляет не только текущей котировкой, но и накопленной позицией: направленный поток сделок влияет на цену, а рост риска позиции меняет готовность участника принимать новый встречный поток. Для этого существуют модели управления дилерским запасом, модели ценового воздействия потока, модели оптимальных котировок при риске позиции и показатели токсичности потока. Однако почти все они требуют данных, которых в обычном MetaTrader 5 нет: сделок с признаком инициатора, стакана и характеристик лимитного потока.
В MetaTrader 5 мы видим цену, тиковый объём и спред. Отсюда практический вопрос: можно ли, используя только OHLCV и спред по закрытым барам, построить воспроизводимую оценку состояния агрегированной пассивной стороны — виртуальной позиции, её средней цены (Inventory Basis) и внутренней цены с поправкой на риск (Reservation Price) — так, чтобы эти уровни можно было реализовать в MQL5 и проверять на независимой истории?
Сразу зафиксируем границы. Мы не восстанавливаем "вход маркет-мейкера" и не реконструируем стакан. Мы строим расчётную модель-прокси, у которой каждый шаг явно определён, а допущения названы. Прямого доказательства того, что такие уровни несут информацию сверх VWAP и ATR, в статье нет: она описывает модель и протокол её проверки.
Проще говоря, статья отвечает на вопрос: можно ли по обычным свечам, тиковому объёму и спреду получить не просто ещё одну среднюю линию, а оценку того, где модель “видит” накопленный риск пассивной стороны рынка.
Практическая задача и границы модели
Представим обычный импульс вверх. Трейдер видит свечи, ускорение и объём, но не видит, где модель оценивает область набора встречной короткой позиции пассивной стороной, и насколько далеко текущая цена ушла от её условной себестоимости. Именно эту недостающую координату и пытается оценить модель.
Входные условия задачи:
- данные: только OHLCV (тиковый объём брокера) и спред;
- расчёт: только по закрытым барам, без заглядывания в будущее;
- реализация: чистый MQL5, Python во время работы индикатора не требуется;
- результат: набор буферов индикатора, читаемых советником через iCustom, и протокол проверки на независимой истории.
Все внутренние состояния — расчётные, они не наблюдаются. Тиковый объём, спред и котировки в FX зависят от поставщика данных, поэтому результаты одного брокера нельзя автоматически переносить на другого: воспроизводимость здесь означает "один и тот же код на тех же данных даёт те же буферы", а не "одинаковые уровни у разных брокеров".
Вся обработка строится как последовательная цепочка:
OHLCV + спред
↓
Оценка направленного агрессивного потока (гипотеза)
↓
Виртуальная позиция пассивной стороны
↓
Средняя цена позиции (Inventory Basis)
↓
Уровень разгрузки с учётом издержек и риска
↓
Внутренняя цена (Reservation Price)
↓
Адаптивные Bid / Ask с поправкой на токсичность
↓
Отклонение цены от расчётных уровней
От простой средней цены к адаптивной модели
Чтобы не превращать статью в цепочку абстрактных формул, каждый следующий шаг имеет собственную реализацию в MQL5. Пять индикаторов показывают эволюцию одной идеи: от простой оценочной средней цены до модели, которая отдельно учитывает позицию, внутреннюю цену, токсичность потока и расстояние рынка до расчётных уровней.
| Этап | Индикатор | Что показано на скриншоте |
|---|---|---|
| 1 | MM Average Entry Price (Proxy) | оценочная средняя цена виртуальной позиции и раздельные средние покупки/продажи |
| 2 | MM Price V2 | Cost Basis + Flow + ATR Zones | себестоимость позиции, ATR-зоны и области потенциальной разгрузки |
| 3 | MM Avellaneda–Stoikov V4 | Reservation Price, расчётные Bid/Ask и раздельная стоимость пассивных сторон |
| 4 | MM Dealer Toxicity V5 | адаптация внутренних уровней к токсичности потока |
| 5 | MM V4/V5 Distance Oscillator | нормированное расстояние цены до уровней V4/V5 и согласованность моделей |
Терминология
Слово "дилер" далее используется как сокращённое обозначение агрегированной пассивной стороны модели. Это не утверждение, что все сделки принадлежат одному реальному маркет-мейкеру. Кроме того, различаются две сущности, которые легко спутать:
- Inventory Basis — оценка средней цены виртуальной позиции, то есть того, где набран риск;
- Reservation Price — внутренняя котировочная цена, рассчитанная от текущего mid-price с поправкой на риск позиции, то есть то, где позиция сегодня "готова" котироваться.
Это разные величины: первая зависит от истории исполнений, вторая — от текущей цены. На графике они выводятся отдельными линиями и не объединяются в одну "дилерскую стоимость".
Далее основной рабочий термин — пассивная сторона; слова “дилер” и “маркет-мейкер” используются только как краткое обозначение этой агрегированной модельной сущности.
Почему у виртуальной позиции есть средняя цена
Начнём с самого понятного слоя. Если позиция набирается несколькими исполнениями, у неё появляется средневзвешенная цена. Пусть каждая новая часть имеет условную цену Pᵢ и вес qᵢ. Тогда средняя цена текущей позиции определяется так:
P_MM = Σ(Pᵢ × qᵢ) / Σqᵢ.
Здесь важна логика учёта. Когда новая сделка увеличивает позицию в том же направлении, средняя цена пересчитывается. Частичное закрытие не должно менять себестоимость остатка. А если позиция проходит через ноль и меняет знак, расчёт средней цены для новой стороны начинается заново.
Это принципиально отличает среднюю цену текущей позиции от исторического VWAP всего потока. Полностью закрытые старые сделки не должны бесконечно "тянуть" за собой уровень, который уже не относится к текущему риску.
Кто находится по другую сторону агрессивного потока
Чтобы перейти от свечей к виртуальной позиции, нужно определить, кто принимает удар агрессивной заявки. Когда покупатель пересекает спред и исполняется по Ask, пассивная сторона продаёт. Когда агрессивный продавец бьёт по Bid, пассивная сторона покупает.
Агрессивная покупка → пассивная продажа → виртуальная позиция смещается в SHORT Агрессивная продажа → пассивная покупка → виртуальная позиция смещается в LONG
На централизованной бирже направление инициатора можно восстанавливать по сделкам и стакану значительно точнее. На большинстве валютных инструментов в MetaTrader 5 такой информации нет, поэтому здесь используется косвенная оценка по доступным признакам бара. Важно понимать, что это гипотеза, а не оценка наблюдаемой величины: один и тот же бар OHLCV соответствует множеству разных последовательностей сделок. Признаки бара могут коррелировать с давлением, но не доказывают сторону инициатора.
Косвенная оценка агрессивного потока по OHLCV
Ниже признаки вводятся по шагам: сначала положение закрытия в баре, затем сила движения, затем отклонение от локальной средней, затем объём и тени.
Первый признак — положение цены закрытия внутри диапазона бара. Для этого используется Close Location Value (CLV):
CLV = (2 × Close − High − Low) / (High − Low), CLV = 0 при High = Low.
Если CLV близок к +1, закрытие находится у максимума бара; если к −1 — у минимума. Защита от нулевого диапазона обязательна: бар с High = Low не должен приводить к делению на ноль. Один этот показатель слишком примитивен, поэтому итоговая оценка объединяет несколько наблюдаемых признаков:
| Компонент | Определение | Что измеряет |
|---|---|---|
| CLV | см. формулу выше | положение Close внутри диапазона |
| Body | (Close − Open) / ATR | направление и размер тела свечи |
| DisplacementATR | (Close − Close[1]) / ATR | размер смещения относительно волатильности |
| VWAPDeviation | (Close − VWAP) / ATR | положение относительно локальной средней |
| VolumeAnomaly | sign(Body) · z(объём) | необычный объём, направленный знаком тела свечи |
| Absorption | (нижняя тень − верхняя тень) / (High − Low) | гипотеза о неудачной попытке продолжить движение |
Три уточнения, которые делают оценку определённой:
- Шкалы. Признаки имеют разные масштабы, поэтому каждый приводится к безразмерному виду: z-оценка по скользящему окну N баров с ограничением на уровне ±3. Без этого веса теряют смысл.
- Направление объёма. Сам по себе объём направления не имеет. Аномалия объёма умножается на знак тела свечи, иначе она вносит в поток систематическое смещение.
- Поглощение. Тень бара может возникать из-за смены потока, низкой ликвидности, новостного проскальзывания или внутрибарной волатильности, и по OHLC эти причины неразличимы. Absorption — слабый косвенный признак и входит в сумму с небольшим весом.
Flow = w₁·CLV
+ w₂·Body
+ w₃·DisplacementATR
+ w₄·VWAPDeviation
+ w₅·VolumeAnomaly
+ w₆·Absorption. VWAP здесь считается по тиковому объёму брокера, поэтому это локальный брокерский прокси, а не рыночный VWAP.
Параметры и процедура их выбора
Чтобы модель была полностью определена, все параметры сведены в таблицу. Значения по умолчанию — отправная точка, а не результат оптимизации.
| Параметр | Смысл | По умолчанию | Как выбирается |
|---|---|---|---|
| w₁…w₆ | веса признаков потока | равные, 1/6 | фиксируются; подбор допускается только на обучающем участке |
| N | окно нормализации признаков | 100 баров | фиксируется, проверяется на устойчивость |
| λ | коэффициент затухания позиции | 0.97 | только на обучающем участке |
| Окно ATR | волатильность для нормировки | 14 | стандартное значение |
| Окно VWAP | локальная средняя | 50 | фиксируется |
| τ = H | горизонт управления позицией, в барах | 20 | только на обучающем участке |
| γ̃ | безразмерное неприятие риска | 0.1 | только на обучающем участке |
| k₀ | базовая интенсивность заявок в формуле δ | 1.5 | фиксируется |
| a, b | чувствительность γ и k к токсичности | 1.0 | фиксируются |
Правило одно: любой подбор выполняется на обучающем участке, после чего параметры замораживаются и оцениваются на независимом участке. Если результат существует только на участке подбора, он ничего не доказывает.
Виртуальная позиция и её затухание
Если просто суммировать весь восстановленный поток от начала истории, модель быстро станет заложником далёкого прошлого. Реальный поставщик ликвидности не хранит один и тот же риск бесконечно: часть позиции закрывается встречным потоком, часть может хеджироваться вне наблюдаемого графика. Поэтому старому состоянию нужен постепенно уменьшающийся вес.
q(t) = λ × q(t−1) + Δq(t), 0 < λ < 1.
Здесь q — безразмерное нормированное состояние модели в диапазоне [−1; +1] (оценка потока ограничивается функцией tanh), а не количество контрактов. Коэффициент λ задаёт память модели: чем он ближе к единице, тем дольше прошлые события влияют на оценку. Его нельзя выбирать только потому, что на одном участке получилась красивая кривая.
Затухание трактуется однозначно: это частичное закрытие или хеджирование, при котором средняя цена остатка не меняется. Когда остаток падает ниже порога, позиция считается нулевой и basis сбрасывается — иначе нижележащая логика получила бы устаревшую себестоимость при нулевой позиции.
Цена исполнения также определена явно: при пассивной продаже (Δq < 0) используется Ask, то есть Close + спред; при пассивной покупке (Δq > 0) — Bid, то есть Close (в MetaTrader 5 цена закрытия бара — это Bid).
Ниже приведена функция, которая обновляет виртуальную позицию и её среднюю цену. Она различает четыре ситуации: начало новой позиции, её увеличение, частичную разгрузку и переворот через ноль.
//+------------------------------------------------------------------+ //| Обновляет виртуальную позицию и её среднюю цену | //| price: цена исполнения встречного потока (Ask при delta<0, | //| Bid при delta>0) | //+------------------------------------------------------------------+ void MM_UpdateInventory(const double price, const double delta, const double decay, double &inventory, double &basis) { const double eps=1.0e-12; //--- затухание: частичное закрытие, basis остатка не меняется inventory*=decay; //--- остаток пренебрежимо мал: позиция нулевая, basis сбрасывается if(MathAbs(inventory)<eps) { inventory=0.0; basis=0.0; } if(MathAbs(delta)<eps) return; const double old_inventory=inventory; const double new_inventory=old_inventory+delta; //--- пустая позиция: начинаем новый расчёт средней цены if(MathAbs(old_inventory)<eps) { inventory=new_inventory; basis=price; return; } //--- увеличение позиции в прежнем направлении if(old_inventory*delta>0.0) { basis=(basis*MathAbs(old_inventory) +price*MathAbs(delta))/ (MathAbs(old_inventory)+MathAbs(delta)); inventory=new_inventory; return; } //--- частичная разгрузка: средняя цена остатка не меняется if(old_inventory*new_inventory>0.0) { inventory=new_inventory; return; } //--- переворот через ноль или полное закрытие inventory=new_inventory; basis=(MathAbs(inventory)>eps ? price : 0.0); }
Функция не знает реальный объём конкретного дилера. В delta передаётся нормированная оценка пассивного потока. Поэтому переменная inventory описывает внутреннее состояние модели, а не фактическое количество контрактов. Одна средневзвешенная цена — сильное упрощение: у реальных участников разные позиции, горизонты и ограничения риска, и единой себестоимости у пассивной стороны как целого нет.

Рисунок 1. Первая версия модели: оценочная средняя цена виртуальной позиции, а также раздельные средние цены покупок и продаж.
На графике появляется то, чего нет в стандартной цене: отдельная оценка себестоимости виртуальной позиции. Особенно интересны участки, где средняя цена некоторое время сохраняется, а затем перестраивается после смены доминирующего потока. Это иллюстрация поведения линии, а не доказательство её полезности.
Три виртуальные позиции и их агрегирование
Одна средняя линия слишком грубо описывает двустороннее котирование. Поэтому внутреннее состояние разделено на три компонента:
- q_B ≥ 0 — предполагаемые покупки пассивной стороны против агрессивных продаж (сторона Bid);
- q_A ≤ 0 — предполагаемые продажи пассивной стороны против агрессивных покупок (сторона Ask);
- q_H — хеджирующая позиция: сглаженная оценка той части риска, которую модель считает вынесенной из основной позиции.
Средняя цена позиции показывает, где риск был набран, но не говорит, где участник готов котироваться сейчас. Для этого вводится отдельный уровень — Reservation Price.
Для формул Reservation Price, токсичности и Dealer Equilibrium они сводятся в одну величину:
q_H(t) = −η · EMA( q_B + q_A ), 0 ≤ η < 1 q(t) = q_B(t) + q_A(t) + q_H(t) — нетто-позиция модели
Inventory Basis относится к доминирующей стороне: при q > 0 берётся basis стороны Bid, при q < 0 — стороны Ask. Усреднять basis длинной и короткой частей нельзя: такая «средняя цена» не имеет экономического смысла. Само разделение не делает скрытую позицию наблюдаемой — это модельное допущение.
Уровень разгрузки с учётом издержек
Средняя цена отвечает только на один вопрос: где набран риск? Но для решения о разгрузке важны спред, затраты на хеджирование, премия за риск и небольшой запас прибыли. Все четыре слагаемых определены как неотрицательные величины в единицах цены, а знак задаётся только направлением позиции. Поэтому формулы для длинной и короткой позиции согласованы по знакам.
Длинная позиция (q > 0): P_sell* = Basis + SpreadCapture + HedgeCost + RiskPremium + ProfitBuffer Короткая позиция (q < 0): P_buy* = Basis − SpreadCapture − HedgeCost − RiskPremium − ProfitBuffer
P_sell* и P_buy* — это уровни, при которых разгрузка части виртуальной позиции становится выгодной после учёта издержек, а не "внутренняя стоимость дилера". Спред берётся из данных MetaTrader 5, но розничный спред смешивает наценку брокера, режим исполнения и рыночную ликвидность, поэтому он является грубым прокси, а не экономикой реального поставщика ликвидности.
Внутренняя цена по модели Avellaneda–Stoikov
Средняя цена позиции статична, тогда как внутренняя котировочная цена должна меняться вместе с размером риска и волатильностью. Эту идею формализует модель Avellaneda–Stoikov.
r(t) = S(t) − q(t) × γ × σ²(t) × τ.
Чтобы масштаб сдвига не был произвольным, единицы измерения заданы явно:
- S — mid-price: Close + Spread/2 (Close в MetaTrader 5 — это Bid);
- q — безразмерная нормированная позиция из диапазона [−1; +1];
- σ² — дисперсия изменения цены за один бар в ценовых единицах (оценка по скользящему окну приращений Close);
- τ = H — горизонт в барах, в тех же единицах, что и σ²;
- γ = γ̃ / ATR, где γ̃ — безразмерный коэффициент неприятия риска; тогда сдвиг получается в единицах цены.
Смысл формулы хорошо виден без сложной математики. Если виртуальная позиция длинная, модель менее заинтересована в новых покупках и охотнее продаёт — поэтому Reservation Price смещается вниз. Для короткой позиции смещение происходит в противоположную сторону. Это риск-скорректированная котировочная цена, а не средняя себестоимость позиции.
В MQL5 сам расчёт занимает всего несколько строк:
//+------------------------------------------------------------------+ //| Рассчитывает Reservation Price с учётом риска позиции | //| При некорректных параметрах возвращает EMPTY_VALUE: ошибка | //| настройки не должна маскироваться нормальным значением. | //+------------------------------------------------------------------+ double MM_ReservationPrice(const double mid_price, const double inventory, const double gamma, const double variance, const double horizon) { //--- проверяем физически допустимые входные параметры if(mid_price<=0.0 || gamma<0.0 || variance<0.0 || horizon<0.0) { Print("MM_ReservationPrice: некорректные параметры"); return(EMPTY_VALUE); } return(mid_price-inventory*gamma*variance*horizon); }
Здесь используется адаптация идеи Avellaneda–Stoikov, без буквального восстановления параметров по лимитному стакану. В OHLCV-данных валютного рынка нет наблюдаемой интенсивности поступления лимитных заявок, поэтому часть величин приходится оценивать косвенно, а перенос модели на баровые прокси требует отдельного обоснования, которого эта статья не даёт.
Расчётные Bid и Ask
Reservation Price становится центром внутреннего диапазона. Ширина δ задана явно, по Avellaneda–Stoikov:
δ(t) = ½ · γ · σ²(t) · τ + (1/γ) · ln(1 + γ / k) Bid* = r(t) − δ(t) Ask* = r(t) + δ(t).
Здесь k — параметр интенсивности встречных заявок; в нашей модели это прокси, а не измеренная величина. В практической реализации есть ещё одно простое ограничение: δ не может быть меньше половины наблюдаемого спреда, иначе расчётный диапазон окажется уже рыночного.
| Уровень | Интерпретация |
|---|---|
| Inventory Basis | оценочная средняя цена текущей виртуальной позиции |
| Reservation Price | внутренняя цена с поправкой на риск накопленной позиции |
| Bid* | нижняя граница расчётного диапазона |
| Ask* | верхняя граница расчётного диапазона |

Рисунок 2. Версия V4: Reservation Price, Optimal Bid/Ask, Inventory Basis и раздельные оценки стоимости пассивных сторон.
На графике V4 видно, как одна исходная идея распадается на несколько уровней. Inventory Basis показывает оценочную себестоимость позиции, Reservation Price — её внутреннюю цену с поправкой на риск, а Bid* и Ask* задают диапазон, внутри которого модель считает принятие встречного потока более рациональным.
Токсичность потока
Здесь возникает опасная ловушка. Если цена далеко ушла от расчётного уровня, очень хочется автоматически назвать её "перекупленной" или "перепроданной" и ждать возврата. Но сильное отклонение может быть не ошибкой рынка, а началом информированного движения. Для поставщика ликвидности это принципиально разные ситуации. Для оценки токсичности используются четыре прокси; названия VPIN и Kyle Lambda сохранены только как ориентиры по происхождению идеи.
Imbalance* (ранее «VPIN*») измеряет дисбаланс восстановленных покупок и продаж за окно:
Imbalance* = |V_buy − V_sell| / V_total.
Это индикатор дисбаланса, а не VPIN: настоящий VPIN строится на объёмных корзинах и классификации объёма на покупки и продажи по сделкам.
λ_Kyle* показывает, насколько сильно цена меняется на единицу направленного потока. Чтобы показатель не становился нестабильным при малом Q, он считается как наклон регрессии по окну, а не как отношение модулей:
λ_Kyle* = max( 0, Σ(ΔP · Q) / Σ(Q²) ).
Чем выше λ_Kyle*, тем сильнее цена реагирует на поток. В терминах модели это признак менее ликвидной или более токсичной среды. Помимо двух перечисленных, используются SpreadZ (z-оценка текущего спреда по окну) и VolRatio (отношение короткого ATR к длинному).
Toxicity = clip( mean( rank(Imbalance*), rank(λ_Kyle*), rank(SpreadZ), rank(VolRatio) ), 0, 1 ),
где rank — процентный ранг в скользящем окне. Два компонента из четырёх (SpreadZ и VolRatio) не используют восстановленный Flow. Это ослабляет, но не устраняет круговую зависимость: Flow формирует позицию, а часть токсичности считается из того же Flow. Поэтому в протоколе проверки предусмотрено сравнение версии с токсичностью и без неё.
Адаптивная дилерская цена
Токсичность меняет два свойства модели: чувствительность к позиции и эффективную интенсивность заявок.
γ_eff = γ₀ × (1 + a × Toxicity) k_eff = k₀ / (1 + b × Toxicity).
Подстановка γ_eff и k_eff в формулы r(t) и δ(t) расширяет диапазон: при уменьшении k слагаемое ln(1 + γ/k) растёт, значит растёт и δ. Теперь расширение Bid/Ask следует из заданной формулы, а не только из слов. В спокойном режиме границы остаются относительно компактными, при сильном одностороннем потоке внутренняя цена быстрее реагирует на позицию, а Bid* и Ask* расходятся шире.
Это защита от слишком простой логики "цена выше Ask* — продаём". При устойчивом информированном потоке модель сначала признаёт, что условия предоставления ликвидности ухудшились, и только потом оценивает расстояние цены до внутренних уровней.

Рисунок 3. Адаптивная версия V5: Reservation Price, Bid/Ask, Inventory Basis и Dealer Equilibrium с поправкой на токсичность потока.
Особенно интересен переход от спокойного участка к сильному одностороннему движению: если адаптация работает по замыслу, границы V5 должны реагировать заметнее именно там, где риск пассивной стороны возрастает. Такой рисунок показывает поведение модели, но не её статистическое преимущество.
Архитектура индикатора MQL5
- На закрытом баре рассчитываются ATR, CLV (с защитой от High = Low), аномалия объёма, локальный VWAP и признак поглощения; все признаки нормируются.
- Из этих признаков формируется оценка направленного агрессивного потока Flow.
- Знак потока инвертируется, после чего обновляются виртуальные позиции q_B и q_A пассивной стороны; затем считаются q_H и нетто-позиция q.
- Для доминирующей стороны позиции рассчитывается Inventory Basis — оценочная средняя цена.
- Из позиции и волатильности вычисляется Reservation Price.
- Прокси Imbalance*, λ_Kyle*, SpreadZ и VolRatio сводятся в Toxicity, которая корректирует чувствительность к риску и ширину котировки.
- Формируются Adaptive Bid, Adaptive Ask и Dealer Equilibrium.
- Расстояние текущей цены до расчётных уровней нормируется на ATR.
Какие буферы должен отдавать индикатор
| Буфер | Назначение |
|---|---|
| Dealer Reservation Price | центральная адаптивная оценка внутренней цены |
| Adaptive Bid | нижняя граница расчётной котировки |
| Adaptive Ask | верхняя граница расчётной котировки |
| Inventory Basis | оценочная средняя цена текущей виртуальной позиции |
| Inventory State | нормированная нетто-позиция q |
| Toxicity | оценка неблагоприятного направленного потока |
Для практического использования важно, чтобы модель не оставалась "картинкой на графике". Все ключевые состояния выводятся в отдельные буферы, поэтому их можно читать из советника через iCustom, использовать как фильтр режима или сравнивать с другими сигналами.
Расстояние цены до расчётных уровней
D(t) = (Price(t) − Level(t)) / ATR(t).
| D | Смысл |
|---|---|
| 0 | цена возле расчётного уровня |
| +1 | цена на один ATR выше уровня |
| −1 | цена на один ATR ниже уровня |
| ±2 | существенное отклонение от расчётного уровня |
Абсолютное расстояние в пунктах плохо сравнивается между разными режимами волатильности. Поэтому отклонение нормируется на ATR. Нормировка делает отклонения сопоставимыми по масштабу, но не по распределению: ATR не учитывает форму распределения возвратов, режимы ликвидности и асимметрию движений.

Рисунок 4. Осциллятор расстояния V4/V5: нормированное отклонение цены от Reservation Price, Bid/Ask и Inventory Basis, а также степень согласованности двух версий модели.
Ноль означает близость к расчётному уровню, +1 — цену примерно на один ATR выше него, −1 — на один ATR ниже. Значения около ±2 описывают существенное отклонение, но сами по себе не являются торговым сигналом.
Как интерпретировать длинную и короткую виртуальную позицию
Inventory Basis = 1.0800 Reservation = 1.0810 Adaptive Ask = 1.0830 Current Price = 1.0845 Inventory = LONG.
Рассмотрим условный пример. Виртуальная позиция модели длинная, её средняя цена находится на 1.0800, Reservation Price — на 1.0810, Adaptive Ask — на 1.0830, а рынок поднялся до 1.0845.
Цена уже выше и средней себестоимости, и верхней расчётной границы. Модель интерпретирует это как область потенциальной разгрузки длинной позиции. Но отсюда не следует автоматический Sell: нужны признаки ослабления одностороннего потока — замедление движения, поглощение покупок или возврат цены внутрь расчётного диапазона.
сильное отклонение цены
↓
одностороннее давление ослабевает
↓
цена возвращается внутрь Adaptive Bid/Ask
↓
появляется основание проверять возврат к Reservation Price
Протокол проверки
На этом месте особенно легко перейти от исследования к самообману. Красивого совпадения нескольких разворотов недостаточно: статья описывает модель, а не доказанное торговое преимущество. Результаты проверки в статье не приводятся: нет out-of-sample тестов, сравнения с базовыми моделями и доверительных интервалов. Скриншоты показывают поведение линий на отдельных участках, а не статистическое преимущество или устойчивость параметров. Ниже описан протокол, который предстоит выполнить:
- данные делятся на обучающий, валидационный и независимый тестовый участки; параметры подбираются только на обучающем и замораживаются до теста;
- сравниваются события отклонения цены от: VWAP; Inventory Basis; Reservation Price; адаптивного варианта с Toxicity; контрольного варианта без дилерского фильтра;
- для каждой версии считаются количество событий, медиана движения после события, доля возвратов к уровню, время возврата, максимальное неблагоприятное отклонение (MAE) и доверительные интервалы;
- проверка повторяется на нескольких инструментах и у нескольких брокеров;
- выполняется абляция: версия с токсичностью сравнивается с версией без неё, чтобы оценить эффект круговой зависимости.
Только после этого можно обсуждать, дают ли расчётные уровни что-то сверх обычного VWAP или простого ATR-отклонения.
Ограничения
- OHLCV не содержит идентификатора конкретного маркет-мейкера и его реальных сделок; направление агрессивного потока — гипотеза.
- Тиковый объём на валютном рынке не является централизованным биржевым объёмом и зависит от брокера.
- Пассивная сторона состоит из множества участников, а не одного дилера; единая виртуальная позиция с единой себестоимостью — сильное упрощение.
- Внешняя хеджирующая позиция напрямую не наблюдается.
- Imbalance* и λ_Kyle* являются приближёнными прокси, а не точным расчётом VPIN и Kyle Lambda по полной ленте сделок и стакану.
- Коэффициент неприятия риска и интенсивность поступления заявок нельзя однозначно восстановить из OHLCV.
- Токсичность частично зависит от того же Flow, из которого строится позиция.
- Выход цены за Adaptive Ask или Adaptive Bid может быть продолжением тренда, а не ошибкой цены.
- Модель не гарантирует прибыль и требует отдельного тестирования на независимых данных.
У этой модели есть жёсткая граница применимости, и её лучше сформулировать прямо. Корректное название результата — Estimated Dealer Inventory Basis / Reservation Price, то есть расчётная оценка, а не "настоящая цена входа маркет-мейкера". Чем яснее это разделение, тем полезнее дальнейшая проверка модели.
Практический результат
Практический результат этой работы — не одна "магическая линия", а связанная система состояний. Она оценивает направление виртуальной позиции пассивной стороны, её среднюю цену, внутреннюю цену с поправкой на риск и адаптивный диапазон Bid/Ask.
В таком виде модель можно использовать тремя способами: как визуальную карту расчётных уровней, как внешний фильтр для собственной торговой логики или как источник буферов для отдельного осциллятора отклонения.
Информативнее не касание линии, а сочетание трёх факторов: состояние позиции, расстояние до Reservation Price и динамика токсичности потока — при условии, что это подтвердит протокол проверки.
Заключение
Мы не получили "рентген" реального маркет-мейкера — прямого ответа рынок при данных ограничениях не даёт. Зато построена воспроизводимая расчётная модель агрегированной пассивной стороны, ясно фиксирующая, какие уровни и состояния извлекаются из OHLCV и спреда и как их интерпретировать.
Практический продукт — не одна волшебная линия, а набор буферов и индикаторов, которые можно скомпилировать и протестировать в терминале:
- Inventory Basis — оценочная средняя цена виртуальной позиции;
- Dealer Reservation Price — внутренняя цена с поправкой на риск;
- Adaptive Bid / Adaptive Ask — расчётный диапазон с учётом токсичности;
- Inventory State — нормированная нетто-позиция;
- Toxicity — прокси неблагоприятного направленного потока;
- Distance Oscillator D(t) = (Price − Level) / ATR.
Каждый уровень имеет понятное происхождение, вычисляется по закрытым барам без заглядывания в будущее и доступен в буферах MQL5 для чтения советником. Самое важное — корректная верификация: показа на нескольких примерах недостаточно. Протокол проверки описан выше, но не выполнен, поэтому модель следует рассматривать как воспроизводимый аналитический инструмент — карту и фильтр, — а не как доказанное торговое преимущество. Следующий шаг — систематическая проверка на независимых данных.
Приложенные файлы
К статье приложены четыре исходных индикатора MQL5 и общий архив MQL5.zip. Все исходники размещаются в отдельной подпапке проекта MM_Dealer_Model, чтобы не загромождать стандартный каталог Indicators. Исполняемые файлы EX5 к статье не прикладываются: терминал создаёт их локально после компиляции исходников.
| Файл | Путь в каталоге терминала / архиве | Назначение | Зависимости |
|---|---|---|---|
| MM_Market_Maker_Price_V2.mq5 | MQL5\Indicators\MM_Dealer_Model\MM_Market_Maker_Price_V2.mq5 | Базовая оценка средней стоимости виртуальной позиции пассивной стороны; MM Cost Basis, ATR-границы, MM Buy Average и MM Sell Average. | Внешние пользовательские индикаторы не требуются. |
| MM_Avellaneda_Stoikov_V4.mq5 | MQL5\Indicators\MM_Dealer_Model\MM_Avellaneda_Stoikov_V4.mq5 | Модель с Reservation Price, Optimal Bid/Ask, Inventory Basis и раздельной оценкой пассивных сторон. | Внешние пользовательские индикаторы не требуются. |
| MM_Dealer_Toxicity_V5.mq5 | MQL5\Indicators\MM_Dealer_Model\MM_Dealer_Toxicity_V5.mq5 | Адаптивная версия дилерской модели с поправкой на токсичность направленного потока. | Внешние пользовательские индикаторы не требуются. |
| MM_V4_V5_Distance_Oscillator.mq5 | MQL5\Indicators\MM_Dealer_Model\MM_V4_V5_Distance_Oscillator.mq5 | Нормирует расстояние цены до расчётных уровней V4/V5 и показывает согласованность двух моделей. | Для работы требуется предварительно скомпилировать исходники MM_Avellaneda_Stoikov_V4.mq5 и MM_Dealer_Toxicity_V5.mq5 в той же папке проекта. Созданные терминалом EX5 остаются локально и к статье не прикладываются. |
| MQL5.zip | MQL5.zip → MQL5\Indicators\MM_Dealer_Model\... | Архив со всеми исходными файлами статьи. Его можно распаковать в каталог установки терминала: файлы автоматически попадут в проектную подпапку MQL5\Indicators\MM_Dealer_Model\. | Архив содержит только исходные MQ5-файлы; исполняемые EX5 отсутствуют. |
Для совместной работы скомпилируйте индикаторы V4 и V5 в папке MQL5\Indicators\MM_Dealer_Model\, затем скомпилируйте осциллятор расстояния. Поскольку все три индикатора находятся в одной папке, вызовы iCustom находят V4 и V5 в каталоге вызывающего индикатора.
Литература
- Avellaneda M., Stoikov S. High-frequency trading in a limit order book. Quantitative Finance, 2008, Vol. 8, No. 3, pp. 217–224. DOI: 10.1080/14697680701381228.
- Kyle A. S. Continuous Auctions and Insider Trading. Econometrica, 1985, Vol. 53, No. 6, pp. 1315–1335. DOI: 10.2307/1913210.
- Easley D., López de Prado M. M., O'Hara M. Flow Toxicity and Liquidity in a High-frequency World. The Review of Financial Studies, 2012, Vol. 25, No. 5, pp. 1457–1493. DOI: 10.1093/rfs/hhs053.
- Ho T., Stoll H. R. Optimal Dealer Pricing under Transactions and Return Uncertainty. Journal of Financial Economics, 1981, Vol. 9, No. 1, pp. 47–73. DOI: 10.1016/0304-405X(81)90020-9.
- O'Hara M. Market Microstructure Theory. Blackwell / John Wiley & Sons, 1995, 304 p. ISBN 978-1-55786-443-7. Библиографическая карточка книги.
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
От начального к среднему уровню: Файл шаблона графика (III)
Инжиниринг признаков для машинного обучения (Часть 4): Реализация временных признаков в MQL5
От начального к среднему уровню: Файл шаблона графика (II)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования