Select stock parameters under a turnover budget
A parameter candidate with the highest measured profit may exceed the trading activity your research protocol allows. Screen a declared turnover budget using completed fills, then compare the feasible candidates. Signal counts are not a substitute: one signal can generate several executions, a rejected order can generate none, and a rebalance can involve very different traded values.
This guide derives turnover and profit from synthetic, closed-round-trip ledgers and constructs a budgeted candidate frontier. It is an external screening method, not a claim that CoTrading automatically constrains arbitrary strategies. Use one market, currency and common research period; the invented results are not historical stock performance.
Declare the turnover convention
Our measure is total absolute executed value on both buys and sells during one fixed research period, divided by initial portfolio NAV. It is gross traded value over initial capital. There is no division by two, no average-NAV denominator and no annualization. Other definitions are valid for other purposes, but changing the denominator or side convention changes the threshold’s meaning.
For example, buying 400 of shares and later selling 400 produces turnover 0.8 against opening NAV 1000 under this convention. It is not 0.4. Do not equate this research measure with a regulated fund’s reported portfolio-turnover ratio or a brokerage’s account-activity measure without checking the relevant definition.
Fix period boundaries and cost treatment too. The SEC bulletin on fees distinguishes transaction and ongoing costs. Turnover can describe activity, but it is not the fee amount or a complete market-impact model. Our zero-fee synthetic ledgers isolate budget accounting; real net performance must include the agreed charges.
Obtain a complete candidate ledger
For each frozen configuration, retain run status, scored session coverage, opening NAV, security and currency, fill ID, quantity, execution price and side. Link each result to its configuration and input version. Keep actual executions separate from requested targets or unfilled orders.
Require a completed run before interpreting an empty fill list as zero activity. Missing fill output from a failed worker is unknown, not a successful no-trade strategy. A candidate can also have a complete run but a missing export; retain that gap instead of manufacturing an empty table.
Check unique fill IDs and nonnegative magnitudes. Repeated export rows can double the measured turnover even when the engine executed only once. Preserve order-level grouping if the fee policy depends on an order rather than individual fills, while computing executed notional from the genuine fill records.
Calculate the worked example from transactions
All valid candidates start with NAV 1000 and finish flat within the same synthetic period. Fees are zero. Candidate A buys and sells ten shares at 99.6 and 100.4. Its total executed value is 2000 and profit eight. B trades four shares at 99.375 and 100.625, giving value 800 and profit five.
C trades two shares at 149 and 151, giving value 600 and profit four. G trades four shares at 99.625 and 100.375, giving value 800 and profit three. F completes with no fills and profit zero. D has missing fill output; E’s run failed despite an empty file. Both remain unknown.
| Candidate | Turnover | Net profit under zero-fee assumption | Budget 0.8 |
|---|---|---|---|
| A | 2.0 | 8 | outside |
| B | 0.8 | 5 | inside |
| C | 0.6 | 4 | inside |
| F | 0 | 0 | inside |
| G | 0.8 | 3 | inside |
| D, E | unavailable | unavailable | unresolved |
The profits reconcile directly from sale proceeds minus purchases because every valid account is flat at both boundaries and costs are zero. They are amounts, not percentages. With the same opening NAV and interval, profit ranking is comparable. An account with residual shares would also require terminal valuation before deriving its net result.
Apply the budget before selecting a winner
The inclusive budget is 0.8, so B, C, F and G qualify. A’s profit is highest, but it is infeasible under the declared activity constraint. Do not relax the budget to two after seeing A’s result while continuing to call the selection budget-constrained.
Keep the infeasible candidate and the exact excess in the report. In a production search, a turnover screen may be a post-run filter rather than a constraint enforced during candidate generation. Label which mechanism you used. Filtering completed outputs does not prove that an optimizer prevents an arbitrary strategy from exceeding the budget during execution.
The core arithmetic uses Python Decimal with string prices:
traded = sum(fill['qty'] * fill['price'] for fill in fills)
turnover = traded / opening_nav
profit = sum(fill['qty'] * fill['price'] * fill['side']
for fill in fills)
Here side is negative for a purchase and positive for a sale. That cash bridge is a profit calculation only under this example’s flat-boundary, zero-fee conditions. Do not reuse it for open positions, dividends or external cash flows without adding the appropriate reconciliation.
Construct the feasible frontier
Within the budget, a candidate is dominated if another has no greater turnover and no lower net profit, with at least one strict improvement. G is dominated by B: both turn over 0.8, but B earns five instead of three. The remaining frontier is B, C and F.
C offers lower turnover and lower profit than B, so neither dominates the other. F offers no trading and no profit. Its presence is mathematically valid under this two-objective definition, although a separate minimum-activity or evidence rule might exclude it. Define that rule before selecting, rather than deleting an inconvenient frontier point afterward.
Our final selection policy chooses the largest profit among feasible candidates, so it selects B. The frontier still helps show the tradeoff: a researcher choosing a stricter budget could prefer C. A curve drawn between observed candidates is not evidence that untested intermediate parameters produce interpolated results.
Test missing data and duplicated executions
The first counterexample is D or E being assigned zero turnover because no usable fill rows are available. That would allow an unknown or failed run through the budget. The script retains both in an unknown list, while F alone receives a legitimate zero from a completed empty ledger.
The different-mechanism check repeats B’s fill export. Duplicate IDs cause rejection before aggregation. This prevents double-counted activity and profit, even though the duplicated rows individually look valid. A genuine partial fill needs a distinct execution ID; it must not be removed merely because its price and quantity happen to match another fill.
Do not count corporate-action quantity changes as traded fills without evidence of execution. Similarly, canceled orders and signals belong in their own event tables. A full account may contain many state changes with no executed notional, and a valid turnover measure should preserve that distinction.
Execute and archive the decision
Download the complete example. Use Python 3.12 or later and run python R615.py. Its standard-library Decimal calculation derives the amounts above from fills, identifies feasible B/C/F/G, frontier B/C/F, selected B and unknown D/E, and rejects repeated fill IDs. It does not call a broker or a real backtest engine.
Accept the package when the period and denominator are fixed, every feasible point links to completed fills, unknown runs remain separate and the frontier can be recomputed from recorded pairs. Preserve the budget, inclusion boundary, profit definition and all rejected candidates.
Recompute if fills, costs, initial capital, period coverage or the turnover convention changes. Rescaling capital can change feasible orders and lots, so do not assume every real candidate’s ratio remains invariant. This budgeted selection is a conditional research decision, not evidence that the chosen parameter is profitable or executable in future markets.
FAQ
Is a signal count a turnover estimate?
Not under this method. Turnover comes from actual executed quantities and prices.
Does a failed run with an empty export have zero turnover?
No. Its activity is unresolved. Only a completed, verified no-fill run earns that status.