Back to Nautilus Trader

Binance SBE Codecs

crates/adapters/binance/src/spot/sbe/README.md

1.231.07.6 KB
Original Source

Binance SBE Codecs

  • generated/ contains Rust code generated by Real Logic's Simple Binary Encoding (SBE) generator from the Binance Spot API SBE schema (schema 3:5). Do not edit these files manually. Regenerate them with the Real Logic SBE tool when the schema changes.
  • stream/ contains hand-written decoders for Binance market data stream messages (schema 1:0).
  • Generic cursor/error utilities are shared from nautilus-serialization behind the sbe feature and re-exported from this module for compatibility.

Market data streams

Binance Spot SBE market data streams use SBE-specific update speeds. The SBE <symbol>@depth diff-depth stream updates every 25ms, while <symbol>@depth20 partial-depth snapshots update every 50ms. Public JSON stream suffixes and update speeds are separate from this SBE surface.

Licensing

  • The generated/ codecs are generated using the Apache-2.0 licensed Real Logic SBE tool; see ../../../licenses/Apache-2.0-RealLogic-SBE.txt and the entry in ../../../licenses/THIRD_PARTY_LICENSES.md.
  • The hand-written stream/ code is covered by the NautilusTrader project license.

Modifications

The generated generated/ code has been modified from the original SBE generator output:

  • Added module-level lint suppression attributes in generated/mod.rs for clippy compatibility
  • Rewrote crate:: -> super:: and collapsed the three pub use crate::SBE_* lines into a single pub use super::{SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_SEMANTIC_VERSION};
  • Reordered the pub use decoder::...; pub use encoder::...; block to come before use super::*; (fixes rustfmt)
  • Removed unused codec modules (institutional/allocations, order amendments, user data stream management, block trades). See the strip list in the regeneration steps below.

Regeneration

The current generated/ tree was produced by Real Logic SBE v1.37.1 against Binance's spot_3_5.xml schema. Stay on the same SBE tool version when bumping the schema; SBE v1.38+ emits a different (fluent-encoder) API that would force call-site rewrites in spot/http/parse.rs, spot/http/client.rs, and spot/websocket/trading/decode_sbe.rs.

Prerequisites

  • JDK 17 or newer to run the SBE jar. A portable Temurin JRE works:

    bash
    mkdir -p /tmp/sbegen && cd /tmp/sbegen
    curl -fsSL -o jre.tar.gz \
      "https://api.adoptium.net/v3/binary/latest/21/ga/linux/x64/jre/hotspot/normal/eclipse?project=jdk"
    tar -xzf jre.tar.gz
    export JAVA="$PWD/$(ls -d jdk-21*-jre)/bin/java"
    
  • The SBE tool jar (Maven Central, uk.co.real-logic:sbe-all):

    bash
    curl -fsSL -o sbe-all-1.37.1.jar \
      "https://repo1.maven.org/maven2/uk/co/real-logic/sbe-all/1.37.1/sbe-all-1.37.1.jar"
    
  • The latest Binance Spot SBE schema:

    bash
    curl -fsSL -o spot_latest.xml \
      "https://raw.githubusercontent.com/binance/binance-spot-api-docs/master/sbe/schemas/spot_prod_latest.xml"
    

    spot_prod_latest.xml is a pointer file (one line) naming the active schema; the corresponding spot_<id>_<version>.xml lives in the same directory. The CHANGELOG for breaking and additive changes is at https://github.com/binance/binance-spot-api-docs/blob/master/CHANGELOG.md.

Generate

bash
mkdir -p /tmp/sbegen/out
"$JAVA" \
  --add-opens java.base/jdk.internal.misc=ALL-UNNAMED \
  -Dsbe.target.language=Rust \
  -Dsbe.output.dir=/tmp/sbegen/out \
  -Dsbe.errorLog=yes \
  -jar /tmp/sbegen/sbe-all-1.37.1.jar /tmp/sbegen/spot_3_5.xml

This produces /tmp/sbegen/out/spot_sbe/ shaped as a crate (with Cargo.toml, src/lib.rs, and one src/<message>.rs per codec). The numInGroup UINT8/UINT16 warnings on every group are from Binance's schema (they use groupSizeEncoding rather than a primitive) and can be ignored.

Transform and lift into generated/

Each generated file needs three text rewrites to fit the project's module layout:

  1. use crate::*; -> use super::*;
  2. pub use crate::SBE_SCHEMA_ID; + ..._VERSION; + ..._SEMANTIC_VERSION; (three lines) -> pub use super::{SBE_SCHEMA_ID, SBE_SCHEMA_VERSION, SBE_SEMANTIC_VERSION};
  3. Remaining crate:: -> super::
  4. Move the pub use decoder::...; pub use encoder::...; block above the use super::*; line.

A reference Python script that does all four steps lives at /tmp/sbegen/transform.py while regenerating; see the commit history for crates/adapters/binance/src/spot/sbe/generated/ for the most recent regen for an example.

Strip unused codec modules

Delete these files from the generator output before copying to generated/:

  • account_allocations_response_codec.rs
  • allocation_report_event_codec.rs
  • allocation_report_type.rs
  • allocation_status.rs
  • allocation_transaction_type.rs
  • allocation_type.rs
  • block_trades_response_codec.rs
  • counter_party_role.rs
  • order_amend_keep_priority_response_codec.rs
  • order_amendments_response_codec.rs
  • user_data_stream_ping_response_codec.rs
  • user_data_stream_start_response_codec.rs
  • user_data_stream_stop_response_codec.rs
  • user_data_stream_subscribe_listen_token_response_codec.rs
  • user_data_stream_subscribe_response_codec.rs
  • user_data_stream_unsubscribe_response_codec.rs

These belong to features the adapter does not consume (institutional allocations, order amendments, user-data stream session management, historical block trades).

Rebuild mod.rs

Take the transformed file list and replace the existing pub mod declarations in generated/mod.rs. Keep the existing header (//! doc comment naming the schema version, the #![forbid(unsafe_code)] and #![allow(...)] / #![expect(...)] lint attributes, and the trait/buffer definitions below SBE_SEMANTIC_VERSION). Update:

  • The doc comment //! Generated SBE codecs for Binance Spot API (schema 3:N).
  • pub const SBE_SCHEMA_ID: u16 = <id>;
  • pub const SBE_SCHEMA_VERSION: u16 = <version>;
  • pub const SBE_SEMANTIC_VERSION: &str = "<semantic>";

Final fixups

  • Run cargo +nightly fmt -p nautilus-binance to normalise the generator's whitespace.
  • Update the schema reference in this README and the mod.rs doc comment.
  • If the schema adds enum values or message types the adapter maps (e.g. symbolStatus), extend the corresponding match arms (e.g. common/status.rs) and add test cases.
  • Keep the requested SBE_SCHEMA_HEADER in spot/http/client.rs and the Spot SBE WebSocket API URLs in common/consts.rs aligned with the generated schema. Update test_sbe_schema_header, test_default_headers_include_sbe, and test_spot_sbe_ws_api_urls_use_current_schema when bumping the schema.
  • cargo build -p nautilus-binance and cargo test -p nautilus-binance must pass.
  • cargo clippy -p nautilus-binance --all-targets must pass.

Version compatibility

spot/http/parse.rs::MessageHeader::validate enforces the schema id but not the exact version, matching the WebSocket SBE path. Binance evolves a schema id additively and rolls new versions out gradually, so one client sees both versions mid-rollout. 3:4 and 3:5 share identical block layouts (only an added symbolStatus enum value), and unknown enum values decode to their null variant, so enforcing an exact version would only hard-fail instrument loading for no gain.

The decoders assume block layouts are stable within a schema id. decode_exchange_info verifies the symbol block length and fails loudly on a mismatch, but the market-data decoders (decode_depth, decode_trades) read groups at a fixed offset rather than advancing to the runtime block_length. A future version that appends fixed-block fields to those messages needs the affected decoder updated to skip the added bytes; regenerate the codecs whenever you need to decode new fields.