2. 订单簿数据结构:限价单与市价单、订单簿的Bid/Ask结构、价格优先与时间优先原则
做市商的订单簿,说白了就是一张实时更新的「买卖挂单表」。我刚开始接触这个的时候,觉得不就是个价格列表嘛,有什么难的?后来真上手做高频策略才发现,这里面的门道比想象中深得多。
今天咱们就把订单簿的底层数据结构拆开来看。你理解了这些,后面搭建策略时才能心里有底。
2.1 限价单与市价单:两种最基础的订单类型
先说说订单类型。交易所里每天跑着几百万笔订单,但归根结底就两种:限价单和市价单。
限价单(Limit Order)
限价单就是你指定一个价格,只有市场价到了这个位置才成交。比如你想在100元买入,那就挂一个限价买单。价格不到100,单子就一直在订单簿里挂着。
我个人习惯把限价单叫做「耐心单」。它不急着成交,但能帮你拿到更好的价格。做市商的核心工作,其实就是大量挂限价单,赚取买卖价差。
市价单(Market Order)
市价单就简单了——你不管价格,直接按当前最优价吃掉对手盘。想快速买入?直接下市价单,系统会从卖一、卖二、卖三一路吃下去。
市价单我管它叫「急性子单」。它保证成交,但价格可能滑点。我在项目中遇到过好几次,行情剧烈波动时,市价单吃下去,成交均价比预期差了好几个tick,那叫一个心疼。
| 订单类型 | 成交保证 | 价格保证 | 典型用途 |
|---|---|---|---|
| 限价单 | 否 | 是 | 做市、挂单、低买高卖 |
| 市价单 | 是 | 否 | 快速建仓、止损、套利 |
2.2 订单簿的Bid/Ask结构:买卖双方的「战场地图」
订单簿长什么样?说白了就是两张表:一张买单表(Bid),一张卖单表(Ask)。
买单这边,价格从高到低排列。最高价的买单叫「买一」,次高的叫「买二」,以此类推。卖单那边正好相反,价格从低到高排列,最低价的卖单叫「卖一」。
你想想看,买一和卖一之间的差价,就是做市商最关心的「Spread」。这个差价越小,说明市场流动性越好。
下面这张图,是我用SVG画的订单簿结构图,帮你直观理解Bid/Ask的排列逻辑:
2.3 价格优先与时间优先原则:订单簿的「排队规则」
订单簿里的单子怎么排队?两个原则:价格优先,时间优先。
价格优先——买单出价高的排前面,卖单出价低的排前面。这很好理解,谁出的价更「狠」,谁就先成交。
时间优先——价格相同的情况下,先挂单的先成交。这就跟排队买奶茶一样,先来的先得。
嗯,这里要注意:不同交易所对时间优先的实现细节略有不同。有的按纳秒级时间戳排序,有的按订单到达网关的顺序。做高频策略时,这些细节会直接影响你的成交概率。
2.4 用Python实现一个简单的订单簿
光说不练假把式。下面我用Python写一个极简的订单簿,帮你把上面的概念串起来。
class OrderBook:
def __init__(self):
self.bids = [] # 买单列表,格式: [价格, 数量, 时间戳]
self.asks = [] # 卖单列表
def add_limit_order(self, side, price, quantity, timestamp):
"""添加限价单"""
order = [price, quantity, timestamp]
if side == 'buy':
self.bids.append(order)
# 价格优先:买单从高到低排序
self.bids.sort(key=lambda x: (-x[0], x[2]))
else:
self.asks.append(order)
# 价格优先:卖单从低到高排序
self.asks.sort(key=lambda x: (x[0], x[2]))
def get_top_of_book(self):
"""获取最优买卖价"""
best_bid = self.bids[0][0] if self.bids else None
best_ask = self.asks[0][0] if self.asks else None
spread = best_ask - best_bid if best_bid and best_ask else None
return best_bid, best_ask, spread
# 使用示例
ob = OrderBook()
ob.add_limit_order('buy', 100.95, 3000, 1)
ob.add_limit_order('buy', 100.90, 1500, 2)
ob.add_limit_order('sell', 101.05, 1200, 1)
ob.add_limit_order('sell', 101.10, 2500, 2)
bid, ask, spread = ob.get_top_of_book()
print(f"买一: {bid}, 卖一: {ask}, 价差: {spread}")
# 输出: 买一: 100.95, 卖一: 101.05, 价差: 0.10
这段代码虽然简单,但核心逻辑都在了。实际生产环境中,订单簿的数据结构会用红黑树或跳表来实现,保证O(log n)的插入和查询性能。不过原理是一样的——价格优先排第一,时间优先排第二。
好了,订单簿的数据结构就聊到这儿。记住三个核心:限价单和市价单的区别、Bid/Ask的排列方式、价格优先和时间优先的排队规则。这些东西看着基础,但做市商策略的每一行代码,都建立在这些基石之上。
公众号:蓝海资料掘金营,微信deep3321