Gate¶
kind = "gate_usdt" (aliases gate, gate_futures) trades Gate APIv4 USDT-settled perpetual futures over the futures WebSocket API, in single position mode.
| Markets | USDT perpetuals (BTC_USDT, ETH_USDT); settle = "usd1" or "btc" selects the other settle currencies' endpoints |
| Order entry | WebSocket API, REST fallback |
| Environments | production, Gate futures TestNet |
| Keys | HMAC-SHA512 |
| Replace | amend in place; the shipped configs use cancel and new |
| Dead man's switch | countdown_cancel_all, per account |
| Example config | configs/gate-usdt.toml |
Connections¶
All three WebSocket connections use ws_url (wss://fx-ws.gateio.ws/v4/ws/usdt).
| channel | purpose |
|---|---|
| md | futures.obu (ob.SYM.50 or .400), futures.book_ticker as BookTicker, futures.trades, futures.tickers as PerpState |
| private | futures.login, then futures.orders, futures.usertrades, futures.positions, futures.balances, each with the auth block and the account's user id |
| trade | futures.login, then futures.order_place, futures.order_cancel, futures.order_amend with req_id = <kind><client id> |
| rest | rest_url (https://fx-api.gateio.ws), the requests below |
request under /api/v4/futures/{settle}/ |
use |
|---|---|
contracts/{name} |
reference data |
order_book?limit=1 |
clock offset; the host has no time endpoint |
accounts |
user id, balances |
positions?holding=true |
reconciliation |
orders?status=open |
reconciliation |
orders (POST, DELETE, PUT) |
order entry fallback |
orders?contract= (DELETE) |
kill switch |
my_trades_timerange |
fill replay |
fee |
account rates, with fetch_fees = true |
countdown_cancel_all |
dead man's switch |
Every connection sends futures.ping every ping_interval_ms. It upgrades with X-Gate-Size-Decimal: 1, so sizes arrive as strings and contracts may be fractional.
| key | default |
|---|---|
stale_ms |
2000 ms |
dead_ms |
twice ping_interval_ms plus 5000 ms; 35000 ms by default |
Keys and signing¶
| where | signature |
|---|---|
| REST | headers KEY, Timestamp (Unix seconds, within 60 s of the venue), SIGN = hex HMAC-SHA512(secret, METHOD\npath\nquery\nhex SHA512(body)\nTimestamp) |
subscription auth |
signs channel=<c>&event=subscribe&time=<t> |
WebSocket API payload.signature |
signs api\n<channel>\n<req_param>\n<timestamp>; req_param is empty for the login |
The signature covers the exact bytes sent.
Instruments and account¶
| field | value |
|---|---|
| quantity | contracts |
contract_multiplier |
quanto_multiplier, base units a contract |
| tick | order_price_round |
| lot | 1 contract |
| minimum, maximum | order_size_min, order_size_max; no minimum notional |
| base, quote | the contract's prefix, the settle currency |
| accepted | type direct; a contract not trading or in_delisting is disabled |
Accounting settles in the settle currency. With keys, load_reference_data() reads GET /accounts for the user id the private channels need. It refuses an account in dual position mode, and fastmm-live exits 3. A dual_long or dual_short position seen later is fatal for the venue. Leverage and margin mode are not read or set.
Market data¶
futures.obu sends a full snapshot (full: true, depth id u) after subscribing, then increments with U and u. An increment applies when U is the local id + 1. Anything else re-subscribes the stream for a new snapshot, at most once per 2 s, and again after 10 s without one.
book_level |
push interval |
|---|---|
| 50 | 20 ms |
| 400 | 100 ms |
Orders¶
| field | value |
|---|---|
size |
signed contracts, a bid positive |
price |
a string; "0" with tif ioc for a market order |
tif |
gtc, ioc, poc (post-only), fok |
text |
t- + FastMM's 14-character id; Gate requires the prefix |
reduce_only |
when the engine sets it |
The venue answers an order request twice: {"ack":true} when it took it, then the result or data.errs with a label and message. The engine's ack comes from the result (emit_ack_from_response) or from the orders channel's first open. Cancel and amend name the order by the venue's id once a reply gave it, else by its text.
Amend keeps the order in place. A size increase moves it to the back of the queue.
Private channels¶
| channel | event | engine message |
|---|---|---|
orders |
finished, finish_as cancelled |
cancel ack, size - left filled |
orders |
finish_as ioc, stp, reduce_only, position_closed, reduce_out, liquidated, auto_deleveraged |
OrderExpired |
orders |
filled; open with a part filled |
nothing; fills come on usertrades |
usertrades |
a trade | fill: id the execution id, fee in the settle currency (a rebate negative), role the liquidity |
positions |
a position | compared with forwarded fills; corrects the engine when they differ for 1 s (position_from_stream) |
balances |
an item | asks for the balances again, at most once a second |
balances |
type fund, text starting with a subscribed contract |
Funding under <time_ms>:<contract> |
The connector completes a fill's cumulative and remaining quantity from its order shadow. The shape of a funding item's text is not documented: a payment the connector cannot place is not booked.
Reconciliation and fills¶
The fill replay runs first, then orders?status=open&contract=C&limit=100 per subscribed contract and positions?holding=true. They become one Begin, OpenOrder*, Position*, End sequence; a contract the positions do not list is flat.
| aspect | fill replay |
|---|---|
| query | GET /my_trades_timerange?from=&to=&limit=1000&offset= |
| scope | one stream for the account |
| window | a day a query, 30 days back |
| paging | newest first, by offset |
Balances¶
The balance leg reads GET /accounts after every snapshot, one row for the settle currency (Balances).
| field | source |
|---|---|
| free | available |
| locked | order_margin + position_margin |
| total | total |
| equity | total + unrealised_pnl |
| maintenance | maintenance_margin |
Dead man's switch¶
POST /countdown_cancel_all {"timeout":N} with dead_mans_switch_s is refreshed at a third of the window. It covers every contract of the account. A lapse kills the venue with DeadMansSwitchLost, and disconnect() sends timeout 0 on a blocking connection (Dead man's switch).
Rate limits¶
| limit | value |
|---|---|
| order placement and amend | 100 r/s per UID, WebSocket API and REST together |
| cancels | 200 r/s |
| other private endpoints | 200 r/10 s each |
| public endpoints | 200 r/10 s per endpoint and IP |
client-side orders_per_second |
default 50, on new orders and amends |
The limiter reads X-Gate-RateLimit-Requests-Remain and -Limit on REST (reset in seconds) and x_gate_ratelimit_* on the WebSocket API (reset in ms). A 429 or TOO_MANY_REQUESTS cools down until the reset.
Errors¶
| label | connector action |
|---|---|
INVALID_KEY, INVALID_SIGNATURE, IP_FORBIDDEN, READ_ONLY, FORBIDDEN, ACCOUNT_LOCKED, POSITION_DUAL_MODE |
fatal |
REQUEST_EXPIRED |
clock resync |
TOO_MANY_REQUESTS, TOO_BUSY |
rate limit |
SERVER_ERROR, INTERNAL |
back off |
ORDER_NOT_FOUND, ORDER_NOT_OWNED |
reconcile |
INSUFFICIENT_AVAILABLE |
insufficient balance |
ORDER_POC_IMMEDIATE |
post-only would cross |
SIZE_TOO_SMALL, SIZE_TOO_LARGE, PRICE_TOO_DEVIATED, INVALID_PRECISION |
lot, size and price rejects |
Not handled¶
futures.order_book_update, the REST-snapshot variant of the book.- Batch orders (
futures.order_batch_place) andfutures.order_cancel_ids. - The fractional lot step of a contract with
enable_decimal: the lot stays 1 contract. - The account book as a funding source.
- USD1- and BTC-settled contracts beyond the endpoint names.
- SBE market data (
/v4/ws/usdt/sbe).
Sources¶
Read 2026-10-03: Gate futures WebSocket (channels and the WebSocket API) and Gate APIv4 (signing, rate limits, labels).