Построение моделей волатильности в MQL5 (Часть I): Первичная реализация
Введение
В этой статье мы представляем библиотеку MQL5 для моделирования и прогнозирования волатильности. Основная цель — предоставить гибкий инструмент для задания различных типов процессов волатильности. Эти инструменты сопровождаются набором аналитических утилит, используемых для количественной оценки качества построенных моделей. Мы продемонстрируем построение различных процессов волатильности из семейств ARCH и GARCH в MQL5.
Обзор кода
Представленная здесь библиотека вдохновлена пакетом arch в Python — специализированным инструментарием для финансовой эконометрики, ориентированным на модели авторегрессионной условной гетероскедастичности, или ARCH, и обобщённые ARCH-модели, то есть GARCH. Хотя основная функция пакета arch заключается в реализации различных моделей волатильности, он также предоставляет разнообразные возможности для моделирования уравнения среднего, например модели с постоянным средним, нулевым средним или авторегрессионные модели AR. Кроме того, пользователи могут задавать различные распределения для стандартизированных остатков, включая нормальное распределение, распределение Стьюдента и асимметричное распределение Стьюдента. Наша цель — нативно воспроизвести эту функциональность в MQL5.

Архитектура этой нативной реализации является модульной: процесс среднего отделён от процесса волатильности и распределения ошибок. Следовательно, модель представляет собой композицию из этих трёх отдельных компонентов. Процесс среднего выступает в качестве основного компонента, к которому присоединяются остальные; примечательно, что все параметры модели оцениваются совместно через этот центральный компонент. Каждый элемент реализован в виде базового класса, а подклассы представляют конкретные варианты.
Все классы библиотеки следуют стандартизированной структуре. В каждом из них предусмотрен параметрический конструктор в дополнение к конструктору по умолчанию. Кроме того, каждый класс включает метод initialize(), который должен вызываться, когда экземпляр создаётся через конструктор по умолчанию. Для удобства метод initialize() вызывается неявно при использовании параметрического конструктора. В следующих разделах рассматривается реализация процессов среднего, процессов волатильности и распределений ошибок.
Настройка модели
Код для моделирования условного среднего находится в файле mean.mqh. В этом файле класс HARX определён как базовый тип для всех реализаций моделей среднего. Как уже упоминалось, модели среднего также служат основным интерфейсом для полной модели волатильности. Этот класс предоставляет функциональность, необходимую для подгонки моделей к данным и генерации прогнозов.
//+------------------------------------------------------------------+ //| Heterogeneous Autoregression (HAR) | //+------------------------------------------------------------------+ class HARX: public CArchModel { protected: bool _initialize(ArchParameters &vol_dist_params); public: HARX(void):m_extra_simulation_params(0) HARX(ArchParameters& model_specification) ~HARX(void) bool initialize(ArchParameters& vol_dist_params) matrix get_x(void) { return m_model_spec.x; } matrix get_regressors(void) { return m_regressors; } vector get_y(void) { return m_model_spec.y; } virtual vector resids(vector ¶ms, vector &y, matrix ®ressors); virtual ulong num_params(void); bool set_volatility_process(CVolatilityProcess* &vp); bool set_distribution(CDistribution* &dist); virtual matrix simulate(vector ¶ms, ulong nobs, ulong burn, vector &initial_vals,matrix &x, vector &initial_vals_vol); ArchForecast forecast(ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); ArchForecast forecast(matrix& x[],ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); virtual ArchForecast forecast(vector& params, matrix& x[],ulong horizon = 1, long start = -1, ENUM_FORECAST_METHOD method=FORECAST_ANALYTIC, ulong simulations=1000, uint seed=0); ArchModelFixedResult fix(vector& params,long first_obs = 0, long last_obs = -1); ArchModelResult fit(double scaling = 1.0, uint maxits = 0, ENUM_COVAR_TYPE cov_type = COVAR_ROBUST, long first = 0, long last = -1, double tol = 1e-9, bool guardsmoothness=false, double gradient_test_step = 0.0); ArchModelResult fit(vector& startingvalues,vector& backcast, double scaling = 1.0, uint maxits = 0, ENUM_COVAR_TYPE cov_type = COVAR_ROBUST, long first = 0, long last = -1, double tol = 1e-9, bool guardsmoothness=false, double gradient_test_step = 0.0); };
Вариации моделей среднего реализованы как подклассы класса HARX. Параметрические конструкторы всех моделей среднего, а также методы initialize() принимают один и тот же параметр — пользовательскую структуру ArchParameters.
struct ArchParameters { // --- Data & Core Configuration vector observations; matrix exog_data; vector mean_lags; ENUM_MEAN_MODEL mean_model_type; ENUM_VOLATILITY_MODEL vol_model_type; ENUM_DISTRIBUTION_MODEL dist_type; ulong holdout_size; bool is_rescale_enabled; double scaling_factor; // --- Mean Model Parameters bool include_constant; bool use_har_rotation; // --- Volatility Process Parameters (GARCH/ARCH) int vol_rng_seed; ulong garch_p; ulong garch_o; ulong garch_q; double vol_power; long sample_start_idx; long sample_end_idx; ulong min_bootstrap_sims; // --- Distribution Parameters vector dist_init_params; int dist_rng_seed; };
Эта структура инкапсулирует все переменные, необходимые для создания полной модели волатильности. Её свойства перечислены ниже.
| Свойство | Тип данных | Описание |
|---|---|---|
| observations | vector | Этот вектор должен содержать временной ряд, который требуется смоделировать. |
| exog_data | matrix | Необязательная матрица для любых экзогенных переменных, которые должны быть включены в модель. Каждый столбец представляет отдельную переменную, а количество строк должно совпадать с длиной зависимой переменной, заданной в свойстве y структуры. |
| mean_lags | vector | Здесь пользователи могут задавать произвольные лаги для процесса AR или HAR. Для модели AR лаги являются простыми ссылками на предыдущие значения относительно текущего значения. Эти лаги могут быть как последовательными, так и непоследовательными. Для процесса HAR значения лагов представляют длины периодов, или окна просмотра назад, по которым рассчитываются средние значения. |
| mean_model_type | перечисление ENUM_MEAN_MODEL | Это перечисление явно задаёт процесс среднего, используемый для моделирования ожидаемого значения зависимой переменной. В настоящее время реализовано шесть моделей среднего: модель с постоянным средним, модель с нулевым средним, а также процессы AR и HAR — каждый с экзогенными переменными или без них. |
| vol_model_type | перечисление ENUM_VOLATILITY_MODEL | Это свойство определяет процесс волатильности, используемый для моделирования условной дисперсии зависимой переменной y. Доступно семь вариантов — от постоянной дисперсии до различных семейств процессов волатильности ARCH и GARCH. По умолчанию используется процесс с постоянной дисперсией. |
| dist_type | перечисление ENUM_DISTRIBUTION_MODEL | Это свойство представляет собой перечисление, задающее распределение ошибок для полной модели. В настоящее время доступны четыре распределения: нормальное распределение, распределение Стьюдента, асимметричное распределение Стьюдента и обобщённое распределение ошибок, или GED. По умолчанию используется нормальное распределение. |
| holdout_size | unsigned long | Это свойство задаёт количество наблюдений, которые должны быть отложены при подгонке модели к данным. |
| is_rescale_enabled | bool | Этот логический флаг указывает, следует ли проверять масштаб данных. Если он установлен в true, модель оценит масштаб данных; если потребуется перемасштабирование, в терминал MetaTrader 5 будет выведено предупреждение с рекомендацией масштабировать данные, а также с рекомендуемым коэффициентом масштабирования. |
| include_constant | bool | Это логическое свойство указывает, следует ли включать константу в модель среднего. |
| use_har_rotation | bool | Это свойство актуально только тогда, когда задана HAR-модель среднего с лагами. Если оно установлено в true, это означает, что усреднение должно выполняться по непересекающимся периодам. Например, предположим, что заданы лаги {1,5,22}: если это свойство равно false, модель использует средние значения по предыдущим 1, 5 и 22 значениям зависимой переменной. И наоборот, если оно равно true, средние рассчитываются с использованием непересекающихся окон — а именно: первый лаг, равный 1, период от 2 до 5 и период от 6 до 22. |
| vol_rng_seed | integer | Необязательное значение seed для генератора случайных чисел, используемого процессом волатильности. |
| garch_p | unsigned long | Параметр p для процессов ARCH/GARCH. |
| garch_o | unsigned long | Параметр o для процессов типа GARCH. |
| garch_q | unsigned long | Параметр q для процессов типа GARCH. |
| vol_power | double | Параметр степени процесса волатильности типа GARCH. |
| min_bootstrap_sims | unsigned long | Минимальное количество бутстрэп-моделирований, используемых при прогнозировании методом бутстрэпа. |
| dist_init_params | vector | Этот вектор содержит начальные параметры для распределения ошибок. |
| dist_rng_seed | integer | Необязательное значение seed для генератора случайных чисел, используемого заданным распределением. |
Переменная типа ArchParameters должна быть объявлена и настроена до того, как она будет передана либо в параметрический конструктор модели среднего, либо в её метод initialize().
Метод initialize() отвечает за проверку всех параметров, чтобы убедиться, что они корректно соответствуют выбранному процессу среднего, процессу волатильности и распределению ошибок. Любые незначительные конфликты, выявленные на этом этапе, автоматически исправляются без вывода сообщений.
bool _initialize(ArchParameters &vol_dist_params) { if(m_model_spec.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type!=m_model_spec.mean_model_type) { m_initialized = false; Print(__FUNCTION__" Incorrect initialization of mean model. \nMake sure input parameters correspond with the correct class "); return false; } if(m_model_spec.mean_model_type!=WRONG_VALUE && vol_dist_params.mean_model_type==WRONG_VALUE) vol_dist_params.mean_model_type = m_model_spec.mean_model_type; m_model_spec = vol_dist_params; switch(m_model_spec.mean_model_type) { case MEAN_CONSTANT: m_model_spec.mean_lags = vector::Zeros(0); m_name = "Constant Mean"; m_model_spec.include_constant = true; m_model_spec.use_har_rotation = false; break; case MEAN_AR: m_model_spec.use_har_rotation = false; m_model_spec.exog_data = matrix::Zeros(0,0); m_name = "AR"; break; case MEAN_ARX: m_model_spec.use_har_rotation = false; m_name ="AR-X"; break; case MEAN_HAR: m_model_spec.exog_data = matrix::Zeros(0,0); m_name = "HAR"; break; case MEAN_HARX: m_name = "HAR-X"; break; case MEAN_ZERO: m_model_spec.exog_data=matrix::Zeros(0,0); m_model_spec.mean_lags = vector::Zeros(0); m_model_spec.include_constant = false; m_model_spec.use_har_rotation = false; m_name = "Zero Mean"; break; default: m_name = "HAR-X"; break; } m_fit_indices = vector::Zeros(2); m_fit_indices[1] = (m_model_spec.observations.Size())?double(m_model_spec.observations.Size()):-1.; if(m_model_spec.mean_lags.Size()) { switch(m_model_spec.mean_model_type) { case MEAN_AR: case MEAN_ARX: m_lags = matrix::Zeros(2,m_model_spec.mean_lags.Size()); m_lags.Row(m_model_spec.mean_lags,0); m_lags.Row(m_model_spec.mean_lags,1); break; case MEAN_HAR: case MEAN_HARX: m_lags = matrix::Zeros(1,m_model_spec.mean_lags.Size()); m_lags.Row(m_model_spec.mean_lags,0); break; } } else m_lags = matrix::Zeros(0,0); m_constant = m_model_spec.include_constant; m_rescale = m_model_spec.is_rescale_enabled; m_rotated = m_model_spec.use_har_rotation; m_holdback = m_model_spec.holdout_size; m_initialized = _init_model(); if(!m_initialized) return false; m_num_params = num_params(); if(CheckPointer(m_vp)==POINTER_DYNAMIC) delete m_vp; m_vp = NULL; switch(vol_dist_params.vol_model_type) { case VOL_CONST: m_vp = new CConstantVariance(m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; case VOL_ARCH: m_vp = new CArchProcess(m_model_spec.garch_p,m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; case VOL_GARCH: m_vp = new CGarchProcess(m_model_spec.garch_p,m_model_spec.garch_q,m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; default: m_vp = new CConstantVariance(m_model_spec.vol_rng_seed,m_model_spec.min_bootstrap_sims); break; } if(CheckPointer(m_distribution)==POINTER_DYNAMIC) delete m_distribution; m_distribution = NULL; switch(vol_dist_params.dist_type) { case DIST_NORMAL: m_distribution = new CNormal(); break; default: m_distribution = new CNormal(); break; } m_initialized = ( m_distribution!=NULL && m_vp!=NULL && m_vp.is_initialized() && m_distribution.initialize(m_model_spec.dist_init_params, m_model_spec.dist_rng_seed) ); return m_initialized; }
Метод вернёт false только в том случае, если существуют проблемы с выборочными данными или если указанные параметры конфликтуют с предоставленным выборочным рядом; в таких случаях метод возвращает false. Если спецификация модели корректна, метод переходит к инициализации остальных компонентов полной модели. Если на этом втором этапе возникают какие-либо ошибки, метод initialize() помечает их и возвращает false. После успешного выполнения метода initialize() можно начинать процесс подгонки модели.
Совместная оценка параметров модели выполняется путём вызова одного из методов fit().
Подгонка модели к данным
Процедура подгонки выполняется с помощью алгоритма нелинейной оптимизации с ограничениями и предобусловленным расширенным лагранжианом из библиотеки Alglib, реализованного в виде класса CMinNLC. Минимизируемой функцией является функция логарифмического правдоподобия, определённая как член класса HARX.
vector objective(vector& parameters, vector& sigma2, vector &backcast, matrix& varbounds, bool individual=false) { return _loglikelihood(parameters,sigma2,backcast,varbounds,individual); }
Входные параметры методов fit() перечислены и объяснены в таблице ниже.
| Название параметра | Тип данных | Описание |
|---|---|---|
| startingvalues | vector | Вектор начальных значений параметров модели, используемых в процессе оптимизации. Пользователи могут задать собственные значения; в противном случае параметр принимает пустой вектор, и тогда подходящие начальные значения будут рассчитаны автоматически. |
| backcast | vector | Этот вектор используется для оценки параметров процесса условной волатильности. Поскольку уравнение условной дисперсии является рекурсивным, для вычисления первого наблюдения требуются начальные значения, если предвыборочные данные недоступны. Этот параметр также принимает пустой вектор, и в таком случае подходящие значения backcast определяются внутренне. |
| scaling | double | Коэффициент масштабирования, используемый для преобразования выборочного ряда. Оптимизатор работает эффективнее, если ему известно, каким образом данные были преобразованы, если такое преобразование выполнялось. Значение по умолчанию — 1. |
| cov_type | перечисление ENUM_COV_TYPE | Перечисление, задающее метод, используемый для оценки ковариационной матрицы параметров. |
| maxits | unsigned long | Значение, задающее максимальное количество итераций, разрешённых для оптимизатора. |
| first,last | integers | Эти значения являются индексами, задающими начало и конец диапазона в выборочном ряду, который будет использоваться для оценки параметров модели. |
| tol | double | Этот параметр задаёт уровень допуска, или порог, используемый для определения момента сходимости процесса оптимизации. |
| guardsmoothness | bool | Это значение настраивает оптимизатор, включая или отключая мониторинг негладкости. При включении оптимизатор учитывает функции, которые могут быть не идеально дифференцируемыми; дополнительные сведения об этом механизме можно найти в документации ALGLIB. |
| gradient_test_step | double | Если этот параметр включён, то есть установлен в ненулевое значение, он предписывает оптимизатору проверить предоставленную аналитическую функцию градиента или якобиана. Хотя это обеспечивает математическую согласованность и может предотвратить ошибки в логике оптимизации, оно существенно снижает скорость процесса. Обратитесь к документации ALGLIB, чтобы определить подходящее значение конфигурации для конкретного варианта использования. |
Метод fit() возвращает структуру ArchModelResult, которая инкапсулирует результат процесса оптимизации, включая оценённые коэффициенты, статистическую значимость и диагностические показатели модели.
struct ArchModelFixedResult { double loglikelihood; vector params; vector conditional_volatility; ulong nobs; vector resid; }; //+------------------------------------------------------------------+ //| arch model result | //+------------------------------------------------------------------+ struct ArchModelResult: public ArchModelFixedResult { long fit_indices[2]; matrix param_cov; double r2; ENUM_COVAR_TYPE cov_type;
Ниже приведены свойства и методы, содержащиеся в структуре ArchModelResult.
| Название свойства | Тип данных | Описание |
|---|---|---|
| params | vector | Результаты процесса оптимизации, представляющие параметры модели волатильности. Значения организованы в определённом последовательном порядке: Параметры модели среднего: идут первыми, например константа, коэффициенты AR/HAR, экзогенные переменные. Параметры волатильности: идут вторыми, например omega, alpha и beta в процессе GARCH. Параметры распределения: перечисляются последними, например степени свободы или параметры асимметрии. |
| conditional_volatility | vector | Этот вектор содержит внутривыборочную условную волатильность, представляющую прогнозы волатильности модели за период оценки. |
| nobs | integer | Это свойство указывает общее количество наблюдений из выборочного ряда, фактически использованных для подгонки параметров модели. |
| resids | vector | Этот вектор содержит остатки полной модели, представляющие разницу между наблюдаемыми значениями и значениями, предсказанными уравнением среднего. Они могут использоваться для оценки качества подгонки модели. |
| loglikelihood | double | Значение функции логарифмического правдоподобия в точке сходимости. Оно представляет минимальное значение, достигнутое целевой функцией в процессе оптимизации. |
| fit_indices | vector | Этот вектор содержит два элемента, которые явно задают диапазон индексов — начало и конец — выборочного ряда, использованного при оценке модели. |
| param_cov | matrix | Эта матрица содержит оценённую ковариационную матрицу параметров модели. Это квадратная матрица, размерность которой соответствует общему количеству оценённых параметров. |
| r2 | double | Даёт меру доли дисперсии зависимой переменной, объясняемой моделью среднего. |
| cov_type | enumeration | Это свойство указывает конкретный метод или оцениватель, использованный для вычисления ковариационной матрицы параметров. |
Методы структуры ArchModelResult обеспечивают более глубокий статистический анализ, выходящий за рамки простых точечных оценок, чтобы определить, действительно ли модель является адекватной. Ниже приведены статистические методы и метрики, которые они предоставляют:
| tvalues(void) | tvalues(void) — возвращает вектор t-статистик для каждого параметра. Он рассчитывается как отношение оценённого коэффициента к его стандартной ошибке. |
vector tvalues(void) { return params/std_err(); }
| pvalues(void) | pvalues(void) — возвращает p-значения, связанные с t-статистиками. Это помогает определить вероятность того, что наблюдаемое значение параметра возникло случайно; обычно значение меньше 0.05 указывает на статистическую значимость. |
vector pvalues(void) { vector pvals = tvalues(); for(ulong i = 0; i<pvals.Size(); ++i) pvals[i] = CAlglib::NormalCDF(-1.0*MathAbs(pvals[i]))*2.0; return pvals; }
| rsquaredadj(void) | Возвращает скорректированный коэффициент детерминации R² для модели среднего. В отличие от стандартного R², этот показатель штрафует за включение лишних переменных, показывая, какая доля дисперсии объясняется моделью с учётом её сложности. |
double rsquared_adj(void) { return 1.0 - ((1.0-r2)*double(nobs-1)/double(nobs-num_params())); }
| stderror(void) | Возвращает стандартные ошибки параметров. Они отражают точность оценок; меньшие ошибки указывают на более надёжные оценки параметров. |
vector std_err(void) { return sqrt(param_cov.Diag()); }
Если процесс оптимизации не сходится, свойства ArchModelResult, как правило, будут содержать значения по умолчанию, а вектор params будет пустым. Поэтому считается хорошей практикой проверять вектор params перед выполнением какого-либо анализа или прогнозирования.
Прогнозирование
После успешной подгонки модели прогнозирование выполняется с помощью перегруженного метода forecast. Такая гибкость позволяет генерировать прогнозы на основе различных входных данных. Следующие параметры используются в разных перегрузках метода forecast для формирования будущих оценок волатильности и среднего.
| Название параметра | Тип данных | Описание |
|---|---|---|
| horizon | unsigned long | Целое число, определяющее горизонт прогнозирования. Оно задаёт, на сколько шагов вперёд модель будет прогнозировать как условное среднее, так и условную волатильность. Значение по умолчанию — 1. |
| start | integer | Этот параметр определяет точку в вашем ряде данных, которая служит началом прогноза. Он задаёт, за каким наблюдением непосредственно последуют будущие прогнозные значения. По умолчанию устанавливается последний доступный индекс в данных. |
| method | ENUM_FORECAST_METHOD | Этот параметр определяет математический подход, используемый для прогнозирования будущей волатильности. Хотя модель среднего обычно следует стандартной схеме, процесс волатильности может прогнозироваться несколькими способами в зависимости от сложности модели. Возможные варианты: Analytic, Simulation или Bootstrap. По умолчанию используется Analytic. Аналитический метод использует замкнутые математические формулы для вычисления ожидаемой дисперсии. Однако у него есть существенное ограничение, связанное с параметром степени. Если модель предполагает, что дисперсия выражается через квадраты остатков, аналитический метод работает для любого горизонта. В противном случае, если модель использует степень, отличную от 2, аналитический метод нельзя применять для горизонтов больше одного. Это связано с тем, что математическое ожидание нелинейного преобразования не имеет простого рекурсивного решения. Метод симуляции, или Монте-Карло, использует предполагаемое распределение для моделирования множества возможных траекторий и усредняет их. В то же время метод бутстрэпа напрямую выполняет повторную выборку из исторических остатков для построения будущих траекторий без предположения о конкретном распределении. |
| simulations | integer | Целое число, задающее количество траекторий или случайных выборок, которые необходимо сгенерировать. Используется исключительно тогда, когда параметр method установлен в Simulation или Bootstrap. |
| seed | integer | Необязательное целое значение, используемое для инициализации генератора псевдослучайных чисел, или RNG. Оно обеспечивает воспроизводимость случайных траекторий, сгенерированных во время прогнозирования методом симуляции или бутстрэпа. |
| params | vector | Необязательный вектор коэффициентов. Если он предоставлен, прогноз будет рассчитан с использованием этих конкретных значений вместо результатов внутреннего метода fit(). |
| x | array of matrices | Этот параметр актуален, когда модель среднего включает экзогенные переменные. Поскольку эти переменные являются внешними по отношению к самому процессу волатильности, модель не может "предсказать" их будущие значения; они должны быть заранее заданы для формирования полного прогноза. Если модель была подогнана с k экзогенными переменными, этот входной параметр необходим для вычисления прогноза. Обратите особое внимание на размерности каждой матрицы, переданной для этой переменной. Требуемая форма зависит от параметра horizon, количества экзогенных переменных и значения start относительно размера выборочного ряда, использованного для построения модели. Размер массива, то есть общее количество матриц, должен быть равен количеству экзогенных переменных. Для каждой матрицы количество строк должно быть как минимум равно разнице между общим размером выборки и начальным индексом, то есть началом прогноза. Наконец, количество столбцов должно соответствовать параметру horizon. |
При вызове метод forecast() возвращает структуру ArchForecast. Этот контейнер инкапсулирует прогнозируемые траектории как для среднего, так и для волатильности. Структура организована в три основные матрицы.
//+------------------------------------------------------------------+ //| arch forecast result | //+------------------------------------------------------------------+ struct ArchForecast { matrix mean; matrix variance; matrix residual_variance;
Матрица mean содержит прогнозные значения условного среднего, то есть ожидаемой цены или доходности. Поле variance содержит матрицу прогнозных значений условной дисперсии. И наконец, матрица residual_variance представляет прогнозы условной дисперсии остатков.
Валидация модели
После подгонки модели тест множителей Лагранжа, или LM-тест, иногда называемый ARCH-тестом Энгла, является стандартным диагностическим инструментом, используемым для проверки того, остаются ли в остатках какие-либо ARCH-эффекты, то есть гетероскедастичность. Если модель адекватна, остатки должны представлять собой белый шум; это означает, что тест не должен выявлять значимой автокорреляции в квадратах остатков. Функция archlmtest() оценивает это, выполняя регрессию квадратов остатков на их собственные лаги.
//+------------------------------------------------------------------+ //| The Lagrange multiplier test | //+------------------------------------------------------------------+ WaldTestStatistic archlmtest(vector& residuals,vector& conditional_volatility,ulong lags,bool standardized = false) { WaldTestStatistic out; vector resids = residuals; if(standardized) resids = resids/conditional_volatility; if(resids.HasNan()) { vector nresids = vector::Zeros(resids.Size() - resids.HasNan()); for(ulong i = 0, k = 0; i<resids.Size(); ++i) if(MathClassify(resids[i]) == FP_NAN) continue; else nresids[k++] = resids[i]; resids = nresids; } int nobs = (int)resids.Size(); vector resid2 = MathPow(resids,2.0); if(!lags) lags = ulong(ceil(12.0*pow(nobs/100.0,1.0/4.0))); lags = MathMax(MathMin(resids.Size()/2 - 1,lags),1); if(resid2.Size()<3) { Print(__FUNCTION__, " Test requires at least 3 non-nan observations "); return out; } matrix matres = matrix::Zeros(resid2.Size(),1); matres.Col(resid2,0); matrix lag[]; if(!lagmat(matres,lag,lags,TRIM_BOTH,ORIGINAL_SEP)) { Print(__FUNCTION__, " lagmat failed "); return out; } matrix lagout; if(!addtrend(lag[0],lagout,TREND_CONST_ONLY,true,HAS_CONST_SKIP)) { Print(__FUNCTION__, " addtrend failed "); return out; } lag[0] = lagout; OLS ols; if(!ols.Fit(lag[1].Col(0),lag[0])) { Print(__FUNCTION__, " OLS fitting failed "); return out; } out.stat = nobs*ols.Rsqe(); if(standardized) { out.null = "Standardized residuals are homoskedastic"; out.alternative = "Standardized residuals are conditionally heteroskedastic"; } else { out.null = "Residuals are homoskedastic"; out.alternative = "Residuals are conditionally heteroskedastic"; } out.df = lags; return out; }
Для неё требуются следующие входные параметры.
| Название параметра | Тип данных | Описание |
|---|---|---|
| residuals | vector | Вектор остатков, полученный из ArchModelResult. Это исходные ошибки подогнанной модели. |
| conditional_volatility | vector | Внутривыборочная условная волатильность для подогнанной модели. |
| lags | unsigned long | Целое число, задающее количество лагов, которые нужно включить в тестовую регрессию. |
| standardized | bool | Этот логический флаг указывает, следует ли стандартизировать остатки с использованием conditional_volatility. |
Вызов функции archlmtest() возвращает структуру WaldTestStatistic.
//+------------------------------------------------------------------+ //|Test statistic holder for Wald-type tests | //+------------------------------------------------------------------+ struct WaldTestStatistic { ulong df; double stat; string null; string alternative; WaldTestStatistic(void) { stat = EMPTY_VALUE; df = 0; null = alternative = NULL; } WaldTestStatistic(double _stat, ulong _df, string _null, string _alt) { stat = _stat; df = _df; null = _null; alternative = _alt; } WaldTestStatistic(WaldTestStatistic &other) { stat = other.stat; df = other.df; null = other.null; alternative = other.alternative; } void operator=(WaldTestStatistic &other) { stat = other.stat; df = other.df; null = other.null; alternative = other.alternative; } double pvalue(void) { int ecode = 0; double val = 1.- MathCumulativeDistributionChiSquare(stat,double(df),ecode); if(ecode) Print(__FUNCTION__," Chisquare cdf error ", ecode); return val; } vector critical_values(void) { vector out = {0.9,0.95,0.99}; int ecode = 0; for(ulong i = 0; i<out.Size(); ++i) out[i] = MathQuantileChiSquare(out[i],double(df),ecode); if(ecode) Print(__FUNCTION__," Chisquare cdf error ", ecode); return out; } };
Эта структура содержит формальные статистические результаты, необходимые для определения того, успешно ли модель устранила кластеры волатильности из данных.
| Название свойства | Тип данных | Описание |
|---|---|---|
| df | unsigned long | Степени свободы теста, что соответствует количеству лагов, указанному при вызове функции. |
| stat | double | Рассчитанная тестовая статистика. При нулевой гипотезе это значение следует распределению хи-квадрат. |
| pvalue(void) | double | Метод pvalue() возвращает вероятность наблюдения тестовой статистики, столь же экстремальной, как рассчитанная, при условии, что ARCH-эффекты больше не сохраняются. |
| crtical(void) | vector | Метод critical() возвращает вектор критических значений для трёх уровней доверия: 90%, 95% и 99%. |
Для оценки адекватности модели мы в первую очередь смотрим на p-значение. Если p-значение больше 0.05, это означает, что модель проходит проверку. Это означает, что мы не можем отвергнуть нулевую гипотезу. Такой результат указывает на то, что остатки являются гомоскедастичными, то есть имеют постоянную дисперсию, а значит, модель ARCH/GARCH выполнила свою задачу. С другой стороны, если p-значение меньше или равно 0.05, мы отвергаем нулевую гипотезу. Это означает, что ARCH-эффекты всё ещё сохраняются в остатках, и модель, вероятно, является неадекватной. В таком случае может потребоваться увеличить порядок лагов или попробовать другой тип модели. Значение stat увеличивается по мере роста корреляции в квадратах остатков. Очень большое значение stat приведёт к очень малому p-значению, сигнализируя о том, что модель пропустила значимые паттерны волатильности.
Пример с включением экзогенных переменных
В этом разделе демонстрируется, как задать модель, включающую экзогенные переменные. Буква X в ARX и HARX относится к этим внешним независимым переменным в уравнении регрессии. В данной структуре моделируемый временной ряд выступает в качестве зависимой переменной, тогда как экзогенные предикторы передаются в виде матрицы, где каждый столбец представляет одну переменную.
Чтобы проиллюстрировать гибкость экзогенных переменных, мы рассмотрим интересную взаимосвязь между моделями ARX и гетерогенными авторегрессионными моделями, или HAR. Используя усреднённые исторические данные как экзогенные входные переменные в модели ARX, мы можем воспроизвести поведение HAR-модели. Это сравнение подчёркивает как практическое применение экзогенных переменных, так и базовую структуру HAR-моделей. HAR-модель была специально разработана для моделирования реализованной волатильности на финансовых рынках, хотя её можно адаптировать и для других переменных. Она называется "гетерогенной", потому что разбивает влияние прошлого на разные временные горизонты — краткосрочный, среднесрочный и долгосрочный — исходя из предположения, что разные типы участников рынка реагируют на волатильность на разных временных масштабах.

Наиболее распространённая версия HAR-модели использует измерения реализованной волатильности по трём длинам периодов: краткосрочной, среднесрочной и долгосрочной. Каждый период определяет количество временных точек, используемых для расчёта средней реализованной волатильности. HAR-модель улавливает долгосрочную память в волатильности за счёт перекрывающихся средних членов.
Модель ARX объединяет стандартный авторегрессионный процесс, или AR, с экзогенными входными переменными (Х). Она предполагает, что текущее значение зависит от собственных прошлых значений, а также от текущих или прошлых значений внешних переменных. Общая формула модели ARX(p,q) выглядит следующим образом.

Скрипт HAR_as_ARX_Demo.ex5 демонстрирует, как модель ARX может использоваться для имитации HAR-модели. Скрипт выполняет следующие шаги:
- Строит стандартную HAR-модель с использованием выбираемого количества усреднённых членов.
- Задаёт ARX-модель, используя те же усреднённые члены в качестве матрицы экзогенных входных данных.
- Сравнивает параметры обеих моделей, чтобы продемонстрировать их эквивалентность.
//+------------------------------------------------------------------+ //| HAR_as_ARX_Demo.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include<Arch\Univariate\mean.mqh> //--- input parameters input string Symbol_="AUDUSD"; input ENUM_TIMEFRAMES TimeFrame=PERIOD_D1; input datetime StartDate=D'2025.01.01'; input ulong HistoryLen = 504; input double ScaleFactor=100.; input bool MeanConstant = true; input string MeanLags ="1,5,22"; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //---download data vector prices; if(!prices.CopyRates(Symbol_,TimeFrame,COPY_RATES_CLOSE,StartDate,HistoryLen)) { Print(" failed to get close prices for ", Symbol_,". Error ", GetLastError()); return; } //--- prices = log(prices); //--- vector returns = np::diff(prices); //--- string lag_info[]; //--- vector lags=vector::Zeros(0); //--- int nlags = StringSplit(MeanLags,StringGetCharacter(",",0),lag_info); //--- double atod; if(nlags>0) { for(uint i = 0; i<uint(nlags); ++i) { if(StringLen(lag_info[i])>0) { atod = StringToDouble(lag_info[i]); if(atod>0 && ulong(atod)<returns.Size()-1) if(lags.Resize(lags.Size()+1,3)) lags[lags.Size()-1] = atod; } } } //--- if(lags.Size()) np::sort(lags); //---build the HAR model ArchParameters har_spec; har_spec.observations=returns*ScaleFactor; har_spec.include_constant = MeanConstant; har_spec.mean_lags = lags; har_spec.vol_model_type = VOL_CONST; //--- HAR harmodel; //--- if(!harmodel.initialize(har_spec)) return; //--- ArchModelResult har = harmodel.fit(ScaleFactor); //--- if(!har.params.Size()) { Print("Convergence failed ", GetLastError()); return; } //--- Print(" Har model parameters\n", har.params); //---Now we build an equivalent ARX model matrix exogvars = matrix::Zeros(returns.Size(),lags.Size()); //---calculate averages double sum; ulong lag,count; for(ulong i = 0; i<exogvars.Cols(); ++i) { lag = (ulong)lags[i]; count = lag; for(ulong k = lag; k<exogvars.Rows(); ++k) { sum = 0.0; for(ulong j = 0; j<count; ++j) sum+=returns[k-j-1]; exogvars[k,i] = sum/double(count); } } //--- ArchParameters arx_spec; arx_spec.observations = ScaleFactor*np::sliceVector(returns,long(lags[lags.Size()-1])); arx_spec.exog_data = ScaleFactor*np::sliceMatrixRows(exogvars,long(lags[lags.Size()-1])); arx_spec.include_constant = MeanConstant; arx_spec.vol_model_type=VOL_CONST; //--- ARX arxmodel; if(!arxmodel.initialize(arx_spec)) return; //--- ArchModelResult arx = arxmodel.fit(ScaleFactor); if(!arx.params.Size()) { Print(" convergence failed ", GetLastError()); return; } //--- Print("ARX model parameters\n", arx.params); } //+------------------------------------------------------------------+
Скрипт был запущен с параметрами по умолчанию.

В результате был получен следующий вывод, показывающий параметры подогнанных моделей.
NR 0 22:12:43.671 HAR_as_ARX_Demo (XAUUSD,D1) Har model parameters CE 0 22:12:43.672 HAR_as_ARX_Demo (XAUUSD,D1) [-0.02336784243846212,-0.04576660950059414,0.02963893847811298,-0.1589020837643845,0.3352700836173772] RE 0 22:12:43.691 HAR_as_ARX_Demo (XAUUSD,D1) ARX model parameters HN 0 22:12:43.691 HAR_as_ARX_Demo (XAUUSD,D1) [-0.02336784243846212,-0.04576660950059416,0.02963893847811294,-0.1589020837643847,0.3352700836173772]
Демонстрация подтверждает, что оба подхода дают идентичные параметры модели, как показано в выводе скрипта.
Заключение
В этой статье мы заложили основу для нативного моделирования волатильности в MQL5. Стандартизировав интерфейс с помощью структур ArchParameters и ArchModelResult, мы создали рабочий процесс, который позволяет задавать спецификацию модели, выполнять оптимизацию и проводить валидацию. Этот фреймворк позволяет просто и последовательно инициализировать модель, подгонять её к набору данных и выполнять строгие диагностические проверки, такие как тест ARCH-LM, чтобы убедиться, что остатки свободны от гетероскедастичности.
Хотя текущая версия библиотеки реализует несколько базовых процессов волатильности, на данный момент она ограничена предположением, что распределения ошибок следуют стандартному нормальному распределению. В следующей части мы реализуем более продвинутые процессы волатильности и расширим библиотеку, добавив поддержку более широкого набора распределений ошибок. Весь код, связанный со статьёй, приведён ниже.
| Файл | Описание |
|---|---|
| MQL5/include/Arch | Эта папка содержит все заголовочные файлы библиотеки моделирования волатильности. |
| MQL5/include/Regression | Эта папка содержит некоторые регрессионные утилиты, используемые в коде моделирования волатильности. |
| MQL5/include/np.mqh | Этот заголовочный файл содержит различные утилиты для работы с векторами и матрицами. |
| MQL5/scripts/HAR_as_ARX_Demo.mq5 | Это скрипт, демонстрирующий спецификацию HAR-модели как AR-модели с экзогенными переменными. |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/20589
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Автоматизация торговых стратегий в MQL5 (Часть 26): Создание системы усреднения на основе пин-баров для многопозиционной торговли
Тестер стратегий для Python и MetaTrader 5 (Часть 02): Работа с барами, тиками и реализация встроенных функций в симуляторе
Разработка инструментария для анализа Price Action (Часть 43): Вероятностный анализ свечных паттернов и пробоев
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Очень интересная идея!
Сочетание волатильности нескольких таймфреймов.
Очень интересная идея!
Сочетание волатильности нескольких таймфреймов.