halo 的技术博客

返回

股票市场的异象大多要靠猜:你不知道机构什么时候调仓,不知道指数什么时候纳入,不知道大单什么时候来。

国债招标不一样。财政部提前公布招标日历,期限已知、日期已知、规模区间已知。这是市场上极少数「供给冲击的时间表提前几个月挂在网上」的场景。

如果「预期到的供给冲击仍然压价」这件事成立,它就是教科书级的价格压力证据——因为信息假说在这里根本站不住脚:所有人都早就知道这批债要来。

12 年、189 次 10 年期关键期限招标的模拟给出的答案:招标前 5 个交易日收益率被推高 1.67bp(折算价格 -13.12bp,t=-5.71),招标后 5 天回补 +7.24bp(t=3.64)

但这篇文章真正想讲的不是这两个数字,而是为什么大多数人自己跑一遍会得出「没有效应」的结论

招标前让渡与招标后回补

左图两条线是同一批 189 次招标、同一套事件研究代码,唯一区别是标的口径。灰线(裸做 10Y 期货)几乎看不出形状,置信带宽得能开车;蓝线(久期中性利差)的 V 型清清楚楚。

这就是本文的第一个核心结论:这个效应不是「弱」,是被噪音埋了

一、为什么裸口径必然测不出来#

先看量级对比。10 年期国债期货的日价格波动,在模拟设定下是 29.19bp。而招标让渡的峰值幅度平均只有 1.57bp 收益率,折算成价格约 12bp——分散在 5 个交易日里,每天摊不到 2.5bp

信噪比 2.5 : 29.19,约等于 1:12。

事件研究的标准做法是靠样本量把噪音开方掉。189 个事件,噪音降到 1/√189 ≈ 1/13.7。勉强够——但前提是这 189 次的噪音相互独立。

问题恰恰在这里:国债收益率的日波动几乎全部来自曲线水平因子。降息预期、通胀数据、风险偏好切换,这些冲击同时打在所有期限上,而且在时间上高度持续(AR 结构)。它不是可以靠样本量摊掉的白噪音。

实测结果印证了这一点:

口径招标前 [-5,0]t 值招标后 [+1,+5]t 值反转覆盖
裸做 10Y 期货-15.51bp-3.17+3.74bp0.7624.1%
久期中性利差-13.12bp-5.71+7.24bp3.6455.2%

裸口径的招标前项勉强过了 3,但反转项 t=0.76 彻底不显著。而反转才是判定「压力 vs 信息」的关键——没有反转,你无法排除「招标前收益率上行是因为市场真的在重新定价基本面」这个竞争性解释。

换句话说:裸口径下,这个研究做不出结论

对冲不是降噪技巧,是策略本身#

处理方式是构造久期中性的期限利差:做空 10 年期,同时按 BPV 比例做多 5 年期(对冲比例 1.80)。5 年期不参与本次招标,但共享同一个水平因子。

效果:日波动从 29.19bp 降到 11.84bp,降幅 59.5%

这里有个容易被忽略的点。很多人把对冲当成「为了让 t 值好看的统计技巧」,但在这个场景里它有更硬的含义:

你本来也只能这么交易。招标让渡是特定期限点上的局部现象,不是整条曲线的平移。如果你裸做 10Y,你承担的主要风险是利率方向——那是一个和招标毫无关系的赌注,它的波动是你想赚的那部分的十几倍。任何理性的固定收益交易员看到这个效应,第一反应就是做成利差交易。

所以「对冲后才测得出」和「对冲后才交易得了」是同一件事的两面。这类效应在研究口径和实施口径上必须一致,否则你回测的东西根本不是你能下的单。

二、被下一次招标污染的反转窗口#

第二个坑更隐蔽,而且是周期性事件研究特有的。

注意上表里对冲口径的反转覆盖率只有 55.2%。但从模型设定看,招标后压力按半衰期 2.1 天的指数衰减,在 [+1,+5] 窗口内理论上应该释放 90.8%

差了 35 个百分点。哪去了?

答案在招标日历里:招标间隔的中位数是 12 个交易日,而让渡爬坡提前 6 个交易日启动

也就是说,对于间隔较短的那些招标,你测量的 [+1,+5] 反转窗口,后半段已经踩进了下一次招标的让渡爬坡期。下一次的向下压力和本次的向上反转在时间轴上直接相减。

这不是模型的人为设定,是真实招标日历的结构性特征——关键期限每月都要发,续发密集时两次间隔可能只有一两周。

用窗口互吞筛选把它分离出来#

判据很直接:只有「距下次招标 ≥ POST_STAT + PRE_WIN = 11 个交易日」的事件,反转窗口才是干净的。

189 次招标里,符合条件的有 105 次(55.6%),被污染的 84 次。

# 下一次招标的爬坡提前 PRE_WIN-1 天开始,
# 因此只有间隔 >= POST_STAT + PRE_WIN 的事件,反转窗口才不被吞
nxt_gap = np.full(used.size, 10**6)
nxt_gap[:-1] = np.diff(used)
CLEAN_GAP = POST_STAT + PRE_WIN          # = 11
clean_ev = nxt_gap >= CLEAN_GAP
python

分组结果:

样本n招标前招标后反转覆盖
干净窗口105-13.22bp+8.70bp (t=3.18)65.8%
被污染84-13.00bp+5.42bp41.7%

招标前的让渡两组几乎一样(-13.22 vs -13.00)——这是关键对照。如果两组的差异来自某种样本选择(比如密集发行期恰好是市场紧张期),那么让渡幅度也该有系统性差异。它没有,说明差异确实只发生在反转窗口,符合「被下一次爬坡吃掉」的机制预测。

覆盖率的 bootstrap 95% 置信区间是 [23.1%, 144.5%]——很宽。这是诚实的呈现:覆盖率是两个带噪均值的比值,比值统计量的分布本来就厚尾,用一个点估计说「反转了 65.8%」是过度自信。能确定的是反转存在且显著为正(t=3.18),至于它精确覆盖了多少,样本量说了不算数。

顺带一提,用错误的 [+1,+8] 窗口测同一批数据:覆盖率 44.3%,t 值从 3.64 掉到 2.45。窗口开得越长污染越重,而直觉上”多观察几天更保险”恰恰是反的。

三、三组对照:排除竞争性解释#

三组对照与横截面识别

事件研究最容易翻车的地方是你的算法在任何日期上都能刷出信号。三组对照专门治这个:

对照组招标前 [-5,0]t 值排除了什么
真实招标日-13.12bp-5.71
错位 +13 日+0.94bp0.39排除「宏观环境相似期都有这现象」
随机日期-1.76bp-0.84排除「短期动量或算法伪影」
纯净市场(无压力序列)-3.66bp-1.66确认引擎不造假信号

错位安慰剂是这三个里最有价值的。它取的是真实招标日 +13 个交易日,处在同一个宏观环境、同一段利率周期、同样的流动性状况,唯一区别是那天不招标。结果 t=0.39,干净利落。

纯净市场对照跑的是完全没有注入招标压力的收益率序列,但用同一套事件研究代码、同一批日期。测出 -3.66bp(t=-1.66)——不显著,但方向恰好是负的,绝对值也不算小

这个数字值得停下来想一想。它意味着:如果我只跑了主实验没跑对照,看到 -13.12bp,我会默认全部归因于招标。但对照告诉我,其中大约有 3.66bp 是这套算法在无信号数据上也能刷出来的——真正可归因于招标的增量约 9.5bp,而不是 13.12bp。

这不是模型 bug,是有限样本下的正常涨落。但它给出一条纪律:任何事件研究的效应幅度,都应该减去纯净对照的幅度再报告。只报主实验数字,等于把随机涨落算进了自己的发现。

横截面:效应必须随机制强度单调#

对照组证明「招标日有事发生」,横截面证明「发生的正是我说的那件事」。

按招标规模五分位分组,让渡幅度:-4.54 / -11.64 / -15.05 / -17.79 / -16.63 bp

按承销商库存压力五分位:-8.03 / -10.89 / -15.99 / -11.59 / -19.16 bp

两条都大体单调(规模组 Q1→Q4 严格单调,Q5 略回落;库存压力组 Q4 有个凹陷)。最大减最小的价差分别是 -12.09bp(t=-1.59)和 -11.12bp(t=-1.58)。

这两个 t 值都没到 2。必须承认这点,不能因为方向对就宣称验证通过。

为什么单调性看得见但显著性不够?分位数分组把 189 个事件切成 5 组,每组只剩 38 个,组间价差的标准误自然大。这是横截面检验的固有代价——分组越细,模式越清晰,统计力越弱

正确的读法是:单调性提供了机制层面的支持性证据(因为随机涨落很难恰好排出接近单调的形状),但它不是独立的显著性证明。真正撑起结论的仍然是全样本 t=-5.71 加上三组对照。

四、可交易性:谁真的能拿到这笔钱#

成本曲线与参与者分层

到这里为止,效应是真的、机制是对的、对照是干净的。然后成本账本上场。

完整策略是:t=-6 收盘做空利差 → t=0 收盘平空并反手做多 → t=+5 收盘平多。

注意这里有 8 次单边成交:每条腿开平各一次,两条腿,两个方向段。这是利差交易的隐藏税——你为了降噪把腿数翻倍,成本也跟着翻倍。

  • 毛收益:21.91bp/次(干净窗口 105 次,年均 8.75 次)
  • 基准成本 1.6bp/单边 × 8 = 12.80bp
  • 净收益 9.11bp/次,成本吃掉毛收益的 58.4%
  • 毛 Sharpe 1.61 → 净 Sharpe 0.67
  • 盈亏平衡成本:2.5bp/单边
  • 胜率 59.0%,年化净收益约 0.80%

盈亏平衡 2.5bp 对国债期货来说是个危险的薄垫子。它大约是半个到一个 tick。这意味着执行质量不是优化项,是生死项——市价单扫单、事件日流动性变差、或者你的规模稍大一点,垫子就没了。

时间衰减:这个异象正在消失#

异象的时间衰减

分年度看,让渡幅度从前 6 年的 -18.62bp(t=-5.82) 掉到后 6 年的 -7.56bp(t=-2.35),只剩 40.6%

净 Sharpe 相应地从全样本 0.67 掉到后 6 年 0.32

模型里这个衰减是外生设定的(套利资本进入的半衰期 7 年),但它对应真实世界一个可观察的事实:这类日历型异象一旦被写成论文,通常就开始死。你回测出来的历史 Sharpe,永远是这个策略最好看的时候

这也解释了为什么全样本数字有误导性:一个报 0.67 Sharpe 的策略,如果它的收益全部来自前半段,那你现在部署它面对的是 0.32 那个世界。

容量墙与三类参与者#

按平方根冲击模型(日均成交 900 亿元):

名义规模5 亿10 亿20 亿50 亿100 亿
净收益(bp)+2.55-0.16-4.01-11.63-20.22

容量墙在 5 亿元。10 亿就已经翻负。对一个年化 0.80% 的策略来说,5 亿规模一年赚约 400 万——扣掉团队和系统成本,这不是一门生意。

但结论到这里会漏掉最重要的一层。右图把参与者分成三类:

(1) 纯 alpha 型(双腿双段,8 次单边):毛 21.91bp → 净 9.11bp。能做,但薄。

(2) 只做反转段(双腿单段,4 次单边):毛 8.70bp → 净 2.30bp,Sharpe 从 0.92 掉到 0.24。少一半成交却更难做,因为反转段的毛收益本来就比让渡段小。

(3) 自然买方(配置盘、指数跟踪、被动接盘):净 11.36bp,成本为零

第三类是这个效应真正的受益者,而且优势最大。原因不需要任何交易技巧:他们本来就要买这批债。招标周期效应对他们不是「要不要开一个仓位」,而是「在哪一天执行本来就要执行的买入」。改变择时日不产生任何增量成交,因此不付任何增量成本

11.36bp 这个数字是扣掉随机日期基线后的净增量——即「在让渡最深处买」相对「随便挑一天买」多省下的价格。

这是整篇文章最实用的一条:同一个市场规律,对不同参与者的价值可以差一个数量级,而差异不在信号质量上,在成本结构上。一个年换手率本来就固定的配置组合,它的每一笔既定交易都自带一个免费的择时期权。绝大多数人不去行权。

五、Bug 复盘:用 = 而不是 += 注入压力#

写这个模拟时踩过一个坑,值得单独说,因为它属于「不报错、结果还挺像样」的那一类。

构造压力路径时,第一版是这么写的:

def build_pressure_bug(days, amps):
    p = np.zeros(N_DAYS + 40)
    ramp = np.arange(1, PRE_WIN + 1) / PRE_WIN
    for d, a in zip(days, amps):
        p[d - PRE_WIN + 1 : d + 1] = a * ramp              # ← 用 = 覆盖
        tail = np.arange(1, 26)
        p[d + 1 : d + 26] = a * np.exp(-tail / TAU_DECAY)  # ← 用 = 覆盖
    return p[:N_DAYS]
python

问题:招标间隔中位数 12 天,而衰减尾巴要写 25 天。下一次招标的爬坡段在写入时,会把上一次尚未衰减完的尾巴整段抹掉

正确写法只差两个字符——+= 而不是 =

p[d - PRE_WIN + 1 : d + 1] += a * ramp
p[d + 1 : d + 26] += a * np.exp(-tail / TAU_DECAY)
python

为什么这个 bug 危险:跑出来的结果是 -12.34bp(t=-5.32),覆盖率 56.5%

对比正确版本的 -13.12bp(t=-5.71),差异小到你根本不会怀疑。方向对、量级对、显著性也够——所有的 sanity check 都会放行。

它的实际后果是系统性低估了压力的持续性:被抹掉的尾巴恰恰是相邻招标之间相互叠加的那部分。在真实市场里,密集发行期的压力叠加是这个效应最值得研究的地方,而这个 bug 会让它完全消失。

教训不是”要小心 +=”,而是:当你的事件间隔小于事件影响的持续期时,任何按事件循环写入时间序列的代码都必须是累加语义。这个条件在债券招标、财报季、期权到期这些场景里普遍成立。检查方法也很简单——把注入的压力序列直接画出来看,叠加区间一眼就能看出来是不是被削平了。

六、三盆冷水#

第一,压力机制是外生注入的,不是从微观结构涌现的。 本文的 A_i 由招标规模和承销商库存压力按设定公式生成。这决定了横截面单调性在某种意义上是「设计出来的」——它验证的是测量方法能否还原已知机制,而不是发现了机制本身。真实市场里的让渡幅度取决于一级交易商的实际资产负债表约束、当日 repo 市场松紧、以及非竞争性投标的占比,这些都不在模型里。

第二,久期中性对冲假设了 5 年期完全不受招标影响。 现实中不成立。如果一级交易商为了给 10Y 腾出额度而抛售 5Y,对冲腿会同向下跌,实际收益低于回测。更麻烦的是这种溢出恰恰在库存压力最大时最强——也就是效应最强的那些事件上,对冲失效也最严重。这会系统性地高估横截面价差。

第三,1.6bp/单边的成本假设对散户和中小机构是乐观的。 它对应做市商级别的执行。考虑到盈亏平衡只有 2.5bp,成本假设从 1.6 提到 2.5 就意味着这个策略归零。而且这还没算保证金占用、展期成本、以及事件日买卖价差走阔——招标日前后流动性变差本身就是让渡产生的原因之一,你想交易的时刻恰好是执行最贵的时刻。

最后#

这个研究链条上,四步里有三步的结论是否定性的:裸口径测不出来、长窗口测反了、纯 alpha 型交易在成本和容量面前几乎不成立。

唯一稳固的正面结论,反而是那个不需要任何交易技巧的:本来就要买债的人,把执行日挪到让渡最深处,白拿 11.36bp

这大概是量化研究里反复出现的一种形态。你花大力气识别出一个真实的市场规律,然后发现能把它变成钱的,不是识别得最准的人,而是成本结构最合适的人。

信号的价值从来不是绝对的——它取决于你是谁。

国债招标周期效应:一级市场供给冲击的可交易节奏
https://blog.halo26812.eu.org/blog/treasury-auction-cycle-effect
Author halo
Published at 2026年7月31日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨