Test within-industry stock factor ranks through tradable baskets
Within-industry ranking answers a practical question: does a stock factor select different companies when each industry receives a fixed number of slots? Build two baskets from the same dated panel, one using the overall score and the other ranking separately inside declared industries. Compare membership, exposure, actual trades and net account value. A regression coefficient alone does not provide this decision comparison.
This guide uses six fictional US stocks and a USD account. All scores, classifications and prices are synthetic. CoTrading industry diagnostics remain planned or unverified; the procedure does not claim that a built-in evaluator already supplies industry-neutral optimization. The deliverable is a dated classification table, two deterministic selection lists and two independently reconciled ledgers.
Establish the classification that existed at the decision
Keep security identifier, classification system, industry code, effective date, publication date and source version. A classification effective later cannot be used to reorganize an earlier universe merely because it is present in today’s file. If the required historical version is unavailable, record that limitation before calling the study an industry-controlled historical test.
The SEC SIC reference explains the industry codes appearing in company filings. It is one possible classification source, not a guarantee that a current list reconstructs every historical classification or that it matches another vendor’s taxonomy. Choose one system for this study rather than mix labels that happen to share similar names.
The fixture calls its industries Tech and Utility. These simplified labels are author-defined, not official SIC assignments. D is Utility as of January 30; a separate record makes it Tech beginning February 1. The January study must retain Utility. This explicit version test isolates classification timing from changes in the factor’s numeric values.
Freeze two selection rules with comparable capacity
The global basket takes the two highest scores across all six eligible stocks. The within-industry basket reserves one slot for Tech and one for Utility, choosing the highest score within each. Both use descending scores and ascending security identifier for ties. Neither may inspect the later mark when choosing a member.
Require at least two valid stocks in an industry before filling its reserved slot. If the industry is smaller, leave that slot in cash; do not transfer it to the larger industry. This is a specific small-sample policy, not a universal optimum. Record the resulting lower exposure instead of pretending that both portfolios remain fully comparable on all dimensions.
Use identical predecision information availability, price definitions and trading dates. The two methods may produce different weights, but a data or execution convention must not change at the same time. Python’s sorting documentation supports the explicit multikey ordering used in the example. Stable input order alone is insufficient when it is not itself an approved tie rule.
Reconstruct the six-stock cross section
Tech stocks A, B and C score nine, eight and seven. Utility stocks D, E and F score three, two and one. Overall sorting selects A and B. The reserved-slot construction selects A and D. In the first basket all stock exposure is Tech; in the second the two stock allocations are split across the author-defined industries.
The difference does not show that the global factor is wrong. Scores may legitimately reflect industry economics. It shows which decision changes when industry representation is constrained. A score’s level may not even be comparable across industries; a within-industry rank deliberately discards that cross-industry level information. Make this tradeoff visible instead of describing the adjustment as a free improvement.
Preserve all six rows with the industry count and both selection flags. An average industry score or a chart of sector weights cannot identify why D replaced B. The row-level table should show B remaining eligible but losing the constrained slot, while D enters as Utility’s highest-scoring member. Those are different reasons from data failure or trade rejection.
Reconcile the global basket from an existing account
Both comparison accounts begin with forty A shares, forty E shares and 200 cash. With all reference prices ten, initial equity is 1,000. These are supplied opening holdings; this fixture does not invent earlier acquisition costs or claim to measure a complete investment lifetime. It compares the next rebalance from the same state.
The global method retains A, sells forty E at ten and buys forty B at ten. Each executed order pays a fictional fee of one. Sale proceeds are 399 after fee and the purchase costs 401, leaving 198 cash. Later supplied marks are A at 10.2 and B at 10.1, giving share values 408 and 404. Final equity is 1,010.
The within-industry method instead sells E and buys D at the same ten reference opens and one-unit fees. Cash is also 198. A remains worth 408 and D’s supplied mark of 10.5 values its forty shares at 420. Final equity is 1,026. The sixteen-unit difference is a synthetic decision consequence, not an estimate of an industry-neutral factor premium.
Exercise the small-industry counterexample
Remove E and F from the valid cross section. Utility now contains only D, below the declared minimum of two, so its slot remains empty even though D has a numeric score. The within-industry target contains A only. From the same initial holdings, sell E and pay one, leaving 599 cash and forty A shares.
At A’s mark of 10.2, equity is 1,007. Only one fee is paid because there is no replacement purchase. This branch changes coverage and exposure, not merely ranking. An implementation that reallocates the unused 400 to A would represent a different strategy, and its performance must not be silently mixed into the reserved-slot result.
The classification counterexample is separate: backfilling D’s later Tech label into January would alter which industry has usable members. Preserve effective-date lookup and small-sample counts independently. Passing the cash arithmetic does not prove that the classification used for the selection was historically permitted.
Run the two-basket acceptance pack
Download the complete example. Save it as R563.py and run python R563.py with Python 3.12 or later. It uses only the standard library and synthetic data. The repository source is docs/growth/research/round-5/examples/R563.py.
Assertions require global members A/B, within-industry members A/D, the correct January and February label for D, and A alone in the undersized-industry branch. Each account reconstructs its own orders and fees. Expected final equities are 1,010, 1,026 and 1,007 respectively; they are not copied from a shared gross-return statistic.
Interpret and update the comparison carefully
Report stock and cash exposure, industry weights, turnover and unfilled slots beside any return. A net difference can combine selection, cash exposure and costs; do not attribute the entire amount to one mechanism without a further controlled decomposition. Equal industry slots are not the same as benchmark industry weights, factor residualization or an optimized risk constraint.
Before extending the study, reconstruct one decision from historical labels through the actual ledger. Repeat after a taxonomy revision, universe change or slot-policy change, saving both versions. Keep A-share, Hong Kong and US panels separate with their own classification coverage and execution rules. The accepted result is a reproducible comparison of two stated constructions, not proof that industry effects have been removed from every dimension of risk.
Diagnose what a changed basket does and does not establish
Begin interpretation with the selected identifiers, not the final difference. Hold the starting account and execution convention fixed, then list which exits and entries came from the global rule and which from the industry reservation. In this fixture A is common to both constructions, E exits in both and only the replacement differs. That makes the decision bridge transparent without pretending the later price path was predictable.
For a larger historical comparison, review whether cash exposure differs because some industries lacked coverage. If it does, distinguish the observed combined result from a separately designed exposure-matched experiment. Do not silently normalize the smaller basket to full investment, because that changes quantities and costs. An exposure-matched variant can be useful, but it needs its own declared construction and ledger.
Classification availability also has two dates. A category may be effective on one date but only become observable to the research pipeline later. A valid historical decision needs a record that satisfies both the chosen effective-date rule and the availability cutoff. Today’s well-documented classification cannot repair an earlier unknown label by assumption. Keep that unknown as an exclusion or explicitly label the study as a retrospective use of current classifications.
Finally, use the member reason table when someone asks whether the factor is “only an industry bet.” The comparison shows sensitivity to one particular constraint, not a universal answer about the source of returns. More than one decomposition may be reasonable. Report the exact two rules, data coverage and costs so readers can assess the limited question that was actually tested.
FAQ
Does within-industry ranking guarantee industry neutrality?
No. Fixed slots do not establish benchmark weights or neutralize all risk exposures.
What happens when an industry has too few valid stocks?
This contract leaves its slot in cash and reports the exposure change explicitly.