第三章:订单簿与报价引擎
做市系统的核心,说白了就两件事:看订单簿和发报价。
订单簿是市场的镜子,报价引擎是我们的手。这两者配合得好,你就能在市场上游刃有余。配合不好?嗯,我见过不少团队,订单簿解析慢了10微秒,整个策略就崩了。
3.1 订单簿数据结构
订单簿长什么样?其实就是一个价格-数量的映射表。买盘叫Bid,卖盘叫Ask。每个价格档位上,挂着对应的委托量。
我个人习惯用红黑树或跳表来实现。为什么?因为订单簿需要频繁的插入、删除和范围查询。数组太慢,哈希表又没法做范围遍历。
核心数据结构:
- Bid侧:按价格降序排列(价高者优先)
- Ask侧:按价格升序排列(价低者优先)
- 每个Level:价格 + 总量 + 订单数
来看一个简化版的订单簿结构:
// 订单簿层级
struct Level {
double price; // 价格
double volume; // 总量
int orderCount; // 订单数
};
// 订单簿
struct OrderBook {
map<double, Level, greater<double>> bids; // 买盘
map<double, Level> asks; // 卖盘
double lastUpdateTime;
};
我在项目中遇到过一个问题:直接用浮点数做Key。结果呢?价格精度导致两个本该合并的Level被分开了。后来我改用整数化价格,比如把1.2345存成12345,乘以最小价格精度。这个坑,大家一定要避开。
3.2 买卖报价生成逻辑
有了订单簿,怎么生成报价?
最基础的做法是:取买一和卖一的中间价,然后加减一个Spread。
但实际没那么简单。你想想看,如果市场深度很差,买一和卖一之间差了好几个Tick,你直接取中间价,很可能挂出去就被吃掉。
我的经验:报价生成要考虑三个维度:
- 市场深度:深度越浅,Spread要越大
- 波动率:波动越大,报价要更保守
- 库存状态:库存偏多,Bid要压低;库存偏少,Ask要抬高
我曾经做过一个策略,只盯着中间价报价。结果遇到一次闪电波动,库存瞬间被打穿。后来我加了一个动态Spread调整模块,根据实时波动率自动扩缩Spread,才稳住了。
报价生成的核心逻辑:
// 报价生成
Quote generateQuote(OrderBook& book, Inventory& inv) {
double midPrice = (book.bestBid() + book.bestAsk()) / 2.0;
double spread = calcDynamicSpread(book, inv);
double bidPrice = midPrice - spread / 2.0;
double askPrice = midPrice + spread / 2.0;
// 库存偏移
double inventorySkew = inv.skew() * 0.1;
bidPrice += inventorySkew;
askPrice += inventorySkew;
return Quote(bidPrice, askPrice);
}
3.3 报价更新频率与策略
报价更新频率,这是个老生常谈的问题。
更新太快,系统压力大,还可能被交易所限频。更新太慢,报价跟不上市场,容易被套利者盯上。
我个人建议:事件驱动 + 定时刷新。
- 事件驱动:订单簿有显著变化时(比如价格变动超过N个Tick),立即更新
- 定时刷新:即使没有事件,每隔X毫秒也刷新一次,防止报价过期
注意:不同交易所的限频规则差异很大。有的允许每秒100次,有的只允许10次。我曾经因为没注意限频,被某交易所封了API半小时。那半小时,库存敞口完全暴露,亏了不少。
更新策略上,我常用这几种:
| 策略名称 | 适用场景 | 更新频率 |
|---|---|---|
| 激进型 | 高流动性、低波动 | 每次Tick都更新 |
| 稳健型 | 中等流动性 | 每3-5个Tick更新一次 |
| 保守型 | 低流动性、高波动 | 固定间隔(如100ms) |
为什么会这样区分?说白了,流动性好的市场,你报价稍微慢一点,就被别人抢走了。流动性差的市场,你报价太频繁,反而容易暴露意图,被对手盯上。
下面这张图展示了订单簿、报价引擎和风控模块之间的协作关系:
嗯,这里要注意一点:报价更新不是越快越好。我见过有人把更新频率设到1ms一次,结果系统CPU跑满,订单簿解析都延迟了。最后报价反而更慢。
我的建议是:先根据交易所限频算出上限,然后留30%的余量。比如限频100次/秒,你就设70次/秒。这样既保证响应速度,又不会触发风控。
总结一下本章核心:
- 订单簿用红黑树或跳表实现,价格用整数化处理
- 报价生成要考虑深度、波动率和库存三个维度
- 更新策略采用事件驱动+定时刷新,频率要留余量
订单簿和报价引擎,是做市系统的心脏。心脏跳得好,整个系统才能稳定运行。下一章我们会聊到风控模块,到时候你会看到,报价引擎和风控是怎么配合的。
公众号:蓝海资料掘金营,微信deep3321