WebSocket di Polymarket: dati in tempo reale che non cadono
Fare polling dell’order book è il modo più comune di bruciare un budget di rate limit senza alcun beneficio. Ecco i quattro stream, le opzioni di sottoscrizione che nessuno documenta e il guasto in cui il tuo bot riceve silenzio e lo scambia per calma.
Se il tuo bot fa polling di GET /book a intervalli regolari, questa pagina ti farà risparmiare gran parte del budget di rate limit e un bel po’ di latenza. Polymarket invia gli aggiornamenti del book via WebSocket, e una sottoscrizione ti costa una connessione invece di migliaia di richieste.
La versione breve
Connettiti a wss://ws-subscriptions-clob.polymarket.com/ws/market, invia una sottoscrizione con i tuoi assets_ids, poi invia un PING ogni 10 secondi o verrai disconnesso. Imposta custom_feature_enabled: true se vuoi gli eventi best_bid_ask, new_market o market_resolved: sono disattivati per impostazione predefinita e la loro assenza sembra esattamente un mercato tranquillo.
I quattro stream
| Stream | URL | Trasporta | Autenticazione |
|---|---|---|---|
| Market | wss://ws-subscriptions-clob.polymarket.com/ws/market | Aggiornamenti pubblici di book, prezzi e ciclo di vita | Nessuna |
| User | wss://ws-subscriptions-clob.polymarket.com/ws/user | Aggiornamenti dei tuoi ordini e trade | Sì |
| RTDS (legacy) | wss://ws-live-data.polymarket.com | Commenti; i prezzi di riferimento sono passati a PolyBolt | Nessuna |
| PolyBolt | wss://ws-live-v2.polymarket.com/ws | Prezzi di riferimento di crypto, equity e TWAP | Sì |
| Sports | wss://sports-api.polymarket.com/ws | Stato e punteggi delle partite in diretta | Nessuna |
Il canale User è quello che molti trascurano
Se il tuo bot fa polling di /data/orders per sapere se il suo ordine è stato eseguito, stai spendendo budget di rate limit per un’informazione che il canale User ti invia nell’istante in cui accade, e con meno latenza. Qualsiasi bot che piazza ordini dovrebbe essere su questo stream.
I prezzi di riferimento si sono spostati il 15 settembre 2026
Polymarket ha rilasciato PolyBolt e ha reso RTDS legacy per i prezzi di riferimento. crypto_prices, crypto_prices_chainlink ed equity_prices ora si trovano su wss://ws-live-v2.polymarket.com/ws, la fonte è passata da Binance/Chainlink a Pyth, i simboli sono in minuscolo btcusd invece di btcusdt o btc/usd, e ora è richiesta l’autenticazione. La mappatura completa è nella guida alla migrazione a PolyBolt. Tutto il resto di questa pagina, cioè i canali market e user del CLOB, non è toccato.
Sottoscriversi al canale market
Connettiti, poi invia un messaggio di sottoscrizione JSON. assets_ids accetta token ID (gli stessi che ottieni dai metadati del mercato) e type deve essere "market".
{
"assets_ids": ["65818619657568813474341868652308942079804919287380422192892211131408793125422"],
"type": "market",
"initial_dump": true,
"level": 2,
"custom_feature_enabled": true
}| Campo | Obbligatorio | Predefinito | Cosa fa |
|---|---|---|---|
assets_ids | Sì | — | Token ID a cui sottoscriversi |
type | Sì | — | Deve essere "market" |
initial_dump | No | true | Invia uno snapshot completo del book alla sottoscrizione |
level | No | 2 | Livello di sottoscrizione: 1, 2 o 3 |
custom_feature_enabled | No | false | Abilita gli eventi best_bid_ask, new_market e market_resolved |
custom_feature_enabled è false per impostazione predefinita
È il tranello della sottoscrizione che costa un pomeriggio a molti. Tre tipi di evento (best_bid_ask, new_market e market_resolved) non vengono consegnati a meno che tu non li attivi. Nessun errore e nessun avviso; semplicemente non li ricevi mai. Se stai aspettando un evento market_resolved che non arriva mai, il motivo è questo.
Mantieni initial_dump: true a meno che tu non abbia un motivo specifico per non farlo. Senza, parti senza alcuno stato del book e devi aspettare gli aggiornamenti incrementali per ricostruirlo, il che significa che il tuo bot inizia la sua vita con un quadro incompleto.
Tipi di messaggio
Ogni messaggio ha un event_type. Gestiscili tutti in modo esaustivo: un tipo non riconosciuto va registrato nei log, non scartato in silenzio, perché è così che scopri che il protocollo è cambiato.
event_type | Significato | Richiede attivazione |
|---|---|---|
book | Snapshot completo dell’order book | No |
price_change | Aggiornamento incrementale di prezzo/livello | No |
last_trade_price | È stato eseguito un trade | No |
tick_size_change | La griglia dei tick del mercato è cambiata | No |
best_bid_ask | Aggiornamento del top of book | Sì |
new_market | È stato creato un mercato | Sì |
market_resolved | Un mercato si è regolato | Sì |
Non ignorare tick_size_change
La dimensione del tick è per mercato e può restringersi man mano che un mercato matura. Se metti in cache una dimensione del tick all’avvio e il mercato la cambia, ogni ordine limite successivo viene rifiutato per violazione della dimensione minima del tick: un 400 che sembra un bug nella tua logica di prezzo. Gestisci l’evento e aggiorna la cache.
Restare connessi: PING ogni 10 secondi
È il requisito che coglie tutti impreparati. Il client deve inviare un PING ogni 10 secondi; il server risponde PONG. Salta l’heartbeat e la connessione viene chiusa.
Nota la direzione: è un heartbeat del client. Non stai aspettando che sia il server a mandarti un ping. Il keepalive WebSocket integrato in una libreria, a un altro intervallo, non lo sostituisce: invia tu il PING a livello applicativo.
import asyncio, json, time
import websockets
URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
STALE_AFTER = 30 # seconds without any message = treat as dead
async def stream(token_ids, on_event):
backoff = 1
while True:
try:
async with websockets.connect(URL) as ws:
await ws.send(json.dumps({
"assets_ids": token_ids,
"type": "market",
"initial_dump": True,
"custom_feature_enabled": True, # or lose 3 event types
}))
backoff = 1 # reconnected cleanly
last_msg = time.monotonic()
async def heartbeat():
while True:
await asyncio.sleep(10) # required cadence
await ws.send("PING")
hb = asyncio.create_task(heartbeat())
try:
while True:
# Silence is a failure mode, not a quiet market.
raw = await asyncio.wait_for(ws.recv(), timeout=STALE_AFTER)
last_msg = time.monotonic()
if raw == "PONG":
continue
for msg in json.loads(raw) if raw.startswith("[") else [json.loads(raw)]:
on_event(msg)
finally:
hb.cancel()
except Exception as exc:
# Reconnect with capped exponential backoff + jitter.
wait = min(backoff, 30) * (0.5 + 0.5 * asyncio.get_event_loop().time() % 1)
print(f"ws down ({exc}); reconnecting in {wait:.1f}s")
await asyncio.sleep(wait)
backoff = min(backoff * 2, 30)Usa l’SDK, a meno che tu non abbia un motivo per non farlo
polymarket-client (Python) e @polymarket/client (TypeScript) implementano heartbeat, riconnessione e framing dei messaggi, e uniscono più feed in un unico stream di eventi tipizzati. Scriverlo a mano conviene solo se ti serve un controllo che l’SDK non espone. Nota che le sottoscrizioni sono solo async: i client sincroni non implementano subscribe().
Cambiare le sottoscrizioni senza riconnettersi
I mercati a cinque minuti scadono di continuo, quindi un bot che segue i "mercati BTC 5m correnti" deve cambiare continuamente il suo insieme di sottoscrizioni. Non devi chiudere la connessione per farlo: il canale market supporta sottoscrizione e annullamento della sottoscrizione su una connessione attiva.
Conta più di quanto sembri. Riconnettersi a ogni rotazione dei mercati significa pagare ripetutamente il costo di apertura della connessione, richiedere di nuovo gli initial dump e creare una finestra in cui non ricevi nulla proprio nel momento in cui si apre un nuovo mercato.
Il guasto che costa soldi
Un WebSocket caduto non genera un’eccezione. Smette di consegnare messaggi. Per un bot ingenuo, "nessun aggiornamento" è indistinguibile da "il mercato non si muove", quindi un bot con una posizione aperta resterà a tempo indeterminato su un prezzo vecchio, convinto che non sia cambiato nulla.
- Tieni traccia dell’età dell’ultimo messaggio. Se su un mercato attivo non arriva nulla da ~30 secondi, sei disconnesso, non in una fase tranquilla. Il timeout di
asyncio.wait_forqui sopra fa esattamente questo lavoro. - Tratta i dati vecchi come una condizione di errore. Smetti di quotare, chiudi le posizioni se le tue regole di rischio lo richiedono e riconnettiti: non continuare a fare trading su un book congelato.
- Usa un backoff con jitter in riconnessione. Un loop di riconnessione stretto durante un disservizio è il modo per farti limitare oltre a essere disconnesso, e una flotta che si riconnette tutta insieme peggiora le cose.
- Risincronizza lo stato dopo la riconnessione. Mentre eri via hai perso degli aggiornamenti. Prendi il nuovo
initial_dumpcome verità e scarta il book precedente, invece di fondere aggiornamenti incrementali in uno snapshot vecchio. - Riconcilia le posizioni dopo ogni interruzione. Se eri disconnesso dal canale User, potresti aver perso un’esecuzione. Rileggi le posizioni prima di agire su uno stato presunto.
WebSocket e rate limit
Una domanda frequente, e la risposta è il senso di tutto l’esercizio: una sottoscrizione non consuma budget di rate limit per richiesta come fa il polling. I limiti documentati di Polymarket sono limiti HTTP per endpoint, e lo streaming li aggira quasi del tutto.
| Approccio | Costo per seguire 20 mercati per un’ora |
|---|---|
Polling di /book ogni secondo | 72,000 richieste su un budget di 1,500 req/10s |
Polling di /books (batch) ogni secondo | 3,600 richieste su un budget di 500 req/10s |
| Sottoscrizione WebSocket | Una connessione, più 360 heartbeat |
Continuerai a fare chiamate HTTP (scoperta dei mercati, dimensioni dei tick, invio degli ordini, riconciliazione delle posizioni), e quelle restano soggette ai rate limit documentati. Lo streaming elimina solo la fonte di volume di richieste più grande e meno utile.
La latenza è un rallentamento travestito
Poiché il livello Cloudflare rallenta ritardando invece di rifiutare, un bot che fa polling oltre il limite non vede 429: vede i suoi tempi di risposta salire in silenzio. Se i dati del tuo book sono passati da 40ms a 3 secondi, non stai vivendo un disservizio; stai vivendo la tua stessa frequenza di richieste.
Cosa gli stream non ti daranno
Un confine che vale la pena dichiarare chiaramente, perché è la cosa che la gente prova subito dopo. Un WebSocket ti dà il book dal momento in cui ti sottoscrivi. Non può darti il book di martedì scorso.
Polymarket non conserva alcun order book storico. Una volta che un mercato si risolve, il suo book restituisce 404, e prices-history conserva solo circa un punto al minuto. Se vuoi testare una strategia su come i mercati sono stati davvero scambiati, ti servono snapshot registrati da qualcuno all’epoca. PolyTest lo fa per i mercati crypto Up/Down, con 8 livelli di profondità per lato e i mercati risolti conservati. Oppure avvia oggi il tuo collector, accetta di partire con zero storico e aspetta.
Domande frequenti
- Qual è l’URL del WebSocket di Polymarket?
- Il canale pubblico market è wss://ws-subscriptions-clob.polymarket.com/ws/market e il canale autenticato user è wss://ws-subscriptions-clob.polymarket.com/ws/user. Ci sono anche altri due stream: RTDS su wss://ws-live-data.polymarket.com per prezzi di riferimento, commenti e attività di trading, e un feed sportivo su wss://sports-api.polymarket.com/ws.
- C’è un rate limit sul WebSocket di Polymarket?
- Una sottoscrizione WebSocket non consuma budget di rate limit per richiesta come fa il polling HTTP: i limiti documentati di Polymarket sono limiti HTTP per endpoint. Lo streaming è proprio il modo consigliato per evitarli. Il requisito vincolante su una connessione è l’heartbeat: invia un PING ogni 10 secondi o la connessione viene chiusa. Le chiamate HTTP che fai comunque per scoperta dei mercati, dimensioni dei tick e invio degli ordini restano soggette ai limiti normali.
- Come mantengo attiva una connessione WebSocket con Polymarket?
- Invia un messaggio PING ogni 10 secondi; il server risponde con PONG. È un heartbeat a livello applicativo lato client, quindi il keepalive integrato di una libreria WebSocket a un intervallo diverso non lo sostituisce. Tieni traccia anche dell’età dell’ultimo messaggio ricevuto: una connessione caduta smette di consegnare dati senza generare errori, quindi tratta circa 30 secondi di silenzio su un mercato attivo come una disconnessione e non come un mercato tranquillo.
- Perché non ricevo gli eventi best_bid_ask o market_resolved?
- Questi eventi sono disattivati per impostazione predefinita. Imposta custom_feature_enabled a true nel messaggio di sottoscrizione per abilitare best_bid_ask, new_market e market_resolved. Quando il flag manca non c’è alcun errore o avviso: gli eventi semplicemente non arrivano mai, il che è facile da scambiare per un mercato inattivo.
- Il mio bot per Polymarket dovrebbe usare i WebSocket o fare polling dell’API REST?
- Usa i WebSocket per i dati live di book e prezzi. Seguire 20 mercati facendo polling di /book una volta al secondo costa 72,000 richieste all’ora su un budget di 1,500 req/10s, mentre una sottoscrizione costa una connessione più gli heartbeat; e il polling restituisce anche una risposta più vecchia, perché vedi il book com’era al tuo ultimo polling e non all’ultima modifica. Tieni REST per la scoperta dei mercati, le dimensioni dei tick, l’invio degli ordini e la riconciliazione delle posizioni.
- Posso cambiare i mercati a cui sono iscritto senza riconnettermi?
- Sì. Il canale market supporta sottoscrizione e annullamento della sottoscrizione degli asset su una connessione attiva, il che conta per i mercati di breve durata come i contratti Up/Down a 5 minuti, che ruotano di continuo. Riconnettersi a ogni rotazione fa pagare ripetutamente il costo di apertura della connessione e lascia un buco di copertura proprio nel momento in cui si apre un nuovo mercato.
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
Polymarket ha sostituito RTDS: la migrazione a PolyBolt
Il 15 settembre Polymarket ha reso RTDS legacy per i prezzi di riferimento, senza troppo clamore. Se invii lo spot in streaming a un bot, sono cambiate sei cose insieme, compresi la fonte di prezzo e il formato dei simboli, e la maggior parte fallisce in silenzio invece che in modo evidente.
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.
Rate limit dell’API di Polymarket: il riferimento completo
Polymarket pubblica i suoi rate limit su diverse pagine, in due sistemi completamente diversi, usando una finestra di 10 secondi che quasi nessuno si aspetta. Qui c’è tutto in un unico set di tabelle, più cosa succede davvero quando superi un limite.
L’SDK Python di Polymarket nel 2026 (e la migrazione da py-clob-client)
Se il tuo codice importa ancora ClobClient da py_clob_client, è costruito su un pacchetto superato, come la maggior parte del codice Polymarket che un assistente AI scriverà per te. Ecco l’SDK attuale e come fare il passaggio.