Polymarket Bot Tutorial · Capitolo 30 di 32

Codice di risk management di livello production per Polymarket bot: position cap, daily loss limit, halt sentinel, fill-rate watchdog, reconcile-on-restart, retry idempotenti. Pattern di codice da un vero trader in produzione.

Cosa copre questo capitolo

Il codice di risk è la maggior parte di un production trading bot. La logica di strategy è la parte facile; i cap, gli halt, i watchdog e i reconciler che la circondano sono ciò che determina se il bot sopravvive alla sua prima settimana negativa. Questo capitolo è il pattern di risk di livello production.

Questo è il capitolo 30 della nostra serie in 32 parti su come costruire un Polymarket trading bot. Trattiamo l’argomento in profondità nelle sezioni qui sotto. Il body content di ogni sezione viene scritto e pubblicato capitolo per capitolo; le risposte della FAQ e i riferimenti sono già completi e riflettono l’esperienza production maturata gestendo il nostro trader.

  • Perché il codice di risk è la parte più importante di un vero trading bot
  • Position cap (per-market, per-strategy, total)
  • Daily loss kill switch
  • Halt sentinel (emergency stop basato su file)
  • Fill-rate watchdog
  • Reconcile diary vs on-chain al riavvio
  • Codice: production-grade loop con awareness degli halt

Perché il codice di risk è la parte più importante di un vero trading bot

Una misurazione che abbiamo fatto sul codebase del nostro bot: il 60% delle LOC è risk code (cap, halt, watchdog, reconciliation). Il 30% è strategy. Il 10% è glue.

Quel rapporto è corretto. La strategy è la parte facile — descrivere quando entrare e quando uscire sta in poche decine di righe. Il risk code è tutto il resto: cosa fare quando il prezzo si muove contro di te più velocemente del previsto, cosa fare quando i fill smettono di arrivare, cosa fare quando il WebSocket cade, cosa fare quando la strategy si rivela non profittevole.

Le storie di fallimento dei builder hanno quasi sempre la stessa forma: la strategy funzionava, ma il bot ha continuato a tradare durante un regime change perché non è scattato nessun halt. Scrivi gli halt prima di scrivere la strategy.

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

Tre cap, applicati nel codice.

  • Per-market cap: massimo $X per market indipendentemente dalla confidence dell’edge. Tipico: $25-100 per bot piccoli, $200-500 per production. Limita il blast radius di una singola chiamata errata su un market.
  • Per-strategy cap: se esegui più strategy, ciascuna riceve una quota del capitale totale. Tipico: 30-50% per strategy. Impedisce che una giornata storta di una strategy consumi il capitale delle altre.
  • Total cap: massima % del saldo wallet deployata simultaneamente. Tipico: 50-70%. Lascia capitale per opportunità inattese o per intercettare i bug di bookkeeping del bot stesso.

Tutti e tre i cap devono essere applicati dentro la funzione di order placement, non solo nella logica della strategy. La strategy può avere un bug; il gate di order placement è l’ultima linea di difesa.

Daily loss kill switch

Il singolo controllo di risk più importante: un daily-loss kill switch.

Regola: se il realized + unrealized PnL da mezzanotte UTC scende sotto -X% del daily balance iniziale, il bot smette di aprire nuove position e, opzionalmente, chiude quelle esistenti. X tipico: 5-10%.

La matematica: un bot con expected win rate del 60% ha forse una probabilità del 5% di una losing streak di 10 trade. Senza kill switch, quella streak si compone: perdita di $200 → il bot continua a tradare → un’altra perdita di $200 → wallet a -40%. Con lo switch che scatta a -10%, la giornata negativa si ferma a $200, e domani il bot riparte da zero.

Lo switch viene applicato lato server: scrivi un file di halt o imposta un flag in database che il trading loop controlla a ogni iterazione. Riavvia solo dopo una manual review.

Halt sentinel (emergency stop basato su file)

Il meccanismo di halt più semplice possibile: il bot controlla la presenza di un file (per esempio /opt/pmt/HALT) a ogni iterazione del loop e smette di tradare se il file esiste.

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)

Per fermare immediatamente da qualsiasi punto (SSH, Telegram bot, monitoring system): touch /opt/pmt/HALT. Per riprendere: rm /opt/pmt/HALT.

L’approccio basato su file è volutamente low-tech perché funziona in condizioni in cui meccanismi di halt più sofisticati falliscono: quando il bot è parzialmente crashato, quando il database non è raggiungibile, quando la API key è soggetta a rate limit. L’accesso al filesystem è sempre disponibile.

Fill-rate watchdog

La strategy assume che gli ordini FOK vengano filled a un certo rate (spesso 60-80%). Quando il rate scende in modo significativo, qualcosa è cambiato: i market maker si sono ritirati, la tua strategy è stata identificata, c’è un outage della API in corso. Qualunque sia il motivo, l’assunzione che guidava la matematica del PnL della strategy è rotta.

Logica del watchdog: conteggio rolling del fill-rate nelle ultime 24 ore. Se < 30% (o 50% dell’atteso), alert + auto-halt. Riprendi solo dopo una manual review.

Il watchdog è utile anche come diagnostica. Un calo improvviso del fill-rate di solito è correlato a un evento esterno (deploy di Polymarket, congestione di Polygon, il tuo IP che viene rate-limited) che vorresti comunque conoscere, indipendentemente dall’impatto sul trading.

Reconcile diary vs on-chain al riavvio

Il bot mantiene un diary delle position che pensa di detenere. La chain mantiene la verità. Dovrebbero sempre coincidere; quando non coincidono, il bot sta operando con una convinzione errata e tradarà in modo sbagliato.

Logica di reconciliation: a ogni riavvio e una volta all’ora durante il normale funzionamento, recupera i saldi on-chain per ogni token che il bot ha toccato. Confrontali con il diary; alert + halt se il balance di un token differisce dal diary oltre la tolleranza di rounding.

La causa più comune della divergenza è un ordine riuscito che la chiamata API del bot si è persa (timeout, retry mai registrato). La chain ha la position; il bot pensa di no. Senza reconciliation, il bot non pubblicherà l’uscita take-profit e la position andrà fino alla resolution.

Codice: production-grade loop con awareness degli halt

Reference: il trading loop production con tutti i controlli di risk collegati.

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)

Il pattern: ogni iterazione passa attraverso il gate. I bug della strategy non possono bypassare i controlli, per costruzione.

Domande frequenti

Che cos’è un halt sentinel?
Un file (per esempio, data/halt_autobuy) che il bot controlla prima di ogni ordine. Se il file esiste, il bot rifiuta di piazzare ordini anche se la strategy lo richiede. Ti permette di fermare il bot nel mezzo di un incidente con un semplice comando touch. Abbiamo aggiunto esattamente questo pattern al nostro trader production dopo un incidente di wedged-fill nell’aprile 2026.
Che position cap dovrei impostare?
Per-market: 1-5% del bankroll. Per-strategy: 10-20%. Esposizione aperta totale: 50-70% del bankroll (mantieni un cash buffer). Limita un SINGOLO ordine all’1-2% del bankroll indipendentemente dalla strategy - un ordine piazzato per errore non dovrebbe mai avere dimensione da account.
Come implemento un daily loss kill switch?
Traccia il realized + unrealized PnL per giorno UTC. Se il daily PnL scende sotto -3% o -5% del bankroll, imposta il halt sentinel e inviati una notifica. Il bot smette di inviare nuovi ordini; le position esistenti vengono gestite manualmente. Reset ogni giorno alle 00:00 UTC.
Cosa dovrebbe fare il bot al riavvio dopo un crash?
Tre passaggi: (1) Reconcile degli open order tramite SDK rispetto al tuo diary locale. (2) Controllo delle open position on-chain rispetto allo stato locale. (3) Se qualcosa diverge, halt del bot e manual review obbligatoria. Non riprendere mai automaticamente in uno stato inconsistente.
Come evito che un singolo bug svuoti il mio account?
Limiti a più livelli: position cap a livello di codice, order-size cap a livello di codice, halt sentinel a livello di file, minimo/massimo implicito a livello di exchange (Polymarket), alert di monitoring che ti segnalano order rate insoliti. Nessun singolo livello è sufficiente - si moltiplicano.
Il bot dovrebbe tradare se il logging fallisce?
No. Se il bot non può scrivere nel proprio diary, non può fare reconciliation al riavvio, il che significa che un crash porta a uno stato inconsistente. Fai hard-fail del bot se il logging fallisce. I bot production sani sono paranoici riguardo alla propria observability.