Четыре числа, все измерены на нашей собственной системе бумажной торговли: одна стратегия, сигналы по бессрочным контрактам BTCUSDT на 1-минутных свечах, 31 день и 1,418 ордеров. Медианное время от закрытия свечи до подтверждения ордера биржей: 195 ms. 99-й перцентиль: 2,970 ms. Медиана в 1% минут с самой высокой реализованной волатильностью: 840 ms. А константа задержки, которая стояла в конфигурации бэктеста большую часть предыдущего года: 0.
Три из этих чисел неинтересны. Все знают, что ноль — ошибка, и рано или поздно заменяют его на какое-нибудь значение, которое почти всегда выбирают на глаз. 100 ms, 250 ms, «возьмём с запасом — 500». По-настоящему важно число 840: оно показывает, что задержка зависит от состояния рынка, а состояния рынка, при которых она резко растёт, — те же, в которых ваш сигнал считает, что нашёл возможность.
Куда уходят 195 миллисекунд
Вот полный бюджет задержки, измеренный поэтапно с временными метками монотонных часов на каждом шаге. Сервер — инстанс AWS в ap-northeast-1, в том же регионе, что и эндпоинты биржи. Для розничной системы без колокации лучше почти не бывает.
| Этап | p50 | p95 | p99 |
|---|---|---|---|
| Закрытие свечи → получение события WS kline-closed | 128 ms | 402 ms | 1,940 ms |
| Разбор данных + обновление состояния признаков | 3 ms | 9 ms | 28 ms |
| Принятие решения: оценка модели + проверки риска | 11 ms | 22 ms | 60 ms |
| Отправка ордера → подтверждение биржи | 47 ms | 180 ms | 1,100 ms |
| От начала до конца (измерено, не сумма этапов) | 195 ms | 690 ms | 2,970 ms |
Перед тем как перейти к интересному, обратите внимание на две вещи. Во-первых, медианы не складываются: 128 + 3 + 11 + 47 = 189, а измеренная медиана полного пути — 195. Перцентили неаддитивны. Если оценивать задержку, складывая p99 отдельных этапов, получится 3,128 ms при фактическом p99 в 2,970. Здесь разница невелика, но при другой взаимосвязи этапов ошибка может быть огромной. Измеряйте весь путь целиком.
Во-вторых, посмотрите на первую строку. Две трети медианного бюджета уходит на ожидание сообщения от биржи о закрытии свечи. Дело не в сети, не в вашем коде и не в маршрутизации ордеров. Биржа агрегирует сделки в kline, определяет, что минута закончилась, и отправляет событие. Перед отправкой стоит очередь, общая для всех подписчиков этого потока.
Откуда берётся 840
Если разбить все 1,418 ордеров по реализованной волатильности минуты, породившей сигнал, распределение сразу распадается на отдельные группы.
| Волатильность свечи сигнала | Ордеров | p50 от начала до конца | p99 от начала до конца |
|---|---|---|---|
| Нижний квартиль | 201 | 141 ms | 488 ms |
| Средние два квартиля | 796 | 183 ms | 1,210 ms |
| Верхний квартиль | 407 | 312 ms | 2,880 ms |
| Верхний 1% всех минут | 14 | 840 ms | 4,100 ms |
Все этапы замедляются одновременно, и эффект накапливается. Очередь агрегации и рассылки биржи зависит от нагрузки на matching engine: свеча с 11,000 сделок закрывается позже свечи с 600 сделками. В это же время ваш процесс обрабатывает больше обновлений стакана и больше сделок, поэтому обновление признаков, обычно занимающее 3 ms, растягивается до 28. REST-путь отправки ордеров конкурирует с потоком панических заявок, и иногда возникает ошибка 503 с повторной попыткой, которая сама по себе стоит целую секунду. Коэффициент корреляции между числом сделок на свече сигнала и задержкой полного пути в нашей выборке составил 0.41. Не так уж много — но достаточно, чтобы константа перестала работать.
Стратегии, которые проходят первичный отбор, почти всегда торгуют пробои, развороты, дисбалансы или каскады ликвидаций. Они срабатывают именно в группе с самой высокой задержкой. Сигнал на импульс, возникающий только после движения цены на 40 bps за минуту, устроен так, что его всегда обслуживает самая медленная версия вашей системы.
Однажды мы целый день искали причину выброса в 3.6 секунды, который появлялся примерно в одно и то же время каждую ночь. Виноват оказался logrotate: он копировал и обнулял файл размером 2 GB на том же томе EBS, куда шёл вывод процесса, из-за чего останавливался event loop. Рынок был ни при чём. Сначала измеряйте, потом обвиняйте микроструктуру.
Как это влияет на исполнение
Пока вы ждёте, цена смещается. В случайную минуту среднее неблагоприятное движение за наши медианные 195 ms составляло около 1.1 bps против направления сигнала. В минутах верхнего квартиля при 312 ms — 5.8 bps. В минутах верхнего 1% при 840 ms — около 14 bps неблагоприятного движения ещё до того, как ордер попадёт в стакан.
На бессрочных контрактах BTC спред почти не влияет на результат: один тик при котировке 84,000 — это 0.012 bps, поэтому ущерб связан с неблагоприятным движением цены, а не с пересечением спреда. Перейдите с той же стратегией на бессрочный контракт средней капитализации — и второй фактор даст о себе знать: спред на лучшем уровне стакана в нашей выборке вырос с 1.4 bps в спокойные минуты до 6.2 bps в верхнем квартиле, а объём на этом уровне упал более чем вдвое. Вы одновременно платите за движение цены, более широкий спред и меньшую глубину стакана — всё из-за одной общей причины.
Когда мы повторно проиграли те же 31 день с условной задержкой для каждой свечи вместо фиксированных 200 ms, средняя цена входа в бэктесте ухудшилась на 3.1 bps. Почти весь эффект пришёлся на 9% сделок. Расхождение между ценой входа в бэктесте и бумажной торговле сократилось с 4.2 bps до 0.9 bps. Sharpe стратегии на IS снизился с 1.7 до 1.1 — это честное значение, каким оно и было с самого начала.
Что же указывать в конфигурации
Не одно число. Сейчас мы делаем так:
- Выбирайте из выборки, не задавайте константу. Для каждого моделируемого ордера выбирайте задержку из эмпирического распределения, учитывающего активность конкретной свечи: достаточно числа сделок и абсолютной доходности, которые уже есть в стандартной kline. Стройте распределение отдельно для каждой биржи и типа ордера, обновляйте раз в месяц.
- Сохраняйте хвост распределения. Не подгоняйте логнормальное распределение и не считайте задачу решённой: p99 формируют волны повторных запросов и паузы GC, которые не воспроизводит никакое гладкое распределение. Мы используем эмпирические квантили и повторно выбираем значения из хвоста выше p95.
- Задержка распространяется и на отмену ордеров. Замена стоп-ордера или отмена хеджа подчиняются той же задержке, а на быстром рынке ваша отмена соревнуется с исполнением. Если симулятор отменяет ордер мгновенно, ваша модель риска выдумана.
- Добавьте проверку актуальности данных и смоделируйте её. Наша система отбрасывает любой сигнал, если к моменту получения его свече больше 1.5 секунд. Это реальное поведение с реальной ценой: оно незаметно удаляет сделки, и в бэктесте должны удаляться те же самые сделки.
- Сверяйте калибровку с бумажной торговлей. Бумажная торговля даёт фактические данные. Записывайте временные метки всех четырёх этапов для каждого ордера и каждую неделю сравнивайте распределения с предположениями симулятора.
В других классах активов та же проблема. Акции США: консолидированная лента добавляет задержку агрегации поверх задержки брокера, и при росте потока сообщений она увеличивается по той же структурной причине. Рынки прогнозов: на большинстве площадок ордера отправляются только через REST, и мы измеряли медиану меньше 100 ms, которая при событии расчёта вырастает до нескольких секунд, когда все приходят одновременно. Криптовалютные опционы: котировка, на которую вы опираетесь, может отставать на две секунды именно в ту минуту, когда базовый актив двинулся.
Суть ошибки — считать параметр исполнения независимой константой, хотя он зависит от той же переменной состояния, что и ваш сигнал. Комиссии ведут себя предсказуемо, фандинг — тоже, а задержка — нет. Если запомнить из всего этого одно число, запомните соотношение: наш p99 в 15 раз выше медианы, а сигналы непропорционально часто приходят ближе к уровню p99.
Добавьте измерения на всех четырёх этапах. Это займёт один рабочий день и расскажет о вашей стратегии больше, чем ещё неделя подбора параметров.
← Все статьи


