当前位置: 首页 > news >正文

C++ 纳秒级交易系统设计

  • C++ 纳秒级交易系统设计
  • 低延迟需求分析
  • 核心数据结构 - Order Book
  • 性能优化原则
  • Lock-Free Data Structures
  • 多核并发处理
  • 性能测量
  • C++ 特性在低延迟中的应用
  • 相关技术栈


  • 罗马帝国 Hueman Contracts

    • 罗马人会在大型活动(如 Syracuse Maximus,可容纳 200,000-300,000 人)前一年,向农民、酿酒商等预定物资
    • 通过提前确定价格,发明了早期的衍生品交易
    • 目的:Reduce World Uncertainty
  • World Uncertainty Index

    • 该指数主要记录负面事件
    • 人类作为心理性生物,对潜在损失的权重高于潜在收益
    • 这解释了为什么人们难以安睡时,往往是担心可能亏损

1.2 现代市场制造(Market Making)

  • 定义:Market Maker 是在金融市场中提供流动性的角色,他们同时报出买入价(Bid)和卖出价(Ask)
  • 盈利模式:通过买卖价差(Bid-Ask Spread)获取微薄利润
  • 特点:Market Making is aLosers Game
    • 不是靠某个"银弹"打败市场
    • 需要持续地在所有方面都做得好
    • 小利润来自承担风险(optionality)的补偿
    • 风险不可免费,因为价格会波动

1.3 C++ 纳秒级交易系统设计

为什么需要低延迟编程?

类别说明示例
快速响应不确定事件对突发新闻、市场变化做出即时反应新闻发布后更新报价、取消订单
"聪明"地处理包含优秀的模型、算法等智能决策更好的交易策略、风险计算

第二部分:低延迟需求分析

2.1 高频交易中的延迟来源

在高频交易(HFT)系统中,延迟发生在多个环节:

消息到达 → 网络接收 → 协议解析 → 订单簿更新 → 策略计算 → 订单生成 → 发送确认 ↓ 每个环节都可能成为瓶颈

2.2 延迟量级参考

延迟级别典型耗时说明
毫秒级1-1000 ms传统系统
微秒级1-1000 μs普通量化系统
纳秒级1-1000 ns高频交易前沿

2.3 交易系统中的参与者与延迟要求

不同市场参与者对延迟的要求不同:

参与者类型延迟敏感度主要策略
Market Maker极高被动提供流动性,依赖快速响应
Arbitrageur极高跨市场/跨品种套利
统计套利基于模型的交易
基本面交易中低基于长期分析

第三部分:核心数据结构 - Order Book

订单簿是交易系统的核心数据结构,记录市场中所有的买卖订单:

  • Bid 侧:买家愿意购买的价格和数量
  • Ask 侧:卖家愿意出售的价格和数量
  • spread买卖价差 = Ask - Bid

3.2 操作

操作说明
Add/Insert添加新订单到订单簿
Remove/Cancel取消已有订单
Modify修改订单价格或数量
Match价格匹配时成交

3.3 数据结构选择原则

高频交易系统选择订单簿数据结构时的考量:

  1. 查找速度:快速定位特定价格或订单
  2. 插入/删除效率:订单更新频繁
  3. 内存局部性:缓存友好
  4. 确定性延迟:避免最坏情况导致的延迟尖刺

第四部分:性能优化原则

4.1 核心工程原则

  1. Make It Work, Make It Right, Make It Fast

    • 先正确实现,再优化性能
  2. Measure Before Optimizing

    • 必须有性能数据支撑优化决策
  3. Optimize the Common Case

    • 关注最频繁的执行路径
  4. Embrace Hardware

    • 充分利用 CPU 硬件特性

4.2 CPU 硬件特性利用

4.2.1 CPU 缓存(Cache)
缓存层级典型大小访问延迟
L1~32 KB~1 ns
L2~256 KB~3-4 ns
L3~10-30 MB~10-20 ns
主存GB 级别~100 ns

优化策略

  • 数据对齐:确保数据结构与缓存行边界对齐
  • Prefetch:提前将数据加载到缓存
  • 数据布局优化:使用SoA(Structure of Arrays)替代AoS(Array of Structures)
4.2.2 分支预测(Branch Prediction)
  • 现代 CPU 通过猜测分支方向来流水线执行
  • 错误预测代价:15-25 个时钟周期
  • 优化方法
    • 减少条件分支数量
    • 使用 likely/unlikely 提示
    • 考虑条件执行或查找表
4.2.3 指令级并行(ILP)
  • CPU 可以在同一时钟周期执行多条独立指令
  • 方法
    • 重排指令以增加并行度
    • 减少数据依赖
    • 展开循环

4.3 内存访问优化

4.3.1 NUMA(Non-Uniform Memory Access)

在多插槽服务器上:

  • 每个 CPU 插槽有本地内存
  • 访问远程内存有额外延迟
  • 优化:线程优先访问本地内存
4.3.2 内存分配策略
策略优点缺点
预分配池无分配延迟、缓存友好内存浪费
对象池减少碎片管理复杂
TLSF 等分配器确定性分配时间-

4.4 缓存优化技巧

数据结构设计

AoS vs SoA

// AoS (Array of Structures) - 缓存不友好structOrder{uint64_tprice;uint32_tquantity;uint32_ttimestamp;};Order orders[1000000];// SoA (Structure of Arrays) - 缓存友好structOrderBook{uint64_tprices[1000000];uint32_tquantities[1000000];uint32_ttimestamps[1000000];};
向量化(Vectorization)
  • 利用 SIMD(Single Instruction Multiple Data)指令
  • SSE/AVX 可以在单条指令处理多个数据
  • 示例场景:批量价格计算、订单匹配
// 伪代码示例:批量处理 4 个价格__m256d prices=_mm256_load_pd(price_ptr);__m256d result=_mm256_mul_pd(prices,multiplier);_mm256_store_pd(result_ptr,result);

第五部分:Lock-Free Data Structures

5.1 为什么需要无锁结构?

对比项有锁方案无锁方案
延迟可能阻塞等待确定性等待
优先级反转可能发生避免
死锁可能发生避免
复杂度相对简单实现复杂

5.2 原子操作

操作说明CAS 用法
CASCompare-And-Swap,比较并交换最基础的无锁原语
FAAFetch-And-Add,原子加法计数器、序列号
Load/Store原子读写数据一致性

5.3 无锁订单簿设计考量

// 简化的无锁订单指针更新示例structalignas(64)OrderNode{uint64_tprice;uint32_tquantity;std::atomic<OrderNode*>next;};// 使用 CAS 更新链表boolupdate_head(std::atomic<OrderNode*>&head,OrderNode*new_node){OrderNode*old_head=head.load(std::memory_order_relaxed);new_node->next.store(old_head,std::memory_order_relaxed);returnhead.compare_exchange_weak(old_head,new_node,std::memory_order_release,std::memory_order_relaxed);}

5.4 ABA 问题与解决方案

  • ABA 问题:线程 A 读取到值 A,切换;线程 B 将值改为 C 再改回 A;线程 A 继续认为值没变
  • 解决方案
    • 使用双宽 CAS(DCAS)存储指针+版本号
    • 使用带计数的指针(如std::shared_ptr
    • 使用内存管理器的回收延迟

第六部分:多核并发处理

6.1 线程模型设计

高频交易系统典型线程模型:

模型特点适用场景
单线程事件循环简单、无锁单核心处理、IO 密集
Per-Symbol 线程每个品种独立处理多品种、低耦合
管道模型阶段间流水线复杂处理流程
混合模型结合多种模型实际生产系统

6.2 避免 False Sharing

False Sharing发生在不同线程修改同一缓存行中的数据时:

// 错误示例:False Sharingstruct{std::atomic<uint64_t>bid_price;// 线程 1 修改std::atomic<uint64_t>ask_price;// 线程 2 修改// 两者在同一缓存行,导致伪共享}order_book;// 正确示例:填充避免 False Sharingstruct{std::atomic<uint64_t>bid_price;// 线程 1 修改charpadding[64-sizeof(uint64_t)];std::atomic<uint64_t>ask_price;// 线程 2 修改charpadding2[64-sizeof(uint64_t)];}order_book;

6.3 内存屏障(Memory Barriers)

屏障类型说明使用场景
Compiler Barrier防止编译器重排汇编内联
Hardware Barrier防止 CPU 重排多线程同步
Full Barrier双向阻塞重要同步点
Acquire获取之前的加载读取共享数据
Release释放之后的存储写入共享数据

第七部分:性能测量方法

7.1 测量的重要性

“If you can’t measure it, you can’t improve it.”

性能优化的前提是准确的测量

7.2 测量工具与技术

7.2.1 硬件性能计数器(PMCs)

使用perf工具:

# 统计缓存命中率perfstat-ecache-references,cache-misses ./trading_system# 记录并分析perf record-g./trading_system perf report
7.2.2 低延迟测量技术
技术说明精度
RDTSCRead Time-Stamp Counter,读取 CPU 时间戳计数器纳秒级
RDTSCPRDTSC with Processor ID,防止乱序纳秒级
Clock_gettimePOSIX 时钟纳秒级(CLOCK_MONOTONIC)
// 使用 RDTSC 进行延迟测量inlineuint64_tget_time_ns(){unsignedintdummy;return__rdtscp(&dummy);}// 使用示例uint64_tstart=__rdtsc();// ... 操作 ...uint64_tend=__rdtsc();uint64_tcycles=end-start;doublelatency_ns=cycles/(CPU_FREQ_GHZ*1000);
7.2.3 追踪与日志
  • 追踪(Tracing):记录每个操作的时序
  • 采样分析:低开销的 CPU 使用分析
  • 热路径分析:识别最频繁的执行路径

7.3 延迟分布分析

指标说明重要性
Mean平均延迟整体性能
Median (P50)中位数典型情况
P9999 百分位大多数请求
P99999.9 百分位尾部延迟
Max最大延迟极端情况

高频交易更关注 P999 而非平均值,因为一次极端延迟可能导致错过交易机会。

7.4 微基准测试(Microbenchmarks)

使用 Google Benchmark 库:

#include<benchmark/benchmark.h>staticvoidBM_OrderBookUpdate(benchmark::State&state){OrderBook book;for(auto_:state){book.update(100,500);}}BENCHMARK(BM_OrderBookUpdate);BENCHMARK_MAIN();

第八部分:C++ 语言特性在低延迟中的应用

8.1 编译期计算

技术说明示例
constexpr编译期求值常量计算
模板元编程类型级计算类型特化
if constexpr编译期条件分支减少分支

8.2 虚函数与内联

类型优点缺点
普通虚函数运行时多态间接调用、难以内联
模板编译期多态代码膨胀
CRTP静多态、可内联语法复杂
// CRTP 示例template<typenameDerived>classOrderBookBase{public:voidupdate(){// 静态派发,编译时内联static_cast<Derived*>(this)->update_impl();}};classFastOrderBook:publicOrderBookBase<FastOrderBook>{public:voidupdate_impl(){/* 高效实现 */}};

8.3 内存管理

技术开销适用场景
栈分配小对象、固定大小
对象池最小频繁创建销毁
arena/区域分配同生命周期对象
智能指针有一定开销非性能关键路径

第九部分:建议

9.1 设计决策清单

在低延迟系统设计中需要考虑的问题:

  • 数据结构的时间复杂度是否满足需求?
  • 是否有不必要的锁竞争?
  • 缓存命中率如何?
  • 是否有 False Sharing?
  • 分支预测成功率如何?
  • 内存分配是否可预期?
  • 系统调用的频率?

原则

  1. 强调工程实践,关注实际问题
  2. 持续改进,不是一次性的银弹方案
  3. 全面优秀:Market Making 的核心理念——持续在所有方面做得好
  4. 未雨绸缪:像罗马人一样做好规划

技术栈

类别工具/库用途
性能分析perf, VTune, Valgrind性能分析
基准测试Google Benchmark微基准测试
并发TBB, Folly, Seastar并行库
网络DPDK, Solarflare低延迟网络
日志spdlog, libfmt高性能日志
  • 书籍
    • Advances in Financial Machine Learning- López de Prado
    • Quantitative Trading- Chan
    • C++ High Performance- Bjorn Andrist
  • 会议:CppCon, Meeting C++, ACCU
  • 论文:ACM SIGOPS, IEEE Transactions

9.2 反模式(Anti-Patterns)

反模式问题替代方案
全局锁严重串行化无锁结构或细粒度锁
不必要的虚函数间接调用CRTP、模板
过度抽象代码复杂度YAGNI 原则
忽略测量盲目优化先测量再优化
premature optimization浪费时间关注瓶颈

总结

  1. 市场制造的本质:需要持续在所有方面做到优秀
  2. 低延迟的两大驱动:快速响应 + 智能决策
  3. 优化方向
    • CPU 缓存友好设计
    • 无锁数据结构
    • 多核并发优化
    • 准确的性能测量
  4. 工程原则:测量优先、关注瓶颈、持续改进

高频交易系统的优化是一个系统性工程,需要在算法数据结构系统设计等多个层面协同优化。

http://www.jsqmd.com/news/1106238/

相关文章:

  • React路由开发
  • 毕业设计项目 基于深度学习的驾驶行为检测(玩手机)
  • 昇腾AI处理器上下文切换优化实践与性能提升
  • 大众点评23年干了件“蠢”事
  • Go WaitGroup开发实践
  • Unity合批优化:静态与动态合批全解析
  • 报文发送非网络基本功能
  • 冻库低温环境下的机器人搬运技术测评
  • Claude Code 接入第三方模型指南
  • ASP.NET Core 之 Identity 入门(一)
  • React Hooks开发实践
  • 集成,持续交付,持续部署,敏捷开发,DevOps的关系
  • 2026年AI论文软件盘点:12款神器助你高效完成初稿生成、排版和降AI率
  • Android开发转AI Agent:第12天——Function Calling,让LLM从“说话“变成“做事“
  • Spring MVC开发实践教程
  • Python装饰器开发实践
  • step1. 调用摄像头
  • 给阿嬤一封来自云端的信(上)
  • NestJS框架教程
  • STM32与MAX9744实现高效音频放大系统设计
  • 量子计算中的基态制备与经典储层方法解析
  • 终极Win11系统优化指南:免费工具让你的Windows 11运行如飞
  • 游戏编程十年总结(下)
  • AI应用GEO排名优化指南:提升搜索可见性
  • 如何提取 Word 文档中的表格并导出为 Excel(Python 教程)
  • 第5章 Function Call 与工具调用框架《AI Agent 开发平台资深技术专家 AI Agent 应用架构师 CTO 面试题库详解》
  • 微架构安全:MDAV问题与防御机制集成挑战
  • JSON数据格式解析与应用
  • 【安全】Sql注入漏洞的危害和防御
  • Medisca在创始人Antonio Dos Santos的引领下开启发展新篇章