Рыночная микроструктура в MQL5 (Часть 1): Надежный базовый слой
Введение
Вы торгуете NQ вблизи открытия нью-йоркской сессии и поэтому анализируете рыночную микроструктуру на минутном уровне, чтобы вовремя реагировать на резкие движения цены. На такой частоте стандартные вычисления могут давать скрытые сбои: возникают NaN/Inf и переполнения при делении на значения, близкие к нулю, вычислении логарифма от неположительной цены, обработке нулевых или отсутствующих цен закрытия на краю истории и оценке дисперсии по очень малым выборкам. Это не ошибки компиляции — это правдоподобно выглядящие числовые значения, которые вводят в заблуждение логику принятия решений.
Эта статья посвящена устранению такого инженерного недостатка. У статьи конкретная практическая цель: создать защитный базовый слой на языке MQL5, который не допускает скрытые численные сбои при внутридневных расчетах. Статья адресована разработчикам на языке MQL5, которые работают с внутридневными данными через CopyClose и SymbolInfoDouble, например с NQ на таймфрейме M1. Результат — компилируемый подключаемый файл. Он проверяет минимальный размер выборки, отклоняет недопустимые ценовые данные, ограничивает и проверяет математические операции, а также предоставляет устойчивые статистические и спектральные функции для последующего расчета показателей микроструктуры.
Чем отличаются внутридневные данные
Исследования показывают, что у внутридневных ценовых данных есть статистические свойства, нехарактерные для данных с меньшей частотой наблюдений. Как отмечает Энгл (2000), наблюдения на такой частоте поступают через неравномерные интервалы времени; для данных характерны тяжелые хвосты распределения, кластеризация волатильности и долговременная зависимость. Это не редкие пограничные случаи, а определяющие свойства данных.
Тяжелые хвосты распределения означают, что экстремальные значения встречаются гораздо чаще, чем предполагает нормальное распределение. При открытии нью-йоркской сессии на NQ цена за один минутный бар может пройти больше, чем за весь предыдущий час. Расчет, основанный на предположении о нормальном распределении доходностей, даст неверный результат именно тогда, когда точность важнее всего.
Кластеризация волатильности означает, что за крупными движениями цены часто следуют другие крупные движения, а за небольшими — небольшие. Это не случайный шум, а структурная закономерность. Но оценка волатильности, полученная для спокойного периода, может оказаться опасно неточной в период высокой активности.
Долговременная зависимость означает, что у рынка есть "память". Движение цены час назад по-прежнему статистически связано с тем, что происходит сейчас. При стандартных расчетах на коротком окне эта информация полностью теряется.
Из-за этих свойств в коде MQL5 без защитных проверок возможны характерные ошибки: вычисление логарифма от неположительной цены, деление на нулевую дисперсию и обращение к массиву при разреженных исторических данных. Ни один из этих случаев не вызывает ошибки компиляции. В результате появляются недопустимые, иногда огромные числовые значения, которые незаметно попадают во все последующие вычисления.
Базовый слой нужен, чтобы выявлять такие ошибки до того, как их результаты попадут в ключевые расчеты.
Архитектура инструментария
Прежде чем писать код, стоит понять, что именно мы будем создавать на протяжении всей серии.

Рисунок 1. Структура серии из двенадцати частей. Каждая статья опирается на общий подключаемый файл, созданный в первой части. Статьи сгруппированы по темам: фрактальный анализ (части 2 и 3), волатильность (часть 4), микроструктурный шум и поток ордеров (части 5 и 6), сигналы с учетом времени и трендовые индикаторы (части 7, 8 и 9), сезонность (часть 10), а также синтез результатов (части 11 и 12).
В каждой статье серии создаются функции, использующие базовый слой. SafeLog, SafeDivide и SafeSqrt используются почти во всех последующих расчетах. Общие структуры данных RobustFractalAnalysis, OrderFlowSignal и TimeAwareSignal служат контейнерами для передачи результатов между разными статьями серии. БПФ включено в базовый слой, поскольку используется в нескольких частях серии. В части 3 БПФ используется для расчета мультифрактального спектра, в части 10 — для анализа сезонности по Фурье, а в части 11 — для синтетического фракционного гауссовского шума.
Если сначала создать базовый слой, в последующих статьях можно сосредоточиться на логике измерений и не повторять типовой код защитных проверок. Кроме того, когда вы соберете весь инструментарий, его компоненты будут говорить на одном языке.
Подключаемый файл имеет следующую структуру:
//+------------------------------------------------------------------+ //| MicroStructure_Foundation.mqh | //| Market Microstructure in MQL5: Robust Foundation — Part 1 of 12 | //| | //| DEPENDS ON : nothing | //| REQUIRED BY : Parts 2 through 12 | //+------------------------------------------------------------------+
Константы и конфигурация
Начнем с констант, задаваемых при компиляции: они определяют числовые границы для всего инструментария.
//+------------------------------------------------------------------+ //| CONSTANTS | //+------------------------------------------------------------------+ #define DBL_MIN_POSITIVE 1e-20 // Smallest value treated as non-zero in division and log guards #define MS_DBL_EPSILON 1e-10 // General floating-point comparison tolerance #define MATH_PI 3.14159265358979323846 // Pi to full double precision for FFT and trigonometric use #define MIN_SAMPLE_SIZE 8 // Minimum bars required before any statistical calculation proceeds #define MAX_SAMPLE_SIZE 5000 // Maximum bars fetched in a single CopyClose call #define MAX_AGGREGATION_LEVEL 10 // Maximum scale levels used in aggregated variance estimators #define NUMERICAL_STABILITY_BOUND 1e100 // Any result exceeding this is treated as a numerical failure #define GMT_OFFSET_HOURS 2 // Broker GMT offset; adjust if your broker runs on a different zone
DBL_MIN_POSITIVE — минимальное значение, которое при защитных проверках деления и логарифмирования считается ненулевым. Использовать встроенную константу MQL5 DBL_MIN для этой проверки было бы слишком жестким решением: в нормализованных расчетах микроструктуры встречаются и допустимые малые значения. Порог 1e-20 позволяет выявлять значения, считающиеся нулевыми при проверке, не отклоняя при этом все малые допустимые результаты.
NUMERICAL_STABILITY_BOUND задает максимальное значение результата, считающегося допустимым. Если результат расчета превышает 1e100, при вычислении произошла ошибка. Это верхняя граница проверки, которая отсекает аномально большие значения, подобные примеру, упомянутому во введении.
MIN_SAMPLE_SIZE равен 8: для любого статистического расчета требуется как минимум восемь точек данных. Если точек данных меньше, результат не имеет статистического смысла, даже если формула выглядит математически корректной.
Значение GMT_OFFSET_HOURS, равное 2, соответствует времени брокера GMT+2. В седьмой части определение торговых сессий опирается на это смещение. Если время брокера имеет другое смещение, измените эту константу один раз — и все зависящие от времени расчеты подстроятся автоматически.
Структуры данных
В инструментарии используются общие структуры данных для передачи результатов анализа между функциями и их повторного использования в разных статьях серии. Если определить их здесь, в последующих статьях структуры не придется объявлять заново.
//+------------------------------------------------------------------+ //| Primary result container for fractal and long-memory analysis. | //| Confidence fields support weighted blending of estimators. | //| computation_status: 0 = success, non-zero = specific failure. | //+------------------------------------------------------------------+ struct RobustFractalAnalysis { double hurst_exponent; // Weighted-average Hurst exponent across estimators double hurst_confidence; // Confidence weight for the Hurst estimate (0–1) double fractal_dimension; // Higuchi fractal dimension blended with Hurst fallback double dimension_confidence; // Confidence weight for the fractal dimension estimate double arfima_d; // GPH fractional differencing parameter d double multifractal_width; // Spectrum width from MFDFA-style tau(q) regression double volatility_persistence; // Normalised persistence: 2 * |H - 0.5| double microstructure_noise; // Enhanced noise estimate from range, body, and close-open double seasonality_strength; // Intraday seasonality ratio (edge vs midday variance) int computation_status; // 0 = success; non-zero codes indicate failure mode string validation_message; // Human-readable description of any failure condition };
Именно поля hurst_confidence и dimension_confidence отличают эту реализацию от упрощенной. Во второй части реализованы три независимых оценщика показателя Херста; их результаты объединяются с весами, зависящими от степени доверия к каждой оценке. Без этих полей негде было бы сохранять промежуточные результаты объединения оценок. Поле computation_status содержит целочисленный код: ноль означает успешное выполнение, ненулевое значение — конкретную ошибку. Благодаря этому вызывающий код может обнаружить и обработать ошибку, а не принять неверный результат за правдоподобное значение.
//+------------------------------------------------------------------+ //| Composite order flow signal combining directional pressure, | //| momentum, exhaustion, and smart-money contribution. | //| direction_numeric enables downstream arithmetic without | //| string comparisons. | //+------------------------------------------------------------------+ struct OrderFlowSignal { double strength; // Volume-weighted directional imbalance (-1 to +1) double momentum; // Short-window minus long-window flow differential double exhaustion; // Current absolute flow relative to recent peak double smart_money; // Large-bar directional bias (signed volume ratio) double convergence; // Mean signal score across sub-indicators double confidence; // Signal reliability weight (0–1) string direction; // "BULLISH", "BEARISH", or "NEUTRAL" double direction_numeric; // +1.0, -1.0, or 0.0 for use in calculations };
У каждого поля структуры OrderFlowSignal есть свое назначение. Сила характеризует дисбаланс по направлениям; импульс — скорость его изменения; истощение отражает ослабление потока ордеров, а smart_money — влияние баров с высоким объемом. Поле direction_numeric предназначено для дальнейших вычислений: в математических выражениях направление нужно представлять числом, а не сравнивать строки.
//+------------------------------------------------------------------+ //| Time-aware composite signal layering session context over flow. | //| Embeds OrderFlowSignal and adds regime, liquidity, and event | //| adjustments for session-adaptive position sizing. | //+------------------------------------------------------------------+ struct TimeAwareSignal { OrderFlowSignal flow_signal; // Underlying order flow analysis double fractal_synergy; // Hurst-regime aligned with flow direction double time_regime_multiplier; // Session weight: 1.5 at NY open, 0.5 off-peak double session_liquidity_factor; // Spread-based liquidity scaling (0.3–1.2) double pre_event_boost; // Additive boost near scheduled events double final_signal; // Combined directional signal (-2 to +2) double time_adjusted_confidence; // Confidence scaled by regime and liquidity string time_context; // Human-readable session label datetime signal_time; // TimeCurrent() at signal generation double time_until_event; // Minutes until next scheduled event double max_position_size; // Suggested size fraction (0–1) double stop_loss_multiplier; // ATR stop multiplier based on confidence };
TimeAwareSignal — составной результат вычислений из седьмой части. В TimeAwareSignal входит OrderFlowSignal; дополнительно учитывается контекст торговой сессии. Поля stop_loss_multiplier и max_position_size позволяют учитывать качество сигнала при выборе размера позиции: сигнал с высокой степенью уверенности при открытии нью-йоркской сессии предполагает иной размер позиции, чем такой же сигнал во время азиатской сессии.
Здесь также определено перечисление PULLBACK_QUALITY, которое используется в девятой части:
//+------------------------------------------------------------------+ //| Pullback quality classification based on Fibonacci retracement | //| depth relative to the most recent swing range. | //+------------------------------------------------------------------+ enum PULLBACK_QUALITY { PBQ_NO_TREND = 0, // No identifiable trend; classification not meaningful PBQ_STRONG = 1, // Retrace below 23.6%: trend intact, shallow pullback PBQ_HEALTHY = 2, // Retrace 23.6%–38.2%: normal corrective structure PBQ_WARNING = 3, // Retrace 38.2%–61.8%: deeper correction, caution advised PBQ_DEEP = 4, // Retrace above 61.8%: trend at risk of reversal PBQ_BROKEN = 5 // Retrace beyond 100%: trend structure broken };
Математические функции с защитными проверками
Это ядро базового слоя. Каждая функция дополняет стандартную математическую операцию защитной проверкой, выявляющей описанные выше ошибки.
SafeDivide
//+------------------------------------------------------------------+ //| SafeDivide: two-gate guard. | //| Gate 1 checks denominator before division. | //| Gate 2 checks result for overflow or NaN after division. | //+------------------------------------------------------------------+ double SafeDivide(double numerator, double denominator, double fallback = 0.0) { if(!MathIsValidNumber(denominator) || MathAbs(denominator) < DBL_MIN_POSITIVE) return fallback; double result = numerator / denominator; if(!MathIsValidNumber(result) || MathAbs(result) > NUMERICAL_STABILITY_BOUND) return fallback; return result; }
Две проверки, а не одна. Первая проверяет знаменатель до выполнения деления. Вторая проверяет полученный результат. Так выявляется ситуация, когда числитель и знаменатель по отдельности допустимы, но при делении из-за особенностей арифметики с плавающей точкой возникает переполнение или NaN. По умолчанию резервное значение равно нулю, но вызывающий код может задать другое значение с учетом контекста.
SafeLog
//+------------------------------------------------------------------+ //| SafeLog: guards against non-positive input. | //| Fallback of -20.0 signals "invalid point" to downstream | //| regression slope calculations without distorting the fit. | //+------------------------------------------------------------------+ double SafeLog(double x, double fallback = -20.0) { if(!MathIsValidNumber(x) || x <= 0) return fallback; double result = MathLog(x); if(!MathIsValidNumber(result)) return fallback; return result; }
Резервное значение -20.0 выбрано намеренно. В этом инструментарии результаты SafeLog чаще всего используются при регрессионном анализе логарифмически преобразованных данных. Нулевое резервное значение исказило бы результат регрессии. Большое по модулю отрицательное значение помечает точку как выброс, который при расчете наклона регрессии естественным образом получает меньший приоритет. Поэтому резервное значение не равно нулю: для последующих расчетов это числовой маркер недопустимой точки.
SafeSqrt и SafeExp
//+------------------------------------------------------------------+ //| SafeSqrt: guards against negative radicand. | //+------------------------------------------------------------------+ double SafeSqrt(double x, double fallback = 0.0) { if(!MathIsValidNumber(x) || x < 0) return fallback; double result = MathSqrt(x); if(!MathIsValidNumber(result)) return fallback; return result; } //+------------------------------------------------------------------+ //| SafeExp: soft-clips extreme inputs rather than hard-failing. | //| Large inputs are not always bad data; they can be valid | //| log-return values. Clamping preserves scale while avoiding NaN. | //+------------------------------------------------------------------+ double SafeExp(double x, double fallback = 0.0) { if(!MathIsValidNumber(x)) return fallback; if(x > 100) return 1e100; if(x < -100) return 1e-100; double result = MathExp(x); if(!MathIsValidNumber(result)) return fallback; return result; }
SafeExp мягко ограничивает экстремальные входные значения, чтобы предотвратить переполнение. Большие входные значения не обязательно означают ошибку в данных: они могут быть допустимыми значениями логарифмической доходности. Такое ограничение сохраняет масштаб значений и помогает избежать NaN/Inf.
SafeTanh
//+------------------------------------------------------------------+ //| SafeTanh: soft-bounding operator used throughout order flow. | //| Compresses signals smoothly to [-1, +1] without hard clipping. | //| DBL_MIN_POSITIVE in the denominator prevents degenerate zero. | //+------------------------------------------------------------------+ double SafeTanh(double x) { if(!MathIsValidNumber(x)) return 0.0; if(x > 10.0) return 1.0; if(x < -10.0) return -1.0; double ex = SafeExp(x); double emx = SafeExp(-x); return (ex - emx) / (ex + emx + DBL_MIN_POSITIVE); }
В шестой части SafeTanh используется в функциях анализа потока ордеров для мягкого ограничения значений. Вместо резкого отсечения значений сигнала за пределами диапазона функция плавно сжимает их. DBL_MIN_POSITIVE в знаменателе предотвращает деление на ноль, если в вырожденном случае обе экспоненты одновременно округляются до нуля.
Проверка данных и доступ к ним
ValidateSymbolV2
//+------------------------------------------------------------------+ //| ValidateSymbolV2: three-attempt validation with spread check. | //| Returns true immediately for the current chart symbol. | //| Spread above 10000 points indicates a data feed problem. | //+------------------------------------------------------------------+ bool ValidateSymbolV2(const string symbol) { if(symbol == NULL || symbol == "") return false; if(symbol == Symbol()) return true; for(int i = 0; i < 3; i++) { double bid = SymbolInfoDouble(symbol, SYMBOL_BID); double ask = SymbolInfoDouble(symbol, SYMBOL_ASK); double point = SymbolInfoDouble(symbol, SYMBOL_POINT); if(bid > 0 && ask > 0 && ask > bid && point > 0) { double spread = (ask - bid) / point; if(spread < 10000) return true; } Sleep(10); } return false; }
Три попытки с паузой 10 миллисекунд между ними. Проверка, что спред меньше 10 000 пунктов, служит контролем корректности: превышение этого порога может указывать на проблему с потоком котировок или на инструмент, недоступный для торговли. Для символа текущего графика функция сразу возвращает true. Это избавляет от лишнего запроса рыночных данных в наиболее распространенном случае.
SafeCopyClose
//+------------------------------------------------------------------+ //| SafeCopyClose: validated data fetch with per-value zero check. | //| Caps request at MAX_SAMPLE_SIZE to prevent memory overrun. | //| Returns 0 if any copied bar has a non-positive close price. | //+------------------------------------------------------------------+ int SafeCopyClose(const string symbol, const int tf, const int start, const int count, double &out[]) { if(!ValidateSymbolV2(symbol) || count <= 0) return 0; int safe_count = MathMin(count, MAX_SAMPLE_SIZE); ArraySetAsSeries(out, true); int copied = CopyClose(symbol, (ENUM_TIMEFRAMES)tf, start, safe_count, out); if(copied <= 0) return 0; for(int i = 0; i < copied; i++) if(out[i] <= 0) return 0; return copied; }
Ограничение MAX_SAMPLE_SIZE значением 5 000 предотвращает запрос на выделение объема памяти, который терминал не сможет предоставить. Проверка каждого скопированного значения выявляет случаи, когда CopyClose завершается успешно, но возвращает бары с нулевой ценой закрытия. Такое возможно на границе доступной истории. При частичном сбое лучше вернуть ноль, чем частично корректный массив: последующие функции могли бы обработать его, не зная о недопустимых значениях.
Статистические примитивы
mean_var
//+------------------------------------------------------------------+ //| mean_var: two-pass variance estimation. | //| Two passes avoid numerical instability when the mean is large | //| relative to the variance, as is typical with price data. | //+------------------------------------------------------------------+ void mean_var(const double &arr[], const int n, double &mean, double &var) { mean = 0; var = 0; if(n <= 0) return; for(int i = 0; i < n; i++) mean += arr[i]; mean /= n; for(int i = 0; i < n; i++) var += (arr[i] - mean) * (arr[i] - mean); var /= n; }
Используются два прохода, а не один: однопроходная формула дисперсии численно нестабильна, когда среднее значение велико относительно дисперсии. Такое возможно и для ценовых данных.
robust_mean_var
//+------------------------------------------------------------------+ //| robust_mean_var: trimmed mean and variance with higher moments. | //| Removes the most extreme 10% of values symmetrically before | //| computing mean, variance, skewness, and excess kurtosis. | //| Falls back to mean_var if the trimmed sample is too small. | //+------------------------------------------------------------------+ void robust_mean_var(const double &arr[], const int n, double &mean, double &var, double &skew, double &kurt) { mean = 0; var = 0; skew = 0; kurt = 0; if(n < 4) return; double sorted[]; ArrayResize(sorted, n); ArrayCopy(sorted, arr, 0, 0, n); ArraySort(sorted); int trim = MathMax(1, (int)(n * 0.10)); int used = n - 2 * trim; if(used < 4) { mean_var(arr, n, mean, var); return; } for(int i = trim; i < n - trim; i++) mean += sorted[i]; mean /= used; for(int i = trim; i < n - trim; i++) var += MathPow(sorted[i] - mean, 2); var /= used; double sd = SafeSqrt(var); if(sd > DBL_MIN_POSITIVE) { for(int i = trim; i < n - trim; i++) { double z = (sorted[i] - mean) / sd; skew += MathPow(z, 3); kurt += MathPow(z, 4); } skew /= used; kurt = kurt / used - 3.0; } }
Именно эта функция отличает инструментарий от упрощенной реализации. При симметричном усечении на 10% наиболее экстремальные значения исключаются до расчета среднего и дисперсии. На NQ с таймфреймом M1 при открытии нью-йоркской сессии такие экстремальные значения реальны, а не вызваны ошибками измерения. Но они не должны определять статистическую оценку типичного поведения. Если данных слишком мало для обоснованного усечения, используется стандартная функция mean_var.
В четвертой части показатели асимметрии и эксцесса используются для анализа волатильности. Высокий эксцесс указывает на тяжелые хвосты распределения. Для NQ при открытии нью-йоркской сессии это почти всегда характерно.
LinearRegressionSlope
//+------------------------------------------------------------------+ //| LinearRegressionSlope: ordinary least squares slope estimate. | //| Used by Hurst estimators (Part 2), fractal dimension (Part 3), | //| and multifractal spectrum (Part 3). Centralising here ensures | //| identical arithmetic across all three. SafeDivide guards against | //| the degenerate case where all x values are identical. | //+------------------------------------------------------------------+ double LinearRegressionSlope(const double &x[], const double &y[], int n) { if(n < 2) return 0.0; double sx = 0, sy = 0, sxy = 0, sxx = 0; for(int i = 0; i < n; i++) { sx += x[i]; sy += y[i]; sxy += x[i] * y[i]; sxx += x[i] * x[i]; } double denom = n * sxx - sx * sx; return SafeDivide(n * sxy - sx * sy, denom); }
Во второй части эту функцию использует каждый оценщик показателя Херста, а в третьей — расчеты фрактальной размерности и мультифрактального спектра. Поскольку функция определена в одном месте, во всех трех расчетах используются одни и те же арифметические операции. SafeDivide защищает от деления на ноль в вырожденном случае, когда все значения x одинаковы.
Реализация БПФ
БПФ включено в базовый слой, поскольку используется в нескольких частях серии. В части 3 БПФ используется для расчета мультифрактального спектра, в части 10 — для анализа сезонности по Фурье, а в части 11 — для синтетического фракционного гауссовского шума. Общая реализация избавляет от трех отдельных версий БПФ, которые со временем могли бы начать различаться.
//+------------------------------------------------------------------+ //| FFT IMPLEMENTATION | //| Cooley-Tukey radix-2 in-place. Input length must be power of 2. | //| Reused by: Part 3 (multifractal), Part 10 (Fourier seasonality), | //| Part 11 (fractional Gaussian noise generation). | //+------------------------------------------------------------------+ void fft(const double &real_in[], const double &imag_in[], double &real_out[], double &imag_out[], int n, bool inverse) { ArrayResize(real_out, n); ArrayResize(imag_out, n); ArrayCopy(real_out, real_in, 0, 0, n); ArrayCopy(imag_out, imag_in, 0, 0, n); //--- Bit-reversal permutation int j = 0; for(int i = 1; i < n; i++) { int bit = n >> 1; for(; (j & bit) != 0; bit >>= 1) j ^= bit; j ^= bit; if(i < j) { double tr = real_out[i]; real_out[i] = real_out[j]; real_out[j] = tr; double ti = imag_out[i]; imag_out[i] = imag_out[j]; imag_out[j] = ti; } } //--- Cooley-Tukey butterfly for(int len = 2; len <= n; len <<= 1) { double ang = 2.0 * MATH_PI / len * (inverse ? -1 : 1); double wr = MathCos(ang); double wi = MathSin(ang); for(int i = 0; i < n; i += len) { double cr = 1.0, ci = 0.0; for(int k = 0; k < len / 2; k++) { double ur = real_out[i + k]; double ui = imag_out[i + k]; double vr = real_out[i + k + len / 2]; double vi = imag_out[i + k + len / 2]; double pvr = vr * cr - vi * ci; double pvi = vr * ci + vi * cr; real_out[i + k] = ur + pvr; imag_out[i + k] = ui + pvi; real_out[i + k + len / 2] = ur - pvr; imag_out[i + k + len / 2] = ui - pvi; double ncr = cr * wr - ci * wi; ci = cr * wi + ci * wr; cr = ncr; } } } //--- Normalise output for inverse transform if(inverse) for(int i = 0; i < n; i++) { real_out[i] /= n; imag_out[i] /= n; } }
Это стандартная БПФ Кули — Тьюки с основанием 2, выполняемая на месте. Длина входных данных должна быть степенью двойки. Во всех частях серии это требование проверяется до вызова функции. Флаг inverse включает обратное БПФ: знак угла поворотного множителя меняется на противоположный, а результат делится на n. Для прямого и обратного преобразований используется один и тот же код "бабочки". Это делает реализацию компактнее и уменьшает риск расхождений между двумя направлениями преобразования.
Завершение работы над подключаемым файлом
Базовый слой готов. В следующих статьях используйте этот относительный путь к подключаемому файлу, чтобы не изменять глобальную папку MQL5\Include:
#include "Includes\MicroStructure_Foundation.mqh"
Благодаря этой строчке кода все функции и структуры из статьи становятся доступны индикатору или советнику, подключившему файл. В область видимости попадают функции безопасной математики, проверки данных, статистические оценщики и БПФ. Во второй части можно сразу перейти к расчету показателя Херста, не повторяя типовой код защитных проверок.
Заключение
Реализованный здесь базовый слой устраняет незаметные ошибки вычислений, из-за которых результаты анализа внутридневной рыночной микроструктуры могут оказаться непригодными для практического применения. MicroStructure_Foundation.mqh — это единый подключаемый файл, который можно добавить в любой индикатор или советник. Он задает четко определенные гарантии, благодаря которым последующим измерениям можно доверять.
Практический результат:
- математические функции с защитными проверками (SafeDivide, SafeLog, SafeSqrt, SafeExp, SafeTanh), которые предотвращают NaN/Inf и мягко ограничивают значения во избежание переполнения;
- функции проверки рыночных данных по символу и чтения истории (ValidateSymbolV2, SafeCopyClose), которые отклоняют недоступные для торговли инструменты, аномальные значения спреда и неположительные цены закрытия;
- численно устойчивые статистические функции (двухпроходный расчет дисперсии, усеченные оценки, наклон по методу наименьших квадратов), устойчиво работающие при тяжелых хвостах и смене режима рынка;
- единая реализация БПФ для согласованных спектральных расчетов.
Благодаря этим защитным проверкам показатели микроструктуры перестают вводить в заблуждение в критические моменты. Во второй части на основе базового слоя будут реализованы три независимых оценщика показателя Херста. Их результаты объединяются с учетом степени доверия к каждой оценке; для вычислений используются описанные здесь функции с защитными проверками.
Список литературы
- Engle, R. (2000). The econometrics of ultra-high-frequency data. Econometrica, 68(1), 1–22.
- Madhavan, A. (2000). Market microstructure: a survey. Journal of Financial Markets, 3, 205–258.
- Dacorogna, M., Gencay, R., Muller, U., Olsen, R., and Pictet, O. (2001). An Introduction to High-Frequency Finance. Academic Press.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/22263
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Нейроструктурный торговый движок — NSTE (Часть II): Шестиступенчатый квантовый фильтр "Врата Джардина"
Свинговые экстремумы и откаты в MQL5 (Часть 3): Определение структурной валидности за рамками простых максимумов и минимумов
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования