bqrtfmrc的知识库

滚动撮合交易在量化系统中的工程实现思考

由bqrtfmrc创建,最终由bqrtfmrc 被浏览 3 用户

在量化交易系统中,撮合模块往往被视为“基础组件”,实现得也相对较早。 常见规则并不复杂:价格优先、时间优先,买卖盘条件满足即可成交。

但在真实系统运行一段时间后,尤其是在接入 tick 级行情、做策略回放或仿真时,我们往往会遇到一个现象: 策略逻辑没有变化,回测和仿真的成交结果却开始出现偏差。

从经验来看,这类问题往往不是策略层引起的,而是撮合算法是否真正符合滚动撮合交易的运行方式。

从系统视角重新看撮合模块

在工程实现中,撮合并不是一个“算价格”的函数,而是一个持续运行的状态机。 它的基本流程可以抽象为:

行情输入 → 订单簿更新 → 撮合判断 → 成交生成 → 成交回报

在 tick 驱动的系统中,这个流程并不是批量触发,而是随着市场变化不断向前推进。

滚动撮合交易的核心特征在于:

  • 每一条新订单、每一次盘口变化都会触发撮合判断
  • 成交是连续发生的,而非集中处理
  • 算法需要与行情节奏保持同步

在这种模式下,撮合实现的稳定性,直接影响策略结果的可复现性。

滚动撮合的基本运行逻辑

从实现角度看,滚动撮合可以拆解为一个非常直观的过程:

  1. 新订单进入系统
  2. 与当前最优对手盘进行比较
  3. 满足条件则成交
  4. 未成交部分继续留在订单簿中

真正决定系统行为的,并不是规则描述本身,而是订单簿的数据结构设计

一个典型的实现方式是:

  • 买盘:按价格从高到低排序
  • 卖盘:按价格从低到高排序
  • 同价位内:严格按照进入顺序处理

这正是撮合规则在代码层面的具体体现。

一个简化的滚动撮合核心示例

from collections import deque

class Order:
    def __init__(self, price, volume):
        self.price = price
        self.volume = volume

def rolling_match(buy_book, sell_book):
    trades = []

    while buy_book and sell_book:
        buy = buy_book[0]
        sell = sell_book[0]

        if buy.price < sell.price:
            break

        volume = min(buy.volume, sell.volume)
        trades.append((sell.price, volume))

        buy.volume -= volume
        sell.volume -= volume

        if buy.volume == 0:
            buy_book.popleft()
        if sell.volume == 0:
            sell_book.popleft()

    return trades

虽然逻辑简洁,但已经包含了滚动撮合的几个关键特性:

  • 成交按时间顺序逐笔推进
  • 支持部分成交
  • 成交价格来源于对手盘
  • 未完成订单自动延续到下一轮撮合

在实际系统中,复杂度更多来自外围问题,例如并发控制、时间顺序保证以及成交回报一致性。

可视化撮合结果的价值

在撮合仿真或策略回放中,仅靠日志往往不够直观。 将成交结果进行简单可视化,能更快发现异常行为。

下面是一个极简示例:

import matplotlib.pyplot as plt

prices = [101, 101, 100.5, 100.5, 100]
times = range(len(prices))

plt.plot(times, prices)
plt.xlabel("Match Sequence")
plt.ylabel("Trade Price")
plt.title("Rolling Matching Trade Price")
plt.show()

这种方式在调试中非常实用,可以帮助快速判断:

  • 成交价格是否出现异常跳变
  • 不同撮合逻辑下成交路径的差异
  • 滑点是否来自撮合层而非策略本身

为什么滚动撮合依赖 tick 行情

在撮合层,时间顺序往往比价格本身更重要。 如果使用聚合后的行情数据作为输入:

  • 多笔真实成交会被压缩
  • 撮合触发点被提前或延后
  • 回测结果容易产生偏差

因此,在工程实践中,更稳妥的方式是:

  • 使用逐笔 tick 行情驱动撮合模块
  • 让撮合节奏与真实市场保持一致

在部分仿真或回放系统中,可以直接接入多市场 tick 行情流作为输入,例如使用 AllTick API 提供的实时 tick 数据。统一的数据结构有助于降低适配成本,也更利于还原滚动撮合的真实行为。

撮合模块值得反复验证

在系统早期,撮合模块往往“看起来能用”。 但在以下场景中,设计差异会被明显放大:

  • 高频回放
  • 多策略并行运行
  • 跨市场扩展

是否真正理解并实现滚动撮合交易,往往决定了:

  • 策略结果能否稳定复现
  • 系统行为是否可信
  • 回测与实盘之间的偏差程度

撮合逻辑本身并不复杂,但它是量化系统中最基础、也最关键的一层。 如果你正在构建或优化交易系统,这一模块非常值得单独拆解和反复验证。

\

{link}