🚪 Gate.io Indonesia

Tutorial Lengkap Integrasi Gate.io API WebSocket untuk Push Data Real-Time

Gate.io WebSocket API menyediakan push data real-time level milidetik, mendukung channel Ticker, depth, dan trade untuk spot/kontrak. Artikel ini menjelaskan koneksi, subscripsi channel, parsing data, dan contoh kode Python & Node.js.

2026-07-12 · Demonjoy — Indonesia

WebSocket vs REST API: Mengapa Memilih Push Real-Time

Dimensi PerbandinganREST APIWebSocket
Cara获取数据Request主动 (polling)Receive被动 (push)
Latensi100-500ms (含 waktu request)1-10ms
Konsumsi bandwidthSetiap request含 header HTTP完整Setelah建立连接 hanya传输数据
Tekanan serverPolling频率高 tekanan大连接持久 lightweight
Skenario适用Query数据 historis监控行情 real-time, strategi量化

Kebutuhan核心 strategi量化 adalah数据 real-time latensi rendah. Jika Anda用 REST API polling 10次/detik untuk获取 harga BTC, setiap latensi 200ms, harga yang Anda看到永远滞后 dari harga真实市场. Dalam mode push WebSocket, perubahan价格在 1-10ms内送达, ini是要求最低 strategi频率高.


Arsitektur Koneksi WebSocket Gate.io

Gate.io menyediakan dua组端点 WebSocket:

Pasar Spot

端点URL
行情 real-timewss://api.gateio.ws/ws/v4/
连接备用wss://api.gateio.ws/ws/v4/?compress=true

Pasar Kontrak

端点URL
行情 real-timewss://fx-api.gateio.ws/ws/v4/
连接备用wss://fx-api.gateio.ws/ws/v4/?compress=true

Parameter ?compress=true启用压缩数据, direkomendasikan启用 untuk减少带宽占用大约 60%.


##建立连接 dan Mekanisme Heartbeat

Proses Koneksi Dasar

import websocket
import json

# WebSocket Spot
ws_url = "wss://api.gateio.ws/ws/v4/"

def on_open(ws):
    print("Koneksi已建立")
    # Setelah成功订阅连接 channel

def on_message(ws, message):
    data = json.loads(message)
    print(f"Menerima数据: {data}")

def on_error(ws, error):
    print(f"Error连接: {error}")

def on_close(ws, close_status_code, close_msg):
    print("Koneksi已关闭")

ws = websocket.WebSocketApp(
    ws_url,
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close
)

ws.run_forever()

Mekanisme Heartbeat保活

Koneksi WebSocket需要定期发送包 heartbeat防止超时断开:

ParameterNilai
间隔 heartbeat30秒
内容 heartbeat{"time": <timestamp>, "channel": "heartbeat"}
超时断开Tidak menerima响应 heartbeat 60秒后断开

Implementasi heartbeat Python:

import time
import threading

def send_heartbeat(ws):
    while True:
        try:
            heartbeat = {
                "time": int(time.time()),
                "channel": "heartbeat"
            }
            ws.send(json.dumps(heartbeat))
            time.sleep(30)
        except Exception as e:
            print(f"Gagal发送 heartbeat: {e}")
            break

#在 on_open中启动线程 heartbeat
def on_open(ws):
    threading.Thread(target=send_heartbeat, args=(ws,), daemon=True).start()

###自动重连断线

import time

def connect_with_retry(max_retries=5, retry_interval=5):
    retries = 0
    while retries < max_retries:
        try:
            ws = websocket.WebSocketApp(ws_url, ...)
            ws.run_forever()
        except Exception as e:
            retries += 1
            print(f"Gagal连接, {retry_interval}秒后重试 (第{retries}次)")
            time.sleep(retry_interval)
            retry_interval *= 2  #递增等待时间
    print("达到次数重试最大,停止连接")

Detail Subscripsi Channel

###格式消息 Subscripsi

Semua消息 subscripsi/unsubscribe采用格式统一:

{
    "time": <timestamp>,
    "channel": "<nama_channel>",
    "event": "<subscribe|unsubscribe>",
    "payload": [<parameter>]
}

Channel Pasar Spot

Channel Ticker — Harga Real-Time

{
    "time": 1689000000,
    "channel": "spot.tickers",
    "event": "subscribe",
    "payload": ["BTC_USDT", "ETH_USDT"]
}

格式数据返回:

{
    "time": 1689000000,
    "channel": "spot.tickers",
    "event": "update",
    "result": {
        "currency_pair": "BTC_USDT",
        "last": "65000.5",
        "change_percentage": "2.35",
        "high_24h": "66000",
        "low_24h": "63500",
        "volume_24h": "1250000000",
        "ask": "65001",
        "bid": "65000"
    }
}
FieldKeterangan
lastHarga成交最新
change_percentagePerubahan 24h
high_24h / low_24hHarga tertinggi/terendah 24h
volume_24hVolume trading 24h (denominasi USDT)
ask / bidHarga sell 1/buy 1最新

Channel Depth — Orderbook买卖 Real-Time

{
    "time": 1689000000,
    "channel": "spot.order_book_update",
    "event": "subscribe",
    "payload": ["BTC_USDT", "100ms"]
}

Frekuensi更新可选: 100ms, 1000ms. 100ms适用于策略频率高, 1000ms适用于监控一般.

数据返回:

{
    "result": {
        "s": 0,  // 0=update order buy, 1=update order sell
        "p": "65000.5",  // harga
        "v": "1.25",  // jumlah, 0表示order价位该被撤销
        "t": 1689000000123
    }
}

Channel Trade —记录成交 Real-Time

{
    "time": 1689000000,
    "channel": "spot.trades",
    "event": "subscribe",
    "payload": ["BTC_USDT"]
}

数据返回:

{
    "result": {
        "id": 123456789,
        "create_time": 1689000000,
        "side": "sell",
        "price": "65000.5",
        "amount": "0.125",
        "currency_pair": "BTC_USDT"
    }
}

Channel Pasar Kontrak

Ticker Kontrak

{
    "time": 1689000000,
    "channel": "futures.tickers",
    "event": "subscribe",
    "payload": ["BTC_USDT"]
}

Depth Kontrak

{
    "time": 1689000000,
    "channel": "futures.order_book_update",
    "event": "subscribe",
    "payload": ["BTC_USDT", "100ms"]
}

Trade Kontrak

{
    "time": 1689000000,
    "channel": "futures.trades",
    "event": "subscribe",
    "payload": ["BTC_USDT"]
}

Channel Update Position (需要认证)

{
    "time": 1689000000,
    "channel": "futures.positions",
    "event": "subscribe",
    "payload": ["BTC_USDT"]
}

Channel认证需要使用签名 Key API, lihat bagian “Akses Channel认证” di bawah.


Akses Channel认证 (数据私有)

Channel认证用于接收数据私有 level akun: update order, perubahan position, perubahan余额等.

Proses认证

1.生成签名:

signature = HMAC-SHA512(secret, channel + timestamp)

2.发送消息认证:

{
    "time": <timestamp>,
    "channel": "futures.positions",
    "event": "subscribe",
    "payload": ["BTC_USDT"],
    "auth": {
        "method": "api_key",
        "KEY": "your_api_key",
        "SIGN": "generated_signature"
    }
}

Implementasi认证 Python

import hmac
import hashlib
import time
import json

def create_auth_message(channel, payload, api_key, api_secret):
    timestamp = int(time.time())
    sign_content = channel + str(timestamp)
    signature = hmac.new(
        api_secret.encode('utf-8'),
        sign_content.encode('utf-8'),
        hashlib.sha512
    ).hexdigest()
    
    return {
        "time": timestamp,
        "channel": channel,
        "event": "subscribe",
        "payload": payload,
        "auth": {
            "method": "api_key",
            "KEY": api_key,
            "SIGN": signature
        }
    }

# Contoh penggunaan
auth_msg = create_auth_message(
    "futures.positions",
    ["BTC_USDT"],
    "your_api_key",
    "your_api_secret"
)
ws.send(json.dumps(auth_msg))

Implementasi认证 Node.js

const crypto = require('crypto');

function createAuthMessage(channel, payload, apiKey, apiSecret) {
    const timestamp = Math.floor(Date.now() / 1000);
    const signContent = channel + timestamp;
    const signature = crypto
        .createHmac('sha512', apiSecret)
        .update(signContent)
        .digest('hex');
    
    return {
        time: timestamp,
        channel: channel,
        event: 'subscribe',
        payload: payload,
        auth: {
            method: 'api_key',
            KEY: apiKey,
            SIGN: signature
        }
    };
}

ws.send(JSON.stringify(createAuthMessage(
    'futures.positions',
    ['BTC_USDT'],
    'your_api_key',
    'your_api_secret'
)));

Contoh Lengkap Python:监控 Harga Real-Time

import websocket
import json
import time
import threading
import hmac
import hashlib

class GateWebSocketClient:
    def __init__(self, api_key=None, api_secret=None):
        self.ws_url = "wss://api.gateio.ws/ws/v4/"
        self.api_key = api_key
        self.api_secret = api_secret
        self.ws = None
        self.subscriptions = []
        self.running = False
    
    def on_open(self, ws):
        print("[连接] Koneksi WebSocket已建立")
        self.running = True
        #重新订阅 semua channel
        for sub in self.subscriptions:
            ws.send(json.dumps(sub))
        #启动 heartbeat
        threading.Thread(target=self._heartbeat, args=(ws,), daemon=True).start()
    
    def on_message(self, ws, message):
        try:
            data = json.loads(message)
            channel = data.get("channel", "")
            event = data.get("event", "")
            
            if channel == "heartbeat":
                return
            
            if event == "update":
                self._process_update(channel, data.get("result"))
            elif event == "subscribe":
                print(f"[订阅] {channel} subscripsi成功")
        except json.JSONDecodeError:
            print(f"[错误] Gagal解析消息: {message[:100]}")
    
    def on_error(self, ws, error):
        print(f"[错误] {error}")
    
    def on_close(self, ws, code, msg):
        print(f"[断开] Koneksi关闭: {code}")
        self.running = False
        #自动重连
        if self.subscriptions:
            time.sleep(3)
            self.connect()
    
    def subscribe_ticker(self, pairs):
        msg = {
            "time": int(time.time()),
            "channel": "spot.tickers",
            "event": "subscribe",
            "payload": pairs
        }
        self.subscriptions.append(msg)
        if self.ws:
            self.ws.send(json.dumps(msg))
    
    def subscribe_orderbook(self, pair, interval="100ms"):
        msg = {
            "time": int(time.time()),
            "channel": "spot.order_book_update",
            "event": "subscribe",
            "payload": [pair, interval]
        }
        self.subscriptions.append(msg)
        if self.ws:
            self.ws.send(json.dumps(msg))
    
    def _heartbeat(self, ws):
        while self.running:
            try:
                ws.send(json.dumps({
                    "time": int(time.time()),
                    "channel": "heartbeat"
                }))
                time.sleep(30)
            except:
                break
    
    def _process_update(self, channel, result):
        if channel == "spot.tickers":
            pair = result.get("currency_pair", "")
            last_price = result.get("last", "0")
            change = result.get("change_percentage", "0")
            print(f"[Ticker] {pair}: harga={last_price}, perubahan 24h={change}%")
        elif channel == "spot.order_book_update":
            side = "Buy" if result.get("s") == 0 else "Sell"
            price = result.get("p", "")
            volume = result.get("v", "")
            print(f"[Depth] update {side}: harga={price}, jumlah={volume}")
    
    def connect(self):
        self.ws = websocket.WebSocketApp(
            self.ws_url,
            on_open=self.on_open,
            on_message=self.on_message,
            on_error=self.on_error,
            on_close=self.on_close
        )
        threading.Thread(target=self.ws.run_forever, daemon=True).start()

# Contoh penggunaan
client = GateWebSocketClient()
client.subscribe_ticker(["BTC_USDT", "ETH_USDT", "SOL_USDT"])
client.subscribe_orderbook("BTC_USDT", "100ms")
client.connect()

time.sleep(60)  #运行 60秒演示

Saran Optimasi Performa

1.压缩数据

启用参数压缩减少大约 60% bandwidth:

ws_url = "wss://api.gateio.ws/ws/v4/?compress=true"

数据压缩需要使用 zlib解压:

import zlib

def on_message(self, ws, message):
    if isinstance(message, bytes):
        message = zlib.decompress(message).decode('utf-8')
    data = json.loads(message)

2. Batasi Jumlah Channel Subscripsi

Tingkat VIPJumlah Koneksi WebSocket最大Subscripsi channel最大 per连接
VIP0-2510
VIP3-41020
VIP5-62050

Hindari subscripsi过多 channel dalam satu连接. Saran按分组 strategi, setiap strategi satu连接独立.

3.缓存数据 Lokal

Untuk数据 depth, gunakan mode更新增量而非 setiap request完整 depth:

class OrderBookCache:
    def __init__(self):
        self.bids = {}  # {harga: volume}
        self.asks = {}
    
    def update(self, side, price, volume):
        book = self.bids if side == 0 else self.asks
        if float(volume) == 0:
            del book[price]  #价位该被清空
        else:
            book[price] = volume
    
    def get_best_bid(self):
        return max(self.bids.keys()) if self.bids else None
    
    def get_best_ask(self):
        return min(self.asks.keys()) if self.asks else None

4.处理异步

Setelah menerima数据 WebSocket, jangan执行操作耗时 dalam回调 on_message. Masukkan数据 ke queue,由线程独立处理:

from queue import Queue
import threading

data_queue = Queue()

def on_message(ws, message):
    data_queue.put(json.loads(message))

def process_data():
    while True:
        data = data_queue.get()
        #执行逻辑 strategi
        strategy.process(data)

threading.Thread(target=process_data, daemon=True).start()

Catatan dan Kesalahan Umum

1.限制连接数

Jangan超过 jumlah连接最大对应等级 VIP.连接多余会被 server拒绝.

2. Heartbeat必须持续

断开 heartbeat超过 60秒会被 server主动断开连接. Pastikan线程 heartbeat正常运行.

3.初始化数据 Depth

Channel depth WebSocket hanya推送更新增量.首次连接时需要通过 REST API获取快照完整 depth,然后叠加更新增量 WebSocket.

4. Presisi Timestamp

Gate.io WebSocket使用 timestamp level秒 (Unix timestamp), tidak是 level毫秒. Saat签名注意使用 int(time.time())而非值毫秒.

5.重新订阅后重连

Setiap重连后需要重新发送消息 subscripsi. Koneksi WebSocket是临时,状态 subscripsi不会在重连后保留.


FAQ

Q: Koneksi WebSocket经常断开怎么办? A: Pastikan heartbeat正常发送 (setiap 30秒一次). Jika仍然断开, periksa稳定性网络,增加逻辑重连并递增等待时间.

Q:同时订阅行情 spot dan kontrak需要两个连接吗? A: Ya. Spot dan kontrak使用端点 WebSocket不同,需要分别建立连接.

Q:签名 timestamp channel认证有有效期吗? A: Timestamp dalam签名必须在时间 server ±5秒范围内. Jika偏差时间 client大,需要先通过 REST API获取时间 server校准.

Q: volume 0 dalam更新 depth代表什么? A: Volume 0表示order价位该已被完全撤销. Dalam缓存 lokal应该删除价位该.

Q: Bagaimana获取数据 K线 historis? A:数据 K线不支持推送 real-time WebSocket,需通过 REST API获取.端点: GET /api/v4/spot/candlesticks


Kesimpulan

WebSocket是基石 trading量化. Gate.io WebSocket API设计规范, mendukung dua市场 spot dan kontrak, mencakup channel核心数据 seperti Ticker, depth, trade, position等.要点接入:

1.架构端点双: Spot dan kontrak分别连接 2.Heartbeat保活:间隔 30秒防止超时断开 3.Depth增量:首次获取快照完整 +后续叠加增量 4.签名认证:签名 HMAC-SHA512接入 channel私有 5.处理异步: Queue数据解耦逻辑接收和处理

Setelah掌握接入 WebSocket, Anda dapat构建系统监控行情 real-time level milidetik,为 strategi量化提供输入数据市场最及时. Ini是 langkah pertama构建系统交易高效.

Gate.io — Indonesia

Low fees, GoPay support.

Mulai Trading Aman di Gate.io →