第4讲:价差与信号计算

各位同学,今天我们来聊聊做市策略里最基础、也最要命的部分——价差和信号计算。说白了,你连买卖价差都算不明白,那后面的策略全是空中楼阁。我当年刚入行时,就吃过这个亏。

4.1 买卖价差计算

买卖价差(Bid-Ask Spread),就是最优卖价减去最优买价。公式很简单:

Spread = Ask_Price - Bid_Price

但实际项目中,我们通常用相对价差:

Relative_Spread = (Ask - Bid) / Mid_Price

为什么要用相对值?因为不同股票价格差太多。茅台2000块,价差2块才0.1%;某低价股2块钱,价差2分钱就是1%。你拿绝对值去比较,根本没法统一处理。

核心要点:价差是流动性的直接体现。价差越小,流动性越好。做市商赚的就是这个价差。

我在项目中遇到过一个问题:有些交易所的订单簿数据里,买一卖一可能同时为空。这时候价差怎么算?我的做法是:如果任意一侧为空,直接返回NaN,后续策略会跳过这个时间点。千万别自作聪明去补一个默认值,那会引入偏差。

4.2 加权中间价

中间价(Mid Price)大家都会算:

Mid = (Bid + Ask) / 2

但这里有个坑——如果买卖挂单量严重不平衡,这个中间价其实很虚。举个例子:

  • 买一:100元,挂1000股
  • 卖一:101元,挂10股

中间价是100.5元。但你想成交,大概率只能按100元卖,因为卖一那10股根本不够吃。这时候就需要加权中间价了。

加权中间价的计算方式有很多种,我个人比较常用的是按挂单量加权:

Weighted_Mid = (Bid_Price * Ask_Size + Ask_Price * Bid_Size) / (Bid_Size + Ask_Size)

为什么这么算?你想想看,如果卖一侧挂单很少,说明卖方力量弱,价格应该更偏向买方。这个公式正好反映了这个逻辑。

小技巧:我习惯同时计算普通中间价和加权中间价,两者的差值可以作为一个信号。差值越大,说明订单簿越不平衡,可能预示着价格即将变动。

4.3 成交量加权平均价(VWAP)

VWAP大家应该不陌生,公式是:

VWAP = Σ(Price_i * Volume_i) / Σ(Volume_i)

但在高频做市场景下,我们通常计算的是实时VWAP,也就是从当天开盘到当前时刻的累计加权平均价。这个指标用来衡量你的成交价格是否跑赢了市场平均水平。

我一般会维护两个VWAP:

  • 全量VWAP:从开盘到现在的所有成交
  • 滚动VWAP:最近N笔成交(比如最近100笔)

滚动VWAP对短期价格变化更敏感。我曾经用滚动VWAP作为做市策略的参考基准,效果比用全量VWAP好不少。

def calc_rolling_vwap(trades, window=100):
    """
    计算滚动VWAP
    trades: list of (price, volume)
    """
    if len(trades) < window:
        return None
    
    recent = trades[-window:]
    total_vol = sum(v for _, v in recent)
    total_val = sum(p * v for p, v in recent)
    
    return total_val / total_vol if total_vol > 0 else None

注意:VWAP对异常成交很敏感。比如一笔大单以极端价格成交,会严重拉偏VWAP。我建议在计算前先做一次价格过滤,剔除明显异常的单子。

4.4 订单簿不平衡指标

这个指标是我做策略时最依赖的信号之一。它衡量的是买卖双方的力量对比。

最简单的版本:

Imbalance = (Bid_Volume - Ask_Volume) / (Bid_Volume + Ask_Volume)

取值范围在-1到1之间。正值表示买方力量强,负值表示卖方力量强。

但实际项目中,只看买一卖一太片面了。我通常会用深度加权的不平衡指标:

def calc_depth_imbalance(order_book, levels=5):
    """
    计算深度加权不平衡
    order_book: 订单簿数据
    levels: 考虑的档位数
    """
    bid_vol = sum(order_book['bids'][i]['volume'] * (levels - i) 
                  for i in range(min(levels, len(order_book['bids']))))
    ask_vol = sum(order_book['asks'][i]['volume'] * (levels - i) 
                  for i in range(min(levels, len(order_book['asks']))))
    
    if bid_vol + ask_vol == 0:
        return 0
    
    return (bid_vol - ask_vol) / (bid_vol + ask_vol)

为什么要加权?因为越靠近最优价的挂单,对价格的影响力越大。我给近端挂单更高的权重,这样算出来的不平衡指标更灵敏。

实战经验:我曾经用这个指标做过一个简单的均值回归策略。当不平衡指标超过0.7时做空,低于-0.7时做多。回测效果不错,但实盘时要注意——极端不平衡往往伴随着大单冲击,滑点会吃掉大部分利润。

4.5 知识体系总览

下面这张图总结了本章的核心内容,我建议你保存下来,写代码时对照着看:

价差与信号计算知识体系 买卖价差 绝对价差 相对价差 流动性度量 → 做市利润来源 加权中间价 普通中间价 量加权中间价 差值信号 → 订单簿平衡度 VWAP 全量VWAP 滚动VWAP 异常过滤 → 成交质量评估 订单簿不平衡指标 简单不平衡 (买一-卖一)/(买一+卖一) 深度加权不平衡 多档位加权计算 均值回归策略 阈值触发信号 所有信号 → 做市决策输入

4.6 实战中的坑

最后分享几个我踩过的坑:

  1. 数据延迟问题:订单簿数据更新频率极高,你算出来的价差可能已经过时了。我一般会打一个时间戳,判断数据是否在可接受的时间窗口内。
  2. 零成交量处理:VWAP计算时如果成交量为0,直接除会报错。记得加个判断。
  3. 极端行情:涨跌停时,买卖价差会变得非常大,不平衡指标也会失效。这时候最好暂停策略。
  4. 交易所差异:不同交易所的订单簿数据结构不一样,有的用价格档位,有的用价格区间。写代码时一定要做一层抽象。

我的建议:刚开始做策略时,先把这四个指标算清楚,画成曲线图,盯着看几天。你会发现很多规律——比如价差在开盘和收盘时最大,中午最小;不平衡指标在重大消息发布前会剧烈波动。这些观察比任何理论都值钱。

好了,这一讲就到这里。记住一句话:信号的质量决定了策略的上限。把基础打牢,后面才能走远。


专注资料整理