У торгового бота обычно смотрят на итог — сколько он заработал. Мне же понадобился ответ на более скучный, но проверяемый вопрос: по какой цене ордера реально исполнялись относительно той цены, что бот сам указал в заявке. Это другой вопрос, чем «сколько прибыли», и отвечает он не на «хорошо ли торгует стратегия», а на «нет ли у нас систематического проигрыша на самом исполнении».
Ниже — как я это померил по фактическим данным, какие две ловушки на этом пути почти поймали меня самого, и почему получившийся «ноль исполнений хуже лимита» не стоит подавать как достижение.
Источник — локальные копии баз двух боевых ботов (SQLite вместе с файлами журнала изменений WAL), снятые для разбора. Анализ выполнялся на копиях, рабочие базы при этом не менялись. Окно — доступная история ордеров с 29 августа по 22 октября 2026 года. Никаких бэктестов и синтетики: только то, что реально записано по отправленным и исполненным заявкам.
Из всех заявок я оставил лимитные. Причина не вкусовая: у лимитной заявки есть явная граница цены — «не дороже X» на покупку, «не дешевле X» на продажу. Эту границу можно взять из записи заявки в базе и честно сравнить со средней ценой фактического исполнения. У рыночной заявки такой зафиксированной границы нет, и сравнивать её исполнение с каким-либо «ориентиром» — значит сравнивать с числом, которое само по себе ничего не гарантирует.
Важно сразу очертить, с чем я сравнивал и с чем — нет:
То есть это не измерение «полной стоимости исполнения» и не доказательство отсутствия проскальзывания. Это ответ ровно на один вопрос: как соотносится средняя цена исполнения с ценой, записанной в самой заявке.
И сразу честная оговорка про сами поля. Я брал сохранённую цену заявки и среднюю цену исполнения как они лежат в базе. Историю формирования первого поля для каждого исторического ордера я отдельно не восстанавливал. Поэтому результат описывает соотношение двух записанных в базе чисел, а не независимую сверку со всеми сообщениями биржи по каждому ордеру.
Всего лимитных заявок в выборке — 2 242. Первое, что нужно сделать до любой арифметики о ценах, — отделить заявки, которые вообще исполнились, от тех, что не исполнились:
2 242 = 2 219 с исполнением + 23 без исполнения (отмена, ноль исполнения)
Дальше про цены говорим только о первой группе — о 2 219 заявках, у которых есть хотя бы частичное исполнение. Сравнив среднюю цену исполнения с записанной ценой каждой такой заявки (дешевле купить — лучше, дороже продать — лучше), получаем второе разделение:
2 219 = 1 759 по цене заявки + 460 лучше + 0 хуже
Эти два разделения важны, потому что числа отвечают на разные вопросы. 460 — это заявки с улучшением цены среди 2 219 получивших исполнение. Ещё 23 заявки отменены без исполнения и в сравнение цен не входят вообще. Показать их рядом можно; нельзя смешивать их смысл и подавать как числа из одного знаменателя.
При подготовке короткой заметки я сам на этом споткнулся: в черновик про лимитные заявки попало число лучших исполнений из общего подсчёта — 516 вместо 460. Число было настоящим, просто отвечало на другой вопрос: общий подсчёт включал и рыночные заявки. Поймалось это только сверкой выборок перед публикацией. Вывод практический: когда считаешь «лучше/хуже», первым делом фиксируй знаменатель — какие именно заявки вошли в подсчёт, — и не давай числу из одной выборки утечь в текст про другую.
Ещё одна деталь, которую легко замести под ковёр. «С исполнением» — это не «исполнена полностью». Внутри 2 219 есть 22 частично исполненные заявки: часть объёма получена, остаток — нет. Это не то же самое, что отмена без единого исполнения. При сравнении цен я брал среднюю цену уже исполненной части, а не выдавал всю заявку за завершённую.
Я отдельно посмотрел, как боты открывали и наращивали позиции (первые входы и последующие доборы здесь объединены в одну группу) и как выходили из них. Все числа ниже — только по лимитным заявкам с исполнением.
| Что делал бот | С исполнением | По цене заявки | Лучше | Хуже |
|---|---|---|---|---|
| Входы и доборы | 1 327 | 1 101 | 226 | 0 |
| Выходы | 892 | 658 | 234 | 0 |
| Вместе | 2 219 | 1 759 | 460 | 0 |
На выходах лучших цен оказалось 234, на входах и доборах — 226, хотя выходных заявок меньше. Это наблюдение, а не объяснение: по этой таблице нельзя сказать, почему так — из-за движения рынка, выбранных цен или прочих условий исполнения. И уж точно «234 против 226» не значит, что выходы принесли больше денег: здесь считаются случаи, а не суммы, а заявки различаются и по объёму, и по величине улучшения цены.
Лимитная заявка устроена буквально: покупка — «не дороже указанной цены», продажа — «не дешевле». Если сравнивать цену исполнения именно с лимитом этой же заявки и без учёта комиссий, то исполнение хуже лимита просто не соответствовало бы условию заявки. Поэтому ноль худших — это не способность бота «переиграть биржу», а свойство самого инструмента: мы проверили, что записанные исполнения в выборке не оказались хуже записанных лимитов, и получили ожидаемый по определению результат.
Ценность такой проверки не в сенсации, а в том, что она ловит аномалии: если бы «хуже лимита» вдруг оказалось не ноль, это был бы сигнал о баге в учёте, в данных или в логике, а не нормальная торговля.
И отдельно: условие по цене ничего не обещает про объём. Можно получить исполнение по лимиту или лучше, можно — только часть, а можно не получить ничего. Само наличие заявки не означает, что сделка состоялась.
У этих 23 лимитных заявок в базе статус отмены и нулевое исполнение. Это всё, что можно утверждать об их результате в рамках данного подсчёта.
Назвать их «23 упущенными прибыльными сделками» было бы выдумкой: мы не считали, что было бы при другом решении. Отмена не равна убытку, но и исполненной её считать нельзя. К тому же заявка не тождественна позиции — в одной позиции может быть несколько заявок. Причину каждой отмены (не хватило встречного объёма, ушла цена, появилась ли потом другая заявка) я по этим данным не устанавливал и удобное объяснение подбирать не стал.
Важны эти 23 ровно тем, что показывают границу честности отчёта: если показать только цены состоявшихся исполнений, можно незаметно вычеркнуть заявки, которые до исполнения не дошли. Тогда всё сказанное останется правдой, но картина — неполной.
Чтобы число не начало жить своей жизнью, перечислю, чего этот замер НЕ говорит:
Я получил не доказательство идеального исполнения, а более точное описание выборки: среди исполненных лимитных заявок случаев хуже записанной цены не нашлось, часть получила цену лучше, отдельно остались отмены и частичные исполнения.
Поэтому, когда вижу красивое число про исполнение, задаю три вопроса — и советую задавать их к любому такому числу, своему или чужому:
Ответы не делают результат хуже — они показывают, что именно он значит. Хорошая цена важна. Просто она ещё не означает, что заявка превратилась в сделку.
Это разбор конкретного измерения, не рекомендация совершать сделки.
а все из-за некорректной постановки задачи.
как там было у классиков: чтобы задать правильный вопрос надо знать половину ответа.
Надо сверять цену исполнения не с ценой лимитной заявки, а с «теоретической» ценой, которая должна быть записана алгоритмом тогда, когда появился сигнал на сделку.
главное справится с делами до рассвета :)