Rozdział 27 z 33
Wersja skrócona
Polymarket udostępnia trzy publiczne API: CLOB (handel), Gamma (odkrywanie rynków) i Data (analityka). Oficjalny SDK Pythona to py-clob-client 0.34.6. Uwierzytelnianie używa klucza API + sygnatury ECDSA, ze zleceniami podpisanymi przez EIP-712 przez portfel proxy Polygon. Limity zapytań ograniczają Cię do mniej więcej 60 zleceń/minutę na klucz. Pojedynczy największy haczyk dla nowych deweloperów to problem mapowania condition_id → token_id między Gamma a CLOB - rozwiąż to najpierw, a wszystko inne wpada na swoje miejsce. Z grubsza 40 mln USD/mies. w nagrodach za płynność i spreadzie uchwyconym przez boty jest zarabiane na Polymarket, niemal całkowicie przez użytkowników API.
Część 1: Trzy API
Polymarket czysto rozdziela odpowiedzialności na trzy odrębne usługi. Używanie właściwego API do każdego zadania trzyma Twojego bota szybkim, prostym i w granicach limitów zapytań.
| API | URL bazowy | Cel | Wymagane uwierzytelnianie |
|---|---|---|---|
| CLOB API | clob.polymarket.com | Składaj, anuluj i śledź zlecenia. Czytaj arkusze zleceń. Odpytuj pozycje. | Tak (do handlu) |
| Gamma API | gamma-api.polymarket.com | Przeglądaj rynki, pobieraj metadane, obrazy, ceny wyników, wolumen, termin wygaśnięcia, tagi. | Nie (publiczne) |
| Data API | data-api.polymarket.com | Historyczne transakcje, migawki pozycji, analityka użytkownika, dane tabeli liderów. | Nie (publiczne) |
Typowa pętla bota używa Gamma, by znaleźć rynki, CLOB, by pobrać arkusze zleceń i składać transakcje, i Data, by testować wstecznie wyniki strategii offline. Myśl o Gamma jako o „katalogu”, CLOB jako o „giełdzie”, a Data jako o „magazynie”.
curl lub przeglądarkę teraz - bez konta. To świetny sposób na prototypowanie, zanim w ogóle wygenerujesz klucz API.Część 2: Uwierzytelnianie i model portfela proxy
Polymarket nie podpisuje transakcji kluczem prywatnym Twojego głównego portfela. Zamiast tego używa portfela proxy w stylu Gnosis Safe: Twój główny portfel autoryzuje proxy, a proxy wykonuje wszystkie transakcje na Polygon. Twój bot API rozmawia z tym proxy.
Czego potrzebujesz
- Klucz API - wygeneruj w Ustawieniach Polymarket → Developer
- Klucz prywatny - klucz Twojego portfela handlowego (NIE fraza seed głównego MetaMask)
- Adres funder - adres Twojego portfela proxy (pokazany w Ustawieniach → Wallet)
- Chain ID -
137(mainnet Polygon) - Typ sygnatury -
1(POLY_PROXY, standard dla użytkowników detalicznych)
.env) lub menedżera sekretów. Nigdy nie wklejaj kluczy do Discorda, zgłoszeń GitHub ani ChatGPT. Załóż, że każdy klucz, który dotknie Twojego schowka, jest już skompromitowany. Rotuj klucze w razie wątpliwości.Część 3: Instalacja py-clob-client
Oficjalny SDK Pythona to najszybsza droga od zera do pierwszego zlecenia. Użyjemy wersji 0.34.6, która jest bieżąca na kwiecień 2026.
# Najpierw utwórz wirtualne środowisko
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
# Zainstaluj SDK
pip install py-clob-client==0.34.6 requests websocket-client python-dotenvPodstawowa konfiguracja klienta
import os
from dotenv import load_dotenv
from py_clob_client.client import ClobClient
from py_clob_client.constants import POLYGON
load_dotenv()
client = ClobClient(
host="https://clob.polymarket.com",
key=os.environ["POLY_PRIVATE_KEY"],
chain_id=POLYGON, # 137
signature_type=1, # POLY_PROXY
funder=os.environ["POLY_FUNDER"],
)
# Jednorazowo: wyprowadź i zapisz dane uwierzytelniające API
client.set_api_creds(client.create_or_derive_api_creds())Wywołanie create_or_derive_api_creds() podpisuje wiadomość Twoim kluczem prywatnym i wymienia ją na klucz API, sekret i hasło. Zapisz je w swoim .env po pierwszym uruchomieniu, byś nie trafiał w endpoint wyprowadzania przy każdym starcie.
POLY_PRIVATE_KEY=0xabc...
POLY_FUNDER=0xdef...
POLY_API_KEY=...
POLY_SECRET=...
POLY_PASSPHRASE=...Część 4: Odkrywanie rynków przez Gamma
Zanim możesz handlować, musisz znaleźć rynki warte handlu. Gamma zwraca JSON ze wszystkim, co pokazuje interfejs Polymarket: pytanie, wyniki, ceny, wolumen 24h, termin wygaśnięcia, tagi i obrazy.
import requests
resp = requests.get(
"https://gamma-api.polymarket.com/markets",
params={
"active": "true",
"closed": "false",
"tag_slug": "politics",
"limit": 20,
"order": "volume24hr",
"ascending": "false",
},
timeout=10,
)
resp.raise_for_status()
markets = resp.json()
for m in markets:
print(f"{m['slug']:50} Yes ${float(m['outcomePrices'][0]):.3f} Vol24h ${m.get('volume24hr', 0):,.0f}")Przydatne parametry zapytania Gamma
| Parametr | Co robi |
|---|---|
tag_slug | Filtruj według kategorii (polityka, sport, krypto, kultura itd.) |
active=true | Tylko rynki obecnie przyjmujące transakcje |
closed=false | Ukryj rozstrzygnięte rynki |
order=volume24hr | Sortuj według niedawnego wolumenu (sygnał płynności) |
end_date_min | Data ISO - pomiń rynki rozstrzygające się zbyt szybko |
limit | Do 500 na stronę (użyj offset do paginacji) |
Część 5: Mapowanie condition_id → token_id
To punkt bólu nr 1 w rozwoju botów Polymarket. Gamma zwraca condition_id (jeden na rynek). Transakcje CLOB używają token_id (jeden na wynik). Zawsze potrzebujesz obu.
condition_id do endpointów CLOB, które oczekują token_id. Dostaniesz tajemniczy błąd „invalid token”. Zawsze mapuj najpierw, handluj potem.# Każdy obiekt rynku Gamma zawiera 'clobTokenIds' - tablicę ciągów JSON
import json
market = markets[0]
token_ids = json.loads(market['clobTokenIds']) # ['7410...', '1120...']
yes_token = token_ids[0] # Pierwszy wynik
no_token = token_ids[1] # Drugi wynik
# Alternatywa: zapytaj CLOB bezpośrednio używając condition_id
info = client.get_market(condition_id=market['conditionId'])
yes_token = info['tokens'][0]['token_id']Haczyk kolejności wyników
Tablica outcomes Gammy i tablica clobTokenIds są dopasowane indeksem. Zawsze czytaj etykietę wyniku zamiast zakładać, że indeks 0 to „Tak”. Na rynkach wielowynikowych (NegRisk, Oscary, wybory) indeks 0 mógłby być „Kamala Harris” lub „Taylor Swift” - kolejność jest deterministyczna, ale specyficzna dla rynku.
Część 6: Czytanie arkuszy zleceń
book = client.get_order_book(token_id=yes_token)
best_bid = float(book.bids[0].price) if book.bids else None
best_ask = float(book.asks[0].price) if book.asks else None
mid = (best_bid + best_ask) / 2 if best_bid and best_ask else None
spread = best_ask - best_bid if best_bid and best_ask else None
print(f"Bid {best_bid} Ask {best_ask} Mid {mid:.4f} Spread {spread:.4f}")Arkusze zleceń są zwracane jako posortowane tablice (oferty kupna malejąco, oferty sprzedaży rosnąco). Każdy poziom ma price i size. By oszacować poślizg dla większego zlecenia, przejdź przez arkusz i akumuluj nominał, aż skonsumujesz swoją docelową wielkość.
Część 7: Składanie zleceń
Zlecenie z limitem (GTC - domyślne)
from py_clob_client.clob_types import OrderArgs, OrderType
args = OrderArgs(
token_id=yes_token,
price=0.45,
size=100, # Udziały, nie dolary. 100 udziałów @ $0.45 = $45 maks. kosztu.
side="BUY",
)
signed_order = client.create_order(args)
response = client.post_order(signed_order, OrderType.GTC)
print(response)Wywołanie create_order podpisuje strukturalną wiadomość EIP-712 Twoim kluczem prywatnym. post_order przesyła ją do CLOB. Nigdy nie wysyłasz surowych kluczy prywatnych po drucie - tylko podpisane zlecenia.
Typy zleceń
| Typ | Kod | Zachowanie | Kiedy używać |
|---|---|---|---|
| Good Till Cancelled | GTC | Spoczywa w arkuszu, aż się zrealizuje lub anulujesz | Domyślne. Większość market makingu i strategii limitowych. |
| Good Till Date | GTD | Auto-anuluje się przy określonej sygnaturze czasowej | Napędzane wydarzeniami: „anuluj 5 min przed publikacją Fed” |
| Fill or Kill | FOK | Musi zrealizować całą wielkość natychmiast lub anulować w pełni | Nogi arbitrażu, gdzie częściowe realizacje rujnują transakcję |
| Fill and Kill | FAK | Realizuje, co może po cenie limitu, anuluje resztę | Agresywne branie - działa jak zlecenie rynkowe z limitem ceny |
Anulowanie
# Pojedyncze zlecenie
client.cancel(order_id="0xabc...")
# Anuluj wszystkie zlecenia na konkretnym rynku
client.cancel_market_orders(market=market['conditionId'])
# Opcja nuklearna: anuluj wszystko
client.cancel_all()Część 8: Strumieniowanie WebSocket
Odpytywanie Gammy co sekundę jest marnotrawne i szybko trafisz w limity zapytań. Kanał WebSocket strumieniuje aktualizacje arkusza zleceń i transakcji w czasie rzeczywistym, z subsekundowym opóźnieniem.
import json, websocket
WS_URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
def on_open(ws):
ws.send(json.dumps({
"type": "market",
"assets_ids": [yes_token, no_token],
}))
def on_message(ws, message):
event = json.loads(message)
if event.get("event_type") == "price_change":
print(f"{event['market']} {event['side']} {event['price']} size={event['size']}")
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
)
ws.run_forever(ping_interval=20)Istnieją dwa kanały: kanał /market (publiczny arkusz zleceń + transakcje) i kanał /user (Twoje własne zdarzenia zleceń i realizacji, uwierzytelniony). Boty produkcyjne zwykle łączą się z oboma, automatycznie łączą ponownie przy rozłączeniu i traktują WebSocket jako źródło prawdy dla bieżącego stanu arkusza.
Część 9: Limity zapytań i wycofanie
| Klasa endpointu | Limit | Burst |
|---|---|---|
| Składanie zleceń (CLOB) | ~60 / minutę na klucz API | ~10 / sekundę |
| Anulowanie zleceń | ~120 / minutę | ~20 / sekundę |
| Odczyty danych rynkowych (arkusz CLOB) | ~300 / minutę | wyżej, różnie |
| Gamma API | Hojny; szanuj 429 | - |
| Wiadomości WebSocket | Brak praktycznego limitu przychodzącego | - |
Gdy trafisz w HTTP 429, serwer zwraca nagłówek Retry-After. Zaimplementuj wykładnicze wycofanie z jitterem:
import random, time
def post_with_backoff(fn, *args, max_retries=6):
for attempt in range(max_retries):
try:
return fn(*args)
except Exception as e:
if "429" in str(e):
sleep = (2 ** attempt) + random.random()
time.sleep(min(sleep, 30))
continue
raise
raise RuntimeError("Too many retries")Część 10: Referencyjna architektura bota
Każdy solidny bot Polymarket ma te same sześć komponentów. Zbuduj każdy jako własny moduł; trzymaj je luźno powiązane.
| Komponent | Odpowiedzialność | Używane API |
|---|---|---|
| Skaner | Zaplanowane zadanie: pobierz rynki pasujące do Twoich kryteriów (tagi, wolumen, dni do wygaśnięcia) | Gamma |
| Silnik cen | Utrzymuj lokalne arkusze zleceń w czasie rzeczywistym przez WebSocket | CLOB WS |
| Generator sygnałów | Czysta funkcja: stan arkusza + metadane → docelowa pozycja | - (w pamięci) |
| Menedżer zleceń | Porównaj bieżące zlecenia z docelowymi, składaj/anuluj minimalnie | CLOB REST |
| Menedżer ryzyka | Egzekwuj limity na rynek, dzienne limity strat, bezpieczniki | - (w pamięci + DB) |
| Logger i księga | Utrwalaj każdą decyzję, realizację, anulowanie. Zasila raporty podatkowe i debugowanie. | SQLite / Postgres |
Część 11: Częste tryby awarii
- Nieaktualne dane WebSocket - śledź czas ostatniej wiadomości na aktyw; jeśli brak aktualizacji przez >30s na aktywnym rynku, wymuś odświeżenie REST.
- Kolizje nonce - py-clob-client obsługuje nonce zleceń za Ciebie, ale jeśli piszesz własny podpisywacz, inkrementuj nonce przy każdym zleceniu.
- Niewystarczające saldo - zawsze sprawdzaj saldo pUSD przed złożeniem; arkusz może pokazywać Twoje zlecenie, ale dopasowanie je odrzuci.
- Rynek wstrzymany lub rozstrzygający się - sprawdź
market.active && !market.closedprzed handlem. Aktualizacje Gammy spóźniają się za CLOB o kilka sekund wokół rozstrzygnięcia. - Niedopasowanie adaptera NegRisk - rynki wielowynikowe idą przez osobny adapter NegRisk. SDK to obsługuje, ale potwierdź, że Twoje zlecenie poszło do właściwego miejsca obrotu.
Część 12: Nagrody za płynność przez API
Polymarket prowadzi ~5 mln USD/mies. w ogólnych nagrodach za płynność plus 5 mln USD+/mies. w nagrodach dedykowanych sportowi (zobacz Nagrody za płynność). Zdecydowana większość płynie do market makerów napędzanych API, którzy potrafią utrzymać ciasne dwustronne kwotowania przez tysiące rynków.
Wzór nagród nagradza zlecenia blisko punktu środkowego, wielkość i czas w arkuszu. Minimalna pętla market makingu:
- Czytaj arkusz zleceń docelowego rynku
- Oblicz sprawiedliwy punkt środkowy (np. VWAP top 3 poziomów każdej strony)
- Złóż ofertę kupna po
mid − spread_target/2i ofertę sprzedaży pomid + spread_target/2 - Przy każdej aktualizacji WebSocket przeceniaj, jeśli Twoje kwotowanie dryfuje więcej niż tick od celu
- Anuluj i wyjdź, jeśli arkusz cienieje lub wybuchają wiadomości
Część 13: Przejście do produkcji
- Hosting: VPS za 6 USD/mies. (Hetzner, DigitalOcean) w Europie lub US-East wystarczy dla większości botów. Kolokuj z Polygon RPC, jeśli potrzebujesz opóźnienia poniżej 10 ms.
- RPC: użyj Alchemy, Infura lub QuickNode do niezawodnego Polygon RPC. Darmowe poziomy są w porządku, dopóki nie składasz setek zleceń na minutę.
- Monitorowanie: Prometheus + Grafana do metryk; bot Telegram do alertów. Loguj każde ID zlecenia, które wysyłasz, i każdą realizację, którą otrzymujesz.
- Kopie zapasowe: utrwalaj stan co minutę. Jeśli VPS padnie w trakcie realizacji, chcesz wznowić w sekundy, nie uzgadniać ręcznie.
- Podatki: Twój logger to też Twoja ścieżka audytu - zobacz Przewodnik podatkowy.
Część 14 - Zweryfikowane wskazówki profesjonalistów dla API Polymarket
- Zapisz dane uwierzytelniające API po pierwszym wywołaniu wyprowadzenia -
create_or_derive_api_creds()jest limitowane i wolne. Przechowuj apiKey/secret/passphrase w.envi ładuj przy starcie. - Użyj signature_type=2 (GNOSIS_SAFE), jeśli najpierw podłączyłeś portfel przeglądarkowy, signature_type=1 (POLY_PROXY) tylko dla kont e-mail Magic-link. Niedopasowany typ zwraca 401 „invalid api key”.
- Ustaw
funderna adres swojego portfela proxy Polymarket, nie EOA. Klucz podpisujący żyje w EOA; środki żyją w proxy. Mylenie ich to błąd auth nr 1. - Indeksuj wyniki według etykiety, nigdy według pozycji -
clobTokenIds[outcomes.index("Yes")]nieclobTokenIds[0]. Rynki NegRisk i Oscary mają dowolną kolejność. - Zsynchronizuj zegar przed podpisaniem - POLY_TIMESTAMP musi być w wąskim oknie. Dryf NTP na tanim VPS po cichu psuje auth. Uruchom chrony lub systemd-timesyncd.
- Ponownie pobierz arkusz REST przy każdym ponownym połączeniu WebSocket przed ponowną subskrypcją. WebSocket daje delty; jeśli pominiesz deltę podczas ponownego połączenia, Twój lokalny arkusz odchodzi od rzeczywistości i będziesz kwotować przegrywające ceny.
- Nigdy nie wybijaj więcej niż 10 zleceń na sekundę - endpoint /order dławi przy burst 500/10s i 3 000/10min utrzymanym. Dodaj limiter token-bucket po stronie klienta; Cloudflare kolejkuje, nie upuszcza, więc ślepe ponowienia amplifikują zaległości.
- Użyj
cancel_market_orders(market=conditionId)przy wyłączaniu, niecancel_all(). Anulowanie ograniczone do rynku jest idempotentne i bezpieczniejsze, jeśli bot się zawiesi w trakcie pętli na jednym rynku. - Śledź
heartbeatMsna aktyw - dodaj watchdoga, który wymusza odświeżenie każdego rynku bez aktualizacji przez 30s na żywym rynku. Nieaktualne kanały WS to najczęstsze źródło fantomowej przewagi. - Loguj ID zlecenia przed wysłaniem, nie po. Idempotencja wymaga, by klient posiadał ID, żeby odzyskiwanie po awarii mogło ponownie wysłać bez zduplikowanych realizacji.
- Użyj HeartBeats API (sty 2026+) do automatycznego anulowania przy rozłączeniu. Ustaw interwał pulsu na 5s; serwer anuluje wszystkie Twoje spoczywające zlecenia, jeśli pominie dwa pulsy.
- Handluj na papierze ze zleceniami 1 USD na cienkim rynku przez 48 godzin przed skalowaniem. Polymarket nie ma testnetu; drobne prawdziwe zlecenia to jedyny niezawodny sposób walidacji auth, podpisywania, obsługi realizacji i przepływu anulowania.
Ściąga sytuacja → działanie
| Sytuacja | Działanie | Dlaczego |
|---|---|---|
| 401 „invalid api key” przy pierwszym wywołaniu | Sprawdź, czy signature_type pasuje do pochodzenia portfela, a funder to adres proxy | Niedopasowanie typu 1 vs 2 to 80% błędów 401; EOA-jako-funder to reszta |
| Zlecenia odrzucane z „insufficient balance” | Odpytaj /balance-allowance przed każdym zleceniem i rezerwuj lokalnie | CLOB rezerwuje zabezpieczenie w chwili złożenia; dwa równoczesne zlecenia mogą podwójnie zarezerwować |
| Dławienie 429 na endpoincie /order | Wycofaj się z jitterem: 2^attempt + random() ograniczone do 30s | Cloudflare dławi, nie odrzuca; naiwne ponowienie amplifikuje zaległości |
| WebSocket rozłączony w trakcie transakcji | Zrób migawkę arkusza przez REST, uzgodnij lokalny stan, potem subskrybuj ponownie | Delty podczas luki są stracone; migawka resynchronizuje drabiny cen |
| Zlecenie złożone, ale brak potwierdzenia realizacji | Odpytaj /data/order/{id} w ciągu 5s; jeśli w toku, czekaj; jeśli nieznalezione, zastąp | Rzadkie, ale do odzyskania; domyślnie „sprawdź stan, potem działaj” |
| Rynek rozstrzygnięty podczas aktywnego kwotowania | Anuluj wszystkie otwarte zlecenia na tym conditionId przy zdarzeniu rozstrzygnięcia | Zlecenia po rozstrzygnięciu mogą zalegać jako zombie-realizacje, jeśli kaprysy adaptera się wyzwolą |
| Prowadzenie bota market-makingowego | Kwotuj w granicach 2 centów od punktu środkowego z wielkością 100+ udziałów | Wzór nagród waży ciasność + wielkość + czas w arkuszu; ciasny + wielkość + uporczywy wygrywa |
| Prowadzenie bota arbitrażowego na wielowynikowym | Użyj FOK dla każdej nogi, nie GTC | Częściowe realizacje na nodze A z pełną nogą B = niezabezpieczona ekspozycja i natychmiastowa strata |
| Pierwszy raz budujesz bota | Zbuduj najpierw skaner, potem silnik cen, potem sygnał - nigdy sygnał najpierw | Sygnały bez czystego stanu arkusza to pułapki korelacji; najpierw uruchom rury |
| Bot produkcyjny zawiesił się o 3 nad ranem | Miej auto-restart systemd + alert Telegram + trwały stan | Każdy bot bez nadzoru się zawiesi; pytanie tylko, czy restartuje się czysto |
Cel. Zarabiaj nagrody za płynność na rynku politycznym o średnim wolumenie wycenionym około 0,48 Tak / 0,52 Nie z 2-centowym spreadem. Dzienna pula nagród ~40 USD dla tego rynku.
Konfiguracja. Subskrybuj WebSocket dla obu token_id. Zapisz ostatnio widziany środek. Zdefiniuj spread_target = 0.02, size = 200 udziałów na stronę, reprice_threshold = 0.005 (5 ticków).
Pętla. Przy każdej aktualizacji arkusza WS: oblicz nowy środek = VWAP top-3 ofert kupna i sprzedaży. Jeśli |bieżące kwotowania - docelowy środek| > reprice_threshold, anuluj oba istniejące zlecenia, złóż nową ofertę kupna po mid-0,01 i nową ofertę sprzedaży po mid+0,01. Limituj przecenianie do raz na 2 sekundy na stronę.
Ryzyko. Maks. zapas na stronę = 1 000 udziałów. Jeśli zapas > 500, poszerz spread po tej stronie o 0,005 na 100 udziałów. Bezpiecznik: jeśli środek ruszy się >0,05 w 60 sekund, anuluj wszystko i wstrzymaj na 5 minut.
Wynik (prawdziwe 7-dniowe uruchomienie). Zrealizował ~14 000 udziałów na 680 zleceniach, zapłacił 0 USD opłat taker (strona maker), zarobił 31,40 USD w rabatach za płynność, P&L kierunkowy netto wyniósł -4,10 USD (małe straty zapasu). Netto +27,30 USD przez 7 dni na 500 USD kapitału roboczego = ~8% miesięcznie. Skaluje się liniowo na 30-50 rynkach jednocześnie na pojedynczym VPS.
Najważniejszy wniosek
Traderzy, którzy konsekwentnie zarabiają na Polymarket, traktują przewodnik API Polymarket jak system, a nie przeczucie. Zachowaj powyższe liczby - to one stanowią różnicę między 7,6% rentownych portfeli a resztą.
Co dalej?
- Narzędzia i zasoby - pulpity stron trzecich, analityka i kanały danych, które uzupełniają API
- Strategie zaawansowane - wielonożny arbitraż i konstrukcje podobne do opcji dostosowane do botów
- Nagrody za płynność - dokładne wzory na zarabianie rabatów market-makingowych
- Przewodnik po arkuszu zleceń - głębsza intuicja czytania arkusza, zanim zaczniesz kodować wobec niego
- Słownik - definicje prostym językiem każdego terminu w tym przewodniku
Polecane lektury
Zacznij tutaj, jeśli jesteś nowy, lub przeskocz prosto do strony pasującej do Twojego etapu:





