外汇实时行情接入:量化系统里最容易被低估的工程模块

41 阅读4分钟

在搭建量化交易系统时,外汇实时行情接口通常是最先完成的模块之一。

连接接口、订阅 EURUSD、看着 tick 数据持续推送,很容易产生一种“行情这块已经搞定了”的错觉。但只要系统开始长期运行,或者逐步接入更多策略和品种,行情模块的设计问题往往会慢慢显现出来。

从工程视角看,行情接入并不是复杂度最高的模块,却往往是返工成本最高的部分。


行情模块的工程特性:依赖多、改动代价大

在真实系统中,行情数据通常会被多个模块同时依赖,例如:

  • 实时策略计算
  • 指标与因子更新
  • 日志记录与回放
  • 回测与仿真对齐

这意味着,一旦行情结构或行为发生变化,影响范围往往不止一个功能点。

相比策略逻辑可以频繁迭代,行情模块更适合被当作基础设施来设计:

  • 行为简单
  • 职责清晰
  • 结构长期稳定

“能跑”只是最低要求,“能长期稳定跑且不频繁调整”才是工程上的合格标准。


为什么实时外汇行情更适合用 WebSocket

在外汇场景中,tick 级行情更新频率较高。如果使用 REST 接口进行轮询,本质上会面临几个问题:

  • 大量无效请求
  • 延迟随轮询周期波动
  • 系统资源消耗与行情频率直接绑定

WebSocket 的推送模型在结构上更贴合实时行情的特点:
有数据才推送,减少了冗余请求,也更容易保持低延迟。

在系统运行时间拉长、订阅品种增多后,这种差异会变得非常明显。


接口之外,更重要的是行情模块的边界

接口文档通常会把字段和订阅方式写得很详细,但很少回答一个关键问题:

行情模块的职责,到哪里为止?

从工程可维护性的角度看,一个相对清晰的边界是:

  • 行情层只负责

    • 建立连接
    • 订阅行情
    • 接收并转发原始数据
  • 业务层再负责

    • 时间判断
    • 品种含义解析
    • 策略逻辑与风控

一旦在行情层引入策略判断或状态逻辑,后续在做回测、并行策略或系统扩展时,复杂度往往会迅速上升。


一个更“克制”的外汇行情接入结构

下面是一个简化的行情接入示例,仅用于说明结构设计(代码逻辑保持基础):

import websocket
import json

WS_URL = "wss://stream.alltick.co/ws"

def on_open(ws):
    ws.send(json.dumps({
        "op": "auth",
        "args": {
            "token": "YOUR_API_KEY"
        }
    }))

    ws.send(json.dumps({
        "op": "subscribe",
        "args": [
            {
                "channel": "tick",
                "symbol": "EURUSD"
            }
        ]
    }))

def on_message(ws, message):
    data = json.loads(message)
    if data.get("channel") == "tick":
        forward_tick(data["data"])

def forward_tick(tick):
    # 行情模块在此结束
    pass

ws = websocket.WebSocketApp(
    WS_URL,
    on_open=on_open,
    on_message=on_message
)

ws.run_forever()

这里的关键点不在于代码本身,而在于 forward_tick 之后不再继续扩展逻辑

行情模块只负责把数据稳定地交出去,不关心策略、不关心交易时间,也不维护业务状态。


多品种订阅时,减少判断反而更稳

在订阅多个外汇品种时,很容易在行情层写出大量条件分支:

  • 如果是 EURUSD
  • 如果是 USDJPY

但在实践中,更可维护的方式通常是:

  • 行情层只识别 symbol
  • 所有行情保持统一结构
  • 具体含义交由下游模块解释

这样在新增品种或扩展系统时,行情模块本身几乎不需要改动。


外汇行情 API 的差异,往往体现在长期使用中

从功能层面看,大多数外汇行情 API 都能提供实时数据。但在工程实践中,更关键的是:

  • 数据字段是否长期稳定
  • 不同资产是否使用统一的数据模型
  • 多品种订阅时推送行为是否一致

一些行情服务在设计阶段就采用统一的推送结构,将外汇、股票、加密资产等行情放在同一模型下处理。例如 AllTick 这类实时行情接口,在跨品种或跨市场使用时,额外适配成本相对较低,更利于系统整体的一致性。

这些差异通常只有在系统长时间运行后,才会逐步体现出来。

生成匹配标题的封面图-7 4.jpeg


小结

在量化系统中,一个设计得当的行情模块,往往“存在感不强”,但却决定了系统的稳定下限。

在接入外汇实时行情时,与其追求接口功能的丰富程度,不如优先关注:

  • 职责边界是否清晰
  • 数据结构是否稳定
  • 与策略和业务模块是否解耦

这些工程层面的选择,往往会在系统规模扩大、策略复杂化之后,持续产生价值。