Build1 publisher3 min readPublished Updated
Monthly splits shrink some A-share backtest cells to just a handful of observations, one to as few as seven
Felix Wang's volume-confirmation test survives 15,900 pooled stock-days and flips sign in all seven setups once it is cut by calendar month, which is the right diagnostic run on cells too small to carry it.
The Engineer · Build desk

What happened
- Felix Wang built 15,900 stock-days from daily bars for 584 liquid Shanghai and Shenzhen names off free public endpoints, conditioning the next day's return on today's move and today's volume ratio.
- Pooled, the folk rule holds: a 3-9.5% up day on normal volume averaged -0.560% the next day at a 42.5% win rate, while the same move on 2-3x volume averaged +0.346% at 50.8%.
- He also printed the line he says most retail backtests omit: across all 15,900 stock-days the next-day mean was -0.063% with a 47.3% win rate, so the whole window drifts down.
- Split by calendar month, all seven setups flip sign, with limit-up follow-through at +2.18% and a 64.2% win rate in June 2026 against -1.39% and 35.6% in July.
- Wang flags his own August column as unreadable, with 5 to 36 observations per bucket, and tells readers to discount the 100% win rate it contains.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- constraint Per-regime reporting is paid for in sample: three monthly cuts leave about 5,300 stock-days each before bucketing, and the rarer setups drop to single-digit cells that cannot carry a mean.
- decision Anyone sizing on this tilt now has to decide whether 0.409 points over the window's drift is worth holding when the sign is a function of which month you measured.
- exposure A trader who calibrated size on the June cell was on the wrong side of the sign in July, and nothing in the pooled table would have flagged it.
- precedent Publishing the unconditional row alongside the buckets sets a cheap standard: a bucket mean quoted without its baseline is not interpretable, and readers can now ask for both.
The measurement holds up under reading, which is not the default for posts of this kind. The volume ratio divides today's volume by the mean of the previous five bars, today excluded, so it is knowable at the close [3]. The forward return runs close to close from the signal bar [3]. That second choice is where the study's only positive aggregate move bucket gets awkward. Limit-up days, meaning a close above 9.5%, average +1.199% the next day on a 56.5% win rate across 338 samples [5], and the forward window opens at the close of a day that finished up more than 9.5%. Whether you are filled at that close is not something the backtest can check.
One nit, visible only because the script is published [15]: the stated requirement is five prior bars and one forward bar, but the loop starts at index 6 [4], which discards the first eligible row for every symbol. It will not move a number in the table.
The interesting cost is sample. 15,900 stock-days across 584 names is 27 bars per name [1]. Cut that three ways and each month holds about 5,300 stock-days before any bucketing at all [8]. Limit-up days are 338 of the 15,900, or 2.1% [4], so a single month's limit-up cell sits on the order of a hundred rows, and that cell is what produced a June-to-July swing of 3.57 percentage points in follow-through, thirty days apart [3]. The June and July columns publish a mean and a win rate and no n [10]. August publishes its n indirectly: Wang puts the range at 5 to 36 per bucket [11], and the 71.4% win rate in the up-3-to-9.5%-on-2x-volume cell [12] is five of seven [6]. A 100% win rate in a monthly table is a statement about n [11].
So the per-regime rule needs a second half: the cell count printed next to every regime mean, and a floor below which the cell is a placeholder. Wang does the first and warns about the second in prose [11]. Prose warnings do not survive a screenshot.
There is a deeper limit in the split variable. The conditioning is the calendar [17]. A month is a label attached afterwards, and you always know today's month while never knowing whether it is a June-type month. Wang's own description of the tape points at the mechanism he did not test. At midday on 10 September 2026 the Shanghai Composite stood at 3937.78, off 0.35% on about 1.09 trillion yuan of turnover, with 1,078 of 5,217 scanned stocks up and 36 limit-ups against 6 limit-downs, which he reads as a narrow, theme-driven tape [13]. Breadth like that is measurable at the close. If narrow breadth is what makes momentum rules look infallible, as he argues [14], the shippable version conditions on breadth and reports each bucket inside each breadth state, which would say something before the month is over.
The pooled edge is also smaller than it reads. Up 3-9.5% on 2-3x volume averages +0.346% on 187 samples [9] against a window baseline of -0.063% [2]. That is 0.409 points over drift [5], with a win rate 3.5 points above the unconditional 47.3% [7]. Printing the baseline row turns the folk rule into a modest tilt, which is the most useful line in the study and the cheapest one to copy.
What to watch
- Whether the repo's monthly table gains a per-cell n column and a minimum-cell floor.
- Whether September's limit-up follow-through holds July's negative sign or reverts to June's.
- Whether the 584-name universe is rebuilt with the liquidity screen applied at the start of the window rather than at scan time.