Skip to content

Crate map

The workspace is organized by dependency direction: small domain crates at the bottom, integrations at the edge, process assembly at the top. Crates depend downward, never upward.

flowchart TD
    L1["core · config · feed<br/><i>primitives</i>"]
    L2["valuation · engine · actors<br/>execution · post_trade<br/><i>processing</i>"]
    L3["strategy · simulator<br/><i>orchestration</i>"]
    L4["venues · market_data<br/><i>integrations</i>"]
    L5["market_data_archive · market_data_backfill<br/>signal_dump<br/><i>binaries</i>"]
    L6["runtime<br/><i>assembly</i>"]

    L1 --> L2 --> L3 --> L4 --> L5 --> L6

    classDef base fill:#2e7d32,stroke:#1b5e20,color:#fff
    class L1 base

Domain crates

Crate Holds Touch it when
core Instruments, sides, order types, timestamps, book and trade events Adding a primitive type everything shares
config JSON config types and validation, RuntimeConfig, VenueConfig Adding a configurable knob
feed Local book state, level and order-level books, book/trade updates Changing how book state is maintained
valuation Signal runtime, signal implementations, registry, profiling Writing or fixing a signal
engine Normalized packets, callback dispatch, VenueEventLoop Changing packet or clock ordering
actors Actors that turn context into intents — passive quoting, IOC aggression Changing quoting behavior
execution Submit/cancel requests, order events, ExecutionVenue, order manager Changing order tracking
post_trade Decision, action, fill, and BBO records; JSONL sinks Adding a post-trade field

valuation means signals

The crate is named valuation for historical reasons but is the home of all computed signals. Its own README notes a rename to signals would fit better. Look here for signal code even though the name does not say so.

Orchestration crates

Crate Holds
strategy The strategy engine and runner — wires signals, actors, execution, risk gates, PnL and drawdown controls, order flow
simulator Venue-agnostic exchange simulation: modeled submit/cancel latency, queue position behind real book orders, normalized fill events

The simulator consumes real recorded market data and never synthesizes market data of its own. It models where your order would have sat in the queue, which is why backtest fills are more conservative than a naive "price touched my level" model.

Historical replay can run many strategy cases over one shared market-data reader and one shared signal engine — each case keeps independent order state and its own liquidity copy, so a parameter sweep avoids re-parsing and re-evaluating signals per case.

Integration crates

Crate Holds
venues Live venue adapters translating exchange APIs to normalized traits
market_data Exchange parsers, Avro schemas, replay readers — the reusable format layer
market_data_archive Continuously running writers that persist live exchange data
market_data_backfill Bounded historical backfills and file maintenance
signal_dump Sampling and lookahead to turn packets plus signals into research rows
runtime Config-to-process assembly, including the algo_mm_bot binary

Dyson's market-data supervisor launches binaries from market_data_archive and market_data_backfill — those are the executables listed on Market data.

Boundary rules

The rules the workspace holds itself to, condensed:

  • Keep core, feed, and execution venue-agnostic.
  • Packet processing and callback dispatch go in engine; event-loop ordering goes in engine::VenueEventLoop.
  • Live exchange protocols go in venues; persisted formats and replay readers go in market_data.
  • Decision logic goes in actors and strategy — not in runtime.
  • Exchange simulation and queue-position models go in simulator — not in venues, strategy, or runtime.
  • Process assembly and operator binaries go in runtime.
  • Do not add top-level venue-specific crates. Add a module under venues (for trading) or market_data (for capture and replay).

The full version lives in crates/README.md in the algo-trading repository.