2、数据源接入基础:REST API 与 WebSocket 协议对比、交易所 API 鉴权机制、数据源连接池管理
做量化交易,第一步就是搞定数据源。没有数据,策略就是空中楼阁。今天咱们聊聊数据源接入的几个核心问题:选什么协议、怎么鉴权、如何管理连接池。
2.1 REST API 与 WebSocket:两种协议的实战选择
我个人习惯把这两个协议比作「打电话」和「挂电话」。REST API 是你主动打过去问行情,WebSocket 是交易所主动给你推送行情。听起来好像 WebSocket 更高级?其实各有各的用武之地。
2.1.1 REST API:简单可靠,但别滥用
REST API 说白了就是 HTTP 请求。你发一个 GET 请求,交易所返回 JSON 数据。优点是简单、调试方便、任何语言都能用。
适用场景:
- 获取历史K线数据(比如回测用)
- 查询账户余额、持仓信息
- 下单、撤单等交易操作
- 低频行情快照(比如每分钟查一次)
我在项目中遇到过一个问题: 有个同事用 REST API 轮询行情,每秒请求一次。结果交易所直接封了 IP。为什么?因为 REST API 有频率限制。大部分交易所对 REST 接口的限制是每秒 1-10 次,超过就给你 429 错误码。
2.1.2 WebSocket:实时推送,但连接维护有讲究
WebSocket 是长连接。建立一次连接后,交易所会持续推送数据给你。延迟低、带宽省,适合高频行情。
适用场景:
- 实时 tick 级行情订阅
- 订单簿深度更新
- 交易对状态变化通知
- 需要毫秒级响应的策略
你想想看,如果做高频交易,用 REST API 轮询,等你拿到数据黄花菜都凉了。WebSocket 才是正解。
但 WebSocket 有个坑: 连接会断。网络波动、交易所重启、防火墙超时,都可能断开。所以必须实现心跳检测和自动重连机制。
2.1.3 协议对比表
| 对比维度 | REST API | WebSocket |
|---|---|---|
| 通信模式 | 请求-响应 | 订阅-推送 |
| 延迟 | 100-500ms | 10-50ms |
| 带宽消耗 | 高(每次全量数据) | 低(增量推送) |
| 连接数 | 可并发多个 | 通常限制 1-5 个 |
| 适用场景 | 低频、历史数据、交易 | 实时行情、高频策略 |
| 容错性 | 天然支持重试 | 需自行实现重连 |
2.2 交易所 API 鉴权机制:别让密钥裸奔
鉴权这事儿,说白了就是证明「你是你」。交易所 API 鉴权主要有三种方式,我按安全等级排个序。
2.2.1 API Key + Secret Key(最常用)
这是最基础的鉴权方式。交易所给你一对密钥:API Key 是公开的,Secret Key 是私密的。每次请求时,用 Secret Key 对参数签名,交易所验证签名是否匹配。
签名流程:
- 拼接请求参数(时间戳、API Key、请求体等)
- 用 Secret Key 做 HMAC-SHA256 签名
- 把签名放在请求头或参数里
# Python 示例:币安 API 签名
import hmac
import hashlib
import time
api_key = "your_api_key"
secret_key = "your_secret_key"
params = {
"symbol": "BTCUSDT",
"timestamp": int(time.time() * 1000)
}
# 拼接参数并签名
query_string = "&".join([f"{k}={v}" for k, v in sorted(params.items())])
signature = hmac.new(
secret_key.encode(),
query_string.encode(),
hashlib.sha256
).hexdigest()
params["signature"] = signature
headers = {"X-MBX-APIKEY": api_key}
2.2.2 JWT Token(较新趋势)
有些交易所开始用 JWT(JSON Web Token)。你拿 API Key 换一个临时 Token,后续请求带 Token 就行。Token 有过期时间,到期需要重新获取。
好处是:Token 泄露了也只是临时有效,不像 Secret Key 那样永久有效。坏处是:需要额外维护 Token 的刷新逻辑。
2.2.3 OAuth 2.0(第三方应用常用)
如果你做的是第三方量化平台,需要用户授权你的应用访问他的交易所账户,那就用 OAuth 2.0。用户授权后,你拿到一个 Access Token,用它来操作。
这个机制在量化场景用得少,因为大部分量化交易者都是自己管理密钥。
2.3 数据源连接池管理:别让连接成为瓶颈
连接池管理,说白了就是「复用连接」。每次请求都新建连接,效率太低。尤其 WebSocket 长连接,建立一次成本很高。
2.3.1 为什么需要连接池?
我举个例子:假设你订阅了 10 个交易对的实时行情。如果每个交易对都开一个 WebSocket 连接,那就是 10 个连接。交易所通常限制连接数,比如币安限制每个 IP 最多 5 个 WebSocket 连接。怎么办?
答案是用连接池。一个连接订阅多个交易对,通过消息通道区分。
2.3.2 连接池的核心参数
| 参数 | 说明 | 推荐值 |
|---|---|---|
| 最大连接数 | 同时保持的连接上限 | 交易所限制的 80% |
| 最小空闲连接 | 保持空闲连接数,避免频繁创建 | 2-5 个 |
| 连接超时 | 建立连接的最大等待时间 | 5-10 秒 |
| 空闲超时 | 空闲连接多久后关闭 | 60 秒 |
| 最大重试次数 | 连接失败后的重试次数 | 3 次 |
2.3.3 实战:WebSocket 连接池实现思路
嗯,这里要注意。连接池不是简单的「创建一堆连接放着」。你需要考虑:
- 连接复用: 多个订阅共享一个连接,通过订阅 ID 区分
- 健康检查: 定期发 ping 检测连接是否存活
- 自动重连: 断连后自动从池中移除,创建新连接
- 负载均衡: 把订阅均匀分配到不同连接上
# 伪代码:WebSocket 连接池管理
class WebSocketPool:
def __init__(self, max_connections=5):
self.pool = []
self.max_connections = max_connections
def get_connection(self):
# 找空闲连接
for conn in self.pool:
if conn.is_idle() and conn.is_alive():
return conn
# 没有空闲,创建新连接
if len(self.pool) < self.max_connections:
conn = self._create_connection()
self.pool.append(conn)
return conn
# 连接池满了,等待或报错
raise ConnectionPoolExhausted()
def _create_connection(self):
# 建立 WebSocket 连接
# 设置心跳、重连回调
pass
def health_check(self):
# 定期检查连接状态
for conn in self.pool:
if not conn.is_alive():
conn.reconnect()
websockets 库配合 asyncio,Java 用 Netty,Go 用 gorilla/websocket。这些库都内置了连接池和重连机制,比自己写稳定得多。
2.4 本章小结
数据源接入看似简单,其实坑不少。选协议要看场景:低频用 REST,高频用 WebSocket。鉴权要保护好密钥,别裸奔。连接池要管理好,别让连接成为瓶颈。
我个人觉得,最容易被忽视的是连接池的健康检查。很多系统上线后突然断连,就是因为没做心跳检测。嗯,这个坑我踩过,希望你别踩。