Kurs budowy bota na Polymarket · Rozdział 24 z 32

Polymarket Perps ma pełne publiczne API z oficjalnymi SDK dla TypeScript i Pythona. W tym rozdziale budujemy bota na prawdziwym interfejsie: uwierzytelnianie za pomocą klucza handlowego proxy, dane rynkowe przez REST i WebSocket, zlecenia z take-profit i stop-loss oraz mechanizmy kontroli ryzyka, które nie pozwalają botowi z dźwignią wyczyścić konta.

Build your own theme park, free in your browserReklama Zareklamuj się tutaj
Zanim zaczniesz budować. Składanie zleceń w Perps nie jest dozwolone ze Stanów Zjednoczonych, Kanady, Kuby, Iranu, Korei Północnej, Syrii, Krymu, Doniecka ani Ługańska, a polymarket.com blokuje też inne kraje. Bot ani zagraniczny serwer tego nie zmieniają. Przy dźwigni błąd w kodzie szybko kosztuje pieniądze, więc testuj na minimalnej wielkości. Dopiero zaczynasz z Perps? Zacznij od przewodnika po Polymarket Perps.

Co obejmuje ten rozdział

  • Kluczowe liczby dla twórców botów
  • Jak zbudowane jest API Perps
  • Krok 1: instalacja SDK i otwarcie sesji
  • Krok 2: odczyt danych rynkowych przez REST i WebSocket
  • Krok 3: składanie zleceń z take-profit i stop-loss
  • Krok 4: szkielet bota z kontrolą ryzyka w kodzie
  • Błędy, wyłącznik czuwakowy (dead man's switch), zasady dla botów i hosting

Każda metoda SDK i każdy endpoint w tym rozdziale pochodzą z dokumentacji Perps Polymarket (docs.polymarket.com/perps, stan na 6 listopada 2026). Nasza własna logika jest oznaczona w komentarzach, a funkcja strategii to wyraźnie oznaczony placeholder.

Kluczowe liczby dla twórców botów (stan na listopad 2026)

ElementWartość
Bazowy URL RESThttps://api.perpetuals.polymarket.com
WebSocketwss://ws.perpetuals.polymarket.com/v1/ws
SDK TypeScript@polymarket/client (z viem do podpisywania)
SDK Pythonpolymarket-client (asynchroniczne)
Dane publiczne/v1/info/*, bez uwierzytelniania
Odczyty prywatne/v1/account/* z nagłówkami polymarket-proxy i polymarket-secret
Podpisane zapisy/v1/trade/*, podpis EIP-712 kluczem proxy, ważny przez 5 minut
Dane uwierzytelniające sesjiDomyślnie wygasają po tygodniu
Minimalne zlecenie10 USD wartości nominalnej; minimalny depozyt 10 pUSD
Największe zlecenie rynkowe1 mln USD na rynkach 50x i 20x, 500 tys. USD na większości pozostałych, 50 tys. USD na monetach 3x i 5x
Format ceny i wielkościCiągi dziesiętne, nie więcej miejsc po przecinku niż na danym rynku i maksymalnie 5 cyfr znaczących
Maksymalna dźwignia50x (BTC, ETH, USA500, US100), w pozostałych przypadkach 20x, 10x, 5x lub 3x zależnie od rynku, niższa dla dużych pozycji
Opłaty (poziom podstawowy)Taker 0,040%, maker 0,0125%; ANT za połowę ceny
FinansowanieCo godzinę, z limitem +/-4% na godzinę
Wyzwalacze TP/SLCena znacznikowa, nie ostatnia transakcja
Keepalive WebSocketPing mniej więcej co 25 sekund; po około 65 sekundach ciszy traktuj połączenie jako nieaktualne
Aktualność tickeraDo 10 sekund opóźnienia

Jak zbudowane jest API Perps

Perps to giełda hybrydowa: kojarzenie zleceń odbywa się offchain, a przechowywanie środków i rozliczenie na Polygon. Onchain są tylko wpłaty i wypłaty, więc za zlecenia nie płacisz gazu. API ma trzy warstwy:

  • Dane publiczne (/v1/info/): instrumenty, tickery, arkusz zleceń, świece, transakcje, finansowanie, opłaty. Nie wymagają klucza i nie podlegają blokadzie geograficznej.
  • Odczyty prywatne (/v1/account/): portfel pozycji, salda, zlecenia, realizacje, konfiguracja.
  • Podpisane zapisy (/v1/trade/): zlecenia, anulowania, dźwignia, izolowany depozyt zabezpieczający, automatyczne anulowanie. Każdy zapis jest kodowany w MessagePack, haszowany keccak256 i podpisywany kluczem proxy jako dane typowane EIP-712.

SDK podpisują wszystko za ciebie. Dostępna jest też specyfikacja OpenAPI (/api-spec/perps-openapi.json na stronie dokumentacji) oraz specyfikacja AsyncAPI dla WebSocket.

Symbole różnią się od przykładów w dokumentacji. Dokumentacja pokazuje BTC-PERP. Działające API zwraca BTC-USD, SP500-USD (USA500), NAS100-USD (US100), ANT-USD i tak dalej. Pobierz listę instrumentów, dopasuj aktualny symbol i zapisz numeryczne id. Nie kopiuj ID z przykładów: na żywo BTC ma 6, a SP500 ma 1.

Krok 1: instalacja SDK i otwarcie sesji

Zainstaluj poleceniem pip install polymarket-client lub npm install @polymarket/client@latest viem. Bot potrzebuje adresu twojego portfela Polymarket oraz klucza prywatnego podpisującego, do którego należy konto Perps (konto jest powiązane z EOA podpisującego, nie z Safe). Otwarcie sesji wymaga jednego podpisu, który autoryzuje nowy klucz handlowy proxy. To on podpisuje potem każde zlecenie, więc klucz, z którego finansujesz konto, nigdy nie handluje. Zapisz session.credentials w postaci zaszyfrowanej, aby później wznowić sesję.

import asyncio
import os
from datetime import timedelta

from polymarket import AsyncSecureClient


async def main():
    client = await AsyncSecureClient.create(
        private_key=os.environ["PRIVATE_KEY"],
        wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
    )
    # One signature creates a proxy trading key. Orders are signed by the proxy,
    # not by your wallet key. Credentials expire after one week by default.
    session = await client.open_perps_session(
        expires_in=timedelta(days=1),
        label="perps-bot",
    )
    stored = session.credentials.model_dump(mode="json")  # keep it encrypted

    instruments = await client.fetch_perps_instruments()
    btc = next(i for i in instruments if i.symbol == "BTC-USD")
    print(btc.id, btc.max_leverage, btc.min_notional, btc.price_decimals)


asyncio.run(main())
import { createSecureClient } from "@polymarket/client";
import { privateKey } from "@polymarket/client/viem";

const client = await createSecureClient({
  wallet: process.env.POLYMARKET_WALLET_ADDRESS!,
  signer: privateKey(process.env.PRIVATE_KEY!),
});

// One signature creates a proxy trading key. Orders are signed by the proxy,
// not by your wallet key. Credentials expire after one week by default.
const session = await client.openPerpsSession({
  expiresIn: 24 * 60 * 60 * 1000,
  label: "perps-bot",
});
const stored = session.credentials; // keep it encrypted

const instruments = await client.fetchPerpsInstruments();
const btc = instruments.find((i) => i.symbol === "BTC-USD");
if (!btc) throw new Error("BTC-USD not listed");
console.log(btc.id, btc.maxLeverage, btc.minNotional, btc.priceDecimals);

Wpłata z poziomu kodu (deposit_to_perps / depositToPerps) wymaga dodatkowo klucza Relayer API z polymarket.com, Ustawienia, Klucze API. Prościej i bezpieczniej jest zasilić konto w aplikacji webowej i trzymać bota z dala od przepływów środków. Od 5 listopada 2026 konta korzystające z książki adresów wypłat mogą wypłacać środki tylko na zapisane adresy. Do dashboardów używaj klucza tylko do odczytu (proxy z etykietą read-only:, które odrzuca podpisane zapisy), nigdy klucza handlowego. Przechowywanie kluczy omawiamy w rozdziale o portfelach i uwierzytelnianiu.

Krok 2: odczyt danych rynkowych przez REST i WebSocket

Ticker zawiera trzy ceny: indeksu (wartość godziwa z takich źródeł jak Pyth, Chainlink Data Streams i Hyperliquid), znacznikową (używaną do PnL, depozytu zabezpieczającego, likwidacji i TP/SL) oraz ostatnią (tylko realizacja), a do tego stawkę finansowania i czas następnego finansowania. Sygnały opieraj na cenie znacznikowej lub cenie indeksu.

# Inside your async main(), after Step 1 (btc is the BTC-USD instrument)
from polymarket import AsyncPublicClient
from polymarket.streams import PerpsBboSpec

client = AsyncPublicClient()

ticker = await client.fetch_perps_ticker(instrument_id=btc.id)
print(ticker.mark_price, ticker.index_price, ticker.funding_rate)

stream = await client.subscribe(PerpsBboSpec(instrument_id=btc.id))
async for event in stream:
    print(event.payload.bid_price, event.payload.ask_price)
// After Step 1 (btc is the BTC-USD instrument)
import { createPublicClient } from "@polymarket/client";

const client = createPublicClient();

const ticker = await client.fetchPerpsTicker({ instrumentId: btc.id });
console.log(ticker.markPrice, ticker.indexPrice, ticker.fundingRate);

const stream = await client.subscribe([{ topic: "perps.bbo", instrumentId: btc.id }]);
for await (const event of stream) {
  console.log(event.payload.bidPrice, event.payload.askPrice);
}

Bez SDK subskrybujesz surowy WebSocket komunikatem {"id": 1, "req": "sub", "chs": ["bbo::6"]}. Dostępne kanały to m.in. bbo::<id>, book::<id>, trades::<id>, tickers::<id> i klines::<id>::1m. Każda aktualizacja ma numer sekwencyjny sq: po luce lub ponownym połączeniu odczytaj stan od nowa przez REST. Do backtestów list_perps_candles / listPerpsCandles stronicuje historię (endpoint REST zwraca do 1 000 świec na wywołanie).

Krok 3: składanie zleceń z take-profit i stop-loss

Zlecenie ma side (BUY lub SELL), quantity w jednostkach aktywa bazowego, opcjonalną price w pUSD oraz czas obowiązywania (gtc, ioc lub fok). Post-only wymaga GTC; reduce-only może jedynie zmniejszyć pozycję. Nie ma flagi long ani short: bez otwartej pozycji BUY otwiera long, a SELL otwiera short.

Zlecenie typu bracket dołącza do wejścia jeden take-profit i jeden stop-loss. Pozostają one uśpione, dopóki wejście nie zrealizuje się w całości, i są anulowane, jeśli wejście zostanie anulowane lub zrealizuje się tylko częściowo. Poniższe ceny są hipotetyczne.

# Inside your async main(), after Step 1 (btc is the BTC-USD instrument)
from polymarket import PerpsTpSlTrigger

result = await session.place_order(
    instrument_id=btc.id,
    side="BUY",
    price="100000",
    quantity="0.01",
    time_in_force="gtc",
    take_profit=PerpsTpSlTrigger(trigger_price="104000"),
    stop_loss=PerpsTpSlTrigger(trigger_price="98000"),
)
print(result.order.id, result.order.status)
// After Step 1 (btc is the BTC-USD instrument)
import { OrderSide, PerpsTimeInForce } from "@polymarket/client";

const result = await session.placeOrder({
  instrumentId: btc.id,
  side: OrderSide.BUY,
  price: "100000",
  quantity: "0.01",
  timeInForce: PerpsTimeInForce.GTC,
  takeProfit: { triggerPrice: "104000" },
  stopLoss: { triggerPrice: "98000" },
});
console.log(result.order.id, result.tpSl.stopLoss?.orderId);

Dla otwartej pozycji place_position_tp_sl / placePositionTpSl dodaje wyzwalacze zamykające całą pozycję. Zasady:

  • Wyzwalacze obserwują cenę znacznikową i wysyłają zlecenie reduce-only. TP/SL pozycji zamyka po cenie rynkowej, więc przy płytkim arkuszu zleceń licz się ze slippage.
  • Jeden take-profit i jeden stop-loss pozycji na rynek. Przesunięcie stopu oznacza anulowanie i utworzenie nowego, a to nie jest operacja atomowa.
  • Wyzwalacz, który cena znacznikowa już przekroczyła, zostanie odrzucony, podobnie jak ceny limitu zbyt odległe od ceny znacznikowej.

Aby przećwiczyć przepływ zleceń ręcznie, zanim go zautomatyzujesz, otwórz rynek BTC na Polymarket Perps i złóż najmniejsze dozwolone zlecenie. Gdy zobaczysz realizacje, opłaty i panel pozycji, łatwiej będzie ci czytać odpowiedzi API.

Krok 4: szkielet bota z kontrolą ryzyka w kodzie

Poniższy szkielet w Pythonie używa wyłącznie udokumentowanych wywołań SDK; logika ryzyka jest nasza. Trzy warstwy ochrony:

  1. Limit dźwigni. Dźwignia jest ustawiana na 3x lub maksimum rynku, zależnie od tego, która wartość jest niższa, z izolowanym depozytem zabezpieczającym, a wielkości wpadające w poziom ryzyka z niższym limitem są odrzucane.
  2. Wyłączniki awaryjne (kill switch). Plik HALT, dzienny limit straty 5% i wyjście w razie likwidacji. Wyłącznik zamyka pozycje zleceniami reduce-only IOC, anuluje pozostałe zlecenia, a potem sprawdza, czy jedno i drugie zniknęło.
  3. Stop na każdej pozycji. Wejścia fill-or-kill oznaczają brak niechronionych częściowych realizacji. Po każdej realizacji ustawiany jest stop i take-profit pozycji; jeśli zostaną odrzucone, pozycja jest natychmiast zamykana.
import asyncio
import logging
import os
from datetime import timedelta
from decimal import Decimal, ROUND_DOWN

from polymarket import AsyncSecureClient, PerpsPositionTpSlTrigger

SYMBOL = "BTC-USD"                   # live API symbol; docs examples say "BTC-PERP"
LEVERAGE_CAP = 3                     # our cap, far below the 50x BTC allows
RISK_PER_TRADE = Decimal("20")       # pUSD we accept losing if the stop fills
STOP_PCT = Decimal("0.02")           # stop 2% from entry
TAKE_PCT = Decimal("0.04")           # take profit 4% from entry
MAX_NOTIONAL = Decimal("2000")       # hard cap per position, in pUSD
MAX_SLIPPAGE = Decimal("0.002")      # worst entry price: ask + 0.2%
MAX_FUNDING = Decimal("0.0005")      # skip longs if funding > 0.05% per hour
DAILY_LOSS_LIMIT = Decimal("0.05")   # kill switch at -5% of start equity
HALT_FILE = "/opt/perps-bot/HALT"    # touch this file to stop the bot


def fit(value: Decimal, decimals: int, sig: int = 5) -> str:
    """Round down to the market's decimals and to 5 significant figures."""
    v = value.quantize(Decimal(1).scaleb(-decimals), rounding=ROUND_DOWN)
    if v != 0:
        step = Decimal(1).scaleb(v.adjusted() - sig + 1)
        if step > Decimal(1).scaleb(-decimals):
            v = v.quantize(step, rounding=ROUND_DOWN)
    return format(v, "f")


def tier_cap(inst, notional: Decimal) -> int:
    """Max leverage allowed for this notional by the market's risk tiers."""
    cap = inst.max_leverage
    for tier in inst.risk_tiers:
        if notional >= Decimal(tier.lower_bound):
            cap = tier.max_leverage
    return cap


async def close_all(session):
    """Close every position with reduce-only IOC orders, then cancel the rest."""
    portfolio = await session.fetch_portfolio()
    for pos in portfolio.positions:
        if pos.size != 0:
            await session.place_order(
                instrument_id=pos.instrument_id,
                side="SELL" if pos.size > 0 else "BUY",
                quantity=abs(pos.size),
                time_in_force="ioc",
                reduce_only=True,
            )
    await session.cancel_all_orders()


async def kill_switch(session, reason: str):
    logging.error("KILL SWITCH: %s", reason)
    for attempt in range(3):
        await close_all(session)
        portfolio = await session.fetch_portfolio()
        open_orders = await session.fetch_open_orders()
        if not open_orders and all(p.size == 0 for p in portfolio.positions):
            return
        await asyncio.sleep(2)
    logging.critical("Positions still open after kill switch: act manually")


async def open_long(client, session, inst):
    ticker = await client.fetch_perps_ticker(instrument_id=inst.id)
    if Decimal(ticker.funding_rate) > MAX_FUNDING:
        return                                     # longs would pay too much
    book = await client.fetch_perps_book(instrument_id=inst.id, depth=10)
    if not book.asks:
        return
    ask = Decimal(book.asks[0].price)
    stop = ask * (1 - STOP_PCT)
    qty = RISK_PER_TRADE / (ask - stop)            # size from the stop, not leverage
    qty = min(qty, MAX_NOTIONAL / ask)
    notional = qty * ask
    if notional < Decimal(inst.min_notional):
        return
    if tier_cap(inst, notional) < LEVERAGE_CAP:
        return                                     # size would break our cap

    entry = await session.place_order(
        instrument_id=inst.id,
        side="BUY",
        price=fit(ask * (1 + MAX_SLIPPAGE), inst.price_decimals),
        quantity=fit(qty, inst.quantity_decimals),
        time_in_force="fok",                       # all or nothing
    )
    if entry.order.status != "filled":
        return

    try:                                           # stop on the whole position
        await session.place_position_tp_sl(
            instrument_id=inst.id,
            take_profit=PerpsPositionTpSlTrigger(
                trigger_price=fit(ask * (1 + TAKE_PCT), inst.price_decimals)),
            stop_loss=PerpsPositionTpSlTrigger(
                trigger_price=fit(stop, inst.price_decimals)),
        )
    except Exception:
        logging.exception("TP/SL rejected: closing the unprotected position")
        await close_all(session)


async def my_signal(client, inst) -> bool:
    """PLACEHOLDER: your strategy goes here. Not part of the SDK."""
    return False


async def main():
    logging.basicConfig(level=logging.INFO)
    client = await AsyncSecureClient.create(
        private_key=os.environ["PRIVATE_KEY"],
        wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
    )
    session = await client.open_perps_session(
        expires_in=timedelta(days=1), label="perps-bot")
    inst = next(i for i in await client.fetch_perps_instruments()
                if i.symbol == SYMBOL)

    # Control 1: leverage cap and isolated margin, set before any order
    await session.update_leverage(
        instrument_id=inst.id,
        leverage=min(LEVERAGE_CAP, inst.max_leverage),
        cross_margin=False,
    )

    # Field names below follow the documented portfolio JSON
    # (margin.total_account_value, in_liquidation). Check them in your SDK.
    start_equity = Decimal((await session.fetch_portfolio()).margin.total_account_value)

    while True:
        portfolio = await session.fetch_portfolio()
        equity = Decimal(portfolio.margin.total_account_value)

        # Control 2: kill switches
        if os.path.exists(HALT_FILE):
            await kill_switch(session, "HALT file found")
            break
        if equity < start_equity * (1 - DAILY_LOSS_LIMIT):
            await kill_switch(session, f"daily loss limit hit: {equity}")
            break
        if portfolio.in_liquidation:
            await kill_switch(session, "account in liquidation")
            break

        in_position = any(p.instrument_id == inst.id and p.size != 0
                          for p in portfolio.positions)
        if not in_position and await my_signal(client, inst):
            await open_long(client, session, inst)   # Control 3 lives here

        await asyncio.sleep(5)


asyncio.run(main())

Obliczanie wielkości pozycji. Wielkość wynika z odległości stopu, a nie z dźwigni. Przy hipotetycznej cenie oferty sprzedaży BTC 100 000 pUSD i stopie 2% stop znajduje się na 98 000. Ryzyko na jednostkę wynosi 2 000, więc ilość to 20 / 2 000 = 0,01 BTC, czyli wartość nominalna 1 000 pUSD. Przy 3x wymaga to około 333 pUSD depozytu zabezpieczającego. Wskaźnik depozytu podtrzymującego dla BTC to 1% (0,5 / 50x), więc cena likwidacji longa wynosi 100 000 x (1 - 1/3) / (1 - 0,01) = około 67 340, co oznacza spadek o 32,7%. Stop na -2% zadziała na długo wcześniej. Jeśli stop zrealizuje się po cenie wyzwalacza, strata wyniesie 20 pUSD plus opłaty: 0,40 za otwarcie i około 0,39 za zamknięcie przy stawce taker 0,040%, czyli około 20,79 pUSD przed slippage. Dźwignia decyduje tylko o tym, ile depozytu zabezpieczającego zostaje zablokowane. Nie zmienia straty na stopie.

Przed uruchomieniem na żywo dodaj dzienny limit transakcji, alerty o realizacjach i wyłącznikach awaryjnych oraz uzgadnianie stanu przy starcie (fetch_portfolio, fetch_open_orders, fetch_orders, list_fills). Zajrzyj do naszych rozdziałów o kodzie zarządzania ryzykiem i paper tradingu, do przewodnika po dźwigni i likwidacji w Perps oraz przewodnika po stawkach finansowania w Perps.

Błędy, ponowienia i wyłącznik czuwakowy

  • 503 service_unavailable nie dowodzi, że żądanie się nie powiodło. Ponawiaj odczyty i zmiany dźwigni z backoffem i respektuj Retry-After. W przypadku podpisanych zmian salda (depozyt zabezpieczający, wypłaty) wysyłaj ponownie wyłącznie dokładnie to samo, pierwotnie podpisane żądanie; nowy podpis oznacza drugą korektę.
  • signature expired: podpis starszy niż 5 minut. Dbaj o synchronizację zegara.
  • insufficient_margin / invalid_leverage: kontrole uwzględniają twoją pozycję oraz wszystkie oczekujące zlecenia.
  • message_rate_limited: wyczerpany limit komunikatów WebSocket. Klucze tylko do odczytu mają 1 000 komunikatów na minutę na IP (burst 50) i cztery połączenia na konto na bramkę; pozostałe limity znajdziesz na stronie Rate Limits w dokumentacji.
  • Błędy formatu: zbyt wiele miejsc po przecinku lub więcej niż 5 cyfr znaczących. Stąd funkcja fit().

Automatyczne anulowanie anuluje wszystkie otwarte zlecenia, jeśli twój bot przestanie je ponownie uzbrajać. Termin musi przypadać co najmniej 5 sekund w przyszłości, a liczba wyzwoleń w ciągu doby UTC jest ograniczona, więc przy czystym zamknięciu bota rozbrajaj mechanizm.

// For quoting bots: cancel all resting orders if this process dies
await session.armAutoCancel({ cancelAt: Date.now() + 60_000 });
const rearm = setInterval(() => {
  // A missed re-arm is fail-safe: the armed switch still fires.
  session.armAutoCancel({ cancelAt: Date.now() + 60_000 }).catch(console.error);
}, 20_000);

// On a clean shutdown
clearInterval(rearm);
await session.disarmAutoCancel();
Automatyczne anulowanie a stopy. Dokumentacja wymienia automatyczne anulowanie jako jeden ze sposobów, w jaki zlecenie TP/SL może zostać anulowane, więc awaria może usunąć stop z otwartej pozycji. Automatyczne anulowanie pasuje do botów kwotujących, takich jak market makerzy. Nasz szkielet nie ma oczekujących zleceń wejścia, więc pozostawia automatyczne anulowanie wyłączone, aby jego stopy pozostały aktywne. Tak czy inaczej, to niska dźwignia chroni bota po awarii przed likwidacją.

Konkursy, kody builderów i zasady dla botów

Dokumentacja wymienia „boty handlowe reagujące na sygnały rynkowe” oraz market makerów jako zastosowania API. Obowiązują dwa zestawy zasad.

  • Konkursy. Zakazane są wash trading, handel z samym sobą, wiele kont, handel głównie dla wolumenu oraz „boty, skrypty lub zautomatyzowane środki mające na celu manipulowanie Programem”. Bot, który handluje naprawdę, jest w porządku; bot, który sztucznie nabija wolumen, może zostać zdyskwalifikowany.
  • Kody builderów (builder codes). Aplikacja handlująca w imieniu innych użytkowników może doliczyć opłatę do 10 punktów bazowych za zgodą każdego tradera. Musi weryfikować lokalizację każdego użytkownika i blokować zlecenia z jurysdykcji objętych ograniczeniami, a nie tylko ostrzegać.

Nagrody za płynność dla makerów i konkursy omawiamy w przewodniku po Polymarket Perps.

Hosting bota

Bot z dźwignią nie powinien działać na laptopie. Musi utrzymywać połączenie WebSocket, reagować na realizacje w ciągu sekund i przetrwać awarię domowego internetu. Uruchom go na VPS pod systemd z automatycznym restartem, trzymaj klucz w pliku środowiskowym, który może odczytać tylko użytkownik bota, i synchronizuj zegar. Składanie zleceń nie jest dozwolone z lokalizacji objętych ograniczeniami, więc nie hostuj bota w USA ani w Kanadzie i nigdy nie używaj VPS do obchodzenia blokady, która dotyczy ciebie. Nasze własne boty uruchamiamy na TradingVPS (link afiliacyjny: otrzymujemy niewielką prowizję, a ty płacisz tyle samo). Nasz rozdział o hostingu VPS porównuje go z innymi dostawcami pod kątem opóźnień, ceny i regionów.

Po etapie paper tradingu zasil konto niewielką kwotą na stronie Polymarket Perps i przez tydzień handluj minimalną wielkością, zanim zaczniesz skalować.

Najważniejsze wnioski

  • Korzystaj z oficjalnych SDK, @polymarket/client lub polymarket-client. Twój portfel podpisuje raz; zlecenia podpisuje klucz proxy.
  • Dopasowuj rynki po aktualnym symbolu (BTC-USD, a nie BTC-PERP) i zapisuj numeryczne ID.
  • Wielkość ustalaj na podstawie odległości stopu, ograniczaj dźwignię w kodzie, używaj izolowanego depozytu zabezpieczającego i zabezpieczaj stopem każdą pozycję zaraz po realizacji.
  • TP/SL uruchamia się według ceny znacznikowej i zamyka po cenie rynkowej. Automatyczne anulowanie może usunąć stopy.
  • Boty są dozwolone, manipulowanie konkursami nie. Nigdy nie handluj z kraju objętego ograniczeniami.

Najczęściej zadawane pytania

Czy Polymarket Perps ma API dla botów handlowych?
Tak. Dostępne jest API REST pod adresem api.perpetuals.polymarket.com, WebSocket pod adresem ws.perpetuals.polymarket.com oraz oficjalne SDK: @polymarket/client dla TypeScript i polymarket-client dla Pythona. Dokumentacja Polymarket wymienia boty handlowe i systemy market makingu jako wspierane zastosowania.
Wybrać SDK dla TypeScript czy dla Pythona?
Dowolne. Oba obejmują ten sam przepływ: utworzenie bezpiecznego klienta, otwarcie sesji Perps, pobranie instrumentów, składanie zleceń z TP/SL i strumieniowanie zdarzeń. SDK dla TypeScript używa viem do podpisywania. SDK dla Pythona jest asynchroniczne. Wybierz język, w którym twój bot jest już napisany.
Czy mój bot potrzebuje klucza prywatnego mojego głównego portfela?
Tylko do otwarcia sesji. Ten jeden podpis autoryzuje klucz handlowy proxy i od tej chwili to proxy podpisuje zlecenia. Dane uwierzytelniające sesji domyślnie wygasają po tygodniu. Przechowuj je zaszyfrowane, a do dashboardów używaj kluczy tylko do odczytu.
Jak ustawić stop loss przez API Perps?
Dołącz wyzwalacze takeProfit i stopLoss do zlecenia wejścia jako bracket albo wywołaj placePositionTpSl (place_position_tp_sl w Pythonie) dla otwartej pozycji. Wyzwalacze obserwują cenę znacznikową i zamykają pozycję zleceniem reduce-only. TP/SL pozycji zamyka całą pozycję po cenie rynkowej.
Jaka jest minimalna wielkość zlecenia na Polymarket Perps?
10 USD wartości nominalnej na zlecenie, a minimalny depozyt to 10 pUSD (stan na listopad 2026). Ceny i wielkości muszą też mieścić się w liczbie miejsc po przecinku danego rynku i mieć maksymalnie 5 cyfr znaczących, w przeciwnym razie zlecenie zostanie odrzucone.
Czy jest wyłącznik awaryjny albo wyłącznik czuwakowy?
Tak. Automatyczne anulowanie anuluje wszystkie otwarte zlecenia, jeśli twój bot przestanie je ponownie uzbrajać, a cancelAllOrders usuwa zlecenia na żądanie. Dokumentacja wymienia automatyczne anulowanie jako jeden ze sposobów, w jaki zlecenie TP/SL może zostać anulowane, więc awaria może też usunąć twoje stopy. Zakoduj również własny wyłącznik awaryjny.
Czy mogę uruchomić bota Polymarket Perps z USA lub Kanady?
Nie. Składanie zleceń w Perps nie jest dozwolone ze Stanów Zjednoczonych, Kanady, Kuby, Iranu, Korei Północnej, Syrii, Krymu, Doniecka ani Ługańska. Nie hostuj tam bota i nie używaj VPS ani VPN do obchodzenia blokady, która dotyczy ciebie.
Czy boty są dozwolone w konkursach handlowych Polymarket Perps?
Handel za pomocą bota jest dozwolony. Regulamin konkursów zakazuje wash tradingu, handlu z samym sobą, posiadania wielu kont, handlu głównie w celu generowania wolumenu oraz botów lub skryptów mających na celu manipulowanie programem. Złamanie tych zasad może skutkować dyskwalifikacją.