3. 行情数据接口:Ticker、OrderBook、Kline、交易对信息、市场统计
行情数据,说白了就是市场的「心跳」。
做量化交易,你首先要能感知到市场在干什么。价格跳了、深度变了、成交量放大了——这些信号都藏在行情接口里。我个人习惯把行情数据分成五类:Ticker、OrderBook、Kline、交易对信息、市场统计。每一类都有它独特的用途,咱们一个一个说。
核心观点:行情接口是交易系统的「眼睛」。数据质量直接决定策略的成败。接口设计上,延迟、吞吐量、数据一致性是三个绕不开的坎。
3.1 Ticker —— 市场的「快照」
Ticker 是最基础的行情数据。它告诉你当前这个交易对「大概什么价」。我见过不少新手一上来就盯着 Ticker 做高频策略,结果亏得很惨。为什么?因为 Ticker 本质是一个汇总数据,它不保证你能按那个价格成交。
一个标准的 Ticker 接口,通常包含这些字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| symbol | string | 交易对,如 BTCUSDT |
| lastPrice | decimal | 最新成交价 |
| bidPrice | decimal | 买一价 |
| askPrice | decimal | 卖一价 |
| volume | decimal | 24小时成交量 |
| highPrice | decimal | 24小时最高价 |
| lowPrice | decimal | 24小时最低价 |
| openPrice | decimal | 24小时开盘价 |
| timestamp | long | 数据生成时间戳(毫秒) |
避坑指南:我曾经在对接某二线交易所时,发现它的 Ticker 里的 bidPrice 和 askPrice 居然不是实时更新的,而是每隔 5 秒才刷新一次。结果我的做市策略按这个价格挂单,全被吃掉了。所以,拿到 Ticker 数据后,一定要先压测一下它的更新频率。
接口设计上,我建议 Ticker 走 WebSocket 推送,而不是 REST 轮询。因为 Ticker 变化太快,轮询的延迟和带宽消耗都不划算。推送频率可以控制在 100ms 到 500ms 一次,具体看你的策略需求。
3.2 OrderBook —— 市场的「深度」
OrderBook 就是买卖挂单的集合。它告诉你「现在有多少人想买,多少钱想买;有多少人想卖,多少钱想卖」。做市商、套利策略、大单拆单,都离不开 OrderBook。
一个典型的 OrderBook 数据结构长这样:
{
"symbol": "BTCUSDT",
"bids": [
["45000.00", "1.5"],
["44999.50", "2.3"],
...
],
"asks": [
["45001.00", "0.8"],
["45001.50", "1.2"],
...
],
"lastUpdateId": 123456789,
"timestamp": 1690000000000
}
这里要注意,bids 和 asks 都是二维数组,每个元素是 [价格, 数量]。价格精度和数量精度由交易所决定,你设计接口时一定要预留足够的精度位。
重要提醒:OrderBook 的增量更新(incremental update)比全量推送更高效。但增量更新有个坑——数据顺序不能乱。我曾经在项目中遇到 WebSocket 断线重连后,增量数据丢失了几条,结果整个 OrderBook 就「歪」了。解决方案是:每次重连后,先拉一次全量快照,再切回增量模式。
我个人习惯把 OrderBook 的深度控制在 20 层以内。太深了,数据量大,延迟高;太浅了,信息不够用。20 层是一个比较平衡的点。
3.3 Kline / 蜡烛图 —— 市场的「历史」
Kline 是技术分析的基石。没有 K 线,你连均线都画不出来。Kline 接口的核心参数就两个:时间周期和数量。
常见的周期有:1m、5m、15m、30m、1h、4h、1d、1w、1M。每个周期对应一个时间窗口。
一个 Kline 数据项通常包含:
| 字段 | 类型 | 说明 |
|---|---|---|
| openTime | long | 这根 K 线的开盘时间 |
| open | decimal | 开盘价 |
| high | decimal | 最高价 |
| low | decimal | 最低价 |
| close | decimal | 收盘价 |
| volume | decimal | 成交量 |
| closeTime | long | 这根 K 线的收盘时间 |
| quoteVolume | decimal | 成交额(以报价币种计) |
| trades | int | 成交笔数 |
个人经验:Kline 的 REST 接口通常支持查询最近 500 到 1000 根 K 线。但如果你要回测,需要拉取几个月甚至几年的数据。这时候我建议你写一个数据抓取脚本,分批拉取,然后存到本地数据库里。别每次都从交易所拉,一来慢,二来容易被限流。
另外,Kline 的 WebSocket 推送是「增量」的——每根 K 线在未关闭前会不断更新。比如 1 分钟 K 线,在这一分钟内,价格每变动一次,交易所就会推送一次更新。你收到后,直接覆盖本地缓存里那根 K 线的 close、high、low 就行。
3.4 交易对信息 —— 市场的「规则」
交易对信息,说白了就是告诉你「这个币怎么交易」。每个交易所、每个交易对都有自己的规则。比如最小下单数量、价格精度、数量精度、最小名义价值等等。
这些信息如果不搞清楚,你的订单很可能被交易所拒绝。我见过有人因为精度问题,下单时价格多了一位小数,结果订单直接被拒,错过了行情。
一个标准的交易对信息接口返回:
{
"symbol": "BTCUSDT",
"status": "TRADING",
"baseAsset": "BTC",
"quoteAsset": "USDT",
"baseAssetPrecision": 8,
"quoteAssetPrecision": 8,
"filters": [
{
"filterType": "PRICE_FILTER",
"minPrice": "0.01",
"maxPrice": "1000000.00",
"tickSize": "0.01"
},
{
"filterType": "LOT_SIZE",
"minQty": "0.000001",
"maxQty": "100000",
"stepSize": "0.000001"
}
]
}
这里的关键字段是 filters。它定义了价格和数量的约束。你的下单模块在构造订单前,一定要先校验这些规则。我习惯在系统启动时,一次性拉取所有交易对信息,缓存到本地,然后每小时刷新一次。
注意:交易对信息不是一成不变的。交易所可能会调整精度、最小数量,甚至下架某个交易对。所以,你的系统要能处理「交易对状态变更」的事件。比如,当 status 变成 "BREAK" 或 "PAUSE" 时,你的策略应该自动停止对该交易对的操作。
3.5 市场统计 —— 市场的「体温」
市场统计接口,通常返回一些汇总指标。比如 24 小时涨跌幅、成交量、成交额、最高最低价、换手率等。这些数据对宏观判断很有用。
举个例子,你想知道今天市场整体情绪怎么样。看 BTC 的 24 小时涨跌幅和成交量变化,基本就能判断个大概。
市场统计接口的设计比较简单,通常就是 Ticker 的扩展版。但要注意,不同交易所对「24 小时」的定义可能不同。有的是滚动 24 小时,有的是从 0 点开始算。你设计系统时,最好统一用滚动 24 小时,这样数据更实时。
3.6 知识体系总览
下面这张图,是我对行情数据接口的整体理解。你可以把它当作一个「地图」,方便你快速定位每个接口的位置和作用。
这张图里,五个子节点分别对应我们刚才讲的五类数据。每个子节点下面,我都列出了它的核心字段和关键设计点。你可以把它当作一个「速查表」,在设计接口时对照着看。
3.7 接口设计的一些通用原则
最后,我想聊聊行情接口设计的几个通用原则。这些是我在多个项目中踩坑踩出来的经验。
- WebSocket 优先,REST 辅助。 行情数据变化快,WebSocket 推送是主流。REST 接口只用来做初始数据拉取和兜底。
- 数据压缩。 行情数据量很大,尤其是 OrderBook 和 Kline。建议用 gzip 或 snappy 压缩,能省 60% 以上的带宽。
- 时间戳统一。 所有接口的时间戳都用毫秒级 Unix 时间戳,避免时区问题。我见过有人用字符串格式的时间,结果解析起来各种坑。
- 限流与熔断。 行情接口也要限流。别以为行情数据是只读的就不需要限流。我曾经在测试环境里忘了加限流,结果把交易所的行情服务器打挂了……嗯,那天的复盘会开得特别长。
一个小技巧:如果你同时对接多个交易所,建议把行情数据统一成自己的内部格式。这样上层策略不用关心底层是哪个交易所,切换起来也方便。我习惯在数据接入层做一个「适配器」,把不同交易所的数据转成统一结构。
好了,行情数据接口就讲到这里。记住,数据是交易系统的血液。接口设计得好,策略跑起来就顺畅;设计得不好,后面全是坑。