market-flow
0.1.0 — early release. Use at your own risk. The API and on-disk format may change in patch releases until 1.0.
A small Rust library that reads newline-delimited JSON (NDJSON) market data and exposes it as an async stream of typed events. Handy for replaying recorded feeds, building order-book logic, or wiring market data into Tokio pipelines without hand-rolling parsers.
Each line in the input file is one JSON object: a snapshot, depth update, or trade.
Input format
Lines look like this (see src/data/input.ndjson for a full sample):
| Field | Notes |
|---|---|
type |
snapshot, depth_batch, or trade |
ts |
Milliseconds since Unix epoch |
symbol |
Instrument id, e.g. BTC-USDT |
bids / asks |
Arrays of [price, qty] (integer JSON numbers) |
side |
buy or sell (trades only) |
Prices and quantities deserialize into rust_decimal::Decimal.
Dependencies
Consumers need Tokio (async runtime) and futures (for StreamExt::next) in addition to this crate:
= "0.1"
= { = "1", = ["macros", "rt-multi-thread"] }
= "0.3"
Example usage
use StreamExt;
use ;
async
Public API
Crate root (market_flow)
| Item | Description |
|---|---|
init_market_event_stream |
Open an NDJSON file and return a stream |
MarketEventStream |
Async Stream of parsed events |
model |
Event types and errors |
market_flow::model::market_event
| Type | Description |
|---|---|
MarketEvent |
Snapshot, DepthBatch, Trade, or Unknown |
OrderbookEvent |
Timestamp, symbol, bids, asks |
OrderbookLevel |
price, qty |
TradeEvent |
Timestamp, symbol, side, price, qty |
Side |
Buy or Sell |
All model fields are public. Types implement Deserialize (for JSON), Debug, Clone, and common comparison traits.
market_flow::model::error
| Type | Description |
|---|---|
MarketFlowError |
IOError or DeserializationError |
Stream contract
- Item type:
Result<MarketEvent, MarketFlowError> - End of file: stream yields
None - Bad line: one
Errper failed line; the stream continues on the next poll (I/O errors aside)
You can also call MarketEventStream::new(path).await directly; it behaves the same as init_market_event_stream.
Development
With just installed:
Or directly:
Benchmarking
We use Criterion to measure two layers:
| Group | What it measures |
|---|---|
parse_line |
serde_json deserialization only (snapshot, trade, all 10 fixture lines) |
stream_file |
End-to-end: open input.ndjson, async line read + parse, drain the stream |
# or: cargo bench
# Quick smoke run (few iterations):
# One benchmark only:
HTML reports land under target/criterion/report/index.html (open in a browser).
What to benchmark next as the project grows:
- Larger NDJSON files (throughput in MB/s)
- Order-book update logic built on top of the stream
- Compare
SmolStrvsStringfor symbols spawn_blockingvs Tokio async I/O if you add a sync path
For stable numbers, run benches on a quiet machine with cargo bench -- --noplot in CI, or save baselines with Criterion’s cargo bench -- --save-baseline main and compare with --baseline main.
Publishing (maintainers)
Tag releases as v0.1.0 on GitHub to match CHANGELOG.md.
Update repository / homepage in Cargo.toml if your fork lives at a different URL.
License
Licensed under the MIT License.