ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

月末策略回测复盘:从漂亮曲线到真实边界的量化研究记录

月末策略回测复盘:从漂亮曲线到真实边界的量化研究记录 先交代一下背景我前前后后研究了两三个月的“月末策略标的”第一版回测曲线漂亮到让人差点直接上实盘——年化收益、最大回撤、胜率每一项都拿得出手。真正开始动手“再研究”之后才一层层发现自己踩了多少坑复权口径对不上、月末的定义太模糊、标的池自带幸存者偏差、几十次交易算出来的胜率根本不显著更别说交易成本把超额收益吃掉大半。这篇文章就是我把整个回测过程重新做一遍的完整记录重点放在怎么拆解策略假设、怎么搭数据基建、怎么识别收益来源以及最终哪些结论可以扛过实战检验。如果你也对日历效应、低频调仓这类策略感兴趣或者正被某条漂亮的净值曲线冲昏头脑这篇应该能帮你省掉不少冤枉时间。先说清楚这整篇只是我自己研究过程的复盘和思考不构成投资建议。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, sizelen(excess_returns), replaceTrue).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(ddof1) / np.sqrt(len(excess_returns))) print(f95% CI: [{ci_low:.4f}, {ci_high:.4f}]) print(ft-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收益和市场环境高度绑定样本外表现需要长期跟踪验证。如果组合里已经配置了趋势跟踪、事件驱动等其他类型的策略可以考虑用月末策略承接一小部分资金轮动或把它当作再平衡的“调节阀”在月末做资产配置的边际调整。就我个人体会而言回测研究最有价值的部分从来不是得到一条漂亮的净值曲线而是通过反复证伪摸清策略的边界。知道自己赚的是什么钱、不赚什么钱比知道某个参数组合的年化收益是多少重要得多。
返回列表