Reduce stock replacement churn with a rank buffer
A ranked stock portfolio can repeatedly replace the same boundary names even when the ranking changes only slightly. A rank buffer adds state: incumbents may remain until a looser exit threshold is breached, while new names must satisfy a tighter entry threshold. Test that membership rule on the same frozen ranking stream rather than changing the factor or claiming the ranks predict returns.
This guide compares immediate top-two replacement with one explicit buffer policy and computes actual synthetic trades. It is an external extension, not a verified CoTrading feature. The account is long-only, single-currency, zero-fee and uses constant invented prices to isolate membership churn.
Freeze the input ranking and tie rule
Save each decision’s eligible security list, information cutoff, score or total ordering and membership date. Both policies must receive exactly the same original ranking. If one uses revised scores, a different universe or information published later, its trade difference cannot be attributed solely to the buffer.
Resolve ties deterministically before selection. Our boundary check sorts equal finite scores by security identifier; A precedes B when both score one. Missing or nonfinite scores need an explicit eligibility policy, not an arbitrary position in a sort. The main fixture supplies already ordered, unique identifiers.
The MSCI discussion of index buffers describes buffers used to limit constituent turnover. It motivates separating entry and retention, but our rank-two/rank-three rule is an original synthetic design, not a reproduction of current MSCI methodology.
Specify which incumbents have priority
The portfolio has two slots. Immediate replacement always chooses the current top two. The buffer first retains incumbents ranked three or better, then fills vacancies from unheld names in the current top two. A newly top-ranked stock does not automatically displace an allowed incumbent when both slots are occupied.
That priority rule matters. Other buffer designs force entry at a separate threshold or rank all retained and new candidates together. Do not use a generic label to hide which policy was executed. Record entry rank, exit rank, capacity and vacancy handling before inspecting turnover.
If only one qualifying name exists, allocate one half to it and keep the other half in cash. Do not renormalize the remaining stock to full weight, since that changes the common weighting policy. Both routes use the same half-capital slot allocation and execution rules.
Build the six-period membership example
The frozen rankings are:
| Period | Ranking from highest to lowest |
|---|---|
| 0 | A, B, C, D |
| 1 | A, C, B, D |
| 2 | A, B, C, D |
| 3 | A, C, B, D |
| 4 | C, D, A, B |
| 5 | C, D, B, A |
Both begin with A and B. Immediate top-two replacement trades B for C, C for B, then B for C across periods one through three. The buffer keeps A/B throughout because B never falls below rank three during those checks.
At period four, B falls to fourth and must exit under the buffer. A remains eligible at rank three, so C fills the open slot and the result is A/C. D is ranked second but cannot displace the eligible A under the declared incumbent-first rule. At period five A falls fourth and D enters, producing C/D.
Execute target changes with real cash sequencing
All four synthetic stocks trade at 100 throughout. Opening capital is 1000, each occupied slot targets five shares and costs are zero. The runner sells exits before buying entries and checks nonnegative cash after every trade, not just after netting an entire rebalance.
retained = [s for s in incumbents if rank[s] <= exit_rank]
desired = list(retained)
for s in ranking[:entry_rank]:
if s not in desired and len(desired) < capacity:
desired.append(s)
The full program translates desired membership into quantities, cash movements and executed notional. It does not estimate turnover by counting rank changes alone. In a real account, unequal prices, drift, fees and lots require the same complete state treatment.
Constant prices deliberately remove performance differences here. Both end with value 1000. This makes the example a membership-policy test, not evidence that retaining a lower-ranked name improves investment returns or that either ranking system contains predictive information.
Reconcile churn and coverage
Immediate replacement records four exits, while the buffer records two. Including initial portfolio formation, total absolute traded value divided by initial capital is five for top-two and three for the buffer. Each replacement exchanges 500 of outgoing stock for 500 of incoming stock; formation adds 1000 to both.
Keep formation convention visible. Excluding it would yield four and two rather than five and three. Neither number is a regulated fund turnover ratio or an annualized estimate. The measured interval consists of six synthetic decisions under a fixed price assumption.
The buffer’s membership sequence is A/B, A/B, A/B, A/B, A/C and C/D. Its reduced churn comes with delayed exposure to C and D. Report that coverage tradeoff instead of saying the buffer retains all desirable opportunities while eliminating only unnecessary costs.
Handle vacancies and blocked exits separately
The vacancy check supplies only A and verifies one occupied slot and cash weight 0.5. An absent eligible name is not an invitation to buy an unqualified stock or make A full weight. Preserve the reason and the unused budget for the next decision.
The different-mechanism counterexample makes B rank fourth while B’s sale is blocked. The selector returns blocked_exit, retains actual holdings for accounting and leaves the desired membership unapplied. B is not labeled valid rule-retained merely because the position cannot be sold.
This distinction protects the exit rule: approved retention still requires rank three or better. A locked, noncompliant holding is an execution exception needing review. A production continuation policy may carry it, reduce other purchases or halt, but must not fabricate a sale or call the nominal buffer successfully applied.
Preserve identity and missing-data decisions
Security aliases and corporate actions need a stable mapping before membership comparison. A renamed ticker should not become a false exit plus entry. Conversely, two different securities with similar names must not be merged merely to reduce the reported churn.
If a ranking observation is missing, follow the frozen policy for retaining, exiting or stopping. Do not use the next available ranking retroactively. A suspension or missing score must not silently move a stock into the qualifying top set, and unknown eligibility is different from a measured low rank.
This fixture checks unique identifiers, a tie example and a blocked-sale branch, but does not implement a full historical security master or exchange calendar. Preserve those limitations when extending it beyond the invented four-stock universe.
Run and accept the comparison
Download the complete example. Use Python 3.12 or later and run python R631.py. Standard-library assertions verify both exit counts, turnover five/three, constant ending values, the six buffer memberships, vacancy cash, deterministic ties and the blocked-exit status.
Archive raw rankings, controls, membership transitions, requested versus executed changes and each cash bridge. Confirm that every approved incumbent satisfies the exit threshold and every new member satisfies entry rules. Preserve exceptions instead of hiding them inside the retained column.
Record the policy version with each transition so later rule changes cannot rewrite earlier retention decisions.
Rebuild after ranking, universe, buffer priority, capacity, prices or execution policy changes. A lower-turnover synthetic result is not a universal strategy improvement and does not verify automatic portfolio membership management in CoTrading.
FAQ
Does a new rank-one stock always enter a full buffered portfolio?
Not under this incumbent-first policy. Other designs need their own explicit priority rules.
Is an unsellable fourth-ranked holding valid retention?
No. Preserve it as an execution exception rather than a successful policy result.