Skip to content

feat(collector): archive bookTicker/raw trade/forceOrder as tape v2 events - #545

Merged
proerror77 merged 2 commits into
mainfrom
codex/archiver-v2-streams
Aug 1, 2026
Merged

proerror77 merged 2 commits into
mainfrom
codex/archiver-v2-streams

Conversation

@proerror77

@proerror77 proerror77 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Change contract

binance-lob-archiver captures <sym>@trade and <sym>@bookTicker (spot + USD-M) and <sym>@forceOrder (USD-M only) alongside depth/aggTrade, writing binance.market_tape.v2 segments whose manifests and session_start rows declare stream_types. Raw trades get per-symbol id-continuity validation (gap → sequence_gap row + replay-unsafe); high-rate shards get a 4× reconnect-proof budget (65536/20s ≈ 3.2k msgs/s) and dedicated queue backlog so rotation barriers can't starve the consumer.

Out of scope

Dependency / merge order

Stacked on the tape-v2-schema PR (base branch codex/tape-v2-schema; retarget to main after it merges). Must land before #537 — a v2-writing candidate cannot pass the old gate (fail-closed interlock, intended).

Focused validation

  • hft-collector suite green (246 lib + 71 archiver incl. 9 new: v2 shard layout per market, dispatch incl. spot-shaped bookTicker, raw-trade gap → replay-unsafe, USD-M-only forceOrder, coverage validation, non-depth shard classification)
  • cargo test -p hft-data --locked green
  • Operational risk noted: whole-catalog trade/bookTicker firehose at peak can exceed the 20s proof buffer → reconnect loop (fail-closed, visible in gate evidence)

Rollout / rollback impact

After merge + release, the next candidate gate must run with the #537 policies. Rollback = cut over back to a previously gated v1 digest (v1 binaries remain gateable under #537).

Issue relationship

Closes #536

Summary by CodeRabbit

  • New Features
    • Added support for Binance trade, book ticker, and USD-M futures liquidation streams alongside existing market data streams.
    • Stream manifests now record supported stream types for clearer coverage and replay handling.
  • Bug Fixes
    • Improved raw-trade sequence validation and market-specific stream enforcement.
    • Enhanced reconnect health monitoring and recovery for high-volume streams.
  • Reliability
    • Increased buffering and queue capacity to support high-rate data collection with fewer interruptions.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Binance archiver now captures trade, bookTicker, and USD-M forceOrder streams. It archives validated events with market-tape schema v2 metadata, validates stream coverage and raw-trade sequences, tracks reconnect health, and preserves legacy and v1 recovery behavior.

Changes

Binance market stream archival

Layer / File(s) Summary
Schema and manifest metadata
rust_hft/tools/collector/src/lob_archiver.rs
SegmentConfig declares stream types. Schema v2 manifests validate and record them, while legacy and v1 recovery retain their previous metadata rules.
Stream sharding and reconnect capacity
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Spot and USD-M configurations create separate trade, bookTicker, and forceOrder shards. High-rate shards receive larger queue and reconnect-proof budgets.
Event dispatch, validation, and archival
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Frame dispatch and event processing support raw trades, book tickers, and force orders. Processing validates symbols, raw-trade sequences, USD-M scope, coverage, and reconnect recovery.
Stream coverage and event validation tests
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Tests cover parsing, archival, stream coverage, USD-M enforcement, reconnect buffering, and independent depth-stream health.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BinanceWebSocket
  participant event_from_frame
  participant process_event
  participant SegmentArchive
  BinanceWebSocket->>event_from_frame: stream frame
  event_from_frame->>process_event: parsed market event
  process_event->>process_event: validate symbol, sequence, and market scope
  process_event->>SegmentArchive: archive validated event
Loading

Possibly related issues

Possibly related PRs

  • proerror77/monday#544 — Introduces the market-tape v2 schema and event types consumed by this collector.
  • proerror77/monday#341 — Shares Binance shard reconnect-health and stream recovery logic.
  • proerror77/monday#124 — Modifies the same archiver event-processing, segment lifecycle, and replay-handling paths.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary collector change: archiving bookTicker, raw trade, and forceOrder events as tape v2.
Description check ✅ Passed The description covers the template sections and provides change, scope, dependency, validation, and rollout details; the scope exception is not required for this diff size.
Linked Issues check ✅ Passed The changes implement all required stream types, tape v2 output, validation, buffering, shard handling, and related tests from issue #536.
Out of Scope Changes check ✅ Passed The changed files and behaviors remain within issue #536 and its stated tape v2 dependency; deployment gate policy work remains excluded.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/archiver-v2-streams

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@proerror77
proerror77 force-pushed the codex/tape-v2-schema branch from 1adcaad to 3b3328e Compare August 1, 2026 00:18
Base automatically changed from codex/tape-v2-schema to main August 1, 2026 00:35
@proerror77
proerror77 enabled auto-merge (squash) August 1, 2026 00:35
Sonic Shih added 2 commits August 1, 2026 08:36
Spot bookTicker payloads carry no e/E/T fields; pin that the archiver
routes them through event_from_frame instead of failing the producer.

Refs #536
@proerror77
proerror77 force-pushed the codex/archiver-v2-streams branch from be4e839 to 47a8888 Compare August 1, 2026 00:36
Comment thread rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Comment thread rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Comment thread rust_hft/tools/collector/src/bin/binance-lob-archiver.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs (1)

4002-4017: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Make trusted_process_state market-aware.

trusted_process_state always builds the four spot streams and never adds {symbol}@forceOrder``. book_ticker_and_force_order_are_archived_without_sequence_state at Lines 4882-4919 sets `config.market = Market::Usdm`, so production would declare five stream types for that config and the coverage shard set would include `btcusdt@forceOrder`.

The test passes only because it never calls validate_stream_coverage_shards. The USD-M fixture therefore does not represent the state the collector reaches at runtime, and it will mask a real mismatch as soon as a test routes coverage validation through it.

Take the market, or the stream-type list, as a parameter and append forceOrder for USD-M.

🛠️ Proposed fix
-    fn trusted_process_state(symbols: &[String]) -> ProcessState {
+    fn trusted_process_state_for(market: Market, symbols: &[String]) -> ProcessState {
         let mut state = ProcessState::new(true);
+        let mut stream_types = vec!["depth@100ms", "aggTrade", "trade", "bookTicker"];
+        if market == Market::Usdm {
+            stream_types.push("forceOrder");
+        }
         state.stream_coverage_shards = vec![symbols
             .iter()
             .flat_map(|symbol| {
                 let symbol = symbol.to_ascii_lowercase();
-                [
-                    format!("{symbol}`@depth`@100ms"),
-                    format!("{symbol}`@aggTrade`"),
-                    format!("{symbol}`@trade`"),
-                    format!("{symbol}`@bookTicker`"),
-                ]
+                stream_types
+                    .iter()
+                    .map(move |stream_type| format!("{symbol}@{stream_type}"))
+                    .collect::<Vec<_>>()
             })
             .collect()];
         state
     }
+
+    fn trusted_process_state(symbols: &[String]) -> ProcessState {
+        trusted_process_state_for(Market::Spot, symbols)
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs` around lines 4002 -
4017, Update trusted_process_state to accept the configured market or
stream-type list, and include the existing four spot streams plus
{symbol}`@forceOrder` when the market is Market::Usdm. Update its callers,
including book_ticker_and_force_order_are_archived_without_sequence_state, so
the generated coverage shard state matches the runtime configuration.
🧹 Nitpick comments (3)
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs (3)

305-336: 🚀 Performance & Scalability | 🔵 Trivial

Plan for the increased websocket connection count.

Each symbol chunk now produces 4 shards for spot and 5 for USD-M, instead of 2. With SYMBOLS=ALL and the default WS_SHARD_SIZE=100, the collector opens 2x to 2.5x more concurrent websocket connections and issues that many more connect attempts per reconnect storm. Binance enforces per-IP connection-attempt limits.

Consider raising WS_SHARD_SIZE for the new high-rate stream types, or staggering the initial connect across shards. Track connect-rejection and reconnect counts per shard in the health file so a limit breach is visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs` around lines 305 -
336, Update stream_shards to account for the increased number of streams per
symbol by raising the effective WS_SHARD_SIZE or otherwise reducing concurrent
shard creation, while preserving complete stream coverage. Also update the shard
connection/reconnect handling to stagger initial connections and record
per-shard connection rejections and reconnect counts in the health file.

3407-3412: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The declared stream-type catalog is duplicated across four literals. Config::stream_types is the authority for the declared catalog, but the same list is written out again in production support code and in three test fixtures. When a stream type is added or renamed, these literals drift silently and the affected tests keep passing against a stale catalog.

  • rust_hft/tools/collector/src/bin/binance-lob-archiver.rs#L3407-L3412: expose the market-keyed list as one reusable function next to Config::stream_types, and call it here instead of the inline four-element literal.
  • rust_hft/tools/collector/src/bin/binance-lob-archiver.rs#L4002-L4017: call the shared function with the fixture's market so USD-M fixtures include forceOrder.
  • rust_hft/tools/collector/src/lob_archiver.rs#L1234-L1239: build stream_types in recovery_config from the shared function for Market::Spot.
  • rust_hft/tools/collector/src/lob_archiver.rs#L1555-L1560: build stream_types in segment_declares_complete_market_tape_surface from the same shared function.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs` around lines 3407 -
3412, Eliminate the duplicated stream-type catalogs by exposing one market-keyed
reusable function alongside Config::stream_types. In
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs lines 3407-3412,
replace the inline list with the shared function; at lines 4002-4017, call it
with the fixture market so USD-M includes forceOrder; in
rust_hft/tools/collector/src/lob_archiver.rs lines 1234-1239 and 1555-1560,
build stream_types through the same function for Market::Spot.

1347-1357: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Use one event type for sequence gaps.

The raw-trade arm writes the event type sequence_gap with a kind field of raw_trade_sequence, which matches the depth path at Lines 1266-1276. The aggregate-trade arm at Lines 1313-1322 writes a dedicated event type aggregate_trade_gap instead.

The manifest event_types map now mixes both conventions, so a consumer that counts gaps must read sequence_gap and aggregate_trade_gap and then inspect kind. Pick one convention. The sequence_gap plus kind form already covers depth and raw trades, so migrating the aggregate-trade arm to it removes the split.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs` around lines 1347 -
1357, The aggregate-trade sequence-gap handling should use the existing unified
event type convention. Update the aggregate-trade arm near the sequence-gap
write to emit event type sequence_gap and include the appropriate
aggregate-trade kind value, matching the depth and raw-trade paths; remove use
of aggregate_trade_gap while preserving the existing gap payload.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs`:
- Around line 933-941: Bound the derived queue capacity in the channel setup
around stream_shards and queue_capacity so it cannot grow indefinitely with
high-rate shard count. Add a configurable absolute maximum, use it to clamp the
sum of max_buffered_diffs and high-rate backlog, and preserve saturation-safe
arithmetic and existing behavior below the cap.
- Around line 1344-1359: Update the raw trade handling around
RawTradeSequenceValidator::observe so an observation error remains recorded via
segment.mark_replay_unsafe(), process_state.sequence_gaps, and the sequence_gap
event, but is not returned to run_session. Continue the capture loop after
logging the gap, while preserving normal error propagation for unrelated
failures.

In `@rust_hft/tools/collector/src/lob_archiver.rs`:
- Around line 1894-1902: Extend the test cases surrounding the RAW_SCHEMA
manifest assertions to cover v2 segments with an empty stream_types array and
with a duplicated stream type. Close each segment and assert the operation fails
with the exact error text “v2 market tape requires a declared stream type set,”
while preserving the existing valid v2 and v1 assertions.
- Line 27: Update the external schema gates in host-rust-lob-shadow-gate.sh at
the trade-summary and aggregate-row checks to accept binance.market_tape.v2
alongside binance.market_tape.v1. Preserve existing v1 compatibility while
allowing RAW_SCHEMA-generated v2 segments containing aggregate_trade_count.
- Around line 703-717: Move the v2 `config.stream_types` validation from the
metadata-writing block to the beginning of `finalize_segment`, before
compression, digesting, renaming, or any filesystem mutation. Keep the existing
validation conditions and error message unchanged, and leave only the valid v2
metadata insertion in the later manifest-generation path.

---

Outside diff comments:
In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs`:
- Around line 4002-4017: Update trusted_process_state to accept the configured
market or stream-type list, and include the existing four spot streams plus
{symbol}`@forceOrder` when the market is Market::Usdm. Update its callers,
including book_ticker_and_force_order_are_archived_without_sequence_state, so
the generated coverage shard state matches the runtime configuration.

---

Nitpick comments:
In `@rust_hft/tools/collector/src/bin/binance-lob-archiver.rs`:
- Around line 305-336: Update stream_shards to account for the increased number
of streams per symbol by raising the effective WS_SHARD_SIZE or otherwise
reducing concurrent shard creation, while preserving complete stream coverage.
Also update the shard connection/reconnect handling to stagger initial
connections and record per-shard connection rejections and reconnect counts in
the health file.
- Around line 3407-3412: Eliminate the duplicated stream-type catalogs by
exposing one market-keyed reusable function alongside Config::stream_types. In
rust_hft/tools/collector/src/bin/binance-lob-archiver.rs lines 3407-3412,
replace the inline list with the shared function; at lines 4002-4017, call it
with the fixture market so USD-M includes forceOrder; in
rust_hft/tools/collector/src/lob_archiver.rs lines 1234-1239 and 1555-1560,
build stream_types through the same function for Market::Spot.
- Around line 1347-1357: The aggregate-trade sequence-gap handling should use
the existing unified event type convention. Update the aggregate-trade arm near
the sequence-gap write to emit event type sequence_gap and include the
appropriate aggregate-trade kind value, matching the depth and raw-trade paths;
remove use of aggregate_trade_gap while preserving the existing gap payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f163cb6a-69ed-414f-8a98-1bbebfaca1fa

📥 Commits

Reviewing files that changed from the base of the PR and between fe79959 and 47a8888.

📒 Files selected for processing (2)
  • rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
  • rust_hft/tools/collector/src/lob_archiver.rs

Comment thread rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Comment thread rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
Comment thread rust_hft/tools/collector/src/lob_archiver.rs
Comment thread rust_hft/tools/collector/src/lob_archiver.rs
Comment thread rust_hft/tools/collector/src/lob_archiver.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(collector): capture bookTicker, raw trade, forceOrder streams in binance-lob-archiver

2 participants