3、交易所API基础:REST与WebSocket协议、API Key权限管理、限频策略

做量化交易,说白了就是跟交易所的服务器打交道。你发指令,它执行,然后给你回执。这个过程中,API就是你和交易所之间的「传话筒」。今天这一章,我就把API这块最核心的三个东西掰开揉碎了讲清楚。

3.1 REST与WebSocket:两种通信方式,各有各的脾气

先说说REST。REST协议就像你给交易所发邮件——你发一条请求,它回一条响应。一来一回,清清楚楚。我刚开始做量化时,第一版策略就是纯REST写的。为什么?因为简单啊,调试起来也方便。

但REST有个硬伤:慢。你想想看,每次查询行情都要发一次HTTP请求,网络延迟加上交易所处理时间,少说几十毫秒。做高频做市的话,这个延迟根本扛不住。

这时候WebSocket就派上用场了。WebSocket像是一条「专线」,你连上去之后,交易所会主动把数据推给你。不需要你一遍遍去问,它自己就来了。

核心区别一句话总结:

  • REST:请求-响应模式,适合下单、查询账户等低频操作
  • WebSocket:订阅-推送模式,适合行情、成交回报等实时数据

我在项目中遇到过一个问题:用REST去拉深度行情,每秒请求一次,结果交易所直接把我IP封了。后来改成WebSocket订阅深度,不仅数据实时了,还再也没触发过限频。

3.1.1 REST API 实战要点

REST API的调用其实不复杂,但有几个坑你得注意。

# 一个典型的REST下单请求(Python示例)
import requests
import time
import hashlib
import hmac

api_key = 'your_api_key'
secret_key = 'your_secret_key'
timestamp = int(time.time() * 1000)

# 构造签名
message = f'{timestamp}GET/api/v1/account'
signature = hmac.new(
    secret_key.encode(),
    message.encode(),
    hashlib.sha256
).hexdigest()

headers = {
    'X-API-KEY': api_key,
    'X-TIMESTAMP': str(timestamp),
    'X-SIGNATURE': signature
}

response = requests.get(
    'https://api.exchange.com/api/v1/account',
    headers=headers
)
print(response.json())

嗯,这里要注意签名算法。不同交易所的签名规则可能不一样,有的要拼接请求体,有的要拼接查询参数。我建议你写一个统一的签名工具函数,别在每个请求里重复写签名逻辑。

3.1.2 WebSocket 实战要点

WebSocket的连接管理比REST复杂一些。你想想看,一条连接可能要保持几个小时甚至几天,中间网络波动、服务器重启,连接随时可能断开。

# WebSocket订阅行情示例
import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    # 处理行情数据
    print(f"收到深度更新: {data['bids'][:3]}")

def on_error(ws, error):
    print(f"连接出错: {error}")
    # 这里要触发重连逻辑

def on_close(ws, close_status_code, close_msg):
    print("连接关闭,准备重连...")
    # 自动重连

def on_open(ws):
    # 订阅深度行情
    subscribe_msg = {
        "op": "subscribe",
        "args": ["depth.BTC-USDT"]
    }
    ws.send(json.dumps(subscribe_msg))

ws = websocket.WebSocketApp(
    "wss://ws.exchange.com/ws",
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close
)
ws.run_forever()

我曾经踩过的坑:WebSocket连接断了之后,如果没有自动重连机制,你的策略就变成了「瞎子」。行情停了,你还傻乎乎地在那做市,结果可想而知。所以,重连逻辑是必须的,而且重连后要重新订阅所有频道。

3.2 API Key权限管理:别把「家底」都交出去

API Key就像你家的钥匙。你会把家门钥匙随便给别人吗?肯定不会。但很多新手做量化时,直接把所有权限的API Key写在代码里,甚至上传到GitHub。这简直是引狼入室。

交易所通常提供以下几种权限:

权限类型 说明 建议
读取权限 查询账户余额、订单状态 必须开启
交易权限 下单、撤单 按需开启
提币权限 将资产转出交易所 强烈建议关闭

我个人习惯是:做市策略用的API Key,只开读取和交易权限。提币权限?想都别想。万一API Key泄露了,最多亏点手续费,不至于把币都丢了。

小技巧:给不同的策略分配不同的API Key。比如套利策略用一个Key,做市策略用另一个Key。这样如果某个Key出了问题,不会影响所有策略。

3.2.1 API Key的安全存储

千万别把API Key硬编码在代码里。我见过有人把Key写在Python文件里,然后传到GitHub公开仓库。第二天账户里的币就没了。

正确的做法是用环境变量或者配置文件:

# 使用环境变量(推荐)
import os
API_KEY = os.environ.get('EXCHANGE_API_KEY')
SECRET_KEY = os.environ.get('EXCHANGE_SECRET_KEY')

# 或者使用配置文件(记得加入.gitignore)
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
API_KEY = config['exchange']['api_key']

3.3 限频策略:别把交易所「惹毛」了

每个交易所都有限频规则。说白了,就是限制你在单位时间内能发多少请求。为什么?因为交易所的服务器资源有限,不能让你一个人把带宽占满了。

限频策略一般分两种:

  • IP限频:限制每个IP地址的请求频率
  • API Key限频:限制每个API Key的请求频率

我在项目中遇到过最头疼的事:做市策略需要频繁撤单和重新挂单,结果触发了交易所的限频,所有请求都被拒绝了。策略直接瘫痪,亏了不少钱。

3.3.1 如何优雅地处理限频

处理限频的核心思路就一个:控制请求节奏。别一股脑地发请求,要有节奏地发。

# 一个简单的限频控制类
import time
from collections import deque

class RateLimiter:
    def __init__(self, max_requests, time_window):
        self.max_requests = max_requests  # 最大请求数
        self.time_window = time_window    # 时间窗口(秒)
        self.request_times = deque()
    
    def wait_if_needed(self):
        now = time.time()
        # 移除时间窗口之外的记录
        while self.request_times and \
              self.request_times[0] < now - self.time_window:
            self.request_times.popleft()
        
        # 如果达到上限,等待
        if len(self.request_times) >= self.max_requests:
            wait_time = self.request_times[0] + \
                       self.time_window - now
            if wait_time > 0:
                time.sleep(wait_time)
        
        self.request_times.append(time.time())

# 使用示例
limiter = RateLimiter(max_requests=10, time_window=1)  # 每秒最多10次

def safe_request():
    limiter.wait_if_needed()
    # 发送实际请求
    response = requests.get('https://api.exchange.com/...')
    return response

避坑指南:我曾经犯过一个错误——只考虑了API Key限频,没考虑IP限频。结果多个策略共用同一个IP,每个策略都以为自己在限频范围内,但加起来就超了。后来我加了一个全局的IP级别限频器,问题才解决。

3.3.2 限频被触发后的处理

万一限频被触发了怎么办?别慌,大多数交易所会在响应头里告诉你限频信息:

# 从响应头中读取限频信息
response = requests.get('https://api.exchange.com/...')
remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
reset_time = int(response.headers.get('X-RateLimit-Reset', 0))

if remaining == 0:
    # 限频触发了,等待重置时间
    wait_time = reset_time - time.time()
    if wait_time > 0:
        print(f"限频触发,等待{wait_time}秒")
        time.sleep(wait_time)

嗯,这里有个细节:有些交易所的限频重置时间是Unix时间戳,有些是相对时间。你得看清楚文档,别搞混了。

3.4 本章知识体系

说了这么多,我把这一章的核心逻辑画成了一张图,方便你理解:

交易所API基础知识体系 通信协议 REST协议 • 请求-响应模式 • 适合低频操作 • 调试方便 WebSocket协议 • 订阅-推送模式 • 适合实时数据 • 需要重连机制 ⚠ 常见问题 • REST延迟高 • WebSocket断连 API Key权限管理 权限类型 • 读取权限(必须) • 交易权限(按需) • 提币权限(关闭) 安全存储 • 环境变量 • 配置文件 • 禁止硬编码 ⚠ 常见问题 • Key泄露 • 权限过大 限频策略 限频类型 • IP限频 • API Key限频 处理策略 • 请求节奏控制 • 限频检测 • 自动等待 ⚠ 常见问题 • 请求过于频繁 • 多策略叠加超限 三者缺一不可:通信协议是基础,权限管理是安全,限频策略是保障

这张图把三个核心模块的关系理清楚了。通信协议是基础,权限管理是安全底线,限频策略是稳定运行的保障。三者缺一不可。

我的建议:刚开始做多交易所做市时,别急着写策略。先把API调通,把限频处理好,把权限管好。基础打牢了,后面写策略才不会被这些「基础设施」问题绊倒。

好了,这一章就到这里。API这块东西看着简单,但细节很多。你动手写代码的时候,肯定会遇到各种奇怪的问题。别怕,慢慢调试,每个坑都是经验。


公众号:蓝海资料掘金营,微信deep3321