Синтетический рынок в контуре торговых ботов
Торговый бот работает в контуре, где сначала — синтетика, потом — реальный рынок. Не вместо, а для разных фаз.
Торговый бот работает в контуре, где сначала — синтетика, потом — реальный рынок. Не вместо, а для разных фаз.
У меня торговый бот работает в контуре, где сначала — синтетика, потом — реальный рынок. Не «или/или», а именно в этой последовательности. Раньше я делал наоборот: гонял тест на истории, деплоил, ловил тонкие случаи в продакшне. Потом понял, что половина тонких случаев — это не «что-то, что случится на рынке», а «что-то, что мой алгоритм неправильно интерпретирует». Вторую категорию на реальных данных не поймать — там нет повторяемости. Синтетика закрывает именно эту дыру.
market-data-emulator (project page) берёт на себя три задачи, на которые реальных данных не хватает.
Реальный рынок даёт мне один текущий режим — он такой, какой есть. Я не могу протестировать, как мой движок оценки рисков ведёт себя в каскаде ликвидаций, если на рынке сейчас нет такого каскада. Я не могу проверить, как стратегия по стакану обрабатывает мгновенный обвал, если мгновенный обвал не случался последние полгода. Эмулятор генерирует нужный режим по запросу: meta.regimes_summary отдаёт {"trend_up": 5, "range": 235} для 240 баров, и я знаю, что в трендовой фазе должен сработать трендовый индикатор, а в боковике — нет. Это не «реалистичные данные», это контролируемая среда. Я выбираю параметры, фиксирую seed, проверяю поведение.
В конвейере программы отдельные блоки — change_point_detector, regime_hmm, spring_detector, wyckoff_detector. Каждый надо тестировать изолированно: что он ловит, что пропускает, что ловит ложно. На реальных данных — это композиция из тестовых выборок реальных дней, и для каждого тестового случая надо искать подходящий день. На синтетике — это сценарий с заранее известным эталоном. change_point_injection сам говорит «сдвиг уровня @ бар 100, среднее +5σ», и мой детектор должен это поймать. В wyckoff_spring есть эталон-пружина, и мой детектор не должен её пропустить. Тест пишется один раз, эталон живёт в реестре сценариев.
Когда я тренирую ML-фильтр на конкретный паттерн (отличить dead_cat_bounce от продолжения тренда, например), мне нужен датасет, где этих паттернов много и в разных вариациях. На реальных данных — 3-5 случаев за год, каждый в уникальном контексте, листовые метки расставляются вручную. На синтетике — 50 примеров каждого паттерна с разными drift-параметрами, разной σ, разными режимами. Модель учится на структуре, а не на конкретных исторических совпадениях. Это не «фейковые данные для обучения», это прирост датасета с контролируемой меткой.
Синтетика не заменяет реальный рынок. Бот, который прошёл только синтетические тесты, не готов к деплою — он не видел живого стакана, микроструктуры, дислокаций. Синтетика покрывает фазу, где реальный рынок либо избыточен (я знаю, что хочу протестировать), либо вреден (на реальных данных учить на каждом примере — это переобучение на историю). Реальный рынок покрывает фазу, где нужна правдоподобная картина без возможности контролировать переменные.
Поэтому порядок такой: синтетика → тесты узлов и движка оценки рисков → тест на истории реальных данных → пробная торговля → боевой режим. Эмулятор — это не инструмент замены реального рынка, это инструмент фазы, где реальный рынок либо не ловит, либо не учит.
OrderbookSnapshot L2 генерируется как функция, а не как результат сопоставления.Если интересно, больше информации о проекте — на странице проекта /projects/market-data-emulator/ или в репозитории github.com/elriseio/market-data-emulator.