← all posts

The Hard Part of Market Data Is Making It Operable

A chart that updates proves the feed is alive. It does not prove the system can be trusted after a gap, retry, failed worker, stale dependency, pair switch, or alert someone has to explain later.

Market data demos well.

A socket opens. Prices move. A chart updates. The system feels alive.

It is easy to show because it is easy to mistake for the product. Live movement looks like trust from a distance. The harder version starts when someone asks whether the data can still be trusted after an upstream gap, a retry, a pair switch, a failed worker, or an alert that fired twenty minutes ago.

The problem has moved from ingestion to operability.

An operable system can explain what it received, what it missed, what it retried, what it skipped, what state the operator is looking at, and why the answer on screen is the answer the system believes.

Ingestion is the visible milestone

The first version of the product promise is simple: collect market data, process it, and show it to someone.

That promise is clean because it leaves out the parts that make the system hard to run. Sources do not expose identical surfaces. Reference data is incomplete. Historical ranges overlap. Some data arrives daily, some arrives monthly, and some only makes sense across a custom window. A retry can duplicate work unless the processor is built to tolerate it. A missing upstream slice can make ten downstream results look broken even when they are only waiting.

The failure modes are ordinary enough to get underestimated.

The first working chart usually arrives before the system has a durable answer for basic operational questions. Is the pair configured? Is the source delayed? Did the backfill already cover this window? Is the worker still alive? Did the latest value come from a live event, a historical snapshot, or a merge between the two?

Those questions often arrive through support channels. They define system behavior.

Market data becomes useful when it is inspectable. A value without provenance can still be shown on a chart. It just cannot be trusted when the chart is the thing someone uses to make a decision.

Replay is an operability primitive

Replay is often treated like a recovery feature. In practice, it is one of the basic requirements for operating the system.

A market-data system that cannot replay a missed range cannot explain the miss. It can only admit that something went wrong and hope the downstream state is close enough. That may be acceptable for a demo. It is weak ground for a system that has to answer questions after the market has moved on.

Replay requires more than "run the job again." The work needs stable identity. The system has to know which pair, source, range, resolution, and dependency set the job represented. It has to distinguish work that never ran from work that ran and failed, work that succeeded and should be skipped, and work that is blocked behind missing upstream state.

Durable task state gives the system memory. Once work is represented as claimable, retryable, inspectable state, the operator no longer has to reconstruct that memory from logs and terminal history. The system can say what exists, what owns it, and what happened.

Idempotency is the other half of the contract. If a retry can corrupt outputs, replay becomes a risk. If a processor can safely see the same window twice, retry becomes a normal state transition. Replay is only useful under pressure when repeating work does not create new uncertainty.

Bounded work is the practical requirement. A missed hour should not require reprocessing a month because the system cannot name the smaller unit. A failed dependency should not force an operator to guess which downstream results are dirty. Replay earns trust when the system can recover the exact work it owes and leave the rest alone.

Visibility is part of the product

A blank dashboard creates work.

It forces the operator to decide whether the system is empty, slow, broken, misconfigured, waiting, filtered, unauthorized, or still starting. The interface may look clean while exporting ambiguity to the person trying to run the system.

Operator visibility has to speak in states the system can defend. Ready, running, failed, stale, skipped, blocked, and waiting on dependency state are different conditions. Collapsing them into "nothing to show" makes the UI easier to build and the system harder to operate.

Dashboards expose backend semantics because users read system state through them. If a stream is configured but stale, the UI needs a different answer than if the stream was never configured. If a pair switch is in progress, that is different from a pair with no events. If a backfill is blocked behind missing reference data, that is different from a worker failure.

The backend can keep those distinctions private for a while. The dashboard eventually forces them into the product.

Dashboard pressure is useful because it makes the system declare what its states mean. Loose operational knowledge turns into API behavior: lifecycle endpoints, status responses, dependency state, stream freshness, snapshot windows, and failure reasons.

A useful operator view filters internal detail around the next action. Retry this range. Wait for this dependency. Add this pair. Check this source. Good visibility reduces the number of mysteries created by normal failure.

Stable semantics beat "latest value"

"Latest value" is too thin for operational decisions.

It hides the path that produced the value. It does not say whether the value is fresh, whether it belongs to the current pair, whether it came from a seed snapshot or a live tail, whether it has already been merged with a later event, or whether the chart window silently changed underneath the user.

Market-data interfaces need stable semantics because users read meaning through motion. A chart that jumps can mean the market moved, the window changed, the pair switched, the source recovered, or the frontend merged two streams incorrectly. The same visual effect can come from several different system events.

The contract has to carry those distinctions. A live view should know how it starts, how it continues, and what each event name means. A seed snapshot followed by a stream tail is a different contract from a best-effort stream of updates. Trade bars, book bars, and book snapshots carry different meanings. Pair lifecycle operations should be deliberate enough that old state does not leak into a new view.

The more the user depends on the dashboard, the less room the system has for implied behavior.

Fixed windows help keep comparisons understandable. A baseline that shifts without being named is not a baseline the operator can reason about. A comparison that mixes pair-local behavior with cross-exchange behavior produces a number, but the number does not carry enough meaning to explain itself.

Stable semantics reduce ambiguity in the chart. They give the system a language for saying what happened before the user turns that visual state into a decision.

Safe boundaries affect trust

Deployment feels separate from market data until the browser participates in runtime behavior.

Once the frontend consumes live streams, switches pairs, shows operational state, and reads runtime configuration, deployment becomes part of correctness. A staging environment that behaves differently from production changes the debugging surface. A value that is public in one environment and secret in another creates a boundary problem.

Browser-visible runtime config needs a clear allowlist. Secrets do not belong in image layers, client bundles, or environment paths that make them reachable from the wrong side of the system. Branch-specific promotion rules matter because operators need to know which code and config produced the screen in front of them.

These rules matter because they preserve trust.

When environments drift, incidents get harder to explain. The same pair switch works in preview and fails in production. The same stream connects locally and dies behind the production route. The same dashboard shows different state because config was baked in during one deploy path and loaded at runtime in another.

Market-data systems already have enough moving parts. The deployment boundary should reduce uncertainty, not create a second version of the product.

Alerts need stored explanations

An alert without context creates follow-up work.

Market data makes this worse because the thing being measured keeps moving. By the time an operator opens the alert, the chart may have changed, the spread may have normalized, the source may have recovered, and the window that made the anomaly obvious may no longer be visible.

The alert record needs to preserve the reason the system believed the event mattered at the time: the observed value, the baseline, the z-score, the sample count, the severity, the comparison mode, and the explanation. A spread-widening alert should be able to say what widened, what it was compared against, how much history supported the baseline, and whether the comparison was local to one pair or relative to peer venues.

Without that stored explanation, the operator has to reconstruct the event under worse conditions. They have to infer the old state from current charts, logs, and memory. Alerting should reduce that reconstruction work.

Explanation functions as operational memory.

The same applies to chart overlays and anomaly markers. A marker that cannot explain itself becomes a visual breadcrumb with no audit trail. It tells the operator that something happened while withholding the part that would make the event actionable.

Market data is temporal. The system has to preserve the meaning of the moment, alongside the measurement.

Operability is the trust layer

The operability requirement appears at each boundary.

Ingestion shows that the feed can move. Replay lets the system recover named work. Visibility gives the operator useful state. Stable semantics keep the frontend and backend aligned on what the user is looking at. Safe boundaries control runtime behavior. Stored explanations let the system defend its own decisions after the fact.

None of those requirements require one specific stack. They require one specific discipline: treat operational truth as part of the product.

Market-data systems have to preserve trust through movement, partial availability, retries, stale state, and decisions made after the interesting moment has already passed. A system that only collects data will eventually leave someone guessing. A system built to operate gives them enough state, history, and explanation to make the next move.

The trust comes from whether the system can still explain itself when the path was not clean.

The one-line version

Market data becomes useful when the system can explain how it got the answer, what it missed, and what it did when the path was not clean.