一笔交易是如何完成的?深入浅出解析订单簿匹配

192 阅读12分钟

订单薄的匹配机制是交易撮合的核心功能,直接决定了交易是否可以高效、公平、有序的完成。并且订单薄在匹配过程中也间接形成了商品的价格,那么订单薄究竟是如何工作的呢?

让我们通过一个简单的例子来一起了解一下吧

订单匹配和价格更新

🎯 问题场景

让我们从一个简单的场景开始,假设我们要交易某种代币。根据市场上买家和卖家的不同,我们可以将这些交易登记在两个不同的薄子上:一个叫做买家薄,记载了每一位买家要购入的价格和数量;另一个叫做卖家薄,记载了每一位卖家要卖出的价格和数量。为了更快的达成交易,买家薄的价格需要从大到小排列,而卖家薄的价格则需要从小到大排列,这样当我们同时从队首将卖家和买家的交易拿出来进行匹配时,可以更快的达成“买单价格>>卖单价格”的条件。

买单簿(Bids):
- 买家A:价格7,数量10
- 买家B:价格6,数量8  
- 买家C:价格5,数量12

卖单簿(Asks):
- 卖家X:价格4,数量6
- 卖家Y:价格5,数量9
- 卖家Z:价格6,数量7

📊 订单簿状态图

可以通过订单薄的状态图直观的判断,当前是否存在可以被撮合的交易。我们按照价格的排序将买单薄和卖单薄绘制在一张图上,当同一个价格买家薄和卖家薄存在重合部分时,就说明当前交易满足了撮合条件,直到交易到没有重合的部分时,说明当前订单薄没有可以撮合的交易,停止撮合,等待新的交易加入订单薄。而重合部分的挂单数量叫做订单薄的深度,深度不足时,则可能导致滑点过高、交易成本上升、价格容易被操控等一系列问题。

价格    买单簿(Bids)          卖单簿(Asks)
 7      A: 10个              |
 6      B: 8Z: 75      C: 12Y: 94      |                    X: 6

🔄 匹配过程详解

我们通过一步步演示上文中订单薄的交易成交过程,来加深对于订单薄匹配机制的理解。

第一步:检查是否可以匹配

匹配条件:买单价格 ≥ 卖单价格

检查最高买单 vs 最低卖单:
- 最高买单:买家A,价格7
- 最低卖单:卖家X,价格4
- 7 ≥ 4 ✓ 可以匹配!

第二步:开始匹配

第一轮匹配:买家A vs 卖家X
买家A:价格7,数量10
卖家X:价格4,数量6

匹配结果:
- 成交价格:4(按卖单价格成交)
- 成交数量:6(取较小值)
- 买家A获得:6个代币,支付 6 × 4 = 24 USDC
- 卖家X获得:24 USDC,卖出6个代币

更新后状态:
买家A:价格7,剩余数量4(10-6)
卖家X:完全成交,从卖单簿移除
第二轮匹配:买家A vs 卖家Y
买家A:价格7,剩余数量4
卖家Y:价格5,数量9

匹配结果:
- 成交价格:5(按卖单价格成交)
- 成交数量:4(买家A的剩余数量)
- 买家A获得:4个代币,支付 4 × 5 = 20 USDC
- 卖家Y获得:20 USDC,剩余5个代币(9-4)

更新后状态:
买家A:完全成交,从买单簿移除
卖家Y:价格5,剩余数量5
第三轮匹配:买家B vs 卖家Y
买家B:价格6,数量8
卖家Y:价格5,剩余数量5

匹配结果:
- 成交价格:5(按卖单价格成交)
- 成交数量:5(卖家Y的剩余数量)
- 买家B获得:5个代币,支付 5 × 5 = 25 USDC
- 卖家Y获得:25 USDC,完全成交

更新后状态:
买家B:价格6,剩余数量3(8-5)
卖家Y:完全成交,从卖单簿移除
第四轮匹配:买家B vs 卖家Z
买家B:价格6,剩余数量3
卖家Z:价格6,数量7

匹配结果:
- 成交价格:6(价格相等,按6成交)
- 成交数量:3(买家B的剩余数量)
- 买家B获得:3个代币,支付 3 × 6 = 18 USDC
- 卖家Z获得:18 USDC,剩余4个代币(7-3)

更新后状态:
买家B:完全成交,从买单簿移除
卖家Z:价格6,剩余数量4

📈 最终状态

成交后的订单簿

价格    买单簿(Bids)          卖单簿(Asks)
 7      |                    |
 6      |                    Z: 45      C: 12个              |
 4      |                    |

成交记录汇总

轮次买家卖家成交价格成交数量总金额
1A(7)X(4)4624
2A(7)Y(5)5420
3B(6)Y(5)5525
4B(6)Z(6)6318

💰 价格更新机制

最新成交价格

最新成交价格 = 最后一笔成交的价格 = 6

价格更新规则

  1. 买单价格 ≥ 卖单价格时成交
  2. 成交价格 = 卖单价格(价格优先原则)
  3. 最新成交价格 = 最后一笔成交的价格

🎯 关键概念解释

1. 价格优先原则

价格优先原则”主要体现在两个方面:

  1. 订单优先级:买单按价格从高到低排序,卖单按价格从低到高排序。这意味着出价最高的买家和要价最低的卖家拥有最高的优先成交权,即“出价越高,排队越靠前,越快成交”。
  2. 成交价确定:当订单匹配时,成交价格是触发该次匹配的订单的价格。由于匹配总是由最高买价和最低卖价触发,而买价≥卖价是匹配条件,因此成交价可以是买方价格或卖方价格。在绝大多数交易所的规则中,为了奖励提供更好价格的挂单方,成交价会采用先挂入订单簿的那个订单的价格(即“时间优先”的另一种体现)。在上述的例子中,因为是卖单X(价格4)先存在于订单簿中,后到的买单A(价格7)与之匹配,所以按卖单X的价格4成交。如果顺序反过来,买单A先挂入,卖单X后到来并与A匹配,则可能按买单A的价格7成交。
买单:按价格从高到低排序
卖单:按价格从低到高排序
成交价格:按卖单价格成交(保护卖家)

2. 时间优先原则

当两个订单价格相同时,“时间优先原则”就会起作用。例如:

  • 买家B1和B2都出价6,分别要买5个和10个。B1先下单,那么B1的订单就会排在B2的前面。
  • 当有一个价格为6的卖单到来时,会优先与排在前面的B1进行匹配。只有B1的订单全部成交后,才会轮到B2。
相同价格的订单:
- 买单:先到先得
- 卖单:先到先卖

3. 部分成交

当买单数量 > 卖单数量时:
- 卖单完全成交
- 买单部分成交,剩余部分继续等待

📊 实际代码中的实现

订单匹配逻辑

fn match_orders(&mut self, bid: &Order, ask: &Order) -> MatchResult {
    // 检查是否可以匹配
    if bid.price < ask.price {
        return MatchResult::NoMatch;
    }
    
    // 确定成交价格(按卖单价格)
    let match_price = ask.price;
    
    // 确定成交数量(取较小值)
    let match_quantity = min(bid.quantity, ask.quantity);
    
    // 执行成交
    let match_amount = match_price * match_quantity;
    
    // 更新订单状态
    bid.quantity -= match_quantity;
    ask.quantity -= match_quantity;
    
    // 生成成交事件
    MatchResult::Matched {
        price: match_price,
        quantity: match_quantity,
        amount: match_amount,
    }
}

价格更新逻辑

fn update_last_price(&mut self, new_price: u64) {
    self.last_price = new_price;
    self.last_update_time = get_current_time();
    
    // 触发价格更新事件
    emit_price_update_event(new_price);
}

🔍 特殊情况分析:理解市场动态

订单簿的匹配并非总是在理想状态下进行。了解这些特殊情况,有助于我们理解市场的真实动态和潜在风险。

1. 价格跳跃

说明:订单簿的连续性可能会被打破。假设当前最低卖单(Ask)是卖家X的4元,此时一个新卖家突然挂出一个价格为8元、数量为5的卖单。如果现有买单都无法匹配这个高价,而卖家X的订单又被全部吃掉,那么市场显示的最低卖价就会从4元“跳跃”到8元。

text

如果卖家突然提高价格:
- 原卖单:价格4,数量6
- 新卖单:价格8,数量5

结果:
- 价格从4跳到8
- 买家需要重新评估是否购买

影响:这种价格跳跃会导致巨大的滑点。对于交易者来说,这意味着市价单的成交成本会急剧上升,市场流动性出现瞬间短缺。

2. 流动性不足

说明:流动性是市场能够承受大额交易而不产生巨大价格冲击的能力。当买卖双方的心理价位差距过大时,就会出现流动性不足。

text

如果买单价格都低于卖单价格:
买单:最高价格3
卖单:最低价格7

结果:
- 无法成交
- 市场流动性不足
- 需要做市商提供流动性

影响:一个流动性不足的市场非常脆弱,少量资金就可能操纵价格,交易成本高昂,资产难以快速变现。这也是为什么去中心化交易所(DEX)和中心化交易所(CEX)都需要做市商来填充订单簿,提供双向报价的原因。

3. 大单冲击

说明:当一笔大额订单进入市场时,它会像一块巨石投入池塘,产生涟漪效应。它会消耗多个价格档位的流动性,从而推动市场价格。

如果出现大买单:
- 买单:价格6,数量100
- 卖单:价格5,数量10

结果:
- 前10个按5成交
- 剩余90个需要更高价格
- 可能推动价格上涨

影响:大单冲击是市场价格发现过程的一部分。它直观地展示了“需求增加推动价格上涨”的经济学原理。对于大户来说,需要采用算法交易将大单拆分成多个小单,以减轻市场冲击。

💡 实际应用建议:从理论到策略

理解订单簿机制最终是为了更好地指导我们的交易和开发行为。

1. 对于普通用户

说明:作为普通交易者,你的目标是尽可能以最优的价格成交,并控制风险。

text

下单策略:
- 限价单:设置合理价格,避免滑点。适合不急于成交,希望控制成本的投资者。
- 市价单:适合紧急情况,但可能有滑点。在快速变动的市场中,能保证成交,但成本不确定。
- 分批下单:大单分多次,减少市场冲击。例如,可以将一笔大买单分成10次下单,观察市场反应并平均成本。

2. 对于做市商

说明:做市商是市场的润滑剂,通过不断提供买卖报价来赚取买卖价差(Spread),但同时也要承担库存风险和价格波动风险。

做市策略:
- 双向报价:同时挂买单和卖单,为市场提供流动性。
- 价差控制:保持合理买卖价差。价差过小,利润微薄;价差过大,缺乏竞争力,无法吸引交易。
- 风险管理:控制持仓规模,及时对冲风险,避免在单边行情中遭受重大损失。

3. 对于开发者

说明:设计和实现一个高效、公平的订单簿匹配引擎是交易所的核心技术挑战。

系统设计:
- 价格精度:合理设置最小价格单位(如0.0001元),精度过高会增加订单簿深度管理的复杂度,过低则会影响价格发现。
- 订单管理:需要高效的数据结构(如红黑树、跳表)来存储和查询订单,以应对高频、大量的订单操作。
- 事件通知:必须有一个低延迟的系统来及时向所有用户广播价格更新和成交信息,确保市场透明度。

📈 价格影响分析:解读市场信号

订单簿不仅是交易的工具,也是洞察市场情绪的窗口。

短期影响

说明:成交价格链的变化揭示了短期内买卖力量的博弈。

成交价格变化:
4 → 5 → 5 → 6

影响因素:
- 买单价格分布:高买单价位挂单越多,上涨支撑越强。
- 卖单价格分布:低卖单价位挂单越多,下跌压力越大。
- 订单数量分布:关键价格档位的大额挂单(“巨墙”)可能成为心理阻力位或支撑位。
- 市场情绪:贪婪或恐惧会直接影响挂单行为。

长期趋势

说明:订单簿的长期状态可以反映资产的宏观趋势。

价格趋势判断:
- 买单价格上升:看涨信号,表明投资者愿意出更高的价格购买。
- 卖单价格下降:看跌信号,表明持有者急于以更低的价格卖出。
- 成交量增加:趋势确认,有量的价格变动才可持续。
- 价差收窄:流动性改善,市场趋于健康成熟。

总结:订单簿远不止是一个简单的排队系统。它的匹配机制是市场公平和效率的基石,其动态变化则凝聚了所有市场参与者的集体智慧。从微观的匹配逻辑到宏观的市场趋势,深入理解订单簿的运作原理,无疑能为您的交易决策、做市策略或系统开发提供坚实的数据基础和深刻的市场洞察。