Разработка научно обоснованного сеточного советника в MQL5: Почему большинство сеточных советников терпят неудачу и что доказал Таранто
Введение
У сеточной торговли плохая репутация. Спросите любого опытного трейдера о сеточных советниках — и ответ будет предсказуем: "Все выглядит отлично, пока советник не обнулит счет". И они правы. Известная статья MQL5 "Сетка и мартингейл: что это такое и как их использовать?" математически доказывает, что наивная сетка стремится к разорению. Бесчисленные темы на форумах и слитые демо-счета подтверждают эту закономерность: стабильная прибыль неделями или месяцами, а затем катастрофический убыток, за считанные дни уничтожающий все.
Однако полностью отвергать сеточную торговлю из-за этих неудач — значит, выражаясь словами из научной литературы, "чрезмерно упрощать итоговую стохастическую систему". Та же математика, которая объясняет неудачу сеток без ограничений, показывает, за счет чего сетка с ограничениями и возможностью перезапуска может быть жизнеспособной и при каких условиях ее можно использовать с прибылью.
Эта статья основана на докторском исследовании Альдо Таранто, выполненном в Университете Южного Квинсленда в 2020-2022 годах. В исследовании сеточная торговля была формализована как двунаправленный ограниченный сеточный стохастический процесс BGC, выведены условия положительного математического ожидания и доказано, что работа без ограничений приводит к почти верному разорению. В исследовании также выявлен механизм, предотвращающий разорение: конечные перезапускаемые циклы с фильтрацией запуска с учетом режима рынка.
Представленный здесь советник — не наивная сетка. Это менеджер циклов, адаптивный к режиму рынка, с тремя режимами работы: BGT для бокового рынка, TGT для тренда и MGT для возврата к среднему после тренда. Он также включает динамический шаг сетки на основе ATR, расчет размера лота на основе эквити, обнаружение структурных сдвигов с помощью CUSUM и диагностический конвейер с сопутствующими инструментами на Python.
Мы рассмотрим следующие темы:
- Задача сеточной торговли — не задача о разорении игрока
- Формула убытка и аварийный выключатель, работающий в реальном времени
- Рост дисперсии, почти верное разорение и механизм перезапуска
- Динамический шаг сетки на основе ATR и динамический расчет размера лота
- Определение режима — VolatilityGate и обнаружение точек изменения
- Три режима сетки — BGT, TGT и MGT
- Промышленная архитектура — фильтры входа, сохранение состояния и диагностика
- Тестирование стратегии
- Диагностический конвейер — анализ и калибровка сетки
- Заключение
Полный исходный код советника, всех девяти заголовочных модулей и обоих сопутствующих скриптов Python приложен в конце статьи.
Задача сеточной торговли — не задача о разорении игрока
Самая серьезная ошибка в обсуждении сеточной торговли — предположение, что сеточные советники представляют собой мартингейловые системы в другой оболочке. Это не так. Таранто и Хан (2020) доказали, что задача сеточной торговли (GTP) и задача о разорении игрока (GRP) — математически разные процессы с принципиально различающимися темпами накопления убытков.
Мартингейл: экспоненциальный рост убытков
В классическом мартингейле — задаче о разорении игрока — ставка удваивается после каждого проигрыша. После n последовательных неблагоприятных шагов совокупный убыток составляет 2^n. Это экспоненциальный рост. Чтобы пережить 10 неблагоприятных шагов, требуется 1 024 единицы капитала. Двадцать таких шагов требуют уже более миллиона единиц капитала. "Смертельная спираль" развивается быстро и безжалостно; каждый опытный трейдер справедливо предостерегает от стратегий мартингейла.
Сеточная торговля — треугольный рост убытков
В двунаправленной сетке — задаче сеточной торговли (GTP) — стратегия не удваивает ставку. Вместо этого на каждом пройденном ценой уровне сетки добавляется одна новая убыточная позиция. После n уровней направленного движения совокупный убыток составляет не 2^n, а треугольное число n(n+1)/2. Это квадратичный рост — значительно более медленный, чем экспоненциальный.
Практическая разница весьма существенна:

Рис. 1. Сравнение роста убытков при мартингейле и сеточной торговле
| Количество пройденных неблагоприятных уровней | Убыток при мартингейле (2^n) | Убыток сетки (n(n+1)/2) | Преимущество сетки с точки зрения выживаемости |
|---|---|---|---|
| 1 | 2 | 1 | 2x |
| 3 | 8 | 6 | 1,3x |
| 5 | 32 | 15 | 2,1x |
| 8 | 256 | 36 | 7,1x |
| 10 | 1024 | 55 | 18,6x |
При 10 неблагоприятных движениях советнику с мартингейлом требуется 1 024 единицы капитала, чтобы выжить. Сеточному советнику требуется всего 55 единиц капитала — примерно в 18 раз меньше. В этом состоит фундаментальное преимущество сеточной торговли перед мартингейлом с точки зрения выживаемости. Это не делает сеточные стратегии безопасными. Это делает их пригодными для инженерной настройки и контроля: более медленный рост убытков дает время обнаружить неблагоприятные условия и вмешаться до того, как ущерб станет непоправимым.
Формальное разграничение — семимартингейл
Таранто формализовал это различие с помощью стохастического дифференциального уравнения BGC:
dX = [f(X,t) - sgn[X,t] · Ψ(X,t)] dt + g(X,t) dW_t
Ключевым элементом здесь является ограничивающая функция BGC Ψ(X,t). Она описывает математический эффект сетки: чем дальше цена отклоняется от начала сетки, тем сильнее ей противодействует структура. Это не жесткий барьер, а мягкое постепенно нарастающее сопротивление, усиливающееся по мере удаления. Сетка создает скрытые отражающие барьеры, возникающие при взаимодействии ее структуры с движением цены.
Благодаря этой ограничивающей функции задача сеточной торговли (GTP) классифицируется как семимартингейл — стохастический процесс, который при определенных условиях может иметь подлинно положительное математическое ожидание. Чистый мартингейл, например задача о разорении игрока, по определению имеет нулевой ожидаемый дрейф. Семимартингейл может иметь положительный дрейф. В этом состоит математическое обоснование того, почему сеточная торговля может работать при правильно заданных ограничениях, тогда как стратегии мартингейла не могут.
В диссертации в качестве теоремы 52 была выведена вероятность выигрыша трейдера в GTP при стартовом капитале i монет, на уровне сетки x, при общем числе монет n:
P(выигрыш трейдера | уровень сетки x) = [1 - ((x+1)/2)^i] / [1 - ((x+1)/2)^n]
Формула убытка и аварийный выключатель, работающий в реальном времени
Наиболее значимый с практической точки зрения результат исследования — формула совокупного убытка. Она позволяет в любой момент определить совокупную экспозицию по плавающему убытку всего по двум величинам: насколько цена снизилась от сессионного максимума и насколько выросла от сессионного минимума.
Определения
Просадка D_t — расстояние в уровнях сетки, на которое цена снизилась от своего максимума с начала цикла сетки:
D_t = floor((SessionHigh - CurrentPrice) / g), где g — шаг сетки в ценовых единицах.
Подъем от минимума U_t — расстояние в уровнях сетки, на которое цена выросла от своего минимума с начала цикла сетки:
U_t = floor((CurrentPrice - SessionLow) / g)
На основе этих двух величин совокупная экспозиция по убытку равна:
L_t = 1/2 * (D_t^2 + D_t + U_t^2 + U_t) — формула совокупного убытка Таранто и Хана, определяющая экспозицию по убыточным позициям в единицах уровней сетки.
Конкретный пример
Рассмотрим сетку с шагом g = 50 пунктов, привязанную к уровню 1,1000. Цена поднялась до сессионного максимума 1,1250, затем опустилась до сессионного минимума 1,0850 и сейчас находится на уровне 1,0900. Следует учитывать, что D_t измеряется от максимума сессии до текущей цены, а не от точки привязки, поэтому он охватывает как движение вверх, так и частичный откат.
Для текущей цены: D_t = floor((1.1250 - 1.0900) / 0.0050) = 7 уровней (от максимума сессии до текущей цены). U_t = floor((1.0900 - 1.0850) / 0.0050) = 1 уровень (от минимума сессии до текущей цены).
Следовательно: L_t = 1/2 * (49 + 7 + 1 + 1) = 29 единиц убыточных сделок.
Проверка позиций по отдельности не требуется. Для расчета общей экспозиции корзины позиций достаточно SessionHigh, SessionLow, CurrentPrice и g. Именно поэтому L_t эффективен: это расчет риска с постоянной вычислительной сложностью O(1).
На диаграмме ниже показано, как D_t и U_t соотносятся с траекторией цены, пересекающей уровни сетки:

Рис. 2. Визуализация формулы L_t с D_t, U_t и убыточными позициями на уровнях сетки
Коэффициент близости к разорению
Сам по себе L_t показывает число единиц убыточных сделок. Чтобы использовать этот показатель на практике, его нормируют относительно эквити, доступного для текущего цикла:
RPR = L_t / E0_cycle — коэффициент близости к разорению, показывающий, насколько текущий цикл близок к исчерпанию маржи.
Теория и реальность — почему мы используем эквити вместо L_t
Формула L_t Таранто математически корректна при допущениях модели: одинаковые лоты на каждом уровне, каждый уровень исполняется ровно один раз, а сетка не выставляет повторно закрытые уровни. Наш советник нарушает все три допущения.
При повторном выставлении один и тот же уровень сетки может исполниться, закрыться по тейк-профиту, быть повторно выставлен, снова исполниться и снова принести убыток — и все это в рамках одного цикла. Формула L_t учитывает каждый уровень только один раз на основе экстремумов сессии, поэтому фактический убыток может быть выше. Напротив, принцип рефракции, сформулированный в теореме 57 диссертации, доказывает, что для колебательных траекторий L_t завышает экспозицию, поскольку использует экстремумы сессии, а не учитывает конкретный порядок пересечения уровней.
Решение: L_t и RPR вычисляются и записываются в лог как диагностические показатели, полезные для анализа после прогона и калибровки. Однако аварийный выключатель, работающий в реальном времени, использует прямое измерение эквити, которое учитывает все: плавающие убытки, реализованные убытки внутри цикла, свопы, комиссии и весь ущерб от повторного выставления.
Ниже показано, как советник вычисляет L_t в диагностических целях:
//+------------------------------------------------------------------+ //| Compute theoretical Lt in grid-level units | //| (Taranto & Khan formula: Lt = 1/2(Dt^2 + Dt + Ut^2 + Ut)) | //+------------------------------------------------------------------+ double ComputeLt(const GridSession &session, double bid) { double dtPrice = session.sessionHigh - bid; double utPrice = bid - session.sessionLow; if(dtPrice < 0) dtPrice = 0; if(utPrice < 0) utPrice = 0; double dtLevels = MathFloor(dtPrice / session.gridSpacing); double utLevels = MathFloor(utPrice / session.gridSpacing); //--- Cap to actual grid depth dtLevels = MathMin(dtLevels, (double)session.totalLevels); utLevels = MathMin(utLevels, (double)session.totalLevels); return 0.5 * (dtLevels * dtLevels + dtLevels + utLevels * utLevels + utLevels); }
Мы вычисляем dtPrice и utPrice как исходные ценовые расстояния от сессионного максимума и минимума до текущей цены Bid, ограничивая отрицательные значения нулем. Значения преобразуются в уровни сетки с помощью MathFloor, ограничиваются фактической глубиной сетки с помощью MathMin, после чего применяется треугольная формула убытка.
Ниже приведен работающий в реальном времени аварийный выключатель — прямая просадка на основе эквити, рассчитываемая на каждом тике:
//--- Equity-based cycle drawdown (runs every tick) double cycleDrawdown = 0; if(g_session.cycleStartEquity > 0) { double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY); cycleDrawdown = (g_session.cycleStartEquity - currentEquity) / g_session.cycleStartEquity; } //--- Tighter threshold for MGT (post-trend recovery) double effectiveKillThreshold = InpRuinThreshold; if(g_session.gridMode == GRID_MODE_MGT && InpMGTKillThreshold > 0) effectiveKillThreshold = InpMGTKillThreshold; //--- Only fire when real money is at risk (not a blocked zero-position cycle) bool cycleIsEmpty = (g_cycleBlocked && openPositionCount == 0); if(!cycleIsEmpty && cycleDrawdown >= effectiveKillThreshold) { if(g_session.gridMode == GRID_MODE_TGT) g_lastCycleWasTGTKill = true; //--- triggers MGT next cycle g_gridCore.CloseAllPositions(g_session, killOrphans); g_session.cycleCount++; g_stateManager.ClearState(); StartNewCycle(); return; }
Аварийный выключатель вычисляет cycleDrawdown как процентное снижение эквити относительно его значения на начало цикла, используя AccountInfoDouble с ACCOUNT_EQUITY. Стоит отметить два нюанса. Во-первых, в режиме MGT — режиме возврата к среднему после тренда, рассмотренном в разделе 6, — используется более жесткий порог аварийного выключателя, поскольку циклы MGT несут более высокий структурный риск. Во-вторых, проверка cycleIsEmpty предотвращает срабатывание аварийного выключателя в заблокированном цикле без открытых позиций. Без этого пустой приостановленный цикл многократно запускал бы логику выхода и приводил бы к неконтролируемому ошибочному росту счетчиков циклов. Когда аварийный выключатель срабатывает в цикле TGT, флаг g_lastCycleWasTGTKill переводит следующий цикл в режим MGT.
Рост дисперсии, почти верное разорение и механизм перезапуска
Понимание причин отказов сеточных советников лежит в основе проектирования каждого механизма безопасности. В исследовании выявлены два математических процесса, приводящих к отказу. Их строгое доказательство делает механизм выживания обоснованным, а не основанным лишь на надежде.
Дисперсия эквити экспоненциально растет со временем
Таранто вывел полное решение для эквити в двунаправленной сеточной системе. Ожидаемое значение эквити имеет вид:
E[E_t] = E_0 · exp([v·t + (2v·mu_t/g) - (v·sigma_t^2/g) - (2v^2·sigma_t^2/g^2)] · t)
Параметры: E_0 — начальное эквити; v — прибыль на уровень сетки; g — шаг сетки; mu_t — дрейф, или сила тренда; sigma_t — диффузия, то есть волатильность, измеряемая через ATR; t — прошедшее время. Но ключевой результат — дисперсия:
Var[E_t] растет как exp(4v^2 · sigma_t^2 / g^2 · t)
Это математически подтверждает наблюдение опытных трейдеров: сетка, работающая 200 часов, существенно опаснее сетки, работающей 20 часов, даже если кривая эквити выглядит схожей. Диапазон возможных исходов, то есть дисперсия, расширяется экспоненциально. Чем дольше продолжается отдельный цикл, тем выше вероятность катастрофического события.
Почти верное разорение при стремлении x к бесконечности
В диссертации формально доказано в разделе 10.1.1, что, если отдельный цикл сетки продолжается бесконечно долго:
- lim (x → ∞) P(трейдер выигрывает) = 0
- lim (x → ∞) P(брокер выигрывает) = 1
Если цена продолжает двигаться по тренду, а сетка продолжает расширяться, трейдер разорится с вероятностью 1. В диссертации уточняется: этот результат "предполагает, что тренд продолжается бесконечно, чего на практике не бывает". Доказательство задает верхнюю границу вероятности разорения. Однако структурный вывод очевиден.
Ни один сеточный советник не может работать бесконечно без механизма перезапуска. Это математическое доказательство, а не гипотеза. Перезапуск — это не стоп-лосс, а сброс дисперсии, возвращающий конечную вероятность разорения для следующего цикла.
Механизм перезапуска
В исследовании прямо сказано: "Возможность закрывать часть сделок или все сделки, когда система находится в прибыли, а затем снова запускать сеточную систему формирует благоприятный цикл положительного денежного потока". Когда цикл завершается и перезапускается, одновременно сбрасываются две величины. Переменная времени t возвращается к нулю, сбрасывая экспоненциальное накопление дисперсии. Уровень сетки x возвращается к нулю, сбрасывая накопление убытков и вновь привязывая сетку к текущей цене.
Перезапуск работает, поскольку в благоприятных условиях сетка имеет положительное математическое ожидание. Условие прибыльности, полученное из решения для эквити, имеет вид:
v·t + (2v·mu_t/g) > (v·sigma_t^2/g) + (2v^2·sigma_t^2/g^2)
Левая часть отражает накопление — выигрыш, зависящий от времени, плюс вклад дрейфа. Правая часть — штраф за дисперсию. Когда волатильность sigma_t умеренная, а дрейф mu_t низкий, как на боковом рынке, доминирует левая часть. Когда возникает сильный тренд, это условие перестает выполняться. Перезапуск позволяет зафиксировать прибыль до того, как дисперсия размоет результат.
Теория и реальность — как и L_t, условие прибыльности правильно отражает общий характер зависимости, но для промышленной эксплуатации недостаточно точно в количественном плане. Точный порог, при котором условие перестает выполняться, зависит от частоты повторного выставления, спредовых издержек и конкретной траектории прохождения через сетку. Это условие используется, чтобы определить, в каком режиме должна работать сетка, по отношению sigma_t/mu_t, а не для расчета сигнала "разрешить/запретить" на каждом тике.
Ниже показано закрытие корзины позиций по целевой прибыли — ядро логики перезапуска:
//--- Profit Monitor (throttled every 10 ticks) double cycleProfit = g_profitMonitor.GetCycleProfit(g_session.cycleStartEquity); if(g_profitMonitor.CheckProfitTarget(cycleProfit, g_session.cycleStartEquity, InpUseProfitPercent, InpProfitTargetDollars, InpProfitTargetPercent)) { //--- Close the entire basket in one shot g_session.state = GRID_STATE_CLOSING; int closedCount = g_gridCore.CloseAllPositions(g_session, profitOrphans); //--- Guard: if broker didn't close everything, retry next tick int remaining = g_profitMonitor.GetPositionCount(); if(remaining > 0) { g_session.state = GRID_STATE_ACTIVE; return; } //--- Book profit, increment cycle, wipe state double finalProfit = g_profitMonitor.GetCycleProfit(g_session.cycleStartEquity); g_session.cumulativeProfit += finalProfit; g_session.cycleCount++; g_stateManager.ClearState(); //--- Restart — variance clock resets here StartNewCycle(); return; }
При проверке прибыли текущее эквити сравнивается с эквити на начало цикла с использованием процентного или фиксированного долларового целевого уровня. По умолчанию целевой уровень прибыли на цикл составляет 3%. При достижении целевого уровня CloseAllPositions() закрывает корзину позиций. Защитная проверка оставшихся позиций повторяет попытку на следующем тике, если брокер не выполнил все закрытия за один проход. После подтверждения счетчик циклов увеличивается на единицу, сохраненное состояние очищается, а StartNewCycle() вновь закрепляет сетку на текущей цене, используя новый шаг сетки, рассчитанный по ATR, и размер лота на основе эквити. Здесь сбрасывается таймер накопления дисперсии.

Рис. 3. Рост дисперсии и механизм перезапуска
Три условия завершения цикла
Закрытие по достижении целевой прибыли — предпочтительный вариант завершения. Однако у советника есть три основных механизма завершения цикла: (1) выход по просадке на основе эквити — аварийный выключатель из раздела 2, основной защитный выход; (2) выход по достижении целевой прибыли — перезапуск после фиксации прибыли, рассматриваемый в этом разделе; (3) выход по предельному возрасту цикла, срабатывающий безусловно при превышении InpMaxCycleHours, по умолчанию 72 часов. Выход по предельному возрасту безусловен, поскольку доказательство экспоненциального роста дисперсии означает, что более длительный цикл статистически опаснее независимо от текущего P&L. Еще один механизм: (4) закрытие всех позиций перед выходными — все позиции принудительно закрываются в пятницу для защиты от риска гэпа.
Четыре состояния рынка
Соотношение дрейфа mu_t и волатильности sigma_t определяет, работает ли сетка при положительном или отрицательном математическом ожидании:
| Состояние рынка | Дрейф mu_t | Волатильность sigma_t | Результат работы сетки |
|---|---|---|---|
| Боковой рынок + высокая волатильность | Низкий | Высокая | Наилучший вариант — быстрое получение прибыли и частые закрытия уровней |
| Боковой рынок + низкая волатильность | Низкий | Низкий | Хороший результат — медленное, но стабильное накопление прибыли |
| Трендовый рынок + высокая волатильность | Высокая | Высокая | Допустимо — контртрендовые колебания дают передышку |
| Трендовый рынок + низкая волатильность | Высокая | Низкий | Худший вариант — устойчивый тренд и максимальное накопление убытков |
Опасный сценарий связан не с высокой волатильностью, порождающей контртрендовые колебания и закрывающей прибыльные позиции. Опасность представляет направленный тренд с низкой волатильностью: цена последовательно проходит уровень за уровнем, а убытки накапливаются по треугольному закону без встречных движений. Именно этот "тихий тренд" призвана выявлять система обнаружения режима, описанная в разделе 5. Вывод о том, что состояние "тренд + волатильность" скорее допустимо, чем фатально, лежит в основе режима TGT, описанного в разделе 6. Если тренд удается выявить, сетка может извлекать из него прибыль, а не бороться с ним.
Главный вывод анализа чувствительности
В диссертации представлен полный анализ чувствительности, см. главу 6, рис. 6.6. Этот вывод определяет всю архитектуру:
| Параметр | Влияние на эквити | Следствие |
|---|---|---|
| sigma_t (волатильность) | Доминирующее | Самая важная переменная в процессе работы |
| mu_t (дрейф) | Доминирующее | Второй по важности — тренд представляет основную опасность |
| g (ширина сетки) | Умеренное | Влияет на время наступления разорения, а не на сам факт его наступления |
| v (прибыль на уровень) | Низкий | Изменяет денежные суммы, но не структурную динамику |
Из этого следует прямое архитектурное требование: проектирование советника должно быть сосредоточено на измерении sigma_t и mu_t и реагировании на них. Оптимизировать шаг сетки или размер лота без учета режима — значит решать не ту задачу. Именно поэтому система использует VolatilityGate и CPDEngine для обнаружения режима, а также три сеточных алгоритма для разных соотношений sigma_t/mu_t.
Динамический шаг сетки на основе ATR и динамический расчет размера лота
Хотя анализ чувствительности показывает, что шаг сетки g оказывает лишь умеренное влияние по сравнению с sigma_t и mu_t, шаг, безопасный при волатильности прошлого месяца, может оказаться опасно малым при волатильности текущего. В диссертации, в исследовании оптимизации с помощью генетического алгоритма из раздела 10.6.2, установлено, что оптимальный статический шаг для валютного рынка составляет примерно 10-15% среднего дневного диапазона. Следовательно, шаг должен масштабироваться с учетом текущей волатильности инструмента, а не быть жестко заданной константой.
Динамический шаг сетки на основе ATR
Советник пересчитывает шаг сетки при каждом перезапуске цикла на основе отдельного хэндла ATR на таймфрейме D1. Формула проста: g = ATR(period, D1) × multiplier; значение ограничивается настраиваемыми нижним и верхним пределами. Шаг сетки не изменяется в середине цикла — иначе структура уровней сетки стала бы несогласованной. Перезапуск цикла — естественная точка повторной калибровки.
Важное проектное решение: для расчета шага сетки используется ATR на дневном таймфрейме D1, а для определения режима — ATR на H4. Это разные задачи. Для расчета шага сетки нужна широкая оценка дневного диапазона, чтобы задать масштаб сеточной лестницы. Для обнаружения режима нужен многочасовой сигнал, достаточно чувствительный, чтобы иметь значение в цикле, который обычно длится от нескольких часов до нескольких дней.
//+------------------------------------------------------------------+ //| ATR-dynamic grid spacing — recalculated at each cycle start | //+------------------------------------------------------------------+ double ComputeATRSpacing() { if(!InpUseATRSpacing || g_spacingATRHandle == INVALID_HANDLE) return InpGridSpacing * SymbolInfoDouble(_Symbol, SYMBOL_POINT); double atrBuffer[]; ArraySetAsSeries(atrBuffer, true); if(CopyBuffer(g_spacingATRHandle, 0, 1, 1, atrBuffer) <= 0) { PrintFormat("[BGC Grid] ATR spacing buffer copy failed; using fixed spacing"); return InpGridSpacing * SymbolInfoDouble(_Symbol, SYMBOL_POINT); } double atrValue = atrBuffer[0]; double spacingPrice = atrValue * InpATRSpacingMultiplier; //--- Clamp to [min, max] in price units double pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT); double minSpacingPrice = InpMinGridSpacingPts * pointSize; double maxSpacingPrice = InpMaxGridSpacingPts * pointSize; spacingPrice = MathMax(spacingPrice, minSpacingPrice); spacingPrice = MathMin(spacingPrice, maxSpacingPrice); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); spacingPrice = NormalizeDouble(spacingPrice, digits); return spacingPrice; }
Функция считывает завершенное значение ATR на D1, используя индекс бара 1 и исключая незавершенный бар 0, с помощью CopyBuffer. Затем оно умножается на InpATRSpacingMultiplier, по умолчанию 0,12, и ограничивается диапазоном [min, max] пунктов. Если хэндл ATR недействителен или не удается скопировать буфер, используется фиксированный шаг сетки. Результат нормализуется с учетом точности символа по числу знаков с помощью NormalizeDouble.
Тонкое следствие: когда активен динамический шаг сетки на основе ATR, проверка соотношения ATR и шага сетки в VolatilityGate становится самокалибрующейся: ATR / (ATR × multiplier) = 1/multiplier. Поэтому она теряет информативность. В этой реализации проверка пропускается и используется только тест σ/μ на основе дрейфа.
Динамический расчет размера базового лота
Замечание 42 диссертации, озаглавленное "Dynamic Trade Sizing", является одним из наиболее значимых с практической точки зрения выводов. В нем содержатся две идеи. Во-первых, наращивание позиции по мере роста капитала: когда цикл завершается с прибылью, базовый лот следующего цикла должен учитывать увеличившийся размер счета. Фиксированное значение BaseLot = 0.01 независимо от роста счета означает, что советник никогда не капитализирует прибыль и всегда приносит одинаковую денежную прибыль за цикл. Во-вторых, защита при снижении эквити: по мере накопления убытков размеры лотов следует уменьшать, чтобы замедлить треугольное накопление убытков.
Советник реализует капитализацию при росте, пересчитывая базовый лот при каждом перезапуске цикла:
//+------------------------------------------------------------------+ //| Dynamic base lot — equity-compounding at cycle restart | //+------------------------------------------------------------------+ double ComputeDynamicBaseLot(double cycleEquity) { if(!InpUseDynamicBaseLot) return InpBaseLot; double lot = cycleEquity * InpLotFraction; //--- Normalise to broker constraints double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); double cap = MathMin(maxLot, InpMaxLotSize); lot = MathMax(lot, minLot); lot = MathMin(lot, cap); if(step > 0) lot = MathFloor(lot / step) * step; lot = NormalizeDouble(lot, 2); if(lot < minLot) lot = minLot; return lot; }
Эффективный базовый лот равен cycleEquity × InpLotFraction и пересчитывается в начале каждого цикла. После прибыльного цикла увеличившееся эквити дает больший лот, обеспечивая капитализацию прибыли. После убыточного цикла уменьшившееся эквити дает меньший лот, снижая экспозицию. Нормализация с округлением вниз по шагу через SymbolInfoDouble гарантирует соответствие лота ограничениям брокера по объему: SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX и SYMBOL_VOLUME_STEP.
Обнаружение режима — VolatilityGate и обнаружение точек изменения
Анализ чувствительности из раздела 3 показал, что sigma_t и mu_t определяют динамику эквити. В этом разделе реализована ответная мера — двухуровневая система обнаружения режима, отвечающая на два разных вопроса. VolatilityGate проверяет: "Благоприятны ли сейчас условия для повторного выставления BGT?" CPDEngine проверяет: "Произошел ли структурный сдвиг процесса?"
VolatilityGate — непрерывный фильтр
VolatilityGate вычисляет три показателя на таймфрейме режима, по умолчанию H4: ATR — прокси sigma_t, величину дрейфа — прокси mu_t и соотношение sigma_t/mu_t. Высокое соотношение означает, что волатильность доминирует над дрейфом, что благоприятно для двунаправленной сеточной торговли. Низкое соотношение означает, что доминирует дрейф, что опасно.
Формула дрейфа заслуживает особого внимания. В ней используется среднее абсолютное изменение скользящей средней MA от бара к бару за период анализа:
mu_t = (1/N) × Σ |MA[i] - MA[i+1]| for i = 0...N-1
Это соответствующий исследованию прокси-показатель мгновенной величины дрейфа из стохастического дифференциального уравнения Ито. Ключевая деталь: используются абсолютные изменения, а не чистое смещение. Чистое смещение может свестись к нулю, если тренд разворачивается в пределах периода анализа, ошибочно указывая на "отсутствие дрейфа" в период резких разнонаправленных колебаний. Абсолютная величина накапливает истинную величину направленного движения.
//+------------------------------------------------------------------+ //| Compute drift (mu_t) as average absolute bar-by-bar MA change | //+------------------------------------------------------------------+ double ComputeDrift() { if(m_maHandle == INVALID_HANDLE) return 0; double maBuffer[]; ArraySetAsSeries(maBuffer, true); if(CopyBuffer(m_maHandle, 0, 1, m_maPeriod + 1, maBuffer) < m_maPeriod + 1) return m_lastDrift; double sumAbsChanges = 0; for(int i = 0; i < m_maPeriod; i++) sumAbsChanges += MathAbs(maBuffer[i] - maBuffer[i + 1]); m_lastDrift = sumAbsChanges / m_maPeriod; return m_lastDrift; } //+------------------------------------------------------------------+ //| Compute sigma_t/mu_t ratio | //| High = ranging (safe), Low = trending (dangerous) | //+------------------------------------------------------------------+ double ComputeSigmaMuRatio() { double atr = GetATRValue(); double drift = ComputeDrift(); if(drift < 0.001) { m_lastSigmaMuRatio = 999; //--- effectively no drift = pure ranging return m_lastSigmaMuRatio; } m_lastSigmaMuRatio = MathMin(atr / drift, 999.0); return m_lastSigmaMuRatio; }
Когда дрейф крайне мал, отношение sigma/mu ограничивается сверху значением 999, что фактически указывает на чистый боковой рынок. Это соотношение используется механизмом периода ожидания: когда sigma/mu опускается ниже InpMinSigmaMuRatio, по умолчанию 5.0, система помечает условия как неблагоприятные. Повторное выставление BGT приостанавливается. Перед возобновлением требуется N последовательных благоприятных баров на таймфрейме режима, что предотвращает быстрые переключения между паузой и возобновлением. Важно, что фильтр по дрейфу применяется только к BGT. TGT и MGT обходят его, поскольку предназначены именно для условий, которые этот фильтр выявляет.
CPDEngine — детектор структурных сдвигов
VolatilityGate — непрерывный сглаженный сигнал, изменяющийся плавно. CPD (Change Point Detection) добавляет дискретный сигнал структурного сдвига: он определяет момент перехода базового процесса из одного режима в другой. Советник реализует алгоритм CUSUM с фиксированным базовым уровнем: сначала собирается начальный базовый период, затем базовый уровень фиксируется и после этого накапливаются отклонения. Когда накопленная сумма пересекает масштабированный порог, фиксируется структурный сдвиг.
Базовый уровень намеренно фиксируется после инициализации, а не пересчитывается по скользящей схеме. Скользящий базовый уровень адаптировался бы к тренду, который должен выявлять, что свело бы на нет цель его использования. Фиксированный базовый уровень сохраняет эталонный режим достаточно долго, чтобы накопился подлинный структурный дрейф.
При срабатывании CPD устанавливается флаг g_cpdBlockActive. Если TGT включен, следующий цикл принудительно переводится в режим TGT — алгоритм следования за трендом из раздела 6. Если TGT отключен, запуск следующего цикла полностью блокируется. Советник не запускает новую сетку BGT при подтвержденном тренде. Блокировка снимается только после того, как VolatilityGate подтверждает восстановление в течение всего периода ожидания.
Три режима сетки — BGT, TGT и MGT
В диссертации формализованы три различных сеточных алгоритма, каждый из которых предназначен для конкретного рыночного режима. Текущий советник приостанавливает работу при неблагоприятных условиях через VolatilityGate. Из диссертации следует, что приостановка — консервативная, а не оптимальная мера. При выявленном тренде сетка, следующая за трендом, может извлекать прибыль из направленного движения, а не простаивать.
BGT — двунаправленная сеточная торговля
Режим бокового рынка по умолчанию. На каждом уровне сетки выше и ниже точки привязки выставляются ордера на покупку и продажу с фиксированным тейк-профитом на следующем соседнем уровне. Опциональный режим приоритета покупок InpBuyBiasAboveAnchor может не выставлять ордера на продажу выше точки привязки для инструментов со структурным восходящим дрейфом. BGT — режим, описанный в математической модели в разделах 1-3. Сценарий отказа BGT — направленные тренды, при которых одна сторона становится прибыльной, а на другой накапливаются убытки.
TGT — трендовая сеточная торговля
Режим следования за трендом. Размещаются только стоп-ордера по направлению тренда. При восходящем тренде выставляются стоп-ордера на покупку выше точки привязки, при нисходящем — стоп-ордера на продажу ниже него. В исходной точке сделка не открывается, чтобы избежать позиции, сразу убыточной против тренда. Отличительная особенность: тейк-профит не устанавливается для отдельных сделок. По мере продолжения тренда позиции остаются открытыми и накапливаются. Корзина позиций закрывается только при достижении целевой прибыли, срабатывании аварийного выключателя, предельном возрасте цикла или закрытии перед выходными. Эта схема с переменным TP позволяет TGT работать как масштабируемый пирамидальный вход, а не как сетка, слишком рано закрывающая прибыльные позиции.
TGT активируется двумя способами: мягким триггером, когда sigma/mu опускается ниже InpTGTSigmaMuThreshold и дрейф доминирует над волатильностью, либо жестким триггером, когда CPD фиксирует структурный сдвиг. Сценарий отказа TGT — ложный сигнал тренда с последующим немедленным разворотом, при котором открытые позиции по тренду остаются без хеджирования.
MGT — сеточная торговля на возврате к среднему
Временный режим восстановления после тренда. Используются только контртрендовые лимитные ордера: выше точки привязки — лимитные ордера на продажу, а ниже него — лимитные ордера на покупку. Фиксированный тейк-профит в направлении точки привязки. MGT — структурная противоположность TGT. В этом режиме предполагается, что затяжной тренд сменится возвратом к среднему. Он срабатывает, когда предыдущий цикл TGT завершился по аварийному выключателю или из-за перезапуска режима (g_lastCycleWasTGTKill = true). Режим MGT намеренно исключен из проверок режима в середине цикла, иначе DetermineGridMode() часто переводила бы его из MGT уже на первом новом баре, разрушая предусмотренную логику восстановления.

Рис. 4. Поведение режимов BGT, TGT и MGT
| Свойство | BGT | TGT | MGT |
|---|---|---|---|
| Направление | Оба направления | Только по тренду | Только против тренда |
| Тип входа | Стоп-ордера + лимитные ордера | Только стоп-ордера | Только лимитные ордера |
| TP для каждой сделки | Фиксированный — на следующем уровне | Переменный — для корзины позиций | Фиксированный — в направлении точки привязки |
| Оптимальный режим | Боковой рынок | Трендовый рынок | Возврат к среднему после тренда |
Логика выбора режима
При запуске каждого цикла DetermineGridMode() выбирает подходящий алгоритм по трехуровневой системе приоритетов:
//+------------------------------------------------------------------+ //| Regime-adaptive mode selection — three-tier priority | //+------------------------------------------------------------------+ ENUM_GRID_MODE DetermineGridMode() { //--- Priority 1: MGT — previous TGT cycle killed -> post-trend recovery if(InpEnableMGT && g_lastCycleWasTGTKill) { g_lastCycleWasTGTKill = false; //--- consume the trigger return GRID_MODE_MGT; } //--- Priority 2: TGT — CUSUM detected regime change (hard signal) if(g_cpdBlockActive && InpEnableTGT) return GRID_MODE_TGT; //--- Priority 2b: TGT — sigma/mu below threshold (soft signal) if(InpEnableTGT) { double sigmaMu = g_volatilityGate.ComputeSigmaMuRatio(); if(sigmaMu < InpTGTSigmaMuThreshold) return GRID_MODE_TGT; } return GRID_MODE_BGT; //--- Default: ranging conditions }
(1) MGT — если предыдущий цикл TGT был принудительно завершен аварийным выключателем или перезапуском режима, включается режим возврата к среднему. Флаг триггера сбрасывается, поэтому он срабатывает только один раз. (2) TGT — два пути: жесткий сигнал от CPD принудительно включает TGT независимо от sigma/mu либо мягкий сигнал, когда sigma/mu опускается ниже порога, указывающего на доминирование дрейфа. (3) BGT — режим по умолчанию для условий бокового рынка. Так реализуется предложенная в диссертации смена циклов, адаптирующаяся к режиму рынка: BGT → TGT → MGT → BGT.
Промышленная архитектура — фильтры запуска, сохранение состояния и диагностика
Один из ключевых принципов проектирования состоит в том, что новый цикл не всегда начинается сразу. Исследование показывает, что запуск сетки при подтвержденном тренде — основной сценарий разорения. StartNewCycle() выполняет три проверки фильтров входа перед активацией сетки:
void StartNewCycle() { //--- Gate 1: CPD hard block — don't deploy BGT into a confirmed trend if(g_cpdBlockActive && !InpEnableTGT) { g_cycleBlocked = true; g_session.state = GRID_STATE_PAUSED; return; } //--- Gate 2: Price-level filter — don't anchor at a recent N-bar extreme if(IsPriceAtExtreme(plDistHigh, plDistLow, plMinDist)) { g_priceLevelBlocked = true; g_cycleBlocked = true; g_session.state = GRID_STATE_PAUSED; return; } g_priceLevelBlocked = false; g_cycleBlocked = false; //--- ... ATR spacing, session init, dynamic lot sizing ... //--- Gate 3: BGT disabled — wait for TGT/MGT conditions ENUM_GRID_MODE mode = DetermineGridMode(); if(InpDisableBGT && mode == GRID_MODE_BGT) { g_cycleBlocked = true; g_session.state = GRID_STATE_PAUSED; return; } //--- All gates passed — arm the grid g_session.gridMode = mode; //--- ... }
Фильтр 1 проверяет блокировку CPD: если CUSUM сработал, а TGT отключен, советник не запускает BGT при подтвержденном тренде. Фильтр 2 проверяет ценовой уровень: если цена находится вблизи недавнего экстремума за N баров, встроенное в сетку свойство возврата к среднему выражено слабее, а привязка сетки в такой точке рискованна. Фильтр 3 обрабатывает необязательный режим отключения BGT: если пользователь отключил BGT, советник ожидает условий для TGT или MGT. Каждый фильтр реализует конкретный вывод исследования: CPD из диссертации, раздел 10.6.1; слабость скрытого барьера по анализу границ LIL; архитектуру переключения режимов из разделов 10.3-10.5.
Сохранение состояния и восстановление
StateManager сохраняет состояние цикла — точка привязки, шаг сетки, экстремумы сессии, базовый уровень эквити, счетчик циклов, режим сетки и направление тренда — в глобальных переменных терминала MQL5. Тикеты не сохраняются. При восстановлении работы GridCore::RecoverPositions() сканирует фактически открытые у брокера позиции и сопоставляет их по близости цен. Благодаря этому восстановление устойчиво к переназначению тикетов на стороне брокера. StateManager также допускает несовпадение динамического шага сетки на основе ATR, чтобы пересчет шага между сессиями не признавал ошибочно сохраненное состояние недействительным.
Правила для выходных
Закрытие всех позиций перед выходными принудительно закрывает позиции в пятницу в настраиваемый час и откладывает перезапуск до понедельника. Это защищает от риска гэпа, который модель непрерывной диффузии, лежащая в основе всего математического аппарата, не учитывает . Закрытие перед выходными реализовано как событие завершения цикла: оно увеличивает счетчик циклов, очищает сохраненное состояние, а перезапуск в понедельник проходит через те же фильтры запуска, что и обычный цикл.
Диагностический конвейер
Советник использует структурированную диагностику в формате CSV вместо проверки только по Журналу. DiagnosticLog.mqh буферизует в памяти три набора данных:BarSnapshot — 30 полей на бар; DiagCycleSummary — 28 полей на завершенный цикл; DiagEventRecord — 7 полей на событие, включая начало и завершение циклов, паузы по дрейфу, срабатывания CPD, переключения режимов, перезапуски из-за смены режима, события выходных и другое. Эти данные записываются в CSV в каталоге общих файлов MetaTrader при выполнении OnDeinit() или OnTester().
Два вспомогательных скрипта Python завершают конвейер. analyze_backtest.py загружает последние выходные CSV-файлы, выполняет десять проверок для выявления ошибок, выводит тринадцать разделов текстового анализа и при необходимости генерирует восемь диагностических графиков. calibrate_parameters.py загружает CSV-файлы за все даты бэктестов, при необходимости получает исторические данные MT5 и выполняет шесть этапов калибровки: кривые зависимости дисперсии от возраста цикла, валидацию аварийного выключателя по теореме 53, вывод порогов sigma/mu, анализ зон условия прибыльности, валидацию ожидаемого числа шагов и обнаружение режима на нескольких таймфреймах. Вместе они образуют инструментарий исследовательского уровня для проверки и уточнения параметров советника на эмпирических данных.
Тестирование стратегии
Полная система была протестирована в Тестере стратегий со следующей конфигурацией. Ниже приведены входные параметры и результаты.

Рис. 5. Кривая эквити в Тестере стратегий

Рис. 6. Сводка результатов Тестера стратегий
Диагностический конвейер — анализ и калибровка сетки
Советник автоматически записывает структурированные диагностические данные CSV во время каждого бэктеста и каждой сессии реальной торговли. Два вспомогательных скрипта Python преобразуют эти необработанные данные в анализ, пригодный для практических решений. В этом разделе показано, как их использовать и какие результаты они дают.
Оба скрипта ожидают CSV-файлы в общем каталоге файлов MetaTrader, обычно %APPDATA%/MetaQuotes/Terminal/Common/Files в Windows. Советник записывает за каждый прогон три файла с префиксом BGC: снимки баров — 30 полей на бар; сводки циклов — 28 полей на завершенный цикл; журнал событий — 7 полей на событие, включая запуск и завершение циклов, паузы из-за дрейфа, срабатывания CPD, переключения режимов, события выходных и другое.
analyze_backtest.py — диагностика после прогона
Этот скрипт загружает последний набор CSV-файлов и сразу выводит диагностическую информацию. Запустите его из командной строки:
python analyze_backtest.py [csv_dir] [--no-charts] [--date YYYYMMDD]
Если аргументы не указаны, по умолчанию используется общий каталог файлов MetaTrader, а последние CSV-файлы выбираются по суффиксу даты. Флаг --date выбирает конкретный прогон. Флаг --no-charts пропускает создание графиков для быстрого текстового анализа.
Скрипт выводит тринадцать разделов текстового анализа: статистику циклов — количество, продолжительность, распределение прибыли по режимам; анализ просадок; поведение системы обнаружения режима; срабатывания аварийного выключателя; паттерны повторного выставления. Кроме того, скрипт выполняет десять автоматических проверок для выявления ошибок, отмечающих такие аномалии, как "циклы-зомби" — чрезмерно длительные циклы, осиротевшие позиции или несоответствия в классификации режимов. Если построение графиков включено, скрипт генерирует восемь диагностических PNG-файлов в каталог analysis_output/, включая кривые эквити с отмеченными границами циклов, тепловые карты просадок и гистограммы распределения режимов.
calibrate_parameters.py — калибровка параметров между прогонами
В то время как analyze_backtest.py анализирует один прогон, calibrate_parameters.py загружает все CSV-файлы за все даты и агрегирует данные нескольких бэктестов для получения статистически устойчивых рекомендаций по параметрам. Запустите его командой:
python calibrate_parameters.py [csv_dir] [--no-mt5]
Флаг --no-mt5 пропускает прямой доступ к историческим данным MT5, если он недоступен, например при работе на компьютере без установленного MetaTrader. Скрипт выполняет шесть этапов калибровки:
- Кривая зависимости дисперсии от возраста цикла — сопоставляет реализованную дисперсию цикла с его возрастом в часах и проверяет вывод раздела 3 об экспоненциальном росте дисперсии на фактических данных бэктеста. На основе этого калибруется параметр InpMaxCycleHours.
- Валидация аварийного выключателя по теореме 53 — вычисляет теоретическую вероятность разорения при текущей конфигурации сетки и сопоставляет ее с наблюдаемой частотой срабатывания аварийного выключателя. Эта проверка показывает, находится ли InpRuinThreshold в подходящем диапазоне для данного размера счета и глубины сетки.
- Вывод порога sigma/mu — анализирует связь между отношением sigma_t/mu_t в начале цикла и его итогом: прибыль или срабатывание аварийного выключателя. На основе этого калибруются параметры InpMinSigmaMuRatio и InpTGTSigmaMuThreshold.
- Анализ зон условия прибыльности — показывает, какие комбинации волатильности и дрейфа приводили к прибыльным, а какие — к убыточным циклам, подтверждая четырехквадрантную классификацию состояний рынка из раздела 3.
- Валидация ожидаемого числа шагов — сопоставляет теоретическое ожидаемое число пересечений уровней сетки до поглощения с наблюдаемой продолжительностью циклов.
- Определение режима на нескольких таймфреймах — оценивает, обеспечивает ли текущий выбор InpRegimeTF, по умолчанию H4, наилучшую точность классификации режимов на исторических данных.
Рабочий процесс
Предполагаемый порядок действий образует цикл обратной связи: запустить бэктест в MetaTrader, CSV-файлы записываются автоматически → запустить analyze_backtest.py для оперативной диагностики и выявления ошибок → накопить результаты нескольких бэктестов с различными параметрами или за разные периоды → запустить calibrate_parameters.py для получения уточненных параметров → применить рекомендации и повторить процесс. Таким образом, советник — не "черный ящик", а исследовательский инструмент со встроенным конвейером эмпирической проверки.
Заключение
В статье представлен основанный на исследованиях подход к сеточной торговле, учитывающий известные математические сценарии отказа с помощью ограниченных перезапускаемых циклов и фильтрации запуска с учетом режима рынка. Ключевые выводы, определяющие архитектуру:
- Сеточная торговля — не мартингейл. Накопление убытков следует ряду треугольных чисел, то есть квадратичному росту, а не экспоненциальному удвоению. Благодаря этому сеточные советники пригодны для инженерной настройки и контроля — более медленный рост убытков дает время для обнаружения неблагоприятных условий и вмешательства.
- Формула L_t обеспечивает оценку риска за постоянное время. Совокупную экспозицию по убытку можно рассчитать по двум величинам без анализа отдельных позиций. На практике L_t используется для диагностики, а прямое измерение эквити — для аварийного выключателя в реальном времени, поскольку допущения формулы, одинаковые лоты и отсутствие повторного выставления, не соответствуют рабочему советнику.
- Дисперсия эквити растет экспоненциально с увеличением продолжительности цикла. Более длительный цикл математически опаснее более короткого. Это обосновывает безусловный перезапуск по предельному возрасту цикла как структурную необходимость.
- Работа сетки без ограничений ведет к почти верному разорению. Это доказанная теорема. Перезапуск — структурный ответ: сбрасываются и таймер накопления дисперсии, и уровень сетки.
- sigma_t и mu_t определяют все. Шаг сетки и размер лота вторичны. В основе архитектуры лежат измерение режима волатильности и дрейфа, а также реагирование на него с помощью VolatilityGate и CPDEngine.
- Три алгоритма для трех рынков. BGT извлекает прибыль в условиях бокового рынка, TGT следует подтвержденным трендам, MGT использует возврат к среднему после тренда. При каждом перезапуске цикла логика выбора режима адаптируется к обнаруженному режиму рынка.
- Динамический шаг сетки на основе ATR и лоты, пересчитываемые по эквити с учетом капитализации прибыли, позволяют сетке адаптироваться к текущим рыночным условиям, а не зависеть от жестко заданных констант.
- Перезапуск — это не отказ. Исследование доказывает, что один неограниченный по времени цикл приводит к разорению. Прибыльные циклы с перезапуском — механизм выживания: они сбрасывают дисперсию, фиксируют прибыль и вновь входят в благоприятную зону.
Отказ от ответственности: эта статья предназначена только для образовательных целей. Сеточная торговля сопряжена со значительным финансовым риском. Приведенные здесь математические доказательства показывают как потенциал, так и ограничения сеточных систем с ограничениями. Всегда тщательно тестируйте советник на демо-счетах, прежде чем рисковать реальными средствами. Результаты прошлых бэктестов не гарантируют будущих результатов.
Весь код, упомянутый в статье, приложен ниже. В таблице ниже перечислены файлы исходного кода.
| Имя файла | Описание |
|---|---|
| GridEA.mq5 | Основной файл советника — оркестратор, входные параметры, управление циклами и правила работы во время выполнения |
| Defines.mqh | Общие перечисления, структуры, константы и модель сессии |
| GridCore.mqh | Размещение ордеров, синхронизация, повторное выставление, закрытие и восстановление для BGT/TGT/MGT |
| LotEngine.mqh | Расчет размера лота по уровням с умеренным множителем и динамическими режимами уменьшения лота |
| LtMonitor.mqh | Вычисление L_t, RPR, диагностика по теоремам 52 и 53, отслеживание с учетом траектории |
| ProfitMonitor.mqh | Логика расчета прибыли по циклу и подсчет позиций |
| VolatilityGate.mqh | Фильтр режима по ATR/дрейфу с механизмом периода ожидания |
| CPDEngine.mqh | CUSUM-детектор структурных сдвигов с фиксированным базовым уровнем |
| StateManager.mqh | Сохранение состояния цикла через глобальные переменные терминала MQL5 |
| DiagnosticLog.mqh | Ведение диагностического журнала в формате CSV (снимки баров, сводки циклов, события) |
| analyze_backtest.py | Анализ после прогона: тринадцать текстовых разделов, десять проверок ошибок, восемь графиков |
| calibrate_parameters.py | Калибровка между прогонами: кривые зависимости дисперсии от возраста, вывод порогов sigma/mu, валидация по теореме 53 |
- Задача о разорении игрока и двунаправленные сеточно-ограниченные торговые и инвестиционные стратегии — IMFI, 2020
- Просадка и рост от минимума для двунаправленных сеточно-ограниченных стохастических процессов — JMS, 2020
- Применение двунаправленных сеточно-ограниченных стохастических процессов в алгоритмической торговле — JMS, 2021
- Границы итерированного логарифма для двунаправленных сеточно-ограниченных стохастических процессов — GSA, 2021
- Двунаправленные сеточно-ограниченные стохастические процессы и их приложения в математических финансах — диссертация PhD, 2022
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21833
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Особенности написания Пользовательских Индикаторов
Единый пайплайн валидации для защиты от переобучения бэктеста
Освоение массивов премии и дисконта: Оптимизация торговли по дисбалансам в PD-массивах
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования