Tutti gli articoli
GuideBot di tradingAPI di PolymarketPython

Come costruire un bot di trading per Polymarket

La maggior parte dei tutorial sui bot per Polymarket si basa su SDK che non esistono più. Questo è il percorso attuale dall’inizio alla fine: cosa installare nel 2026, come funziona davvero l’autenticazione, dove sono i buchi nei dati e i problemi che uccidono i bot nella prima settimana.

14 min di lettura

La maggior parte dei tutorial sui bot per Polymarket è superata

Polymarket è passata a SDK unificati: polymarket-client per Python e @polymarket/client per TypeScript. Sostituiscono py-clob-client, @polymarket/clob-client-v2, @polymarket/builder-relayer-client e @polymarket/builder-signing-sdk. Se una guida ti dice di eseguire pip install py-clob-client, o se il tuo assistente AI genera quell’import, sta lavorando su materiale vecchio. Tutto ciò che segue usa i pacchetti attuali.

Un bot per Polymarket è fatto di sei pezzi: trovare i mercati, leggere i prezzi, decidere, piazzare ordini, gestire le posizioni e restare in vita. I primi due sono facili, il quarto è macchinoso e il sesto è dove la maggior parte dei bot muore davvero. Questa guida percorre l’intero arco con codice verificato, ed è onesta sulle parti davvero difficili.

Passo 0: decidi su cosa opera il tuo bot

Vale la pena farlo prima di scrivere una sola riga, perché determina tutto il resto. I mercati di Polymarket si dividono in due famiglie che non hanno quasi nulla in comune:

Mercati su eventiMercati crypto Up/Down
EsempiElezioni, sport, premibtc-updown-5m, eth-updown-15m
DurataDa settimane a mesiDa 5 minuti a 24 ore
Cosa muove il prezzoNotizie, informazioni, sentimentMicrostruttura e flusso degli ordini
Il vantaggio viene daEssere meglio informatiEssere più veloci o prezzare meglio
Operazioni al giornoUna manciataCentinaia
Sensibilità alla latenzaBassaAlta

Se stai automatizzando, quasi certamente ti interessa la seconda famiglia: alta frequenza, continua e abbastanza meccanica da poter essere codificata. Sono trattati in dettaglio in i mercati Up/Down spiegati.

Passo 1: installa l’SDK attuale

Entrambi gli SDK ti danno un’unica interfaccia client su tutte le API di Polymarket, modelli tipizzati, paginazione coerente e firma integrata: una grande quantità di lavoro macchinoso che non vuoi reimplementare.

pip install polymarket-client
# or: uv add polymarket-client / poetry add polymarket-client

Ci sono quattro client Python, e scegliere quello giusto conta più di quanto sembri:

ClientDati pubbliciTradingTempo reale
AsyncPublicClientSìNoSì
AsyncSecureClientSìSìSì
PublicClientSìNoNo
SecureClientSìSìNo
Le sottoscrizioni in tempo reale sono solo async: i client sincroni non implementano subscribe(). Ai bot servono le varianti async; quelle sincrone sono per script e notebook.

Inizia con il client pubblico

Puoi costruire e testare la scoperta dei mercati, la lettura dei prezzi, la generazione dei segnali e l’intera pipeline di dati con AsyncPublicClient: niente chiavi, niente wallet, nessun rischio. Passa ad AsyncSecureClient solo quando sei pronto a piazzare un ordine. La maggior parte dei bug emerge molto prima.

Passo 2: trova i mercati

La scoperta dei mercati pubblici non richiede alcuna credenziale. Il paginatore dell’SDK è coerente su tutti i metodi di elenco, quindi questo schema vale in generale.

import asyncio
from polymarket import AsyncPublicClient


async def main() -> None:
    async with AsyncPublicClient() as client:
        pages = client.list_markets(closed=False, page_size=50)

        # Iterate items directly when page boundaries do not matter.
        async for market in pages.iter_items():
            if "updown" in (market.slug or ""):
                print(market.slug, market.condition_id)


asyncio.run(main())

Due cose da tenere a mente. Primo, page.next_cursor è un cursore opaco: salvalo così com’è se vuoi riprendere una scansione in seguito, e non provare ad analizzarlo o a costruirne uno. Secondo, /markets ha il rate limit più stretto di tutta la piattaforma, 300 req / 10s, quindi metti in cache i metadati dei mercati invece di rielencarli in un ciclo stretto. Tutti i numeri sono nel riferimento ai rate limit.

Passo 3: autenticati

Per fare trading serve un wallet. L’SDK Python costruisce il signer a partire da una chiave privata locale:

import os
from polymarket import AsyncSecureClient

client = await AsyncSecureClient.create(
    private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
    wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
)

Sotto il cofano, Polymarket usa due livelli di autenticazione: L1 è una firma del wallet EIP-712 che dimostra che controlli l’indirizzo e ti permette di creare o derivare le credenziali API; L2 firma ogni richiesta privata con quelle credenziali usando HMAC-SHA256. L’SDK gestisce entrambi, ed è il motivo principale per usarlo.

I due errori di autenticazione che incontrerai

Credenziali incomplete: L2 richiede la chiave, il secret e la passphrase. Due su tre producono una richiesta ben formata con una firma non verificabile. Deriva dell’orologio: la firma contiene un timestamp, quindi un container con l’orologio sballato di qualche secondo viene respinto. Entrambi si presentano con lo stesso poco utile Unauthorized/Invalid api key. La decodifica completa è nel riferimento agli errori.

Gestione della chiave

Quella chiave privata può spostare fondi. Tienila in variabili d’ambiente o in un secret manager: mai nel codice sorgente, mai in un’immagine container, mai nel repo che stai per pushare. Usa un wallet dedicato, finanziato solo con quanto il bot può permettersi di perdere, così un bug è limitato dal saldo e non dal tuo giudizio alle 3 di notte.

Passo 4: ottieni i prezzi in tempo reale

L’errore architetturale più comune in un primo bot è fare polling di /book a intervalli regolari. Consuma il tuo budget di rate limit, aggiunge latenza e scala male. Usa invece le sottoscrizioni: l’SDK unisce più feed in un unico stream di eventi.

from polymarket.streams import MarketSpec

async with await client.subscribe([MarketSpec(token_ids=[token_id])]) as stream:
    async for event in stream:
        # MarketBookEvent | MarketPriceChangeEvent | MarketLastTradePriceEvent
        # | MarketTickSizeChangeEvent | MarketBestBidAskEvent
        # | NewMarketEvent | MarketResolvedEvent
        handle(event)

Se ti connetti al WebSocket grezzo invece di usare l’SDK, devi inviare un PING ogni 10 secondi o la connessione viene chiusa, e ti serve custom_feature_enabled: true per ricevere gli eventi best_bid_ask, new_market e market_resolved. Questi aspetti e gli schemi di riconnessione sono trattati nella guida ai WebSocket. A parte questo, i prezzi di riferimento sono passati a PolyBolt il 15 settembre 2026: se il tuo bot riceve lo spot in streaming, vedi la guida alla migrazione.

Passo 5: piazza un ordine

Un ordine a mercato è la cosa più semplice che funzioni, e amount è espresso in pUSD che sei disposto a spendere, non in quote:

market = await client.get_market(slug="<market-slug>")
token_id = market.outcomes.yes.token_id
assert token_id is not None

response = await client.place_market_order(
    token_id=token_id,
    side="BUY",
    amount="10",          # spend up to 10 pUSD
)

if not response.ok:
    raise RuntimeError(response.message)

# Settlement is on-chain and asynchronous — this waits for it.
hashes = await client.wait_for_order_fill_settlement(response)

Per gli ordini limite in attesa, ci sono due regole che ti morderanno prima di qualsiasi altra cosa. I prezzi devono stare sulla griglia dei tick del mercato: chiama GET /tick-size per ogni mercato invece di dare per scontato 0.01, perché la dimensione del tick varia e può restringersi man mano che un mercato matura. E gli ordini sotto la size minima del mercato vengono respinti subito. Entrambi tornano come 400 con messaggi specifici, elencati nel riferimento agli errori.

Un 200 su un batch non significa successo

Quando invii più ordini, gli errori dei singoli ordini vengono restituiti dentro l’array della risposta 200, come campi errorMsg individuali. Itera l’array e controlla ogni voce. I bot che controllano solo lo stato HTTP credono in silenzio di avere posizioni che non hanno: una classe di bug davvero pericolosa.

Passo 6: scopri se la strategia funziona

Tutto ciò che c’è sopra è idraulica, e l’idraulica è la metà facile. La domanda difficile è se la tua strategia fa soldi, ed è qui che costruire un bot per Polymarket si separa nettamente dal costruire un bot per il crypto spot.

Non esiste una testnet. Niente sandbox, niente API demo, niente endpoint di paper trading. Queste parole non compaiono da nessuna parte nella documentazione di Polymarket. Il tuo primo ordine reale è fatto con soldi veri contro controparti reali. Vedi Polymarket ha una testnet? per i quattro modi di aggirare il problema.

E non esiste un order book storico. Una volta che un mercato si risolve, il suo book restituisce 404. Conserva una serie di prezzi di circa un punto al minuto, e solo se la chiedi con un inizio e una fine espliciti:

TOK=<token_id_of_a_resolved_market>
START=<epoch seconds the window opened>
END=$((START + 300))

curl -s "https://clob.polymarket.com/book?token_id=$TOK"
# {"error":"No orderbook exists for the requested token id"}   HTTP 404

curl -s "https://clob.polymarket.com/prices-history?market=$TOK&startTs=$START&endTs=$END&fidelity=1"
# about 6 points for a 5-minute market; interval=max returns [] for older ones

Quindi non puoi fare backtest partendo da Polymarket. Ti servono snapshot point-in-time che qualcuno ha registrato mentre i mercati erano attivi. È quello che PolyTest fornisce per i mercati crypto Up/Down: 240M+ snapshot, 8 livelli di profondità del book per lato, timestamp sotto il secondo, mercati risolti conservati:

import os, requests

BASE = "https://api.polytest.io/api/v1"
H = {"X-API-Key": os.environ["POLYTEST_KEY"]}

markets = requests.get(f"{BASE}/markets",
                       params={"coin": "btc", "market_type": "5m", "limit": 50},
                       headers=H).json()["markets"]

snaps = requests.get(f"{BASE}/markets/{markets[0]['id']}/snapshots",
                     params={"include_orderbook": "true"},
                     headers=H).json()["snapshots"]


def simulate_fill(levels, qty):
    """Walk the ladder. Mid-price is not a price you can trade at."""
    filled = cost = 0.0
    for lvl in levels:
        take = min(lvl["size"], qty - filled)
        cost += take * lvl["price"]
        filled += take
        if filled >= qty:
            break
    return cost / filled if filled >= qty else None


print(simulate_fill(snaps[0]["orderbook"]["asks"], 500))

L’errore che rende inutile un backtest

Se fai backtest sul prezzo medio stai testando un’identità aritmetica, non una strategia. Gli spread Up/Down sono regolarmente di 2–5 centesimi su un contratto che si regola a $1, spesso più ampi del vantaggio dichiarato. Scorri il book e prendi l’esecuzione che avresti davvero ottenuto. Questo solo cambiamento uccide la maggior parte delle strategie, ed è esattamente ciò che vuoi che faccia, a basso costo, prima di finanziarle.

Passo 7: sopravvivi al contatto con la produzione

Un bot che opera correttamente per un’ora e poi si blocca è peggio di nessun bot. Questi sono i problemi che si verificano davvero, in ordine approssimativo di frequenza:

ProblemaCosa vediGestione
Rate limitLatenza in aumento, non erroriCloudflare rallenta invece di rifiutare: tieni d’occhio il p99, non il tasso di errore
Riavvio del motore di matching425 Too EarlyRiprova con backoff; non generare alert sui casi singoli
Exchange in pausa503Smetti di aprire posizioni. Cancella se consentito
Modalità cancel-only503 sui nuovi ordiniIl percorso di cancellazione deve funzionare indipendentemente da quello di ingresso
Modalità post-only503 + retry_after_secondsAspetta esattamente quel tempo, poi riprova
Signer non corrispondenteErrore 400 sul signer dell’ordineCredenziali vecchie di un altro wallet: derivale di nuovo
Caduta del WebSocketSilenzioNessun dato non equivale a nessun cambiamento: tieni traccia dell’età dell’ultimo messaggio
Deriva dell’orologio401 su un bot che ieri funzionavaUsa NTP; è il problema che fa perdere più tempo

Il silenzio è lo stato pericoloso

Un WebSocket caduto non genera un’eccezione: smette semplicemente di consegnare messaggi. Un bot che ha una posizione aperta e non riceve aggiornamenti crederà tranquillamente che il mercato sia fermo all’ultimo prezzo visto. Tieni traccia dell’età dell’ultimo messaggio e tratta i dati vecchi come una condizione di errore, non come calma.

  • Testa il percorso di cancellazione prima di quello di ingresso. Non riuscire a uscire è molto peggio che non riuscire a entrare.
  • Limita l’esposizione nel codice, non nella tua testa. Un limite rigido di posizione trasforma un bug logico in una piccola perdita invece che in una perdita illimitata.
  • Costruisci un kill switch e testalo davvero. Un kill switch non testato è un commento.
  • Aggiungi jitter al lavoro schedulato. Worker che si svegliano esattamente allo stesso secondo creano un picco sincronizzato molto sopra la tua frequenza media.
  • Registra ogni richiesta e risposta per la prima settimana. Ti serviranno, e non potrai ricostruirle dopo.
  • Genera alert per categorie, non per messaggi. Polymarket inserisce ID degli ordini e prezzi nelle stringhe di errore, quindi gli alert sulla stringa grezza sono puro rumore.

Un ordine di sviluppo realistico

La sequenza che fa perdere meno tempo e soldi:

  1. Integrazione in sola lettura, client pubblico, niente chiavi. Verifica scoperta dei mercati, parsing, paginazione e backoff. Un giorno, gratis.
  2. Backtest della strategia su book storici con una simulazione onesta delle esecuzioni. La maggior parte delle idee muore qui. È proprio questo lo scopo.
  3. Paper trading live per almeno una settimana: registra gli ordini previsti invece di inviarli. Verifica uptime, riconnessioni e tempistiche.
  4. Vai live con la size minima, con un limite rigido all’esposizione e un kill switch testato.
  5. Aumenta le dimensioni solo quando i numeri live corrispondono a quelli su carta. Se divergono, il tuo modello di esecuzione era sbagliato: torna al passo 2.

I passi 1, 3 e 4 li costruisci in pochi giorni. Il passo 2 richiede dati che Polymarket non conserva, ed è anche il passo che più sicuramente fa risparmiare soldi. Inizia una prova gratuita su PolyTest: basta per scoprire se la tua idea sopravvive allo spread.

Domande frequenti

Come costruisco un bot di trading per Polymarket?
Installa l’SDK unificato attuale: polymarket-client per Python o @polymarket/client per TypeScript. Usa AsyncPublicClient per trovare i mercati e leggere i prezzi senza credenziali, poi AsyncSecureClient con una chiave privata per fare trading. Iscriviti al canale market del WebSocket invece di fare polling dei prezzi, piazza gli ordini con place_market_order e gestisci le risposte 425, 429 e 503 con un backoff. Prima di andare live, fai backtest su snapshot storici dell’order book con una simulazione realistica delle esecuzioni, perché Polymarket non ha una testnet e non conserva lo storico dell’order book.
Quale SDK dovrei usare per un bot per Polymarket nel 2026?
Usa gli SDK unificati: polymarket-client per Python o @polymarket/client per TypeScript. Sostituiscono i vecchi pacchetti py-clob-client, @polymarket/clob-client-v2, @polymarket/builder-relayer-client e @polymarket/builder-signing-sdk. Un SDK Rust unificato è in sviluppo. La maggior parte dei tutorial e del codice generato dall’AI fa ancora riferimento ai pacchetti deprecati, quindi controlla gli import prima di fidarti di uno snippet.
Posso fare paper trading su Polymarket prima di rischiare soldi veri?
Non tramite Polymarket: non c’è una testnet, una sandbox né un’API demo. Puoi costruirti da solo uno strato di paper trading facendo girare il ciclo della tua strategia live sui dati di mercato di produzione e registrando gli ordini previsti insieme allo stato del book in quell’istante, invece di inviarli. Questo dimostra che il tuo bot è solido dal punto di vista operativo, ma presume le esecuzioni, quindi non ti insegnerà nulla sulla posizione in coda o sull’impatto sul mercato.
Come faccio il backtest di un bot di trading per Polymarket?
Ti servono snapshot storici dell’order book di terzi, perché l’API di Polymarket restituisce 404 per il book di un mercato risolto e conserva solo circa un punto al minuto di storico dei prezzi. Scarica snapshot point-in-time con la profondità completa, riproducili in ordine cronologico senza sbirciare avanti e simula le esecuzioni scorrendo i livelli del book invece di assumere il prezzo medio. Gli spread Up/Down di 2-5 centesimi su un contratto da $1 di solito sono più grandi del vantaggio dichiarato, quindi i backtest sul prezzo medio sono fuorvianti.
Perché il mio bot per Polymarket riceve Unauthorized/Invalid api key?
Il più delle volte per uno di due motivi. O il tuo set di credenziali è incompleto (l’autenticazione L2 richiede insieme la chiave API, il secret e la passphrase), oppure l’orologio di sistema è andato alla deriva, perché la firma della richiesta contiene un timestamp e pochi secondi di deriva la invalidano. Meno spesso, hai derivato le credenziali con un wallet diverso da quello con cui stai facendo trading.
Per un bot per Polymarket mi serve un WebSocket o posso fare polling?
Usa il WebSocket. Fare polling di /book a intervalli regolari consuma il budget di rate limit, aggiunge latenza e scala male. Iscriviti al canale market del CLOB per gli aggiornamenti pubblici del book e dei prezzi, e al canale user per gli aggiornamenti dei tuoi ordini e delle tue operazioni. Se ti connetti al WebSocket grezzo invece che tramite un SDK, invia un PING ogni 10 secondi per mantenere viva la connessione.

Ottieni i dati storici che Polymarket non conserva

PolyTest registra i mercati crypto Up/Down di Polymarket mentre sono attivi: 240M+ snapshot con 8 livelli di profondità dell’order book, timestamp sotto il secondo e mercati risolti conservati. Inizia con una prova gratuita di 3 giorni.

Continua a leggere