一、系统架构总览:交易系统分层架构

跨市场套利系统,说白了就是一台「抢钱机器」。但机器要跑得稳,架构得先搭对。我做了这么多年量化,见过太多团队一上来就写策略,结果数据层崩了、执行层延迟高、风控形同虚设……最后亏得底裤都不剩。

今天咱们就聊聊,一个靠谱的套利系统,到底该怎么分层。

1. 交易系统分层架构

我个人习惯把系统拆成四层:数据层、策略层、执行层、风控层。每一层各司其职,层与层之间通过消息队列解耦。你想想看,如果所有逻辑都揉在一个进程里,改个风控参数还得重启整个系统,那得多痛苦?

数据层

数据层是系统的「眼睛」。它负责从各个交易所拉取行情数据,包括盘口深度、成交记录、K线等。我在项目中遇到过一个问题:某次行情数据量暴增,直接导致数据库连接池被打满,策略层拿不到数据,整个系统瘫痪了10分钟。

所以数据层要做的,不只是「拿数据」,还要做缓冲、清洗、对齐。比如不同交易所的时间戳格式不一样,你得统一成UTC毫秒级。再比如某些交易所的深度数据是增量推送,你得自己维护一个本地的订单簿快照。

核心要点:数据层必须支持多源异构数据的实时接入,延迟控制在毫秒级,同时要有数据质量监控机制。

策略层

策略层是系统的「大脑」。它根据数据层提供的行情,计算价差、判断套利机会、生成交易信号。这里有个坑:很多人以为策略层就是写个价差公式就完事了。其实不然,策略层还要处理订单簿不平衡、流动性评估、滑点预估等复杂逻辑。

我曾经踩过一个坑:策略层直接读取数据层的原始数据,没有做时间对齐。结果两个交易所的行情时间戳差了200毫秒,算出来的价差全是错的,白白亏了几十万。从那以后,我强制要求数据层必须输出对齐后的数据,策略层只管算,不管对齐。

我的建议:策略层最好做成插件化架构,每个策略独立部署、独立升级。这样新策略上线不影响老策略,回测也方便。

执行层

执行层是系统的「手脚」。它负责把策略层生成的信号,转换成实际的交易所订单。执行层要考虑的事情很多:订单拆分、路由选择、重试机制、防自成交等。

举个例子:你发现BTC在币安和OKX之间有价差,想买低卖高。执行层需要决定:是先买还是先卖?如果先买,买完之后价差消失了怎么办?如果同时下单,万一一边成交一边没成交,就变成了单边敞口。这些都需要执行层来处理。

注意:执行层的延迟直接决定了套利能否成功。我见过团队用Python写执行层,结果下单延迟超过500毫秒,价差早没了。执行层必须用C++或Java,且要部署在离交易所服务器最近的地方。

风控层

风控层是系统的「刹车」。它实时监控整个系统的运行状态,包括仓位、资金、延迟、异常信号等。一旦发现风险,立即干预——比如暂停交易、平仓、报警。

风控层有个原则:宁可错杀,不可放过。我见过一个团队,风控阈值设得太宽松,结果一次极端行情导致仓位爆了。后来他们改了策略:只要价差超过历史3倍标准差,直接暂停所有交易。虽然会错过一些机会,但至少不会亏大钱。

层级 核心职责 技术选型 延迟要求
数据层 行情接入、清洗、对齐 WebSocket、Kafka、Redis <10ms
策略层 价差计算、信号生成 Python、C++、Rust <50ms
执行层 订单管理、路由、重试 Java、C++、gRPC <5ms
风控层 实时监控、风险干预 Go、Flink、Prometheus <100ms

2. 微服务架构设计

分层架构是逻辑上的,微服务架构是物理上的。说白了,就是把每一层再拆成更小的服务,独立部署、独立扩展。

我习惯这样拆:

  • 行情服务:负责接入交易所行情,输出标准化数据
  • 计算服务:负责价差计算、信号生成
  • 订单服务:负责下单、撤单、查询
  • 风控服务:负责实时监控、风险判断
  • 账户服务:负责资金管理、仓位记录
  • 日志服务:负责所有操作的审计日志

每个服务都可以独立扩缩容。比如行情数据量大了,我只需要加行情服务的实例,其他服务不用动。再比如某个策略出了问题,我只需要重启对应的计算服务,不影响其他策略。

关键点:微服务之间通过API网关统一入口,内部用gRPC或消息队列通信。不要用RESTful,延迟太高。

3. 消息队列选型

消息队列是系统的「血管」。数据层产生的行情数据,通过消息队列流向策略层;策略层产生的信号,通过消息队列流向执行层。选对了消息队列,系统就成功了一半。

我对比过几种主流方案:

消息队列 吞吐量 延迟 持久化 适用场景
Kafka 极高 中等(~10ms) 行情数据、日志
RabbitMQ 低(~1ms) 订单指令、信号
Redis Pub/Sub 中等 极低(<1ms) 实时行情、心跳
NATS 极低(<1ms) 高频交易

我个人习惯这样搭配:

  • 行情数据用Kafka。因为行情数据量大、需要持久化、允许一定延迟。
  • 订单指令用RabbitMQ。因为订单指令要求可靠投递、延迟低。
  • 实时信号用Redis Pub/Sub。因为信号要求极低延迟,且不需要持久化。
避坑指南:我曾经用Kafka做订单指令传输,结果有一次Kafka集群挂了,订单指令丢失了十几条,导致仓位对不上。从那以后,订单指令我坚决不用Kafka,改用RabbitMQ+确认机制。

4. 系统架构总览图

下面这张图,是我画的一个简化版架构图。你可以看到数据从交易所进来,经过各层处理,最终变成订单发出去。每一层之间都有消息队列做缓冲,确保系统不会因为某一层的故障而整体瘫痪。

跨市场套利系统架构总览 交易所A 交易所B 交易所C 数据层(行情接入、清洗、对齐) 消息队列(Kafka / RabbitMQ / Redis) 策略层(价差计算、信号生成) 执行层(订单管理、路由、重试) 风控层(实时监控、风险干预)

嗯,这张图虽然简单,但核心思想都在里面了。每一层各司其职,层与层之间通过消息队列解耦,风控层像幽灵一样监控着所有层。这样的架构,才能支撑起一个稳定、高效的跨市场套利系统。

最后说一句:架构设计没有银弹。我给出的这套方案,适合大多数套利场景。但如果你做的是高频套利,延迟要求到微秒级,那可能得用FPGA或者专用硬件。不过那是另一个话题了,咱们后面再聊。
专注资料整理