Free lesson · Quant strategy development
08 / Build a bot that preserves the experiment
Open interactive lessonPractice calculationsExplore labs
Start with the idea
A trading bot is a state machine as well as a prediction function. The state includes fills already received and orders that might still execute. A good forecast does not compensate for duplicated orders or incorrect positions.
Symbols, units & horizon
- Q_target: intended signed position in units
- Q_filled: reconciled current signed position
- Q_open: signed remaining quantity in acknowledged live orders
- Q_new: additional signed order intent
- Positive quantity: buy or long, negative: sell or short
- Order intent: desired quantity, not evidence of a completed fill
When and why to use this
Use explicit state and stable identifiers to make live behaviour match the backtest’s intent. Replay failures before testing capital at risk.
Separate the deterministic research logic from data adapters and order routing. Given the same timestamped inputs and portfolio state, the strategy should produce the same intent. Keep live credentials and broker execution outside this training lab; the code below is architectural pseudocode.
Architecture pseudocode
def on_market_event(event, state):
data = ingest_and_validate(event) # timestamps, sequence, missing fields
if not data.is_fresh or not state.is_reconciled:
return PAUSE_AND_RECONCILE
features = transform_with_frozen_model(data.history)
forecast = predict_return_and_uncertainty(features)
target = construct_portfolio(forecast, state.positions)
intent = target - state.positions - state.pending_exposure
if not risk_checks_pass(intent, state, data):
return NO_NEW_ORDER
if expected_benefit(intent) <= all_in_cost(intent) + buffer:
return NO_NEW_ORDER
order_id = stable_id_for_this_intent(event, state)
persist_intent_before_submission(order_id, intent)
return submit_once_then_reconcile(order_id, intent)
def on_execution_report(report, state):
apply_fill_once(report.execution_id, report)
reconcile_positions_cash_and_open_orders(state)
persist_state_and_metrics(state)The pseudocode omits broker-specific details on purpose. The core requirements are idempotent fill handling, durable intent, reconciliation after ambiguous responses, and a portfolio-wide risk check. Restart recovery is part of trading behaviour: it must not recreate orders that already exist.
- Use the same signal and portfolio code in replay and paper mode; vary only data and execution adapters.
- Replay delayed, duplicated and out-of-order events. Verify that duplicate execution reports cannot double a position.
- Test partial fills, rejects, cancellation races, disconnections, clock drift and process restarts.
- Record model version, feature snapshot, intended position, risk decision, order ID and realised costs for every trade.
- Reconcile daily P&L into forecast return, exposure changes, execution, borrow, funding and unexplained residual.
Calculate remaining order intent
- If target quantity is T, filled position is Q and signed outstanding order quantity is O, the remaining required intent is .
- A partial fill moves quantity from O into Q, leaving Q+O unchanged until the order is cancelled, replaced or fully resolved. This conservation check catches accidental duplicate orders.
Target 100 shares, position 40 and 30 shares still working gives new intent 30. A 10-share partial fill changes position to 50 and outstanding to 20; new intent remains 30.
Python implementation
Self-contained teaching example. Python 3.10+; dependencies and input conventions are shown in the code and notation. Run in your own Python environment.
def remaining_order_intent(target, reconciled_position, acknowledged_open_quantity):
"""Use reconciled broker state; a pending cancellation is still open."""
return target-reconciled_position-acknowledged_open_quantity
print(remaining_order_intent(100, 40, 30)) # only 30 more, not 60Continue learning
Quant Strategy Development — all lessons- 01 / Start with a source of return
- 02 / The variables that actually enter the decision
- 03 / Test predictive information before a complex model
- 04 / Momentum and trend: information that persists
- 05 / Mean reversion and relative value
- 06 / Carry, events, and liquidity provision
- 07 / Convert a forecast into a trade decision
- 08 / Build a bot that preserves the experiment
- 09 / Decide whether the edge is real enough to continue
Quantitative finance and development glossary · Python resources and libraries · Research sources and limitations