Skip to content
All strategies

Strategies

美股行业ETF三年输家—赢家逆向组合

Outcome: Abandoned

UseqSectorLongHorizonContrarianBasket

Outcome Summary

UseqSectorLongHorizonContrarianBasket tested a three-year losers-minus-winners sector ETF basket with annual replacement. After eight iterations, the repaired lifecycle executed 20 consecutive annual baskets, but the backtest returned -15.4953% with Sharpe -0.1574 and negative average closed-position returns. Backtest review abandoned the tested specification before optimization, without rejecting long-horizon reversal generally.

Hypothesis

Derived by the Research Lead from 发明者量化-小小梦《量化交易「从均值回归看逆向投资」》:将多年输家随后超过多年赢家的观点,操作化为美国行业ETF的长期横截面逆向组合。采用USEQ日线,买入过去三年表现最差的两个行业ETF,同时卖空表现最好的两个,持有一年后平仓并重新排序。行业ETF、组合数量、一年持有期和保护性止损均为Research Lead的选择,不是原作者提供的交易规则。文章提到的三至五年形成期保留为优化范围;本实验不复现原论文的股票样本、盈利分析或三年持有结果。成交使用决策日收盘市价,不要求下一交易日开盘成交。仅使用拆股调整价格;平台不计股息,因此测试的是价格逆转,不是完整总回报策略。

这是源文章股票和行业长期逆转观点的直接价格操作化,不把多年逆向投资改写成分钟级RSI反弹,也不将股票研究换成资金费率机制。组合采用固定、明确的九个行业ETF,不依赖缺失的历史股票指数成员或市值数据,且只在全部ETF已存在并有足够历史后开始。它增加多标的、多空研究,针对当前单标的62.9%和仅做多80.7%的集中问题。corpus_concentration为空,无法声称这些ETF在近期实验中未被使用。选择USEQ而非为满足加密场所配额改变源机制;不使用下一交易日开盘订单、可选同柱止盈止损政策或独立对冲模式。长期持有导致样本较少,应将证据不足报告为低置信度,而非据此拒绝测试。

negative_expectancy: decline optimization of this Research Lead sector-ETF, three-year formation and one-year holding operationalization. After the lifecycle repair, annual baskets execute consistently, but measured closed-position economics remain negative and below the USEQ review floor. No verified implementation repair or measured profitable parameter region supports another developer iteration. This rejects the tested specification, not the source author's strategy or long-horizon reversal generally; alternative formation and holding periods remain untested.

Implementation

Ranks nine synchronized USEQ sector ETFs by 756-session split-adjusted price return; buys two losers and shorts two winners with equal within-side sizing, rotates on a fixed 252-session calendar grid, and applies 20% protective stops without refilling stopped legs.

Corrects the Layer 1.5 mismatch by explicitly configuring the primary and all eight extra instruments with 1-DAY bars and preserving the fixed bar_interval parameter. Existing ranking, execution, sizing and calendar logic are unchanged; only the source docstring now explicitly identifies the required interval. This feedback concerns configuration consistency and provides no evidence to abandon the hypothesis.

Verification Results

The sandbox closed two losing legs near their protective stops and retained two open positions. This truncated smoke test does not establish long-horizon profitability; full-history evaluation should assess reversal returns after spread, impact, and short borrow costs.

Backtest Review

Sharpe
-0.16
Total return
-15.50%
Max drawdown
29.45%
Trades
78
Win rate
42.3%
Profit factor
0.76

Annual replacement is restored: trade records show 20 consecutive annual baskets, each entering two long and two short legs. The previous skipped-year defect is no longer evident.

Code implements trailing-price loser/winner ranking and capital-relative sizing; initial leg notionals are approximately $12,500 each.

All nine input audits pass; accounting_valid and metrics_reliable are true.

Across 78 closed positions, average return is -1.9025% of notional versus the +0.05% USEQ review floor; profit factor is 0.763 and average P&L is -$243.73.

Total return is -15.4953%, despite +3.5685 percentage points of ending unrealized gains. Sharpe is -0.1574. QA's economic concern is borne out by the full-history result.

The 78 legs represent approximately 20 annual basket observations, not 78 independent portfolio bets. No optimization sweep establishes a profitable parameter region.

benchmark_meaningful is false; single-leg buy-and-hold comparisons do not determine this verdict.

Analysis

Do not optimize or retune parameters. Reproduce the 2005-01-10 boundary: the four 2004 legs close, but no replacement fills appear until 2006-01-10. Trace that boundary through cancel, close, open and confirm using the existing audit logs; compare submitted orders, fills, position updates and any engine entry suppression. Establish whether this report executed the supplied code version. Enforce that every eligible boundary either confirms exactly four freshly ranked replacement fills at the permitted decision……Show moreShow less

Do not optimize or retune parameters. Reproduce the 2005-01-10 boundary: the four 2004 legs close, but no replacement fills appear until 2006-01-10. Trace that boundary through cancel, close, open and confirm using the existing audit logs; compare submitted orders, fills, position updates and any engine entry suppression. Establish whether this report executed the supplied code version. Enforce that every eligible boundary either confirms exactly four freshly ranked replacement fills at the permitted decision close or raises an explicit execution failure; a successful run must not silently skip replacement. Validate consecutive annual boundaries, including reselected instruments, and produce a boundary-to-fill reconciliation before another full-history review. The existing callbacks and alerts have not demonstrated that repair, so identify the actual failing transition instead of repeating the previous callback advice. ## Library refinements (from the knowledge library; test them, do not assume them) Library order-management examples support verifying completion before advancing a rotation and distinguishing terminal orders from filled orders. Resolve the skipped 2005 replacement before interpreting performance or changing trading parameters. 1. [entry] Require a reconciled replacement basket at every annual boundary: Keep all trading parameters fixed. Reproduce 2005-01-10 and match the executed strategy artifact to the supplied version. Reconcile cancel, close, open and confirm transitions against submitted orders, fills, position updates and engine entry suppression; identify the first failed transition before repairing it. Every eligible boundary must confirm full equity-derived, whole-share replacement fills for exactly two freshly ranked long legs and two short legs at the permitted decision close, including reselected instruments. Advance completed-cycle state only after old positions close, replacement fills reconcile to new positions, and rotation orders are resolved. Retain rotation_poll_ns=1000000 and rotation_timeout_ns=1000000000. Missing, suppressed, rejected, partial or late replacement fills must raise an explicit execution failure. Validate consecutive annual boundaries and produce a boundary-to-fill reconciliation before another full-history review. — The analyst reports old legs closing in 2005 without replacements until 2006, so the reported Sharpe of 0.059 and profit factor of 1.068 do not yet reliably evaluate the intended strategy. The tutorial waits for order completion before proceeding. The advanced documentation explains that cancelled execution tasks stop accepting targets and demonstrates waiting for cancellation before creating a replacement task. The scenario reference checks remaining quantity even when an order is terminal. These support lifecycle and fill checks, but do not establish the actual NautilusTrader failure; this proposal specifies acceptance criteria rather than asserting a diagnosis or repeating callback advice. (source: t41.py p.1; TargetPosTask 高级功能 p.1; Scenario And Margin p.1)

Iteration History

Verification failed (Layer 1 — static analysis): - Banned import: src.data.market_calendar — strategies may only import the framework bases and helpers (src.strategies.base_template, src.strategies.rolling_options_template, src.strategies.polymarket_series_template, src.strategies.helpers); collectors, the database, the backtest engine and the registry are outside the sandbox. (line 11)

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] The truncated sandbox does not establish profitability. Full-history analysis should reconcile closed losses, remaining inventory, spread/impact and borrow costs; its reported 275.12% exposure also needs reconciliation against the configured 50% entry gross exposure. - [critical] open_pending_basket requires self.clock.timestamp_ns() == self.decision_ns. The base template explicitly distinguishes the simulated backtest clock from the……Show moreShow less

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] The truncated sandbox does not establish profitability. Full-history analysis should reconcile closed losses, remaining inventory, spread/impact and borrow costs; its reported 275.12% exposure also needs reconciliation against the configured 50% entry gross exposure. - [critical] open_pending_basket requires self.clock.timestamp_ns() == self.decision_ns. The base template explicitly distinguishes the simulated backtest clock from the wall clock used in paper/live. A synchronized daily bar processed even slightly after its close timestamp therefore raises rotation_execution_missed before submitting the selected entries. This makes the basket unable to execute in ordinary paper/live operation despite passing the sandbox. (line 179) — fix: Validate the decision against the synchronized bars' timestamps, and distinguish simulated execution time from paper/live delivery time. Use the platform's supported close-processing semantics and an explicit stale-decision policy without requiring exact wall-clock equality to the historical bar timestamp. - [warning] The strategy maintains its own exchange holidays and trading-session enumeration instead of using the platform calendar. Its timestamp-anchored schedule avoids process-counter drift, but duplicated calendar rules can diverge from the sessions used by collection and execution. (line 59) — fix: Build the anchored session ordinal using src.strategies.helpers.sessions.is_trading_day and session_date. Preserve the configured anchor and hold_bars cadence; do not import src.data directly.

Validate the decision against the synchronized bars' timestamps, and distinguish simulated execution time from paper/live delivery time. Use the platform's supported close-processing semantics and an explicit stale-decision policy without requiring exact wall-clock equality to the historical bar timestamp.

open_pending_basket requires self.clock.timestamp_ns() == self.decision_ns. The base template explicitly distinguishes the simulated backtest clock from the wall clock used in paper/live. A synchronized daily bar processed even slightly after its close timestamp therefore raises rotation_execution_missed before submitting the selected entries. This makes the basket unable to execute in ordinary paper/live operation despite passing the sandbox.

Build the anchored session ordinal using src.strategies.helpers.sessions.is_trading_day and session_date. Preserve the configured anchor and hold_bars cadence; do not import src.data directly.

The strategy maintains its own exchange holidays and trading-session enumeration instead of using the platform calendar. Its timestamp-anchored schedule avoids process-counter drift, but duplicated calendar rules can diverge from the sessions used by collection and execution.

Verification failed (Layer 4 — QA review) [class=code_defect]: - [edge_concern] The truncated sandbox does not establish profitability. Full-history analysis should assess price reversal after spread, impact and borrow costs; dividends are excluded. - [critical] Long and short rankings independently break ties by ascending instrument ID. With identical formation returns, both select XLB and XLE at basket_size=2. The overlap then calls rotation_failure(), permanently setting rotation_phase to 'failed'; subsequent signal evaluations raise again. Valid flat-price input therefore disables the strategy instead of resolving the stated deterministic ranking. (line 324) — fix: Resolve tied selections deterministically into disjoint baskets, retaining ascending instrument-ID priority within each side—for example, select losers first, then select winners from the remaining instruments. Verify a fully warmed, calendar-boundary case with identical returns.

Resolve tied selections deterministically into disjoint baskets, retaining ascending instrument-ID priority within each side—for example, select losers first, then select winners from the remaining instruments. Verify a fully warmed, calendar-boundary case with identical returns.

Long and short rankings independently break ties by ascending instrument ID. With identical formation returns, both select XLB and XLE at basket_size=2. The overlap then calls rotation_failure(), permanently setting rotation_phase to 'failed'; subsequent signal evaluations raise again. Valid flat-price input therefore disables the strategy instead of resolving the stated deterministic ranking.

Verification failed (Layer 1.5 — hypothesis/config consistency) [class=hypothesis_mismatch]: - optimization_plan fixes bar_interval at 1-DAY

Outcome Summary

Restoring consistent annual execution did not establish an economic edge for the tested specification; alternative formation and holding periods remain untested.

Backtest review issued an abandon verdict because expectancy remained negative after the annual basket lifecycle was repaired, falling below the +0.05% USEQ review floor. Optimization and subsequent analyst and risk reviews were not reached.

Buy the two worst-performing US sector ETFs over three years and short the two best performers, replacing the basket annually to test long-horizon price reversal without dividends.

The backtest returned -15.4953%, with Sharpe -0.1574, maximum drawdown 29.4461%, and 78 closed positions across approximately 20 annual baskets. Average closed-position return was -1.9025% of notional and profit factor was 0.763.

Analysis

量化交易「从均值回归看逆向投资」

Backtest and paper results are hypothetical. Trading involves risk of loss.