第二章 系统架构总览:分层架构设计、核心组件与数据流
好,咱们直接进入正题。这一章我打算聊聊高频交易系统的骨架——也就是整体架构长什么样。很多新手一上来就盯着策略代码猛写,结果行情来了,系统崩了,订单飞了。嗯,这种事我在早期项目里见过太多次了。
说白了,高频交易系统就是一个极致的实时数据处理管道。它要处理的事情其实不复杂:拿到行情,做出决策,执行交易。但难就难在,这一切必须在微秒甚至纳秒级别完成。
2.1 分层架构设计:为什么必须分层?
我个人习惯把系统拆成四层。你想想看,如果不分层,所有逻辑揉在一起,改一个地方可能引发连锁反应。我见过一个团队,因为行情解析和策略逻辑混在一起,换个交易所协议,整个系统重写了一遍——太痛了。
这四层分别是:
- 接入层:负责跟交易所打交道。接收行情、发送订单。
- 业务逻辑层:策略计算、订单管理、风控检查。
- 数据层:存储历史数据、日志、配置。
- 监控层:系统健康检查、延迟监控、告警。
每一层只做自己的事。接入层不关心策略怎么算,策略层不关心数据怎么存。这样出了问题,定位也快。
核心原则:层与层之间通过明确定义的接口通信。接口要轻量,最好是共享内存或者无锁队列。别用HTTP——那延迟你扛不住。
2.2 核心组件拆解
系统里最关键的四个组件,我一个个说。
2.2.1 行情组件
行情组件是系统的眼睛。它负责从交易所接收实时数据,然后分发给策略模块。
这里有个坑——行情数据是海量的。以国内期货为例,一个合约每秒可能产生几百笔行情。如果全量推送,带宽和CPU都扛不住。我在项目中遇到过,一开始没做行情过滤,结果策略模块处理不过来,直接丢数据。
解决方案是什么?行情预处理。在接入层就做一次清洗:去重、校验、聚合。只把有用的数据往上送。
// 伪代码:行情预处理
void onMarketData(MarketData md) {
if (!validate(md)) return; // 校验失败,丢弃
if (isDuplicate(md)) return; // 重复数据,丢弃
md = aggregate(md); // 聚合tick数据
publishToStrategy(md); // 发布给策略
}
2.2.2 策略组件
策略组件是大脑。它拿到行情后,根据预设的规则或模型,决定要不要下单。
策略分两种:事件驱动型和定时轮询型。高频交易里,几乎全是事件驱动。行情来了,立刻触发计算。轮询?那延迟你受不了。
我建议策略模块做成插件化。每个策略是一个独立的动态库,可以热加载。这样上线新策略不用重启系统。嗯,这个设计我在一个实盘项目里用过,效果不错。
避坑指南:策略模块里千万别做IO操作,比如写数据库、发网络请求。这些操作会阻塞计算线程。我曾经见过一个策略,因为里面加了个日志写入,延迟从5微秒飙到500微秒——直接废了。
2.2.3 交易组件
交易组件是手和脚。它负责把策略的决策变成实际的订单,发送到交易所。
这里有个关键点:订单生命周期管理。一个订单从发送到成交,中间可能经历多种状态:已发送、已确认、部分成交、全部成交、已撤销。交易组件必须准确跟踪每个订单的状态。
我习惯用一个订单状态机来管理。每个订单进来,状态机自动流转。如果出现异常状态(比如超时未确认),立刻告警并做处理。
| 订单状态 | 说明 | 下一步动作 |
|---|---|---|
| PENDING | 已生成,待发送 | 发送到交易所 |
| SENT | 已发送,等待确认 | 等待交易所回执 |
| ACKED | 交易所已确认 | 等待成交或撤销 |
| FILLED | 全部成交 | 通知策略,更新持仓 |
| CANCELLED | 已撤销 | 释放资源 |
2.2.4 风控组件
风控组件是刹车。没有它,系统可能一天就把一年的钱亏完。
风控要检查的东西很多:
- 资金检查:账户余额够不够?
- 持仓检查:会不会超仓?
- 频率检查:每秒下单次数是否超限?
- 价格检查:订单价格是否偏离市场太远?
风控必须放在交易组件之前。也就是说,策略的决策要先过风控,风控通过了,才能发到交易所。这个顺序不能乱。
注意:风控逻辑要尽可能简单、快速。别在风控里做复杂计算。我见过一个系统,风控里做了个机器学习模型预测市场——结果模型跑一次要10毫秒,订单早飞了。风控就是风控,别越界。
2.3 数据流与资金流
搞清楚了组件,咱们再看看数据怎么流、钱怎么流。
2.3.1 数据流
数据流是单向的,从行情到策略到交易。大致是这样的:
- 交易所推送行情数据到接入层。
- 接入层清洗、聚合后,推送给策略模块。
- 策略模块计算后,生成订单指令,发给风控。
- 风控检查通过后,订单指令发给交易模块。
- 交易模块发送订单到交易所,并接收回执。
- 回执信息再反向流回策略模块,用于更新状态。
你可能会问:为什么回执要流回策略?因为策略需要知道订单是否成交,才能决定下一步动作。比如一个限价单没成交,策略可能需要撤单重发。
这里有个设计要点:数据流要尽量少拷贝。每次拷贝都是延迟。我习惯用共享内存或者零拷贝技术,让数据在组件间直接传递。
2.3.2 资金流
资金流跟数据流不一样。资金流是事后清算的。也就是说,交易过程中,系统并不实时操作资金账户。它只是记录每一笔交易的盈亏,等到收盘后统一结算。
但注意,虽然不实时操作资金,但风控必须实时检查资金。比如账户里只有100万,策略却要下200万的单,风控必须拦住。
我建议在系统里维护一个虚拟资金账户。每次交易前,从虚拟账户里扣减保证金。成交后,更新盈亏。这样既不影响交易速度,又能实时控制风险。
一句话总结:数据流是实时的、单向的;资金流是事后的、清算的。两者不要混在一起处理。
2.4 架构设计的几个原则
最后,分享几个我这些年总结的原则:
- 低耦合:组件之间只通过接口通信,别共享内存状态。
- 高内聚:每个组件只做一件事,并且做好。
- 可观测:每个组件都要暴露监控指标,出了问题能快速定位。
- 可回放:行情数据要能回放,方便策略回测和问题排查。
嗯,这一章就到这里。下一章咱们深入行情组件,聊聊怎么在微秒级别处理海量数据。