4. 价格发现的核心算法:最大成交量原则

集合竞价的核心,说白了就是一句话:找出一个价格,让想买的人和想卖的人都能尽可能多地成交。这个价格,就是咱们常说的开盘价或收盘价。

我刚开始接触这个算法时,觉得不就是找个交点嘛,跟小学的相遇问题差不多。后来真上了生产环境才发现,这里面的门道比想象中深得多。嗯,咱们今天就把这个「最大成交量原则」彻底拆开看看。

4.1 什么是最大成交量原则?

先给个正式定义:
在集合竞价阶段,系统会遍历所有可能的成交价格,然后选择那个能够使成交量达到最大的价格作为最终成交价。

你想想看,如果价格定高了,买方不愿意买;定低了,卖方不愿意卖。只有那个恰到好处的价格,才能让买卖双方都满意,成交量自然最大。

我在项目中遇到过这样一个案例:某只股票在集合竞价时,有3个价格都能产生相同的最大成交量。这时候怎么办?别急,后面会讲处理规则。

4.2 算法核心逻辑

最大成交量原则的实现,其实就三步:

  1. 收集订单:把所有买卖委托按价格排序
  2. 计算累计量:从最低价到最高价,逐档计算累计买单和累计卖单
  3. 找最大值:在每个价格上,取累计买单和累计卖单的较小值,找到那个最大值

我习惯用一张图来理解这个过程:

最大成交量原则 — 算法流程图 1. 收集买卖订单 2. 按价格排序 3. 计算累计量 4. 逐价计算成交量 5. 找到最大成交量 6. 确定成交价 算法流程方向 图4-1 最大成交量算法执行流程

4.3 一个具体的计算例子

光说理论太干,咱们直接上例子。假设某只股票在集合竞价阶段收到以下订单:

价格(元) 累计买单量(手) 累计卖单量(手) 可成交量(手)
10.00 1000 200 200
10.02 800 400 400
10.04 600 600 600 ← 最大
10.06 400 900 400
10.08 200 1200 200

看到没?在10.04元这个价格上,累计买单600手,累计卖单600手,可成交量是600手。其他价格要么买方不够,要么卖方不够,成交量都小于600。所以,10.04元就是最终的集合竞价成交价

核心公式:

在每个价格 P 上,可成交量 V(P) = min(累计买单量(P), 累计卖单量(P))

最终成交价 = argmax V(P)

4.4 多价格平局怎么办?

刚才说了,有时候会出现多个价格都能产生相同的最大成交量。这时候交易所会有一套「破局规则」。我以A股为例:

  1. 优先选最小剩余量:计算每个价格上未成交的买卖单量之和,选最小的那个
  2. 如果还平局:选最接近前收盘价的那个
  3. 如果还平局:选中间价(比如两个价格,取平均值)

我曾经在回测系统里遇到过这种平局情况,当时没处理这个细节,结果回测结果跟实盘差了0.02%。排查了两天才发现是平局处理逻辑没写对。嗯,这种边界情况最容易出问题。

4.5 代码实现示例

下面是我个人习惯用的一个简化版实现,用Python写的:

def find_max_volume_price(buy_orders, sell_orders):
    """
    最大成交量原则实现
    buy_orders: 买方订单列表,每个元素为 (价格, 数量)
    sell_orders: 卖方订单列表,每个元素为 (价格, 数量)
    """
    # 按价格排序
    buy_orders.sort(key=lambda x: x[0], reverse=True)  # 从高到低
    sell_orders.sort(key=lambda x: x[0])               # 从低到高
    
    # 计算累计量
    cum_buy = 0
    cum_sell = 0
    price_volume = {}
    
    # 合并所有价格点
    all_prices = sorted(set([p for p, _ in buy_orders] + [p for p, _ in sell_orders]))
    
    buy_idx = 0
    sell_idx = 0
    
    for price in all_prices:
        # 累计所有高于等于当前价格的买单
        while buy_idx < len(buy_orders) and buy_orders[buy_idx][0] >= price:
            cum_buy += buy_orders[buy_idx][1]
            buy_idx += 1
        
        # 累计所有低于等于当前价格的卖单
        while sell_idx < len(sell_orders) and sell_orders[sell_idx][0] <= price:
            cum_sell += sell_orders[sell_idx][1]
            sell_idx += 1
        
        # 计算可成交量
        volume = min(cum_buy, cum_sell)
        price_volume[price] = volume
    
    # 找最大成交量对应的价格
    max_volume = max(price_volume.values())
    candidates = [p for p, v in price_volume.items() if v == max_volume]
    
    # 平局处理(简化版)
    if len(candidates) == 1:
        return candidates[0]
    else:
        # 这里可以加入更复杂的平局处理逻辑
        return candidates[len(candidates) // 2]  # 取中间价

避坑指南:

我曾经在实现时犯过一个低级错误——直接用价格作为字典key,但浮点数精度问题导致两个本该相等的价格被当成不同key。后来我改用整数(价格乘以最小变动单位)才解决。建议你们也注意这个细节。

4.6 实际应用中的注意事项

  • 订单簿快照:集合竞价期间,订单簿是动态变化的,算法需要处理实时更新的订单流
  • 价格档位:不同交易所的最小价格变动单位不同,A股是0.01元,有些品种是0.001元
  • 大单处理:遇到大单时,累计量的变化可能很剧烈,算法要能平滑处理
  • 时间优先级:在价格相同的情况下,时间优先原则仍然适用

重要提醒:

最大成交量原则虽然看起来简单,但在高频交易场景下,毫秒级的订单变化都会影响最终结果。如果你在做量化策略,建议用真实的历史数据回测,别光靠理论推导。

好了,关于最大成交量原则的核心内容就这些。说白了,它就是集合竞价价格发现的「定海神针」,所有复杂的规则最终都是为了实现这个目标——让最多的人成交。


专注资料整理