市场微观结构:订单簿深度、买卖价差、流动性分层与滑点计算

各位同学,今天我们来聊聊做市引擎最底层的那些事儿——市场微观结构。

说实话,我刚开始做量化那会儿,觉得策略就是找规律、写代码、跑回测。直到有一次实盘,我的做市单被市场瞬间吃掉,滑点直接吞掉了两周的利润。嗯,从那以后我才真正明白:不理解微观结构,做市就是闭着眼睛开车

一、订单簿深度:市场的真实面貌

订单簿是什么?说白了,就是所有挂在交易所上的买单和卖单的集合。每一档价格上挂了多少钱,一目了然。

我个人习惯把订单簿分成三个区域来看:

  • 近端流动性:距离当前价格最近的3-5档,这是做市商的主战场
  • 中段流动性:5-20档,机构大单和套利者常在这里埋伏
  • 远端流动性:20档以外,通常是止损单和长期限价单

你想想看,如果近端只有薄薄一层,中段突然变厚,这说明什么?说明有大户在等着接货或者砸盘。我在做BTC永续合约时遇到过好几次这种情况,每次都是行情反转的前兆。

核心指标:订单簿深度 = 各档位挂单量的加权和。深度越厚,市场越能承受大额交易而不产生剧烈价格波动。

二、买卖价差:做市商的利润来源

买卖价差(Bid-Ask Spread),就是买一价和卖一价之间的差值。做市商赚的就是这个差价。

但这里有个坑——名义价差和实际价差是两码事

名义价差就是买一卖一的价格差。但实际交易中,你挂单不一定能立刻成交,中间可能隔着好几档。我建议用加权平均价差来评估真实成本:

def weighted_spread(order_book, depth=5):
    """
    计算加权平均价差
    order_book: 订单簿数据,包含bids和asks
    depth: 考虑几档深度
    """
    bids = order_book['bids'][:depth]
    asks = order_book['asks'][:depth]
    
    bid_volume = sum([b[1] for b in bids])
    ask_volume = sum([a[1] for a in asks])
    
    bid_price = sum([b[0]*b[1] for b in bids]) / bid_volume
    ask_price = sum([a[0]*a[1] for a in asks]) / ask_volume
    
    return ask_price - bid_price

这段代码我用了好几年,简单但实用。它告诉你:如果你想吃掉前5档的所有流动性,实际要付出的价差是多少。

三、流动性分层:谁在跟你做对手盘?

流动性不是均匀分布的。我把它分成三个层次:

层次 特征 典型参与者
第一层 高频做市商,挂单薄、撤单快 量化基金、专业做市商
第二层 中频交易者,挂单较厚、停留时间长 套利者、趋势交易者
第三层 低频大单,隐藏在远端 机构投资者、矿工

为什么会分层?因为不同参与者的交易目标和时间尺度不一样。高频做市商可能几秒钟就撤单,而机构的大单可能挂一整天。

我的经验:做跨交易所套利时,一定要识别出第一层流动性。那些高频做市商的单子撤得飞快,你还没反应过来,价格已经变了。我曾经因为没注意这个,在OKX和Binance之间做套利,结果单子被高频做市商抢跑,亏了一笔。

四、滑点计算:从理论到实战

滑点,就是预期成交价和实际成交价之间的差值。做市策略最怕的就是滑点,因为它直接吃掉你的利润。

滑点主要来自三个方面:

  1. 市场冲击:你的单子太大,吃掉了多档流动性
  2. 延迟:从下单到成交,价格已经变了
  3. 对手盘行为:有人在你前面抢单

我常用的滑点计算模型是这样的:

def slippage_estimate(order_book, trade_volume):
    """
    估算给定交易量的滑点
    order_book: 订单簿
    trade_volume: 交易量(正数为买入,负数为卖出)
    """
    if trade_volume > 0:
        # 买入,从asks侧吃单
        levels = order_book['asks']
        side = 'asks'
    else:
        # 卖出,从bids侧吃单
        levels = order_book['bids']
        side = 'bids'
    
    remaining = abs(trade_volume)
    total_cost = 0
    executed_volume = 0
    
    for price, volume in levels:
        if remaining <= 0:
            break
        take = min(remaining, volume)
        total_cost += take * price
        executed_volume += take
        remaining -= take
    
    if executed_volume < abs(trade_volume):
        # 流动性不足,用最后一档价格估算剩余部分
        total_cost += remaining * levels[-1][0]
        executed_volume += remaining
    
    avg_price = total_cost / executed_volume
    mid_price = (order_book['bids'][0][0] + order_book['asks'][0][0]) / 2
    
    slippage = abs(avg_price - mid_price) / mid_price * 10000  # 返回bp
    
    return slippage
注意:这个模型假设你能按订单簿上的价格成交。实际上,在高频交易中,你看到的订单簿可能已经过时了。我建议在计算滑点时额外加一个安全边际,比如10%-20%。

五、知识体系总览

下面这张图是我自己整理的,把本章的核心逻辑串起来了:

市场微观结构 订单簿深度 买卖价差 流动性分层 滑点计算 近/中/远端 加权深度 名义vs实际 加权平均价差 高频/中频/低频 对手盘识别 市场冲击 延迟+抢跑 四个核心要素相互影响,共同决定做市策略的盈亏

这张图我画了好几次才满意。你看,四个要素是相互关联的:订单簿深度影响价差,流动性分层决定滑点大小,而滑点又反过来影响你做市的报价策略。

实战建议:刚开始做跨交易所套利时,别急着上大仓位。先花一周时间,每天记录各个交易所的订单簿深度和价差变化。我当年就是这么干的,后来发现不同交易所的流动性分层差异很大——比如Binance的近端流动性比OKX厚30%左右,但撤单速度也快一倍。

好了,这一章的内容就到这里。记住一句话:微观结构不是理论,是你每天都要面对的现实。下次实盘前,先跑一遍滑点计算代码,看看你的策略到底能承受多大的交易量。


公众号:蓝海资料掘金营,微信deep3321