Stale Quotes and Feed Health in an Agent Trading Loop
By DX Research Group · · Market data
A quiet-market example for separating old prices from broken subscriptions.
An autonomous trading agent may keep reasoning while its market-data stream becomes quiet. We separate quote age from subscription health so the runtime can record why a state snapshot was accepted or withheld.
A quote can be old because the market has not changed or because the collector stopped receiving updates. Those cases demand different interpretations. One timestamp cannot explain both market freshness and transport health.
Follow a quiet interval
Assume a synthetic best quote last changed at 14:00:00. A decision occurs at 14:00:08. Its quote age is eight seconds. Meanwhile, the collector received a transport heartbeat at 14:00:07.900. Heartbeat age is 100 milliseconds. The connection appears recently active under this fixture, while the last observed quote remains eight seconds old.
Now consider another collector with the same quote but no received heartbeat since 14:00:00. Its quoted price is identical, yet its health evidence is different. A feature that uses only quote price cannot distinguish the two.
Coinbase's WebSocket channel documentation describes heartbeats containing sequence and last-trade identifiers, and notes that ticker-batch updates depend on changes. Channel semantics therefore matter when interpreting silence. A lack of a price update can reflect an unchanged market.
Track multiple ages
Store last quote event time, last quote receipt time, last message receipt time, and last relevant health-message receipt time. Compute ages relative to the decision's actual availability boundary. Include subscription state and the expected product set, because a healthy connection may still lack the instrument you requested.
Use named fields rather than one vague fresh boolean. A boolean can summarize policy, but the underlying ages and health evidence should remain reviewable. This helps distinguish a strict freshness policy from an infrastructure incident.
Choose a policy from the task
For illustration, an application might decline to use quotes more than five seconds old. Under that rule, both collectors' quotes are unusable even though only the second shows missing recent health evidence. Five seconds is an example threshold, an explicitly assumed local threshold.
Report the number of excluded decisions at several documented thresholds if threshold choice affects a research conclusion. Keep the model, questions, and evaluation period fixed. Changing freshness policy also changes the population on which predictive results are measured.
Test recovery, not just failure detection
Create fixtures for a quiet healthy feed, a silent broken feed, an active connection missing one product subscription, and a reconnect awaiting a new snapshot. Recovery should not immediately mark an old cached book fresh merely because a socket opened. Require the data needed by your protocol's reconstruction contract.
A recent heartbeat is evidence about the channel under its documented semantics. Application queues and derived features require separate health evidence. Instrument the capture and processing stages separately when that distinction matters.
Keep stale observations visible
Store rejected quote identifiers and rejection reasons alongside decision records. This preserves a path to diagnosing missed coverage without fabricating a newer price. A clean dashboard can show an unavailable value with its age rather than a precise-looking stale number. The goal is an honest availability record that supports later evaluation, with the threshold’s scope made explicit.
Place this check in the agent loop
Our state and memory framework explains how this input contract fits a persistent trading agent. Use the harness-transfer test design to distinguish a data-adapter change from a change in model behavior.