Симуляция исполнения: лестница от фантазии по цене закрытия до реальности с учетом очереди
Ваш бэктест содержит две модели: модель вашего альфы и модель ваших исполнений. Большинство тратит 95% усилий на первую и наследует вторую от того фреймворка, который оказался под рукой. Это неправильный порядок приоритетов. Посредственный сигнал с честной моделью исполнения дает посредственную, но реальную оценку PnL. Отличный сигнал с fill_price = candle.close дает число, которое вообще ничего не оценивает — это результат допущения, которое вы никогда не проверяли.
Для тейкер-стратегий на ликвидных инструментах модель исполнения — это поправочный член. А для всего, что связано с пассивными лимитными ордерами — маркет-мейкинг, пассивные входы, сбор ребейтов на post-only — модель исполнения и есть стратегия. Получите ли вы филл, когда, в каком объеме и в зависимости от какого последующего движения цены — все это определяет знак PnL, а не только его величину.
В статье Паритет бэктеста и живой торговли мы построили полную таксономию расхождений между бэктестом и живой торговлей и оценили расхождение в исполнении на 5/5 по серьезности — худший класс. Та статья дала симуляции исполнения три грубых уровня точности и пошла дальше. Эта статья — углубленный компаньон: полная лестница, ступень за ступенью, с жизненным циклом ордера как конечным автоматом, вычислимыми границами вероятности исполнения и измеренным экспериментом, точно показывающим, на какой ступени лестницы "прибыльная" мейкер-стратегия умирает.
Лестница

Каждая ступень требует больше данных и больше кода, и каждая ступень устраняет конкретное систематическое искажение. Ступени упорядочены по тому, что именно они делают неправильно, а не просто по стоимости реализации.
Ступень 0: филл по цене закрытия
fill_price = bar.close
Ордер исполняется мгновенно, полностью, по цене закрытия бара, который породил сигнал. Сигнал был вычислен по этому же закрытию, значит вы торгуете на данных, которых не существовало в момент печати цены: заглядывание в будущее, переодетое в костюм исполнения. Любая стратегия с оборотом здесь выглядит хорошо.
Ступень 1: открытие следующего бара
fill_price = next_bar.open
Минимальная честная модель для тейкер-логики на барах. Сигнал вычисляется на баре , исполнение происходит по первой наблюдаемой цене бара . Это убивает заглядывание в будущее, но все еще предполагает нулевой спред, нулевое воздействие на рынок, бесконечную ликвидность по цене открытия и стопроцентную гарантию исполнения. Для лимитных ордеров это вырождается в логику touch-fill (почему это яд — ниже).
Ступень 2: спред и фиксированное проскальзывание
half_spread = mid * spread_bps / 2e4
slip = mid * slippage_bps / 1e4
fill_price = mid + side * (half_spread + slip) # side: +1 buy, -1 sell
Теперь каждая тейкер-сделка платит половину спреда плюс калиброванную константу. Это первая ступень, на которой высокооборотная стратегия может умереть в бэктесте — в этом и смысл. Остаточная ошибка: проскальзывание не постоянно. Оно масштабируется с размером ордера относительно отображаемой глубины и резко растет именно тогда, когда ваша стратегия больше всего хочет торговать. Фиксированные 5 базисных пунктов — это усреднение по режимам рынка; ваша стратегия не торгует средний режим.
Ступень 3: проход по глубине L2 для рыночных ордеров
Имея снэпшоты стакана, вы перестаете угадывать проскальзывание и вычисляете его. Рыночная покупка объемом проходит по стороне аска уровень за уровнем; цена исполнения — это объемно-взвешенное среднее по пройденным уровням:
def depth_walk(levels: list[tuple[float, float]], qty: float) -> tuple[float, float]:
"""levels: [(price, size), ...] sorted best-first. Returns (vwap, filled_qty)."""
remaining, cost = qty, 0.0
for price, size in levels:
take = min(size, remaining)
cost += take * price
remaining -= take
if remaining <= 0:
break
filled = qty - remaining
return (cost / filled if filled > 0 else float("nan"), filled)
Две поправки делают эту модель существенно честнее. Первая — задержка: проходите по стакану таким, каким он был через после временной метки вашего решения, где — измеренная задержка от сигнала до биржи: стакан, который вы видели, не тот стакан, по которому вы бьете. Вторая — частичные исполнения маркетебл-ордеров: если отображаемая глубина в пределах вашей предельной цены меньше , модель обязана вернуть частичное исполнение и оставить остаток в стакане, что передает задачу конечному автомату ниже.
Остаточная ошибка на ступени 3 — это воздействие на рынок и пополнение стакана: вы потребляете стакан как статический объект, но реальные стаканы частично пополняются (и реальные контрагенты реагируют). Для клипов размером ниже нескольких процентов от глубины на лучшей цене эта ошибка мала; для более крупных клипов нужна модель воздействия (Almgren-Chriss, 2001), надстроенная сверху.
Ступень 4: вероятностные исполнения лимитных ордеров с учетом позиции в очереди
Ступени 0-3 отвечают на вопрос "по какой цене исполнится мой агрессивный ордер". Ступень 4 отвечает на более сложный вопрос: исполнится ли мой пассивный ордер вообще — и это единственная ступень, способная оценить мейкер-стратегию. Пассивный лимитный ордер по цене исполняется, когда накопленный торгуемый объем по цене превышает объем очереди, стоявшей перед ним. Для этого нужно отслеживать вашу позицию в FIFO-очереди, которую вы не можете наблюдать напрямую.
Механика оценки позиции в очереди — начальная позиция, правила обновления при сделках и отменах, семейство функций для распределения ненаблюдаемых отмен — это примитив, который мы построили в статье Очередь внутри стены. Здесь я не буду выводить его заново; симулятор просто использует его. Что добавляет ступень 4 — это правило принятия решения об исполнении поверх этой оценки, разобранное в разделе о вероятности исполнения ниже.
Насколько важна эта ступень, показывает литература: Moallemi и Yuan (2016) в работе "A Model for Queue Position Valuation in a Limit Order Book" показывают, что для инструментов с крупным тиком экономическая ценность позиции в начале очереди против конца очереди сопоставима с половиной спреда — тем же порядком величины, что и вся теоретическая маржа маркет-мейкинговой стратегии. Модель исполнения, игнорирующая позицию в очереди, не просто неверно оценивает PnL мейкера — она оценивает PnL совсем другой стратегии.
Существует и ступень 5 — полная агентная симуляция, где рынок реагирует на ваши ордера (queue-reactive модели в смысле Huang, Lehalle и Rosenbaum, 2015; мультиагентные фреймворки вроде ABIDES, Byrd et al., 2020). Исторический реплей, даже с учетом очереди, предполагает, что ваш ордер ничего не меняет в поведении всех остальных участников. Это допущение нормально работает на розничных объемах и все сильнее нарушается по мере того, как ваши котировки становятся заметной долей уровня. Ступень 5 здесь не рассматривается; просто имейте в виду, что лестница не заканчивается на четвертой ступени.
Частичные исполнения как конечный автомат
Ступени 0-2 могут притворяться, что ордер — это функция: отправил, получил цену, готово. Начиная со ступени 3, ордер — это процесс с жизненным циклом, и симулятор обязан моделировать его как конечный автомат, иначе он молча неправильно обработает именно те случаи, которые важнее всего.

enum OrderState {
PendingNew, // sent, not yet acked (latency window)
Resting { remaining: f64, q_ahead: f64 }, // in book, queue position estimated
PartialFill { remaining: f64, q_ahead: f64 }, // some qty done, rest still queued
PendingAmend, // amend in flight
PendingCancel, // cancel in flight
Filled,
Canceled { filled_qty: f64 }, // may be partially filled at cancel time
Rejected,
}
Переходы несут в себе экономический смысл:
PendingNew→Resting: ордер встает в очередь позади всего, что присутствовало в момент подтверждения, а не в момент решения. Ваша позиция в очереди инициализируется объемом уровня на момент . Симуляторы, инициализирующие позицию на момент решения, систематически завышают приоритет в очереди — ровно на объем, пришедший за время окна задержки, а это обычно наибольший объем во время всплесков активности.Resting→PartialFill: сделка по вашему уровню, превышающая объем очереди перед вами, исполняет вас частично. Остаток сохраняет свою (теперь ставшую передовой) позицию. Частичные исполнения — это не шум, это информация: получить филл на 0.3 из 1.0 и увидеть, как цена отскакивает — это другое PnL-событие, чем полный филл, и процесс инвентаря мейкера строится именно из этих фрагментов.Resting→PendingAmend→Resting: ловушка. Практически на любой криптобирже аменд — это cancel/replace:cancelReplaceот Binance атомарен против двойного исполнения, но возвращает новый ID ордера в конце очереди. Даже площадки с нативной семантикой модификации (CME Globex) сохраняют временной приоритет только при уменьшении объема; изменение цены или увеличение объема лишает приоритета. Поэтому в симуляторе: любой аменд цены сбрасываетq_aheadдо полного текущего объема уровня. Квотирующий движок, перевыставляющий котировку каждые 500 мс, не "поддерживает котировку" — он бесконечно заново встает в конец очереди, и его реалистичный профиль исполнений — это почти чистый неблагоприятный отбор. В сочетании с результатом Моаллеми-Юаня: перевыставление котировок имеет свою цену, и эта цена — ваша позиция в очереди.PendingCancel→PartialFill→Canceled: отмены тоже занимают время. В окне между решением снять котировку и достижением отменой матчинг-движка вас все еще может исполнить — и это будут худшие филлы, которые вы когда-либо получите, потому что причина, по которой вы снимали котировку — рынок вот-вот вас переедет. Симулятор без задержки отмены удаляет из вашей истории именно самые токсичные филлы.
Конечный автомат также делает учет симулятора честным: комиссии начисляются по каждому событию исполнения, инвентарь обновляется по каждому событию исполнения, а статистика времени в состоянии (сколько ордера стоят перед исполнением против отмены) становится напрямую сопоставимой с живыми логами — на этом и построен цикл калибровки в конце статьи.
Вероятность исполнения лимитного ордера: три модели и вилка
Дан ордер, стоящий по цене (скажем, бид). Когда симулятор объявляет филл? Три правила принятия решения, в порядке возрастания честности:
1. Touch-fill (наивное). Филл, если цена коснулась вашего уровня: . Это правило первого прохождения (first-passage-time), и его несостоятельность была измерена четверть века назад: Lo, MacKinlay и Zhang (2002) в работе "Econometric Models of Limit-Order Executions" (Journal of Financial Economics 65) подгоняют модели выживания к реальным данным лимитных ордеров и заключают, что гипотетические исполнения, построенные по времени первого прохождения, "являются очень плохими прокси для реальных исполнений лимитных ордеров". Механизм сбоя структурный: когда цена касается вашего уровня и отскакивает, касание поглотило переднюю часть очереди — трейдеров, выставившихся раньше вас. Touch-fill приписывает вам их филлы. Хуже того, он приписывает именно хорошие филлы (касание-и-отскок — прибыльный сценарий для мейкера), тогда как ваш реальный набор филлов смещен в сторону касания-и-пробоя — филлов с неблагоприятным отбором.
2. Trade-through (консервативная граница). Филл только если цена торгуется строго через ваш уровень: , или на тиковых данных — накопленный торгуемый объем по превышает весь уровень целиком. Если цена прошла насквозь, вся очередь по была поглощена, значит вы были исполнены независимо от позиции. Это никогда не приписывает вам филл, которого вы бы не получили. Ее искажение зеркально противоположно искажению touch-fill: она отказывает вам в каждом филле, где очередь истощилась до вашей позиции без полного пробоя, а те филлы, что она все же дает — непропорционально филлы пробоя (с неблагоприятным отбором). Мейкер-бэктест на trade-through — это стресс-тест, а не оценка.
3. Оценка истощения очереди. Отслеживайте накопленный торгуемый объем по вашей цене из ленты сделок и отмененный объем , выведенный из дельт L2. Ваша оценка очереди перед вами:
где — объем уровня на момент входа ордера (по времени подтверждения), а — доля отмен, предполагаемая пришедшей из очереди перед вами: тот самый параметр, чья принципиальная форма (семейство ) выведена в статье о позиции в очереди. Исполнение начинается, когда ; ваш исполненный объем — это торгуемый объем сверх этого значения, что естественным образом дает частичные исполнения:
Установка (все отмены перед вами) дает оптимистичный край этой модели; — пессимистичный край. Когда у вас есть только разреженные снэпшоты L2 и нет ленты сделок по уровню — обычное дело для крипто-фидов с троттлингом 100 мс — можно опереться на модель-априор: Cont, Stoikov и Talreja (2010) в работе "A Stochastic Model for Order Book Dynamics" (Operations Research 58) моделируют каждый ценовой уровень как очередь рождения-гибели и вычисляют через преобразования Лапласа вероятность того, что ордер по биду исполнится раньше, чем сдвинется мид, при заданных текущих размерах очередей. Это аналитический оракул вероятности исполнения: грубый по сравнению с реплеем ленты сделок, но намного лучше touch-fill и достаточно дешевый для вычисления внутри горячего цикла бэктеста.
Дисциплина вилки
Три правила — не конкуренты, а упорядочение:
которое порождает PnL-вилку. Запускайте каждый мейкер-бэктест три раза и отчитывайтесь интервалом:
(верхнее неравенство приблизительное — touch-fill может не только завышать, но и неправильно ранжировать стратегии, поскольку приписывает вам контрфактические хорошие филлы). Отсюда следует правило принятия решения: мейкер-стратегия пригодна к развертыванию только если она выживает на консервативном краю вилки, и только если вилка достаточно узкая, чтобы точечная оценка что-то значила. Стратегия, показывающая +3k на trade-through, имеет вилку шириной 2.1k / +$0.4k, говорит вам что-то реальное.
Эксперимент: спуск одной мейкер-стратегии по лестнице

Возьмем один нарочито простой мейкер — симметричные котировки на лучшем биде/аске, фиксированные клипы 0.05 BTC, лимит инвентаря ±0.5 BTC с тейкер-выравниванием на лимите. Один месяц данных по BTCUSDT перпетуалу: минутные бары для нижних ступеней, диффы L2 со 100 мс плюс лента сделок для верхних ступеней; комиссия мейкера 1.0 б.п., тейкера 4.0 б.п. Один и тот же код сигнала на каждой ступени (общее ядро, так что единственная переменная — модель исполнения). Цифры ниже — один показательный прогон из наших: ваши величины будут отличаться по площадке, месяцу и размеру, но форма — нет:
| Ступень | Модель исполнения | Доля исполненных котировок | Филлов | PnL за месяц | Вердикт |
|---|---|---|---|---|---|
| 0 | close-fill | 98% | 41,200 | +$14,800 | фантазия |
| 1 | next-bar-open / touch на минутных барах | 89% | 37,400 | +$9,600 | фантазия с задержкой |
| 2 | touch + спред и фиксированное проскальзывание на тейкер-выравниваниях | 89% | 37,400 | +$7,100 | издержки учтены, филлы все еще фиктивны |
| 3 | + проход по L2-глубине на тейкер-выравниваниях | 89% | 37,400 | +$6,400 | выходы честны, входы все еще фиктивны |
| 4a | trade-through (консервативный) | 21% | 8,900 | -$3,900 | стресс-граница |
| 4b | истощение очереди, калиброван | 37% | 15,600 | -$700 | лучшая оценка |
| 4c | истощение очереди, (оптимистичный) | 44% | 18,700 | +$1,900 | верхний край |
| — | живой теневой прогон, тот же месяц | 35% | 14,100 | -$1,150 | реальность |
Читайте таблицу сверху вниз и смотрите, где стратегия умирает. Это не ступень 2 — комиссии и проскальзывание срезают 26%, а стратегия все еще выглядит устойчиво прибыльной. Она умирает между ступенью 3 и ступенью 4, и умирает по причине, которую не может уловить ни одна модель издержек: отбор филлов. Touch-fill дал 37,400 филлов, большинство из которых были касание-и-отскок — чистый захват спреда. Модель с учетом очереди удалила 58% этих филлов, и удаленные филлы были непропорционально прибыльными: когда уровень задет слегка, очередь перед мейкером с розничной задержкой, перевыставляющим котировки, поглощает все. Филлы, доживающие до ступени 4, смещены в сторону свипов, вычищающих уровень — филлов, где цена уже движется сквозь вас. Доля исполнения упала в 2.4 раза; PnL сменил знак. Эта асимметрия — потеря хороших филлов при сохранении плохих — это неблагоприятный отбор, сделанный механически явным, и он невидим на любой ступени ниже четвертой.
Обратите внимание также, что сделала вилка: [-1,900] охватывает ноль, с калиброванной оценкой в -1,150. Симулятор не попал в живой PnL до доллара — он поймал знак, величину и долю исполнения с точностью до 2 пунктов. Именно для этого нужна модель исполнения. Бэктест на ступени 1 промахнулся мимо живого PnL на $10,750 на стратегии, чья вся месячная валовая маржа составляла несколько тысяч долларов: ошибка модели исполнения была примерно в 3 раза больше размера самого альфы. Отсюда тезис: ваша модель исполнения — более крупное допущение, чем ваш альфа.
Одна оговорка для нижних ступеней: если вам приходится жить на баровых данных (ступени 0-2), как минимум разрешайте внутрибарную неоднозначность через адаптивную детализацию — спускаясь с минутного таймфрейма до секундного/100 мс/сделок там, где уровни SL, TP или котировок попадают внутрь диапазона бара. Детализация исправляет ошибки последовательности (какой уровень был задет первым), но не может исправить ошибки очереди; это компаньон по разрешению данных к этой статье, а не замена ступени 4.
Цикл калибровки: замыкание на живые филлы
Симулятор ступени 4 имеет свободные параметры — , задержку , задержку отмены, допущение о пополнении уровня. Без калибровки это просто по-другому сформированная догадка. Цикл, превращающий его в инструмент:
1. Логируйте все вживую. Каждое событие ордера с биржевыми временными метками: отправка, подтверждение, каждое частичное исполнение, подтверждения амендов, подтверждения отмен. Плюс состояние L2 на момент отправки. Это та же дисциплина логирования, которую паритет бэктеста и живой торговли требует для своего DivergenceMonitor — калибровка модели исполнения является самым глубоким слоем этого монитора.
2. Прогоните те же ордера через симулятор. Подайте записанные рыночные данные и записанные инструкции ордеров (не филлы) в симулятор. Теперь у вас есть парные исходы: для каждого живого ордера — симулированный исход.
3. Сравнивайте распределения, а не средние, по бакетам. Единое глобальное совпадение доли исполнения может скрывать компенсирующие ошибки (слишком оптимистично в спокойных режимах, слишком пессимистично во всплесках — что в сумме дает "калибровано"). Разбивайте по драйверам:
import numpy as np
from scipy.stats import ks_2samp
def calibration_report(pairs, bucket_key):
"""pairs: [{'bucket':…, 'live_filled':bool, 'sim_filled':bool,
'live_ttf':float|None, 'sim_ttf':float|None}, …]"""
out = {}
for b in sorted({p['bucket'] for p in pairs}):
grp = [p for p in pairs if p['bucket'] == b]
live_fr = np.mean([p['live_filled'] for p in grp])
sim_fr = np.mean([p['sim_filled'] for p in grp])
live_ttf = [p['live_ttf'] for p in grp if p['live_ttf'] is not None]
sim_ttf = [p['sim_ttf'] for p in grp if p['sim_ttf'] is not None]
ks = ks_2samp(live_ttf, sim_ttf) if len(live_ttf) > 20 and len(sim_ttf) > 20 else None
out[b] = {
'n': len(grp),
'fill_rate_live': live_fr,
'fill_rate_sim': sim_fr,
'fill_rate_gap': sim_fr - live_fr, # signed: + means sim optimistic
'ttf_ks_pvalue': ks.pvalue if ks else None,
}
return out
Две статистики на бакет: знаковый разрыв доли исполнения (симулятор минус живая торговля) и KS-тест на распределениях времени до исполнения среди исполненных ордеров. Сравнение времени до исполнения — это острый инструмент: симулятор может совпадать по долям исполнения, но исполнять в систематически неверные моменты времени, что портит всю нижестоящую статистику инвентаря и неблагоприятного отбора. Это в точности урок из подхода Lo-MacKinlay-Zhang через анализ выживаемости: исполнение — это задача времени-до-события, так и валидируйте ее.
4. Подгоняйте параметры в порядке идентифицируемости. Сначала задержка (измеряется напрямую по временным меткам подтверждений — не подгоняется). Затем — минимизацией разрыва доли исполнения по бакетам глубины очереди. Затем проверьте бакеты по режимам волатильности: устойчивый оптимистичный разрыв, сконцентрированный в бакетах всплесков, обычно означает, что ваш симулятор недомоделирует токсичные филлы из-за задержки отмены или пополнение уровня, а не проблему с .
5. Перезапустите вилку. После калибровки оценка истощения очереди должна располагаться внутри вилки, рядом с живым результатом, и — реальный тест приемки — ранжирование вариантов стратегии в симуляторе должно совпадать с их ранжированием в теневом режиме. Затем зафиксируйте параметры и перекалибровывайте по расписанию; динамика исполнений дрейфует вместе с тарифными сетками площадки, изменениями размера тика и составом HFT-участников, а , откалиброванный в марте — это гипотеза уже к июлю.
Ожидания сходимости по нашим прогонам: некалиброванный симулятор ступени 4 обычно попадает в пределах ±10-15 пунктов от живой доли исполнения; после одного прохода калибровки — ±3-5 пунктов, с p-значениями KS-теста на времени до исполнения, уже не отвергающими гипотезу равномерно. Лучше этого на историческом реплее вы не добьетесь — остаток составляет реакция рынка на вас самих, а это проблема ступени 5.
Что нужно вынести
- Назовите свою ступень. Каждый бэктест стоит на этой лестнице — выбрали вы ступень сами или ее выбрал за вас ваш фреймворк. Если вы не можете назвать ступень своей модели исполнения и ее известные искажения, у вашего числа PnL есть погрешности, которых вы не видели.
- Тейкеры могут остановиться на ступени 3. Проход по глубине плюс измеренная задержка честно оценивают агрессивное исполнение на розничных объемах. Сэкономленные усилия потратьте на качество данных.
- Мейкеры начинают со ступени 4. Ниже нее логика исполнения лимитных ордеров не просто приблизительна — она отбирает контрфактический набор филлов с противоположным смещением неблагоприятного отбора. Touch-fill бэктесты мейкер-стратегий — самый надежный генератор стратегий, умирающих при столкновении с продакшеном.
- Моделируйте жизненный цикл, а не сам филл. Частичные исполнения, сброс очереди при аменде, задержка отмены — конечный автомат это место, где живут токсичные филлы, а токсичные филлы это место, где умирает PnL мейкера.
- Отчитывайтесь вилкой. Консервативная и оптимистичная границы стоят двух дополнительных прогонов бэктеста и превращают "мой бэктест говорит +3.9k, +$1.9k]" — а это другое, и лучшее, решение.
- Калибруйтесь по живым филлам в бакетах. Модель исполнения, валидированная только в агрегате — это модель исполнения со скрытыми компенсирующими ошибками. Бакетизированные разрывы доли исполнения плюс KS-тесты времени до исполнения, перекалиброванные ежеквартально.
Ступени этой лестницы — не академическая градация: каждая устраняет конкретную ложь, которую до этого рассказывал вам ваш бэктест. Поднимайтесь, пока ложь не станет меньше вашей маржи.
Полезные ссылки
- Moallemi, C., Yuan, K. — A Model for Queue Position Valuation in a Limit Order Book (2016)
- Cont, R., Stoikov, S., Talreja, R. — A Stochastic Model for Order Book Dynamics, Operations Research 58(3), 549-563 (2010)
- Lo, A., MacKinlay, C., Zhang, J. — Econometric Models of Limit-Order Executions, Journal of Financial Economics 65(1), 31-71 (2002)
- Huang, W., Lehalle, C.-A., Rosenbaum, M. — Simulating and Analyzing Order Book Data: The Queue-Reactive Model, JASA 110(509), 107-122 (2015)
- Almgren, R., Chriss, N. — Optimal Execution of Portfolio Transactions (2001)
- Byrd, D., Hybinette, M., Balch, T. — ABIDES: Towards High-Fidelity Multi-Agent Market Simulation (2020)
- Binance API — Cancel-Replace order semantics
- CME Globex — Order modification and time priority rules
Citation
@article{soloviov2026fillsimulation,
author = {Soloviov, Eugen},
title = {Fill simulation: the ladder from close-price fantasy to queue-aware reality},
year = {2026},
url = {https://marketmaker.cc/blog/fill-simulation-partial-fills-backtest},
description = {Five rungs of fill simulation fidelity — from close-price fills to probabilistic queue-position models. Partial fills as a state machine, limit-fill probability bounds as a PnL bracket, and a calibration loop against live fills.}
}
Авторы
Инженер торговых систем
Разработка торговых ботов с 2017 года: межбиржевой арбитраж (подключал до 30 бирж), парный арбитраж на коинтеграции между спотом и фьючерсами, скальпинг, фронтраннинг, торговля по новостям, сентиментный анализ, трендовые алгоритмы, а также алгоритмы управления и балансировки портфелей. Делает выставление ордеров до 1 мс, warehouse для big data, бэктестинг-движки, AI-агентов и интерфейсы для ботов (в т.ч. open-source profitmaker.cc). Стек: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, архитектура.