概述
在构建多资产量化策略、开展跨市场回测研究时,往往需要同时获取外汇、贵金属、加密货币、股票的实时与历史行情数据。不少研究者会直接对接多家第三方数据服务,期望快速完成数据聚合,但实际开发过程中,各类接口的协议、字段、时间体系差异会产生大量适配成本,甚至会埋下回测与实盘的数据一致性隐患。
本文基于项目实践,梳理跨市场行情接入的典型问题,给出 API 的评估维度,介绍一套内部数据模型归一化的工程实现思路,并提供可用于策略原型开发的 Python WebSocket 示例代码,旨在为多资产策略研究、实盘原型开发提供可复用的技术参考。
跨市场行情接入的常见技术问题
在开展多资产监控面板开发的过程中,曾同时对接三家不同数据源分别获取外汇贵金属、加密货币、股票行情。各服务商的鉴权逻辑、标的编码、时间格式、返回字段相互独立,大量开发工作量消耗在数据格式转换,而非业务与策略逻辑本身。总结四类高频问题:
1. 标的编码体系不统一
同一交易品种,不同服务商编码规则存在差异。例如欧元兑美元存在EURUSD、EUR/USD两种写法;加密货币交易对分为BTC‑USDT与BTCUSDT格式;股票标的需要追加对应交易所后缀。直接将 A 服务商的编码传入 B 服务商接口,通常无法获取有效行情,会造成数据缺失。
2. 时间戳与字段数据类型混杂
时间戳存在秒级、毫秒级、时间字符串等多种输出形式;价格、成交量字段部分接口返回数值,部分返回字符串。若未做统一类型处理,在回测的时序计算、指标运算阶段会出现异常报错,干扰策略验证。
3. 推送模式、心跳与限流规则不一致
部分数据源支持 WebSocket 长连接实时推送,部分仅支持轮询拉取。各接口的心跳保活、断线恢复、访问频率限制均为独立规则,难以复用同一套客户端逻辑,增加多源并发维护成本。
4. 各市场交易时间模型存在显著差异
加密货币 7×24 小时连续交易;外汇周末休市;股票包含开盘、午休、法定节假日停盘周期。如果采用固定超时作为行情异常判定标准,休市阶段会产生大量无效告警,无法区分正常休市与真实数据源故障,不利于策略运行状态监控。
多资产行情 API 评估要点
结合实践经验,评估多资产行情 API,核心目标是降低外部接口带来的适配工作量,减少后续回测、实盘之间的数据不一致风险,重点考察如下维度:
- 鉴权体系:多类资产是否可复用同一 Token 完成身份校验;
- 协议一致性:不同品种的订阅报文结构、推送字段命名是否具备稳定性;
- 文档完备度:是否提供完整、可查阅的标的编码对照表;
- 运行约束:明确的访问配额、限流规则,同时文档对心跳、断线重连机制有清晰说明。
完全统一全品类字段的外部接口并不存在。即便是同一服务商,股票、外汇、加密货币也可能划分不同接入端点,存在局部字段差异。务实处理方式:优先选择协议标准化程度较高的数据源,在程序内部构建适配层消化剩余差异。
在原型研究阶段,可选用 AllTick API 开展测试工作,外汇、贵金属、加密货币共用一组 WebSocket 接入端点,美股、港股、A 股使用另一组端点,两套链路订阅协议保持一致,能够减少适配层的开发工作量。
工程实现:内部 Quote 模型隔离外部数据差异
应用价值:保证回测与实盘使用同一套内部数据模型,消除第三方接口变更对上层策略逻辑的影响。
无论外部数据源输出格式如何,在程序内部定义专属行情实体Quote,仅保留策略研究必需的核心字段:数据源标识、品种代码、价格、成交量、毫秒级时间戳。
所有第三方原始行情数据流入系统后,第一步执行归一化转换,映射为统一的Quote对象。策略计算、指标分析、回测模块、行情监控均依赖该内部模型,完全不感知第三方原始返回格式。
该架构带来两项关键收益:
- 更换底层数据源时,仅修改数据转换逻辑,策略、回测等上层代码无需改动;
- 新增一类交易市场,仅补充数据源配置,无需大规模重构现有业务逻辑。
此前项目中,基于这套抽象架构,完成港股、美股行情新增接入仅耗费半天调试时间。研究开发中建议遵循一条原则:策略与回测逻辑,不要直接绑定第三方 API 原始 JSON 结构。
实战代码:单进程多路 WebSocket 行情接收原型
以下 Python 代码为研究原型,单进程维护多组独立 WebSocket 连接,不同市场链路相互隔离,单条连接故障不会干扰其余行情数据流,可用于多资产策略原型的数据接收环节。
python
运行
import asyncio
import json
import os
import uuid
from dataclasses import dataclass
import websockets
BASE = "wss://quote.alltick.co"
FEEDS = {
"multi": { # 外汇、贵金属、加密货币
"path": "/quote-b-ws-api",
"codes": ["EURUSD", "GOLD", "BTCUSDT"],
},
"stock": { # 美股、港股、A股
"path": "/quote-stock-b-ws-api",
"codes": ["AAPL.US", "700.HK", "600519.SH"],
},
}
heartbeat = {"cmd_id": 22000, "seq_id": 1, "trace": "heartbeat", "data": {}}
@dataclass
class Quote:
feed: str
code: str
price: float
volume: float
ts_ms: int
def normalize(feed, tick):
"""将外部原始tick归一化为内部Quote模型,供策略、回测模块调用"""
return Quote(
feed=feed,
code=tick["code"],
price=float(tick["price"]),
volume=float(tick["volume"]),
ts_ms=int(tick["tick_time"]),
)
async def run_feed(name, cfg, queue):
token = "填写申请获取的AllTick_token"
uri = f"{BASE}{cfg['path']}?token={token}"
subscribe = {
"cmd_id": 22004,
"seq_id": 1,
"trace": str(uuid.uuid4()),
"data": {"symbol_list": [{"code": c} for c in cfg["codes"]]},
}
while True: # 断线自动重连
try:
async with websockets.connect(uri) as ws:
await ws.send(json.dumps(subscribe))
async def beat():
while True:
await asyncio.sleep(10)
await ws.send(json.dumps(heartbeat))
task = asyncio.create_task(beat())
try:
async for raw in ws:
msg = json.loads(raw)
if msg.get("cmd_id") == 22998:
await queue.put(normalize(name, msg["data"]))
finally:
task.cancel()
except (websockets.ConnectionClosed, OSError):
await asyncio.sleep(3)
async def consumer(queue):
while True:
q = await queue.get()
# 此处可扩展:写入数据库、送入策略计算模块、回测预处理
print(q.feed, q.code, q.price, q.ts_ms)
async def main():
queue = asyncio.Queue()
await asyncio.gather(
consumer(queue),
*[run_feed(n, c, queue) for n, c in FEEDS.items()],
)
asyncio.run(main())
原型开发注意点
- 各市场维持独立 WebSocket 连接,分别处理订阅、心跳、断线重连;解析后的数据推送至公共异步队列统一消费;
- 同一会话下重复发送订阅指令会覆盖原有标的列表,动态增减品种时,需要提交完整标的集合;
- 接入新数据源务必校验原始报文的时间戳单位,时间单位错误会直接造成回测时序错乱。
归一化完成后仍需要处理的工程要点
完成内部模型转换,不等于数据链路完全就绪,还有若干会影响回测可靠性的细节需要处理:
-
分市场实现行情异常判断逻辑
不要使用全局统一超时阈值。加密货币监控阈值可适当缩短;外汇、股票需要结合交易日历进行判断。外汇周末无推送属于正常休市,不应判定为数据故障。
-
规避浮点数运算精度问题
外汇报价多为 5 位小数,A 股为 2 位,加密货币最高可达 8 位小数。涉及净值、盈亏等金额相关计算,建议使用
Decimal类型运算,避免浮点数累积误差,防止回测结果出现偏移。 -
历史 K 线数据同样执行归一化
实时行情一般通过 WebSocket 获取,历史 K 线大多依赖 REST 接口,两套接口返回结构往往不一致。历史 K 线获取之后,同样转换为
Quote内部模型再入库,实现回测历史数据、实盘实时数据使用同一套对象,减少实盘与回测的逻辑割裂。
总结
多资产策略研究中,跨市场行情接入不存在捷径。在数据源选型阶段优先选择协议规范、文档完整的 API;架构层面通过适配层隔离外部接口差异,保障回测、策略模块的逻辑稳定性。
开展多资产研究项目时,优先定义统一的内部行情数据模型,能够有效降低后续迭代、数据源切换带来的改造成本,提升回测结果与实盘运行的一致性。

