4、交易所API对接:REST与WebSocket协议、鉴权机制、限频策略

做市引擎要跟交易所打交道,API对接就是那座桥。桥修不好,车就过不去。我见过太多团队,策略模型跑得漂亮,结果API一接就崩——要么连不上,要么被限频封了,要么鉴权失败。说白了,API对接是基本功,但也是最容易翻车的地方。

今天咱们就聊聊交易所API对接的三个核心问题:用什么协议、怎么证明你是谁、以及如何不被交易所拉黑。

4.1 REST vs WebSocket:什么时候用哪个?

交易所通常提供两种API:REST和WebSocket。很多人纠结选哪个,其实没那么复杂。

REST 是请求-响应模式。你问一句,它答一句。适合做查询、下单这种需要确认结果的操作。比如查账户余额、提交限价单,用REST就很合适。

WebSocket 是推送模式。你连上后,交易所主动给你推数据。适合做行情订阅、订单状态更新。你想想看,如果每秒要刷100次行情,用REST轮询,光请求头就够你受的。

我的经验: 我个人习惯把REST和WebSocket混着用。行情走WebSocket,下单走REST。为什么?因为WebSocket的鉴权一旦断了重连,中间可能漏掉订单状态更新,而REST每次请求都带鉴权,更可靠。

来看一个简单的对比:

特性 REST WebSocket
通信模式 请求-响应 全双工推送
延迟 较高(每次握手) 低(长连接)
适用场景 下单、查询 行情、订单推送
连接数 可并发多连接 通常限制1-2个

4.2 鉴权机制:别让你的API Key裸奔

交易所的鉴权,说白了就是证明「你是你」。常见的做法是API Key + Secret Key + 签名。

流程大概是这样的:

  1. 你在交易所后台生成一对Key:API Key(公开)和Secret Key(保密)
  2. 发请求时,把API Key、时间戳、请求参数拼成一个字符串
  3. 用Secret Key对这个字符串做HMAC-SHA256签名
  4. 把签名塞进请求头里发出去

嗯,这里要注意:时间戳很重要。交易所通常会检查时间戳是否在5秒内,防止重放攻击。我遇到过有人服务器时间不准,结果所有请求都被拒了。

避坑指南: 我曾经把Secret Key直接写死在代码里,结果不小心提交到了GitHub。十分钟后,账户里的币被洗劫一空。从那以后,我所有密钥都走环境变量或密钥管理服务。

来看一段Python示例:

import hmac
import hashlib
import time
import requests

def sign_request(api_key, secret_key, params):
    # 1. 加入时间戳
    params['timestamp'] = int(time.time() * 1000)
    
    # 2. 按字母序排序参数
    sorted_params = sorted(params.items())
    
    # 3. 拼接成字符串
    query_string = '&'.join([f"{k}={v}" for k, v in sorted_params])
    
    # 4. HMAC-SHA256签名
    signature = hmac.new(
        secret_key.encode(),
        query_string.encode(),
        hashlib.sha256
    ).hexdigest()
    
    # 5. 加入请求头
    headers = {
        'X-API-Key': api_key,
        'X-Signature': signature
    }
    
    return headers

# 使用示例
api_key = "your_api_key"
secret_key = "your_secret_key"
params = {'symbol': 'BTCUSDT', 'side': 'BUY', 'quantity': '0.01'}

headers = sign_request(api_key, secret_key, params)
response = requests.post(
    'https://api.exchange.com/v1/order',
    json=params,
    headers=headers
)

4.3 限频策略:别把交易所惹毛了

每个交易所都有限频规则。你发请求太快,它就会给你返回429 Too Many Requests,甚至直接封IP。

限频通常分两种:

  • IP限频: 每个IP每秒最多N次请求
  • 账户限频: 每个API Key每秒最多M次请求

不同交易所的限频规则差别很大。币安是每分钟1200次权重请求,OKX是每秒100次。你想想看,如果没搞清楚规则,策略一跑起来就撞墙。

我的建议: 别把限频当成束缚,把它当成保护。我习惯在代码里实现一个令牌桶算法,自己先限流,而不是等交易所来限我。

令牌桶的Python实现:

import time
import threading

class TokenBucket:
    def __init__(self, rate, capacity):
        self.rate = rate          # 每秒生成令牌数
        self.capacity = capacity  # 桶容量
        self.tokens = capacity    # 当前令牌数
        self.last_time = time.time()
        self.lock = threading.Lock()
    
    def acquire(self, tokens=1):
        with self.lock:
            # 先补充令牌
            now = time.time()
            elapsed = now - self.last_time
            self.tokens = min(
                self.capacity,
                self.tokens + elapsed * self.rate
            )
            self.last_time = now
            
            # 检查是否有足够令牌
            if self.tokens < tokens:
                return False
            
            self.tokens -= tokens
            return True

# 使用:每秒最多10次请求
bucket = TokenBucket(rate=10, capacity=10)

def safe_request(url, params):
    while not bucket.acquire():
        time.sleep(0.1)  # 等100ms再试
    return requests.get(url, params=params)

4.4 知识体系总览

说了这么多,咱们用一张图把核心逻辑串起来:

交易所API对接核心知识体系 协议选择 鉴权机制 限频策略 REST:下单/查询 WebSocket:行情/推送 API Key + Secret Key HMAC-SHA256签名 时间戳防重放 IP限频 账户限频 令牌桶算法 核心原则 协议选对、密钥藏好、限频做足 三者缺一不可,否则做市引擎跑不稳

4.5 实战中的那些坑

最后分享几个我踩过的坑:

  • WebSocket断线重连: 交易所的WebSocket连接不是永久的。我遇到过连接断了半小时,行情停了,策略还在傻傻地发单。解决方案是加心跳检测,5秒没收到数据就重连。
  • 签名参数顺序: 不同交易所对参数排序要求不一样。有的要按字母序,有的要按出现顺序。我建议写个通用签名函数,针对每个交易所做适配。
  • 限频重置时间: 有些交易所的限频窗口是滑动窗口,有些是固定窗口。固定窗口的话,整点重置时会有瞬间的请求洪峰,要注意平滑处理。

一个小技巧: 我习惯在代码里加个API调用日志,记录每次请求的耗时和返回码。这样出了问题,翻日志就能定位是网络问题、鉴权问题还是限频问题。

好了,API对接这块就聊到这儿。记住一句话:对接交易所,慢就是快。把协议、鉴权、限频这三个基本功打扎实了,后面的策略实现才能稳如老狗。

专注资料整理