Seven Trading Bot Checks: Timing, Costs and Unknown Orders
TECH INSIGHT / EXPLAINED
A trading bot can lose money because of its strategy, implementation, costs or market conditions. These seven checks address implementation and evaluation errors; passing them does not establish a profitable strategy.
Local execution of the actual project
These captures show the existing project UI or functions executed locally with non-private sample inputs. Each caption states the scope of the execution.
1. Define when information becomes available
A completed closing price is unavailable before the close. If a decision needs that final value, give it a later executable fill in the model. A one-row shift can help align signals, but cannot repair an incorrectly labelled bar, missing session or unrealistic fill. Write down signal time, submission time and fill assumption separately.
2. Charge every change in exposure
For a simplified long/flat model, turnover must include the initial entry and any final liquidation you assume. A diff() that leaves the first row missing can omit its cost. Partial fills, changing weights and short reversals need more detailed accounting. Use fees applicable to the instrument and a justified execution model; a fixed slippage number is a scenario, not an observed fact.
3. Keep evaluation separate from selection
Record every parameter configuration tried, reserve a chronological evaluation period, and inspect neighboring settings. A single sharp optimum is a reason to investigate sensitivity, not proof of fraud or proof that all neighboring optima are robust. Repeatedly tuning against the held-out period turns it into training data.
4. Make exhausted retries an explicit failure
A loop that handles every 429 with continue can fall out and return None after its final attempt. Raise a defined exhaustion error and notify with a safe correlation ID. Bound read retries, honor applicable Retry-After information and separate rate-limit handling from authentication or validation failures. An order timeout requires status reconciliation before any resubmission.
5. Count pending and unknown orders
A zero balance does not prove there is no accepted, unfilled buy. Two workers can both observe zero and submit. Persist one intent per strategy/account/signal and reserve it atomically; reconcile open orders and fills on restart. A client order ID helps only within the venue’s documented uniqueness and lookup rules. This pure decision function demonstrates the gate, not the database transaction:
def entry_gate(intent_state, position_qty, open_buy_qty, reconciled):
if not reconciled:
return "reconcile_first"
if intent_state != "new":
return "inspect_existing_intent"
if position_qty != 0 or open_buy_qty != 0:
return "exposure_already_exists"
return "eligible_for_atomic_reservation"
assert entry_gate("unknown", 0, 0, True) != "eligible_for_atomic_reservation"
assert entry_gate("new", 0, 1, True) == "exposure_already_exists"6. Treat a stop as a plan, not a guaranteed loss cap
Position sizing needs a planned risk budget, cash or margin limits, quantity increments and cost allowance. A stop order can fill beyond its trigger after a gap. Distinguish planned loss from stress loss and cap aggregate exposure. A fully paid long position and leveraged short exposure do not have the same loss bounds.
7. Graduate by evidence, not elapsed weeks
Use historical tests, simulated execution and the venue’s supported test environment. Deliberately exercise token expiry, reconnects, stale data, partial fills, unknown order results and restart reconciliation. Two quiet weeks may contain none of those events. Record acceptance criteria and a rollback procedure before any separately authorized live deployment.
Sources and further reading
Binance timeout and unknown execution · Investor.gov order types · Position-sizing example · Read-request retry handling
Content and examples reviewed: 2026-09-29
댓글
댓글 쓰기