第二章:市场选择与数据源——主流交易所介绍与API接入
做跨市场套利,第一步不是写策略,而是选对市场、拿对数据。这个道理我是在一次惨痛教训后才真正理解的——当时我花了两周搭建的套利模型,上线后发现两边数据时间戳差了整整3秒,结果可想而知。
今天我们就来聊聊,怎么选交易所、怎么接数据、怎么把数据洗干净对齐。这些都是基本功,但恰恰是这些基本功决定了你的套利系统能不能跑起来。
2.1 主流交易所:谁是你的菜?
目前全球交易量最大的三家交易所,分别是Binance、OKX和Coinbase。我个人的习惯是,做套利至少选两家,最好三家都接上。
| 交易所 | 特点 | 适合场景 | API限制 |
|---|---|---|---|
| Binance | 流动性最好,交易对最全 | 主流币种套利、高频策略 | 1200次/分钟(WebSocket无限制) |
| OKX | 深度不错,永续合约丰富 | 期现套利、跨品种套利 | 600次/分钟 |
| Coinbase | 合规性强,数据质量高 | 机构级策略、美股相关套利 | 300次/分钟 |
我的建议:新手先从Binance+OKX开始。这两家API文档写得清楚,社区资源也多。Coinbase的API相对严格,适合进阶。
2.2 API接入:从零开始拿数据
接入API其实不复杂,但有几个坑你得提前知道。我曾经因为没处理好API限频,被Binance封了IP整整24小时……嗯,那天的回测数据全废了。
2.2.1 REST API vs WebSocket
说白了,REST API就像你去问路,问一次答一次;WebSocket就像你开了个对讲机,对方一直跟你说话。
- REST API:适合获取历史数据、下单操作。请求-响应模式,简单可靠。
- WebSocket:适合实时行情订阅。数据推送模式,延迟低,但连接维护麻烦点。
我个人习惯是:历史数据用REST,实时行情用WebSocket。两者配合使用,效率最高。
2.2.2 代码示例:Binance实时行情订阅
下面这个例子,是我在项目中实际用过的简化版。它订阅BTC/USDT的实时成交数据,然后打印出来。
import asyncio
import websockets
import json
async def subscribe_binance_trade():
uri = "wss://stream.binance.com:9443/ws/btcusdt@trade"
async with websockets.connect(uri) as ws:
print("已连接到Binance WebSocket")
while True:
data = await ws.recv()
trade = json.loads(data)
print(f"价格: {trade['p']}, 数量: {trade['q']}, 时间: {trade['T']}")
asyncio.run(subscribe_binance_trade())
小技巧:WebSocket连接可能会断,记得加自动重连逻辑。我一般用asyncio的wait_for配合重试机制,效果不错。
2.3 数据清洗:脏数据是套利的头号杀手
你拿到的原始数据,基本不能直接用。为什么?因为交易所的数据里夹杂着各种异常——空值、重复、乱序、甚至错误的价格。
我记得有一次,OKX返回了一个价格为0的成交记录,我的策略直接触发了买入信号……还好是模拟盘。
2.3.1 常见脏数据类型
- 空值/缺失值:某个时间点的数据没返回
- 重复数据:同一条成交记录推送了两次
- 时间戳乱序:后发生的数据先到达
- 异常价格:明显偏离市场价(比如0、999999)
2.3.2 清洗流程
我一般按这个顺序处理:
- 去重:用交易ID或时间戳+价格组合去重
- 去空:删除价格或数量为空的记录
- 过滤异常:价格超出3倍标准差就剔除
- 排序:按时间戳升序排列
import pandas as pd
def clean_trade_data(df):
# 去重
df = df.drop_duplicates(subset=['trade_id'])
# 去空
df = df.dropna(subset=['price', 'quantity'])
# 过滤异常价格
mean_price = df['price'].mean()
std_price = df['price'].std()
df = df[(df['price'] > mean_price - 3*std_price) &
(df['price'] < mean_price + 3*std_price)]
# 排序
df = df.sort_values('timestamp')
return df
注意:过滤异常价格时,别用太严格的阈值。市场剧烈波动时,3倍标准差可能把真实数据也删掉了。我一般先用2倍标准差标记,人工确认后再决定是否删除。
2.4 数据对齐:套利的核心难点
数据对齐,说白了就是把不同交易所的数据放到同一个时间轴上。你想想看,Binance和OKX的服务器时间可能差了几十毫秒,如果不对齐,你看到的价差可能是假的。
2.4.1 时间戳对齐
我常用的方法是:
- 先获取各交易所的服务器时间,计算本地与服务器的时差
- 将所有数据的时间戳统一转为UTC
- 按固定的时间窗口(比如1秒、100毫秒)进行重采样
2.4.2 重采样示例
def resample_trades(df, freq='1S'):
# 将时间戳设为索引
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df = df.set_index('timestamp')
# 重采样:每秒取最后一笔成交价
resampled = df['price'].resample(freq).last()
return resampled
核心要点:对齐的精度决定了套利策略的成败。做高频套利,我一般用10毫秒级别的对齐;做中低频,1秒级别就够了。
2.5 本章知识体系总览
下面这张图,是我自己画的数据流框架。它展示了从交易所到策略引擎的完整链路。
这张图你看懂了吗?从上到下,数据从交易所流出,经过接入、清洗、对齐三层处理,最终变成可供策略使用的干净数据。每一步都不能省,省了就是给自己挖坑。
个人经验:数据清洗和对齐这部分,我建议你花至少40%的时间。策略逻辑可以改,但数据质量不行,一切都是白搭。我曾经因为时间戳没对齐,跑了一个月的回测全是假信号……那感觉,真不好受。
公众号:蓝海资料掘金营,微信deep3321