Polymarket Bot Tutorial · Глава 30 из 32

Production-grade code для risk management в Polymarket bots: position caps, daily loss limits, halt sentinels, fill-rate watchdogs, reconcile-on-restart, idempotent retries. Code patterns from real production trader.

Что охватывает эта глава

Risk code - это большая часть production trading bot. Логика strategy - самая простая часть; окружающие caps, halts, watchdogs и reconcilers и определяют, переживет ли bot свою первую плохую неделю. Эта глава - production-grade risk pattern.

  • Почему risk code - это большая часть реального trading bot
  • Position caps (per-market, per-strategy, total)
  • Daily loss kill switch
  • Halt sentinels (file-based emergency stop)
  • Fill-rate watchdog
  • Reconcile diary vs on-chain on restart
  • Code: production-grade halt-aware loop

Почему risk code - это большая часть реального trading bot

Один показатель, который мы получили на собственном codebase бота: 60% LOC - это risk code (caps, halts, watchdogs, reconciliation). 30% - strategy. 10% - glue.

Это правильное соотношение. Strategy - простая часть: описать, когда входить и когда выходить, можно в нескольких десятках строк. Risk code - это всё остальное: что делать, когда price движется против вас быстрее, чем ожидалось, что делать, когда fills перестают проходить, что делать, когда WebSocket падает, что делать, когда strategy оказывается убыточной.

Большинство историй провала builder'ов похожи друг на друга: strategy работала, но bot продолжал торговать во время смены режима рынка, потому что halt так и не сработал. Пишите halts до того, как писать strategy.

Position caps (per-market, per-strategy, total)

Три cap'а, enforced в code.

  • Per-market cap: max $X на market независимо от confidence в edge. Типично: $25-100 для small bots, $200-500 для production. Ограничивает blast radius ошибочного решения по одному market.
  • Per-strategy cap: если вы запускаете несколько strategies, каждая получает свою долю total capital. Типично: 30-50% на strategy. Не позволяет одному плохому дню одной strategy съесть capital остальных.
  • Total cap: max % от balance wallet, deployed одновременно. Типично: 50-70%. Оставляет capital для неожиданных возможностей или для ловли собственных bookkeeping bugs бота.

Все три cap'а должны enforced внутри order-placement function, а не только в logic strategy. У strategy может быть bug; order-placement gate - это последняя линия защиты.

Daily loss kill switch

Самый важный отдельный risk control: daily-loss kill switch.

Правило: если realized + unrealized PnL с полуночи UTC опускается ниже -X% от starting daily balance, bot перестаёт открывать new positions и, optionally, закрывает existing ones. Типичное значение X: 5-10%.

Математика такая: у bot с expected win rate 60% есть, возможно, 5% chance серии из 10 подряд убыточных trades. Без kill switch эта серия накапливается: loss $200 → bot продолжает trading → ещё loss $200 → wallet down на 40%. Если switch срабатывает на -10%, плохой день ограничивается $200, а завтра bot начинает заново.

Switch enforced на server side: запишите halt file или установите database flag, который trading loop проверяет на каждой итерации. Перезапускать только после manual review.

Halt sentinels (file-based emergency stop)

Самый простой возможный halt mechanism: bot проверяет наличие file (например, /opt/pmt/HALT) на каждой итерации loop и останавливает trading, если file существует.

def trading_loop():
    while True:
        if os.path.exists("/opt/pmt/HALT"):
            log("HALT file detected, sleeping")
            time.sleep(30)
            continue
        run_one_iteration()
        time.sleep(5)

Чтобы немедленно остановить bot откуда угодно (SSH, Telegram bot, monitoring system): touch /opt/pmt/HALT. Чтобы возобновить: rm /opt/pmt/HALT.

Подход на базе file intentionally low-tech, потому что он работает в условиях, где более сложные halt mechanisms дают сбой: когда bot частично crashed, когда database недоступна, когда API key ограничен rate limit'ом. Доступ к file system почти всегда доступен.

Fill-rate watchdog

Strategy assumes, что FOK orders исполняются с некоторой rate (часто 60-80%). Когда rate заметно падает, что-то изменилось: market makers ушли, вашу strategy распознали, идёт API outage. Какой бы ни была причина, assumption, лежавшее в основе PnL math strategy, больше не работает.

Логика watchdog: rolling 24-hour count fill-rate. Если < 30% (или 50% от expected), alert + auto-halt. Возобновление - только после manual review.

Watchdog полезен и как diagnostic. Резкое падение fill-rate обычно связано с внешним событием (Polymarket deploy, congestion в Polygon, rate limit для вашего IP), о котором вы захотите узнать независимо от влияния на trading.

Reconcile diary vs on-chain on restart

Bot ведёт diary позиций, которые, по его мнению, он держит. Chain хранит truth. Они всегда должны совпадать; когда это не так, bot работает на неверном предположении и будет торговать неправильно.

Логика reconciliation: при каждом restart и раз в час во время normal operation получайте on-chain balances для каждого token, с которым bot работал. Сравнивайте с diary; alert + halt, если balance любого token отличается от diary больше, чем на tolerance для округления.

Самая частая причина divergence - успешный order, который API call бота не зафиксировал (timeout, retry не был записан). Chain содержит position; bot считает, что её нет. Без reconciliation bot не выставит take-profit exit, и position дойдёт до resolution.

Code: production-grade halt-aware loop

Reference: production trading loop, в который встроены все risk controls.

def production_loop():
    while True:
        # Halt checks
        if os.path.exists("/opt/pmt/HALT"):
            sleep_with_log(30); continue
        if daily_pnl_below_threshold():
            create_halt("daily PnL kill"); continue

        # Reconcile every hour
        if now() - last_reconcile > 3600:
            ok = reconcile_diary_vs_chain()
            last_reconcile = now()
            if not ok: create_halt("reconciliation failed"); continue

        # Fill-rate watchdog
        if recent_fill_rate() < 0.30:
            create_halt("fill rate collapse"); continue

        # Strategy
        try:
            run_strategy_once()
        except Exception as e:
            log_exception(e)
            if consecutive_exceptions >= 5:
                create_halt(f"exceptions: {e}"); continue
        time.sleep(5)

Паттерн такой: каждая итерация проходит через gate. Bugs strategy не могут обойти controls по конструкции.

Часто задаваемые вопросы

Что такое halt sentinel?
Это file (например, data/halt_autobuy), который bot проверяет перед каждым order. Если file существует, bot отказывается размещать orders, даже если strategy говорит обратное. Это позволяет остановить bot прямо во время инцидента одной командой touch. Мы добавили этот точный pattern в наш production trader после инцидента с wedged-fill в апреле 2026.
Какие position caps мне стоит выставить?
Per-market: 1-5% от bankroll. Per-strategy: 10-20%. Total open exposure: 50-70% от bankroll (оставляйте cash buffer). Ограничьте SINGLE order на уровне 1-2% от bankroll независимо от strategy - один order по ошибке не должен быть размером с весь account.
Как реализовать daily loss kill switch?
Отслеживайте realized + unrealized PnL по каждому UTC day. Если daily PnL опускается ниже -3 до -5% bankroll, установите halt sentinel и отправьте себе уведомление. Bot перестаёт размещать new orders; existing positions управляются вручную. Сброс - ежедневно в 00:00 UTC.
Что bot должен делать при restart после crash?
Три шага: (1) Сверить open orders через SDK с локальным diary. (2) Проверить open positions on-chain относительно локального state. (3) Если есть расхождение, остановить bot и потребовать manual review. Никогда не возобновляйте работу автоматически в inconsistent state.
Как не дать одному bug опустошить мой account?
Слоистые limits: cap на уровне code для position, cap на уровне code для order-size, halt sentinel на уровне file, implicit minimum/maximum на уровне exchange (Polymarket), monitoring alerts, которые page вас при необычной rate orders. Одного слоя недостаточно - они работают в комбинации.
Стоит ли bot торговать, если logging не работает?
Нет. Если bot не может писать в diary, он не сможет выполнить reconciliation при restart, а это значит, что crash приведёт к inconsistent state. При сбое logging bot должен hard-fail. Здоровые production bots параноидально относятся к собственной observability.