3. 数据获取:使用API获取实时汇率数据
做跨币种套利,第一步就是搞定数据。没有实时、准确的价格,后面所有策略都是空中楼阁。我个人习惯把数据获取比作「做饭前的买菜」——菜买不好,厨艺再好也白搭。
这一章,咱们就聊聊怎么从交易所和外汇市场拿到实时汇率数据。我会用 Binance、OKX 和 Forex 三个典型来源做例子,把代码和坑都摆出来。
3.1 为什么数据获取是套利策略的命门?
你想想看,价差套利赚的就是那零点几秒的差价。如果数据延迟了1秒,可能利润就没了,甚至变成亏损。我在项目中遇到过好几次,因为API调用频率限制,导致数据更新不及时,策略开仓后价格已经变了。
说白了,数据获取要满足三个核心要求:
- 实时性:延迟越低越好,最好在毫秒级
- 准确性:价格不能有偏差,尤其是深度数据
- 稳定性:API不能动不动就断,要有重连机制
核心原则:宁可错过一次交易机会,也不要因为错误数据做一次错误交易。
3.2 交易所API:Binance 和 OKX
加密货币交易所的API是最常用的数据源。它们都提供REST和WebSocket两种方式。我个人建议:用WebSocket拿实时行情,用REST做下单和查询。
3.2.1 Binance 实时行情获取
Binance的API文档写得挺清楚。我一般用 python-binance 这个库,省事。下面是一个获取BTC/USDT实时价格的例子:
from binance.client import Client
from binance.websockets import BinanceSocketManager
import time
# 初始化客户端(不需要API Key也能获取行情)
client = Client()
# REST方式:获取最新价格
def get_latest_price(symbol='BTCUSDT'):
ticker = client.get_symbol_ticker(symbol=symbol)
return float(ticker['price'])
# WebSocket方式:实时推送
def handle_socket_message(msg):
if msg['e'] == '24hrTicker':
print(f"最新价格: {msg['c']}")
# 启动WebSocket
bm = BinanceSocketManager(client)
conn_key = bm.start_symbol_ticker_socket('BTCUSDT', handle_socket_message)
bm.start()
# 保持运行
time.sleep(60)
bm.stop_socket(conn_key)
我的经验:WebSocket虽然实时性好,但偶尔会断连。一定要加心跳检测和自动重连。我曾经因为没处理断连,策略空跑了半小时,亏了不少手续费。
3.2.2 OKX 实时行情获取
OKX的API和Binance大同小异,但有个细节要注意——它的交易对命名是 BTC-USDT(用横杠),而Binance是 BTCUSDT(无分隔符)。这个坑我踩过,代码里一定要统一处理。
import requests
import json
# REST方式获取OKX行情
def get_okx_price(symbol='BTC-USDT'):
url = f"https://www.okx.com/api/v5/market/ticker?instId={symbol}"
response = requests.get(url)
data = response.json()
return float(data['data'][0]['last'])
# WebSocket方式
import websocket
def on_message(ws, message):
data = json.loads(message)
if 'data' in data:
print(f"OKX {data['data'][0]['instId']}: {data['data'][0]['last']}")
ws = websocket.WebSocketApp(
"wss://ws.okx.com:8443/ws/v5/public",
on_message=on_message
)
ws.run_forever()
注意:OKX的WebSocket需要发送订阅消息,不像Binance那样直接连接就能收到数据。具体格式参考官方文档,别搞错了。
3.3 外汇数据:Forex 实时汇率
做跨币种套利,免不了要涉及法币汇率。比如你交易的是BTC/USDT,但最终要换算成USD计价,那就需要USD/CNY的汇率。
外汇数据源我常用的是 Alpha Vantage 和 OANDA。前者免费但有调用限制,后者收费但更稳定。
import requests
# 使用Alpha Vantage获取EUR/USD实时汇率
def get_forex_rate(from_currency='EUR', to_currency='USD'):
api_key = 'YOUR_API_KEY'
url = f"https://www.alphavantage.co/query"
params = {
'function': 'CURRENCY_EXCHANGE_RATE',
'from_currency': from_currency,
'to_currency': to_currency,
'apikey': api_key
}
response = requests.get(url, params=params)
data = response.json()
rate = data['Realtime Currency Exchange Rate']['5. Exchange Rate']
return float(rate)
# 示例:获取EUR/USD
eur_usd = get_forex_rate('EUR', 'USD')
print(f"EUR/USD: {eur_usd}")
避坑指南:Alpha Vantage免费版每分钟只能调用5次。如果你同时监控多个货币对,很容易超限。我建议用缓存策略——每10秒更新一次,而不是每次策略循环都去请求。
3.4 数据获取的核心逻辑框架
下面这张图是我自己总结的数据获取流程。说白了,就是「统一接入、统一清洗、统一输出」。
这个框架的好处是:不管底层换了哪个交易所,上层策略代码都不用改。我一开始没做这层抽象,后来换了数据源,改代码改到崩溃。嗯,吃一堑长一智。
3.5 数据对齐:跨交易所的时间同步
做价差套利,最怕的就是时间不同步。比如Binance的BTC价格是10:00:00.100,OKX的是10:00:00.200,这100毫秒的偏差可能让价差信号完全失真。
我的做法是:
- 统一使用UTC时间,避免时区转换错误
- 每个数据点都带上时间戳,精确到毫秒
- 在策略层做时间对齐,只比较时间戳相差小于50ms的数据
import pandas as pd
from datetime import datetime
# 假设从两个交易所拿到数据
data_binance = {
'price': 50000.0,
'timestamp': datetime.utcnow().timestamp() # 精确到秒
}
data_okx = {
'price': 50001.0,
'timestamp': datetime.utcnow().timestamp()
}
# 时间对齐检查
def is_aligned(data1, data2, max_diff_ms=50):
diff_ms = abs(data1['timestamp'] - data2['timestamp']) * 1000
return diff_ms <= max_diff_ms
if is_aligned(data_binance, data_okx):
spread = data_okx['price'] - data_binance['price']
print(f"价差: {spread}")
else:
print("数据时间不同步,跳过本次计算")
重要提醒:不要相信交易所返回的时间戳!有些交易所的时间戳是服务器时间,和你本地时间可能有偏差。我建议用本地时间戳覆盖,或者用NTP同步所有机器的时间。
3.6 实战中的避坑指南
做数据获取这几年,我踩过的坑能写一本书。挑几个最典型的说说:
- API限频:Binance的REST接口每分钟最多1200次请求。别傻乎乎地每秒请求一次,用WebSocket代替。
- 网络抖动:跨境访问交易所API,延迟可能从50ms跳到500ms。加个超时重试机制,超时时间设3秒就够了。
- 数据缺失:偶尔会有某个交易所的数据没返回。别让整个程序崩溃,用上次有效数据填充,或者直接跳过。
- 小数点精度:不同交易所对价格的小数位数要求不同。Binance的BTC价格是2位小数,OKX可能是5位。统一格式化,避免计算误差。
我的习惯:每次启动策略前,先跑一个「数据健康检查」——确认所有数据源都能正常返回,延迟在可接受范围内。这步花不了几秒钟,但能避免很多坑。
3.7 小结
数据获取是套利策略的基石。记住三个关键词:实时、准确、稳定。用WebSocket拿实时数据,用REST做辅助查询,用统一框架管理多数据源。时间对齐和异常处理是重中之重,别在这上面省功夫。
下一章,咱们会把这些数据用起来,开始真正的价差计算和信号生成。但在此之前,先把数据获取这关过了——毕竟,巧妇难为无米之炊嘛。
公众号:蓝海资料掘金营,微信deep3321