English
preview
Рыночная микроструктура в MQL5 (Часть 6): Поток ордеров

Рыночная микроструктура в MQL5 (Часть 6): Поток ордеров

MetaTrader 5 — Индикаторы |
34 0
Max Brown
Max Brown

Введение

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

Поток ордеров — непосредственная причина изменения цены. Цена движется, когда одна сторона рынка действует агрессивнее другой: покупатели совершают сделки по Ask, а продавцы — по Bid. На минутных данных OHLCV нельзя напрямую определить, кто был агрессором сделки — покупатель или продавец. Функции этой статьи строят приближенные оценки потока ордеров на уровне баров. При их расчете учитываются показатели шума и волатильности из четвертой и пятой частей. Выходные данные увязаны со структурой OrderFlowSignal, зарезервированной еще в первой части серии.

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

Функция VPIN_OHLC() по баровым данным приближенно оценивает компонент дисбаланса объема в показателе VPIN, предложенном Изли, Лопесом де Прадо и О'Хара (2012). Для канонического VPIN нужны бакеты фиксированного объема, в которых каждая сделка учитывается при оценке дисбаланса. Каждый минутный бар фьючерса NQ объединяет сотни сделок. Как и в случае спреда Ролла в пятой части, агрегация внутри бара поглощает микроструктурный сигнал, поэтому дисбаланс приближается к 0,5. По 602 сессиям диапазон VPIN составляет от 0,45 до 0,62; при стрессе показатель повышается на 6%. Это слабый, но корректный по направлению сигнал. Показатель сохранен как лучшее доступное приближение по OHLCV; его нельзя трактовать как статистически откалиброванную вероятность информированной торговли.

Функция TradeIntensity() сравнивает объем текущей сессии со скользящим базовым уровнем за 20 сессий. В первых 20 сессиях коэффициенты завышены, поскольку базовый уровень в этот период еще формируется. В исследовании это дает один экстремальный выброс (1250×) в первой сессии. В статистике использованы значения, винзоризированные по 99-му процентилю (1,63×); это описано в разделе исследования.

Результат работы — шесть функций, добавленных в MicroStructure_Foundation.mqh, новая структура OrderFlowAnalysis и сигнал потока, связанный с показателями шума и волатильности из четвертой и пятой частей. Новый подключаемый файл не создается. Сопутствующая работа доступна на SSRN под номером 6847024.



Теория потока ордеров

Поток ордеров и ценовое воздействие

Кайл (1985) показал, что информированные трейдеры маскируют ордера среди шумового потока, а цены подстраиваются по мере того, как маркет-мейкеры оценивают информацию, содержащуюся в потоке ордеров. Главный вывод: направление и величина дисбаланса объема — превышения объема покупок над объемом продаж — служат наблюдаемым следом информированной активности. Когда покупатели действуют агрессивнее продавцов, цены растут. Когда преобладают продавцы, цены падают. Изменение цены на единицу потока ордеров с учетом направления характеризует лямбда Кайла — коэффициент ценового воздействия.

На тиковом уровне можно непосредственно определить агрессора сделки: покупка совершается по Ask, продажа — по Bid. На уровне баров направление агрессивной сделки приходится определять косвенно. Стандартное правило оценки, используемое в VPIN, алгоритме Ли — Реди (1991) и данной прокси на основе OHLCV, таково: закрытие бара около максимума указывает на преобладание покупателей, около минимума — на преобладание продавцов. Такая оценка верна в среднем, но зашумлена на отдельных барах. Поэтому доверительные интервалы баровых показателей потока ордеров шире, чем у тиковых аналогов.

VPIN — синхронизированная по объему вероятность информированной торговли

Изли, Лопес де Прадо и О'Хара (2012) предложили VPIN как показатель токсичности потока ордеров в реальном времени. Каноническое определение использует бакеты фиксированного объема: каждый содержит одинаковое количество рыночной активности, а дисбаланс объемов покупок и продаж оценивает вероятность того, что хотя бы один контрагент в этом бакете был информированным. Главное свойство VPIN — стационарность по рыночной активности, а не по времени на часах. Бакет соответствует одному объему участия в рынке независимо от того, заполняется он за десять секунд или десять минут.

Реализованное здесь приближение по OHLCV — функция VPIN_OHLC() — заменяет объемные бакеты барами фиксированной длительности. При таком приближении стационарность теряется, но направленный сигнал сохраняется. Функция дает добросовестную оценку первого порядка для доли дисбаланса; ограничение явно обозначено в заголовке функции и разделе исследования.

Индекс умных денег

Индекс умных денег выявляет внутридневной паттерн: крупные информированные участники чаще действуют к концу сессии, после затухания шумовой волатильности открытия. Ценовые движения в начале сессии в основном определяются потоком розничных участников, реакцией на новости и выносом стопов. Движения в конце сессии с большей вероятностью отражают позиционирование институциональных участников. Падение цены в начале сессии с восстановлением к концу (положительный SMI) указывает на накопление со стороны информированных участников. Рост цены в начале сессии с ослаблением к концу (отрицательный SMI) указывает на распределение со стороны институциональных участников.

Интенсивность торговли

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

Связь с частями 4 и 5

Связь шестой части с предыдущими статьями явная и двусторонняя. Коэффициент шума из пятой части корректирует вес flow_confidence. При шуме выше 75-го процентиля (0,632) оценки VPIN и дисбаланса менее надежны: на объемную прокси для определения агрессора влияют те же кратковременные рыночные помехи, которые искажают цену. Если интенсивность скачков из четвертой части превышает 90-й процентиль (2,1%), flow_confidence присваивается ноль. В сессиях со скачками не следует торговать по сигналам потока. При оценке моментума потока рекомендуется учитывать индекс кластеризации из четвертой части: моментум потока ордеров устойчивее при кластеризации волатильности.



Реализация

Новая структура — OrderFlowAnalysis
//+------------------------------------------------------------------+
//| OrderFlowAnalysis: order flow measurement results.               |
//| Populated by PopulateOrderFlowAnalysis().                        |
//| flow_confidence is gated on noise (Part 5) and jump intensity    |
//| (Part 4). It is zero when the session is jump-contaminated.      |
//+------------------------------------------------------------------+
struct OrderFlowAnalysis
  {
   double vpin;               // VPIN_OHLC: volume imbalance proxy [0,1]
   double flow_imbalance;     // Signed volume-weighted directional flow [-1,+1]
   double trade_intensity;    // Session vol relative to 20-session baseline
   double smart_money;        // Late-session minus early-session return differential
   double flow_momentum;      // Short-window minus long-window flow differential
   double flow_confidence;    // Reliability weight [0,1]; 0 = jump-contaminated
  };

VPIN_OHLC()

Для каждого бара прокси для объема покупок равна (Close - Low)/(High - Low) × Volume, а прокси для объема продаж — дополняющей величине. VPIN — средняя абсолютная доля дисбаланса, нормированная на общий объем в пределах окна. Возвращает значение из диапазона [0, 1]. Значения выше 75-го процентиля (0,539) указывают на повышенный направленный дисбаланс, выше 90-го процентиля (0,559) — на сильный. В заголовке функции прямо указано: это приближение по OHLCV, которое нельзя трактовать как откалиброванную вероятность VPIN из работы Изли и соавт. (2012).

//+------------------------------------------------------------------+
//| VPIN_OHLC: volume imbalance proxy over a rolling window.         |
//| buy_vol  = (Close-Low)/(High-Low) * Volume                       |
//| sell_vol = (1-(Close-Low)/(High-Low)) * Volume                   |
//| VPIN = mean(|buy-sell|) / mean(total vol) across the window.     |
//|                                                                  |
//| THIS IS NOT THE EASLEY-LOPEZ DE PRADO-O'HARA VPIN.               |
//| The canonical VPIN uses fixed-volume buckets, not fixed time     |
//| bars. On NQ M1, intrabar aggregation compresses the imbalance    |
//| signal toward 0.5. Treat as a directional indicator only.        |
//+------------------------------------------------------------------+
double VPIN_OHLC(const string symbol, const int tf,
                  const int window)
  {
   if(!ValidateSymbolV2(symbol) || window < 5) return 0.5;
   double high[], low[], close[];
   long   vol[];
   ArraySetAsSeries(high,true); ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true); ArraySetAsSeries(vol,true);
   if(CopyHigh     (symbol,(ENUM_TIMEFRAMES)tf,0,window,high)  < window) return 0.5;
   if(CopyLow      (symbol,(ENUM_TIMEFRAMES)tf,0,window,low)   < window) return 0.5;
   if(SafeCopyClose(symbol,tf,0,window,close)                  < window) return 0.5;
   if(CopyTickVolume(symbol,(ENUM_TIMEFRAMES)tf,0,window,vol)  < window) return 0.5;
   double sum_imb = 0.0, sum_vol = 0.0;
   for(int i = 0; i < window; i++)
     {
      double br = high[i] - low[i];
      if(br <= DBL_MIN_POSITIVE) continue;
      double v    = (vol[i] > 0) ? (double)vol[i] : 1.0;
      double frac = MathMax(0.0, MathMin(1.0,
                             (close[i] - low[i]) / br));
      double buy_v  = frac * v;
      double sell_v = (1.0 - frac) * v;
      sum_imb += MathAbs(buy_v - sell_v);
      sum_vol += v;
     }
   if(sum_vol <= DBL_MIN_POSITIVE) return 0.5;
   return MathMax(0.0, MathMin(1.0, sum_imb / sum_vol));
  }

OrderFlowImbalance()

Направленный поток с учетом знака, взвешенный по объему. Расширяет функцию OrderImbalance() из пятой части: сохраняется величина отклонения от 0,5, поэтому результат с учетом знака чувствительнее к барам с выраженным направлением. Возвращает значения из интервала [-1, +1].

//+------------------------------------------------------------------+
//| OrderFlowImbalance: signed volume-weighted directional flow.     |
//| Each bar: signed_imb = ((Close-Low)/(High-Low) - 0.5) * 2 * vol  |
//| Returns sum(signed_imb) / sum(vol) in [-1,+1].                   |
//| +1 = all closes at high (buyer dominated).                       |
//| -1 = all closes at low (seller dominated).                       |
//+------------------------------------------------------------------+
double OrderFlowImbalance(const string symbol, const int tf,
                           const int window)
  {
   if(!ValidateSymbolV2(symbol) || window < 3) return 0.0;
   double high[], low[], close[];
   long   vol[];
   ArraySetAsSeries(high,true); ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true); ArraySetAsSeries(vol,true);
   if(CopyHigh     (symbol,(ENUM_TIMEFRAMES)tf,0,window,high)  < window) return 0.0;
   if(CopyLow      (symbol,(ENUM_TIMEFRAMES)tf,0,window,low)   < window) return 0.0;
   if(SafeCopyClose(symbol,tf,0,window,close)                  < window) return 0.0;
   if(CopyTickVolume(symbol,(ENUM_TIMEFRAMES)tf,0,window,vol)  < window) return 0.0;
   double weighted_sum = 0.0, total_vol = 0.0;
   for(int i = 0; i < window; i++)
     {
      double br = high[i] - low[i];
      if(br <= DBL_MIN_POSITIVE) continue;
      double frac = MathMax(0.0, MathMin(1.0,
                             (close[i] - low[i]) / br));
      double v   = (vol[i] > 0) ? (double)vol[i] : 1.0;
      weighted_sum += (frac - 0.5) * 2.0 * v;
      total_vol    += v;
     }
   if(total_vol <= DBL_MIN_POSITIVE) return 0.0;
   return MathMax(-1.0, MathMin(1.0, weighted_sum / total_vol));
  }

TradeIntensity()

Вычисляет средний объем бара в текущем окне и делит его на сохраненный базовый уровень. Вызывающий код должен передавать базовый уровень из более длинного периода истории — обычно средний объем бара за 20 сессий. Благодаря этому функция не хранит состояние и ее удобно тестировать. Значения выше 1,0 указывают на активность выше средней; для NQ M1 рекомендуемый порог повышенной активности — 75-й процентиль (1,13×).

//+------------------------------------------------------------------+
//| TradeIntensity: current vol relative to historical baseline.     |
//| Returns mean_volume(window) / baseline.                          |
//| baseline must be pre-computed from a longer lookback (caller).   |
//| Values above 1.0 = above-average activity.                       |
//| NOTE: baseline requires at least 20 sessions to be meaningful.   |
//| The first 20 sessions after data start will produce inflated     |
//| values as the baseline warms up. Check baseline > 1 before use.  |
//+------------------------------------------------------------------+
double TradeIntensity(const string symbol, const int tf,
                       const int window, double baseline)
  {
   if(!ValidateSymbolV2(symbol) || window < 2
      || baseline <= DBL_MIN_POSITIVE) return 1.0;
   long vol[];
   ArraySetAsSeries(vol, true);
   if(CopyTickVolume(symbol,(ENUM_TIMEFRAMES)tf,0,window,vol) < window)
      return 1.0;
   double sum_v = 0.0;
   int    valid = 0;
   for(int i = 0; i < window; i++)
      if(vol[i] > 0) { sum_v += (double)vol[i]; valid++; }
   if(valid == 0) return 1.0;
   return MathMax(0.0, (sum_v / valid) / baseline);
  }

SmartMoneyIndex()

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

//+------------------------------------------------------------------+
//| SmartMoneyIndex: late-session minus early-session return.        |
//| Positive: late buying after early selling = accumulation signal. |
//| Negative: late selling after early buying = distribution signal. |
//| n_early / n_late: bars used for each window (default 15).        |
//| Normalized by session range to be dimensionless.                 |
//+------------------------------------------------------------------+
double SmartMoneyIndex(const string symbol, const int tf,
                        const int window, int n_ends = 15)
  {
   if(!ValidateSymbolV2(symbol) || window < 2 * n_ends + 10) return 0.0;
   double open[], high[], low[], close[];
   ArraySetAsSeries(open,true); ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true); ArraySetAsSeries(close,true);
   if(CopyOpen (symbol,(ENUM_TIMEFRAMES)tf,0,window,open)  < window) return 0.0;
   if(CopyHigh (symbol,(ENUM_TIMEFRAMES)tf,0,window,high)  < window) return 0.0;
   if(CopyLow  (symbol,(ENUM_TIMEFRAMES)tf,0,window,low)   < window) return 0.0;
   if(SafeCopyClose(symbol,tf,0,window,close)              < window) return 0.0;
   //--- Note: ArraySetAsSeries=true means index 0 = most recent bar
   //--- Early bars = end of array (oldest); late bars = start (newest)
   double early_ret = 0.0;
   for(int i = window - 1; i >= window - n_ends; i--)
     {
      if(open[i] <= 0 || close[i] <= 0) continue;
      double r = SafeLog(close[i]) - SafeLog(open[i]);
      if(MathAbs(r) < 0.1) early_ret += r;
     }
   double late_ret = 0.0;
   for(int i = 0; i < n_ends; i++)
     {
      if(open[i] <= 0 || close[i] <= 0) continue;
      double r = SafeLog(close[i]) - SafeLog(open[i]);
      if(MathAbs(r) < 0.1) late_ret += r;
     }
   //--- Normalize by session range
   double h_max = high[0], l_min = low[0];
   for(int i = 1; i < window; i++)
     { if(high[i] > h_max) h_max = high[i];
       if(low[i]  < l_min) l_min = low[i]; }
   double mid = (h_max + l_min) / 2.0;
   if(mid <= DBL_MIN_POSITIVE) return 0.0;
   double norm_range = (h_max - l_min) / mid;
   if(norm_range <= DBL_MIN_POSITIVE) return 0.0;
   return MathMax(-1.0, MathMin(1.0,
                  (late_ret - early_ret) / norm_range));
  }

OrderFlowMomentum()

Разность потока с учетом знака: значение в коротком окне минус значение в длинном. Показывает, усиливается направленное давление или ослабевает. Положительные значения указывают на ускорение роста давления покупателей, отрицательные — на возврат потока к среднему.

//+------------------------------------------------------------------+
//| OrderFlowMomentum: short-window minus long-window flow.          |
//| Positive: directional pressure building.                         |
//| Negative: flow mean-reverting.                                   |
//| Uses the same signed volume proxy as OrderFlowImbalance().       |
//+------------------------------------------------------------------+
double OrderFlowMomentum(const string symbol, const int tf,
                          int short_w = 10, int long_w = 30)
  {
   if(!ValidateSymbolV2(symbol) || short_w < 2 || long_w <= short_w)
      return 0.0;
   double short_flow = OrderFlowImbalance(symbol, tf, short_w);
   double long_flow  = OrderFlowImbalance(symbol, tf, long_w);
   return MathMax(-2.0, MathMin(2.0, short_flow - long_flow));
  }

PopulateOrderFlowAnalysis()

Функция-обертка вызывает все шесть функций и корректирует flow_confidence по коэффициенту шума из пятой части и интенсивности скачков из четвертой. Если jump_intensity превышает порог 90-го процентиля из четвертой части (2,1%), flow_confidence присваивается ноль. Если noise_ratio превышает порог 75-го процентиля из пятой части (0,632), flow_confidence пропорционально уменьшается. Вызывающий код передает базовый уровень функции TradeIntensity(); рекомендуется использовать скользящее среднее объема бара за 20 сессий.

//+-------------------------------------------------------------------+
//| PopulateOrderFlowAnalysis: fills OrderFlowAnalysis struct.        |
//| vol_baseline: 20-session rolling mean bar volume (caller-supplied)|
//| flow_confidence gated on:                                         |
//|   jump_intensity > 0.021 (Part 4 P90) → confidence = 0            |
//|   noise_ratio > 0.632 (Part 5 P75)   → confidence reduced         |
//+-------------------------------------------------------------------+
void PopulateOrderFlowAnalysis(const string symbol, const int tf,
                                const int window,
                                OrderFlowAnalysis      &ofa,
                                const MicrostructureAnalysis &msa,
                                const VolatilityAnalysis     &va,
                                double vol_baseline = 0.0)
  {
   ofa.vpin           = VPIN_OHLC(symbol, tf, window);
   ofa.flow_imbalance = OrderFlowImbalance(symbol, tf, window);
   ofa.trade_intensity= TradeIntensity(symbol, tf, window,
                          (vol_baseline > DBL_MIN_POSITIVE)
                          ? vol_baseline : 1.0);
   ofa.smart_money    = SmartMoneyIndex(symbol, tf, window);
   ofa.flow_momentum  = OrderFlowMomentum(symbol, tf, 10, 30);
   //--- Flow confidence: gated on noise (Part 5) and jumps (Part 4)
   if(va.jump_intensity > 0.021)
     {
      ofa.flow_confidence = 0.0;  // jump-contaminated session
     }
   else if(msa.noise_ratio > 0.632)
     {
      //--- Elevated noise: reduce confidence proportionally
      double excess = (msa.noise_ratio - 0.632) / (1.0 - 0.632);
      ofa.flow_confidence = MathMax(0.0, 0.7 * (1.0 - excess));
     }
   else
     {
      //--- Normal noise: confidence scaled from noise quality
      ofa.flow_confidence = MathMax(0.0, MathMin(1.0,
                            1.0 - (msa.noise_ratio / 0.632) * 0.3));
     }
   //--- NaN guards
   if(!MathIsValidNumber(ofa.vpin))            ofa.vpin            = 0.5;
   if(!MathIsValidNumber(ofa.flow_imbalance))  ofa.flow_imbalance  = 0.0;
   if(!MathIsValidNumber(ofa.trade_intensity)) ofa.trade_intensity = 1.0;
   if(!MathIsValidNumber(ofa.smart_money))     ofa.smart_money     = 0.0;
   if(!MathIsValidNumber(ofa.flow_momentum))   ofa.flow_momentum   = 0.0;
   if(!MathIsValidNumber(ofa.flow_confidence)) ofa.flow_confidence = 0.0;
  }



Эмпирическое исследование — поток ордеров на NQ M1

Все оценщики применялись к данным тех же 602 нью-йоркских сессий фьючерса NQ на таймфрейме M1, что и в пятой части (январь 2024 г. - июнь 2026 г.). Базовый уровень для интенсивности торговли — скользящее среднее объема бара за 20 сессий. Поскольку базовый уровень формируется в первые 20 сессий, значения интенсивности торговли винзоризируются по 99-му процентилю (1,63×), чтобы устранить влияние выброса первой сессии. В выборке представлены все пять стрессовых режимов.

Figure 1 — VPIN-60 and smart money index time series with regime shading

Рис. 1. VPIN-60 (вверху) и индекс умных денег (внизу) по 602 сессиям NQ, январь 2024 г. - июнь 2026 г. VPIN умеренно повышается во время декабрьского решения ФРС и тарифного эпизода апреля 2025 года (+6%). SMI отрицателен во время шока Банка Японии (продажи в конце сессии) и максимален во время тарифного эпизода апреля 2026 года (накопление в конце сессии).

Таблица 1. Сводная статистика (602 нью-йоркские сессии, фьючерсы NQ, M1)
ПоказательСреднее значениеСтандартное отклонениеМин.25%Медиана75%Макс.
VPIN-60 [0,1]0,5230,0280,4520,5030,5220,5390,617
Дисбаланс потока [-1,+1]0,0210,056-0,185-0,0160,0240,0610,158
Интенсивность торговли (винзоризированная)1,0050,2340,5050,8480,9691,1351,632
Индекс умных денег0,0230,251-0,643-0,1420,0150,1790,866
Моментум потока0,0040,131-0,495-0,0790,0030,0930,404
Достоверность сигнала потока [0,1]0,6500,1820,0000,6750,7110,7270,792

Перед анализом режимов нужно пояснить распределение VPIN. По 602 сессиям значения лежат от 0,45 до 0,62 — диапазон шириной 0,17 вокруг центрального значения 0,52. Такое узкое распределение подтверждает, что агрегация в бары M1 существенно подавляет сигнал дисбаланса объема, как и предполагалось во введении. Каждый минутный бар NQ объединяет сотни сделок; суммарные объемы покупок и продаж внутри него почти сбалансированы, даже если за сессию направленное давление существенно. Функция VPIN_OHLC включена как лучшее доступное приближение на уровне баров: при стрессе она показывает повышение в верном направлении. Однако сами числовые значения нельзя трактовать как вероятности.

Средняя достоверность сигнала потока составляет 0,650. В сорока сессиях (6,6%) значение достоверности confidence равно 0 из-за скачков, выявленных показателем из четвертой части. В остальных 68,4% сессий достоверность выше 0,70: примерно для двух третей выборки сигнал потока проходит фильтр как надежный.

Figure 2 — VPIN vs noise ratio scatter and SMI by regime box plots

Рис. 2. Слева — VPIN-60 в сопоставлении с коэффициентом шума (часть 5) по 602 сессиям (r = 0,331, p < 0,001). При повышенном шуме VPIN обычно тоже выше. Это согласуется с интерпретацией, что на таймфрейме M1 шум и информированный поток не независимы. Справа — индекс умных денег по режимам. Шок Банка Японии — единственный режим с отрицательной медианой SMI, указывающей на продажи в конце сессии. Во время тарифного эпизода апреля 2026 года покупки в конце сессии наиболее сильны.

Таблица 2. Сравнение режимов (602 сессии)
РежимСессииVPIN-60Относительно нормального режимаДисбаланс потокаSMIДостоверность сигнала потока
Нормальный5560,522—0,0210,0210,653
Шок Банка Японии (август 2024 г.)80,523+0,2%0,010-0,0620,434
Решение ФРС (декабрь 2024 г.)60,553+5,9%0,028-0,0330,576
Тарифный шок, апрель 2025 г.140,554+6,0%0,0080,0130,656
Тарифный шок, апрель 2026 г.180,506-3,2%0,0310,1470,690

Три вывода из сравнения режимов напрямую связаны с предыдущими статьями серии.

Во-первых, при шоке Банка Японии VPIN всего на +0,2% выше обычного уровня. При этом в пятой части он назван эпизодом с максимальной волатильностью (коэффициент шума 0,677), а в четвертой занимает второе место по волатильности (23,8% в годовом выражении). Это расхождение позволяет предположить, что сворачивание керри-трейда на фоне шока Банка Японии вызвало всплеск волатильности без соответствующего роста информированного направленного потока. Такая картина согласуется с каскадом ликвидаций, когда все участники одновременно выступают продавцами, а не со сделками информированных участников против неинформированных. SMI = -0,062 поддерживает эту интерпретацию: продажи продолжались до закрытия сессии, а признаков накопления информированными участниками не было.

Во-вторых, при тарифном шоке апреля 2025 года VPIN на 6% выше обычного уровня, но дисбаланс потока (0,008) и SMI (0,013) близки к нулю. Повышенный VPIN при почти нулевом направленном дисбалансе согласуется с большими объемами с обеих сторон: рынок активен, но ни покупатели, ни продавцы не преобладают. Это согласуется с выводом четвертой части об обратном эффекте левериджа во время тарифного шока: при одинаковой агрессивности обеих сторон итогового направленного давления не возникает.

В-третьих, при тарифном эпизоде апреля 2026 года VPIN ниже обычного уровня (-3,2%), а SMI максимален в выборке (0,147). VPIN ниже обычного уровня при положительном SMI — отдельный паттерн: сессия в целом проходит при низкой общей активности, но к ее концу участники систематически накапливают позиции. Это может согласовываться с выводом сопоставления работ в четвертой и пятой частях: рынки, по-видимому, адаптировались к тарифному режиму, а информированные участники уже заняли позиции, а не реагируют постфактум.

Figure 3 — Intraday flow imbalance profile and flow confidence histogram

Рис. 3. Слева — внутридневной дисбаланс потока с учетом знака (синий, левая ось) и средний объем (красный, правая ось) по минутам после открытия нью-йоркской сессии. При открытии дисбаланс потока близок к нулю, затем немного растет. Это согласуется с преобладанием шума в начале торгов и более выраженным направлением движения позднее. Справа — распределение достоверности сигнала потока по 602 сессиям. Пик при confidence = 0 соответствует 40 сессиям со скачками.



Ограничения

Ограничения OHLCV из пятой части в равной степени применимы и здесь. Главное дополнительное ограничение шестой части: функция VPIN_OHLC() не реализует VPIN в формулировке Изли, Лопеса де Прадо и О'Хара. Канонический VPIN требует бакетов фиксированного объема: каждое наблюдение соответствует одинаковому объему рыночной активности независимо от времени на часах. Функция VPIN_OHLC() использует бары фиксированной длительности, поэтому бары с малым и большим объемом одинаково участвуют в расчете дисбаланса. На NQ M1 это дает узкое распределение VPIN (от 0,45 до 0,62), описанное в разделе исследования.

Индекс умных денег чувствителен к параметру n_ends — числу начальных и конечных баров, используемых в расчете. Значение по умолчанию, 15 баров, откалибровано под нью-йоркскую сессию NQ M1: первые 15 минут отражают шум открытия, последние 15 минут — институциональный поток перед закрытием. При применении функции к другим инструментам или сессиям иной структуры заново откалибруйте n_ends.

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

Теоретически корректная реализация использует бакеты по объему или денежной стоимости сделок, описанные Лопесом де Прадо (2018) и реализованные Ньороге (2026) для платформы MQL5. Агрегация по бакетам устраняет смещение этих показателей из-за временных баров и дает значения VPIN со статистическими свойствами, которых требует подход Изли и соавт. (2012). Функции статьи дают лучшие доступные приближения по OHLCV и подходят для индикаторов, работающих в реальном времени без доступа к тикам.



Практические пороги

Все пороги получены из эмпирического распределения по 602 сессиям NQ M1 (январь 2024 г. - июнь 2026 г.). Это эвристические рабочие пороги, а не формальные критические значения статистических тестов; они относятся именно к этому инструменту и периоду выборки.

ПоказательПороговое значениеОснованиеИнтерпретацияДействие
VPIN-60> 0,55990-й процентильСильный дисбаланс объемаУменьшите размер позиции; увеличьте расстояние до стоп-лосса
VPIN-60> 0,53975-й процентильПовышенный дисбалансСоблюдайте повышенную осторожность; внимательно следите за ситуацией
Дисбаланс потока> 0,09290-й процентильСильное давление покупателейРассмотрите возможность торговли в направлении потока
Дисбаланс потока< -0,05510-й процентильСильное давление продавцовРассмотрите возможность торговли в направлении потока
Интенсивность торговли> 1,1375-й процентильПовышенная активность; сигнал потока более надеженУвеличьте вес показателей потока
Интенсивность торговли< 0,8525-й процентильСпокойная сессия; сигнал потока менее надеженСнизьте вес показателей потока; опирайтесь на волатильность
SMI> 0,33090-й процентильВыраженное накопление в конце сессииРассмотрите возможность отдавать предпочтение длинным позициям в следующей сессии
SMI< -0,29310-й процентильВыраженное распределение в конце сессииРассмотрите возможность отдавать предпочтение коротким позициям в следующей сессии
Достоверность сигнала потока< 0,56510-й процентильШум или скачки искажают сигналНе торгуйте, опираясь только на показатели потока
Достоверность сигнала потока= 0—Сессия со скачками, искажающими сигналНе используйте никакие показатели потока
//--- Example: full signal combining Parts 4, 5, and 6
RobustFractalAnalysis  rfa;
MicrostructureAnalysis msa;
VolatilityAnalysis     va;
OrderFlowAnalysis      ofa;

PopulateHurstAnalysis            (Symbol(), PERIOD_M1, 90, rfa);
PopulateVolatilityAnalysis       (Symbol(), PERIOD_M1, 90, va, rfa);
PopulateMicrostructureAnalysis   (Symbol(), PERIOD_M1, 90, msa, rfa);
PopulateOrderFlowAnalysis        (Symbol(), PERIOD_M1, 90, ofa, msa, va,
                                  vol_baseline);  // caller pre-computes baseline

//--- Gate: only trade when flow is reliable
if(ofa.flow_confidence < 0.565) return;  // P10 threshold

//--- Select direction from flow imbalance and SMI
double direction = 0.0;
if(ofa.flow_imbalance > 0.092 && ofa.smart_money > 0.0)
   direction = +1.0;  // buyer pressure + late accumulation
else if(ofa.flow_imbalance < -0.055 && ofa.smart_money < 0.0)
   direction = -1.0;  // seller pressure + late distribution

if(MathAbs(direction) < 0.5) return;  // no aligned signal

//--- Volatility-targeted sizing (Part 4)
double current_vol = (msa.noise_ratio < 0.632)
                      ? va.realized_vol : va.figarch_vol;
double target_vol  = 0.0004;
double base_pos    = (current_vol > DBL_MIN_POSITIVE)
                      ? target_vol / current_vol : 1.0;

//--- Scale by confidence and trade intensity
double intensity_scale = MathMin(1.5,
                                  MathMax(0.5, ofa.trade_intensity));
double position = direction * base_pos
                   * ofa.flow_confidence * intensity_scale;



Структура папок и путь к подключаемому файлу

Все функции шестой части добавлены в существующий заголовочный файл базового слоя. Новые файлы не создаются. Структура папок не изменилась по сравнению с частями 1-5:

MQL5\
└── Indicators\
    └── HurstProfile\
        ├── HurstProfile.mq5
        └── Includes\
            └── MicroStructure_Foundation.mqh
#include "Includes\MicroStructure_Foundation.mqh"



Заключение

Шесть функций завершают практический и безопасный пайплайн извлечения информации о потоке ордеров из данных OHLCV на таймфрейме M1 при отсутствии тиковых данных. Они дают прокси для направленного дисбаланса (VPIN_OHLC, только направление), поток объема с учетом знака (OrderFlowImbalance), масштабирование активности сессии (TradeIntensity с базовым уровнем за 20 сессий), внутридневное выявление информированного потока (SmartMoneyIndex), краткосрочное ускорение давления (OrderFlowMomentum) и функцию-обертку (PopulateOrderFlowAnalysis), возвращающую структуру OrderFlowAnalysis.

Важно: достоверность сигнала потока — не формальность, она проходит фильтрацию. Сессии с jump_intensity выше 90-го процентиля из четвертой части исключаются (confidence = 0), а повышенный шум из пятой части пропорционально уменьшает вес. Для NQ M1 приведены практические пороги (P75/P90) и схемы применения показателей (VPIN, flow_imbalance, SMI, trade_intensity, flow_confidence).

Получается готовый измерительный блок для включения в стратегию: вычислить показатели → применить фильтр достоверности → выбрать направление (flow_imbalance + SMI) → определить размер позиции по волатильности и интенсивности торговли. Такой подход позволяет последовательно извлекать информацию о направлении из свечных данных, проводить аудит всего процесса и не торговать с чрезмерной уверенностью на основе микроструктурных артефактов.


Как получить исходный код через MQL5 Algo Forge

Algo Forge предоставляет облачный контроль версий на базе Git, поэтому вам будет доступна актуальная версия кода, в том числе обновления и исправления после публикации статьи. Полный репозиторий доступен в MQL5 Algo Forge.


Список литературы

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/22939

Прикрепленные файлы |
HurstProfile.mq5 (12.98 KB)
За пределами GARCH (Часть VII): Прогнозирование волатильности методом Монте-Карло в MQL5 За пределами GARCH (Часть VII): Прогнозирование волатильности методом Монте-Карло в MQL5
Мы реализуем модуль CMonteCarlo, который преобразует подогнанные параметры MMAR в прогноз волатильности методом Монте-Карло. Модуль выполняет N независимых симуляций на выбранном горизонте прогнозирования и возвращает среднее, медиану, стандартное отклонение и 95-процентный доверительный интервал на основе процентилей. При необходимости доступны значения каждого прогона. Адаптивная глубина каскада выбирает минимальное k, при котором b^k покрывает горизонт прогнозирования, обеспечивая быстродействие и согласованность симуляции.
Создание индикатора профиля объёма "Спектр ликвидности" (Liquidity Spectrum) на языке MQL5 Создание индикатора профиля объёма "Спектр ликвидности" (Liquidity Spectrum) на языке MQL5
Создайте в MQL5 профиль объёма «Спектр ликвидности», который распределяет объём по равным ценовым интервалам за выбранный период анализа с использованием цен закрытия свечей. В данном руководстве рассматриваются получение данных с помощью функций копирования, разбиение по ценовым интервалам и нормализация, а также отрисовка прямоугольников объёма и линий POC с использованием объектов графика и временных смещений для выявления на графике зон ликвидности с высокой активностью.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
За пределами GARCH (Часть VI): Фракционное броуновское движение и мультипликативный каскад в MQL5 За пределами GARCH (Часть VI): Фракционное броуновское движение и мультипликативный каскад в MQL5
В этой статье реализуется модуль моделирования MMAR: по параметрам, полученным при подгонке (H, распределение, коэффициенты, выборочная волатильность), он строит синтетические ценовые траектории. Модуль строит мультифрактальное торговое время с помощью мультипликативного каскада, генерирует фракционное броуновское движение методом Дэвиса — Харта или разложением Холецкого, масштабирует его до целевой волатильности и строит составной процесс посредством деформации времени. Читатели получат класс на языке MQL5, пригодный для многократного использования, рекомендации по выбору метода в зависимости от длины траектории и этапы валидации для сценарного тестирования и применения метода Монте-Карло в следующей части.