Hayashi-Yoshida 领先滞后估计:在异步 tick 里找谁先动
两只关联资产里,谁先动、谁跟随?大盘 ETF 涨了,成份股几秒后跟上;期货动了,现货滞后半秒——这个『谁领先谁』的时间差,是高频交易里最值钱的信息之一。但要从真实 tick 数据里量出这个 lag 极难:两条序列的成交时刻从不对齐,你一旦重采样到固定网格,就把秒级的领先滞后模糊进了分钟级的格子,lag 直接消失。本文把 Hayashi-Yoshida 估计量升级成领先滞后探测器:给一条序列的时间轴整体平移 L 秒再算 HY 交叉相关,扫描所有 L、峰值所在即领先滞后时间。用纯 numpy 造 leader/follower 结构(follower=leader 滞后 8 秒+噪声),完整复现交叉相关峰值精准锁定 8 秒;对比固定网格 last-tick 如何被粗粒度模糊掉 lag;量化样本量与信号强度对 lag 估计稳健性的影响(一天数据 vs 一周数据、ρ=0.2 的平峰 vs ρ=0.8 的尖峰)。附完整 Python 与四类真实陷阱。
先问一个高频交易里价值连城的问题:两只关联资产同时波动,到底是谁先动、谁在跟随?
沪深 300 ETF 涨了,成份股会在几秒内跟上;股指期货动一下,现货指数滞后半秒才反应;一只大盘龙头拉升,同板块的小弟们排队跟进。这个”谁领先谁”的时间差——哪怕只有几秒——就是套利者的饭碗:你看到 leader 动了,抢在 follower 反应过来之前下单,吃的就是这几秒的确定性。
但问题在于:从真实 tick 数据里把这个 lag 量出来,出奇地难。 难点还是那个老敌人——异步成交。两条序列的成交时刻从不对齐,你一旦为了对齐把它们重采样到固定网格(比如 1 分钟),就把秒级的领先滞后关系直接碾进了分钟级的格子里,lag 消失得无影无踪。
结论先放这:解法是把 Hayashi-Yoshida 估计量从”算协方差”升级成”探测领先滞后”。 给其中一条序列的时间轴整体平移 L 秒,再算 HY 交叉相关;扫描所有可能的 L,交叉相关的峰值出现在哪个 L,那个 L 就是领先滞后时间。本文从零把这套方法和代码走一遍。
(如果你还不熟悉 Epps 效应和 HY 估计量的基本原理,建议先看上一篇《Epps 效应与高频相关性》,本文默认你知道”异步成交为什么会毁掉高频相关性”以及”HY 如何用重叠区间绕开它”。)
先造一个 leader / follower 世界#
要验证方法对不对,得先有一个”上帝视角下已知答案”的数据。我造一个明确的领先滞后结构:follower 的收益 = leader 收益平移 8 秒 + 自身噪声。 也就是 follower 落后 leader 整整 8 秒。
import numpy as np
rng = np.random.default_rng(7)
n = 20000 # 秒(约等于一个交易日多一点)
true_lag = 8 # follower 落后 leader 8 秒
rho = 0.7 # 领先-滞后关系的强度
sigma = 0.15 / np.sqrt(n)
# leader 的 latent 收益
r_leader = sigma * rng.standard_normal(n)
# follower:把 leader 收益平移 true_lag,再混入自身噪声
noise = rng.standard_normal(n) * sigma
r_follower = np.zeros(n)
r_follower[true_lag:] = rho * r_leader[:-true_lag] + np.sqrt(1 - rho**2) * noise[true_lag:]
r_follower[:true_lag] = noise[:true_lag]
p_leader = 100 * np.exp(np.cumsum(r_leader))
p_follower = 80 * np.exp(np.cumsum(r_follower))python把两条价格叠在一起看,follower 的走势就像 leader 平移 8 秒后的回声:

肉眼能感觉到”红线在跟蓝线”,但感觉不出来到底滞后几秒。这正是我们要量化的东西。
核心思想:平移 + 交叉相关,扫出峰值#
普通相关性只回答”两者相不相关”,不回答”谁先谁后”。要挖出方向和时间差,得引入交叉相关(cross-correlation):把其中一条序列相对另一条平移 L,再算相关。
- 如果 leader 真的领先 follower 8 秒,那么把 leader 往后推 8 秒、正好和 follower 对齐时,相关性最高。
- 扫描所有 L(从领先到滞后),交叉相关会在 L = 真实 lag 处出现一个尖峰。
def shifted_corr(ra, rb, shift):
# 正 shift:把 b 相对 a 往后挪,检验 a 是否领先 b
if shift > 0:
a, b = ra[:-shift], rb[shift:]
elif shift < 0:
a, b = ra[-shift:], rb[:shift]
else:
a, b = ra, rb
return np.corrcoef(a, b)[0, 1]
lags = np.arange(-25, 26)
cc = [shifted_corr(r_leader, r_follower, s) for s in lags]
peak = lags[int(np.argmax(cc))] # 峰值位移 = 估计的领先滞后python画出来,峰值精准落在 8 秒:

峰值位置 = 8 秒,和真实滞后完全吻合。峰的位置告诉你时间差,峰的高度告诉你关系强度,峰在正轴还是负轴告诉你谁领先谁。一张图三个信息。
这在同步、稠密数据上很干净。但真实 tick 是异步稀疏的——这才是 HY 登场的地方。
异步 tick 下:HY 平移法 vs 固定网格#
真实市场里,leader 和 follower 的成交时刻各自独立、稀疏、错位。现在把上面的思想搬到异步数据上:给 follower 的成交时间轴整体平移 L 秒,再用 HY 估计量算这条平移后的交叉协方差。
def hy_cross(times_a, ret_a, times_b, ret_b, shift):
# 把 b 的时间轴整体平移 shift 秒后做 HY 交叉协方差
tb0, tb1 = times_b[:-1] + shift, times_b[1:] + shift
ta0, ta1 = times_a[:-1], times_a[1:]
cov = 0.0
for i in range(len(ret_a)):
overlap = (tb0 < ta1[i]) & (tb1 > ta0[i]) # 时间重叠即累加
cov += ret_a[i] * ret_b[overlap].sum()
return covpythonHY 的精髓和上一篇一样:不对齐、不填充、不丢数据,只靠”时间区间是否重叠”来配对累加。加一个平移量 L,它就从”算协方差”变成”探测领先滞后”。
对比 HY 平移法和传统的”重采样到 10 秒固定网格再算交叉相关”:

差距一目了然:
- HY 平移法(绿):在异步稀疏数据上,峰值依然稳稳落在 8 秒附近。它保留了成交的原始时间戳精度,秒级的 lag 就能秒级地测出来。
- 10 秒固定网格(灰):峰被彻底模糊。因为你把数据重采样到 10 秒格子的那一刻,8 秒的领先滞后就被压进了一个格子里——你的测量精度不可能高于你的采样粒度。 想测秒级 lag,却用 10 秒网格,等于用米尺量头发丝。
这是全文最关键的一点:领先滞后的可测精度,取决于你有没有保住 tick 的原始时间戳。 一旦重采样,秒级信息就永久丢失了,再精巧的算法也救不回来。HY 平移法的价值就在于它原生吃异步 tick,不需要经过那道有损的重采样。
lag 估计有多稳?样本量与信号强度#
复现出峰值很爽,但实盘里你得问一句:这个 8 秒是真的,还是噪声凑出来的巧合? 峰值定位的稳健性取决于两个东西——你有多少数据,以及信号有多强。

**左图——样本量的作用:**用不同长度的数据各跑 60 次,看 lag 估计的均值和波动。数据少(500 个 tick,约几分钟)时,估计在真值附近剧烈抖动,误差棒很长——你今天测出 8 秒、明天可能测出 3 秒或 14 秒。随着样本增加到几千、上万个 tick,估计迅速收敛到 8 秒且波动收窄。结论:几分钟的数据测领先滞后几乎没意义,至少要积累到相当规模的成交才谈得上可信。
**右图——信号强度的作用:**关系越强(ρ=0.8),峰越尖锐、越好辨认;关系越弱(ρ=0.2),峰几乎被噪声淹没,你根本挑不出一个可靠的峰值位置。结论:领先滞后关系本身弱的资产对,别指望测出稳定的 lag——平峰意味着任何”峰值”都可能是随机波动的产物。
这两张图合起来给的实务准则很清楚:只在关系够强、数据够多的资产对上做领先滞后套利。 弱信号 + 短样本,你测出来的 lag 是纯噪声,照着它下单等于给市场送钱。
四类真实陷阱(进阶)#
陷阱一:领先滞后关系不是常数,会随 regime 漂移甚至反转。 你今天测出 A 领先 B 8 秒,可能是因为最近 A 的流动性更好、价格发现更快。一旦市场结构变了(B 上了新的做市商、A 遇上流动性枯竭),领先滞后可能缩短、消失甚至反向。把某天测出的 lag 当成永恒常数去下单,是领先滞后套利最常见的死法。 必须用滚动窗口持续重估,并监控峰值高度——峰一变平就说明关系在衰减,该停手了。
陷阱二:因果幻觉——领先不等于”leader 导致 follower”。 交叉相关峰值告诉你的是”A 的波动在时间上先于 B”,不是”A 引起了 B”。真实原因可能是第三方共同驱动(一条宏观新闻同时影响两者,但因为 A 流动性好先反应),或者纯粹是成交频率差异造成的假象——流动性高的资产天然显得”领先”,因为它 tick 更密、价格更新更快,这是采样效应不是价格发现。 把这种伪领先当真信号去套利,会在关系不存在的地方反复亏损。判别的办法之一:控制流动性后再看 lag 是否还在。
陷阱三:平移量的符号和时间轴方向极易搞反。 hy_cross 里那个 shift 到底是”把 B 往前推”还是”往后推”、正号代表”A 领先”还是”B 领先”,差一个符号,你的结论就完全反了——本来该在 leader 动之后抢 follower,结果你去抢 leader,方向反了稳亏。上线前必须用已知答案的合成数据(像本文这样注入一个确定的 lag)反复校验符号约定,确认代码测出来的方向和你注入的方向一致,再碰真实数据。这种符号错误在回测里往往不报错、还能跑出”盈利”曲线(因为你其实在用未来信息),最阴险。
陷阱四:可测的 lag 不等于可交易的 lag。 就算你精确测出 leader 领先 follower 8 秒,能不能吃到取决于你的下单链路够不够快。如果你从看到 leader 信号、到订单真正打进 follower 的簿子需要 5 秒,那你只剩 3 秒的可利用窗口;如果链路延迟 10 秒,这 8 秒 lag 对你完全无效——别人比你快,早就把价差吃没了。 领先滞后套利本质是延迟竞赛,测出 lag 只是入场券,你的执行延迟必须显著小于 lag 才有意义。回测里加上真实的下单延迟和滑点,很多看着诱人的 lag 会瞬间归零。
一句话总结#
领先滞后估计要回答的不是”两者相不相关”,而是”谁先动、领先多久、关系多强”。核心工具是交叉相关的峰值——峰的位置给你时间差,峰的高度给你关系强度,峰的符号给你方向。
而在真实的异步 tick 世界里,这一切的前提是保住成交的原始时间戳。一旦重采样到固定网格,秒级的领先滞后就被碾成了粉末。Hayashi-Yoshida 平移法的价值就在于它原生吃异步数据,用”时间重叠”绕开对齐难题,把秒级 lag 秒级地测出来。
但测出 lag 只是开始。它会随 regime 漂移、会被流动性差异伪装成因果、符号一错方向全反、更要命的是你的执行速度得快过这个 lag 才吃得到。领先滞后从来不是一个静态的数字,而是一场关于速度、稳健性和因果判断的持续博弈。