第九章 实盘交易系统架构:低延迟架构设计、订单管理模块、风控模块
做基差交易,策略再好,执行跟不上也是白搭。我见过太多人,回测曲线漂亮得像艺术品,一上实盘就亏得亲妈都不认识。为什么?说白了,就是系统架构没扛住。
今天咱们聊聊实盘交易系统的三大核心模块:低延迟架构、订单管理、风控。这三个东西,就像人的骨架、肌肉和免疫系统,缺一个你都跑不起来。
一、低延迟架构设计:别让速度成为你的短板
基差交易对延迟有多敏感?我举个例子。有一次我在做沪深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 订单路由与重试机制
订单发出去,不一定能成功到达交易所。网络抖动、交易所限流,都可能导致丢单。我建议这样处理:
- 发送时生成唯一ID:用时间戳+自增序列,确保全局唯一
- 设置超时重试:如果500毫秒内没收到确认,重新发送
- 幂等性检查:交易所收到重复订单时,能识别并返回已有结果
个人经验:重试次数别太多,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
这些日志有什么用?复盘时,你可以找出延迟瓶颈、分析订单失败原因、优化策略参数。说白了,没有日志的交易系统,就像没有黑匣子的飞机,出了问题你都不知道怎么死的。
四、系统架构总览
最后,我用一张图来总结整个系统架构:
这张图里,数据流是单向的:行情从源进来,经过网关、队列、策略、风控,最后通过订单网关发到交易所。每个模块各司其职,互不干扰。我个人觉得,这种架构最大的好处是:任何一个模块出问题,都不会影响其他模块的正常运行。
最后提醒一句:系统架构不是一次设计完就完事了。你需要持续监控每个模块的延迟、吞吐量、错误率。我每周都会看一次系统性能报告,发现瓶颈就优化。交易系统,永远没有最优,只有更优。