月份效应这个词,第一次听到的人多半会觉得不靠谱——不就是几月涨几月跌吗,这也算研究?但真把股票数据拉出来跑一遍,你会发现事情远没那么简单:同一份行情,换个复权方式结论就反了;同一个月份,样本区间往前挪五年,显著性就消失了。我在做因子回测的空档里反复折腾过日历效应这个题目,踩过的坑比得到的结论多得多,所以这篇不谈玄学,只谈怎么把月份效应这件事做得能被别人复核。
这篇文章适合三类人:手里有行情数据想自己做统计验证的开发者、刚接触量化研究想找一个完整练手题目的新手、以及看过一些“几月魔咒”说法但不确定该不该信的交易者。核心讲三件事——月份效应在统计上到底该怎么定义,从原始行情到月度效应表中间有哪些必须处理的细节,以及跑出结果之后怎么判断它是真规律还是数据噪音。
1. 先把概念摆正:月份效应到底在研究什么
1.1 日历效应的本质是“按时间切片后的统计差异”
日历效应这个词听起来很学术,拆开看其实特别朴素:把一段时间序列按某种时间维度切成若干组,然后比较各组之间的统计特征有没有系统性差异。切法可以是月份、星期几、每月第几个交易日、节气、节假日前后,甚至是每月月初和月末。月份效应只是其中最常被讨论的一种切法,把一年十二个月当成十二个分组标签。
理解这一点很关键,因为它决定了这件事的数学本质——你做的不是预测,而是分组比较。很多新手一上来就想“我能不能用月份预测下个月涨跌”,方向就跑偏了。月份效应研究的正确姿势是:在历史样本里,某些月份的收益分布在统计上是否显著不同于其他月份。它是一个描述性统计问题,不是一个预测模型问题。搞清楚这层,后面所有的检验方法、稳健性设计才有落脚点。
再往深一层说,任何日历效应都面临一个天然困境:一年只有十二个月,样本再长,每个月份标签下的独立观测数也就那么几十个。这意味着统计功效天生偏弱,你很难拿到那种“一看就假不了”的证据。所以月份效应研究里,怎么把有限的样本用足、怎么避免过度解读,比用什么高级模型重要得多。
1.2 三种验证口径:均值、胜率、风险调整后收益
同一份月度收益序列,至少有三套口径可以拿来衡量月份差异,而且它们的结论经常不一致,这是最容易吵架的地方。第一种是均值口径,直接看各月平均收益率,这也是媒体报道里最常用的说法。第二种是胜率口径,统计某个特定月份里上涨的次数占比,它衡量的是方向一致性,对极端值不敏感。第三种是风险调整口径,用平均收益除以波动率,或者干脆看夏普比的月度分解。
为什么三种口径会打架?举个典型情况:某个月份平均收益很高,但主要是被一两次暴涨拉起来的,中位数其实偏低,胜率也就五成出头。这种月份用均值口径看很亮眼,用胜率口径看毫无优势,用风险调整口径看甚至不如平均水平。我的习惯是三套口径一起跑,任何一套单独亮眼、另外两套平庸的月份,一律先当可疑处理。
实际操作里还有一个容易被忽略的细节:算术平均和几何平均的差别。月度收益的算术平均可以直接用于t检验,但它会系统性高估长期复合收益,尤其在有较大波动的序列里。如果目的是评估“长期持有某个季节性策略能赚多少”,必须用几何平均或者累乘口径重算一遍,否则数字会虚高,而且样本波动越大虚高得越厉害。
1.3 为什么这个题目最容易产出假结论
月份效应是量化研究里“假阳性”的高发区,原因有三个。第一个是多重比较问题:你在十二个月里挨个检验,即使每个检验的显著性水平设在百分之五,纯靠运气也会期望出现零点六个“显著”月份,只要样本里碰巧有一两个月特别扎眼,人就会自动把它解释成规律。第二个是样本区间可选性:研究者往往会不自觉地试多个起点终点,挑出最好看的那一段来展示。第三个是叙事偏误——一旦看到某个月份数字特殊,人脑立刻开始编故事,比如“这个月是财报空窗期”“这个月资金面紧张”,理由听着都挺顺,但换个市场、换个年代,同样的故事往往就对不上了。
我自己的应对办法很土但有效:在做任何分组统计之前,先在纸上写下样本区间、口径、检验方法,然后严格执行,不允许中途改。如果结果不好看,那就是不好看,记录下来。事后回头翻,那些被我“忍痛放弃”的月份,绝大多数在后续样本里都回归平庸了,而那些一开始就漂亮的结论,反而有相当一部分能撑住。这个经验告诉我,研究纪律本身就是过滤噪音的有效手段。
2. 数据准备:脏数据会毁掉整个结论
2.1 样本区间不是越长越好
新手最容易犯的错误是“数据越多越可靠”,于是一口气拉二十年甚至三十年。问题是市场结构在变:交易制度改过、涨跌停规则调整过、参与者结构变了、指数成分股换过好几轮。把三十年的数据揉在一起算月度均值,等于假设这三十年是同一个数据生成过程,这个假设基本站不住。
我的做法是分段处理。先按制度或市场结构的大变化切出几个子区间,在每个子区间内单独做月份统计,然后看效应在子区间之间是否一致。如果某个效应只在最早那一段存在,最近十年完全消失了,那它对当下的参考价值就很有限——哪怕全样本的检验结果非常显著。反过来,如果效应在各个子区间里方向一致、量级接近,只是显著性有高有低,那可信度就高很多。
子区间的长度也有讲究。太短(比如五年)每个月份只有五个观测,统计上什么都说明不了;太长(比如二十年)又会把不同阶段混在一起。我通常按八到十二年一段来切,保证每个月有八十到一百二十个观测,同时大致对应一轮完整的市场周期。这个数字没有理论最优,是我试下来觉得平衡感最好的区间。
2.2 复权口径决定了一半的结论
这条是血泪教训。同一只标的,用不复权价格算月度收益,和用前复权、后复权算,结果能差出好几个百分点——尤其在分红集中的月份。这个问题在指数层面影响小一些(价格指数和全收益指数的差异是系统性的),但如果你研究的是一篮子个股的等权组合,复权方式选错,等于在数据里人为制造了一个“分红月效应”。
具体来说,不复权价格在除权日会出现一个跳空缺口,这个缺口会被算成负收益,而这个缺口恰好集中在年报、中报分红密集的月份。结果就是某些月份的平均收益被系统性压低,你还以为是市场规律。用前复权能消除这个缺口,但前复权价格会随着新的分红不断调整历史数据,导致你昨天跑的结果和今天跑的不一样,这在需要复现的研究里是个麻烦。
我的处理原则是:个股层面用后复权或者总收益口径,保证历史数据不随新事件变动;指数层面明确区分价格指数和全收益指数,做收益率统计时优先用全收益口径。如果手上只有价格指数,至少要在结论里注明“未含分红”,别把差异算到月份效应头上。
2.3 交易日对齐与特殊样本处理
月收益率的切分看着简单,其实处处是坑。第一个坑是“自然月最后一天”和“最后一个交易日”的区别。前者在遇到周末和长假时会取不到数据,后者才是正确的锚点。第二个坑是停牌。个股停牌期间价格不动,但月末取价时如果恰好停牌,你取到的是停牌前的价格,这个价格可能已经严重滞后,用它算出来的月度收益是失真的。
第三个坑是新股和退市样本。新股上市首月往往有极端收益,退市前一个月也有异常波动,这些样本混进去会让某些月份的分布尾部变厚。我的做法是设一个最小观测门槛:上市不满六十个交易日的样本剔除,退市前最后二十个交易日的样本剔除,停牌超过五个交易日的月份标记出来单独看。这些门槛都是经验值,目的是把明显不属于“正常交易状态”的样本隔离掉。
第四个坑是指数成分调整。如果你研究的是某个指数的成分股组合,成分股每年调整会带来样本不连续。简单办法是直接用指数本身的收益率序列,省掉成分股重构的麻烦;如果一定要用成分股,就得按调整日期分段,保证每段内的成分是固定的,否则你算出来的“组合收益”其实是不同股票池拼接的结果。
3. 从原始行情到月度效应表:核心计算拆解
3.1 月收益率到底怎么切
先把最基础的代码写清楚,不然后面全是空中楼阁。假设手上的数据表有两列,交易日和收盘价,已经按日期升序排好。核心思路是先标记每个交易日所属的月份,然后取每个月最后一个交易日的收盘价,相邻两个月末价格相除减一,就是月收益率。
import pandas as pd import numpy as np df = df.copy() df['trade_date'] = pd.to_datetime(df['trade_date']) df = df.sort_values('trade_date').reset_index(drop=True) # 标记年月 df['ym'] = df['trade_date'].dt.to_period('M') # 每月最后一个交易日的收盘价 month_end = df.groupby('ym', as_index=False).tail(1) month_end = month_end[['ym', 'trade_date', 'close']].reset_index(drop=True) # 月收益率 month_end['ret'] = month_end['close'].pct_change() month_end['month'] = month_end['ym'].dt.month # 首月收益率为空,直接剔除 month_end = month_end.dropna(subset=['ret'])这里有个容易忽略的点:第一个月的收益率必然是空的,因为找不到上一个月末的价格。如果样本从某年一月开始,那这一年的第一个月就被吃掉了,实际参与统计的月份会比你以为的少一个。做样本区间统计的时候要把这个损耗算进去。
还有一种切法是用固定的交易日窗口,比如每月第二十个交易日到下一个第二十个交易日。这种切法在海外市场研究里比较常见,好处是每个窗口的交易日数完全相同,避免了不同月份天数差异带来的波动率偏差。坏处是它和自然月的直觉对不上,做出来读者不好理解。我个人倾向于自然月加月末交易日锚定,然后在稳健性检验里用固定交易日窗口跑一遍做交叉验证,两套结果一致才敢下结论。
3.2 分组统计的代码实现
拿到月度收益序列之后,分组统计本身几行代码就够,难的是把该算的指标一次算全。我一般会输出样本数、均值、中位数、标准差、胜率、最大值、最小值这一组完整描述,然后在后面单独做检验。
def month_stats(ret_series, month_series): g = pd.DataFrame({'ret': ret_series, 'month': month_series}) out = g.groupby('month')['ret'].agg( n='count', mean='mean', median='median', std='std', win=lambda x: (x > 0).mean(), best='max', worst='min' ) # 年化后的等效收益,仅作直观参考 out['ann_equiv'] = (1 + out['mean']) ** 12 - 1 # 简单t统计量 out['t_stat'] = out['mean'] / (out['std'] / np.sqrt(out['n'])) return out.sort_index() stats = month_stats(month_end['ret'], month_end['month'])这段代码里有个陷阱要提醒:ann_equiv这一列把月度均值直接按十二次方年化,数学上是不严谨的,因为它假设每个月都重复这个收益。它的唯一用途是让数字看起来直观一点,比如“这个月平均零点八个百分点,年化大概十个点”,千万别拿它当真实预期收益写进结论。我在早期报告里犯过这个错,被自己后来的回测打脸。
还有一个细节是标准差。不同月份的标准差可能差异很大,如果你只比较均值而忽略波动,很容易得出错误结论。比如某个月平均收益高两个百分点,但标准差是其他月份的两倍,风险调整后其实毫无优势。所以我习惯在看均值表的同时,把标准差和胜率并排放,三个数字一起看。
3.3 显著性检验与多重检验校正
分组统计出来只是描述,要不要相信它得上检验。最直接的是对每个月份做单样本t检验,零假设是这个月平均收益等于零。但这个思路有个问题:它检验的是“是否为零”,而不是“是否不同于其他月份”。如果你想知道某个月是否具有独特的季节性,应该做的是两样本比较——这个月的收益序列和其余月份的收益序列做均值差异检验。
from scipy import stats as st results = [] for m in range(1, 13): this_m = month_end.loc[month_end['month'] == m, 'ret'] other = month_end.loc[month_end['month'] != m, 'ret'] t, p = st.ttest_ind(this_m, other, equal_var=False) # 效应量:均值差除以合并标准差 pooled = np.sqrt((this_m.var() + other.var()) / 2) d = (this_m.mean() - other.mean()) / pooled results.append({'month': m, 'mean_diff': this_m.mean() - other.mean(), 't': t, 'p': p, 'cohen_d': d, 'n': len(this_m)}) res_df = pd.DataFrame(results)跑完这一步,十二个p值排在一起,多重比较问题就来了。控制这个问题的办法有两种:Bonferroni校正简单粗暴,把显著性阈值除以检验次数,十二次检验就要求单次p值小于万分之四左右,非常严格,容易漏掉真实效应;FDR校正在探索性研究里更合适,它控制的是“被判为显著的结论里假阳性的期望比例”,不那么保守。
from statsmodels.stats.multitest import multipletests rej, p_adj, _, _ = multipletests(res_df['p'].values, alpha=0.05, method='fdr_bh') res_df['p_fdr'] = p_adj res_df['sig_fdr'] = rej我的经验是:Bonferroni结果拿来做最终判断,FDR结果拿来看趋势。如果某个月份连Bonferroni都能过,那确实值得深挖;如果只有FDR过,就当作“有微弱信号,需要更多证据”,不要急着下结论。
3.4 结果表格化与呈现方式
跑完上面的流程,把结果整理成一张表,比任何文字描述都直观。下面是我习惯的呈现格式,字段做了脱敏处理,数值是示意性的。
| 月份 | 样本数 | 月均收益 | 标准差 | 胜率 | 与其余月均值差 | t值 | FDR校正p值 |
|---|---|---|---|---|---|---|---|
| 1月 | 118 | 0.62% | 5.8% | 56% | +0.28% | 0.91 | 0.42 |
| 2月 | 118 | 1.35% | 6.4% | 61% | +1.02% | 2.34 | 0.09 |
| 3月 | 118 | 0.21% | 6.1% | 52% | -0.12% | -0.35 | 0.73 |
| 4月 | 118 | 0.94% | 5.5% | 58% | +0.61% | 1.87 | 0.14 |
这张表能一眼看出几个信息:二月的均值差和t值都相对突出,但FDR校正后p值接近临界,说明“显著”这件事本身并不牢固;四月的效应量不小但t值偏低,可能是波动大导致;三月基本没有任何迹象。把这些放在一张表里,比单独拎出二月说“二月效应显著”要诚实得多。
表格里我特意保留了“与其余月均值差”和“效应量”两列,因为它们比p值更能说明问题有多大。一个统计显著但效应量只有零点一个百分点的月份,和一个效应量一个百分点但样本太短导致不显著的月份,前者在实盘里可能根本覆盖不了交易成本,后者反而值得继续跟踪。
4. 结果怎么读:把统计显著翻译成能落地的判断
4.1 效应量比p值更值得盯
做研究的人对p值有种执念,好像小于零点零五就等于发现了真理。但在日历效应这个场景里,p值高度依赖样本量和波动率。样本短、波动大,再强的效应也测不出来;样本长、波动小,哪怕效应量微不足道也能“显著”。所以我看结果的第一眼永远是效应量,第二眼才是显著性。
具体做法是把月度均值差换算成更贴近实际的单位:假设你在年初就固定了全年的持仓月份切换方案,这个效应一年能贡献多少超额,扣掉两边切换的交易成本还剩多少。还是拿示意数据说:二月均值差一个百分点听着不小,但如果你的策略是每年只在二月加仓、三月减仓,一年就两次交易,成本大概千分之一到千分之二,扣完还剩零点八个百分点左右,这个量级是有意义的。反过来,如果某个月均值差只有零点二个百分点,来回两次切换成本直接吃掉大半,那无论p值多小都不值得做。
还有一个量化手法是看置信区间。均值差的百分之九十五置信区间如果跨过零且上下界都很宽,说明估计精度差,这时候纠结均值是正是负意义不大。我一般会在表里只保留置信区间明显不跨零的月份做进一步讨论,其余的一律归入“证据不足”。
4.2 稳健性检验的三板斧
跑出初步结果之后,必须做稳健性检验,否则你都不知道自己信的是什么。我常用的三板斧是:子样本切分、滚动窗口、跨市场对照。这三招分别对应“时间上稳不稳”“近年还灵不灵”“换个地方还成不成立”。
子样本切分最直接,把样本按时间对半或者分三段,每段单独跑一遍分组统计,看效应方向和量级是否一致。如果效应只在前半段存在,后半段完全消失,那基本可以判定这是历史特定阶段的产物。滚动窗口更进一步,用固定长度(比如十年)的窗口逐年滑动,把每个窗口里的月度均值差画成一条时间序列。这条线如果是平的,说明效应稳定;如果是一路衰减,说明市场在把这个规律消化掉。
跨市场对照是最有说服力但也最容易被误用的一招。在另一个交易规则类似的市场里跑同样的流程,如果效应方向和量级接近,可信度大增;如果完全没有,也不代表原来的结论一定错,可能只是市场结构差异。关键是不要拿这个对照来“证明”什么,只把它当作一个参考维度。
我自己跑过几轮之后的体会是:能同时通过子样本和滚动窗口检验的月份效应,少之又少。绝大部分看起来漂亮的结论,在滚动窗口下都会露馅——要么只在某几个窗口显著,要么方向来回横跳。这个过程很打击人,但也正是它让我后来对任何季节性说法都保持距离。
4.3 交易成本与可实现性
统计上成立的东西,落地时最容易被忽略的是交易成本。月份效应的天然缺陷是调仓频率低但切换明确:你得在月初建仓、月末平仓,一年十二次进出,双边成本累积起来不是小数目。按单边万分之五算,一次完整切换千分之一,十二次就是一点二个百分点,这还没算冲击成本和滑点。
所以判断一个月份效应值不值得做,第一步是把年化效应量算出来,第二步是扣掉估算的交易成本,看剩下的实惠有多少。我见过一些研究报告,把月份效应年化三四个百分点说得天花乱坠,但完全没提成本——实际上扣完可能只剩一个点出头,风险却不小,性价比非常一般。
还有一层现实的约束是资金容量。月份效应本质上是择时,择时策略的容量取决于标的流动性。如果是宽基指数这类流动性好的标的,容量问题不大;如果是小市值组合,切换时点集中可能带来明显的冲击成本,实际收益会大幅缩水。这一点在纸面回测里完全看不出来,只有真正下单才会体会。
4.4 与其他日历效应的交叉污染
月份效应很少单独存在,它经常和别的日历效应纠缠在一起,最常见的是月初月末效应和星期效应。举个例子:如果某个特定月份恰好包含更多的交易日,而交易日的分布又和星期分布相关,那你看到的“月份差异”可能一部分来自星期效应。类似地,长假前后的收益特征往往很特殊,如果某个节假日在某个月份里集中出现,这个月份的统计就会被拉偏。
处理办法是在回归框架里同时放入多个日历变量,看月份变量在控制住其他变量之后还剩多少解释力。简单做法是跑一个多元回归,因变量是日收益或者月收益,自变量包括月份哑变量、星期哑变量、是否节假日前后的哑变量,然后看月份哑变量的系数和显著性变化。如果加入其他变量之后月份效应大幅缩水,那说明它大部分是被别的效应带出来的。
这一步很多人跳过,因为单变量分析已经出了结果,急着写结论。但我实测下来,跳过这一步的代价很高:曾经有一组看起来挺像回事的月份差异,加上星期控制之后几乎完全消失,后来查明是样本期内某个月份的历史交易日分布恰好偏移造成的。如果当时直接下结论,就等于把一个统计假象当成了市场规律。
5. 常见问题与排查技巧实录
5.1 问题速查表
做这个题目过程中遇到的问题,我整理成一张表,按症状、可能原因、排查动作来组织,方便对照。
| 症状 | 可能原因 | 排查动作 |
|---|---|---|
| 某月均值特别高但中位数很低 | 极端值主导 | 检查该月最大最小收益,尝试缩尾后重算 |
| 换复权方式结论反转 | 分红集中的月份被误算 | 统一用总收益口径重跑,对比差异出现的月份 |
| 全样本显著但近年消失 | 市场结构变化或规律被消化 | 做滚动窗口,看效应量的时间序列 |
| 加入其他日历变量后效应缩水 | 与星期或节假日效应混淆 | 跑多元回归,观察系数变化 |
| 不同起点的结论完全不同 | 起点敏感性高 | 固定检验次数,做起点敏感性扫描 |
| 月度收益分布明显非正态 | 少数月份有极端行情 | 改用bootstrap或秩检验,别硬套t检验 |
这张表里最值得说的是最后一条。月度收益的分布往往不是正态的,尾部比正态厚,尤其在波动大的市场里。t检验对非正态有一定稳健性,但样本只有一百个左右时,偏态和厚尾会明显影响p值。这时候用bootstrap重抽样会更稳妥,尤其是分块bootstrap——因为月度收益存在一定的自相关,普通bootstrap会低估不确定性。
def block_bootstrap_diff(x, y, n_boot=5000, block=6, seed=7): rng = np.random.default_rng(seed) x, y = np.asarray(x), np.asarray(y) diffs = np.empty(n_boot) for i in range(n_boot): sx = _block_sample(x, block, rng) sy = _block_sample(y, block, rng) diffs[i] = sx.mean() - sy.mean() return np.percentile(diffs, [2.5, 97.5]), diffs def _block_sample(arr, block, rng): n = len(arr) n_blocks = int(np.ceil(n / block)) starts = rng.integers(0, max(n - block, 1), n_blocks) out = np.concatenate([arr[s:s + block] for s in starts]) return out[:n]5.2 几个我踩过的坑
第一个坑是拿自然年做分组。刚开始我图省事,直接按年份分组算年均收益,然后拿年均收益去比较不同年份,结论当然乱七八糟。月份效应必须按跨年的月份标签聚合,把每年的一月放在一起,每年的二月放在一起,这样每个月份标签下才有足够的观测。这个错误听起来很低级,但我在第一次写代码时真的犯过。
第二个坑是忽略了交易日数量的差异。不同月份的天数不同,交易日数也就不同,二月普遍比其他月份少两到三个交易日。如果某个月的平均日收益率和其他月份接近,但因为交易日少,月度总收益就会偏低,这个差异不是市场规律,是日历结构造成的。修正办法是在比较月收益时,顺便看一眼日均收益,或者直接用固定交易日窗口的切法做交叉验证。
第三个坑是对“显著”的过度解读。有段时间我特别执着于找出显著性,试了各种样本区间、各种检验方法,最后确实凑出了几个p值很小的月份。但冷静下来看,这些结论互相矛盾——用这个区间显著的月份,换个区间就不显著了;用这个检验方法过线的,换个方法就不过了。这种靠筛选出来的显著,本质上是在拟合噪音。后来我给自己定了条规矩:任何结论必须在预设的样本和方法下一次性得出,不允许事后调整。
第四个坑是忽视市场制度变化的时点。有些市场在历史上调整过涨跌停幅度、调整过交易时间、调整过结算规则,这些变化会影响收益率的分布特征。如果样本跨越了这些时点而没有做分段处理,统计结果就可能被制度差异污染。做研究前花半小时查一下样本期内的重大制度变化,能省掉后面很多麻烦。
第五个坑是把“效应存在”和“效应可利用”混为一谈。统计上找到差异,和能不能拿它赚钱是两件事。中间隔着交易成本、资金容量、执行时点、心理承受能力等一堆现实约束。我现在看任何季节性研究,第一反应都是问“扣完成本还剩多少”,而不是“p值多少”。这个思维转变花了挺长时间,但确实让我少走了很多弯路。
6. 验证体系怎么搭才算完整
6.1 样本外验证的实操安排
前面所有工作都是在同一份样本上做的,无论检验多严格,都存在过拟合的可能。真正能提升可信度的是样本外验证。具体做法是把数据按时间切成两段,前一段用来发现规律、确定参数,后一段完全不碰,等前面全部定稿之后,只用后一段跑一次验证,结果不管好坏都如实记录。
这个流程听起来简单,执行起来最难的是纪律。因为你在前一段跑出结果之后,很难忍住不去看后一段,而一旦看了,样本外就不成立了。我的办法是写一个脚本,把参数和检验逻辑全部固定下来,然后用一个开关控制跑哪一段,前一段调通之后锁死代码,过一段时间再跑后一段。中间这段时间不去碰它,减少主观干预。
样本外的结果通常比样本内难看很多,这是正常的。如果效应量衰减了一半但方向还在,说明规律可能真实存在但被市场部分消化了;如果方向反了或者完全消失,那就得承认前面的发现大概率是噪音。我经历过的几次验证里,能撑住的不到三分之一,这个比例其实挺符合我对这类研究的预期。
6.2 把结论写成可复查的形式
最后说一个容易被忽略但很重要的点:把你的研究过程写成别人能复查的形式。至少要包含样本区间、数据口径、复权方式、检验方法、多重比较处理方式这几个要素。缺了任何一个,别人都没法判断你的结论是真发现还是数据处理方式的副产品。
我习惯在结果表下面附一段说明,写清楚每个数字是怎么算出来的,包括剔除规则、缩尾处理、检验的具体形式。这些东西写起来枯燥,但它是研究可信度的基础。一份没写清口径的月份效应报告,哪怕结论再漂亮,也只能当谈资,不能当依据。
跑完这一整套流程,我对月份效应的态度变得很平:它可能存在,但强度远低于初看时的印象,而且绝大多数效应在扣除成本、做完全套稳健性检验之后,剩下的可利用空间非常有限。真正有价值的不是某个具体月份的数字,而是这套从数据清洗到显著性检验再到稳健性验证的完整方法论。这套流程换个题目照样能用,比如研究星期效应、节前效应,甚至完全不相关的时间序列分组问题。
我个人在实际操作中的体会是,做这类研究最大的敌人不是数据不够多,而是忍不住想去“找到点什么”。把预期放低,把纪律守住,让数据自己说话,出来的结论虽然平淡,但至少是站得住的。