halo 的技术博客

返回

问题:中间价是个被 tick 网格锁死的粗糙估计#

盘口上买一 10.00、卖一 10.01,中间价 10.005。这个数字看起来天经地义,但它有个致命的性质:只要买一卖一不变,无论盘口挂单量怎么变化,中间价永远是 10.005

现在看两个盘口:

买一价买一量卖一价卖一量中间价
盘口 A10.005000 手10.01100 手10.005
盘口 B10.00100 手10.015000 手10.005

两个盘口的中间价一模一样。但任何做过盘口的人都知道,这是完全相反的两种局面:盘口 A 买方堆了 5000 手、卖方只剩 100 手,下一笔主动买单就能吃穿卖一,价格几乎必然向上跳;盘口 B 反过来。

中间价把这个信息全扔了。它的取值被锁在 tick 网格的半格上,而真实的「有效价格」——那个如果市场连续可分、你能立刻无成本成交的公允价——在价差内部连续游走。价差 1 分钱的时候,中间价的误差最大就是半分钱;听着不多,但对做市商来说,半分钱就是全部利润。

中间价与微观价格路径对比

上图是本文模拟的一段盘口。橙色虚线是隐藏的真实有效价格(现实中不可观测,模拟里我们知道),深灰色阶梯是中间价——它被 tick 网格锁死,只能跳格;蓝色线是微观价格,它能在价差内部平滑移动,明显更贴近橙线。下半部分是挂单不平衡:绿色代表买盘占优,红色代表卖盘占优。

微观价格:最朴素的那版#

最直接的修正叫加权中间价(weighted mid),也常被直接称为 microprice:

Pmicro=PaskQbid+PbidQaskQbid+QaskP_{\text{micro}} = \frac{P_{\text{ask}} \cdot Q_{\text{bid}} + P_{\text{bid}} \cdot Q_{\text{ask}}}{Q_{\text{bid}} + Q_{\text{ask}}}

注意这个交叉加权:买一量 QbidQ_{bid} 乘的是卖一价 PaskP_{ask}。第一次看总觉得反了,但方向是对的——买盘挂单堆得越厚,说明买方支撑越强、卖一越容易被吃穿,有效价格就越靠近卖一价。

import numpy as np

def weighted_mid(bid, ask, bid_size, ask_size):
    """加权中间价:买盘越厚,价格越靠近卖一"""
    return (ask * bid_size + bid * ask_size) / (bid_size + ask_size)

def imbalance(bid_size, ask_size):
    """挂单不平衡,取值 [0, 1],>0.5 表示买盘占优"""
    return bid_size / (bid_size + ask_size)

# 前面表格里的两个盘口
print(weighted_mid(10.00, 10.01, 5000, 100))   # 10.00980  -> 贴近卖一
print(weighted_mid(10.00, 10.01, 100, 5000))   # 10.00020  -> 贴近买一
python

同样的中间价 10.005,微观价格给出 10.0098 和 10.0002,跨度接近一整个价差。这就是被中间价扔掉的那部分信息。

写成不平衡的形式更容易看清结构:令 I=Qbid/(Qbid+Qask)I = Q_{bid} / (Q_{bid} + Q_{ask}),则

Pmicro=Pmid+(I12)SP_{\text{micro}} = P_{\text{mid}} + \left(I - \tfrac{1}{2}\right) \cdot S

其中 S=PaskPbidS = P_{ask} - P_{bid} 是价差。所以微观价格就是中间价加上一个「不平衡 × 价差」的线性修正项,修正幅度天然被限制在半个价差以内。

它到底有多准:用已知答案的模拟来验#

真实市场里没人知道「真实有效价格」是多少,所以无法直接算误差。解决办法是做受控模拟:我自己造一个隐藏的有效价格 ftf_t 让它随机游走,再按一个明确的机制生成盘口——有效价格越靠近卖一,卖一队列越容易被吃掉、挂单量越小。这是真实市场里不平衡携带信息的核心机制。

6 万个快照、1 tick 价差,用后一半样本做样本外评估,比较三种估计对隐藏 ff 的追踪误差:

估计量RMSE(分)相对中间价改善
中间价 mid0.288
加权中间价 weighted mid0.14250.8%
校准后的微观价格0.10663.0%

加权中间价把追踪误差直接砍掉一半,而且这一半是白捡的:不需要估任何参数,两个价格两个挂单量,一行算术。

校准曲线:线性修正其实不够好#

加权中间价隐含假设「偏移量随不平衡线性变化」。真的是这样吗?把样本按不平衡分成 25 组,每组算实际偏移 E[fPmidI]E[f - P_{mid} \mid I] 的均值,画出来:

校准曲线

蓝线是真实调整量,橙色虚线是加权中间价隐含的调整量。两者方向一致(这证明加权公式的符号是对的),但蓝线更陡:真实校准斜率 0.0139,加权中间价只有 0.0100。也就是说,朴素加权在极端不平衡时修正不足——不平衡到 0.9 的时候,实际有效价格比加权中间价预测的还要更靠近卖一。

修法很自然:不假设任何函数形式,直接把这条经验曲线查表用(这是 Stoikov 微观价格思路的简化版)。关键是必须因果——用前半段样本估校准表,后半段样本应用:

那句 if ok.sum() == 0: return np.zeros(nbins) 不是防御性废话——后面的过拟合检验会证明它是真的会被触发的分支。

RMSE 对比与价差敏感性

左图是四种估计的 RMSE。右图更有实践意义:价差越宽,微观价格越值钱。1 tick 价差时改善 50.7%,8 tick 时 53.6%。道理很直白——中间价的误差上界是半个价差,价差越宽,中间价可能错得越离谱,修正的空间也就越大。所以微观价格对流动性差、价差宽的品种更有用,而不是相反。

五项对抗式检验#

好看的数字必须先被怀疑。以下每一项都是「如果微观价格是假的,这里应该露馅」。

检验一:安慰剂盘口——抽掉信息机制#

把模拟里挂单量与有效价格位置的关联切断(info=False),挂单量变成纯噪声。如果微观价格的优势是真的来自信息,这里必须归零:

有信息盘口安慰剂盘口
RMSE 改善+50.8%−2.32%
与下一步中间价变动相关0.4600.0069

改善由 +50.8% 变成 −2.32%(略微变差,因为加了纯噪声),相关系数从 0.460 塌到 0.0069。干净归零。微观价格没有魔法,它只是把盘口里本来就有的信息读出来;盘口里没有信息,它就什么都读不出来。

检验二:买卖方向标反#

前面说过交叉加权「第一眼觉得反了」。那就真的把它写反,看会怎样:

wmid_flip = (ask * ask_size + bid * bid_size) / (bid_size + ask_size)  # 错误加权
python

RMSE 改善变成 −58.15%——比中间价差了近六成。这个强烈的负号有两重意义:一是确认了正确方向确实是交叉加权,二是说明这个符号错误在真实项目里会造成灾难性后果,而且不会报错,只会安静地让你的估价系统性偏向错误一侧。任何接入新数据源时,第一件事就是用这个方法验证符号。

检验三:样本内 vs 样本外#

校准表是拟合出来的,会不会只是记住了噪声?

改善
样本内(用测试段自己估表,作弊)63.08%
样本外(前半段估表,后半段用)63.04%

差异只有 0.04 个百分点。3 万个训练样本配 40 个分箱,平均每箱 750 个观测,过拟合空间基本为零。 这是个好消息,但它有个前提条件——样本量。

检验四:小样本下校准表会崩#

把训练样本量和分箱数做成网格,看样本外改善:

训练样本10 箱40 箱200 箱
20058.74%0.00%0.00%
50059.09%57.45%0.00%
2,00060.32%62.75%58.82%
10,00060.46%63.02%62.97%
30,00060.46%63.04%63.18%

那些 0.00% 就是前面那个「退化分支」被触发了:分箱太细、每箱样本不够,校准表整个退化成中间价。这不是崩溃,是设计好的安全失败——宁可退回中间价,也不要用 3 个样本估出来的均值去做修正

真正的教训在于:分箱数必须随样本量走。200 个样本用 10 箱还能拿到 58.74%,用 40 箱就直接失效。经验法则是每箱至少 100 个观测;盘口数据看着量大,但如果你按品种、按时段分别校准,单元格里的样本会迅速变稀。

检验五:预测跨度——85% 命中率是怎么回事#

微观价格相对中间价的偏移,能预测未来中间价往哪走吗?

信号衰减

跨度 h(快照)相关系数方向命中率
10.46085.2%
20.38575.1%
50.27964.9%
100.21359.9%
200.16056.6%
500.09953.8%
1000.07052.4%

85.2% 的下一步命中率是本文最容易被误读的数字,必须说清楚:它预测的是「中间价在价差内部的下一次微小抖动」,不是「价格会不会走出一段能覆盖成本的行情」。信号半衰期极短——10 个快照后就只剩 59.9%,100 个快照后 52.4%,基本是抛硬币。

而且校准版和朴素加权版在方向预测上完全打平(h=1 时都是 85.2%)。原因是方向只取决于偏移的符号,而两者符号总是一致;校准只改变幅度。所以:要估价(做市报价、组合估值、成交质量分析)用校准版;只要方向,朴素加权就够了。

实践中它用来做什么#

做市报价的锚。 做市商围绕微观价格而非中间价报价,能减少被逆向选择的概率。盘口显示买方占优时,微观价格上移,你的报价跟着上移,避免卖一被人白吃。

成交质量评估。 评价一笔成交好坏,基准用微观价格比中间价公允。用中间价当基准,在盘口失衡时会系统性高估或低估滑点——这一点和实现价差分解的度量口径问题是同一类陷阱。

估值与风控。 持仓按中间价估值,在盘口极度失衡时会偏离可实现价格;对流动性差的品种尤其明显。这也是右图那条「价差越宽收益越大」曲线的实际含义。

下单时机的微调。 微观价格显著偏向卖一时,主动买单可能面临上跳,值得等一等;但记住上面那张衰减表——这个优势只在极短跨度内有效,别拿它当日内择时信号用

诚实边界#

第一,模拟的信息机制是我设定的,不是从真实数据里发现的。 本文所有数字来自受控模拟,好处是「真实有效价格」已知、可以算真误差;代价是那个「有效价格越靠近卖一、卖一队列越薄」的机制是我写进去的。真实市场里这个关系的强度、稳定性、是否随品种和时段变化,都需要用实盘盘口数据重新校准。这些数字应该读作「机制成立时能拿到多少」,不是「你的品种上一定能拿到多少」。

第二,只用了买一卖一,忽略了盘口深度。 真实盘口有 5 档、10 档,深层挂单同样携带信息,而且第一档最容易被撤单和冰山单操纵。只看第一档的微观价格,在存在大量冰山单与隐藏流动性的市场里会被系统性欺骗——显示的 100 手背后可能是 5000 手。

第三,没有建模挂单的时间维度。 同样是 5000 手买盘,刚挂上去的和已经挂了十分钟的,信息含量完全不同;限价单排队位置那篇讨论的队列动态在这里被整个忽略了。真正的高频估价模型会用挂单年龄、撤单率、成交流不平衡等一整组特征,微观价格只是其中最简单的一个。

第四,命中率不等于可交易。 再强调一次:85.2% 的下一步方向命中率,对应的价格幅度是价差的一个零头。扣掉手续费和冲击成本后,这个「优势」在绝大多数情况下不足以支撑一个独立策略。它的价值在于改善你已经要做的事(报价、估值、择时微调),而不是成为一个新的事

归宿#

微观价格是市场微观结构工具箱里性价比最高的那个:一行算术,追踪误差砍半,不需要估参数、不需要训练、不需要额外数据。如果你的系统现在还在用中间价做任何与价格相关的判断,换成加权中间价几乎是免费的升级。

想再进一步就上校准表,样本外还能再多拿 12 个百分点,但记住两条:每箱至少 100 个观测(否则安全退化成中间价),校准必须因果(用历史估表、用当下应用)。

最后是那条最重要的分界线:微观价格改善的是估价精度,不是预测能力。85% 那个数字很诱人,但它衰减得比你建仓的速度还快。把它当成一把更准的尺子,而不是一台印钞机。

Microprice 微观价格:用挂单量加权修正中间价的方向偏差
https://blog.halo26812.eu.org/blog/midprice-microprice-estimator
Author halo
Published at 2026年8月4日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨