Skip to content
All strategies

Strategies

行业ETF月度动量配置:截面优选、绝对动量过滤与月内止损

Outcome: Backtest Review

SectorEtfMonthlyAbsoluteMomentum

行业ETF月度动量配置:截面优选、绝对动量过滤与月内止损

Hypothesis

将原文行业配置机制改编为九只美国行业ETF的日线、无杠杆、只做多策略。采用21个交易日收益排序,每月选择前三名,仅持有同期绝对收益为正的标的,并设置月内收盘止损。不复制不可直接交易的中信行业指数,不声称复现原文收益。前三名、仓位预算和止损数值均为本次预注册的实现选择,原文摘录没有给出这些完整参数。

保留来源的截面动量、时序动量和止损三项核心机制。与已失败的美国行业ETF策略相比,本次不做空落后行业、不使用12-1月风险调整排名、不叠加债券,也不优化杠杆。只做多会加重现有方向集中,因此这是遵守来源机制的明确例外;多标的USEQ配置减少新增单币和Binance期货实验。corpus_concentration为空,不能声称这些ETF在近期语料中尚未使用。美国行业ETF上的机制仍可能无效,过去失败构成负面先验。

Implementation

Long-only, unlevered monthly sector rotation over nine US sector ETFs (XLB, XLE, XLF, XLI, XLK, XLP, XLU, XLV, XLY; daily USEQ bars). On the close of the last trading day of each month (platform session calendar, calendar-anchored, no bar counters) the nine are ranked by 21-session return; the target set is the top 3 whose own 21-session return is > 0 (absolute-momentum floor). Holdings outside the target are sold and new targets bought with market orders that fill at the next session open (platform next_open_fill). Intra-month, a holding whose daily close is stop_loss_pct (6% baseline, tunable 4-6%) below its anchor is sold at the next open and is only eligible again at the next month end. Anchor = entry fill price, or the month-end close at which a held ETF was retained for a new month. Sizing: whole shares, per-position fraction = min(0.20, 0.6/3, 0.012/stop_loss_pct) x leverage(1.0) = 20% of equity, max gross 60% (3 x 20%).

Replaces the previous code that raised in should_enter: next-session-open fills are now platform-supported (next_open_fill), so month-end close decisions are submitted as plain market orders and fill at the next open. Primary XLB uses the standard should_enter/should_exit path via scalar flags set in calculate_signal; the eight extra legs are traded with _submit_entry_instrument/_submit_exit_position. Signal = XLB's continuous 21-session return. Alignment: a leg only scores when its latest bar has the same close……Show moreShow less

Replaces the previous code that raised in should_enter: next-session-open fills are now platform-supported (next_open_fill), so month-end close decisions are submitted as plain market orders and fill at the next open. Primary XLB uses the standard should_enter/should_exit path via scalar flags set in calculate_signal; the eight extra legs are traded with _submit_entry_instrument/_submit_exit_position. Signal = XLB's continuous 21-session return. Alignment: a leg only scores when its latest bar has the same close stamp as the primary bar (barrier + explicit check), so no future bar is used. Rebalance requires all nine legs scored. Risk control route (a): 20% notional x 6% close stop = 1.2% of equity at the stop (risk_per_position_pct), plus month-end signal exits; worst case gap loss is bounded well inside the 15% max trade loss. State (per-leg stop anchors, last rebalance day) is plain scalar attributes. The fixed nine-ETF universe has existed continuously since 1998, so no point-in-time listing filter is needed. Interpretation note: the stop is re-anchored at a retained position's month-end close so a carried position's 'intra-month' stop measures that month's loss (otherwise a retained position below its old entry would be force-sold the next day). Sector momentum on US ETFs has a negative prior in our corpus.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['top_k', 'leverage', 'stop_loss_pct', 'rebalance_months', 'momentum_lookback', 'whole_shares_only', '_optimization_plan', 'max_gross_exposure', 'use_bracket_orders', 'risk_per_position_pct', 'baseline_stop_loss_pct', 'absolute_momentum_floor', 'reentry_only_at_month_end', 'execution_next_session_open', 'capital_fraction_per_position'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: RuntimeError:……Show moreShow less

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['top_k', 'leverage', 'stop_loss_pct', 'rebalance_months', 'momentum_lookback', 'whole_shares_only', '_optimization_plan', 'max_gross_exposure', 'use_bracket_orders', 'risk_per_position_pct', 'baseline_stop_loss_pct', 'absolute_momentum_floor', 'reentry_only_at_month_end', 'execution_next_session_open', 'capital_fraction_per_position'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000) - steady_downtrend: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000) - flat_ranging: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000) - volatility_spike: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000) - zero_volume: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000) - price_gap: RuntimeError: execution_contract_unsupported: monthly nine-ETF rotation requires month-end close decisions filled at the next session open. Installed NautilusTrader backtest/engine.pyx rejects AT_THE_OPEN orders; base market helpers execute at the current simulated price. Supply engine-level next-session-open execution before evaluating this strategy. Same-close or next-close execution is not authorized. (bar timestamp: 1735690860000)

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

Verification failed (Layer 3 — sandbox backtest): execution_contract_unsupported: the registered nine-ETF portfolio requires month-end close decisions executed at the next session open. The base template has no next-session-open portfolio execution hook. Engine support is required before this run can be evaluated. Bar type used: XLB.USEQ-1-DAY-LAST-EXTERNAL, Bars processed: 0 Ensure your strategy produces trades with the given data and parameters.

Analysis

顺势而为,行业趋势配置模型研究-中信证券-20200409 - BigQuant量化交易

Backtest Review

Sharpe
0.19
Total return
38.01%
Max drawdown
31.00%
Trades
607
Win rate
51.2%
Profit factor
1.16

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