Туторіал ботів Полімаркет · Розділ 30 з 32

Код управління ризиками рівня продакшену для ботів Полімаркет: ліміти позицій, денні ліміти збитків, файли-сторожі зупинки, сторожі частоти виконання, звірка при перезапуску, ідемпотентні повтори. Патерни коду від реального трейдера в продакшені.

Що охоплює цей розділ

Код ризиків - це більша частина торгового бота в продакшені. Логіка стратегії - найлегша частина; саме ліміти, зупинки, сторожі й звірники навколо неї визначають, чи переживе бот свій перший невдалий тиждень. Цей розділ - патерн управління ризиками рівня продакшену.

  • Чому код ризиків - це більшість справжнього торгового бота
  • Ліміти позицій (на ринок, на стратегію, загальний)
  • Аварійний вимикач за денним збитком
  • Файли-сторожі зупинки (аварійна зупинка на основі файлу)
  • Сторож частоти виконання
  • Звірка журналу з ончейном при перезапуску
  • Код: цикл рівня продакшену з урахуванням зупинок

Чому код ризиків - це більшість справжнього торгового бота

Один із показників, який ми виміряли у власній кодовій базі бота: 60% рядків коду - це код ризиків (ліміти, зупинки, сторожі, звірка). 30% - стратегія. 10% - «клей».

Це правильне співвідношення. Стратегія - найлегша частина: опис того, коли входити і коли виходити, уміщується в кілька десятків рядків. Код ризиків - це все інше: що робити, коли ціна рухається проти вас швидше, ніж очікувалося, що робити, коли виконання перестають проходити, що робити, коли WebSocket обривається, що робити, коли стратегія виявляється збитковою.

У більшості історій провалу будівельників ботів спільний сюжет один: стратегія працювала, але бот продовжував торгувати після зміни режиму, тому що жодна зупинка не спрацювала. Пишіть зупинки раніше, ніж стратегію.

Ліміти позицій (на ринок, на стратегію, загальний)

Три ліміти, які мають бути примусово задані в коді.

  • Ліміт на ринок: максимум $X на один ринок незалежно від упевненості в перевазі. Типово: $25-100 для малих ботів, $200-500 для продакшену. Обмежує радіус ураження однієї неправильної ставки на окремий ринок.
  • Ліміт на стратегію: якщо ви запускаєте кілька стратегій, кожна отримує свою частку загального капіталу. Типово: 30-50% на одну стратегію. Захищає капітал інших стратегій від поганого дня однієї з них.
  • Загальний ліміт: максимальний % від балансу гаманця, який може бути задіяний одночасно. Типово: 50-70%. Залишає капітал для неочікуваних можливостей або щоб зловити власні баги обліку бота.

Усі три ліміти слід примусово задавати всередині функції виставлення ордера, а не лише в логіці стратегії. У стратегії може бути баг; шлюз виставлення ордера - це остання лінія захисту.

Аварійний вимикач за денним збитком

Найважливіший окремий контроль ризику: аварійний вимикач за денним збитком.

Правило: якщо реалізований + нереалізований фінрезультат від опівночі UTC падає нижче -X% від початкового денного балансу, бот припиняє відкривати нові позиції і (за бажанням) закриває наявні. Типове X: 5-10%.

Математика: бот із 60% очікуваним відсотком виграшів має, можливо, 5% шанс на серію програшів із 10 угод. Без аварійного вимикача ця серія наростає: $200 збитку → бот продовжує торгувати → ще $200 збитку → гаманець просідає на 40%. Якщо вимикач спрацьовує на -10%, поганий день обмежується $200, а завтра бот починає з нуля.

Задавайте вимикач на сервері: створіть файл зупинки або встановіть прапорець у базі даних, який торговий цикл перевіряє на кожній ітерації. Перезапускайте лише після ручної перевірки.

Файли-сторожі зупинки (аварійна зупинка на основі файлу)

Найпростіший можливий механізм зупинки: бот перевіряє наявність файлу (наприклад, /opt/pmt/HALT) на кожній ітерації циклу і зупиняє торгівлю, якщо файл існує.

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)

Щоб негайно зупинити бота звідки завгодно (SSH, бот у Telegram, система моніторингу): touch /opt/pmt/HALT. Щоб відновити роботу: rm /opt/pmt/HALT.

Підхід на основі файлу навмисно простий, бо він працює в умовах, коли складніші механізми зупинки падають: коли бот частково впав, коли база даних недоступна, коли ключ API отримав ліміт частоти. Доступ до файлової системи є завжди.

Сторож частоти виконання

Стратегія припускає, що ордери FOK заповнюються з певною частотою (часто 60-80%). Коли частота помітно падає, щось змінилося: маркетмейкери пішли, вашу стратегію ідентифікували, триває збій API. Якою б не була причина, припущення, на якому будувалася математика фінрезультату стратегії, зламане.

Логіка сторожа: ковзний 24-годинний підрахунок частоти виконання. Якщо < 30% (або 50% від очікуваного), сповіщення + автозупинка. Відновлення лише після ручної перевірки.

Сторож також корисний як діагностика. Раптове падіння частоти виконання зазвичай корелює із зовнішньою подією (розгортання Полімаркет, перевантаження Polygon, ваш IP отримав ліміт частоти), про яку вам варто знати незалежно від впливу на торгівлю.

Звірка журналу з ончейном при перезапуску

Бот веде журнал позицій, які, на його думку, він тримає. Чейн зберігає істину. Вони мають завжди збігатися; коли це не так, бот працює на хибному припущенні й торгує неправильно.

Логіка звірки: на кожному перезапуску і раз на годину під час нормальної роботи отримуйте ончейн-баланси для кожного токена, якого бот торкався. Порівнюйте з журналом; сповіщення + зупинка, якщо баланс будь-якого токена відрізняється від журналу більше, ніж допускає допуск округлення.

Найпоширеніша причина розбіжності - успішний ордер, який виклик API бота пропустив (тайм-аут, повтор так і не записано). Чейн має позицію; бот думає, що не має. Без звірки бот не виставить вихід із тейк-профітом, і позиція дійде до врегулювання.

Код: цикл рівня продакшену з урахуванням зупинок

Приклад: торговий цикл продакшену з усіма контролями ризику, підключеними належним чином.

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)

Патерн такий: кожна ітерація проходить через шлюз. Баги стратегії не можуть обійти контролі за самою конструкцією.

Поширені запитання

Що таке файл-сторож зупинки?
Файл (наприклад, data/halt_autobuy), який бот перевіряє перед кожним ордером. Якщо файл існує, бот відмовляється виставляти ордери, навіть якщо стратегія цього вимагає. Це дає змогу зупинити бота посеред інциденту однією командою touch. Ми додали саме цей патерн до нашого трейдера в продакшені після інциденту із заклиненим виконанням у квітні 2026 року.
Які ліміти позицій встановити?
На ринок: 1-5% від банкролу. На стратегію: 10-20%. Загальна відкрита експозиція: 50-70% від банкролу (тримайте грошовий буфер). Обмежуйте ОДИН ордер до 1-2% від банкролу незалежно від стратегії - один помилковий ордер ніколи не має дорівнювати розміру рахунку.
Як реалізувати аварійний вимикач за денним збитком?
Відстежуйте реалізований + нереалізований фінрезультат за добу UTC. Якщо денний фінрезультат падає нижче -3 до -5% від банкролу, встановіть файл-сторож зупинки й сповістіть себе. Бот припиняє нові ордери; наявні позиції керуються вручну. Скидання щодня о 00:00 UTC.
Що бот має робити при перезапуску після збою?
Три кроки: (1) Звірте відкриті ордери через SDK з вашим локальним журналом. (2) Перевірте відкриті позиції ончейн проти вашого локального стану. (3) Якщо щось розходиться, зупиніть бота й вимагайте ручної перевірки. Ніколи не відновлюйте роботу автоматично в неузгодженому стані.
Як запобігти тому, щоб один баг спорожнив мій рахунок?
Багатошарові ліміти: ліміт позиції на рівні коду, ліміт розміру ордера на рівні коду, файл-сторож зупинки на рівні файлів, неявний мінімум/максимум на рівні біржі (Полімаркет), сповіщення моніторингу, що будять вас за незвичної частоти ордерів. Жоден окремий шар не є достатнім - вони перемножуються.
Чи має бот торгувати, якщо моє логування падає?
Ні. Якщо бот не може писати у свій журнал, він не може звіритися при перезапуску, а отже, збій призводить до неузгодженого стану. Жорстко зупиняйте бота, якщо логування падає. Здорові боти в продакшені параноїдально ставляться до власної спостережуваності.