跳至正文
全部策略

策略

SPY 市场强弱条件下的半月日历策略

结局: 已放弃

SpyStrengthConditionedHalfMonthCalendar

结局总结

该策略检验了中国指数规则(由市场强弱决定的半月日历效应)在 SPY 上是否有效。历经 30 年、252 笔交易,收益为 +19.6%,夏普比率为 0.15,收益来自约 25% 名义本金的多头敞口。空头部分甚至在计入成本前就亏损。经过 3 次迭代后,分析师放弃了该策略:信号不含信息(IC 0.013,t=0.24),阿尔法为负,回撤达到 23.0%,超过 15% 限额,且滚动前向测试未通过。此结论仅针对将该规则迁移至 SPY 日线数据,不涉及原始中国指数结果。

假设

受来源启发,对国信证券发表于 BigQuant 宽邦的市场强弱条件月初效应进行改编。使用 SPY.USEQ 的 1-DAY 日线:强势市场保持多头;较弱市场则在日历日 15 之前做多,从日历日 15 起做空。原报告研究的是中国指数。本实验检验该效应能否迁移至流动性较高的 US 指数 ETF;它并未复现该报告,也不采用其声称的收益。由于无法核实完整的 PDF 的 RPS 定义,因此采用下文明确登记的因果代理指标。

保留来源中的指数日历机制,而不是臆造加密货币季节性优势。USEQ 提供数十年的日线历史数据,且执行成本低。多空敞口针对投资组合 82.6% 只做多的集中问题,也避免再增加一个 Binance 实验。来源的指数择时设计足以支持单一标的范围。corpus_concentration 为空,因此无法确认标的特定的新颖性。该策略通过按日历条件决定持有规则,与失败的 SPY 单时段超调反转策略及行业动量轮动不同。期权和 Hyperliquid 数据不足,不足以支持将股票日历机制迁移至不适合的工具。

premise_falsified(no_edge)。三十年的 SPY 数据表明,这一日历规则没有价值。其阿尔法为负,相对于 SPY 的信息比率为 -0.47,信号 IC 为 0.013(t=0.24)。问题不在费用:每笔交易 0.291%,而底线为 0.05%。该策略突破了自身的 15% 回撤限额(23.0%),滚动前向测试也因候选覆盖不足而否决了它。没有可调参数,迭代无法改变结果。此前的 SPY 和 QQQ 日历策略(期权到期周期、养老金月末、QQQ 月初月末效应)也已放弃。本结论仅针对将国信证券月初效应迁移至 SPY 日线数据,不检验原始中国指数结果。研究应停止在 US 大盘指数上提出半月日历策略。

实现

在日线上交易 SPY.USEQ。市场强度是 SPY 的 252 日价格排名的 10 日均值。当强度达到 0.6 或更高时,策略持有多头。低于 0.6 时,在当月 15 日之前的交易时段做多,从 15 日起做空;依据下一交易时段的日历日期。每次决策都在交易时段收盘时作出,并于下一交易时段开盘执行。为此,策略在决策收盘价上下各一个最小变动单位放置一组关联的二选一取消订单:一个 STOP_MARKET 和一个 MARKET_IF_TOUCHED,方向均与交易方向一致。一秒计时器让交易场所在撮合下一根 K 线之前接受这组订单。若开盘价跳空越过其中一个价位,该订单作为市价单以开盘价成交,另一订单则取消。方向反转时,使用一笔净额订单,规模等于现有持仓加上新持仓。如果收盘时持仓出现 4% 亏损,则在下一开盘平仓。只有目标方向改变后才会重新入场。仓位规模取以下两者中的较小值:权益的 25%,以及以 1x 倍杠杆计算的 4% 止损(占权益 25%)对应的 1% 风险金额。

迭代 2 故意在 __init__ 中触发错误,因为撮合引擎会拒绝 AT_THE_OPEN 订单。该错误就是 Layer-2 失败的全部原因。此版本使用标准订单类型执行固定的 next_session_open 规则。我检查了引擎源码。USEQ 的订单延迟为 100 毫秒,且引擎只会在下一根 K 线撮合后处理在途订单。因此,收盘时发送的普通市价单会在下一个 CLOSE 成交,而非下一开盘价成交。延迟后触发的计时器可让交易场所于决策时接受已挂出的配对订单,因此引擎先处理下一根 K 线开盘价时,该订单对已生效。对 2015-2017 进行本地 SPY 运行,拒单数为零。核对过的成交与下一根 K 线开盘价精确到最小报价单位匹配,少数成交于触发价而非开盘价。包含两项决策修正。(1)日历日现按交易执行所在时段的日期计算(收盘后的下一个工作日),因此“从第 15 天起做空”适用于从第 15 天起的交易时段。未对交易所假期建模,因为 market_calendar 不在导入允许列表中。(2)一处实际错误:get_position_pnl_pct 返回 PERCENT,所以旧止损在 -0.04% 触发,而非 -4%。现在改为与 stop_loss_pct*100 比较。每个计划参数均保留其固定值和含义,未添加可调参数。Layer 1 和 Layer 2 在本地通过。Layer 2 在两个稳定趋势合成情景中将信号标记为冻结,这符合基于排名的强度评分预期;该警告不会导致层级测试失败。

验证结果

目前可接受。如果导入许可列表将来包含 src.data.market_calendar,请使用其下一交易时段函数。

_next_session_day 将下一个 WEEKDAY 作为执行时段,并忽略交易所假日。只有在假日导致下一交易时段跨越日-15边界时才会出错。例如:若耶稣受难日在 14 日,代码会算出日14(做多),但实际执行在周一,即日17(应做空)。这种情况很少见,开发者也已记录,因为 market_calendar 不在导入许可列表中。

可选:在完整回测中记录与 K 线开盘价不同的成交数量。如果数量较多,就进一步拉开触发价(例如 ±0.5 bp),这样即使开盘价等于收盘价,订单仍会在后一根 K 线开盘时触发。

下一开盘执行使用一组 OCO STOP_MARKET/MIT 挂单,分别位于决策收盘价上下一个最小变动单位。如果下一开盘价与决策收盘价完全相同(在 SPY 上相差不超过一美分),两边挂单在开盘时都不会触发。随后其中一边会在盘中触发,并以触发价成交,即决策收盘价 ±1 个最小变动单位,而非开盘价。开发者自己的运行记录中有少量成交发生在触发价。这会在少数交易日造成少量、对称地按收盘价成交。这不是方向性前视。

无需采取行动。也可以在取消事件中重新发出订单。

_cancel_stale_orders 发出取消请求后,_process_primary 会在同一根 K 线上运行。取消请求需经过交易场所的延迟,因此缓存仍显示已取消订单处于未平仓状态。基类在空仓时会因“order_in_flight”提前返回,或者 should_exit 返回 False,因此重新发出的决策又延迟一个交易时段。只有在完整交易时段内 SPY 与前一收盘价的偏差始终不超过一个最小变动单位时才会发生,这种情况实际上几乎不会出现。

在 should_exit 中保留未平仓订单防护。如果以后添加括号订单,请恢复平仓前先取消订单的步骤。

_submit_exit 覆盖了基类实现,并在平仓前移除了其 _close_pending 防护及 cancel_all_orders。在此处这样做是安全的:只要该标的仍有未完成订单,should_exit 就会返回 False,因此平仓订单不会叠加,也没有需要取消的保护性订单。

沙盒:夏普比率 0.18,PF 1.06,46 笔已平仓交易,贝塔 0.13。亏损出现在压力波动率三分位组(-6.1%)、rate_shock_2022 和 covid_2020。半月规则源自中国指数研究。该规则向 SPY 的迁移尚未得到证实;在疲弱的 US 市场中,月后半段做空可能只是在做空反弹。每年约有 8 次完整买卖,完整的 1993+ 历史数据大约能提供 250 笔交易,因此完整回测可以对其进行衡量。首先检查弱势状态下的空头部分(做空胜率 0.35)是否具有正的毛期望收益。如果没有,说明只有只做多的强势过滤器在发挥作用。

回测评审

夏普
0.15
总收益率
19.56%
最大回撤
23.02%
总交易数
252
胜率
40.5%
盈利因子
1.12

样本可靠:从 1994 到 2024 共平仓交易 253 笔(127 笔多头,126 笔空头),账目清晰且无数据缺口。

avg_trade_return_pct 为 0.29%,高于 USEQ 的 0.05% 底线。PF 为 1.12,夏普比率为正值 0.15。

执行具有因果性:订单在下一交易时段开盘成交,从不在决策收盘时成交。

核心假设对应的部分亏损。126 笔 SHORT 交易(弱势状态、月后半段)合计净亏损 -$23,746。借贷成本仅约 $621,所以该部分在计入成本前也已亏损。127 笔 LONG 交易合计盈利 +$39,843。QA 的担忧得到证实:在疲弱的 US 市场中,半月做空大多是在做空反弹。

最终保留的是名义规模约为 25% 的 SPY 多头。贝塔为 0.12,阿尔法为 -0.0027,信息比率为 -0.47,因此该策略相对于其基准敞口没有增加超额收益。总回报为 +19.6%,周期为 30 年。

信号-IC 诊断否决了该预测:IC 0.013,t=0.24,结论为“rejected_no_information”。夏普比率 95% CI 的区间为 [-0.20, 0.51]。

策略从 2016-06-28 到 2018-10-25 一直空仓。多头触发止损后,登记规则“reentry_after_stop = next_target_direction_change”随即在强势状态持续期间阻止做多达 28 个月,因此错过了 2016-18 的上涨行情。这与“强势市场保持多头”相矛盾。

最大回撤为 23.0%,超过预先登记的 15%。压力波动率三分位组亏损(-7.1%,夏普比率 -0.08)。

优化计划的可调参数集为空(操作为“冻结”),因此优化无法改变结果。

分析

账目处理无误:订单在下一交易时段开盘时成交,没有前视,样本包含 30 年的 SPY 数据和 252 笔已平仓交易。

问题不在费用:平均单笔交易回报为 0.291%,约为 0.05% USEQ 底线的 5.8 倍。市场冲击占毛收益的 11.8%。

没有跑赢买入并持有:30 年总回报为 +19.6%,夏普比率 0.15(95% 区间 -0.20 至 0.51),盈利因子 1.12,年化阿尔法 -0.27%,相对于 SPY 买入并持有的主动比率为 -0.47。

该信号不含信息:与远期收益的相关性(IC)为 0.013,t=0.24。

最大回撤为 23.0%,超过预先登记的 15% 风险限额。该限额不可豁免,且回撤尚未恢复(约 9,300 天)。

滚动检验因候选覆盖不足而否决该策略:59 个窗口中仅有 36 个找到可接受的候选,最新窗口没有候选。从第 2009 个窗口起,唯一的固定规则在每个窗口都突破了 15% 的回撤上限。策略没有可调参数。

结果不一致:16/30 年为正(53%,低于 60% 底线),仅 1997 就贡献了 40% 的利润,且策略在高波动率三分位组中亏损(夏普比率 -0.08)。样本内夏普比率随时间从约 1.4 降至约 0.2。

代码缺陷,已记录,但并非本次结论的原因:策略从 2016-06 到 2018-10 一直空仓。止损阻止了重新入场,而市场强度目标仍为多头。

迭代历史

验证失败(第 1.5 层——假设/配置一致性)[类别=hypothesis_mismatch]: - optimization_plan 将杠杆固定为 1.0

验证失败(第 2 层——合成情景): 使用的参数:['leverage', 'risk_pct', 'stop_loss_pct', 'capital_fraction', 'execution_policy', '_optimization_plan', 'reentry_after_stop', 'strength_threshold', 'calendar_switch_day', 'price_rank_lookback', 'strength_smoothing_bars'] 检查 __init__ 是否通过 self.parameters.get() 设置了所有属性。 - steady_uptrend:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 -……展开收起

验证失败(第 2 层——合成情景): 使用的参数:['leverage', 'risk_pct', 'stop_loss_pct', 'capital_fraction', 'execution_policy', '_optimization_plan', 'reentry_after_stop', 'strength_threshold', 'calendar_switch_day', 'price_rank_lookback', 'strength_smoothing_bars'] 检查 __init__ 是否通过 self.parameters.get() 设置了所有属性。 - steady_uptrend:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 - steady_downtrend:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 - flat_ranging:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 - volatility_spike:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 - zero_volume:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。 - price_gap:设置错误:RuntimeError:execution_policy_unsupported:next_session_open 需要运行器级别的交易时段开盘价格事件和排队的目标执行;已安装的撮合引擎拒绝 AT_THE_OPEN。请勿使用同收盘价市价成交来评估此假设。

结局总结

在弱势 US 市场中,月后半段做空 SPY 多数是在做空反弹。对 US 个大盘指数使用半月日历规则未显示出优势,与此前放弃的 SPY/QQQ 日历策略一致,因此研究应停止提出这类策略。

回测复核将其送去优化。随后分析师将其作为 premise_falsified(no_edge)放弃。信号 IC 为 0.013(t=0.24),相较于 SPY 没有阿尔法,且回撤突破了预先登记的 15% 限额。滚动前向测试因候选覆盖不足而否决该策略(36/59 个窗口);由于没有可调参数,迭代无法改变结果。

该策略检验了国信证券发表于中国指数研究中的市场强弱条件月初效应,能否迁移至 SPY 日线数据。当平滑的 252 日价格排名强度代理指标大于或等于 0.6 时,策略保持多头;否则在日历日 15 之前做多,从日历日 15 起做空。

在 1994-2024 期间,总回报为 +19.6%,夏普比率为 0.15(95% CI -0.20 至 0.51),共计 252 笔已平仓交易。每笔交易平均回报为 0.291%,盈利因子为 1.12,阿尔法为 -0.0027,信息比率为 -0.47,最大回撤为 23.0%。126 笔空头交易净亏损约 $23.7k,多头交易盈利约 $39.8k。

分析

基于市场强弱的月初效应指数投资方法 国信证券_20180813_ - BigQuant量化交易

Stratmill 是研究与模拟交易工具,不提供财务建议,也不是经纪商。回测与模拟结果均为假设性结果。交易存在亏损风险。