Рыночная микроструктура в MQL5 (Часть 4): Волатильность с эффектом памяти
Введение
В первой части создан защитный базовый слой: математические функции с проверками, проверка ценовых данных и устойчивые статистические функции. Во второй части введена оценка показателя Херста со взвешиванием по достоверности. Она показала, что данные US100 на таймфрейме M1 в Globex находятся вблизи границы случайного блуждания: объединенная оценка H = 0,511, скользящая H ≈ 0,48. В третьей части добавлена функция-оценщик GPH параметра дробного дифференцирования d: объединенная оценка d = -0,006, стандартное отклонение между сессиями — 0,153.
Стандартные показатели волатильности — ATR и стандартное отклонение доходностей — исходят из независимости отдельных баров. При этом остаются без учета четыре эмпирических свойства волатильности: кластеризация — за крупными движениями следуют крупные; персистентность — шоки волатильности затухают медленно; асимметрия — отрицательная доходность повышает будущую волатильность сильнее равной ей по модулю положительной; смешение режимов — ряд может объединять разные законы масштабирования, и усредненные H и d тогда вводят в заблуждение. При работе с внутридневными данными US100 на таймфрейме M1 эти свойства прямо влияют на выбор размера позиции, размещение стоп-лоссов и фильтрацию сигналов. Если не учитывать эти свойства, торговая система будет систематически неверно откалибрована.
В этой статье в MicroStructure_Foundation.mqh добавляются две группы измерительных функций: (1) переработанная реализация мультифрактального спектра на основе MFDFA: она заменяет прежнюю прокси по разбросу τ и возвращает Δα с полем достоверности R²; (2) набор показателей волатильности: RealizedVolatility(), DurationVolatility(), FractionalVolatility(), прокси по мотивам FIGARCH, VolatilityClusteringIndex(), LeverageEffect(), JumpIntensity() и PopulateVolatilityAnalysis().
В этом эмпирическом исследовании используются фьючерсы NQ E-mini Nasdaq 100 с CME Globex, а не CFD-инструмент US100 из предыдущих черновиков. NQ — базовый контракт, торгуемый на бирже; US100 — розничный CFD-инструмент, цена которого формируется на основе индекса, а не реального потока ордеров по фьючерсу. Кластеризация волатильности, асимметрия эффекта левериджа, интенсивность скачков и мультифрактальная структура являются свойствами формирования цены на уровне биржи. Поэтому использование данных самого фьючерсного контракта — более корректный методологический выбор для такого анализа. Двухлетний набор данных NQ на таймфрейме M1 — 514 нью-йоркских сессий с мая 2024 г. по май 2026 г. — охватывает четыре значимых стрессовых эпизода: сворачивание керри-трейда после действий Банка Японии в августе 2024 года; ястребиный сюрприз ФРС в декабре 2024 года; тарифный шок "Дня освобождения" в апреле 2025 года; второй тарифный эпизод в апреле 2026 года.
Прежде чем перейти к реализации, нужно уточнить несколько важных моментов.
Функция FIGARCHVolatility() не является подогнанной моделью FIGARCH. Для полноценной оценки FIGARCH нужна оптимизация методом максимального правдоподобия по сотням наблюдений; ее вычислительная стоимость не подходит для работы на языке MQL5 в реальном времени. Функция рассчитывает реализованную волатильность со степенными весами, определяемыми по оценке d методом GPH из третьей части. Это инженерная прокси по мотивам FIGARCH. Она учитывает структуру памяти волатильности, не требуя затрат на оценку полноценной модели FIGARCH.
Функция LeverageEffect() использует подогнанную модель GJR-GARCH(1,1,1) через библиотеку волатильности Дьюба (Юн, 2026). Здесь оцениваются реальные параметры модели, а не применяется эвристика. Функция возвращает нормированный показатель асимметрии γ/(α + γ + β): он не зависит от масштаба и позволяет сравнивать сессии напрямую. Флаг, задаваемый при компиляции, выбирает вариант с библиотекой Дьюба либо более простой резервный вариант. Оба описаны в разделе о структуре папок.
Функция JumpIntensity() использует бипауэр-вариацию как базовый уровень для порога обнаружения скачков. Такой подход устойчивее простого порога по σ, но остается относительным индикатором, а не формальным тестом на скачки.
Результат работы — восемь функций, обновленных или добавленных в MicroStructure_Foundation.mqh; переработанная MFDFA, возвращающая Δα с полем достоверности R²; и полностью заполненная структура VolatilityAnalysis без полей-заглушек. Новый подключаемый файл не создается. Эмпирическую основу серии описывают две сопутствующие рабочие статьи, доступные на SSRN: SSRN 6809080 и SSRN 6847024.
Стилизованные факты о волатильности
Кластеризация волатильности означает, что за крупными изменениями цены обычно следуют другие крупные изменения любого знака, а за небольшими — небольшие. Энгл (1982) описал это явление как "эффект ARCH", за что получил Нобелевскую премию. Автокорреляция квадратов доходностей при лаге, равном 1, непосредственно характеризует кластеризацию. Для дневных данных типичны значения выше 0,2; во внутридневных данных кластеризация часто сильнее. Функция VolatilityClusteringIndex() измеряет кластеризацию напрямую. Это диагностическая прокси, а не подогнанная модель.
Персистентность волатильности означает медленное затухание ее шоков — гиперболическое, а не экспоненциальное, как в GARCH(1,1). Параметр дробного дифференцирования d из третьей части позволяет измерить эту память: если для ряда квадратов доходностей d > 0, у волатильности есть долгая память. Функция FractionalVolatility() непосредственно использует оценку d из третьей части, что намеренно связывает эту статью с частью 3. Ключевое упрощение состоит в том, что d оценивается по ряду доходностей, а затем применяется к квадратам доходностей. При этом для доходностей и волатильности предполагается один и тот же параметр памяти. Для внутридневных данных по акциям это разумное приближение, но оно не гарантировано.
Эффект левериджа (Блэк, 1976) описывает асимметрию: отрицательная доходность повышает будущую волатильность сильнее равной ей по модулю положительной. Стандартная модель эффекта — GJR-GARCH (Глостен, Джаганнатан и Ранкл, 1993). Она добавляет к GARCH(1,1) параметр асимметрии γ: σ²t = ω + α·ε²{t-1} + γ·I_{t-1}·ε²_{t-1} + β·σ²_{t-1}, где I_{t-1} = 1 при отрицательной доходности предыдущего периода. Функция LeverageEffect() оценивает модель через библиотеку Дьюба и возвращает нормированное отношение γ/(α + γ + β).
Скачки волатильности редки, но имеют серьезные последствия. Андерсен, Боллерслев и Диболд (2007) предложили бипауэр-вариацию BPV = (π/2)·mean(|r_t|·|r_{t-1}|) как базовый показатель, устойчивый к скачкам. Функция JumpIntensity() берет BPV за основу порога вместо выборочного стандартного отклонения: скачки, которые требуется обнаружить, сами искажают простой порог по σ. На данных NQ с таймфреймом M1 за 514 сессий средняя интенсивность скачков составляет 1,4%, а 90-й процентиль — 2,1%. Значение выше 5% скорее указывает на артефакты данных — ошибочные тики, смену контракта или аномалии потока котировок, — чем на реальные скачки рынка.
Мультифрактальность позволяет определить, описывается ли ряд одним законом масштабирования или сочетанием нескольких. Стандартная мера ширины спектра — Δα = α_max − α_min. Здесь α(q) — показатель Гельдера, получаемый преобразованием Лежандра из τ(q) = q·h(q) − 1. Обновленная функция MultifractalSpectrum() вычисляет эту ширину и записывает среднее R² регрессий масштабирования в поле достоверности. Узкая Δα (< 0,3) означает, что H и d надежно описывают ряд. Широкая Δα (> 0,5) означает, что в ряду есть противоположные режимы памяти, взаимно компенсирующиеся при усреднении.
Реализация 1 — переработанный мультифрактальный спектр (MFDFA)
Структура алгоритма MFDFA осталась неизменной. Изменен только выходной показатель: вместо прежнего разброса τ возвращается Δα, вычисленная преобразованием Лежандра; кроме того, функция принимает выходной параметр достоверности. Фильтр выбросов (|r| ≥ 0,1) сохранен: он исключает случаи смены контракта и ошибочные тики, которые иначе исказили бы моменты при отрицательных q, где в сумме q-х степеней доминируют крупные колебания.
Преобразование Лежандра выполняется следующим образом. Для каждой регрессии при заданном q сохраняется наклон h(q). Показатель Гельдера вычисляется как α(q) = h(q) + q·h′(q), где h′(q) приближенно определяется центральными конечными разностями. Ширина спектра равна Δα = max(α) - min(α). Показатель достоверности равен среднему R² по всем регрессиям при разных q. Если он ниже 0,65, масштабирование ненадежно и результат считается недоступным.
//+------------------------------------------------------------------+ //| MultifractalSpectrum: MFDFA returning Legendre-transform Δα. | //| confidence = mean R² of the log(F) ~ log(s) regressions. | //| Returns Δα = max(α) − min(α). Returns 0.0 on failure. | //| | //| Outlier filter: |r| >= 0.1 removed before profile construction. | //| MFDFA is sensitive to extreme values at negative q because large | //| fluctuations dominate the q-th moment. Rollovers and bad ticks | //| must be excluded before the profile is built. | //+------------------------------------------------------------------+ double MultifractalSpectrum(const string symbol, const int tf, const int period, double &confidence, int q_min = -5, int q_max = 5) { confidence = 0.0; if(!ValidateSymbolV2(symbol) || period < 100) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, period + 1, close) < period + 1) return 0.0; //--- Build log-return array; filter gross outliers double returns[]; ArrayResize(returns, period); int valid = 0; for(int i = 0; i < period; i++) { if(close[i] <= 0.0 || close[i + 1] <= 0.0) continue; double r = SafeLog(close[i + 1]) - SafeLog(close[i]); if(MathAbs(r) < 0.1) returns[valid++] = r; } if(valid < 100) return 0.0; ArrayResize(returns, valid); //--- Cumulative sum profile (demeaned) double mean_r = 0.0; for(int i = 0; i < valid; i++) mean_r += returns[i]; mean_r /= valid; double y[]; ArrayResize(y, valid); double cum = 0.0; for(int i = 0; i < valid; i++) { cum += returns[i] - mean_r; y[i] = cum; } //--- Geometric scales (powers of two); minimum 4 full segments. //--- Minimum scale = 16: below this, linear detrending is unreliable //--- on noisy M1 data. Maximum = valid/4 ensures 4 full segments. int scales[]; int max_scale = valid / 4, s = 16, scale_count = 0; while(s <= max_scale) { ArrayResize(scales, scale_count + 1); scales[scale_count++] = s; s *= 2; } if(scale_count < 2) return 0.0; //--- q values int q_cnt = q_max - q_min + 1; double q_vals[], h_q[]; ArrayResize(q_vals, q_cnt); ArrayResize(h_q, q_cnt); ArrayInitialize(h_q, 0.0); for(int qi = 0; qi < q_cnt; qi++) q_vals[qi] = q_min + qi; double r2_sum = 0.0; int r2_cnt = 0; for(int qi = 0; qi < q_cnt; qi++) { double q = q_vals[qi]; double logF[], logS[]; int points = 0; for(int sidx = 0; sidx < scale_count; sidx++) { int seg_s = scales[sidx], n_seg = valid / seg_s; if(n_seg < 2) continue; double F_sum = 0.0; int seg_cnt = 0; for(int v = 0; v < n_seg; v++) { int start = v * seg_s; double sx = 0.0, sy = 0.0, sxy = 0.0, sxx = 0.0; for(int k = 0; k < seg_s; k++) { sx += k; sy += y[start+k]; sxy += k*y[start+k]; sxx += k*k; } double dn = seg_s * sxx - sx * sx; if(MathAbs(dn) < DBL_MIN_POSITIVE) continue; double sl = (seg_s*sxy - sx*sy)/dn, ic = (sy - sl*sx)/seg_s; double var = 0.0; for(int k = 0; k < seg_s; k++) { double res = y[start+k] - (ic + sl*k); var += res*res; } var /= seg_s; if(q == 0.0) F_sum += MathLog(MathMax(var, DBL_MIN_POSITIVE)); else F_sum += MathPow(MathMax(var, DBL_MIN_POSITIVE), q/2.0); seg_cnt++; } if(seg_cnt == 0) continue; double Fq = (q == 0.0) ? MathExp(F_sum/seg_cnt) : MathPow(F_sum/seg_cnt, 1.0/q); if(Fq <= DBL_MIN_POSITIVE) continue; ArrayResize(logF, points+1); ArrayResize(logS, points+1); logF[points] = MathLog(Fq); logS[points] = MathLog((double)seg_s); points++; } if(points < 2) continue; double lsx=0,lsy=0,lsxy=0,lsxx=0; for(int p=0;p<points;p++){lsx+=logS[p];lsy+=logF[p];lsxy+=logS[p]*logF[p];lsxx+=logS[p]*logS[p];} double den = points*lsxx - lsx*lsx; if(MathAbs(den) < DBL_MIN_POSITIVE) continue; h_q[qi] = (points*lsxy - lsx*lsy) / den; //--- R² for this q regression double ym=lsy/points, ss_tot=0, ss_res=0; double pi_int = (lsy - h_q[qi]*lsx)/points; for(int p=0;p<points;p++) { double pr = pi_int + h_q[qi]*logS[p]; ss_res += (logF[p]-pr)*(logF[p]-pr); ss_tot += (logF[p]-ym)*(logF[p]-ym); } if(ss_tot > DBL_MIN_POSITIVE) { r2_sum += 1.0 - ss_res/ss_tot; r2_cnt++; } } if(r2_cnt > 0) confidence = r2_sum / r2_cnt; //--- Legendre transform: α(q) = h(q) + q·h'(q) //--- h'(q) by central finite differences double alpha[]; ArrayResize(alpha, q_cnt); for(int qi = 0; qi < q_cnt; qi++) { double dh; if(qi == 0) dh = h_q[1] - h_q[0]; else if(qi == q_cnt-1) dh = h_q[q_cnt-1] - h_q[q_cnt-2]; else dh = (h_q[qi+1] - h_q[qi-1]) / 2.0; alpha[qi] = h_q[qi] + q_vals[qi] * dh; } double amax = alpha[0], amin = alpha[0]; for(int qi = 1; qi < q_cnt; qi++) { if(alpha[qi] > amax) amax=alpha[qi]; if(alpha[qi] < amin) amin=alpha[qi]; } double delta_alpha = amax - amin; if(!MathIsValidNumber(delta_alpha) || delta_alpha > 10.0) return 0.0; return MathMax(0.0, delta_alpha); } //+------------------------------------------------------------------+ //| PopulateMultifractalAnalysis: writes multifractal_width (Δα) and | //| dimension_confidence (mean R²) into RobustFractalAnalysis. | //| Sessions with confidence < 0.65 have unreliable Δα estimates. | //+------------------------------------------------------------------+ void PopulateMultifractalAnalysis(const string symbol, const int tf, const int period, RobustFractalAnalysis &result) { result.multifractal_width = 0.0; result.dimension_confidence = 0.0; if(!ValidateSymbolV2(symbol) || period < 100) return; double conf = 0.0; double width = MultifractalSpectrum(symbol, tf, period, conf); if(MathIsValidNumber(width)) result.multifractal_width = width; if(MathIsValidNumber(conf)) result.dimension_confidence = conf; }
Реализация 2 — реализованная волатильность и волатильность с поправкой на длительность
Функция RealizedVolatility() возвращает квадратный корень из среднего квадратов логарифмических доходностей. Это базовый оценщик: при расчете не предполагается определенная структура памяти или рыночных режимов. Функция DurationVolatility() переводит RV в годовое выражение с учетом длительности бара. В исходной реализации знаменателем было 252 × 86 400 секунд — расчет исходил из круглосуточной торговли. Нью-йоркская сессия длится с 09:30 до 16:00 ET — 23 400 секунд в день. После исправления функция использует 23 400 секунд для данных на таймфрейме M1, а для дневных и старших таймфреймов — длительность полных суток.
//+------------------------------------------------------------------+ //| RealizedVolatility: sqrt(mean(squared log-returns)) | //+------------------------------------------------------------------+ double RealizedVolatility(const string symbol, const int tf, const int window, int shift = 0) { if(!ValidateSymbolV2(symbol) || window < 2) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, shift, window + 1, close) < window + 1) return 0.0; int n_returns = ArraySize(close) - 1; double sum_sq = 0.0; int valid = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); sum_sq += r * r; valid++; } if(valid == 0) return 0.0; return MathSqrt(sum_sq / valid); } //+------------------------------------------------------------------+ //| DurationVolatility: session-aware annualized realized volatility.| //| Uses NY session seconds (23,400) for M1; full-day (86,400) for | //| H1 and above. The previous version used 86,400 for all frames, | //| which overstated annualized vol for session-filtered M1 data. | //+------------------------------------------------------------------+ double DurationVolatility(const string symbol, const int tf, const int bars, int shift = 0) { if(!ValidateSymbolV2(symbol) || bars < 2) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, shift, bars + 1, close) < bars + 1) return 0.0; int n_returns = ArraySize(close) - 1; double sum_sq = 0.0; int valid = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); sum_sq += r * r; valid++; } if(valid == 0) return 0.0; double realized = MathSqrt(sum_sq / valid); int tf_sec = PeriodSeconds(tf); if(tf_sec <= 0) return 0.0; //--- NY session = 23,400 s for M1; full day for longer frames double day_sec = (tf == PERIOD_M1) ? 23400.0 : 86400.0; double ann_factor = MathSqrt(252.0 * day_sec / tf_sec); return realized * ann_factor; }
Реализация 3 — фракционная волатильность
Функция FractionalVolatility() применяет ядро памяти ARFIMA к квадратам доходностей. Веса затухают пропорционально kd−1, где k — лаг, а d — оценка методом GPH из третьей части. При d = 0 веса одинаковы, а результат равен стандартной реализованной волатильности. При d > 0 более ранние наблюдения получают относительно больший вес; оценка волатильности учитывает дальнюю зависимость. При d < 0 веса убывают быстрее, чем при равномерном усреднении, отражая антиперсистентность.
//+------------------------------------------------------------------+ //| FractionalVolatility: ARFIMA memory-kernel weighted volatility. | //| Weights: w_k = k^(d-1). When d = 0, equals realized volatility. | //| Simplification: d from returns applied to squared returns. | //| This assumes return memory and volatility memory share the same | //| parameter — reasonable for intraday equity, not guaranteed. | //+------------------------------------------------------------------+ double FractionalVolatility(const string symbol, const int tf, const int window, double d = -1.0) { if(!ValidateSymbolV2(symbol) || window < 5) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, window + 1, close) < window + 1) return 0.0; int n_returns = ArraySize(close) - 1; if(n_returns < 4) return 0.0; double returns[]; ArrayResize(returns, n_returns); int valid_ret = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); if(MathAbs(r) < 0.1) returns[valid_ret++] = r; } if(valid_ret < 5) return 0.0; ArrayResize(returns, valid_ret); if(d <= -0.49 || d >= 0.49) { double conf_dummy; d = GPHEstimator(returns, valid_ret, conf_dummy); } d = MathMax(-0.49, MathMin(0.49, d)); double sum_w = 0.0, sum_wrr = 0.0; for(int k = 1; k <= valid_ret; k++) { double w = MathPow((double)k, d - 1.0); if(!MathIsValidNumber(w) || w > 1e10) w = 1.0; sum_w += w; sum_wrr += w * returns[valid_ret - k] * returns[valid_ret - k]; } if(sum_w <= DBL_MIN_POSITIVE) return 0.0; return MathSqrt(MathMax(0.0, sum_wrr / sum_w)); }
Реализация 4 — прокси по мотивам FIGARCH
Функция FIGARCHVolatility() не является подогнанной моделью FIGARCH. Полноценная FIGARCH требует оценки параметров методом максимального правдоподобия; для обработки в реальном времени 390-барных сессий на таймфрейме M1 это слишком затратно. Функция служит прокси для условной дисперсии со степенным взвешиванием. Рекурсия весов w_j = w_j-1 · (j-1-d)/j представляет собой усеченное ядро фракционного дифференцирования (Бэйли и соавт., 1996), непосредственно применяемое к квадратам доходностей. Для базовой дисперсии используется бипауэр-вариация, а не выборочное среднее: так нижняя граница остается устойчивой к отдельным скачкам доходности. Жестко заданные omega = 1e-6 и beta = 0.85 удалены. Теперь функция использует оценку d методом GPH из третьей части и базовую бипауэр-вариацию.
//+------------------------------------------------------------------+ //| FIGARCHVolatility: FIGARCH-inspired power-law conditional proxy. | //| | //| THIS IS NOT A FITTED FIGARCH MODEL. It is a power-law weighted | //| realized volatility proxy using the fractional differencing | //| kernel of Baillie et al. (1996). The memory exponent d comes | //| from the Part 3 GPH estimate. The baseline is bipower variation, | //| which is robust to isolated jump returns. | //+------------------------------------------------------------------+ double FIGARCHVolatility(const string symbol, const int tf, const int window, double d = -1.0) { if(!ValidateSymbolV2(symbol) || window < 20) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, window + 2, close) < window + 2) return 0.0; int n_returns = ArraySize(close) - 1; if(n_returns < 20) return 0.0; double returns[]; ArrayResize(returns, n_returns); int valid_ret = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); if(MathAbs(r) < 0.1) returns[valid_ret++] = r; } if(valid_ret < 20) return 0.0; ArrayResize(returns, valid_ret); if(d <= -0.49 || d >= 0.49) { double conf_dummy; d = GPHEstimator(returns, valid_ret, conf_dummy); } d = MathMax(-0.49, MathMin(0.49, d)); //--- Bipower variation baseline: BPV = (π/2)·mean(|r_t|·|r_{t-1}|) //--- Robust to isolated jumps: a single large return contaminates //--- at most two adjacent products, leaving the mean stable. double bpv_sum = 0.0; int bpv_cnt = 0; for(int i = 1; i < valid_ret; i++) { bpv_sum += MathAbs(returns[i]) * MathAbs(returns[i-1]); bpv_cnt++; } double baseline_var = (bpv_cnt > 0) ? (M_PI/2.0) * bpv_sum / bpv_cnt : 0.0; //--- Fractional differencing kernel: w_0 = 1; w_j = w_{j-1}*(j-1-d)/j int L = MathMin(100, valid_ret - 1); double weights[]; ArrayResize(weights, L); weights[0] = 1.0; for(int j = 1; j < L; j++) { weights[j] = weights[j-1] * (j - 1.0 - d) / (double)j; if(!MathIsValidNumber(weights[j]) || MathAbs(weights[j]) > 1e6) weights[j] = 0.0; } double cond_var = 0.0, sum_w = 0.0; for(int j = 0; j < L; j++) { int idx = valid_ret - 1 - j; if(idx < 0) break; cond_var += weights[j] * returns[idx] * returns[idx]; sum_w += weights[j]; } if(sum_w > DBL_MIN_POSITIVE) cond_var /= sum_w; else cond_var = baseline_var; cond_var = MathMax(cond_var, baseline_var); if(cond_var <= 0.0) return 0.0; return MathSqrt(cond_var); }
Реализация 5 — индекс кластеризации, эффект левериджа GJR и интенсивность скачков на основе бипауэр-вариации
Функция VolatilityClusteringIndex() не изменилась: она возвращает автокорреляцию квадратов доходностей при лаге, равном 1, — прямой диагностический показатель эффекта ARCH.
Функция LeverageEffect() была существенно переработана. Исходная реализация сравнивала дисперсию следующего бара после отрицательных и положительных доходностей. Это была простая эвристика, а не модель эффекта левериджа. В переработанной версии через библиотеку волатильности Дьюба подгоняется модель GJR-GARCH(1,1,1), а функция возвращает нормализованное отношение асимметрии γ/(α + γ + β). Это отношение не зависит от масштаба и сопоставимо между сессиями. Учитывается условие стационарности: функция возвращает 0.0, если α + γ/2 + β ≥ 1. Вариант выполнения выбирается флагом времени компиляции USE_GJR_LEVERAGE. Если библиотека Дьюба не установлена, функция компилируется и работает с исходной резервной оценкой дисперсии с разделением по знаку доходности.
Функция JumpIntensity() теперь берет бипауэр-вариацию в качестве базового уровня вместо выборочного стандартного отклонения. Доходность считается скачком, если ее квадрат превышает σ_mult ² × BPV. Такой подход устойчивее: скачкообразные доходности сами завышают выборочную σ, с которой их затем сравнивают.
//+------------------------------------------------------------------+ //| VolatilityClusteringIndex: lag-1 autocorrelation of squared rets | //| Diagnostic for the ARCH effect. Values above 0.1 confirm | //| clustering; above 0.2 indicate strong, predictable volatility. | //+------------------------------------------------------------------+ double VolatilityClusteringIndex(const string symbol, const int tf, const int window) { if(!ValidateSymbolV2(symbol) || window < 3) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, window + 1, close) < window + 1) return 0.0; int n_returns = ArraySize(close) - 1; if(n_returns < 3) return 0.0; double sq_ret[]; ArrayResize(sq_ret, n_returns); int valid = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); sq_ret[valid++] = r * r; } if(valid < 3) return 0.0; ArrayResize(sq_ret, valid); double mean = 0.0; for(int i = 0; i < valid; i++) mean += sq_ret[i]; mean /= valid; double num = 0.0, den = 0.0; for(int i = 0; i < valid - 1; i++) { num += (sq_ret[i] - mean) * (sq_ret[i+1] - mean); den += (sq_ret[i] - mean) * (sq_ret[i] - mean); } if(den <= DBL_MIN_POSITIVE) return 0.0; return MathMax(-1.0, MathMin(1.0, num / den)); } //+------------------------------------------------------------------+ //| LeverageEffect: GJR-GARCH(1,1,1) asymmetry parameter. | //| Returns γ/(α + γ + β) in [0, 1] — normalized, scale-free. | //| | //| Requires Dube volatility library. Add before your #include: | //| #define USE_GJR_LEVERAGE | //| Without this define, falls back to next-bar variance asymmetry. | //| Returns 0.0 if model fails to converge or stationarity | //| condition α + γ/2 + β >= 1 is violated. | //+------------------------------------------------------------------+ double LeverageEffect(const string symbol, const int tf, const int window) { if(!ValidateSymbolV2(symbol) || window < 30) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, window + 1, close) < window + 1) return 0.0; int n_returns = ArraySize(close) - 1; if(n_returns < 30) return 0.0; double SCALE = 100.0; double returns[]; ArrayResize(returns, n_returns); int valid = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); if(MathAbs(r) < 0.1) returns[valid++] = r * SCALE; } if(valid < 30) return 0.0; ArrayResize(returns, valid); #ifdef USE_GJR_LEVERAGE //--- GJR-GARCH path (Dube library required) //--- Model: σ²_t = ω + α·ε²_{t-1} + γ·I_{t-1}·ε²_{t-1} + β·σ²_{t-1} //--- params order after fit(): [mu, omega, alpha, gamma, beta] vector obs; obs.Init(valid); for(int i = 0; i < valid; i++) obs[i] = returns[i]; ArchParameters spec; spec.observations = obs; spec.include_constant = true; spec.vol_model_type = VOL_GJR_GARCH; spec.garch_p = 1; spec.garch_o = 1; spec.garch_q = 1; ConstantMean gjr_model; if(!gjr_model.initialize(spec)) return 0.0; ArchModelResult res = gjr_model.fit(SCALE); if(!res.params.Size()) return 0.0; double alpha = res.params[2]; double gamma = res.params[3]; double beta = res.params[4]; if((alpha + gamma/2.0 + beta) >= 1.0) return 0.0; // stationarity if(alpha < 0.0 || gamma < 0.0 || beta < 0.0) return 0.0; double denom = alpha + gamma + beta; if(denom <= DBL_MIN_POSITIVE) return 0.0; return MathMax(0.0, MathMin(1.0, gamma / denom)); #else //--- Fallback: next-bar variance asymmetry proxy //--- Measures sign-conditioned next-bar squared return ratio. //--- Less rigorous than GJR-GARCH; requires no external library. double sum_sq_neg = 0.0, sum_sq_pos = 0.0; int cnt_neg = 0, cnt_pos = 0; for(int i = 0; i < valid - 1; i++) { double v = returns[i+1] * returns[i+1]; if(returns[i] < 0.0) { sum_sq_neg += v; cnt_neg++; } else { sum_sq_pos += v; cnt_pos++; } } if(cnt_neg == 0 || cnt_pos == 0) return 0.0; double vn = sum_sq_neg/cnt_neg, vp = sum_sq_pos/cnt_pos; double dn = vn + vp; if(dn <= DBL_MIN_POSITIVE) return 0.0; return MathMax(-1.0, MathMin(1.0, (vn - vp) / dn)); #endif } //+------------------------------------------------------------------+ //| JumpIntensity: proportion of returns classified as jumps. | //| Baseline: bipower variation BPV = (π/2)·mean(|r_t|·|r_{t-1}|). | //| A return is a jump when r²_t > sigma_mult² × BPV. | //| BPV is robust to isolated jumps; sample σ is not. | //| Values above 2% indicate elevated activity; above 5% indicates | //| data artifacts (bad ticks, rollovers). Reject if > 5%. | //+------------------------------------------------------------------+ double JumpIntensity(const string symbol, const int tf, const int window, double sigma_mult = 3.0) { if(!ValidateSymbolV2(symbol) || window < 5 || sigma_mult <= 0.0) return 0.0; double close[]; if(SafeCopyClose(symbol, tf, 0, window + 1, close) < window + 1) return 0.0; int n_returns = ArraySize(close) - 1; if(n_returns < 5) return 0.0; double returns[]; ArrayResize(returns, n_returns); int valid = 0; for(int i = 0; i < n_returns; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); if(MathIsValidNumber(r)) returns[valid++] = r; } if(valid < 5) return 0.0; ArrayResize(returns, valid); //--- Bipower variation baseline double bpv_sum = 0.0; for(int i = 1; i < valid; i++) bpv_sum += MathAbs(returns[i]) * MathAbs(returns[i-1]); double bpv = (valid > 1) ? (M_PI/2.0) * bpv_sum / (valid - 1) : 0.0; if(bpv <= DBL_MIN_POSITIVE) return 0.0; double threshold_sq = sigma_mult * sigma_mult * bpv; int jumps = 0; for(int i = 0; i < valid; i++) if(returns[i] * returns[i] > threshold_sq) jumps++; return (double)jumps / valid; }
Реализация 6 — функция-обертка PopulateVolatilityAnalysis
Сигнатура функции-обертки осталась такой же, как в первоначальной версии. Теперь в поле асимметрии записывается стандартизированный коэффициент асимметрии логарифмических доходностей — диагностический показатель распределения, а не жестко заданный ноль. Полю volatility_confidence структуры RobustFractalAnalysis, как и прежде, присваивается значение индекса кластеризации.
//+------------------------------------------------------------------+ //| PopulateVolatilityAnalysis: fills all VolatilityAnalysis fields. | //| asymmetry = standardized skewness of log-returns. | //| This is a distributional diagnostic. The volatility asymmetry | //| is captured separately by leverage_effect (GJR γ ratio). | //+------------------------------------------------------------------+ void PopulateVolatilityAnalysis(const string symbol, const int tf, const int period, VolatilityAnalysis &result, RobustFractalAnalysis &rfa) { result.realized_vol = RealizedVolatility(symbol, tf, period, 0); result.duration_vol = DurationVolatility(symbol, tf, period, 0); result.fractional_vol = FractionalVolatility(symbol, tf, period, -1.0); result.figarch_vol = FIGARCHVolatility(symbol, tf, period, -1.0); result.clustering_index = VolatilityClusteringIndex(symbol, tf, period); result.leverage_effect = LeverageEffect(symbol, tf, period); result.jump_intensity = JumpIntensity(symbol, tf, period, 3.0); //--- Standardized skewness of log-returns double close[]; result.asymmetry = 0.0; if(SafeCopyClose(symbol, tf, 0, period + 1, close) >= period + 1) { int nret = ArraySize(close) - 1, vld = 0; double rets[]; ArrayResize(rets, nret); for(int i = 0; i < nret; i++) { if(close[i] <= 0.0 || close[i+1] <= 0.0) continue; double r = SafeLog(close[i+1]) - SafeLog(close[i]); if(MathAbs(r) < 0.1) rets[vld++] = r; } if(vld > 3) { double mu = 0.0, var = 0.0, sk = 0.0; for(int i=0;i<vld;i++) mu += rets[i]; mu /= vld; for(int i=0;i<vld;i++) var += (rets[i]-mu)*(rets[i]-mu); var /= vld; double sd = MathSqrt(var); if(sd > DBL_MIN_POSITIVE) { for(int i=0;i<vld;i++) { double z=(rets[i]-mu)/sd; sk += z*z*z; } result.asymmetry = sk / vld; } } } //--- NaN/Inf guards if(!MathIsValidNumber(result.realized_vol)) result.realized_vol = 0.0; if(!MathIsValidNumber(result.duration_vol)) result.duration_vol = 0.0; if(!MathIsValidNumber(result.fractional_vol)) result.fractional_vol = 0.0; if(!MathIsValidNumber(result.figarch_vol)) result.figarch_vol = 0.0; if(!MathIsValidNumber(result.clustering_index)) result.clustering_index = 0.0; if(!MathIsValidNumber(result.leverage_effect)) result.leverage_effect = 0.0; if(!MathIsValidNumber(result.jump_intensity)) result.jump_intensity = 0.0; if(!MathIsValidNumber(result.asymmetry)) result.asymmetry = 0.0; //--- Volatility confidence proxy rfa.volatility_confidence = result.clustering_index; if(!MathIsValidNumber(rfa.volatility_confidence)) rfa.volatility_confidence = 0.0; }
Эмпирическое исследование — волатильность NQ на таймфрейме M1 и ширина мультифрактального спектра
Все оценщики применялись к данным 514 нью-йоркских сессий фьючерса NQ E-mini Nasdaq 100 на CME Globex за период с мая 2024 года по май 2026 года. Фильтр нью-йоркской сессии сохраняет бары со временем открытия в интервале от 14:30 до 21:00 UTC. Сессии с менее чем 300 барами на таймфрейме M1 исключаются. Данные получены у поставщика фьючерсных котировок для розничных клиентов; биржа-источник — CME Group. Значения поля асимметрии винзоризированы по первому и 99-му процентилям (-1,39 и 1,85). Это ограничивает влияние трех сессий с экстремальной асимметрией — максимум 7,81, — указывающей на артефакты внутридневных данных, которые не отсеял фильтр |r| < 0,1. Во всех остальных полях используются исходные значения. Все 514 сессий проходят минимальный порог R² для MFDFA — 0,65; наименьшее наблюдаемое R² равно 0,851. Показанные здесь значения левериджа получены из прокси для дисперсии с разделением доходностей по знаку, рассчитанной скриптом анализа на Python. В MQL5 функция LeverageEffect() использует GJR-GARCH(1,1,1) через библиотеку Дьюба, если определен флаг USE_GJR_LEVERAGE. В этом режиме она возвращает значения только из интервала [0, 1]. Прокси возвращает значения в диапазоне [-1, +1], поэтому возможен отрицательный леверидж — он наблюдался во время тарифного эпизода апреля 2025 года.

Рис. 1. Реализованная волатильность сессий NQ в годовом выражении (%) за 514 сессий, май 2024 г. - май 2026 г. Заштрихованы выявленные стрессовые эпизоды. Тарифный шок апреля 2025 года (темно-красный) выделяется сильнее всего: средняя годовая волатильность составила 38,2% — в 3,1 раза выше обычного уровня.
Таблица 1. Сводная статистика по 514 нью-йоркским сессиям фьючерса NQ на таймфрейме M1| Показатель | Среднее значение | Стандартное отклонение | Мин. | 25% | Медиана | 75% | Макс. |
|---|---|---|---|---|---|---|---|
| Реализованная волатильность (на бар) | 0,00042 | 0,00018 | 0,00013 | 0,00029 | 0,00038 | 0,00050 | 0,00310 |
| Волатильность с поправкой на длительность (в годовом выражении, %) | 13,39% | 7,45% | 4,38% | 9,10% | 11,88% | 15,72% | 96,53% |
| Фракционная волатильность (на бар) | 0,00036 | 0,00015 | 0,00010 | 0,00024 | 0,00033 | 0,00044 | 0,00220 |
| Прокси FIGARCH (на бар) | 0,00041 | 0,00017 | 0,00012 | 0,00028 | 0,00037 | 0,00049 | 0,00290 |
| Индекс кластеризации | 0,146 | 0,096 | -0,031 | 0,076 | 0,138 | 0,203 | 0,575 |
| Эффект левериджа (прокси) | 0,046 | 0,132 | -0,596 | -0,036 | 0,055 | 0,127 | 0,445 |
| Интенсивность скачков (бипауэр-вариация, 3σ) | 1,40% | 0,57% | 0,00% | 1,03% | 1,29% | 1,80% | 3,60% |
| Асимметрия (винзоризированный коэффициент асимметрии) | -0,071 | 0,555 | -1,386 | -0,367 | -0,139 | 0,169 | 1,850 |
| d (оценка методом GPH) | -0,010 | 0,077 | -0,246 | -0,061 | -0,011 | 0,044 | 0,202 |

Рис. 2. Распределение шести показателей по рыночным режимам. На графике волатильности с поправкой на длительность (вверху слева) тарифный шок апреля 2025 года выделяется как явный выброс. Индекс кластеризации (вверху по центру) заметно ниже при остром рыночном стрессе: во время кризисов волатильность становится менее предсказуемой от бара к бару. Δα (внизу по центру) остается стабильно высокой во всех режимах.
Три показателя волатильности — реализованная, фракционная и прокси FIGARCH — изменяются сходным образом: парные корреляции выше 0,97. Фракционная волатильность в среднем на 14% ниже реализованной. Это согласуется со слегка антиперсистентным d = -0,010 из третьей части: слабая антиперсистентность уменьшает вес последних наблюдений. Прокси FIGARCH занимает промежуточное положение между двумя оценками.
Два результата сравнения режимов требуют отдельного пояснения. Во-первых, при остром стрессе индекс кластеризации ниже: 0,107 во время тарифного шока против 0,147 в обычных сессиях. При остром стрессе волатильность становится более хаотичной и менее предсказуемой от бара к бару, а не сильнее кластеризуется. Эффект ARCH ослабевает именно тогда, когда он был бы наиболее полезен для прогнозирования. Во-вторых, во время тарифного шока апреля 2025 года прокси эффекта левериджа была отрицательной (-0,011): движения вверх усиливали волатильность сильнее движений вниз. Это согласуется с шорт-сквизами и резкими восстановительными ралли во время ценовых дислокаций, вызванных тарифами. Однако одного эпизода на одном инструменте недостаточно, чтобы установить причинно-следственную связь. Реализация GJR-GARCH на языке MQL5 учитывает асимметричную реакцию дисперсии через параметр γ. Однако приведенные здесь значения получены из прокси, а не из подогнанной модели GJR.
Во время тарифного эпизода апреля 2026 года волатильность в годовом выражении составила 11,5% против обычного уровня 12,5%. Это согласуется с предположением Брауна (2026e), что к 2026 году тарифный режим уже в значительной мере был учтен в ценах. Согласованность результатов двух работ служит косвенным подтверждением, хотя выборка охватывает один инструмент, а интерпретация остается предварительной.

Рис. 3. Слева — зависимость индекса кластеризации от прокси эффекта левериджа по 514 сессиям (r = 0,127, p = 0,004). Эти два показателя, по-видимому, в значительной степени независимы и дополняют друг друга. Стрессовые режимы, отмеченные цветными точками, группируются в разных квадрантах. Особенно выделяется отрицательная прокси эффекта левериджа во время тарифного шока апреля 2025 года. Справа — Δα в сопоставлении с реализованной волатильностью (r = 0,022, p = 0,616). Мультифрактальность не коррелирует с уровнем волатильности, что согласуется с ее ролью структурной характеристики, не зависящей от величины волатильности.
Ширина мультифрактального спектра (Δα — преобразование Лежандра)
Для всех 514 сессий получены допустимые оценки MFDFA: средний показатель достоверности R² составляет 0,972, минимальный — 0,851. В каждой сессии показатель достоверности выше порога 0,65, поэтому ни одну оценку не требуется помечать как ненадежную по качеству. Это более сильный результат, чем в пилотном исследовании US100, где семь из 72 сессий не достигли порога. Он согласуется с более регулярным масштабированием реальной фьючерсной микроструктуры по сравнению с CFD-прокси, хотя различие может объясняться и другими факторами.
| Показатель | Δα | Достоверность по R² |
|---|---|---|
| Сессии с допустимыми оценками | 514 | 514 |
| Среднее значение | 0,889 | 0,972 |
| Стандартное отклонение | 0,176 | 0,024 |
| Мин. | 0,460 | 0,851 |
| 25% | 0,764 | 0,962 |
| Медиана | 0,875 | 0,979 |
| 75% | 0,985 | 0,990 |
| Макс. | 1,659 | 1,000 |
Значения Δα для фьючерсов NQ существенно выше, чем в пилотном исследовании CFD US100: медиана 0,875 против 0,498. Это ожидаемо: биржевые фьючерсы проявляют более сильную мультифрактальность, чем CFD-прокси, поскольку отражают реальную неоднородность потока ордеров. Взаимодействие информированных трейдеров, маркет-мейкеров, HFT-алгоритмов и институционального потока создает более сложную структуру масштабирования, чем брокерский продукт, отслеживающий индекс. Это согласуется с главным утверждением статьи: близкие к нулю H и d из второй и третьей частей — результат усреднения резко противоположных режимов памяти, а не свидетельство отсутствия памяти у ряда.
Таблица 2. Сводка по режимам (514 сессий)| Режим | Сессии | Средняя волатильность (%) | Относительно нормального режима | Кластеризация | Эффект левериджа | Среднее значение Δα |
|---|---|---|---|---|---|---|
| Нормальный | 468 | 12,52 | — | 0,147 | 0,048 | 0,891 |
| Шок Банка Японии (август 2024 г.) | 8 | 23,77 | 1,9× | 0,072 | 0,008 | 0,812 |
| Решение ФРС (декабрь 2024 г.) | 6 | 15,42 | 1,2× | 0,207 | 0,047 | 0,774 |
| Тарифы, апрель 2025 г. | 14 | 38,22 | 3,1× | 0,107 | -0,011 | 0,885 |
| Тарифы, апрель 2026 г. | 18 | 11,46 | 0,9× | 0,164 | 0,055 | 0,929 |
Распределение режимов по Δα:
- Δα < 0,76 (умеренное смешение режимов) — 125 сессий (24,3%);
- Δα 0,76-0,99 (сильное смешение режимов — типичный случай) — 265 сессий (51,6%);
- Δα > 0,99 (экстремальное смешение режимов) — 124 сессии (24,1%).
В двухлетней выборке NQ нет почти монофрактальных сессий (Δα < 0,30). Минимальное наблюдаемое Δα составляет 0,460. Значит, нижний порог из пилотного исследования US100 (Δα < 0,30 — почти монофрактальный режим) к фьючерсам NQ неприменим. Во всех сессиях мультифрактальность как минимум умеренная; различается лишь степень смешения режимов.
Практическая интерпретация и торговые пороги
Все приведенные ниже пороги получены из эмпирического распределения по 514 сессиям NQ на таймфрейме M1 с мая 2024 года по май 2026 года. Это эвристические рабочие пороги по эмпирическим квантилям, а не формальные критические значения статистических тестов или оптимальные границы с точки зрения теории принятия решений. Они относятся именно к NQ на таймфрейме M1 и этому периоду выборки. Рассматривайте их как отправную точку и заново определяйте для своего инструмента, таймфрейма и периода данных.
| Показатель | Пороговое значение | Основание | Интерпретация | Действие |
|---|---|---|---|---|
| Индекс кластеризации | > 0,20 | 75-й процентиль | Выраженный эффект ARCH; волатильность предсказуема от бара к бару | Выбирайте размер позиции с учетом целевой волатильности; отдавайте предпочтение прокси FIGARCH |
| Индекс кластеризации | < 0,08 | 25-й процентиль | Слабая кластеризация; доходности близки к независимым одинаково распределенным величинам (i.i.d.) | Достаточно более простой оценки реализованной волатильности |
| Эффект левериджа (GJR) | > 0,13 | 75-й процентиль | Выраженная асимметрия; отрицательные шоки сильнее повышают волатильность | Увеличьте расстояние до стоп-лосса для коротких позиций; уменьшите размер длинных позиций при входе |
| Эффект левериджа (GJR) | < -0,10 | — | Обратная асимметрия (режим резкого отскока после стрессового эпизода) | Не применяйте стандартную логику эффекта левериджа; уменьшите размер позиции |
| Интенсивность скачков | > 2,1% | 90-й процентиль | Повышенная частота экстремальных доходностей | Уменьшите размер позиции; проверьте поток котировок |
| Интенсивность скачков | > 5% | — | Вероятный артефакт данных | Отклоните данные сессии; не торгуйте |
| Δα (мультифрактальный показатель) | < 0,76 | 25-й процентиль | Умеренное смешение режимов; оценки H и d частично надежны | Предпочтительна фракционная волатильность; используйте H и d с осторожностью |
| Δα (мультифрактальный показатель) | > 0,99 | 75-й процентиль | Экстремальное смешение режимов; средние оценки H и d ненадежны | Отдавайте предпочтение прокси по мотивам FIGARCH; считайте H и d менее информативными |
| Достоверность по R² | < 0,65 | — | Оценка MFDFA ненадежна (редкий случай для NQ) | Считайте значение Δα недоступным |
//--- Example: adaptive position sizing using volatility and multifractal width RobustFractalAnalysis rfa; VolatilityAnalysis va; PopulateMultifractalAnalysis(Symbol(), PERIOD_M1, 390, rfa); PopulateVolatilityAnalysis(Symbol(), PERIOD_M1, 90, va, rfa); //--- Select volatility estimate based on regime double current_vol; if(rfa.multifractal_width > 0.99 && rfa.dimension_confidence > 0.65) current_vol = va.figarch_vol; // strong mixing: use memory proxy else if(va.clustering_index > 0.20) current_vol = va.fractional_vol; // moderate clustering: fractional else current_vol = va.realized_vol; // normal: simple realized vol //--- Scale to target volatility (0.0004 calibrated to NQ M1 mean realized vol) double target_vol = 0.0004; double base_position = 1.0; if(current_vol > DBL_MIN_POSITIVE) base_position = target_vol / current_vol; //--- Reduce when jump activity is elevated if(va.jump_intensity > 0.02) base_position *= MathMax(0.3, 1.0 - va.jump_intensity * 10.0); //--- Widen stop asymmetrically when GJR leverage is significant double stop_multiplier = 1.0; if(va.leverage_effect > 0.10) stop_multiplier = 1.0 + va.leverage_effect;
Структура папок и путь к подключаемому файлу
Все функции четвертой части добавлены в существующий заголовочный файл базового слоя. Новые файлы не создаются. Структура папок остается прежней:
MQL5\
└── Indicators\
└── HurstProfile\
├── HurstProfile.mq5
└── Includes\
└── MicroStructure_Foundation.mqh Для использования функции LeverageEffect() с GJR-GARCH дополнительно установите библиотеку волатильности Дьюба, описанную и приложенную в статье 22258 сообщества MQL5 (Юн, К. Т., 2026).. После установки добавьте директиву define перед директивой include в индикаторе или советнике:
#define USE_GJR_LEVERAGE #include "Includes\MicroStructure_Foundation.mqh"
Без директивы define файл компилируется и работает с резервной прокси для дисперсии с разделением по знаку доходности. Поле leverage_effect заполняется всегда; его интерпретация зависит от ветви выполнения, как указано в заголовке функции.
Заключение
В этой статье мы переработали и расширили функции волатильности в файле MicroStructure_Foundation.mqh, устранив методологические недостатки, выявленные модератором.
Этот вариант отличается от исходного тремя основными изменениями. Во-первых, функция LeverageEffect() теперь подгоняет модель GJR-GARCH(1,1,1) через библиотеку Дьюба и возвращает нормализованное отношение асимметрии γ/(α + γ + β), а не эвристическую оценку дисперсии следующего бара. Во-вторых, функция MultifractalSpectrum() теперь возвращает Δα, полученную преобразованием Лежандра, и показатель достоверности R² вместо прокси на основе разброса τ. В-третьих, функция JumpIntensity() использует бипауэр-вариацию как базовый уровень: порог остается устойчивым к влиянию тех самых скачков, которые он должен выявлять.
Эмпирическое исследование 514 сессий фьючерса NQ на таймфрейме M1 за май 2024 г. - май 2026 г. подтверждает: парные корреляции трех оценок волатильности выше 0,97; средняя интенсивность скачков на основе бипауэр-вариации составляет 1,4%, и ни в одной сессии она не превышает 5%; медиана Δα, полученной преобразованием Лежандра, равна 0,875 при среднем R², равном 0,972; все 514 сессий проходят порог достоверности R² 0,65.
Практический результат — полностью заполненная структура VolatilityAnalysis: realized_vol и fractional_vol характеризуют уровень волатильности и память; clustering_index — предсказуемость от бара к бару; leverage_effect (GJR) — асимметричную реакцию; jump_intensity отмечает сессии с артефактами; asymmetry описывает распределение доходностей; прокси FIGARCH дает условную дисперсию с поправкой на память, если Δα указывает на сильное смешение режимов. В пятой части эти показатели будут использоваться как обусловливающие входные признаки для оценки микроструктурного шума и анализа потока ордеров.
Список литературы
- Andersen, T.G., Bollerslev, T. & Diebold, F.X. (2007). Roughing it up: Including jump components in the measurement, modeling, and forecasting of return volatility. Review of Economics and Statistics, 89(4), 701–720.
- Baillie, R.T., Bollerslev, T. & Mikkelsen, H.O. (1996). Fractionally integrated generalized autoregressive conditional heteroskedasticity. Journal of Econometrics, 74(1), 3–30.
- Black, F. (1976). Studies of stock price volatility changes. Proceedings of the 1976 Meetings of the American Statistical Association, Business and Economic Statistics Section, 177–181.
- Bollerslev, T. (1986). Generalized Autoregressive Conditional Heteroskedasticity. Journal of Econometrics, 31(3), 307–327.
- Браун, М. (2026a). Рыночная микроструктура в MQL5 (Часть 1): Надежный базовый слой. Статьи сообщества MQL5.
- Браун, М. (2026b). Рыночная микроструктура в MQL5 (Часть 2): Измерение долгой памяти в MQL5 с помощью оценщиков Херста. Статьи сообщества MQL5.
- Браун, М. (2026c). Рыночная микроструктура в MQL5 (Часть 3): Оценка параметра d модели ARFIMA методом GPH. Статьи сообщества MQL5.
- Brown, M. (2026d). Measuring the Memory Structure of Intraday Returns: Evidence from E-mini S&P 500 Futures. SSRN Working Paper 6809080.
- Brown, M. (2026e). Intraday Microstructure Dynamics of E-mini S&P 500 Futures: Volatility Regimes, Liquidity Decay, and Long Memory in Realized Volatility. SSRN Working Paper 6847024.
- Dmitrievsky, M. (2019). Grokking market "memory" through differentiation and entropy analysis. Статьи сообщества MQL5.
- Engle, R.F. (1982). Autoregressive Conditional Heteroskedasticity. Econometrica, 50(4), 987–1007.
- Glosten, L.R., Jagannathan, R. & Runkle, D.E. (1993). On the Relation between the Expected Value and the Volatility of the Nominal Excess Return on Stocks. Journal of Finance, 48(5), 1779–1801.
- Юн, К.Т. (2026a). Построение моделей волатильности в MQL5 (Часть II): Реализация моделей GJR-GARCH и TARCH. Статьи сообщества MQL5, статья 22258.
- Yun, K.T. (2026b). Building Volatility Models in MQL5 (Part III): Implementing the SLSQP Algorithm for Model Estimation. Статьи сообщества MQL5, статья 22714.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/22638
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
За пределами GARCH (Часть V): Подгонка мультифрактального спектра в MQL5
Оптимизация на основе кривых Безье — Bezier Curve-based Optimization (BCO)
За пределами GARCH (Часть IV): Реализация анализа разбиений в MQL5
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования