跳至正文
全部策略

策略

跳月形成期动量:做多做空US只行业ETF

结局: 已放弃

SkippedMonthSectorMomentum

结局总结

SkippedMonthSectorMomentum测试了跳月形成期动量能否用八只US行业ETF预测接下来21个交易时段的表现,采用做多前-2名、做空后-2名的组合。经过3次迭代,代码始终未通过第4层QA审查。轮动逻辑在旧组合平仓仍在途时为新腿定仓,并依赖精确时间戳重新入场,因此各期组合不完整且不平衡。唯一一次沙盒测量(夏普比率-0.02,PF 0.98,178个仓位中每个仓位-0.125%)被判定不能代表该假设。运行在回测审查、优化、分析师或风险阶段之前就已放弃。

假设

检验行业赢家在多月形成期后的表现是否优于输家,并观察接下来21个交易时段。使用八只流动性强的US行业ETF和同步日线K线,买入排名最高的两个行业,做空排名最低的两个行业。形成期收益剔除最近21个交易时段,以区分中期延续与即时反转。这是对原始股票十分位研究的改编,并非复现。评估之后可执行的收益,切勿使用来源中展示的形成期平均值。

源代码包含明确的截面动量机制。原代码错误地对单个对数收益率取指数,而非对滚动总和取指数;排序则必须在每个日期分别进行。保留这些修正后的机制,并测试跳过一个月的行业层面版本。仅做多敞口是规模为83.2%的最大组合失衡;本方案增加多空和多标的敞口。Hyperliquid配置不足,但该平台已有相对强弱轮动策略。期权方案反复出现结构性失败。按形成期收益对行业排序,不同于以52周高点为锚的方案,也不同于日历入场失败。再平衡是一种操作安排,并非声称存在日历异常。语料库集中度数据不可用,因此无法断言此前对这些特定标的的使用较少。

verification_loop:验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget -……展开收起

verification_loop:验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget - gross`约为0。这会导致名义金额0(位CLEARED,因此该仓位在整个21个交易日周期内被丢弃),或只留下少量残余仓位(规模不足)。(b) 原先持有且再次入选的标的:其位标记会保留(`continue`),并计划从on_position_closed重新入场。但平仓单在rotation_ts + 100毫秒后才成交,因此`self.clock.timestamp_ns() != self._rotation_ts`提前返回,且下一次轮换前没有任何地方调用 _open_pending()。这些标的整个周期都保持空仓。结果是:首次轮换后,组合在完整、部分和空仓状态之间交替,多空两侧金额也不平衡。沙盒结果印证了这一点。预计约有65次轮换 × 4个仓位 ≈ 260个头寸,但实际记录了178个,且avg_position_pct为13.7%,而目标是15%。实际交易的并非该假设所述的每21个交易日做多前-2名、做空后-2名。(第168行)——修复方法:使用持久化的轮换状态,而非精确时间戳匹配。待处理位标记保留至下一次轮换。计算`gross`时,排除已有仅减仓平仓单待成交的头寸(这些头寸将被替换)。每一侧的仓位规模按 _rotation_equity * leg_equity_fraction 计算。在on_position_closed中,以及每根主 K 线开始时作为后备处理,只要仍有位标记且上一组合的平仓单已全部成交,就调用 _open_pending()。移除`clock == _rotation_ts`保护条件,或将其替换为“同一轮换周期”。仅在订单确已提交后,或仓位规模 - [警告] 投资组合的回撤暂停条件(15%)会在本次运行剩余时间内永久生效,且不会重新启用。在25年回测中,一次回撤就可能彻底终止交易,从而缩小样本。这符合原描述,因此仅作为警告;但分析师应了解暂停条件是否触发。(第133行)——修复方法:记录暂停日期。如果假设允许,可考虑在权益恢复后于下一次轮换重新启用,或设置按交易日计算的冷却期。 - [警告] 超出所提供的XNYS休市日期表的日期,会回退为按工作日计数。该回退方式使用了不同的交易日编号,因此轮换阶段会在表格边界处跳变(1998之前/2030之后)。这不会影响沙盒或回测窗口。(第117行)——修复方法:目前可以接受。扩展日期表,或在可导入时使用 src/data/market_calendar,以保持阶段连续。

实现

使用8只SPDR行业ETF的日线USEQK线实施行业动量策略。按形成期收益对每只ETF排序:计算端点价格比,区间为formation_sessions,剔除最近21个交易时段。每隔21个XNYS交易时段,按日历网格对齐,策略平掉所有仓位,买入排名前2的ETF,并做空排名后2的ETF。每条腿占权益的15%(总敞口为60%)。每条腿在交易场所设有12%止损;组合回撤达到15%时停止交易。

第3次迭代修复了第2层故障。合成测试 K 线的时间戳不在所提供的XNYS休市日期表中,策略因此引发 ValueError。现在,表格之外的日期会映射为从工作日计数得到的交易日编号。该编号仅取决于 K 线时间戳,因此重启、回测和模拟交易的结果仍一致。表格内的日期继续使用精确的XNYS交易日网格。其他内容没有变化。

验证结果

验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget -……展开收起

验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget - gross`约为0。这会导致名义金额0(位CLEARED,因此该仓位在整个21个交易日周期内被丢弃),或只留下少量残余仓位(规模不足)。(b) 原先持有且再次入选的标的:其位标记会保留(`continue`),并计划从on_position_closed重新入场。但平仓单在rotation_ts + 100毫秒后才成交,因此`self.clock.timestamp_ns() != self._rotation_ts`提前返回,且下一次轮换前没有任何地方调用 _open_pending()。这些标的整个周期都保持空仓。结果是:首次轮换后,组合在完整、部分和空仓状态之间交替,多空两侧金额也不平衡。沙盒结果印证了这一点。预计约有65次轮换 × 4个仓位 ≈ 260个头寸,但实际记录了178个,且avg_position_pct为13.7%,而目标是15%。实际交易的并非该假设所述的每21个交易日做多前-2名、做空后-2名。(第168行)——修复方法:使用持久化的轮换状态,而非精确时间戳匹配。待处理位标记保留至下一次轮换。计算`gross`时,排除已有仅减仓平仓单待成交的头寸(这些头寸将被替换)。每一侧的仓位规模按 _rotation_equity * leg_equity_fraction 计算。在on_position_closed中,以及每根主 K 线开始时作为后备处理,只要仍有位标记且上一组合的平仓单已全部成交,就调用 _open_pending()。移除`clock == _rotation_ts`保护条件,或将其替换为“同一轮换周期”。仅在订单确已提交后,或仓位规模 - [警告] 投资组合的回撤暂停条件(15%)会在本次运行剩余时间内永久生效,且不会重新启用。在25年回测中,一次回撤就可能彻底终止交易,从而缩小样本。这符合原描述,因此仅作为警告;但分析师应了解暂停条件是否触发。(第133行)——修复方法:记录暂停日期。如果假设允许,可考虑在权益恢复后于下一次轮换重新启用,或设置按交易日计算的冷却期。 - [警告] 超出所提供的XNYS休市日期表的日期,会回退为按工作日计数。该回退方式使用了不同的交易日编号,因此轮换阶段会在表格边界处跳变(1998之前/2030之后)。这不会影响沙盒或回测窗口。(第117行)——修复方法:目前可以接受。扩展日期表,或在可导入时使用 src/data/market_calendar,以保持阶段连续。

迭代历史

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

验证失败(第2层——合成情景): 使用的参数:['leverage', 'min_notional', 'skip_sessions', 'stop_loss_pct', '_optimization_plan', 'formation_sessions', 'max_gross_exposure', 'rebalance_sessions', 'leg_equity_fraction', 'xnys_closure_offsets', 'selection_count_per_side', 'portfolio_drawdown_stop_pct'] 检查 __init__ 是否设置了 self.parameters.get() 返回的所有属性。 - steady_uptrend: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000) - steady_downtrend: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000) - flat_ranging: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000) - volatility_spike: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000) - zero_volume: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000) - price_gap: ValueError: 交易时段不在提供的XNYS日历范围内;请刷新日历元数据(K线时间戳:1735705980000)

结局总结

在事件驱动的多腿轮动中,应跨K线保留轮动状态,并按轮动权益为新腿定仓,同时排除平仓在途的仓位;不要假设平仓会在提交时的同一时间戳成交。

经过3次迭代后,由于第4层QA审查发现严重代码缺陷,该运行在验证循环中被放弃。轮动未能重建2个多头/2个空头的组合:计算新仓位腿规模并检查精确时间戳重新入场条件时,平仓仍在100毫秒USEQ延迟期间等待成交。因此,部分仓位被遗漏或规模不足(记录了178个仓位,预期约260个;平均仓位为13.7%,目标为15%),且组合的多空美元金额未能平衡。

从八只US行业ETF中,做多形成期多月收益最强的两只,做空最弱的两只;跳过最近21个交易时段,并每隔21个交易时段再平衡,以捕捉中期行业动量,同时与短期反转区分开来。

未记录完整回测或优化。唯一的表现证据是QA未优化的沙盒冒烟测试(形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%。QA指出,由于各组仓位不完整且规模不足,该测试未能检验这一假设。

放弃原因

verification_loop:验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget -……展开收起

verification_loop:验证失败(第4层 — QA审查)[类别=code_defect]: - [edge_concern] 冒烟测试(未优化,形成期=126):平仓178个头寸,PF 0.98,夏普比率-0.02,每个头寸-0.125%;计入借贷成本后,优势接近于零。以下缺陷意味着该测试没有按规定检验假设,因为各组仓位不完整且规模不足。修复后应重新测量,再解读结果。运行时间也很长:8个标的的1,653根日线耗时249秒,预计完整历史数据约需949秒。对于每根 K 线执行 O(8) 循环来说,这个速度出乎意料地慢,应进行性能分析。 - [严重] 轮换时未重建2个多头/2个空头的组合。在calculate_signal中,先为旧多空头寸提交close_position,随后立即调用 _open_pending()。回测中的 SimulatedExchange 会将指令排队(use_message_queue),而USEQ设为latency_ms=100,因此这些平仓单都尚未成交。(a) 新选入的标的:`gross`仍包括全部旧组合(约占权益的0.6 x),因此`budget - gross`约为0。这会导致名义金额0(位CLEARED,因此该仓位在整个21个交易日周期内被丢弃),或只留下少量残余仓位(规模不足)。(b) 原先持有且再次入选的标的:其位标记会保留(`continue`),并计划从on_position_closed重新入场。但平仓单在rotation_ts + 100毫秒后才成交,因此`self.clock.timestamp_ns() != self._rotation_ts`提前返回,且下一次轮换前没有任何地方调用 _open_pending()。这些标的整个周期都保持空仓。结果是:首次轮换后,组合在完整、部分和空仓状态之间交替,多空两侧金额也不平衡。沙盒结果印证了这一点。预计约有65次轮换 × 4个仓位 ≈ 260个头寸,但实际记录了178个,且avg_position_pct为13.7%,而目标是15%。实际交易的并非该假设所述的每21个交易日做多前-2名、做空后-2名。(第168行)——修复方法:使用持久化的轮换状态,而非精确时间戳匹配。待处理位标记保留至下一次轮换。计算`gross`时,排除已有仅减仓平仓单待成交的头寸(这些头寸将被替换)。每一侧的仓位规模按 _rotation_equity * leg_equity_fraction 计算。在on_position_closed中,以及每根主 K 线开始时作为后备处理,只要仍有位标记且上一组合的平仓单已全部成交,就调用 _open_pending()。移除`clock == _rotation_ts`保护条件,或将其替换为“同一轮换周期”。仅在订单确已提交后,或仓位规模 - [警告] 投资组合的回撤暂停条件(15%)会在本次运行剩余时间内永久生效,且不会重新启用。在25年回测中,一次回撤就可能彻底终止交易,从而缩小样本。这符合原描述,因此仅作为警告;但分析师应了解暂停条件是否触发。(第133行)——修复方法:记录暂停日期。如果假设允许,可考虑在权益恢复后于下一次轮换重新启用,或设置按交易日计算的冷却期。 - [警告] 超出所提供的XNYS休市日期表的日期,会回退为按工作日计数。该回退方式使用了不同的交易日编号,因此轮换阶段会在表格边界处跳变(1998之前/2030之后)。这不会影响沙盒或回测窗口。(第117行)——修复方法:目前可以接受。扩展日期表,或在可导入时使用 src/data/market_calendar,以保持阶段连续。

分析

策略回测:复制动量策略形成期 | Stratmill

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