Skip to content

feat(data): validate Binance market tape - #104

Merged
proerror77 merged 1 commit into
mainfrom
codex/binance-market-tape-contract
Jul 17, 2026
Merged

proerror77 merged 1 commit into
mainfrom
codex/binance-market-tape-contract

Conversation

@proerror77

@proerror77 proerror77 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Change contract: Add one shared typed Binance market-tape contract that validates schema/event identity, bounded source clocks, diff-depth U/u/pu continuity, and aggregate-trade numeric and sequence invariants before downstream research consumers can accept a frame.

Out of scope: Collector wiring; immutable artifact manifest or snapshot compilation; backtest consumer changes; DuckDB or PostgreSQL changes; Polymarket; L3/order-id data; queue, impact, fill, or capacity modeling; live execution.

Dependency or merge order: None. This PR is based directly on main SHA a3e879f and can merge or roll back independently. The later OSS artifact verifier will consume this contract in a separate PR.

Focused validation:

  • cargo test --locked -p hft-data: 13 passed
  • cargo fmt --check -p hft-data
  • cargo clippy --locked -p hft-data --all-targets -- -D warnings
  • cargo check --locked -p hft-data
  • Counterexamples cover reversed U/u ranges, sequence gaps, stale rollback, malformed pu/T, incorrect futures pu chains, error-state poisoning, source-clock rollback, stale source delay, and aggregate-trade gaps
  • Positive coverage includes reconnect-safe first frames and overlap ranges that contain previous_u + 1
  • Independent review initially found missing depth sequence validation; the red/green fix was re-reviewed with zero findings and APPROVE
  • Review scope: 2 files, 633 additions, below the 750-line review limit

Rollout or rollback impact: This exports a shared validation module but does not wire it into a production collector or execution path, so runtime behavior is unchanged until a later consumer PR. Revert this PR to remove the contract; no data migration, database schema, deployment, or live-trading change is involved.

Summary by CodeRabbit

  • New Features
    • Added support for validating Binance market tape data, including depth updates and aggregate trades.
    • Added checks for supported schemas, event types, timestamps, sequencing, identifiers, and numeric fields.
    • Added detection of delayed, missing, duplicated, or out-of-order market events.
  • Tests
    • Added comprehensive validation coverage for malformed data, clock violations, sequence gaps, and rollbacks.

@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 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a public Binance market-tape module with schema allowlists, depth and aggregate-trade parsers, clock checks, per-symbol sequence validators, helper functions, and comprehensive unit tests.

Changes

Binance market tape

Layer / File(s) Summary
Market-tape contracts and module export
rust_hft/data-pipelines/core/src/binance_market_tape.rs, rust_hft/data-pipelines/core/src/lib.rs
Defines supported schemas and event types, shared JSON and clock-validation helpers, and exports the new module.
Depth clock parsing and sequencing
rust_hft/data-pipelines/core/src/binance_market_tape.rs
Parses depth events, validates update IDs and timestamps, and tracks per-symbol sequence continuity and source-time ordering.
Aggregate-trade parsing and sequencing
rust_hft/data-pipelines/core/src/binance_market_tape.rs
Parses aggregate trades, validates IDs, positive decimals, dual clocks, delays, and strict per-symbol trade sequencing, with unit coverage for accepted and rejected cases.

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

Sequence Diagram(s)

sequenceDiagram
  participant ArchivedEvent
  participant DepthSourceClock
  participant DepthSourceClockSequenceValidator
  ArchivedEvent->>DepthSourceClock: Parse and validate depth event
  DepthSourceClock->>DepthSourceClockSequenceValidator: Observe symbol update
  DepthSourceClockSequenceValidator-->>DepthSourceClock: Accept or reject sequence
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: Binance market tape validation.
Description check ✅ Passed The description covers the required sections and includes validation, out-of-scope, dependencies, and rollout details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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/binance-market-tape-contract

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.

@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: 3

🤖 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/data-pipelines/core/src/binance_market_tape.rs`:
- Around line 221-248: The validator around the last-trade state must also track
each trade’s previous last_trade_id and validate the next first_trade_id is
exactly previous last_trade_id + 1, rejecting both gaps and rollbacks while
preserving aggregate-ID and timestamp checks. Extend the state stored by the
last map and add a targeted counterexample test with consecutive aggregate IDs
but discontinuous underlying trade ranges.
- Around line 130-145: Update the state handling in the clock validation method
around the last-entry insertion so an omitted transaction time does not replace
the previously observed Some value; retain the last known transaction timestamp
for subsequent rollback checks while preserving None when no prior timestamp
exists. Add a targeted counterexample test covering Some(100) → None → Some(99),
which must reject the rollback.
- Around line 55-59: Update the archived constructors from_archived_event and
the corresponding archived event constructor to validate the envelope’s schema
and event type against the exact frame type before calling from_frame. Reject
unsupported schemas and mismatched envelope/frame identities, and add targeted
counterexample tests covering both unsupported schemas and mislabeled
event/frame pairs.
🪄 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

Run ID: b8e3cdec-9f46-4704-8909-35856693d51f

📥 Commits

Reviewing files that changed from the base of the PR and between a3e879f and 66c8b99.

📒 Files selected for processing (2)
  • rust_hft/data-pipelines/core/src/binance_market_tape.rs
  • rust_hft/data-pipelines/core/src/lib.rs

Comment on lines +55 to +59
pub fn from_archived_event(raw: &Map<String, Value>, received_at_ns: u64) -> Result<Self> {
Self::from_frame(
raw.get("frame").context("depth event has no frame")?,
received_at_ns,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Bind archived schema and event type to the parsed frame.

Both archived constructors extract only frame, so an unsupported schema or mislabeled event (snapshot containing a depth update, for example) is accepted. Validate the archived schema/event pair and require the exact expected event type before parsing.

Add counterexamples for unsupported schemas and mismatched envelope/frame identities. As per coding guidelines, “Every safety boundary must have a targeted counterexample test.”

Also applies to: 165-170

🤖 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/data-pipelines/core/src/binance_market_tape.rs` around lines 55 -
59, Update the archived constructors from_archived_event and the corresponding
archived event constructor to validate the envelope’s schema and event type
against the exact frame type before calling from_frame. Reject unsupported
schemas and mismatched envelope/frame identities, and add targeted
counterexample tests covering both unsupported schemas and mislabeled
event/frame pairs.

Source: Coding guidelines

Comment on lines +130 to +145
if clock.event_time_ms < previous_event_time
|| previous_transaction_time
.zip(clock.transaction_time_ms)
.is_some_and(|(previous, current)| current < previous)
{
anyhow::bail!("{} depth source-time rollback", clock.symbol);
}
}
self.last.insert(
clock.symbol.clone(),
(
clock.event_time_ms,
clock.transaction_time_ms,
clock.final_update_id,
),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve the last known transaction clock when T is omitted.

A Some(100) → None → Some(99) sequence passes because Line 142 replaces the prior timestamp with None. Compare future values against the last observed transaction time and retain that value across frames without T.

Add this omission/rollback sequence as a counterexample test. As per coding guidelines, “Every safety boundary must have a targeted counterexample test.”

🤖 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/data-pipelines/core/src/binance_market_tape.rs` around lines 130 -
145, Update the state handling in the clock validation method around the
last-entry insertion so an omitted transaction time does not replace the
previously observed Some value; retain the last known transaction timestamp for
subsequent rollback checks while preserving None when no prior timestamp exists.
Add a targeted counterexample test covering Some(100) → None → Some(99), which
must reject the rollback.

Source: Coding guidelines

Comment on lines +221 to +248
if let Some((previous_id, previous_event_time, previous_trade_time)) =
self.last.get(&trade.symbol).copied()
{
let expected = previous_id
.checked_add(1)
.context("aggregate trade id overflow")?;
if trade.aggregate_trade_id != expected {
anyhow::bail!(
"{} aggregate trade gap expected={} received={}",
trade.symbol,
expected,
trade.aggregate_trade_id
);
}
if trade.event_time_ms < previous_event_time
|| trade.trade_time_ms < previous_trade_time
{
anyhow::bail!("{} aggregate trade source-time rollback", trade.symbol);
}
}
self.last.insert(
trade.symbol.clone(),
(
trade.aggregate_trade_id,
trade.event_time_ms,
trade.trade_time_ms,
),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate continuity of the underlying trade-ID ranges.

The validator tracks only aggregate_trade_id; consecutive aggregate IDs with first_trade_id jumping beyond the previous last_trade_id + 1 are accepted, silently losing trade-level sequence evidence. Store the previous last_trade_id and reject gaps or rollbacks in first_trade_id.

Add a counterexample with consecutive aggregate IDs but discontinuous trade ranges. As per coding guidelines, “Every safety boundary must have a targeted counterexample test.”

🤖 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/data-pipelines/core/src/binance_market_tape.rs` around lines 221 -
248, The validator around the last-trade state must also track each trade’s
previous last_trade_id and validate the next first_trade_id is exactly previous
last_trade_id + 1, rejecting both gaps and rollbacks while preserving
aggregate-ID and timestamp checks. Extend the state stored by the last map and
add a targeted counterexample test with consecutive aggregate IDs but
discontinuous underlying trade ranges.

Source: Coding guidelines

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.

1 participant