# SBE Encoding

JSON is human-readable and works everywhere, but it is verbose. Decimal
values encoded as strings are particularly wasteful. The **Market Data
Adapter** also publishes the same data over **SBE**
(<https://www.fixtrading.org/standards/sbe/>) for clients that want
something denser and faster to parse.

## Characteristics

- Every SBE message is semantically identical to its JSON counterpart
  and exposes the same fields.
- Encoders and decoders are generated automatically from the SBE schema.
- Most schema-defined data maps directly to the JSON documentation.
- One exception: decimals (mostly prices and quantities) need a custom
  encoding. See below.

## Schema metadata

| Field        | Value           |
|--------------|-----------------|
| `id`         | `1`             |
| `version`    | `7`             |
| `byteOrder`  | `littleEndian`  |
| `package`    | `com.cryptostruct.commons.events.marketdata.sbe.v6` |

Each message starts with a fixed `messageHeader` composite, six 16-bit
unsigned integers in this order:

| Field              | Type     | Description                                   |
|--------------------|----------|-----------------------------------------------|
| `blockLength`      | `uint16` | Size of the fixed-length root block in bytes  |
| `templateId`       | `uint16` | Identifies the message type (see table below) |
| `schemaId`         | `uint16` | Always `1`                                    |
| `version`          | `uint16` | Schema version of the encoded message         |
| `numGroups`        | `uint16` | Number of repeating groups in the root block  |
| `numVarDataFields` | `uint16` | Number of variable-length fields after groups |

## Template IDs

| ID     | Message                     | Direction          |
|--------|-----------------------------|--------------------|
| `1000` | `snapshotEvent`             | Server -> Client   |
| `1001` | `snapshotUpdateEvent`       | Server -> Client   |
| `1002` | `tradesEvent`               | Server -> Client   |
| `1005` | `stateEvent`                | Server -> Client   |
| `1006` | `tobEvent`                  | Server -> Client   |
| `1007` | `markPriceEvent`            | Server -> Client   |
| `1008` | `indexPriceEvent`           | Server -> Client   |
| `1009` | `fundingRateEvent`          | Server -> Client   |
| `1011` | `subscribeRequestMessage`   | Client -> Server   |
| `1012` | `unsubscribeRequestMessage` | Client -> Server   |
| `1013` | `loginRequestMessage`       | Client -> Server   |
| `1014` | `loginResponseMessage`      | Server -> Client   |
| `1017` | `liquidationsEvent`         | Server -> Client   |

## Using SBE

To consume SBE instead of JSON:

1. Connect to the SBE endpoint or domain socket
   (see [Accessing Data](accessing-data.md) for endpoint discovery).
2. Flag your messages as binary. WebSockets do this natively. For
   domain sockets, see [Binary Framing](binary-framing.md).

> [!NOTE]
> The stand-alone release of the market-data protocol specification
> contains the SBE schema and sample data for every message in both
> JSON and SBE encoding. Download it from
> [cryptostruct.com/download](https://cryptostruct.com/download).

---

## Decimal encoding

The CryptoStruct trading system handles numbers with up to **18 decimal
places**. SBE's primitive number types (and most languages' primitive
types) cannot represent that range reliably, so decimals get a custom
encoding.

### Representation

A decimal is a pair:

- **Unscaled value**: an arbitrarily large integer.
- **Scale**: an integer.

The number is reconstructed as:

```
number = unscaled * (10 ^ -scale)
```

### SBE storage

- **Unscaled value**: a byte array, sized to the number's actual width.
    - Negative values use **two's complement**
      (<https://en.wikipedia.org/wiki/Two%27s_complement>).
    - Byte order: big-endian (most significant byte first).
- **Scale**: an 8-bit integer.

## Example

```
unscaled value: [4, 1]
scale: 2

The two bytes of the unscaled value form a 16-bit integer with value 1025:

1025 * (10 ^ -2) = 10.25
```

---
