Usage and configuration

Everything tunable lives in config/config.toml. Nothing operational is hardcoded, and the parser enforces exactly what the comments promise — types, enumerated choices, bounds — failing with a message that names the offending key, so a session cannot start from a configuration it could not honor.

Credentials

Keys come from the file named by credentials.env_file — .env beside the repository root in the shipped configuration — or from the process environment, never from the configuration file itself. Copy the template and fill it in:

cp .env.example .env      # then set ALPACA_API_KEY_ID and ALPACA_SECRET_KEY
chmod 600 .env

Paper-account keys work for market data; point [alpaca] trading_base at the paper endpoint, as the shipped configuration does. load_credentials! warns if the file is group- or world-readable.

Entry points

Every script activates and instantiates the scripts environment itself (scripts/Project.toml: the package by path, plus CairoMakie and UnicodePlots for the figures and the dashboard plots), so a fresh clone needs no preparation, and each accepts an alternative config path as its first argument.

julia --threads=auto scripts/stream.jl   # live capture
julia scripts/backfill.jl                # historical download over the configured window
julia scripts/compact.jl  data/raw/<session>_part001.jsonl
julia scripts/replay.jl   data/raw/<session>_part001.jsonl
julia scripts/visualize.jl data/raw/<session>_part001.jsonl
julia scripts/monitor.jl                 # read-only dashboard for a running session

From the REPL the same operations are run_stream, run_backfill, compact_raw and replay_source. The figure functions need using CairoMakie beside the package, and monitor_raw draws its plots once using UnicodePlots has run; the package itself depends on neither.

[provider]

KeyMeaning
nameProvider adapter. One of: "alpaca" (US equities, credentialed), "binance" (crypto spot, public).
feedLive feed. Binance: "trade" or "aggTrade". Alpaca: one of "iex" (real-time, single venue, 30 symbols on the free tier), "delayed_sip" (consolidated tape, 15 minutes late, free), "sip" (real-time consolidated, paid).

On the free tier delayed_sip is the scientifically stronger choice: it is the complete consolidated tape, and a fixed 15-minute offset is irrelevant to any analysis that is not trading on it.

[credentials]

KeyMeaning
env_fileKEY=value file holding the API credentials, relative to the configuration file unless absolute.

Relative paths are resolved against the directory of the configuration file, so a configuration can be copied into any project and keeps working. load_config() without an argument reads the repository's own config/config.toml, and is refused in an installed copy of the package, where that file is a read-only template to copy (MarketTickStreamer.DEFAULT_CONFIG).

[stream]

KeyMeaning
symbolsSubscription list; at most limits.max_symbols entries.
channelsSubset of "trades", "quotes", "bars". Trades only by default: quote and bar frames are parsed into Quote and Bar and delivered to the on_quote / on_bar callbacks of live_source, but neither is persisted. A quote stream carries an order of magnitude more messages than the trade stream, so storing it is a separate decision.
require_market_openQuery the market clock before connecting and exit if closed.
wait_for_openWhen closed, sleep until the next open instead of exiting. The wait is shifted by the feed's intrinsic delay.
stop_at_market_closeSchedule a graceful stop at the session's next close, likewise shifted.
reconnect_max_retriesReconnection attempts per disconnect before giving up. The counter resets after any connection that delivered data.
reconnect_base_delay_sBackoff base; the delay is base * 2^attempt, jittered.
reconnect_max_delay_sBackoff cap.
stale_timeout_sWatchdog interval: a connection that delivers no frame for this long is severed and retried.

The watchdog exists because HTTP.jl 1.x WebSockets have no read idle timeout, so a silently dead TCP connection would otherwise block the read loop indefinitely.

[storage]

KeyMeaning
data_dirRoot of the data tree, relative to the configuration file, or absolute.
raw_subdirAppend-only NDJSON session files.
processed_subdirCompacted per-symbol per-day files.
flush_interval_sSink flush interval.
flush_max_ticksSink flush batch-size threshold; whichever trigger comes first.
processed_format"csv" or "arrow". CSV for interoperability and inspection; Arrow when size or read time demands it.
processed_compressionCompression of Arrow record batches: "none", "zstd" or "lz4"; Arrow only. Uncompressed files are memory-mapped and read lazily. "zstd" is about five times smaller (8 against 44 bytes per print on a liquid US equity day) and is decompressed on load.

[limits]

KeyMeaning
max_session_hoursHard stop for a live session.
max_raw_file_mbRoll to a new raw part file beyond this size.
channel_capacityIn-flight tick buffer; the producer blocks when full.
max_symbolsSubscription cap.
min_free_disk_gbRefuse to start, and stop an active session, below this free space.
max_live_heap_mbLive-heap ceiling for backfill and compaction; the streaming paths check it and spill rather than exhaust memory.
max_open_spill_filesFile handles a spilling compaction keeps open at once.
compact_mem_fractionShare of the free RAM an in-memory compaction may claim; beyond it the run spills.
spill_headroomScratch space a spilling compaction requires, as a multiple of the input size.
compact_footprint_factorEstimated in-memory footprint per byte of input, which decides whether a file fits in memory.

These are the safety margins. They are the sole source of truth for the cutoffs — no threshold is hardcoded elsewhere in the pipeline.

[replay]

KeyMeaning
pace"recorded" honors the original inter-arrival times; "max" emits as fast as the consumer takes them.
speedTime-compression factor when pacing is honored; 60.0 replays an hour in a minute.
clockTimestamp that orders and paces the replay: "recv" (local receipt), "exchange" (the venue's own), or "auto" — receipt time when every record has it, exchange time otherwise. A backfilled recording has no receipt clock.

[backfill]

KeyMeaning
start_date, end_dateInclusive exchange dates (America/New_York). Either an ISO date "YYYY-MM-DD" or a sentinel: "today", or "today-<N>d" for N calendar days back.
feedHistorical feed, "iex" or "sip". Free accounts have full SIP history back to 2016, minus the trailing 15 minutes.
page_limitRows per REST page, from 1 to the provider maximum (Alpaca 10000, Binance 1000), which is also the default. A larger value is rejected: Binance clamps it without an error, and a clamped page reads as the end of the tape.
rate_limit_sleep_sPause between pages. The free tier allows 200 requests per minute.
resumeSkip (symbol, day) pairs already present under processed/, so an aborted download resumes instead of restarting.

The sentinels keep a committed configuration from going stale. They count calendar days, not trading days: a window may land on a weekend or a holiday and return nothing, which the session report will show as an empty capture rather than an error.

[rest]

KeyMeaning
request_timeout_sRead timeout of a REST request.
connect_timeout_sConnection timeout of a REST request.
max_retriesRetries on transient failures: 429, 5xx, timeouts and dropped connections.

[quality]

non_price_conditions lists, per tape, the sale-condition codes that disqualify a print from a price path. Tapes "A" and "B" are CTA-processed, "C" is UTP-processed, "O" is the OTC tape; the same character means different things across them, which is why the lists are separate. The shipped defaults are the provider's own published lists.

This is used only by price_forming, filter_price_forming and the n_price_forming column of session_report. Capture is never filtered — see Replay & Analysis Interfaces for why the distinction belongs to the analysis rather than to the recording.

A print carrying several conditions is disqualified by any one of them, and a print on a tape with no list is kept. The set lands in the session sidecar with the rest of the configuration, so a result stays attributable to the eligibility rule that produced it.

To decode the codes themselves, fetch the provider's own glossary with condition_map rather than assuming a mapping.

[monitor]

Attach-mode terminal dashboard, read-only and opt-in.

KeyMeaning
refresh_sRefresh interval.
top_symbolsRows in the per-symbol bar plot.
rate_window_sRate-history window; at least refresh_s.

[logging]

KeyMeaning
level"debug", "info", "warn" or "error".
log_to_fileTee the log to a per-session file under log_dir.
log_dirLog directory, relative to the configuration file, or absolute.

File logs are always flushed and are sanitized of terminal control sequences, so a killed session still leaves a readable tail.

[alpaca]

Endpoint roots, overridable so the suite can point the whole pipeline at an in-process mock server.

KeyDefault
trading_basehttps://paper-api.alpaca.markets (paper keys) or https://api.alpaca.markets (live keys).
data_basehttps://data.alpaca.markets
ws_basewss://stream.data.alpaca.markets/v2