Strategies
SuperMind 反包 Screen on A-Share Large Caps: Close Re-Crosses Above MA20 While MA20 > MA120 Within 10 Sessions of a Five-MA Squeeze (32 pre-2016 CNEQ large caps, 1-DAY, long-only, next-open fills, 15-session clock + 8% stop)
Outcome: Abandoned
SuperMindFanbaoMaSqueezeCneqPanel
Outcome Summary
The Research Lead turned a SuperMind A-share 反包 screen (an MA20 re-cross in an MA20 > MA120 uptrend after a five-MA squeeze) into a long-only test on 32 CNEQ large caps with standard exits and sizing. After a sizing fix in iteration 1, the backtest review sent it to optimization despite a thin edge and a large shortfall against the equal-weight basket. Optimization lifted per-trade returns to 0.62% with a 10.2% drawdown, but walk-forward OOS Sharpe was only 0.20, results swung across windows and years, and the strategy was positive in just 4 of 9 calendar years. The analyst abandoned it after 2 iterations on that hard year-consistency failure, and it never reached risk review or paper trading.
Hypothesis
Implementation
Unchanged 32-stock CNEQ daily MA re-cross/squeeze panel with next-open entries, 15-session/regime exits and 8% protective stops. Entry caps now use each stock’s own bar and quantities are rounded down to 100-share lots after capping.
Sizing-only implementation fix: the previous call supplied the expensive primary stock’s bar to every leg. _affordable_size uses max(supplied bar close, cached leg prices), incorrectly applying that primary price to cheaper names and creating similarly small odd-lot quantities. No candidate-count division appears in the cap; get_equity_mtm remains unchanged. Log equity, raw shares, cash-capped shares, margin-capped shares, final board lots and entry_diag per entry. All rules and previous_config values are preserved. No rerun was performed: average entry exposure, peak gross exposure and the equal-weight 32-name buy-and-hold comparison over the identical development window remain for the pipeline rerun; no benchmark result is claimed.
Verification Results
Optionally delay arming the stop until the first session close after the fill, so the stop is live from the following open. For example, place it in calculate_signal once _sessions_since(buf, pos.ts_opened) >= 1.
on_position_opened places the 8% reduce-only STOP_MARKET as soon as the next-open entry fills. If the engine matches that stop against the rest of the entry session's bar, the stop can close the position on the day it was bought. A-share T+1 forbids that, and the hypothesis says T+1 is respected by construction and that the stop rests from the next open. The trigger is 8% below the fill, so the stop is never crossed when placed. This only matters on an intraday drop of 8% or more on the entry day, and the ±10% price limit makes that rare.
No change required. Keep emulation_trigger unset.
The hypothesis names submit_stop_order. That helper only handles the primary instrument, so the code uses a raw order_factory.stop_market on each leg. That is an acceptable equivalent: the stop is reduce-only, uses GTC, has no emulation_trigger, is not crossed at placement, and is cancelled in on_position_closed. Whether a session that opens through the trigger fills at the open depends on the engine's session-stop setting (SF_SESSION_STOP_FILLS), not on this code.
Optional: no change needed for correctness.
When one name exits and another enters on the same close, the new entry is capped by cash before the exit proceeds settle at the next open. The new entry can therefore come out smaller than 12.5% of equity, or be skipped. This is a conservative under-deployment, not a correctness bug.
Keep it, as long as the base only uses it as a warm-up count.
min_bars_required() overrides the framework method; Layer 1 flags this as base_shadow. The override returns max(ma_long+2, 60+squeeze_window+1), which is consistent with the indicator needs and with the 170-bar warmup in the contract.
The source gives no exits. The 15-session clock and the regime exit are the Research Lead's choices, so the result measures that operationalization. The basket is built from today's large caps (survivorship bias is limited but not removed). The analyst should compare it with an equal-weight buy-and-hold of the same 32 names over the identical window, as the hypothesis requires. Per lesson L211, check that the realised average deployment per name is close to 12.5% x 0.97 of equity. The sizing change in this iteration targets that.
Backtest Review
- Sharpe
- 0.33
- Total return
- 17.16%
- Max drawdown
- 16.81%
- Trades
- 385
- Win rate
- 47.0%
- Profit factor
- 1.16
The sizing fix from iteration 1 worked. Median entry notional is 11,793 CNY (range 6,389 to 13,818), about 12% of equity. That matches position_fraction 0.125 x cash_buffer 0.97 with 100-share lots.
The trades match the hypothesis: 300 long-only trades on the 32-name panel. Most close at the 15-session clock (about 21 calendar days, 136 trades), and the rest close on the regime exit or the 8% stop. There are no shorts and no same-day round trips, so T+1 is respected.
The sample is adequate for a walk-forward: 300 closed trades over about 6.3 years of development data.
Per-trade economics clear the floor: average trade return is 0.33% against the CNEQ floor of 0.15%.
Risk is moderate: max drawdown is 16.8%, inside the 25% contract limit and well below the equal-weight basket's 39.8%. The worst loss was 1,601 CNY, about 1.6% of equity, on a stop gap of -13.9%. The largest position was about 14% of equity.
The edge is thin. PF is 1.10 (gross winners +86.9k vs losers -78.8k CNY), Sharpe 0.23, total return +9.0% (CAGR 1.4%), Calmar 0.08, and the longest drawdown lasted 1,359 days.
Benchmark (lesson 170 / QA concern): the equal-weight buy-and-hold of the same 32 names returned +79.5% over the same window, with a 39.8% drawdown. The strategy holds about 3 of 8 slots on average, roughly 35% of the time in the market. A basket scaled to that exposure would return about +28%, against the strategy's +9%. Drawdown is 0.42x the basket's, so this is not pure beta, but the strategy has not yet shown an edge over the basket.
Results swing by year: 2019 +12.9% and 2024 +17.0% carry the result, while 2018, 2022, 2023 and 2025 lose. One or two years carry most of the profit.
Survivorship bias: the basket is today's large caps, so the risk is limited but not removed.
Analysis
Fees are not the problem. The final parameters (squeeze_band 0.031, hold_sessions 11) average 0.62% per trade against the CNEQ floor of 0.15%, with PF 1.37 over 421 trades. Commissions are 4% of gross profit and modeled impact is 6.7%.
Risk is controlled. Drawdown is 10.2% against the pre-registered 25%. The worst realised loss is 1.42% of equity and the largest position is 12.3% of equity, both within the risk_control stop-loss route.
The holdout (Jan 2025 to Oct 2026, 91 trades) has Sharpe 0.95 and 4.7% drawdown. It is consistent with the walk-forward OOS (z +0.61) but not significant (t 1.25 vs a hurdle of 2.0).
The sensitivity sweep found no cliffs, and all 6 checkable pre-registered predictions were met.
HARD FAILURE (enforced, not waivable): the final parameters are positive in only 4 of 9 calendar years (44% vs the 60% floor). This rules out both promotion and labelled paper observation.
The walk-forward evidence is weak and swings in sign. Pooled outer OOS Sharpe is 0.20 (t 0.42 vs a lineage-adjusted hurdle of 2.54, DSR 0.45). Only 6 of 12 outer windows are positive, ranging from -3.7 to +4.0. The inner-training PBO is 0.37-0.98, mostly above 0.6.
The profit is concentrated: 2024 alone carries 54% of the PnL. The initial backtest lost money in 2018, 2022, 2023 and 2026, and lost in calm regimes (Sharpe -0.39).
Parameter stability is unstable. The walk-forward's choice of squeeze_band jumped between about 0.017 and 0.039 (dispersion 0.95), and hold_sessions is moderate. The deployed set sits on an optimum that moves from window to window.
There is little alpha against the equal-weight basket of the same names. The initial run had alpha 0.004, beta 0.16 and information ratio -0.35. The executed-signal diagnostic shows IC -0.01 (t -0.13), indistinguishable from noise.
The full-history Sharpe rose from 0.33 to 0.63 only after both tunables were fitted on the development data. The out-of-sample procedure did not reproduce that gain (0.20).
soft
inconclusive
hard failure
advisory only
Iteration History
Handle on_order_rejected for these stops. A simple option is a close-based backstop in calculate_signal: exit at the next open if close <= avg_px_open*(1-stop_loss_pct) and no reduce-only stop is working on that leg.
The 8% protective stop is a raw reduce-only STOP_MARKET submitted in on_position_opened. This skips submit_stop_order's session-venue capability guard. With SF_SESSION_STOP_FILLS on, the same-price release tick puts the stop in the book before the entry bar is matched, which is correct. With the switch off, the guard does not fire. The stop then reaches the book only after the entry session's range has been matched. If that session closes more than 8% below the fill, the venue rejects the stop as already crossed, and the position stays unprotected until the time or regime exit. The trigger cannot be crossed when it is placed (8% below the fill at the open), so the code itself is not defective.
Optional: size from the cash available after the pending exits, or accept the conservative shrink.
Exits and new entries decided on the same close fill at the same next open. The entry's cash cap (base helper) is computed from free cash at submission, before the exit proceeds arrive. When the book is nearly full, a replacement entry can be shrunk or dropped. This changes the realised slot count slightly but does not change any rule.
None required.
min_bars_required overrides the framework method (static-analysis warning). It returns max(ma_long+2, 60+squeeze_window+1), which is consistent with what _features needs, so this looks deliberate and harmless.
Outcome Summary
Clearing the fee floor and drawdown limits is not enough: an MA re-cross/squeeze screen on large caps showed almost no alpha over a buy-and-hold of the same names and its profit was concentrated in a few years, so check year consistency and basket-relative alpha early, before spending iterations on tuning.
The analyst abandoned it after optimization on a hard, non-waivable gate: the final parameters were positive in only 4 of 9 calendar years (44% vs the 60% floor), which rules out both promotion and labelled paper observation. Supporting concerns were that 6 of 12 outer walk-forward windows were positive, 2024 produced 54% of the PnL, the chosen squeeze band moved between windows, and the executed-signal IC was -0.01 (noise).
A long-only daily screen on 32 pre-2016 Chinese A-share large caps (CNEQ), distilled from a SuperMind 反包 screen: buy when the close crosses back above MA20 while MA20 > MA120, within 10 sessions of a five-MA (5/10/20/30/60) squeeze; exit on a 15-session clock, a regime exit or an 8% stop.
The initial backtest returned +17.2% over 385 long trades (Sharpe 0.33, avg trade 0.43%, max drawdown 16.8%, alpha 0.004, information ratio -0.35 vs the equal-weight basket of the same names). After optimization (squeeze_band 0.031, hold_sessions 11) it made 0.62% per trade with PF 1.37 over 421 trades and a 10.2% drawdown, but pooled walk-forward OOS Sharpe was only 0.20 (t 0.42 vs a 2.54 hurdle) and the 2025-26 holdout Sharpe of 0.95 (t 1.25) was not significant.
Analysis
(iwencai量化)反包_、20日均线大于120日均线、至少5根均线重合的股票
Backtest and paper results are hypothetical. Trading involves risk of loss.