☰
月末策略回测复盘:从漂亮曲线到真实边界的量化研究记录
2026/9/30 8:18:11 网站建设 项目流程

先交代一下背景:我前前后后研究了两三个月的“月末策略标的”,第一版回测曲线漂亮到让人差点直接上实盘——年化收益、最大回撤、胜率每一项都拿得出手。真正开始动手“再研究”之后,才一层层发现自己踩了多少坑:复权口径对不上、月末的定义太模糊、标的池自带幸存者偏差、几十次交易算出来的胜率根本不显著,更别说交易成本把超额收益吃掉大半。这篇文章就是我把整个回测过程重新做一遍的完整记录,重点放在怎么拆解策略假设、怎么搭数据基建、怎么识别收益来源,以及最终哪些结论可以扛过实战检验。如果你也对日历效应、低频调仓这类策略感兴趣,或者正被某条漂亮的净值曲线冲昏头脑,这篇应该能帮你省掉不少冤枉时间。

先说清楚,这整篇只是我自己研究过程的复盘和思考,不构成投资建议。

1. 为什么反复盯住“月末”:策略假设与标的选择逻辑

1.1 先拆解月末效应的三层市场逻辑

市面上谈“月末策略”的人很多,但大家对这个效应为什么存在的解释往往特别含糊。我自己的习惯是,任何策略动手回测之前,先把市场机制拆到能说服自己为止。归纳下来,所谓月末效应无非三层来源。

第一层是机构调仓。很多公募、私募产品习惯在月末或季末复盘仓位、更新组合,资金会在最后几个交易日集中流向或流出某些标的。这个逻辑的强度和产品考核周期直接相关,所以月末效应在季末、半年末、年尾往往比普通月份更明显。第二层是资金面与结算周期。月末是资金结算密集期,回购利率、短端利率常有脉冲式波动,部分对流动性敏感的资产会被错杀,或者反过来产生对冲需求。这一层并不均匀分布在所有股票上,它更偏向债券、货基以及高股息类权益资产。第三层是指数再平衡。很多指数在月末或季末调整成分股,跟踪资金会被动买入卖出,相关标的出现方向相对可预测的成交脉冲,最适合用ETF去捕捉。

搞清楚这三层逻辑之后,你会发现市面上各种“月末策略”其实是在赚三类不同的钱。把“月末”当成一个笼统的日历效应直接跑回测,是最低级的用法,我第一版策略恰恰就犯了这个错误,所以后来怎么优化都觉得心虚。

1.2 标的池的三种选择,背后是三种风险偏好

蒙着眼睛选标的肯定不行。我把常见方案分成三类:宽基ETF、行业主题ETF、个股。

宽基ETF是最大路的做法,优点非常明显——流动性好、容量大、交易摩擦小,缺点是效应会被指数层面的噪声稀释,超额收益通常不厚。行业主题ETF的弹性更足,比如券商、科技、消费这类资金敏感型板块,月末调仓的脉冲会更强,但行业景气切换往往把日历效应压得看不见,样本期稍微短一点就失效。个股的想象空间最大,要是能提前识别机构月末加仓的票,超额收益会非常可观,但个股价格里充斥着太多非策略噪声,几笔异常公告就能把统计显著性彻底打穿。

第一轮我在标的池上做了个错误决定:把宽基ETF和个股混在同一个池子里回测,想着“分散持仓”能同时拿到两类收益。结果净值曲线确实好看,但收益归因之后发现,超额收益几乎全来自那几只个股,而这些个股没有经过严格的存续期约束,相当于把幸存者偏差直接放进了模型。第二轮我改成“宽基ETF打底,叠加行业ETF按信号轮动”,池子更干净,可解释性也强得多。

这里有个很容易忽略的点:标的选择不是越多越好,而是要和样本量匹配。月度调仓一年只有12次,如果标的池塞进50只股票,算下来每只标的只有几十个观测样本,任何统计推断都不靠谱。宁可把池子收窄到15到20只,把每只标的的观测历史尽量拉长。

1.3 假设先行:没有市场逻辑的策略不值得回测

我后来反复强调一个原则:回测的起点不应该是“我偶然发现某些日子涨得多”,而应该是“我对某个市场机制有明确假设,回测只是去验证这个假设能不能带来可交易的收益”。

如果假设月末效应的主源是机构调仓,那策略应该把仓位集中在机构重仓的板块,并且用超额收益而不是绝对收益来评估。如果假设主源是指数再平衡,那策略盯住的方向就应该是指数公告日与生效日之间的窗口,而不是笼统地“月末最后几天买入”。没有这种机制层面的假设,回测就很容易退化成参数搜索游戏——换一个窗口、换一组标的、换一种持有天数,总能在历史数据里找出一个很赚钱的组合。但这种组合放到未来,很大概率只是把噪声拟合成了一条漂亮曲线。

我现在做任何回测研究,第一件事都是先在文档里把“我认为钱在哪里、为什么在那里”写清楚,再开始碰数据。这个流程看着慢,其实反而节省时间,因为在数据基建和参数调优上可以少走很多弯路。

2. 回测基建的六个坑:数据口径、复权和滑点假设

2.1 复权方式不对,单月收益可能差好几个百分点

先讲最隐蔽的坑——复权。国内行情软件默认显示前复权,很多人直接把前复权价格拿来计算收益率,这是一个非常容易犯的惯性错误。前复权以当前价格为基准向历史调整,不同时间下载的数据会随“当前价格”变化而产生不同的历史序列;后复权价格保留了真实的分红配股累计关系,更适合用来结算收益率。

对月末策略这种低频调仓来说,持有期只有几个交易日,看起来复权影响不大,实际并非如此。如果标的在持有期中间发生大比例分红或转增,除权基准日前后价格会出现跳跃,前复权序列计算信号可能没问题,但用于结算买入卖出收益时,1%到3%的误差很容易就出来了。别小看这个误差,一个年化超额10%的策略被吃掉三五个点,性质就变了。

我的做法是双轨校验:信号计算用前复权序列,收益结算用后复权序列,两者算出来的月度收益如果偏差超过0.5%,就说明样本期内有重要除权事件,必须手工复核。这个过程很枯燥,但能避免很多根因不明的心虚。

2.2 “月末”在交易日历上有至少四种定义

“月末最后一天买入”这句话听起来很明确,落地到回测代码里就麻烦了——到底按自然日月末还是交易日月末?信号是在收盘前用还是收盘后用?跨越长假和非长假,窗口天数怎么算?这些细枝末节决定的是完全不同的回测结果。

我拿同一批标的、同一套成本参数,对四种月末定义做了对比。下面这组数字只用来展示分析方法,数据经过处理,不代表任何具体标的的收益表现,不必抠死数值本身。

月末定义买入方式年化超额收益(示意)胜率(示意)最大回撤(示意)
自然日最后一天跳到下一个交易日开盘7.8%54%14.2%
交易日最后一天当日收盘买入12.6%57%11.8%
最后3个交易日等权连续三日分批买入9.7%55%12.9%
最后5个交易日等权连续五日分批买入6.3%52%15.4%

单纯看数字,“交易日最后一天收盘买入”最漂亮,但这也是实盘最难复现的交易方式。尾盘资金拥挤、流动性收缩,你很难在收盘那一刻拿到理想的成交均价。我的建议是,先想明白实盘到底会怎么执行,再倒推回测里怎么设定成交时点。我最终选的是“最后三个交易日等权分批”,虽然收益指标不是最高,但执行上更接近真实,参数稳定性也更好。

2.3 交易成本、滑点和涨跌停,一个都不能略

很多策略死因不在选股逻辑,而在交易成本假设。回测里一个“收盘价买入”很轻松,实盘里光佣金、印花税、滑点就能把月度策略的摩擦成本抬高好几个百分点。第二轮回测我统一用了一套偏保守的参数:

成本项参数设置
佣金(双边合计)0.03%
印花税(仅卖出侧)0.05%
固定滑点(单边)0.05%
冲击成本估算按成交额额外计提0.02%
涨跌停无法成交买入遇涨停、卖出遇跌停,跳转到次日开盘执行

这套参数比很多回测框架的默认值保守,尤其是滑点单边0.05%。对小资金来说略有余量,但低频策略交易次数本来就不多,成本多计提一点,反而能过滤掉大量“纸上谈兵”的策略。

涨跌停规则也要尤其注意。月末调仓日经常是资金抢跑的时点,个别标的涨停一点不奇怪,回测里如果不处理“涨停买不进、跌停卖不出”的场景,收益里就会混入大量幻想成交。真实行情下,集合竞价排队可能排一整天才成交,跳转到次日开盘已经是乐观处理,资金量再大一点,连次日开盘都挤不进去。成本测算的原则只有一个:宁可保守到难受,也别乐观到做梦。

2.4 基准与无风险利率的选择决定了策略“真实超额”

评估月末策略不能只看绝对年化收益。这类策略天然持股时间短、空仓时间多,在牛市中非常容易跑出虚高的年化收益。我用了两个对齐方式:绝对收益基准采用沪深300全收益指数,超额收益用策略收益减去同期基准收益之后再统计。

无风险利率我直接取年化2%作为常数,夏普比率统一用周度收益口径计算,避免月度收益样本太少导致的方差失真。毕竟策略一年只有12次交易,直接按月收益算夏普,稳定性很差。更稳妥的方法是把策略周收益和基准周收益对齐,用信息比率去衡量超额质量。每一步数据处理都尽量贴近“可验证”原则,是我踩过坑以后才真正建立起来的习惯。

3. 第一轮回测结果与直觉的冲突:年化收益越高越可疑

3.1 收益来源归因:别把β当α

第一轮回测最醒目的一条曲线:样本期内年化收益超过25%,最大回撤不到8%,胜率接近六成。量化新手看到这张图大概率会觉得策略成了,我当时第一反应也是继续堆高收益。但把月度收益按时间摊开做归因之后,问题立刻浮出来:收益高度集中在少数月份,大约一半的正收益来自样本期里的十几个月份,其他月份贡献平平甚至亏钱。

更有意思的是,这些大涨月份和市场整体上行区间高度重合。换句话说,策略其实是在用“空仓躲大跌+持股跟大涨”的方式赚beta,并不是每个月末调仓本身产生了多少alpha。我把当月基准收益和策略收益做线性回归,看截距项是否显著为正,结果很扎心,第一版策略的截距在统计上离显著差得远。收益结构就是“带择时的指数暴露”,和日历效应没有本质关系。

3.2 参数敏感性检查:参数稍微一动,收益就断崖下跌

真正有效率的策略,收益水平应该在参数邻域内相对平滑,而不是只有一组参数点突然冒尖。我把调仓窗口从“最后1个交易日”逐步扩大到“最后5个交易日”,结合不同持有天数做网格测试。下面是示意数据,用来解释分析方法,不代表真实业绩。

调仓窗口持有天数年化收益(示意)夏普(示意)最大回撤(示意)
最后1个交易日3天18.2%1.1012.1%
最后2个交易日3天14.7%0.9613.2%
最后3个交易日3天11.5%0.8414.0%
最后4个交易日3天8.9%0.7215.3%
最后5个交易日3天6.6%0.5816.7%

收益随窗口拉长逐级递减,这个方向是对的,离月末越远效应越弱。但真正让我警惕的是落差太大,回测结论对参数极其敏感。敏感本身不一定是坏事,关键是你得问:这个参数实盘能稳定复现吗?交易总不能每次都掐着最后一秒钟下单去赚那个最高的年化数字,一旦资金拥挤、系统延迟,策略收益就可能掉到曲线另一端。

更严格的检验方法是滚动样本外测试。在每个时间点只用过去60个月的数据挑选参数,然后在随后的月份用选好的参数去交易,绝不掺入任何未来信息。逐期推进之后,如果样本外的表现依然稳定,才谈得上策略值得信任。第一版策略在这个测试里漏了馅,样本外收益比回测平均低一半以上。

3.3 按市场环境切分样本:牛市里的月末效应可能只是放大镜

接着我把样本期按市场状态切成三组:明显上行段、明显下行段、震荡段。结论非常清楚:策略超额收益在震荡段勉强为正,上行段的收益主要来自市场整体上涨,下行段不仅没有防御属性,反而因为集中持仓在月末拉高了回撤。

这说明月末效应在很多月份不是独立的赚钱机器,更像一个放大器。市场向上时,月末资金回流形成的脉冲让涨幅略高于平均水平,于是回测把这些增量统统记成策略收益;市场向下时,脉冲力度不足以扭转整体走势,策略照常亏损。这个认知一旦建立,我对月末策略的定位就自动降级了——它不是稳定产生alpha的独立策略,而是带有日历偏离的指数暴露工具。不是不能用,但别指望它单独扛起投资组合。

4. “再研究”重点纠错:未来函数、幸存者偏差与小样本陷阱

4.1 未来函数:我用十分钟就知道第一轮错在哪

所谓未来函数,就是回测过程中把未来才出现的数据偷渡到了历史决策点。第一版策略里有个筛选条件:根据月度结束后才公布的资金流向数据,去选择当月已经买入的标的。系统当然会选出事后看起来最正确的那一批,收益自然也惊人,但实盘里根本没有任何办法在月末收盘前知道月末收盘后的数据。

自查方法其实不复杂,把策略每一步都拆成“决策时点能看到的信息”和“决策时点之后才生成的信息”两张清单。凡是出现在第二张清单里的变量,一律不能进信号。我后来还写了个更粗暴的检查脚本:把每笔交易信号人为延后一到三天执行,观察策略换手后的收益变化。如果一个规则只能靠当天收盘瞬间的精确价格才能盈利,延迟到次日就完全失效,那它多半是过拟合了瞬时微观结构,而不是真正抓住了月末效应。

4.2 幸存者偏差:现在的存续标的骗了过去的收益

第二处隐患藏在标的池。第一轮研究我用的是今天依然存续的ETF和个股名单,然后直接把这份名单套回2010年做历史回测,问题随之而来:样本期内退市、清盘、合并的标的根本没进入回测,只有活到现在的“幸存者”参与了统计。这就像只看没辍学学生的期末成绩来评价教育体系,整体水平必然被高估。

我专门把两套池子做了对比:一套是“当前存续标的全历史回测”,另一套是按季度更新成分名单、及时剔除已退市标的的动态池子。同一策略在两套池子上的年化收益差距可以达到2到4个百分点,个别年份差距更大。应对方案是,回测必须使用“历史时点可得”的标的池,或者至少做动态滚动。对有退市风险的个股,我还会强制加上“退市即末日平仓”的处理规则,逼自己面对真实的终止风险和流动性风险。

4.3 小样本与统计显著性:120次交易撑不起一个暴富结论

统计检验这关最容易被忽略。月度调仓一年12笔,回测拉到十年也只有120笔交易。看起来够多,但月度收益的标准差通常比均值大一个数量级,这意味着120笔里只要有几笔异常大的收益,均值就会发生明显偏移。

我习惯用自助法来检验超额收益均值是否稳定为正。逻辑是把每笔月末策略的超额收益序列当作原始样本,有放回地随机重采样一万次,每次计算重采样样本的均值,最后看这些均值的95%置信区间是否包含0。参考代码是这样的:

import numpy as np excess_returns = np.array([...]) # 每笔月末策略相对基准的超额收益 rng = np.random.default_rng(42) boot_means = np.array([ rng.choice(excess_returns, size=len(excess_returns), replace=True).mean() for _ in range(10000) ]) ci_low, ci_high = np.percentile(boot_means, [2.5, 97.5]) t_stat = excess_returns.mean() / (excess_returns.std(ddof=1) / np.sqrt(len(excess_returns))) print(f"95% CI: [{ci_low:.4f}, {ci_high:.4f}]") print(f"t-statistic: {t_stat:.3f}")

第一版策略跑完这轮自助检验之后,置信区间把0包在里面,t值远低于2的常见显著性门槛。这个结果比任何收益曲线都说明问题:现象或许存在,但在现有样本量下根本无法证实它具有稳定可交易的价值。把样本拉到15年、20年,显著性当然会好看一些,但很多标的上市时间根本覆盖不了那么久,强行扩容只会引入更多幸存者偏差。所以我最后的判断是:这类策略适合当辅助配置,不适合作为核心alpha来源。

5. 从回测到实盘:资金管理、开仓时点与执行细节

5.1 尾盘集合竞价与提前建仓的时间窗口

回测里的“月末收盘价买入”很干净,实盘里想复制就难了。尾盘集合竞价是唯一能接近收盘价的批量成交窗口,但如果要在窗口期同时买入一批标的,委托量太大会抬高成交均价,量太小又可能吃不饱仓位。

我的操作习惯是把最终建仓日提前一到两个交易日,核心仓位在T-3到T-2日分批买入,少量机动仓在T日尾盘竞价补齐。这样即便T日因流动性缺失买不进,核心仓位已经在场,不会因为一天的资金拥挤错过整个月末脉冲。想明白一个逻辑就很容易接受这个妥协:回测好看往往是因为假设每一天都按收盘价成交,而实盘的首要任务是让成交尽量贴近决策逻辑,不是追求单日最优价格。

半年度末和年度末要格外小心,6月底和12月底是流动性和波动率同时放大的窗口,做市商报价价差变宽,冲击成本比平时翻一倍都有可能。如果策略容量大,建议直接把这几个特殊月份的调仓规模减半。

5.2 分批建仓还是集中调仓:实盘容量与交易成本

回测里另一个隐藏假设是“一次全部换仓”。小资金这样做没问题,资金量到了几百万以上,集中调仓对自身造成的冲击成本就不可忽略。低频策略交易次数本来就少,我倾向于把一次调仓拆成三日等权执行,或者采用“30%底仓+70%机动仓调整”的方式,保留纪律性的同时降低单日冲击。

执行方式变化之后,回测逻辑也要同步修改。三日等权分批建仓和一次性T日收盘买入相比,年化收益会低一点,但波动率和最大回撤通常更平滑。量化从来不是收益越高越好,而是要看“在可承受风险和真实交易成本之下,收益是否还有吸引力”。资金量不大的人完全可以用一次性调仓,但至少要在回测里把成本预算拉高一点,免得实盘被滑点打脸。

5.3 异常行情下的自动熔断与人工干预规则

实盘中最容易翻车的是极端行情。月末可能出现系统性大跌,回测规则还是会照常发出开仓信号,这时候机械执行等于在瀑布里接刀。我设置的熔断规则不复杂:主要宽基基准指数当日跌幅超过3%时,暂停当日新开仓;连续两个交易日累计跌幅超过5%时,本月整体调仓取消,资金保留到次月再行决定。

这类干预规则必须在回测里同步体现,绝不能在实盘里临时加上去。任何脱离历史验证的规则,都可能让“人工判断”变成情绪化交易的借口。我在第二轮回测里加入熔断之后,策略年化收益小幅下降,但最大回撤和尾部风险显著降低。我觉得这个取舍非常值得,因为做回测研究的最终目的不是追求一个永远无法复现的历史数值,而是找到一个在未知未来里至少不容易崩盘的策略结构。

5.4 边界感:月末策略适合放在组合的哪个位置

整个重做过程下来,我对月末策略的态度已经非常清晰:它不是一条独立致富的路径,而是一个低频率、可解释、容量适中的辅助型策略。它的优势在于交易透明度高,所有信号都建立在明确的日历和价格行为上,出了问题很容易追溯;劣势在于没有稳定且统计显著的独立alpha,收益和市场环境高度绑定,样本外表现需要长期跟踪验证。

如果组合里已经配置了趋势跟踪、事件驱动等其他类型的策略,可以考虑用月末策略承接一小部分资金轮动,或把它当作再平衡的“调节阀”,在月末做资产配置的边际调整。就我个人体会而言,回测研究最有价值的部分从来不是得到一条漂亮的净值曲线,而是通过反复证伪摸清策略的边界。知道自己赚的是什么钱、不赚什么钱,比知道某个参数组合的年化收益是多少重要得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询