第九章 实盘交易系统架构:低延迟架构设计、订单管理模块、风控模块

做基差交易,策略再好,执行跟不上也是白搭。我见过太多人,回测曲线漂亮得像艺术品,一上实盘就亏得亲妈都不认识。为什么?说白了,就是系统架构没扛住。

今天咱们聊聊实盘交易系统的三大核心模块:低延迟架构、订单管理、风控。这三个东西,就像人的骨架、肌肉和免疫系统,缺一个你都跑不起来。

一、低延迟架构设计:别让速度成为你的短板

基差交易对延迟有多敏感?我举个例子。有一次我在做沪深300期现套利,基差从-5个点瞬间跳到-3个点,中间只隔了200毫秒。如果你的系统延迟超过100毫秒,这单基本就废了。

低延迟架构的核心,其实就是三件事:减少数据路径、优化计算效率、避免阻塞

1.1 数据链路设计

我个人习惯用这样的数据流:

行情源 → 行情网关 → 内存队列 → 策略引擎 → 订单网关 → 交易所

这里有个关键点:所有模块都在同一台机器上,用共享内存通信。别用网络IPC,那玩意儿延迟至少多出50微秒。

核心原则:数据从行情源到策略引擎,路径上的中间环节越少越好。我见过有人把行情先存数据库再读出来算,那延迟直接奔着秒级去了。

1.2 代码层面的优化

嗯,这里要注意几个细节:

  • 避免动态内存分配:交易系统里,new和delete是敌人。我习惯在启动时一次性分配好所有内存池。
  • 使用无锁队列:多线程环境下,锁是最大的延迟来源。我推荐用Disruptor或者自己实现一个RingBuffer。
  • CPU亲和性绑定:把行情线程、策略线程、风控线程分别绑定到不同的物理核心上,避免上下文切换。

避坑指南:我曾经在一个项目里,因为没做CPU亲和性绑定,行情线程和风控线程抢同一个核心,导致行情处理延迟从10微秒飙到200微秒。后来绑定了核心,问题直接解决。

1.3 硬件层面的选择

如果你做高频基差交易,硬件不能省。我建议:

组件 推荐配置 原因
CPU Intel Xeon 或 AMD EPYC,高频型号 单核性能决定延迟下限
内存 DDR5,低延迟时序 内存访问延迟影响数据读取
网卡 Solarflare 或 Mellanox,支持DPDK 绕过内核协议栈,直接收发包
硬盘 NVMe SSD,但尽量少用 日志写入别影响主流程

二、订单管理模块:别让订单丢了或重复

订单管理,说白了就是管好你的每一笔委托。我刚开始做交易时,觉得这模块没啥技术含量,直到有一次因为订单状态没同步,导致重复下单,亏了十几万。从那以后,我再也不敢小看它。

2.1 订单生命周期管理

一个订单从出生到死亡,状态变化是这样的:

新建 → 已发送 → 已确认 → 部分成交 → 全部成交
                                    → 已撤单
                                    → 已拒绝

每个状态转换,都必须有明确的触发条件和处理逻辑。我习惯用状态机来实现:

class Order {
    int orderId;
    string symbol;
    double price;
    int volume;
    OrderStatus status;  // 用枚举管理
    
    void onAck() {
        if (status == SENT) {
            status = CONFIRMED;
            // 记录日志
        }
    }
    
    void onFill(int filledVol) {
        if (status == CONFIRMED || status == PARTIAL_FILL) {
            filledVolume += filledVol;
            if (filledVolume == volume) {
                status = ALL_FILLED;
            } else {
                status = PARTIAL_FILL;
            }
        }
    }
}

注意:订单状态机必须线程安全。我建议用无锁方式实现,或者用单线程处理所有订单事件。别在多个线程里同时修改同一个订单的状态,会出大问题。

2.2 订单簿与委托队列

订单管理模块里,还得维护一个本地的订单簿。说白了,就是记录你当前所有未成交的委托。我习惯用两个数据结构:

  • 按订单ID索引的哈希表:用于快速查找单个订单
  • 按合约和时间排序的跳表:用于批量查询和撤单

为什么用跳表?因为撤单时经常需要按时间顺序批量操作,哈希表做不到有序遍历。

2.3 订单路由与重试机制

订单发出去,不一定能成功到达交易所。网络抖动、交易所限流,都可能导致丢单。我建议这样处理:

  1. 发送时生成唯一ID:用时间戳+自增序列,确保全局唯一
  2. 设置超时重试:如果500毫秒内没收到确认,重新发送
  3. 幂等性检查:交易所收到重复订单时,能识别并返回已有结果

个人经验:重试次数别太多,3次就够了。我曾经设了10次重试,结果交易所恢复后,一下子涌进去10个重复订单,全成交了。嗯,那天的风控报告很难看。

三、风控模块:别让亏损失控

风控模块,是交易系统的最后一道防线。我见过太多人,策略赚钱时觉得自己天下无敌,结果一次黑天鹅事件就爆仓了。风控不是用来限制你的,是用来保护你的。

3.1 事前风控:下单前检查

每一笔订单在发出去之前,都要经过风控检查。我习惯做这几项:

检查项 规则 触发动作
资金检查 订单金额 ≤ 可用资金 × 杠杆倍数 拒绝下单
持仓检查 单合约持仓 ≤ 最大持仓限制 拒绝下单
频率检查 每秒下单次数 ≤ 10次 延迟或拒绝
价格检查 订单价格偏离市价 ≤ 1% 拒绝下单

你想想看,如果没有价格检查,万一策略算错了,发了个离谱的价格出去,那损失可不是闹着玩的。

3.2 事中风控:持仓监控

订单成交后,风控模块要持续监控持仓状态。我建议做这几件事:

  • 实时计算盈亏:每收到一次行情,就重新算一遍所有持仓的浮动盈亏
  • 设置止损线:总亏损超过某个阈值,自动平仓
  • 监控敞口:基差交易里,期现敞口必须严格对冲,别出现单边暴露

核心逻辑:风控模块必须独立于策略模块运行。我见过有人把风控逻辑写在策略代码里,结果策略出bug时,风控也跟着失效了。风控模块应该有自己的进程,甚至自己的机器。

3.3 事后风控:日志与复盘

交易结束后,风控模块要生成完整的日志和报告。我习惯记录这些信息:

时间戳 | 订单ID | 合约 | 方向 | 价格 | 数量 | 状态 | 延迟(ms)
2025-01-15 09:30:01.123 | 10001 | IF2501 | BUY | 3800.0 | 1 | FILLED | 45
2025-01-15 09:30:01.456 | 10002 | IC2501 | SELL | 5600.0 | 1 | REJECTED | 32

这些日志有什么用?复盘时,你可以找出延迟瓶颈、分析订单失败原因、优化策略参数。说白了,没有日志的交易系统,就像没有黑匣子的飞机,出了问题你都不知道怎么死的。

四、系统架构总览

最后,我用一张图来总结整个系统架构:

行情源 行情网关 内存队列 策略引擎 订单管理 风控模块 订单网关 交易所 行情数据 共享内存 策略信号 订单指令 风控检查 发送订单 成交回报

这张图里,数据流是单向的:行情从源进来,经过网关、队列、策略、风控,最后通过订单网关发到交易所。每个模块各司其职,互不干扰。我个人觉得,这种架构最大的好处是:任何一个模块出问题,都不会影响其他模块的正常运行

最后提醒一句:系统架构不是一次设计完就完事了。你需要持续监控每个模块的延迟、吞吐量、错误率。我每周都会看一次系统性能报告,发现瓶颈就优化。交易系统,永远没有最优,只有更优。

公众号:蓝海资料掘金营,微信deep3321