Узнайте, как кэширование базовой линии ломает сравнение при внешних изменениях. Практический пример на Python и фикс.
Представьте: ваша программа внезапно закрывает все позиции и прекращает работу, хотя ничего не сломалось. Причина — кэшированная базовая линия, которая перестала соответствовать реальности. Разберём этот баг на примере торгового робота и покажем, как его исправить.
Программа защищает от дневных убытков: сохраняет базовую линию на старте дня и сравнивает с текущим значением. Вот типичный код:
day_pnl = current_equity - day_start_equity
if day_pnl <= -daily_loss_limit:
close_everything()
stop_for_the_day()Этот код корректен для измерения торговых результатов, но полностью ошибочен, если стоимость актива меняется по другим причинам — например, при выводе средств. Equity падает на 500, day_pnl показывает -500, и программа решает, что день катастрофический, хотя позиции ни в чём не виноваты. Депозит даёт зеркальную проблему: цель по прибыли достигается деньгами, которые просто добавили.
Базовая линия и измеряемое значение молча перестали означать одно и то же. day_start_equity — это стоимость счёта до сегодняшней торговли, а current_equity — текущая стоимость. Их разница равна торговому результату, только если торговля — единственное, что меняет число. Никто не записал это допущение. Оно было верным в момент написания кода и оставалось верным, пока не перестало.
Это не торговый баг. Это баг, который возникает, когда вы кэшируете опорную точку и сравниваете с ней живое состояние, а другой актор может менять базовое значение вне полосы. Примеры: лимитеры скорости, хранящие стартовый счётчик и сбрасываемые административно; сигнализации дискового пространства, базирующиеся на загрузке, после чего кто-то монтирует том; прогресс-бары, вычисляющие процент от изменяющегося общего значения.
Нельзя остановить изменение значения. Можно обнаружить внешнее изменение и сдвинуть базовую линию на ту же величину, чтобы разница продолжала измерять то, что вы имели в виду.
shift = detect_out_of_band_change() # +500 депозит, -500 вывод
day_start_equity += shift
peak_equity += shift
initial_balance += shift # все базовые линии, не только очевидныеВ нашем случае платформа фиксирует переводы как отдельный тип записей, так что обнаружение — это сканирование истории по этому типу. Конкретно:
# MQL5 код для детекции
long type = HistoryDealGetInteger(ticket, DEAL_TYPE);
if (type == DEAL_TYPE_BALANCE || type == DEAL_TYPE_CREDIT)
sum += HistoryDealGetDouble(ticket, DEAL_PROFIT);Сдвигаем базовые линии — и измеряемый результат не меняется от перевода, что и было нужно.
Моей первой мыслью было исправить всё, что читает баланс. Это была бы вторая ошибка. Размер позиции — процент от баланса. Если половину счёта вывели, сумма, которую вы можете рисковать, действительно должна уменьшиться вдвое. Это не искажение, а правильная реакция на уменьшение денег. Только рисковые базовые линии нужно было сдвигать — те, что измеряют изменение во времени. Всё, что измеряет текущую способность, уже было верно.
Стоит спросить при любом таком фиксе: какие из этих значений измеряют изменение, а какие — состояние? Только первый тип нуждается в корректировке.
Программа сохраняет базовые линии, чтобы перезапуск в середине дня не сбрасывал их. Итак: переводите деньги, пока она остановлена, запускаете снова — и она верно восстанавливает базовую линию до перевода, а затем мгновенно срабатывает на фикс, который в остальном работает идеально.
Сверка должна происходить и при запуске, и во время работы. Я нашёл это только логически пройдя путь перезапуска, а не тестированием, что само по себе маленький урок.
Направьте программу на демо-счёт, выведите небольшую сумму и убедитесь, что измеренный результат дня не изменился. Две минуты. Я никогда не запускал этот тест, и, подозреваю, почти никто из тех, кто выпускает подобный софт, тоже.
Реализация на MQL5 доступна на GitHub под лицензией MIT: mql5-balance-operations-guard. Я пишу о создании автоматических торговых систем на goldscalpers.com.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →