Polymarket Bot Tutorial · Rozdział 30 z 32
Kod zarządzania ryzykiem klasy production-grade dla Polymarket bots: position caps, daily loss limits, halt sentinels, fill-rate watchdogs, reconcile-on-restart, idempotent retries. Wzorce kodu od prawdziwego tradera produkcyjnego.
Co obejmuje ten rozdział
Kod ryzyka to większość production trading bot. Logika strategy jest łatwa; to otaczające ją limity, zatrzymania, watchdogs i reconcilers decydują o tym, czy bot przetrwa swój pierwszy zły tydzień. Ten rozdział to wzorzec risk code klasy production-grade.
To jest rozdział 30 z naszej 32-częściowej serii o budowie Polymarket trading bot. Omawiamy temat szczegółowo w sekcjach poniżej. Treści główne dla każdej sekcji są pisane i publikowane rozdział po rozdziale; odpowiedzi FAQ i references są już kompletne i odzwierciedlają production experience z prowadzenia własnego tradera.
- Dlaczego risk code to większość prawdziwego 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
Dlaczego risk code to większość prawdziwego trading bot
Pewien pomiar, który wykonaliśmy na własnym codebase bota: 60% LOC to risk code (caps, halts, watchdogs, reconciliation). 30% to strategy. 10% to glue.
Ten rozkład jest prawidłowy. Strategy to łatwa część — opisanie, kiedy wejść i kiedy wyjść, mieści się w kilku dziesiątkach linii. Risk code to wszystko inne: co zrobić, gdy price porusza się przeciwko tobie szybciej niż oczekiwano, co zrobić, gdy fills przestają wpadać, co zrobić, gdy WebSocket się rozłącza, co zrobić, gdy strategy okazuje się nieopłacalna.
Większość historii porażek builderów ma ten sam kształt: strategy działała, ale bot nadal handlował po zmianie regime, bo nie zadziałał żaden halt. Najpierw napisz halts, dopiero potem strategy.
Position caps (per-market, per-strategy, total)
Trzy caps, egzekwowane w kodzie.
- Per-market cap: maks. $X na jeden market, niezależnie od confidence edge. Typowo: $25-100 dla małych botów, $200-500 dla production. Ogranicza zasięg rażenia jednej błędnej decyzji na pojedynczym market.
- Per-strategy cap: jeśli uruchamiasz kilka strategy, każda dostaje część całego capital. Typowo: 30-50% na jedną strategy. Zapobiega sytuacji, w której zły dzień jednej strategy zużywa capital pozostałych.
- Total cap: maks. % balance wallet deployed jednocześnie. Typowo: 50-70%. Zostawia capital na nieoczekiwane okazje albo na wychwycenie własnych błędów bookkeeping bota.
Wszystkie trzy caps powinny być egzekwowane wewnątrz funkcji order-placement, a nie tylko w logice strategy. Strategy może mieć bug; gate order-placement to ostatnia linia obrony.
Daily loss kill switch
Najważniejsza pojedyncza kontrola ryzyka: daily-loss kill switch.
Zasada: jeśli realized + unrealized PnL od północy UTC spadnie poniżej -X% początkowego daily balance, bot przestaje otwierać nowe positions i opcjonalnie zamyka istniejące. Typowe X: 5-10%.
Matematyka: bot z oczekiwanym win rate 60% ma być może 5% szansy na losing streak z 10 trade'ów. Bez kill switch taki streak się kumuluje: strata $200 → bot dalej handluje → kolejna strata $200 → wallet w dół o 40%. Z przełącznikiem uruchamianym przy -10% zły dzień kończy się na $200 straty, a jutro bot zaczyna od nowa.
Przełącznik jest egzekwowany po stronie serwera: zapisz plik halt albo ustaw flagę w database, którą trading loop sprawdza przy każdej iteracji. Restart tylko po manual review.
Halt sentinels (file-based emergency stop)
Najprostszy możliwy mechanizm halt: bot sprawdza plik (np. /opt/pmt/HALT) przy każdej iteracji pętli i zatrzymuje trading, jeśli plik istnieje.
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)
Aby natychmiast zatrzymać bot z dowolnego miejsca (SSH, Telegram bot, monitoring system): touch /opt/pmt/HALT. Aby wznowić: rm /opt/pmt/HALT.
Podejście file-based jest celowo low-tech, ponieważ działa w warunkach, w których bardziej zaawansowane mechanizmy halt zawodzą: gdy bot jest częściowo crashed, gdy database jest niedostępna, gdy API key ma rate limit. Dostęp do file system jest zawsze dostępny.
Fill-rate watchdog
Strategy zakłada, że ordery FOK fillują się z pewnym rate (często 60-80%). Gdy rate spada znacząco, coś się zmieniło: market makers wycofali się, twoja strategy została zidentyfikowana, trwa outage API. Niezależnie od powodu założenie, które napędzało matematykę PnL strategy, jest już błędne.
Logika watchdog: rolling 24-hour fill-rate count. Jeśli < 30% (lub 50% oczekiwanego), alert + auto-halt. Wznowienie tylko po manual review.
Watchdog jest też przydatny diagnostycznie. Nagły spadek fill-rate zwykle koreluje z wydarzeniem zewnętrznym (Polymarket deploy, congestion Polygon, rate limiting twojego IP), o którym i tak chciałbyś wiedzieć niezależnie od wpływu na trading.
Reconcile diary vs on-chain on restart
Bot utrzymuje diary pozycji, które uważa, że posiada. Chain utrzymuje prawdę. Te dwa źródła powinny zawsze się zgadzać; gdy tak nie jest, bot działa na błędnym założeniu i będzie handlował nieprawidłowo.
Logika reconciliation: przy każdym restarcie i raz na godzinę podczas normalnej pracy pobierz on-chain balances dla każdego tokena, którego bot dotknął. Porównaj z diary; alert + halt, jeśli saldo któregokolwiek tokena różni się od diary o więcej niż rounding tolerance.
Najczęstszą przyczyną rozjazdu jest udany order, którego nie odnotował API call bota (timeout, retry nigdy nie został zapisany). Chain ma pozycję; bot uważa, że jej nie ma. Bez reconciliation bot nie wystawi take-profit exit i pozycja dojedzie do resolution.
Code: production-grade halt-aware loop
Reference: production trading loop ze wszystkimi wpiętymi kontrolami ryzyka.
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)
Wzorzec jest prosty: każda iteracja przechodzi przez gate. Bugs strategy nie mogą ominąć kontroli, z definicji.











