Astrobot
v1.2 · 2026-09
02 · Pipeline

Как работает

Под капотом — две дорожки: research (как модель обучали и тестировали на истории) и live (как ровно та же модель работает на бирже сейчас). Принципиально важно: используется один и тот же файл модели, поэтому решения на бирже совпадают с симуляцией с точностью до копейки — никакой подмены не происходит. Дальше — пошагово, что происходит внутри каждой дорожки.

1
Загрузка котировок
26 тикеров MOEX (blue chips) × часовые бары × 2016-01..2025-06 (~30k баров на тикер). Источник OHLCV — T-Invest API (история через backtrader.ru bundle для consistency)
2
Расчёт стратегий (long+short FSM)
2 773 параметризованных стратегий на тикер: 12 skip-list + 10 direction-aware + 55 candle patterns × сетки параметров. FSM (Finite State Machine) поддерживает long+short с event shift(1) для anti-leakage. Каждая выдаёт signed position ∈ {−1, 0, +1}
3
Отбор top-50 стратегий
Ранжирование по feature importance на TRAIN+VAL (CatBoost feature_importance после первого pass). Замена v6.0 подхода (top-100 by Sharpe с квотами 9+11+80) — importance-ranked отбор отсёк CDLDOJI шум, оставил действительно informative стратегии
4
Сборка обучающего датасета
73 фичи × ~615k строк × 26 тикеров. Состав: 50 raw {sid}_position (signed) + 8 raw indicators (RSI/ADX/NATR/CHOP/MACD/CCI/BB) + 6 hourly ctx + 6 daily ctx + 2 macro (dividend + CBR) + ticker_id. Target: forward 20-bar log return ансамбля (clip ±10%)
5
Обучение CatBoost RMSEWithUncertainty
Regression с RMSEWithUncertainty loss. Cross-ticker — одна модель на все 26 тикеров (ticker_id как categorical). Output на каждый бар: μ̂ (ожидаемый возврат) + σ̂² (uncertainty). Early stopping на VAL 2023. Seed=42, 45s train
6
Расчёт целевых позиций (kelly_vol L+S)
meta_pos = clip(kelly_fraction · μ̂ / σ̂² × vol_target/realized_vol, −1, +1) × cost_gate × turnover_filter. kelly_fraction=0.5, target_vol_annual=0.15, halflife=20, cost_hurdle=0.0003, min_change=0.20. long_only=False — signed positions сохраняются
7
Asymmetric hurdle entry filter (v1.2: 15L / 6S)
Кандидат заходит в priority queue если pred_mean > +15 bps (long) ИЛИ pred_mean < −6 bps (short). До v1.2 было 18L/12S: порог лонга опущен ради недобора bull-фаз, шорта — потому что под честной семантикой оптимум сместился к частым мелким шортам
8
Симуляция портфеля (10-slot priority rotation L+S)
10 fixed slots. 4 actions: {BUY, SELL_TO_CLOSE, SELL_SHORT, BUY_TO_COVER}. Каждый бар: топ-10 по |meta_pos| → slots; слабейший вытесняется при появлении сильнее (forced exit); при |target_pos| ≤ EPS_ACTIVE=0.10 — natural exit. v1.2: sign-flip exit — разворот знака прогноза закрывает позицию и открывает новую (раньше сим переворачивал её бесплатно, из-за чего доходность была завышена). Шорты интрадей — EOD-cover на баре 21:00, ночёвок и borrow нет. Комиссия 5 bps/side
9
Shared cash pool (v1.2: cb=0.10)
Explicit cash переменная. slot_equity = total × 0.90 / 10 ≈ 9% (до v1.2 буфер был 30%, slot ≈ 7%). Буфер урезан после того, как шорты стали внутридневными — залог под ночной перенос больше не нужен. Открытые позиции компаундятся per-slot по mark-to-market. signed qty_lots в state
10
KPI / multi-seed evaluation
Sharpe, CAGR, MaxDD, Calmar; monthly returns; per-ticker contribution. 5-seed sweep обязателен (D_4 amplifier std ~0.4-0.7 — single-seed = lottery). Shuffle leakage test (label shuffle) PASS +13.88σ above null

Тот же inference pipeline, но на свежих часовых барах с T-Invest. Запускается cron'ом каждый час (close of bar + 5 мин buffer) в торговые часы MOEX. С 13.05.2026 — Phase 3 sandbox; с 25.06.2026 — PROD live (LIVE_TRADING=1, реальные деньги на боевом счёте T-Invest).

1
cron каждый час (торговые часы MSK)
runner.py — idempotent по bar_ts: один бар — один полный цикл. ENABLE_SHORT=1 в env (иначе main.py default long-only)
2
Проверки: halt-флаг и новый бар
Если halted.flag присутствует или нового бара ещё нет — выход без действий. Статусы монитора: HALT — только >3 исключений в час; PAUSE — разрыв котировок >2 ч (новые позиции не открываются); ALERT — просадка >10% от пика и возраст позиции >30 дней (уведомление, торговля продолжается)
3
Загрузка котировок (T-Invest)
UTC cache → MSK-naive parquet, формат как в research. Кэш incremental — догружается только дельта. Trailing window WARMUP=2000 bars (для ADX/UI convergence)
4
Расчёт индикаторов и стратегий
Trailing 2000 баров для top-50 стратегий из bundle + 8 семейств raw indicator. Subprocess wrapper над Meta_model/strategy_indicator_calc/main.py --mode live. Те же strategy_id, что и при обучении
5
Inference модели
73-фичевая X-матрица → тот же CatBoost artifact (bit-exact parity с research) → kelly_vol L+S sizer → signed meta_pos per ticker (19 тикеров в live, top ликвидных MOEX)
6
Asymmetric hurdle filter (15L / 6S bps)
Кандидат на entry проходит если pred_mean > +15 bps ИЛИ pred_mean < −6 bps. Уже открытые позиции не трогает. Params: HURDLE_BPS_ENTRY=15, HURDLE_BPS_ENTRY_SHORT=6. gate15: на барах с 15:00 МСК новые шорты не открываются — короткому сигналу не хватает времени до вечернего закрытия
7
Расчёт целевого портфеля (v1.2: kelly-вес входа)
7 слотов на боевом капитале (research-конфигурация — 10). Priority по |meta_pos|, force-exit weakest, shared cash pool 90% / 7 slots ≈ 12.9% per slot. Вход берёт не весь слот: w = clip((|pred_mean| / σ₁₂₀) / 0.20, 0.4, 1), где σ₁₂₀ — std часовых лог-ретёрнов за 120 баров (причинная, без текущего). Сигнал уверенно перекрывает шум бумаги → слот целиком; слабый на фоне шума → 40%. morncap: шорт-входу на утреннем баре вес × 1.5 (кэп 1.0) — там 2/3 шорт-альфы. Signed qty_lots в sizer_state, EPS_ACTIVE=0.10 для natural exit, sign-flip exit при развороте знака
8
Вечерний бар 21:00 — EOD-cover и парковка кэша
EOD-cover: все шорты закрываются на баре 21:00 (детект на 21:00 и 22:00, новые шорты на них запрещены) — запас вечерней сессии 1ч45м на исполнение. CASH-park: бот считает «ядро» — минимум свободного кэша за торговый день — и покупает на него LQDT (фонд ликвидности); при нехватке рублей под утренние входы паи продаются в том же баре до отправки ордеров. Гистерезис 5% equity, мин-сделка 500 ₽, любая ошибка по фонду = WARN и no-op, торговлю не блокирует
9
Отправка ордеров (prod)
4 actions {BUY, SELL_TO_CLOSE, SELL_SHORT, BUY_TO_COVER} → broker_side {BUY, SELL} для T-Invest API. broker.post_market_order на боевом счёте T-Invest (ProductionBroker, LIVE_TRADING=1)
10
Мониторинг + Telegram
Автостопа по просадке нет (решение 26.06.2026): просадка — часть стратегии, авто-стоп выбивал бы на дне, решение остаётся за человеком. Просадка 10% от пика и позиция старше 30 дней — только Telegram-алерт. Автоматика останавливает торговлю (halted.flag, снимается вручную) единственным гейтом — 3+ исключения в час, то есть при технической поломке; при разрыве котировок > 2 ч включается PAUSE: открытые позиции ведутся, новые не открываются. Уведомления по entry/skip/exit/replace + утренний и вечерний отчёт. observation_sanity.py — 6 проверок корректности (parity, state, sign distr, hurdle hit, turnover, action coverage)