07 · 数据与基础设施
交易系统是「数据驱动」的系统:行情数据要低延迟接入、订单数据要零丢失、资金数据要精确到分、历史数据要能支撑回测与研究。本篇从工程师视角讲交易系统的数据体系、存储选型、消息中间件、任务调度、监控告警、部署架构与安全合规。
免责声明:本站全部内容仅用于学习与研究,不构成任何投资建议。市场有风险,投资需谨慎。
一、交易系统的数据体系
| 数据类别 | 内容 | 特点 | 存储方案 |
|---|---|---|---|
| 行情数据 | 逐笔成交、盘口快照、K 线、指数 | 海量、高写入、只追加 | 时序数据库 / Parquet 分片文件 |
| 订单数据 | 下单/撤单/成交回报、委托状态 | 结构化、强一致、审计需求 | 关系型数据库(MySQL/PostgreSQL) |
| 资金数据 | 账户余额、持仓、保证金、流水 | 一致性要求最高,多币种 | 关系型数据库 + 账本式流水表 |
| 财务与基本面数据 | 财报、估值、分红、公告 | 低频、非结构化+结构化 | 关系型数据库 + 对象存储(公告 PDF) |
| 另类数据 | 舆情、新闻、链上数据、资金流 | 高噪音、多格式 | 搜索引擎/图数据库/对象存储 |
1.1 行情数据(最大的存储压力)
- 期货逐笔:单品种一天约百万级记录,全市场多年数据是 TB 级。
- K 线可以预聚合、分周期存储(1m/5m/15m/1h/1d),大幅减少查询量。
- 读写分离:实时写入热库(内存/SSD),历史数据冷存(Parquet + 对象存储),回测直接读冷数据。
1.2 订单与资金数据(强一致是关键)
- 订单表设计要点:状态机字段(已提交→已接受→部分成交→全部成交→已撤销)、与交易所订单 ID 的映射关系、原始报文快照(用于对账)。
- 资金/持仓更新必须记账式:只允许「余额变动流水表 + 汇总余额」的结构,禁止直接覆盖余额字段,否则对账无从谈起。
⚠️ 禁止直接覆盖余额字段
资金/持仓更新必须记账式:只允许「余额变动流水表 + 汇总余额」的结构,禁止直接覆盖余额字段,否则对账无从谈起。 账户余额不是靠一次 UPDATE 维护的,而是靠逐笔流水累加——这是资金数据「强一致」的唯一可靠实现。
二、时序数据库选型
| 方案 | 写入性能 | 查询能力 | 压缩比 | 适用场景 |
|---|---|---|---|---|
| ClickHouse | 极高(列式批量写入,单机百万行/秒级) | 极强(SQL 聚合分析海量历史) | 高(列式+编码压缩,可达 10:1) | 历史行情归档、大规模因子计算、回测数据仓库 |
| TimescaleDB | 高(PostgreSQL 插件,继承 PG 生态) | 强(标准 SQL + 连续聚合视图) | 中高 | 中小体量行情、与业务库同栈 |
| InfluxDB | 高 | 中(自带 Flux 查询,生态独立) | 中 | 监控指标(CPU/内存/延迟)轻量存储 |
| Parquet 文件 + 对象存储 | 批量写入(不实时) | 中(需查询引擎如 DuckDB/Spark) | 高 | 历史归档、离线研究、回测数据集 |
选型结论:
- 实时热数据(当天逐笔、盘口):Redis/内存或高性能 TSDB 短窗口。
- 历史归档(回测、因子研究):ClickHouse 或 Parquet + DuckDB 是主流答案。
- 监控指标:Prometheus 本身就是时序库,无需再叠 InfluxDB。
- 不要用 MySQL 硬扛逐笔行情写入,会迅速成为瓶颈。
三、实时缓存与消息
3.1 Redis:实时状态缓存
| 用途 | 说明 |
|---|---|
| 行情缓存 | 最新价/最新盘口存 Redis,行情网关写、策略/前端读,降低数据库压力 |
| 分布式锁 | 订单去重、防重复下单 |
| 限流计数 | 交易所 API 频率限制(每秒 N 次)的滑动窗口计数 |
| 会话/状态缓存 | 持仓快照、策略运行状态 |
3.2 Kafka:事件总线
Kafka 在交易系统中扮演解耦总线角色:行情接入、订单执行、风控、结算、报表各系统之间不直接互相调用,而是发布/订阅事件。
交易所WebSocket ──> 行情网关 ──> Kafka[tick] ──> 策略引擎 / 风控 / 前端行情
交易网关 ─────────> Kafka[order-req] ──> 交易所API ──> Kafka[order-rpt] ──> 策略 / 风控 / 结算为什么用 Kafka 做解耦?
- 生产者消费者分离:行情网关挂了,消费端(策略)不受影响;新增一个消费端(如风控、研究归档)无需改生产端代码。
- 削峰:行情突发(极端行情成交量暴增)时,消息可暂存在 Kafka,消费者按自己的速度处理。
- 回放:策略重启后可以从 topic 指定 offset 重放行情,天然支持状态恢复与复盘。
- 多副本:数据不丢(配合 acks=all),满足订单事件「零丢失」诉求。
3.3 消息设计要点
- 订单事件必须幂等:同一事件重放多次不产生重复下单(按 clientOrderId 去重)。
- 主题命名规范:
market.<symbol>.tick、order.<account>.report,便于管理与权限隔离。 - 端到端确认:下游消费后写「已处理」标记,否则重启后重复处理。
四、任务调度与批处理
4.1 调度方案
| 方案 | 适用 | 说明 |
|---|---|---|
| Cron(单机) | 简单定时任务 | 单点,机器挂了任务丢失 |
| Celery beat / APScheduler | Python 生态 | 定时任务 + 队列分发,适合中等复杂度 |
| Airflow / DolphinScheduler | 复杂 DAG 依赖 | 任务间有先后依赖(先结算后出报表)时使用 |
| 自研调度 + Kubernetes CronJob | 高可控 | 配合容器化,任务失败自动重跑 |
4.2 典型收盘后任务链(期货/股票)
收盘 ──> 日终行情归档 ──> 对账(交易所持仓/资金 vs 本地) ──> 结算(手续费/保证金/盈亏)
──> 报表生成(日账单/绩效) ──> 数据备份 ──> 因子更新/回测日批每个任务都要:幂等(可重跑)、有超时、有告警、有执行日志。对账任务对不上必须当日人工介入,绝不允许自动忽略。
五、监控告警体系
5.1 三件套
| 组件 | 作用 |
|---|---|
| Prometheus + Grafana | 指标采集与可视化:进程、延迟、成功率、队列积压 |
| 日志系统(ELK / Loki) | 集中式日志:查订单链路、错误堆栈 |
| 链路追踪(Jaeger / SkyWalking) | 一次下单从网关到交易所再回传的全链路耗时 |
5.2 核心指标清单
| 指标 | 定义/计算 | 健康线(示例) |
|---|---|---|
| 行情延迟 | 交易所行情时间 → 本地网关收到时间 | < 100ms(普通 WebSocket),< 5ms(撮合级) |
| 行情断流 | 连续 N 秒无新行情 | 0 次/日 |
| 订单成功率 | 成功订单 / 提交订单总数 | > 99% |
| 订单超时率 | 提交后超时未回报 / 总数 | < 0.1% |
| 接口错误率 | 交易所 API 返回错误 / 请求数 | < 1% |
| 接口限流命中率 | 触发限流重试次数 | 越低越好,> 1% 需要检查频率 |
| 资金偏差 | 交易所余额 vs 本地余额 | 必须恒为 0 |
| 撤单失败率 | 撤单超时未确认 / 撤单数 | < 1% |
| 队列积压 | Kafka topic 消费滞后(Lag) | 实时 topic < 几百条 |
5.3 告警分级
| 级别 | 方式 | 例子 |
|---|---|---|
| P0(立即) | 电话 + 短信 | 资金对不上、策略异常裸奔、断网 |
| P1(5 分钟内) | IM 群 @ | 行情断流、订单成功率下降、限流 |
| P2(当日处理) | IM + 工单 | 延迟升高、报表延迟 |
| P3(周例会) | 周报 | 容量预警、优化建议 |
六、部署架构
6.1 标准方案:Docker + Kubernetes
| 层 | 组件 | 说明 |
|---|---|---|
| 容器化 | Docker | 统一环境,避免「在我机器上能跑」 |
| 编排 | Kubernetes | 滚动更新、自愈、弹性扩容 |
| 网络 | Service Mesh / Ingress | 服务间通信与流量治理 |
| 配置 | ConfigMap / 环境变量 | 交易所 Key、费率等配置外置 |
| 状态 | PVC / 外部存储 | 交易系统核心状态不要依赖容器本地盘 |
交易类进程的部署纪律:状态必须可重建。持仓、订单状态放在外部存储或可用 Kafka 回放重建,容器可以随时被杀、被重启。
💡 状态必须可重建容器可以随时被杀被重启
状态必须可重建。 持仓、订单状态放在外部存储或可用 Kafka 回放重建,容器可以随时被杀、被重启——如果一次容器重启就需要人工恢复持仓,你的系统就还没达到上线标准。
💡 部署原则先解决正确性再谈延迟
先解决正确性,再谈延迟。 绝大多数量化策略(中低频)里,100ms 与 1ms 的差异无关紧要;先保证系统不丢单、不重复下单、可对账。基础设施建设的优先级应当是:数据不丢、订单不重、资金可对账、故障可恢复,其次才是延迟与吞吐。
6.2 进阶选项:低延迟部署
| 方案 | 解决的问题 | 代价 |
|---|---|---|
| 同机房托管(Colocation) | 与交易所服务器同机房/同可用区,网络延迟从几十 ms 降到 <1ms | 成本高、运维要求高,仅高频策略需要 |
| 专线(Dedicated Line) | 稳定带宽、低抖动,比公网波动小 | 按带宽收费 |
| 就近可用区 | 与交易所同云厂商同区域,普通量化够用 | 几乎无额外成本,建议优先做 |
部署原则:先解决正确性,再谈延迟。绝大多数量化策略(中低频)里,100ms 与 1ms 的差异无关紧要;先保证系统不丢单、不重复下单、可对账。
6.3 容灾与演练
- 双机房/多云至少保证「交易所 API 链路」有备用出口。
- 定期演练:主网关宕机后流量切换、数据库主从切换、Kafka 分区重建。
- 备份策略:订单与资金数据每日全量 + 实时 binlog 同步,备份异地存放。
七、网络安全
| 议题 | 最佳实践 |
|---|---|
| API Key 加密存储 | 密钥加密(AES/GCM)后存外部密钥管理服务(Vault/KMS),环境变量不落日志 |
| 密钥隔离 | 交易 Key 与只读 Key 分离;生产/测试环境各自独立 Key,权限最小化 |
| 签名算法 | 交易所通常要求 HMAC-SHA256/Ed25519:时间戳 + 请求参数 + 密钥签名;时间戳要防重放(5 分钟内有效) |
| IP 白名单 | 交易所侧配置:只有公司出口 IP 可调用提现/交易接口 |
| 多因子认证 | 后台管理、提现操作强制 MFA(TOTP/短信) |
| 提现审批 | 提现走人工双人复核,绝不允许程序自动提现 |
| 审计 | 所有管理操作留痕(谁、何时、做了什么),定期审计密钥轮换 |
| 内网隔离 | 策略/风控/柜台系统放私有网络,公网仅暴露行情网关等必要入口 |
交易系统的安全事故几乎都是「人」的失误:Key 打进了日志、Key 提交进了 Git、测试 Key 拥有提现权限。权限最小化 + 密钥轮换 + 审计留痕是三道必守底线。
💀 提现走人工双人复核绝不允许程序自动提现
提现走人工双人复核,绝不允许程序自动提现。 交易系统的安全事故几乎都是「人」的失误:Key 打进了日志、Key 提交进了 Git、测试 Key 拥有提现权限。权限最小化 + 密钥轮换 + 审计留痕是三道必守底线。
八、数据合规
| 议题 | 要点 |
|---|---|
| 个人信息保护 | 用户手机号/身份证等敏感信息加密存储、脱敏展示,遵守《个人信息保护法》(中国)等当地法规 |
| 交易记录保存义务 | 按监管要求保存订单、成交、资金流水(中国《证券法》等要求保存期限一般为 20 年,境外各市场要求不同,需按属地核查) |
| 跨境数据传输 | 数据出境需申报/评估(中国境内数据出境合规要求),境内外数据分域存储 |
| 数据最小化 | 只采集业务必需的数据,定期清理过期敏感数据 |
| 留痕与审计 | 数据访问权限分级,敏感数据访问留痕,配合监管检查 |
合规事项必须咨询法律与合规专业人士,本篇只提供工程视角的检查清单,不构成法律意见。
九、数据质量与数据治理
- 行情质量校验:价格异常(跳变超阈值)、时间戳乱序、重复推送——实时校验 + 告警,坏数据入库要打标签。
- 数据版本管理:行情数据重算/修复后必须升版本,回测结果与数据版本绑定,避免「同样的代码,结果不一样」。
- 元数据管理:品种合约信息(合约乘数、最小变动价位、交易时间表)集中维护,各系统引用不重复定义。
- 对账体系:行情(K 线可复算)、订单(交易所回报 vs 本地)、资金(每日三栏对账:交易所/清算所/本地)三层对账自动化。
⚠️ 风险提示
交易系统属于「高可用、高一致、高安全」系统:一笔重复下单、一次行情断流未被发现、一个 Key 泄露,都可能造成远超软件 bug 范畴的实资金损失。基础设施建设的优先级应当是:数据不丢、订单不重、资金可对账、故障可恢复,其次才是延迟与吞吐。所有监控指标、演练预案都应在真实故障前反复验证。本文内容仅用于工程学习与参考,不构成任何投资建议。