Блог им. SergeyBagdasarov_d69

Сверяем цену исполнения с лимитом заявки: разбор по базам двух ботов

У торгового бота обычно смотрят на итог — сколько он заработал. Мне же понадобился ответ на более скучный, но проверяемый вопрос: по какой цене ордера реально исполнялись относительно той цены, что бот сам указал в заявке. Это другой вопрос, чем «сколько прибыли», и отвечает он не на «хорошо ли торгует стратегия», а на «нет ли у нас систематического проигрыша на самом исполнении».

Ниже — как я это померил по фактическим данным, какие две ловушки на этом пути почти поймали меня самого, и почему получившийся «ноль исполнений хуже лимита» не стоит подавать как достижение.

Данные и что именно сравнивалось

Источник — локальные копии баз двух боевых ботов (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 упущенными прибыльными сделками» было бы выдумкой: мы не считали, что было бы при другом решении. Отмена не равна убытку, но и исполненной её считать нельзя. К тому же заявка не тождественна позиции — в одной позиции может быть несколько заявок. Причину каждой отмены (не хватило встречного объёма, ушла цена, появилась ли потом другая заявка) я по этим данным не устанавливал и удобное объяснение подбирать не стал.

Важны эти 23 ровно тем, что показывают границу честности отчёта: если показать только цены состоявшихся исполнений, можно незаметно вычеркнуть заявки, которые до исполнения не дошли. Тогда всё сказанное останется правдой, но картина — неполной.

Границы вывода

Чтобы число не начало жить своей жизнью, перечислю, чего этот замер НЕ говорит:

  • он не про комиссии — денежную разницу между двумя ценами нельзя просто прибавить к прибыли бота;
  • он не про рыночные заявки — на них сравнение с «ориентиром» не доказывает выгоду относительно доступного тогда рынка, поэтому ноль нельзя распространить на все типы заявок и объявить «у нас нет проскальзывания»;
  • он не про «всегда» — речь о двух базах и конкретном окне; база хранит историю, но сама по себе не подтверждает неизменность торгового режима на всём протяжении.

Что в итоге

Я получил не доказательство идеального исполнения, а более точное описание выборки: среди исполненных лимитных заявок случаев хуже записанной цены не нашлось, часть получила цену лучше, отдельно остались отмены и частичные исполнения.

Поэтому, когда вижу красивое число про исполнение, задаю три вопроса — и советую задавать их к любому такому числу, своему или чужому:

  1. С какой ценой сравнивали — с лимитом самой заявки, с рыночной котировкой, с чем-то ещё?
  2. Какие заявки вошли в подсчёт — какой знаменатель, не смешаны ли выборки?
  3. Куда делись те, что не исполнились — учтены ли они вообще?

Ответы не делают результат хуже — они показывают, что именно он значит. Хорошая цена важна. Просто она ещё не означает, что заявка превратилась в сделку.

Это разбор конкретного измерения, не рекомендация совершать сделки.

Данная публикация является личным мнением автора. Мнение владельца сайта может не совпадать с мнением автора.
683
47 комментариев
Если лимитрая полностью не исполнилась по заданной цене, она двигается в сторону исполнения, или сделка пропускается?
Задача трех тел, если FILL_OR_KILL, то отменяется. Если обычная, то остается в стакане по заданной цене.
Михаил Михалев, это понятно.
У меня по тестам системы, допустим 100 сделок в месяц. 60 в плюс, 40 в минус. И хорошая эквити.
Сделки, например, покупать доллар по 80 каждый час.
Вопрос, смогу ли я совершить эти 100 сделок с помощью FILL_OR_KILL, чтобы повторить результаты тестов, или тесты этому исполнению не соответствуют?
Вопрос два: если двигать лимитку в сторону исполнения, это будет лучше, чем пропустить сделку?
Задача трех тел, так всё зависит от наполненности стакана и объёмов. Можно разве что промоделировать проскальзывание на основании истории обезличенных сделок и подобрать такое проскальзывание, которое удовлетворяет N процент сделок. Понятно, что если бить в рынок лимитками с FILL_OR_KILL объемами по 100млн руб, то в реальности всё будет совсем иначе:)

Задача трех тел, Вы спрашиваете как раз о том, чего наш подсчёт не показывает: что лучше — дождаться исполнения, передвинуть заявку или отказаться от входа. По одним ценам состоявшихся исполнений это не решить. В выборке есть 23 отменённые заявки без исполнения, но что было бы при другом способе входа, я не проверял. Поэтому советовать «двигать» или «пропускать» по этому разбору было бы необоснованно — тут нужно учитывать и сделки, в которые каждый вариант вообще не вошёл.

Михаил Михалев, а если заявка выставленная по 80 будет исполнена в течении дня, стоит ли отказываться от сделки и делать Килл, может часик или минуту подождать?
__rtx,
а все из-за некорректной постановки задачи.

как там было у классиков: чтобы задать правильный вопрос надо знать половину ответа.

Сверяем цену исполнения с лимитом заявки: разбор по базам двух ботов
Надо сверять цену исполнения не с ценой лимитной заявки, а с «теоретической» ценой, которая должна быть записана алгоритмом тогда, когда появился сигнал на сделку.

Дмитрий Овчинников, Согласен: чтобы оценить, сколько теряется между сигналом и исполнением, нужна цена, относительно которой алгоритм принял решение. Сравнение с лимитом самой заявки на этот вопрос не отвечает. В этом разборе я сопоставил два сохранённых поля — цену заявки и среднюю цену исполнения; получилась проверка записей в базе, а не оценка качества исполнения стратегии. Во вступлении я сформулировал задачу шире, чем позволяет такой замер, — это стоило написать точнее. Полезное здесь — отдельно показать неисполненные и частичные заявки, которые теряются за красивой статистикой цен. Но ни «ноль хуже лимита», ни 460 исполнений лучше сами по себе не говорят, насколько хорошо бот исполняет сигналы.

__rtx,
главное справится с делами до рассвета :)
По моему, автор не понимает, ни что на самом деле нужно измерить, ни как это сделать. А отсюда все претензии уважаемых комментаторов. 

avatar

SergeyJu, Вступление действительно получилось шире самого исследования. Я проверил соотношение записанной цены заявки и исполнения, но начал с вопроса о потерях на исполнении. Это разные задачи — границу между ними стоило обозначить точнее с самого начала.

SergeyJu,
все меньше реальных авторов и все больше ИИ.
__rtx,
я просто боюсь, а чтобы не бояться пью коньяк :)

__rtx, Замечание про заявки, которые стоят в стакане, и те, что сразу исполняются по встречным предложениям, — по делу. В опубликованном подсчёте такого разделения нет, поэтому вывести из 460 улучшений, сколько заявок сразу забрали встречный объём, я не могу. И да, «ноль хуже лимита» сам по себе не открытие — для проверки записей в базе это ожидаемый результат, и как показатель качества исполнения бота его подавать нельзя. Здесь согласен.

__rtx, Да, здесь я неточно выразился. В обычном стакане исполнение лучше действующего лимита указывает на то, что заявка забрала встречный объём. Моя фраза «не могу вывести» получилась слишком общей.

Но исполнение ровно по лимиту не обязательно означает, что заявка стояла в стакане: сразу исполниться можно и по своей предельной цене. Поэтому разделить всю выборку на активные и пассивные только по этим двум ценам не получится. Тем более у нас подсчёт по заявкам со средней ценой исполнения, а не по каждому отдельному исполнению.

Мы сейчас разрабатываем торговую платформу и обкатываем собственные машины — и на реальных деньгах, и в демо. Для этой статьи взяли именно базы двух машин с реального счёта. Поэтому вопрос для нас практический: разобраться, что действительно произошло с отправленными заявками и что из сохранённых данных можно установить. Спасибо за уточнение про встречный объём — эту часть в предыдущем ответе стоило объяснить точнее.

__rtx, 

и я Вам скажу куда посмотреть.

В отчет брокера можно смотреть.
avatar
Сделки, прошедшие по цене лучше заявленной, поймали встречную заявку и попали на биржевую комиссию или на две( если брокерская равна биржевой).
Если  таких сделок больше чем неисполненных, значит бот хромает. Тщательнее надо. Должно быть наоборот. Или использовать костыли -  заявки с флагом BoC (только пассивная).
avatar
__rtx, 
Кучу ситуаций можно привести когда по рынку лучше и когда лимиткой.
Здесь несколько другая куча. Лимитка исполненная как рыночная — это ошибка бота, которую можно и нужно избегать. Если что, я про трейдинг, а не про «инвестирование».
avatar
__rtx, 
Контекст здесь очевиден.
Биржевая комиссия >> брокерская комиссия
В Т-инвестициях, например, он совсем другой.
avatar
Synthetic, контекст не очевиден. 
Если не знать, как и зачем выставлялись заявки, какие действия были при неисполнении и неполном исполнении, вообще непонятно, что исследовалось и, главное, для чего. 
avatar
__rtx, «Все стали «стаканщиками».»,
хуже, если все стали бы тарелочницами.
__rtx, так то, если средняя сделка системы, скажем, 0.4% на высоколиквидном инструменте, то плевать на проделки Андрея К в стакане. Можно бить как по рынку, так и ставить лимитку до исполнения, ну или передвигать ее раз в пару минут, если цена ушла.
Задача трех тел, конечно. Я поэтому и говорю что это очень «контекстозависимая» вещь и неоднозначная. Если горизонт удержания больше чем горизонт на котором adverse selection орудует то это переводит алгоритм в другой класс/тип который не взаимодействует с ним. Т.е. например хфт и инвесторы или те кто тренды или типа того торгует в принципе никак не конкурируют т.к. находятся в разных фазах «движения своих позиций» и никак друг другу не мешают не конкурируют и почти не пересекаются а когда пересекаются могут лишь по дружески поприветствовать друг друга потому что ни за что не конкурируют даже наоборот немного помогают друг другу т.к. цели обычно противоположные один хочет по рынку или около того(не трогая свой ордер или исполняя чей-то(часто хфтшный т.к. подставлять свои хфт любит) в стакане) а другой исполнения и «не трогаемый(не двигающийся/не фронтранящий)» ордер никак ему не мешает т.к. не переставляется. Т.е. функция горизонта разная и поэтому «пути» тоже.
avatar

Задача трех тел, с соотношением результата сделки и расходов на исполнение согласен. Только по одной средней сделке я бы способ входа не выбирал: важны ещё размер заявки и доступный объём в стакане.

Мы сейчас обкатываем собственную торговую платформу: есть машины на реальных деньгах и отдельные демо-машины. Поэтому вопрос для нас вполне практический. Но в этой статье замер был уже: посмотрели записанные цены и отдельно учли частичные исполнения и отмены. Сколько преимущества съедает исполнение, этим подсчётом мы ещё не установили.

Вы способ входа фиксируете для всей стратегии или меняете в зависимости от текущей ликвидности?

Сергей Багдасаров, да, вход фиксированный. Т.к. система построена на тестах постоянным лотом, то и частичный вход, либо отмена входа для моих стратегий не подходит, т.к. это будет совсем другая система, не та, которая построена на тестах.
Я держу лимитную заявку пару-тройку минут до ее исполнения. Как правило всегда наливают. Если нет, то передвигаю ее, либо ее остаток в новый спред. 
Позиция держится от нескольких часов до нескольких дней.

Задача трех тел, спасибо, теперь понятно, почему для вас важен полный вход: система тестировалась постоянным лотом, и в реальной торговле вы сохраняете тот же объём. 

 Медленные трендовики обычно мирятся с тем, что отдают +- спред на каждую пару покупка/продажа или чуть больше плюс комиссы. 
Просто потому, что борьба за спред предполагает (а) издержки на дополнительное программирование (б) расходы на быстрый доступ и оборудование для него. И для них принципиальны не потери на спреде, а исполнение заявки, поэтому неисполненная будет переставляться, поэтому морока с расщеплением заявок на более мелкие и далее можно дойти до айсбергов и тому подобного. 
В этом контексте замкнутое исследование должно включать в себя финрез от правила определения цены заявки при условии, что её надо выставить по не очень свежим данным, то есть с задержкой 0,1 секунды, например, и правила перестановки заявки при неполном исполнении. 
И все это непросто потому, что задача зависит как от общей ликвидности инструмента, так и от текущей краткосрочной волатильности его. Что там у ХФТ я не знаю. Да и пограничные с ХФТ области понимаю смутно, не мой хлеб.
avatar

SergeyJu, здесь важный момент: если менять правило перестановки, меняется не только цена исполнения, но и набор состоявшихся сделок. Поэтому по одним исполненным заявкам такие варианты полноценно не сравнить — нужно учитывать и частичные исполнения, и то, что осталось без исполнения.

В статье мы разбирали более узкий вопрос по базам двух работающих машин: как записанная цена исполнения соотносится с сохранённым лимитом заявки. Влияние задержки данных и разных правил перестановки на итоговый результат здесь не проверялось.

Для такого сравнения я бы рассматривал оба правила вместе, на одинаковых исходных условиях и с учётом комиссий. Иначе можно получить более выгодную цену у исполненных заявок, но худший общий результат из-за тех, которые так и не исполнились.

Сергей Багдасаров, ищите и обрящете
пишите и получите отклик
avatar

SergeyJu, спасибо за замечания и полезный разговор. 

Сергей Багдасаров, 
… Влияние задержки данных и разных правил перестановки на итоговый результат здесь не проверялось...

А зря. Такой проверкой Вы получите ответ на вопрос какую «альфу» используете execution или direction(при 1 секунде задержки 100% отделить можно). И соответственно горизонт времени жизни сигнала. Если он длинный и средний результат знатно выше комисии и спреда то direction моменты эксплуатируете это почти всегда масштабируется очень хорошо коррелирует с правильным бэктестом менее подвержено конкуренции ноль затрат на инфраструктуру и дольше живёт(такая альфа). Если execution то то что перечисленно умножается на -1 и ещё возможны неприятные сюрпризы например комиссия в этом контексте может быть лишь частью проблемы и не самой затратной.
avatar

__rtx, да, такую проверку стоит сделать. В нашем замере её не было, поэтому выводов об источнике преимущества из него не делаем. Только «выдержало задержку» я бы пока считал признаком, а не доказательством заработка именно на направлении. Вы обычно проверяете несколько задержек и смотрите, как меняется результат? 

У быстрых алгоритмов, хфт, при идеальном решении, рано или поздно дальнейшее развитие упрется в железо и локацию, где сидят более умные, более финансово обеспеченные, и другие более близкие к бирже. Да и сама биржа имеет возможность что-либо замедлить для сторонних. 
Т.е. для конкуренции на равных с этими ребятами нужны вначале мозги, потом большие вложения в инфраструктуру, а потом и неформально близкие знакомства с ребятами, которые там. 
Тут знаете, как в шоу бизнесе. Не достаточно быть томной и красивой, не достаточно, чтобы за тебя забашлял папик, иногда таки придется переспать с продюсером.

Читайте на SMART-LAB:
Фото
📌 За публикациями и эфирами: как работает IR
Новости компании, презентации результатов, встречи и эфиры с руководством — всё это части работы IR, или Investor Relations: связей с...
Фото
💵 Юань ниже 12 рублей — сценарий на ближайшую неделю
Рубль укрепляется — именно такого движения давно ожидал Алексей Михеев, инвестиционный стратег ВТБ Мои Инвестиции . С максимума 6...
Фото
Курс интересный. А мне он подойдёт?
Возможно, вы уже посмотрели программу «Айкидо трейдера», сохранили ссылку и пока думаете. Хочется понять, что из этого пригодится именно вам....
Фото
НМТП - РСБУ за сложный 3-й квартал. Прибыль порта сломлена, но не обнулена

теги блога Сергей Багдасаров

....все тэги



UPDONW
Новый дизайн