WebSocket 应用示例
# !/usr/bin/env python
# coding: utf-8
import hashlib
import hmac
import json
import logging
import time
# pip install -U websocket_client
from websocket import WebSocketApp
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class GateWebSocketApp(WebSocketApp):
def __init__(self, url, api_key, api_secret, **kwargs):
super(GateWebSocketApp, self).__init__(url, **kwargs)
self._api_key = api_key
self._api_secret = api_secret
def _send_ping(self, interval, event):
while not event.wait(interval):
self.last_ping_tm = time.time()
if self.sock:
try:
self.sock.ping()
except Exception as ex:
logger.warning("send_ping routine terminated: {}".format(ex))
break
try:
self._request("spot.ping", auth_required=False)
except Exception as e:
raise e
def _request(self, channel, event=None, payload=None, auth_required=True):
current_time = int(time.time())
data = {
"time": current_time,
"channel": channel,
"event": event,
"payload": payload,
}
if auth_required:
message = 'channel=%s&event=%s&time=%d' % (channel, event, current_time)
data['auth'] = {
"method": "api_key",
"KEY": self._api_key,
"SIGN": self.get_sign(message),
}
data = json.dumps(data)
logger.info('request: %s', data)
self.send(data)
def get_sign(self, message):
h = hmac.new(self._api_secret.encode("utf8"), message.encode("utf8"), hashlib.sha512)
return h.hexdigest()
def subscribe(self, channel, payload=None, auth_required=True):
self._request(channel, "subscribe", payload, auth_required)
def unsubscribe(self, channel, payload=None, auth_required=True):
self._request(channel, "unsubscribe", payload, auth_required)
def on_message(ws, message):
# type: (GateWebSocketApp, str) -> None
# handle whatever message you received
logger.info("message received from server: {}".format(message))
def on_open(ws):
# type: (GateWebSocketApp) -> None
# subscribe to channels interested
logger.info('websocket connected')
ws.subscribe("spot.trades", ['BTC_USDT'], False)
if __name__ == "__main__":
logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.DEBUG)
app = GateWebSocketApp("wss://api.gateio.ws/ws/v4/",
"YOUR_API_KEY",
"YOUR_API_SECRET",
on_open=on_open,
on_message=on_message)
app.run_forever(ping_interval=5)
package main
import (
"crypto/hmac"
"crypto/sha512"
"crypto/tls"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/url"
"time"
"github.com/gorilla/websocket"
)
type Msg struct {
Time int64 `json:"time"`
Channel string `json:"channel"`
Event string `json:"event"`
Payload []string `json:"payload"`
Auth *Auth `json:"auth"`
}
type Auth struct {
Method string `json:"method"`
KEY string `json:"KEY"`
SIGN string `json:"SIGN"`
}
const (
Key = "YOUR_API_KEY"
Secret = "YOUR_API_SECRETY"
)
func sign(channel, event string, t int64) string {
message := fmt.Sprintf("channel=%s&event=%s&time=%d", channel, event, t)
h2 := hmac.New(sha512.New, []byte(Secret))
io.WriteString(h2, message)
return hex.EncodeToString(h2.Sum(nil))
}
func (msg *Msg) sign() {
signStr := sign(msg.Channel, msg.Event, msg.Time)
msg.Auth = &Auth{
Method: "api_key",
KEY: Key,
SIGN: signStr,
}
}
func (msg *Msg) send(c *websocket.Conn) error {
msgByte, err := json.Marshal(msg)
if err != nil {
return err
}
return c.WriteMessage(websocket.TextMessage, msgByte)
}
func NewMsg(channel, event string, t int64, payload []string) *Msg {
return &Msg{
Time: t,
Channel: channel,
Event: event,
Payload: payload,
}
}
func main() {
u := url.URL{Scheme: "wss", Host: "api.gateio.ws", Path: "/ws/v4/"}
websocket.DefaultDialer.TLSClientConfig = &tls.Config{RootCAs: nil, InsecureSkipVerify: true}
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
panic(err)
}
c.SetPingHandler(nil)
// read msg
go func() {
for {
_, message, err := c.ReadMessage()
if err != nil {
c.Close()
panic(err)
}
fmt.Printf("recv: %s\n", message)
}
}()
t := time.Now().Unix()
pingMsg := NewMsg("spot.ping", "", t, []string{})
err = pingMsg.send(c)
if err != nil {
panic(err)
}
// subscribe order book
orderBookMsg := NewMsg("spot.order_book", "subscribe", t, []string{"BTC_USDT"})
err = orderBookMsg.send(c)
if err != nil {
panic(err)
}
// subscribe positions
ordersMsg := NewMsg("spot.orders", "subscribe", t, []string{"BTC_USDT"})
ordersMsg.sign()
err = ordersMsg.send(c)
if err != nil {
panic(err)
}
select {}
}
Gate.hk 提供了一个简单而健壮的 Websocket API 来集成现货交易状态信息为您的业务或应用提供支持。
我们当前使用 Python
作为代码示例,将来会有更多语言示例支持!
代码示例位于右侧深色区域,您可以点击右上方的标签切换示例的编程语言。
Websocket 链接地址:
wss://api.gateio.ws/ws/v4/
我们提供了 WebSocket SDK 来帮助开发者进行业务复用。
SDK 的源代码 在 gatews (opens new window) GitHub 仓库。
2023-04-21
freeze
,freeze_change
,change_type
字段到 spot.cross_balances
频道推送2022-12-12
avg_deal_price
字段到 spot.orders
频道推送2022-12-07
freeze
,freeze_change
,change_type
字段到 spot.balances
频道推送2022-11-22
time_ms
到全部频道推送2022-07-05
spot.cross_loan
频道通知用户用户全仓保证金借款和利息更新2021-07-23
spot.cross_balances
频道来通知 全仓杠杆余额(cross margin balance) 更新text
字段在 spot.usertrades
服务通知中2021-04-27
spot.orders
, spot.balances
, spot.margin_balances
和 spot.funding_balances
服务通知中2021-03-17
t
在所有的 order book 频道的 result
中2021-01-26
WebSocket操作分为不同的频道。频道可以是公共的或私有的。 公共频道可以直接订阅,而私有频道需要使用Gate APIv4 密钥对进行身份验证(有关详细信息,请参阅下面的身份验证 (opens new window))。
所有频道都支持以下事件:
subscribe
由客户端发起。客户端使用此方法告诉服务器它对此频道感兴趣,并要求服务器在频道相关数据更改时通知 新数据。
unsubscribe
由客户端发起。客户端使用此方法告诉服务器它不再对此频道感兴趣,并停止发送任何进一步的频道更新。
update
由服务器发起。服务器使用此方法将更改的数据发送给所有订阅此频道的客户端。客户端不能使用此操作事件。
客户端请求示例
{
"time": 1611541000,
"id": 123456789,
"channel": "spot.orders",
"event": "subscribe",
"payload": ["BTC_USDT", "GT_USDT"],
"auth": {
"method": "api_key",
"KEY": "xxxx",
"SIGN": "xxxx"
}
}
从客户端发起的 subscribe
或 unsubscribe
请求都是通用 JSON 格式且包含以下字段:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
time | Integer | 是 | 精确到秒的请求时间。请求时间和服务器时间之间的间隔不能超过60秒。 |
id | Integer | 否 | 请求 id(可选),服务器将此 id 发送回来,用来帮助您确定服务器响应哪个请求 |
channel | String | 是 | 需要订阅的 websocket 频道 |
auth | Auth | 否 | 私有频道的身份验证凭证。详见 身份验证(Authentication) 细节部分 |
event | String | 是 | 频道的操作事件。例如 subscribe , unsubscribe |
payload | Any | 否 | 请求详细参数(可选) |
注意,payload
的类型是基于 channel 的,不同 channel 需要的 payload 参数不同。但 subscribe
和 unsubscribe
的 payload 在同一个 channel 中使用的格式都是相同的。
以 spot.orders
频道为例,此频道需要的 payload 格式是一个货币列表。你可以指定 ["BTC_USDT", "ETH_USDT", "etc"]
作为 subscribe
的 payload 以接收关于这些货币对的订单更新通知。然后在 unsubscribe
payload 中指定 ["etc"]
来去掉这个货币对的订单更新通知。
为了简单起见,下面的频道(channel)描述只给出对应频道的 payload 格式,但是您需要发送完整的请求来执行频道订阅操作。
服务端响应示例
{
"time": 1611541000,
"channel": "spot.orders",
"event": "subscribe",
"error": null,
"result": {
"status": "success"
}
}
服务端响应包括对 客户端请求的响应 和 服务端发起的更新消息通知。 与请求类似,服务端响应与客户端请求格式都是几乎相同的 JSON 格式:
字段 | 类型 | 描述 |
---|---|---|
time | Integer | 精确到秒的响应时间 |
id | Integer | 从客户端请求 payload 中提取的请求 ID (如果请求参数中有的话) |
channel | String | WebSocket 频道名称 |
event | String | 服务端频道事件(即,update )或 用于从客户端发起的请求的 event |
error | Error | 如果服务端正常接受客户端的请求,则返回为空;否则,返回请求被拒绝的详情。 |
result | Any | 返回来自服务端的新数据通知 或 对客户端请求的响应。如果有错误返回则 error 不为空,没有错误则此字段为空。 |
注意:如果它是服务端发起的数据更新通知 那么 result
的类型是基于 channel 的,不同 channel 的 result
类型有所不同。
但如果是对客户端订阅请求的响应,那么 result
为固定的 {"status": "success"}
。
验证订阅请求是否成功,您只需要检查 error
字段是否为空即可,不需要再解析 result
字段。
为了简单起见,下面的频道(channel)描述只给出对应频道的 payload 格式。
错误对象的格式如下:
字段 | 类型 | 描述 |
---|---|---|
code | Integer | 错误码 |
message | String | 错误详情描述 |
请求异常时,服务端返回的消息会包含一个 error
对象,包括对应的错误码和具体的错误信息:
code | message |
---|---|
1 | Invalid request body format(无效请求格式) |
2 | Invalid argument provided(提供的参数无效) |
3 | Server side error happened.(服务端发生异常) |
WARNING
注意:您使用的 GateAPIv4 密钥对至少开了 spot(现货) read(读)权限, 如果启用密钥白名单,则您的出方向 IP 地址必须在密钥的 IP 白名单中。
# example WebSocket signature calculation implementation in Python
import hmac, hashlib, json, time
def gen_sign(channel, event, timestamp):
# GateAPIv4 key pair
api_key = 'YOUR_API_KEY'
api_secret = 'YOUR_API_SECRET'
s = 'channel=%s&event=%s&time=%d' % (channel, event, timestamp)
sign = hmac.new(api_secret.encode('utf-8'), s.encode('utf-8'), hashlib.sha512).hexdigest()
return {'method': 'api_key', 'KEY': api_key, 'SIGN': sign}
request = {
'id': int(time.time() * 1e6),
'time': int(time.time()),
'channel': 'spot.orders',
'event': 'subscribe',
'payload': ["BTC_USDT", "GT_USDT"]
}
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
print(json.dumps(request))
如果频道是私有的,例如 spot.orders
频道用于获取用户订单更新,那么客户端请求需要携带身份验证信息。
身份验证由请求体中的 auth
字段发送,格式如下:
字段 | 类型 | 描述 |
---|---|---|
method | String | 身份验证方法。目前只接受一个方法 api_key |
KEY | String | Gate APIv4 用户 key 字符串 |
SIGN | String | 使用 GateAPIv4 secret 和请求信息生成的认证签名 |
WebSocket 认证使用与 Gate APIv4 API 相同的签名计算方法,即:
HexEncode(HMAC_SHA512(secret, signature_string))
,但有以下区别:
channel=<channel>&event=<event>&time=<time>
,
这里的 <channel>
, <event>
, <time>
对应的请求信息auth
字段的请求主体中发送。您可以登录到控制台查看 Gate APIv4 密钥和秘密.
系统API用于检索服务元信息,不用于订阅。
spot.ping
代码示例
import time
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send('{"time": %d, "channel" : "spot.ping"}' % int(time.time()))
print(ws.recv())
响应示例
{
"time": 1545404023,
"channel": "spot.pong",
"event": "",
"error": null,
"result": null
}
检查与服务器的连接是否仍然存活。
这是一种额外的连接可达性检查。服务器使用协议层的ping/pong (opens new window)消息来检查客户端是否仍然连接。它不强制要求使用这种方法。如果您使用一些知名的WebSocket客户端库,通常不需要关心这个API。
然而,从客户端的角度来看,这个API可以帮助客户端主动检查与服务器的连接是否仍然可达。此外,如果服务器接收到客户端的spot.ping
请求,它还将重置客户端的超时计时器。
TIP
此频道不需要身份验证
spot.tickers
更新速度: 1000ms
Ticker是对现货交易状态的高级概览。它显示了最高、最低和最后的交易价格。它还包括每日成交量以及价格在过去一天内的变化情况等信息。
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.tickers",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 货币对列表 |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606291803,
"channel": "spot.tickers",
"event": "update",
"result": {
"currency_pair": "BTC_USDT",
"last": "19106.55",
"lowest_ask": "19108.71",
"highest_bid": "19106.55",
"change_percentage": "3.66",
"base_volume": "2811.3042155865",
"quote_volume": "53441606.52411221454674732293",
"high_24h": "19417.74",
"low_24h": "18434.21"
}
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | Ticker 对象 |
» currency_pair | String | 货币对 |
» last | String | 最新成交价 |
» lowest_ask | String | 卖方最低价 |
» highest_bid | String | 买方最高价 |
» change_percentage | String | 涨跌百分比,跌用负数标识,如 -7.45 |
» base_volume | String | 交易货币成交量 |
» quote_volume | String | 计价货币成交量 |
» high_24h | String | 24小时最高价 |
» low_24h | String | 24小时最低价 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.trades",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 货币对列表 |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606292218,
"channel": "spot.trades",
"event": "update",
"result": {
"id": 309143071,
"create_time": 1606292218,
"create_time_ms": "1606292218213.4578",
"side": "sell",
"currency_pair": "GT_USDT",
"amount": "16.4700000000",
"price": "0.4705000000",
"range": "2390902-2390902"
}
}
请注意,公共交易频道只通知交易中的吃单方。下面的私有用户交易频道将通知所有与用户相关的交易。
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | 公共成交详情 |
» id | Integer | 成交 ID |
» create_time | Integer | 成交时间,精确到秒 |
» create_time_ms | String | 成交时间,毫秒精度 |
» side | String | 买单或者卖单 |
» currency_pair | String | 交易货币对 |
» amount | String | 交易数量 |
» price | String | 交易价 |
» range | String | 成交范围(格式: "开始ID-结束ID") |
Property | Value |
---|---|
side | buy |
side | sell |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.candlesticks",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["1m", "BTC_USDT"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 订阅参数。从左到右是 interval , cp |
» interval | String | 是 | K线数据点间隔时间 |
» cp | String | 是 | 交易货币对 |
Property | Value |
---|---|
interval | 10s |
interval | 30s |
interval | 1m |
interval | 3m |
interval | 5m |
interval | 15m |
interval | 30m |
interval | 1h |
interval | 2h |
interval | 4h |
interval | 6h |
interval | 8h |
interval | 12h |
interval | 1d |
interval | 7d |
interval | 30d |
要订阅多个货币对或具有不同时间间隔的数据,只需发送多个带有不同参数的订阅请求即可。
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606292600,
"channel": "spot.candlesticks",
"event": "update",
"result": {
"t": "1606292580",
"v": "2362.32035",
"c": "19128.1",
"h": "19128.1",
"l": "19128.1",
"o": "19128.1",
"n": "1m_BTC_USDT",
"a": "3.8283"
}
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | K线数 |
» t | String | Unix 时间戳,精确到秒 |
» v | String | 交易量,只有市场行情的 K 线数据里有该值 |
» c | String | 收盘价 |
» h | String | 最高价 |
» l | String | 最低价 |
» o | String | 开盘价 |
» n | String | 订阅名称,格式为 <interval>_<cp> |
»a | String | 基础货币交易金额 |
深度有 3 个订阅频道,分别满足不同的需求。它们是:
spot.book_ticker
及时推送订阅货币对的最优卖/买(ask/bid)单。
spot.order_book_update
定时推送 深度增量更新数据,可用于维护本地深度。
spot.order_book
基于订阅的 level,定时推送深度全量更新
每个货币对的深度更新都有一个内部更新 ID,该 ID 在每个订单成交后递增 1。深度更新 ID 对应于 REST API 的 GET /api/v4/spot/order_book
响应中的ID
字段。
如何维护本地订单簿/深度:
以指定的 level 和更新频率订阅 spot.order_book_update
。
例如 ["BTC_USDT", "1000ms", "10"]
每 1s 推送 BTC_USDT 订单簿/深度的前10个的更新。
缓存 WebSocket 通知。每个通知用 U
和 u
来分别标识自上条通知的起始 ID 和最新 ID。
使用 REST API 获取基础订单簿/深度,并确保订单簿/深度 ID 被记录(下面称为baseID
)
例如使用:https://api.gateio.ws/api/v4/spot/order_book?currency_pair=BTC_USDT&limit=100&with_id=true
获取10个 BTC_USDT 基础深度。
迭代缓存的 WebSocket 通知,然后找到第一个包含baseID的,
例如U <= baseId+1
且 u >= baseId+1
,然后开始消费通知。注意 size
在通知里都是绝对值。 使用他们替换对应价格 price
中的原始 size
。
如果 size
等于 0,从订单簿/深度中删除价格。
转储所有满足要求的通知 u < baseID+1
。 如果 baseID+1 < first notification U
,那将
意味着当前基础深度已经落后当前的通知。从第三步重新开始获取最新的基础深度。
如其后有发现任何满足 U > baseID+1
的通知,那意味着一些更新通知丢失。需要从第三步开始重构本地深度。
SDK GitHub repository (opens new window) 中可以找到实现上述方法的示例的应用程序
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.book_ticker",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 交易货币对列表 |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606293275,
"channel": "spot.book_ticker",
"event": "update",
"result": {
"t": 1606293275123,
"u": 48733182,
"s": "BTC_USDT",
"b": "19177.79",
"B": "0.0003341504",
"a": "19179.38",
"A": "0.09"
}
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | Order book ticker object |
» t | Integer | 深度更新毫秒时间戳 |
» u | Integer | 深度更新ID |
» s | String | 货币对 |
» b | String | 最优买单价 |
» B | String | 最优买单数量 |
» a | String | 最优卖单价 |
» A | String | 最优卖单数量 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.order_book_update",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT", "100ms"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 订阅参数,从左到右是 cp , interval |
» cp | String | 是 | 货币对 |
» interval | String | 是 | 通知更新速度 |
Property | Value |
---|---|
interval | 100ms |
interval | 1000ms |
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606294781,
"time_ms": 1606294781236,
"channel": "spot.order_book_update",
"event": "update",
"result": {
"t": 1606294781123,
"e": "depthUpdate",
"E": 1606294781,
"s": "BTC_USDT",
"U": 48776301,
"u": 48776306,
"b": [
["19137.74", "0.0001"],
["19088.37", "0"]
],
"a": [["19137.75", "0.6135"]]
}
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | 自从上次更新变化后的卖买单列表(asks/bids) |
» t | Integer | 深度更新变化毫秒时间戳 |
» e | String | 忽略这个参数 |
» E | Integer | 深度更新时间戳(精确到秒).已经弃用,建议使用 t 字段 |
» s | String | 货币对 |
» U | Integer | 自动上次深度后的第一个深度 ID |
» u | Integer | 自动上次深度后的最新深度 ID |
» b | Array[OrderBookArray] | 自上次更新以来的 bids 更新,按价格从高到低排序 |
»» OrderBookArray | Array[String] | [Price, Amount] 数组对 |
» a | Array[OrderBookArray] | 自上次更新以来的 asks 更新,按价格从地到高排序 |
»» OrderBookArray | Array[String] | [Price, Amount] 数组对 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time": int(time.time()),
"channel": "spot.order_book",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT", "5", "100ms"]
}))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 订阅参数,从左到右分别是 cp , level , interval |
» cp | String | 是 | 货币对 |
» level | String | 是 | 深度长度 |
» interval | String | 是 | 通知更新速度 |
Property | Value |
---|---|
level | 5 |
level | 10 |
level | 20 |
level | 30 |
level | 50 |
level | 100 |
interval | 100ms |
interval | 1000ms |
TIP
此频道不需要身份验证
通知示例:
{
"time": 1606295412,
"time_ms": 1606295412213,
"channel": "spot.order_book",
"event": "update",
"result": {
"t": 1606295412123,
"lastUpdateId": 48791820,
"s": "BTC_USDT",
"bids": [
["19079.55", "0.0195"],
["19079.07", "0.7341"],
["19076.23", "0.00011808"],
["19073.9", "0.105"],
["19068.83", "0.1009"]
],
"asks": [
["19080.24", "0.1638"],
["19080.91", "0.1366"],
["19080.92", "0.01"],
["19081.29", "0.01"],
["19083.8", "0.097"]
]
}
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | Order book levels |
» t | Integer | 深度更新毫秒时间戳 |
» lastUpdateId | Integer | 深度副本当前的深度ID |
» s | String | 货币对 |
» bids | Array[OrderBookArray] | 在当前快照的 顶层 bids(买单) 数据,按价格从高到低排序 |
»» OrderBookArray | Array[String] | [Price, Amount] 数组对 |
» asks | Array[OrderBookArray] | 在当前快照的 顶层 asks(卖单) 数据,按价格从低到高排序 |
»» OrderBookArray | Array[String] | [Price, Amount] 数组对 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.orders",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT"]
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 货币对列表 |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
如果你想订阅全部货币对订单更新,你可以使用!all
来作为货币对列表参数。
WARNING
需要认证
通知示例:
{
"time": 1694655225,
"time_ms": 1694655225315,
"channel": "spot.orders",
"event": "update",
"result": [
{
"id": "399123456",
"text": "t-testtext",
"create_time": "1694655225",
"update_time": "1694655225",
"currency_pair": "BTC_USDT",
"type": "limit",
"account": "spot",
"side": "sell",
"amount": "0.0001",
"price": "26253.3",
"time_in_force": "gtc",
"left": "0.0001",
"filled_total": "0",
"avg_deal_price": "0",
"fee": "0",
"fee_currency": "USDT",
"point_fee": "0",
"gt_fee": "0",
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"create_time_ms": "1694655225315",
"update_time_ms": "1694655225315",
"user": 3497082,
"event": "put",
"stp_id": 0,
"stp_act": "-",
"finish_as": "open",
"biz_info": "-",
"amend_text": "-"
}
]
}
更新的订单列表。请注意,可能会在一条通知中更新多个货币对的订单。
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[Object] | 更新订单列表 |
» id | String | 订单 ID |
» user | Integer | 用户 ID |
» text | String | 用户自定义订单信息 |
» create_time | String | 订单创建时间,精确到秒 |
» create_time_ms | String | 订单创建时间,精确到毫秒 |
» update_time | String | 订单最新更新时间,精确到秒 |
» update_time_ms | String | 订单最新更新时间,精确到毫秒 |
» event | String | 订单事件 - put : 订单创建- update : 订单成交更新- finish : 订单关闭或者取消 |
» currency_pair | String | 交易货币对 |
» type | String | 订单类型. limit - 限价单 |
» account | String | 账户类型. spot - 现货账户; margin - 杠杆账户;cross_margin - 全仓杠杆账户 |
» side | String | 买单或者卖单 |
» amount | String | 交易数量 |
» price | String | 交易价 |
» time_in_force | String | Time in force 策略。 - gtc: GoodTillCancelled - ioc: ImmediateOrCancelled ,立即成交或者取消,只吃单不挂单 - poc: PendingOrCancelled,被动委托,只挂单不吃单 |
» left | String | 交易货币未成交数量 |
» filled_total | String | 已成交总金额 |
»avg_deal_price | String | 订单成交均价 |
» fee | String | 成交扣除的手续费 |
» fee_currency | String | 手续费计价单位 |
» point_fee | String | 手续费抵扣使用的点卡数量 |
» gt_fee | String | 手续费抵扣使用的 GT 数量 |
» gt_discount | Boolean | 是否开启GT抵扣 |
» rebated_fee | String | 返还的手续费 |
» rebated_fee_currency | String | 返还手续费计价单位 |
»auto_repay | Boolean | 启用或禁用跨保证金订单生成的自动借贷的自动还款功能。默认情况下禁用。请注意以下事项: 1. 该字段仅对跨保证金订单有效。保证金账户不支持为订单设置自动还款 2. auto_borrow 和 auto_repay 不能同时在同一订单中设置为 true. |
»auto_borrow | Boolean | 在杠杆或全仓杠杆交易中使用,以允许在余额不足时自动借入足够的金额 |
»stp_id | Integer | 具有相同stp_id 组的用户之间的订单不允许自成交。有关详细信息,请参阅ApiV4。 |
»stp_act | String | 自成交预防操作。用户可以使用此字段设置自成交预防策略。 |
»finish_as | String | 订单的完成状态说明如下. - open :正在处理 - filled :完全成交 - cancelled :手动取消- ioc :时效性为IOC ,立即完成- stp :因自成交预防而取消 |
»amend_text | String | 用户在修改订单时添加的自定义数据。 |
Property | Value |
---|---|
类型 | limit |
类型 | market |
类型 | limit_repay |
类型 | market_repay |
类型 | limit_borrow |
类型 | market_borrow |
类型 | limit_borrow_repay |
account | spot |
account | margin |
account | portfolio |
side | buy |
side | sell |
time_in_force | gtc |
time_in_force | ioc |
time_in_force | poc |
spot.usertrades
更新速度: 实时
通知用户在指定货币对中的个人交易。与spot.trades
频道不同,这是一个私有频道,并通知与用户相关的所有交易,不论交易角色(Maker/Taker)如何。
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.usertrades",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload": ["BTC_USDT"]
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
订阅参数格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | 货币对列表 |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
如果你想订阅全部用户合约成交更新,你可以使用 !all
来作为合约列表参数。
WARNING
需要认证
通知示例:
{
"time": 1605176741,
"channel": "spot.usertrades",
"event": "update",
"result": [
{
"id": 5736713,
"user_id": 1000001,
"order_id": "30784428",
"currency_pair": "BTC_USDT",
"create_time": 1605176741,
"create_time_ms": "1605176741123.456",
"side": "sell",
"amount": "1.00000000",
"role": "taker",
"price": "10000.00000000",
"fee": "0.00200000000000",
"point_fee": "0",
"gt_fee": "0",
"text": "apiv4"
}
]
}
更新的用户交易列表。请注意,可能会在一条通知中更新多个货币对的交易。
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[UserTrade] | Updated user trades list |
» id | Integer | 成交 ID |
» user_id | Integer | 用户 ID |
» order_id | String | 关联的订单 ID |
» currency_pair | String | 交易货币对 |
» create_time | Integer | 成交时间,精确到秒 |
» create_time_ms | String | 成交时间,毫秒精度 |
» side | String | 买单或者卖单 |
» amount | String | 交易数量 |
» role | String | 交易角色 (maker/taker) |
» price | String | 交易价 |
» fee | String | 成交扣除的手续费 |
» fee_currency | String | 手续费计价单位 |
» point_fee | String | 手续费抵扣使用的点卡数量 |
» gt_fee | String | 手续费抵扣使用的 GT 数量 |
» text | String | 用户自定义信息 |
Property | Value |
---|---|
side | buy |
side | sell |
role | maker |
role | taker |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.balances",
"event": "subscribe", # "unsubscribe" for unsubscription
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
不需要 payload
WARNING
需要认证
通知示例:
{
"time": 1605248616,
"time_ms": 1605248616763,
"channel": "spot.balances",
"event": "update",
"result": [
{
"timestamp": "1667556323",
"timestamp_ms": "1667556323730",
"user": "1000001",
"currency": "USDT",
"change": "0",
"total": "222244.3827652",
"available": "222244.3827",
"freeze": "5",
"freeze_change": "5.000000",
"change_type": "order-create"
}
]
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[SpotBalance] | 新的余额更新列表 |
» timestamp | String | 余额更新时间戳戳,精确到秒 |
» timestamp_ms | String | 余额更新时间戳戳,精确到毫秒 |
» user | String | 用户 ID |
» currency | String | 变更的货币 |
» change | String | 变更数量 |
» total | String | 总现货余额 |
» available | String | 可用现货余额 |
»freeze | String | 冻结余额数量 |
»freeze_change | String | 余额锁定的变动金额 |
»change_type | String | 余额变动类型 - withdraw - deposit - trade-fee-deduct - order-create : 订单创建 - order-match : 订单成交更新 - order-update : 取消订单或修改订单 - margin-transfer - future-transfer - cross-margin-transfer - other |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.margin_balances",
"event": "subscribe", # "unsubscribe" for unsubscription
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
不需要 payload
WARNING
需要认证
通知示例:
{
"time": 1605248616,
"channel": "spot.margin_balances",
"event": "update",
"result": [
{
"timestamp": "1605248812",
"timestamp_ms": "1605248812123",
"user": "1000001",
"currency_pair": "BTC_USDT",
"currency": "BTC",
"change": "-0.002",
"available": "999.999836",
"freeze": "1",
"borrowed": "0",
"interest": "0"
}
]
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[MarginBalance] | 保证金余额更新列表 |
» timestamp | String | 保证金更新时间戳戳,精确到秒 |
» timestamp_ms | String | 保证金更新时间戳戳,精确到毫秒 |
» user | String | 用户 ID |
» currency_pair | String | 货币对 |
» currency | String | 变化货币 |
» change | String | 变更数量 |
» available | String | 可用保证金余额 |
» freeze | String | 锁定的金额,例如用于资金账簿 |
» borrowed | String | 借贷总额 |
» interest | String | 借款未付利息总额 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.funding_balances",
"event": "subscribe", # "unsubscribe" for unsubscription
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
不需要 payload
WARNING
需要认证
通知示例:
{
"time": 1605248616,
"channel": "spot.funding_balances",
"event": "update",
"result": [
{
"timestamp": "1605248616",
"timestamp_ms": "1605248616123",
"user": "1000001",
"currency": "USDT",
"change": "100",
"freeze": "100",
"lent": "0"
}
]
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[FundingBalance] | 借贷余额更新列表 |
» timestamp | String | 更新时间戳,精确到秒 |
» timestamp_ms | String | 更新时间戳,精确到毫秒 |
» user | String | 用户 ID |
» currency | String | 变更货币 |
» change | String | 变更数量 |
» freeze | String | 锁定的金额,例如用于资金账簿 |
» lent | String | 贷出款额 |
代码示例:
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.cross_balances",
"event": "subscribe", # "unsubscribe" for unsubscription
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
不需要 payload
WARNING
需要认证
通知示例:
{
"time": 1605248616,
"time_ms": 1605248616763,
"channel": "spot.cross_balances",
"event": "update",
"result": [
{
"timestamp": "1605248616",
"timestamp_ms": "1605248616123",
"user": "1000001",
"currency": "USDT",
"change": "100",
"total": "1032951.325075926",
"available": "1022943.325075926",
"freeze": "0",
"freeze_change": "0",
"change_type": "cross-margin-transfer"
}
]
}
通知结果格式:
字段 | 类型 | 描述 |
---|---|---|
result | Array[SpotBalance] | 余额更新列表 |
» timestamp | String | 更新时间戳,精确到秒 |
» timestamp_ms | String | 更新时间戳,精确到毫秒 |
» user | String | 用户 ID |
» currency | String | 变更货币 |
» change | String | 变更数量 |
» total | String | 总现货余额 |
» available | String | 可用余额 |
»freeze | String | 冻结余额数量 |
»freeze_change | String | 余额锁定的变动金额 |
»change_type | String | 余额变动类型 - withdraw - deposit - trade-fee-deduct - order-create : 订单创建 - order-match : 订单成交更新 - order-update : 取消订单或修改订单 - margin-transfer - future-transfer - cross-margin-transfer - other |
spot.cross_loan
更新速度: 实时
此频道已被弃用,因为数据已过时
通知用户交叉保证金借款和利息更新
任何交叉保证金借款或还款操作都会生成新的通知。
spot.cross_balances
(余额变动)频道,但spot.cross_balances
频道通知只包含余额变动(没有贷款信息),而此频道通知将包含余额、已借金额和利息信息。代码示例
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.cross_loan",
"event": "subscribe", # "unsubscribe" for unsubscription
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
不需要 payload
WARNING
需要认证
推送示例
{
"time": 1658289372,
"time_ms": 1658289372763,
"channel": "spot.cross_loan",
"event": "update",
"result": {
"timestamp": 1658289372338,
"user": "1000001",
"currency": "BTC",
"change": "0.01",
"total": "4.992341029566",
"available": "0.078054772536",
"borrowed": "0.01",
"interest": "0.00001375"
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | 新的全仓保证金借款和利息更新消息 |
»timestamp | int64 | 秒级时间戳 |
»user | String | 用户 ID |
»currency | String | 变更的货币 |
»change | String | 变更数量 |
»total | String | 总现货余额 |
»available | String | 可用余额 |
»borrowed | String | 已借金额 |
»interest | String | 从借款产生的未付利息总额 |
代码示例
import time
import json
# pip install websocket_client
from websocket import create_connection
ws = create_connection("wss://api.gateio.ws/ws/v4/")
request = {
"time": int(time.time()),
"channel": "spot.priceorders",
"event": "subscribe", # "unsubscribe" for unsubscription
"payload" : ["!all"],
}
# refer to Authentication section for gen_sign implementation
request['auth'] = gen_sign(request['channel'], request['event'], request['time'])
ws.send(json.dumps(request))
print(ws.recv())
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
payload | Array[String] | 是 | List of currency pairs |
您可以多次订阅/取消订阅。除非明确取消订阅,否则之前订阅的货币对不会被覆盖。
如果你想订阅全部货币对订单更新,你可以使用!all
来作为货币对列表参数。
WARNING
需要认证
推送示例
{
"time": 1691847986,
"time_ms": 1691847986454,
"channel": "spot.priceorders",
"event": "update",
"result": {
"market": "METAN_USDT",
"uid": "13679450",
"id": "247480109",
"currency_type": "METAN",
"exchange_type": "USDT",
"reason": "",
"err_msg": "",
"fired_order_id": 0,
"instant_cancel": false,
"trigger_price": "0.00302",
"trigger_rule": "<=",
"trigger_expiration": 900,
"price": "0.00300",
"amount": "26666.667",
"source": "",
"order_type": "limit",
"side": "buy",
"engine_type": "normal",
"is_stop_order": false,
"stop_trigger_price": "",
"stop_trigger_rule": "",
"stop_price": "",
"ctime": "1691517983131",
"ftime": "1691517983131"
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
result | Object | |
»market | String | 市场名称 |
»uid | String | 用户 ID |
»id | String | 订单 id |
»currency_type | String | 货币类型 |
»exchange_type | String | 交易货币类型 |
»reason | String | 订单结束的附加描述信息 |
»err_msg | String | 错误信息 |
»fired_order_id | int | 触发后委托单ID |
»instant_cancel | bool | 是否即时取消 |
»trigger_price | String | 触发价格 |
»trigger_rule | String | 触发规则 |
»trigger_expiration | int | 触发最长等待触发时间,超时则取消该订单,单位是秒 s |
»price | String | 挂单价格 |
»amount | String | 挂单数量 |
»source | String | source |
»order_type | String | 订单类型,目前默认为限价单 |
»side | String | 买卖方向 - buy: 买 - sell: 卖 |
»engine_type | String | 引擎类型 |
»is_stop_order | bool | 是否为止损单 |
»stop_trigger_price | String | 触发价格 |
»stop_trigger_rule | String | 触发规则 |
»stop_price | String | 止损价格 |
»ctime | String | 创建时间 |
»ftime | String | 结束时间 |
WebSocket API 允许通过 WebSocket 连接下单、取消、修改和查询订单。
客户端请求示例
span
客户端发起的api
请求遵循通用的JSON格式,包含以下字段:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
time | Integer | 是 | 请求时间(以秒为单位)。请求时间和服务器时间之间的差距不得超过60秒 |
id | Integer | 否 | 可选的请求ID,服务器将回传该ID,以帮助您识别服务器响应的是哪个请求 |
channel | String | 是 | WebSocket 要订阅的频道 |
event | String | 是 | 固定为"api" |
payload | Object | 是 | 可选的请求详细参数 |
»req_id | String | 是 | 由客户端提供的消息的唯一标识符。它将在响应消息中返回,用于识别相应的请求。 |
»req_param | []Byte | 是 | 请求的API参数 |
请注意,payload.req_param
的类型与频道相关。以spot.order_place
为例,payload.req_param
与apiv4的 /spot/orders (opens new window) 或 /spot/batch_orders (opens new window) 相同。 您可以使用示例在GT_USDT上下一个限价订单。
服务端 ack 推送示例
{
"request_id": "request-2",
"ack": true,
"header": {
"response_time": "1681985856667",
"status": "200",
"channel": "spot.order_place",
"event": "api",
"client_id": "::1-0x140033dc0c0"
},
"data": {
"result": {
"req_id": "request-2",
"req_header": null,
"req_param": {
"text": "t-my-custom-id",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1"
}
}
}
}
服务端 api 推送示例
{
"request_id": "request-2",
"header": {
"response_time": "1681986204784",
"status": "200",
"channel": "spot.order_place",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"id": "1700664330",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986204",
"update_time": "1681986204",
"create_time_ms": 1681986204832,
"update_time_ms": 1681986204832,
"status": "open",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "open"
}
}
}
服务器响应包括对客户端请求的确认响应和API结果的回调消息更新。 服务器响应遵循通用的JSON格式,包含以下字段:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。 如果"ack"为false,这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 如果这是一个"ack"响应,那么"result"是请求的有效载荷(payload),否则"result"是API的响应。 |
»errs | Object | 这只在请求失败时可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误消息详情 |
Error 推送示例
{
"request_id": "xxxx",
"ack": false,
"header": {
"response_time": "1677816784084",
"status": "401",
"channel": "spot.login",
"event": "api",
"client_id": "::1-0x14002ba2300"
},
"data": {
"errs": {
"label": "INVALID_KEY",
"message": "Invalid key provided"
}
}
}
错误对象的格式如下:
字段 | 类型 | 描述 |
---|---|---|
label | String | 以字符串格式表示错误类型 |
message | String | 错误信息详情 |
::: 警告: 注意:您使用的 GateAPIv4 密钥对必须具有相应的权限(例如,订单下单频道必须具有现货写入权限),并且如果启用了密钥的 IP 白名单,则您的出站 IP 地址必须在白名单中。 :::
代码示例
package main
import (
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"encoding/json"
"fmt"
"strconv"
"time"
)
func GetApiSignature(secret, channel string, requestParam []byte, ts int64) string {
hash := hmac.New(sha512.New, []byte(secret))
key := fmt.Sprintf("%s\n%s\n%s\n%d", "api", channel, string(requestParam), ts)
hash.Write([]byte(key))
return hex.EncodeToString(hash.Sum(nil))
}
// example WebSocket signature calculation implementation in go
func main() {
apiKey := "YOUR_API_KEY"
secret := "YOUR_API_SECRET"
requestParam := ""
channel := "spot.login"
ts := time.Now().Unix()
requestId := fmt.Sprintf("%d-%d", time.Now().UnixMilli(), 1)
req := ApiRequest{
Time: ts,
Channel: "",
Event: "api",
Payload: ApiPayload{
ApiKey: apiKey,
Signature: GetApiSignature(secret, channel, []byte(requestParam), ts),
Timestamp: strconv.FormatInt(ts, 10),
RequestId: requestId,
RequestParam: []byte(requestParam),
},
}
fmt.Println(GetApiSignature(secret, channel, []byte(requestParam), 1677813908) ==
"2a8d9735bc0fa5cc7db97841482f317b515663d2a666abe8518ab214efada11b3da77ddc1e5fde529d5f780efa3366e302f5e3d2f7670460ae115801442e7461")
marshal, _ := json.Marshal(req)
fmt.Println(string(marshal))
}
type ApiRequest struct {
App string `json:"app,omitempty"`
Time int64 `json:"time"`
Id *int64 `json:"id,omitempty"`
Channel string `json:"channel"`
Event string `json:"event"`
Payload ApiPayload `json:"payload"`
}
type ApiPayload struct {
ApiKey string `json:"api_key,omitempty"`
Signature string `json:"signature,omitempty"`
Timestamp string `json:"timestamp,omitempty"`
RequestId string `json:"req_id,omitempty"`
RequestParam json.RawMessage `json:"req_param,omitempty"`
}
请求示例
{
"time": 1681984544,
"channel": "spot.login",
"event": "api",
"payload": {
"api_key": "ea83fad2604399da16bf97e6eea772a6",
"signature": "6fa3824c8141f2b2283108558ec50966d7caf749bf04a3b604652325b50b47d2343d569d848373d58e65c49d9622ba2e73dc25797abef11c9f20c07da741591e",
"timestamp": "1681984544",
"req_id": "request-1"
}
}
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 请求ID将由服务器发送回,以帮助您识别服务器响应的是哪个请求,它与外部的id 不同 |
api_key | string | 是 | apiv4 key |
headers | object | 是 | apiv4 自定义 header |
signature | string | 是 | apiv4 签名 |
timestamp | string | 是 | Unix时间戳(以秒为单位) |
WebSocket API的操作身份验证使用与Gate APIv4 API相同的签名计算方法,即HexEncode(HMAC_SHA512(secret, signature_string))
,但有以下不同之处:
"<event>\n<channel>\n<req_param>\n<timestamp>"
,其中<event>
、<channel>
、<req_param>
、<timestamp>
是对应的请求信息。login
频道中的req_param
始终为空字符串。payload
发送。Login 推送示例
{
"request_id": "request-1",
"ack": false,
"header": {
"response_time": "1681985856666",
"status": "200",
"channel": "spot.login",
"event": "api",
"clientId": ""
},
"data": {
"result": {
"api_key": "ea83fad2604399da16bf97e6eea772a6",
"uid": "110284739"
}
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。 如果"ack"为false(false该字段不会出现在响应中),这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 如果这是"ack"响应,则"result"是请求的有效载荷,否则"result"是API的响应 |
»»api_key | String | 登录成功的 API 密钥 |
»»uid | String | 登录用户 ID |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
placeParam = {"text":"t-my-custom-id","currency_pair":"GT_USDT","type":"limit","account":"spot","side":"buy","amount":"1","price":"1"}
ws = create_connection("wss://api.gateio.ws/ws/v4/")
channel = "spot.order_place"
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": placeParam
}
}))
for i in range(2):
data = ws.recv()
print("data: ", data)
请求参数示例
{
"time": 1681986203,
"channel": "spot.order_place",
"event": "api",
"payload": {
"req_id": "request-2",
"req_param": {
"text": "t-my-custom-id",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1"
}
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id 不同 |
req_param | object | 是 | API订单模型的JSON字节数据,可以是包含API订单模型的数组;API订单模型的详细信息请参考API (opens new window) |
headers | object | 是 | apiv4 自定义 header |
单笔订单的 "ack" 推送示例
{
"request_id": "request-2",
"ack": true,
"header": {
"response_time": "1681986203814",
"status": "200",
"channel": "spot.order_place",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"req_id": "request-2",
"req_header": null,
"req_param": {
"text": "t-my-custom-id",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1"
},
"api_key": "",
"timestamp": "",
"signature": ""
}
}
}
订单数组的 "ack" 推送示例
{
"request_id": "xxxx",
"ack": true,
"header": {
"response_time": "1677810708738",
"status": "200",
"channel": "spot.order_place",
"event": "api",
"client_id": "::1-0x140002f63c0"
},
"data": {
"result": {
"req_id": "xxxx",
"req_header": null,
"req_param": [
{
"text": "t-my-custom-id",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1"
},
{
"text": "t-my-custom-id",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1"
}
]
}
}
}
下单 推送示例
单笔订单的推送示例
{
"request_id": "request-2",
"header": {
"response_time": "1681986204784",
"status": "200",
"channel": "spot.order_place",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"id": "1700664330",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986204",
"update_time": "1681986204",
"create_time_ms": 1681986204832,
"update_time_ms": 1681986204832,
"status": "open",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "open"
}
}
}
已更新的订单列表。请注意,可能会在一条通知中更新多个货币对的订单
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false(false该字段不会出现在响应中),这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 如果这是"ack"响应,则"result"是请求的有效载荷,否则"result"是API的响应 |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
time = int(time.time())
cancelParam = {"order_id":"1694883366","currency_pair":"GT_USDT"}
channel = "spot.order_cancel"
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": cancelParam
}
}))
print(ws.recv())
取消订单请求示例
{
"time": 1681986206,
"channel": "spot.order_cancel",
"event": "api",
"payload": {
"req_id": "request-5",
"req_param": {
"order_id": "1700664330",
"currency_pair": "GT_USDT"
}
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id不同。 |
req_param | object | 是 | 有关API取消订单的详细信息,请查看API (opens new window)。 |
取消订单推送示例
{
"request_id": "request-5",
"header": {
"response_time": "1681986206282",
"status": "200",
"channel": "spot.order_cancel",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"id": "1700664330",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986204",
"update_time": "1681986206",
"create_time_ms": 1681986204832,
"update_time_ms": 1681986206330,
"status": "cancelled",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "2",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "cancelled"
}
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false(false该字段不会出现在响应中),这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 单个订单取消的响应详细信息,请查看API (opens new window)。 |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
time = int(time.time())
cancelWithIdsParam = [{"id":"1694883366","currency_pair":"GT_USDT"}]
channel = "spot.order_cancel_ids"
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": cancelWithIdsParam
}
}))
print(ws.recv())
客户端请求示例
{
"time": 1681986208,
"channel": "spot.order_cancel_ids",
"event": "api",
"payload": {
"req_id": "request-9",
"req_param": [
{
"currency_pair": "GT_USDT",
"id": "1700664343"
}
]
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id不同。 |
req_param | object | 是 | 详情见 api (opens new window) |
取消订单推送示例
{
"request_id": "request-9",
"header": {
"response_time": "1681986208564",
"status": "200",
"channel": "spot.order_cancel_ids",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": [
{
"currency_pair": "GT_USDT",
"id": "1700664343",
"succeeded": true
}
]
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false(false该字段不会出现在响应中),这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 响应详见api (opens new window) |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
time = int(time.time())
cancelParam = {"side":"buy","currency_pair":"GT_USDT"}
channel = "spot.order_cancel_cp"
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": cancelParam
}
}))
print(ws.recv())
{
"time": 1681986207,
"channel": "spot.order_cancel_cp",
"event": "api",
"payload": {
"req_id": "request-7",
"req_param": {
"currency_pair": "GT_USDT",
"side": "buy"
}
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id不同。 |
req_param | object | 是 | detail toapi (opens new window) |
取消订单推送示例
{
"request_id": "request-7",
"header": {
"response_time": "1681986207412",
"status": "200",
"channel": "spot.order_cancel_cp",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": [
{
"id": "1700664337",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986206",
"update_time": "1681986207",
"create_time_ms": 1681986206384,
"update_time_ms": 1681986207444,
"status": "cancelled",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "cancelled"
}
]
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false(false该字段不会出现在响应中),这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 响应详情见api (opens new window) |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
time = int(time.time())
amendParam = {"order_id":"1694883366","currency_pair":"GT_USDT","price":"2"}
channel = "spot.order_amend"
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": amendParam
}
}))
print(ws.recv())
客户端请求示例
{
"time": 1681986206,
"channel": "spot.order_amend",
"event": "api",
"payload": {
"req_id": "request-4",
"req_param": {
"order_id": "1700664330",
"currency_pair": "GT_USDT",
"price": "2"
}
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id不同。 |
req_param | object | 是 | API修改订单,详细信息请参考api (opens new window) |
修改订单 推送示例
{
"request_id": "request-4",
"header": {
"response_time": "1681986206145",
"status": "200",
"channel": "spot.order_amend",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"id": "1700664330",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986204",
"update_time": "1681986206",
"create_time_ms": 1681986204832,
"update_time_ms": 1681986206176,
"status": "open",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "2",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "open"
}
}
}
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false,这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 响应详见api (opens new window) |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |
代码示例
#!/usr/bin/python
import time
import json
# pip install websocket_client
from websocket import create_connection
time = int(time.time())
statusParam = {"order_id":"1694883366","currency_pair":"GT_USDT"}
channel = "spot.order_status"
ws = create_connection("wss://api.gateio.ws/ws/v4/")
ws.send(json.dumps({
"time":time,
"channel":channel,
"event":"api",
"payload":{
"req_id":"test_1",
"req_param": statusParam
}
}))
print(ws.recv())
客户端请求示例
{
"time": 1681986205,
"channel": "spot.order_status",
"event": "api",
"payload": {
"req_id": "request-3",
"req_param": {
"order_id": "1700664330",
"currency_pair": "GT_USDT"
}
}
}
Payload 格式:
字段 | 类型 | 必选 | 描述 |
---|---|---|---|
req_id | string | 是 | 服务器将发送回的请求ID,用于帮助您识别服务器响应的是哪个请求,它与外部的id不同。 |
req_param | object | 是 | 详见api (opens new window) |
订单状态 推送示例
{
"request_id": "request-3",
"header": {
"response_time": "1681986205829",
"status": "200",
"channel": "spot.order_status",
"event": "api",
"client_id": "::1-0x140001623c0"
},
"data": {
"result": {
"id": "1700664330",
"text": "t-my-custom-id",
"amend_text": "-",
"create_time": "1681986204",
"update_time": "1681986204",
"create_time_ms": 1681986204939,
"update_time_ms": 1681986204939,
"status": "open",
"currency_pair": "GT_USDT",
"type": "limit",
"account": "spot",
"side": "buy",
"amount": "1",
"price": "1",
"time_in_force": "gtc",
"iceberg": "0",
"left": "1",
"fill_price": "0",
"filled_total": "0",
"fee": "0",
"fee_currency": "GT",
"point_fee": "0",
"gt_fee": "0",
"gt_maker_fee": "0.0015",
"gt_taker_fee": "0.0015",
"gt_discount": true,
"rebated_fee": "0",
"rebated_fee_currency": "USDT",
"stp_id": 1,
"stp_act": "cn",
"finish_as": "open"
}
}
}
已更新的订单列表。请注意,可能会在一条通知中更新多个货币对的订单。
推送格式:
字段 | 类型 | 描述 |
---|---|---|
request_id | String | 消息的唯一标识符 |
ack | Bool | "ack"消息的返回表示WebSocket的确认消息(目前在下单接口中存在)。如果"ack"为false,这意味着该消息是一个响应消息,您可以通过检查"data.errs"来确定请求是否成功。 |
header | Map | 响应的元信息 |
»response_time | String | 响应发送时间(以毫秒为单位) |
»channel | String | 请求的频道 |
»event | String | 请求事件 |
»client_id | String | 唯一客户端标识 ID |
data | Object | 签名时间(以秒为单位) |
»result | Object | 响应详见api (opens new window) |
»errs | Object | 只有在请求失败时才可用 |
»»label | String | 以字符串格式表示错误类型 |
»»message | String | 错误信息详情 |