撮合引擎模块
版本: v0.2.0 更新日期: 2025-12-17 开发团队: @yutiansut @quantaxis
📋 目录
模块概述
撮合引擎是 QAExchange 的核心交易组件,负责订单的接收、匹配和成交处理。
设计原则
- 高性能: 单订单处理延迟 P99 < 10μs
- 高吞吐: 支持 > 300,000 orders/sec
- 零拷贝: 基于 qars::Orderbook 的零拷贝撮合
- 并发安全: DashMap + RwLock 无锁设计
模块结构
src/matching/
├── mod.rs # 模块入口,重导出 qars 类型
├── engine.rs # ExchangeMatchingEngine 核心实现
├── auction.rs # 集合竞价增强
├── trade_recorder.rs # 成交记录器
└── core/
└── mod.rs # MatchingEngineCore (独立进程版本)
架构设计
系统架构图
┌─────────────────────────────────────┐
│ ExchangeMatchingEngine │
│ │
OrderRequest │ ┌─────────────────────────────┐ │
─────────────────>│ │ DashMap<String, │ │
│ │ Arc<RwLock< │ │
│ │ Orderbook>>> │ │
│ └─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────┐ │
│ │ qars::Orderbook │ │ Success/Failed
│ │ ┌─────────┬─────────┐ │ │ ──────────────────>
│ │ │bid_queue│ask_queue│ │ │
│ │ │(买盘) │(卖盘) │ │ │
│ │ └─────────┴─────────┘ │ │
│ └─────────────────────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ TradeRecorder │ │ TradeRecord
│ │ (成交记录器) │ │ ──────────────────>
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
数据流
1. 订单接收
OrderRouter ──> ExchangeMatchingEngine.process_order()
2. 订单撮合
process_order() ──> Orderbook.process_order()
──> order_matching() [递归撮合]
3. 结果处理
Success::Filled ──> TradeRecorder.record()
──> TradeGateway.notify()
4. 行情更新
lastprice 更新 ──> MarketDataBroadcaster
核心组件
ExchangeMatchingEngine
主撮合引擎,管理多个合约的订单簿。
#![allow(unused)] fn main() { pub struct ExchangeMatchingEngine { /// 合约代码 -> 订单簿映射 orderbooks: DashMap<String, Arc<RwLock<Orderbook<InstrumentAsset>>>>, /// 成交记录器 trade_recorder: Arc<TradeRecorder>, /// 合约昨收盘价 prev_close_map: DashMap<String, f64>, /// 当前交易日 trading_day: Arc<RwLock<String>>, } }
InstrumentAsset
合约资产类型,使用字符串哈希作为高效的 Copy 类型。
#![allow(unused)] fn main() { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InstrumentAsset(u64); impl InstrumentAsset { pub fn from_code(code: &str) -> Self { // 使用 DefaultHasher 生成稳定哈希 } } }
Orderbook (来自 qars)
价格-时间优先的订单簿实现。
#![allow(unused)] fn main() { pub struct Orderbook<Asset> { pub asset: Asset, pub lastprice: f64, pub trading_state: TradingState, bid_queue: OrderQueue<Asset>, // 买盘:价格降序 ask_queue: OrderQueue<Asset>, // 卖盘:价格升序 sequence: AtomicU64, // 订单ID生成器 } }
撮合算法
价格-时间优先 (Price-Time Priority)
撮合规则:
1. 价格优先
- 买单:高价优先(愿意出更高价的买方优先成交)
- 卖单:低价优先(愿意接受更低价的卖方优先成交)
2. 时间优先
- 相同价格时,先到的订单优先成交
买盘排序:价格降序 → 时间升序
┌─────────┬─────────┬─────────┐
│ 85200 │ 85100 │ 85000 │ ← 价格从高到低
│ ts=100 │ ts=101 │ ts=102 │ ← 同价格按时间
└─────────┴─────────┴─────────┘
卖盘排序:价格升序 → 时间升序
┌─────────┬─────────┬─────────┐
│ 85300 │ 85400 │ 85500 │ ← 价格从低到高
│ ts=200 │ ts=201 │ ts=202 │ ← 同价格按时间
└─────────┴─────────┴─────────┘
撮合流程
#![allow(unused)] fn main() { fn process_order(order: OrderRequest) -> Vec<OrderProcessingResult> { match order { NewLimitOrder { direction, price, volume, .. } => { // 1. 检查是否可撮合 if can_match(direction, price) { // 2. 递归撮合直到无法继续 order_matching(order, results); } // 3. 剩余数量进入队列 if remaining_volume > 0 { store_new_limit_order(order); results.push(Success::Accepted { .. }); } } CancelOrder { id, direction } => { // 撤单处理 process_order_cancel(id, direction); } // ... } } }
成交类型
| 类型 | 说明 | 触发条件 |
|---|---|---|
Accepted | 订单被接受 | 订单进入队列等待 |
Filled | 完全成交 | 订单数量全部成交 |
PartiallyFilled | 部分成交 | 订单数量部分成交 |
Cancelled | 已撤销 | 撤单成功 |
Amended | 已修改 | 改单成功 |
API参考
合约注册
#![allow(unused)] fn main() { /// 注册新合约 /// /// # 参数 /// - `instrument_id`: 合约代码(如 "cu2501") /// - `prev_close`: 昨收盘价 /// /// # 返回 /// - `Ok(())`: 注册成功 /// - `Err(ExchangeError)`: 注册失败 pub fn register_instrument( &self, instrument_id: String, prev_close: f64, ) -> Result<(), ExchangeError> }
订单处理
#![allow(unused)] fn main() { /// 处理订单请求 /// /// # 支持的订单类型 /// - NewLimitOrder: 限价单 /// - NewMarketOrder: 市价单 /// - CancelOrder: 撤单 /// - AmendOrder: 改单 /// /// # 返回 /// - Vec<OrderProcessingResult>: 处理结果列表 pub fn process_order( &self, instrument_id: &str, order: OrderRequest<InstrumentAsset>, ) -> Vec<OrderProcessingResult> }
状态查询
#![allow(unused)] fn main() { /// 获取订单簿 pub fn get_orderbook(&self, instrument_id: &str) -> Option<Arc<RwLock<Orderbook<InstrumentAsset>>>> /// 获取所有合约列表 pub fn get_instruments(&self) -> Vec<String> /// 获取最新价格 pub fn get_last_price(&self, instrument_id: &str) -> Option<f64> /// 获取昨收盘价 pub fn get_prev_close(&self, instrument_id: &str) -> Option<f64> }
交易状态控制
#![allow(unused)] fn main() { /// 设置交易状态 /// /// # 状态类型 /// - PreAuctionPeriod: 集合竞价申报期 /// - AuctionOrder: 集合竞价下单期 /// - AuctionMatch: 集合竞价撮合期 /// - ContinuousTrading: 连续交易 /// - Closed: 休市 pub fn set_trading_state( &self, instrument_id: &str, state: TradingState, ) -> Result<(), ExchangeError> }
性能指标
基准测试结果
| 指标 | 测试值 | 目标值 | 状态 |
|---|---|---|---|
| 订单吞吐量 | ~368,000 orders/sec | > 100,000 | ✅ |
| 撮合吞吐量 | ~800,000 trades/sec | > 100,000 | ✅ |
| 单订单延迟 P50 | 3.09 μs | < 50 μs | ✅ |
| 单订单延迟 P99 | 6.11 μs | < 100 μs | ✅ |
| 撮合延迟 P50 | 2.22 μs | < 50 μs | ✅ |
| 撮合延迟 P99 | 2.40 μs | < 100 μs | ✅ |
| 深度撮合(100档) | 190.74 μs | < 1 ms | ✅ |
内存使用
- 单订单内存占用: ~128 bytes
- 10万订单簿深度: ~15 MB
- 100合约×1万深度: ~150 MB
测试覆盖
测试统计
test result: ok. 76 passed; 0 failed; 0 ignored
测试分类
| 类别 | 测试数 | 说明 |
|---|---|---|
| 基础功能 | 24 | InstrumentAsset、Engine创建等 |
| 买卖撮合 | 6 | 买入/卖出基础场景 |
| 成交类型 | 5 | 完整/部分成交 |
| 撤单场景 | 5 | 撤单成功/失败 |
| 价格时间优先 | 3 | 优先级验证 |
| 订单类型 | 4 | 限价/市价/改单 |
| 交易状态 | 3 | 连续/集合竞价/休市 |
| 多账户撮合 | 3 | 跨账户成交 |
| 边界条件 | 6 | 异常场景处理 |
| 多标的压力 | 3 | 并发多合约 |
| 大规模订单 | 3 | 千/万级订单 |
| 吞吐量测试 | 3 | 性能基准 |
| 延迟测试 | 3 | 延迟统计 |
| 并发安全 | 3 | 多线程测试 |
| 极端场景 | 4 | 压力/极值测试 |
详细测试文档请参考:撮合引擎测试指南