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.
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)
| Element | Wartość |
|---|---|
| Bazowy URL REST | https://api.perpetuals.polymarket.com |
| WebSocket | wss://ws.perpetuals.polymarket.com/v1/ws |
| SDK TypeScript | @polymarket/client (z viem do podpisywania) |
| SDK Python | polymarket-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 sesji | Domyślnie wygasają po tygodniu |
| Minimalne zlecenie | 10 USD wartości nominalnej; minimalny depozyt 10 pUSD |
| Największe zlecenie rynkowe | 1 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ści | Ciągi dziesiętne, nie więcej miejsc po przecinku niż na danym rynku i maksymalnie 5 cyfr znaczących |
| Maksymalna dźwignia | 50x (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 |
| Finansowanie | Co godzinę, z limitem +/-4% na godzinę |
| Wyzwalacze TP/SL | Cena znacznikowa, nie ostatnia transakcja |
| Keepalive WebSocket | Ping mniej więcej co 25 sekund; po około 65 sekundach ciszy traktuj połączenie jako nieaktualne |
| Aktualność tickera | Do 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.
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:
- 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.
- 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.
- 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_unavailablenie dowodzi, że żądanie się nie powiodło. Ponawiaj odczyty i zmiany dźwigni z backoffem i respektujRetry-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();
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/clientlubpolymarket-client. Twój portfel podpisuje raz; zlecenia podpisuje klucz proxy. - Dopasowuj rynki po aktualnym symbolu (
BTC-USD, a nieBTC-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.





