Jesse: крипто-алготрейдинг фреймворк с минутным движком на Python и Rust

Подробный обзор Jesse - фреймворка для алготрейдинга на крипторынках. Минутная симуляция, стратегии как конечные автоматы, Rust-ускоренные индикаторы, оптимизация с защитой от переобучения и граница между open-source ядром и live-торговлей.

Jesse — алготрейдинг фреймворк

Большинство open-source бэктестеров делятся на два лагеря: академические стеки, которые прекрасно тестируют, но непригодны для реальной торговли, и боевые терминалы, которые торгуют, но не дают нормально исследовать. Jesse пытается быть и тем, и другим — фреймворк для крипто-трейдинга с единым движком для бэктеста, оптимизации и (через плагин) живой торговли.

Под капотом — конкретные инженерные решения, которые стоит понять, прежде чем писать свою первую стратегию.

Архитектура: не библиотека, а контур

Jesse — это связка движка исполнения + API + UI:

  • CLI (jesse run) поднимает uvicorn с FastAPI
  • Роутеры для бэктеста, оптимизации, Monte Carlo, стратегий
  • PostgreSQL через Peewee для хранения свечей
  • LSP для редактора стратегий в браузерном UI
  • Плагин jesse-live для реальной торговли (отдельный репозиторий)

Карта ответственности прямо зафиксирована в AGENTS.md: правка бэктеста может ударить по live, а изменения индикаторов на Rust требуют пересборки нативной части.

Минутная симуляция: «источник истины»

Минутная симуляция Jesse

Критический инвариант Jesse зашит в assert: в бэктест можно передать только 1-минутные свечи. Если подсунете 5m-ряд — получите ValueError.

Почему это важно:

  • Движок мыслит минутной сеткой. Старшие таймфреймы — это агрегаты: стратегия на 1h вызывается каждые 60 минут, но ордера исполняются внутри каждой минуты по high/low.
  • Нет «параллельных миров данных». Все таймфреймы — виды одного потока, что уменьшает класс ошибок при смешивании дискретизаций.
  • Предсказуемый детерминизм. Если несколько ордеров попадают в один high-low диапазон, они сортируются по эвристике (направление свечи), а не моделированием стакана.
# Research API — изолированный бэктест для мультипроцессинга
from jesse.research import backtest

# Только 1m свечи! Таймфрейм — в route
result = backtest(
    config,
    routes=[("Binance", "BTC-USDT", "4h", "MyStrategy")],
    candles=candles_1m,  # строго 60_000 мс между свечами
)

Перед каждым прогоном свечи копируются через deepcopy, а после — store.reset(). Один процесс может гнать сотни trials без накопления мусора в глобальном состоянии.

Strategy: конечный автомат с декларативными ордерами

Strategy — центральный класс Jesse. Несколько принципов, которые стоит знать:

Кэш цены

Внутри одного вызова _execute() цена фиксируется в _cached_price = self.close. Цена не «плавает» из-за побочных эффектов — защита от тонких гонок.

Декларативные ордера

Вместо императивного broker.buy(100) Jesse использует декларативный подход:

def go_long(self):
    qty = utils.size_to_qty(self.balance * 0.5, self.price)
    self.buy = qty, self.price          # entry
    self.stop_loss = qty, self.price * 0.97  # stop
    self.take_profit = qty, self.price * 1.05  # target

Система сама решает: market, limit или stop — в зависимости от положения цены заявки относительно текущей. В live цена округляется по precision биржи.

Спот vs фьючерсы

take_profit/stop_loss внутри go_long() на споте запрещены — нужно переносить в on_open_position(). Это не придирка: маржинальная логика на споте и фьючерсах различается, и смешивание API привело бы к немым багам.

Фильтры с защитой от ошибок

# ❌ Так НЕ надо (вызов со скобками)
def filters(self):
    return [self.filter_1()]

# ✅ Так НАДО (ссылка без скобок)
def filters(self):
    return [self.filter_1]

Jesse ловит эту ошибку и выдаёт готовый пример — мелочь, которая экономит часы в Discord.

Оптимизация: не максимум прибыли, а отсечение мусора

Функция пригодности (fitness) борется с переобучением на нескольких уровнях:

  1. Минимум сделок. Если меньше 5 — конфигурация невалидна (score ≈ 0). Грубый, но рабочий фильтр против «стратегии из трёх сделок на удаче».

  2. Нормализация объёма. log10(total_trades) относительно оптимума, чтобы не раздувать вес количества.

  3. Выбор метрики. Sharpe, Calmar, Sortino, Omega, Serenity — каждая нормализуется своим диапазоном.

  4. Двухэтапная проверка. Сначала оптимизация на training-свечах, затем бэктест на отдельном testing-периоде. Не «подогнали под одну кривую».

«Умный» Sharpe

Sharpe и Sortino имеют флаг smart: стандартное отклонение умножается на штраф за автокорреляцию доходностей. Идея: ряд, который выглядит «гладким», но зависит от прошлого, не должен получать тот же Sharpe, что и ряд ближе к IID.

Rust под капотом

Индикаторы (EMA, RSI, MACD, ATR…) массово используют jesse-rust. Даже базовая арифметика — subtract_floats, sum_floats — вынесена в Rust: накопление ошибки float на тысячах сделок превращает бэктест в фантастику.

Граница open-source и live

  • Live-торговля подключается только через плагин jesse-live (отдельный репозиторий, коммерческий).
  • В live баланс и маржа приходят с биржи, а не из симулятора.
  • Часть логики стратегии отключается в live (if jh.is_livetrading(): return).

Не копируйте вслепую ветки «не live» в продакшен.

Сильные стороны и ограничения

✅ Плюсы⚠️ Минусы
Единая минутная симуляцияТолько крипто (нет акций, фьючерсов CME)
Чистый research APILive — отдельный платный плагин
Rust в горячих местахФреймворк диктует свою дисциплину
Осмысленная функция оптимизацииНет модели проскальзывания и ликвидности
Явное разделение live/sandboxMIT лицензия не гарантирует поддержку

Ссылки

Вывод

Jesse — это попытка свести крипто-алготрейдинг к повторяемому контуру: минутный движок, строгий Strategy, Rust на индикаторах, research API без утечек, оптимизация с тестовым периодом. Репозиторий читается как учебник по тому, какие инварианты нужно зафиксировать, пока пользователи пишут «ещё одну стратегию в пять строк» — и где эти инварианты спасут от собственной уверенности в бэктесте.