ZeroOverhead-HFT:把交易系统的每个组件做成编译期可替换的“乐高积木”。
本系统(代号 Legos)的核心架构是基于 Rust Trait 与泛型的静态分发设计。 六大组件全部定义为 trait,装配时只用泛型参数指定具体实现——编译期的 单态化(Monomorphization) 会把层层解耦的组件抹平、内联成一条直线代码, 运行期彻底消除虚函数指针跳转(Dynamic Dispatch),热路径零堆分配, 压榨出如同手写一体化 C++ 般的零开销低延迟表现。
切换积木 = 改一行泛型参数 = 重新编译。不改逻辑代码,不碰运行时配置。
// 回测装配
Pipeline<CsvFileFeed, SpscRingBuffer<MarketTick, 4096>, L2FlatArrayBook<10>,
MarketMakerStrategy, PassThroughRisk, SimulatedExchange>
// 实盘装配:只换泛型参数,其余代码一字不动
Pipeline<NativeItchParser, SharedMemoryBus<MarketTick, 4096>, L3MapBook,
MarketMakerStrategy, HardLimitRisk, FixProtocolGateway>按“由内到外、由低向高”的顺序构建(若先写策略/网关会导致 Trait 后期大规模重构):
| Phase | 内容 | 交付 crate |
|---|---|---|
| 1. 数据总线与基础设施 | 先确立核心数据结构 MarketTick(32 字节定长、Copy,热路径零堆分配)、Order,再实现 SpscRingBuffer(手写无锁队列:MaybeUninit 数组 + 原子 head/tail)和 SharedMemoryBus(Linux 共享内存跨进程)。无锁队列的并发安全是全系统的血管,最先跑通 |
legos-core, legos-bus |
| 2. 高频内存账簿 | L2FlatArrayBook:固定连续数组上的零堆分配二分插入/查找维护价格梯队,L1/L2 缓存友好;L3MapBook:按订单 ID 的树状结构,用于深度排队分析 |
legos-book |
| 3. 外围网关与仿真器 | CsvFileFeed(回测读文件)、SimulatedExchange(回测内存撮合)、NativeItchParser(实盘 NASDAQ ITCH 5.0 二进制解析)、FixProtocolGateway(实盘 FIX 4.4)。解析出的 MarketTick 丢进总线驱动账簿,形成输入闭环 |
legos-feed, legos-gateway, legos-risk |
| 4. 策略逻辑与泛型管线编织 | MarketMakerStrategy 做市、ArbitrageStrategy 跨场所套利;Pipeline 主循环用一行泛型声明把 6 大组件在编译期织成直线流水线;core_affinity 把主循环绑定到指定物理 CPU 核心;criterion 全链路延迟基准 |
legos-strategy, legos-app |
legos/
├── legos-core # 地基:MarketTick/Order/OrderIntent/OrderAck(定长 Copy)+ 六大 trait + 订单状态机
│ # MarketDataFeed / MessageBus / OrderBook / TradingStrategy /
│ # PreTradeRisk / ExecutionGateway —— 热路径无 dyn、无堆分配
├── legos-bus # Phase 1:SpscRingBuffer<T: Copy, const CAP: usize>(原子 head/tail)
│ # SharedMemoryBus(shm_open+mmap,extern "C" 直调 POSIX,零第三方依赖)
├── legos-book # Phase 2:L2FlatArrayBook<LEVELS>(扁平数组二分查找+copy_within 平移)
│ # L3MapBook(BTreeMap<u64, Order> + 价格档树)
├── legos-feed # Phase 3:CsvFileFeed(含 data/sample_ticks.csv 示例数据)
│ # NativeItchParser(ITCH 5.0:'A'/'E'/'C'/'X'/'D')
├── legos-risk # Phase 3:PassThroughRisk(恒 Ok,单态化后零开销)
│ # HardLimitRisk(单笔名义金额/数量/每秒订单数硬限额)
├── legos-gateway # Phase 3:FixProtocolGateway(FIX 4.4 NewOrderSingle,TCP,失败永不 panic)
│ # SimulatedExchange(内存撮合 + 滑点模型,64 槽位零堆分配报价表)
├── legos-strategy # Phase 4:MarketMakerStrategy / ArbitrageStrategy /
│ # PythonBindingStrategy(默认 stub;python feature 切真实嵌入)
├── legos-app # Phase 4:Pipeline<F, B, Bk, S, R, G> 泛型主循环 + core_affinity 绑核
│ # + benches/pipeline_bench.rs(criterion 全链路基准)
└── legos-testnet # 0 成本实盘验证:TestnetWsFeed(Binance Testnet 免费 WS 行情)
# TestnetRestGateway(Testnet 免费 REST 下单,虚拟资金)
# + src/bin/paper_trade.rs(paper-trading 压力测试)
所有替换都在类型层面完成。legos-app/src/main.rs 的 _demo_swap_bricks_at_compile_time
函数(虽未被 main 调用,但会被编译)就是证明:
// 回测 → 实盘:换三个泛型参数
let mut pipe: Pipeline<
CsvFileFeed,
SpscRingBuffer<MarketTick, 4096>,
L3MapBook, // ← L2FlatArrayBook<10> 换成 L3MapBook
MarketMakerStrategy,
HardLimitRisk, // ← PassThroughRisk 换成 HardLimitRisk
FixProtocolGateway, // ← SimulatedExchange 换成 FixProtocolGateway
> = Pipeline::new(feed, bus, book, strategy, risk, gateway);| 场景 | 行情 | 总线 | 账簿 | 策略 | 风控 | 网关 |
|---|---|---|---|---|---|---|
| 本地回测 | CsvFileFeed |
SpscRingBuffer |
L2FlatArrayBook<10> |
MarketMakerStrategy |
PassThroughRisk |
SimulatedExchange |
| 实盘交易 | NativeItchParser |
SharedMemoryBus |
L2FlatArrayBook<10> |
MarketMakerStrategy |
HardLimitRisk |
FixProtocolGateway |
| 深度研究 | CsvFileFeed |
SpscRingBuffer |
L3MapBook |
PythonBindingStrategy |
PassThroughRisk |
SimulatedExchange |
| 模拟盘压力测试 | TestnetWsFeed |
(直连账簿) | L2FlatArrayBook<10> |
MarketMakerStrategy |
HardLimitRisk |
TestnetRestGateway |
全程免费:公开行情不要 key,testnet 下单用虚拟资金。分两步:
# 抓一天的 BTCUSDT 公开成交数据(data.binance.vision 日度 zip,免费、无需 key)
python3 scripts/fetch_ticks.py --symbol BTCUSDT --date 2026-09-27 --out data/btcusdt.csv
# 输出末尾有一行校验:OK rows=478532 cols=symbol_id,side,price,qty,kind,ts_ns ts_range=[...]
# 用抓到的数据跑回测(第一个 CLI 参数覆盖默认示例 CSV)
cargo run -p legos-app -- data/btcusdt.csv输出格式与 CsvFileFeed 的解析 schema 严格一致
(symbol_id,side,price,qty,kind,ts_ns,见 legos-feed/SPEC.md),
价格/数量刻度(1e-8)与 TestnetWsFeed 完全对齐(对齐单测覆盖)。
说明:公开成交数据只有
TRADE事件、没有挂单事件,账簿形不成买卖盘口, 所以做市策略的intents为 0——这是预期行为,不是 bug。 这一步验证的是吞吐链路:47.8 万个 tick 零丢失走完 feed → 总线 → 账簿 → 策略 → 风控 → 网关(含背压不变量回归测试)。 策略行为验证请用legos-feed/data/sample_ticks.csv(含 ADD 事件)。
也可用 OKX 公开接口抓近期数据(同样免费、无需 key):
python3 scripts/fetch_ticks.py --source okx --symbol BTCUSDT --max-trades 10000 --out data/btcusdt_okx.csv把泛型参数换成实盘积木(legos-testnet/src/bin/paper_trade.rs 已装配好):
TestnetWsFeed // ← CsvFileFeed:Binance Testnet 免费 WS 行情,无需 key
→ L2FlatArrayBook // 账簿不变
→ MarketMakerStrategy
→ HardLimitRisk
→ TestnetRestGateway // ← SimulatedExchange:Testnet REST 下单,虚拟资金# 1. 免费申请 testnet key(虚拟资金,0 成本):
# 打开 https://testnet.binance.vision → 登录 → API Management → Create API(HMAC)
export BINANCE_TESTNET_API_KEY=...
export BINANCE_TESTNET_API_SECRET=...
# 2. 跑模拟盘(默认 BTCUSDT,500 个 tick 后退出并打印统计)
cargo run -p legos-testnet --bin paper_trade -- BTCUSDT 500安全说明:
- 行情流不需要 key,匿名即可订阅;
- 下单 key 只从环境变量读取,代码里没有任何硬编码密钥 (缺失时直接报错并提示申请步骤,不会静默失败);
- 下的是 testnet 真实订单(虚拟资金),不是 dry-run, 但每单后 sleep 300ms 做限流保护,Ctrl-C 可随时中断;
- 如所在地区打不开
testnet.binance.vision(如返回 451),TestnetWsFeed::binance_mainnet可换用主网公开行情流做只读验证。
以下为真实录制的终端输出(非示意)。
$ cargo run -p legos-app --bin legos-app
[legos-app] 主循环已绑定到 CPU 核心 0
[legos-app] 回测数据源: legos-feed/data/sample_ticks.csv
[legos-app] 回测完成: PipelineStats {
ticks: 20,
intents: 18,
sent: 18,
rejected_by_risk: 0,
rejected_by_gateway: 0,
fills: 0,
illegal_transitions: 0,
}解读:做市策略对 20 个 tick 产生 18 个交易意图,全部通过风控并送达模拟网关,订单状态机零非法转换。fills: 0 是因为示例数据的买卖报价没有交叉(模拟撮合只在交叉时成交);链路本身已被 intents/sent 验证,成交路径的覆盖见单测与基准。
$ cargo run --release -p legos-app --bin tail_latency
tail_latency: N = 10000000 ticks
pinned to core 1
tsc_hz = 1.498e9 ticks/s (200ms sleep calibration)
rdtsc overhead floor = 15 cycles (subtracted from every sample)
warmup done (200000 ticks)
fills = 9999996
sort took 28.847599ms
+----------------+------------+
| metric | latency |
+----------------+------------+
| mean | 35.8 ns |
| p50 | 30.0 ns |
| p99 | 70.1 ns |
| p999 | 170.2 ns |
| max | 3169124.9 ns |
+----------------+------------+
note: per-tick pipeline latency, in-process compute only (no network I/O).解读:逐 tick 用 CPU 时间戳计数器计时并扣除计时器本底;p999 170.2ns,max 的 3.2ms 是共享虚拟机的调度噪声(见 PERF.md)。口径为纯进程内计算,不含网络 I/O。
见上文"0 成本实盘验证 → 第 2 步"。本机因 Binance 地理限制(451)无法录制,请在本地运行:
cargo run -p legos-testnet --bin paper_trade -- BTCUSDT 500需要 Rust 1.70+(本仓库用 rustup 安装,见环境备注):
cargo build --workspace # 构建全部 9 个 crate
cargo test --workspace # 运行全部单测(88 个,含多线程 SPSC 压力测试)
cargo run -p legos-app # 回测:CSV → 总线 → 账簿 → 做市策略 → 风控 → 模拟撮合
cargo run -p legos-app -- data/btcusdt.csv # 用 scripts/fetch_ticks.py 抓的真实数据回测
cargo bench -p legos-app # criterion 全链路延迟基准(feed→bus→book→strategy→risk→gateway)启用 Python 嵌入(需要 Python 3.8+ 开发环境):
cargo build -p legos-strategy --features pythoncargo bench -p legos-app(release,benches/pipeline_bench.rs),机器:x86_64 Linux:
| 基准 | 含义 | 结果 |
|---|---|---|
spsc_ring_buffer/push_pop_tick |
无锁队列一推一取 | ~17.4 ns |
l2_book/apply_tick |
L2 账簿处理一个 MarketTick | ~21.7 ns |
full_pipeline/tick_to_fill_1000 |
全链路 1000 tick(feed→bus→book→strategy→risk→gateway) | ~47.8 µs(≈47.8 ns/tick) |
注:以上为开发机上的相对参考值,实盘延迟以生产环境实测为准。
| 位置 | Stub 内容 | 原因 |
|---|---|---|
legos-strategy::PythonBindingStrategy(默认构建) |
on_tick 恒返回 None 的同名占位 |
避免默认构建依赖 Python 解释器;--features python 切换为 pyo3 真实嵌入 |
NativeItchParser 未实现的消息类型('S'/'R'/'H'/'P'/'Q'/'B'/'U' 等) |
按长度跳过 | 实现 'A'/'E'/'C'/'X'/'D' 已覆盖盘口重构所需的全部订单流;其余类型在模块文档中列表说明,可按需追加分支 |
SimulatedExchange 的非交叉限价单 |
返回 Accepted(挂单,不建完整订单簿) |
回测撮合的最小可用语义;文档化说明 |
ArbitrageStrategy |
只发出买入腿意图 | 卖出腿对冲归执行层/组合管理;文档化说明 |
CsvFileFeed 的 order_id |
恒为 0 | CSV 格式不携带订单号;L2 账簿不依赖它,L3 场景请用 ITCH feed |
MIT