Top-of-Book over RF
Besides the request/response protocol served over WebSocket, the Market Data Adapter can push top-of-book updates as bare UDP datagrams. Each datagram carries exactly one top-of-book event in a compact binary encoding, with no framing, no handshake, and no acknowledgement.
The encoding is compact enough to travel over RF (radio) links, which is what it was built for. An RF hop between two regions can beat the fibre route, and top-of-book is the one topic worth the scarce bandwidth on such a link.
Two ways to receive it
Through a regional proxy
This is the normal setup, and the one to assume unless you have agreed otherwise. CryptoStruct operates proxy services in the target region. A proxy consumes the RF/UDP stream and forwards the updates to you over a regular WebSocket connection.
Nothing changes on your side:
-
Same protocol, same login, same subscriptions, same choice of JSON or SBE.
-
Same delivery guarantees, because the transport to you stays TCP-based.
-
Every market-data topic stays available on that one connection, not just top-of-book.
-
Top-of-book simply arrives earlier. You profit from the RF path automatically.
Nothing on this page applies to you in that case. It is worth reading only if you are considering the direct path below.
Directly over UDP
Reading the datagrams yourself removes the proxy hop, which is as low as the latency goes. In exchange you take on everything the proxy would otherwise absorb:
-
Packet loss, duplication, and reordering, which you have to detect yourself (see
Detecting packet loss ). -
Top-of-book only, for a fixed set of instruments, in selected regions.
-
The decoder described in the rest of this page.
Worth it when you have measured that the proxy hop costs you something that matters. Otherwise the proxy is the better trade.
Warning
UDP gives no delivery and no ordering guarantees. Packets can be lost,
duplicated, or reordered, and nothing is resent. Always track the
sequence number described in
Availability
The RF infrastructure exists in selected regions only, and link capacity is scarce enough that each one carries a fixed set of instruments. Contact CryptoStruct to find out what is available at your location.
For the direct path there is no login and no subscription. You agree a host, a port, and a set of instruments with CryptoStruct, and the Market Data Adapter pushes those instruments to that address for as long as it runs.
What this means in practice:
-
Only the agreed instruments arrive. The set is fixed up front. You cannot request an instrument at runtime, and nothing outside the set is ever broadcast. To add or remove instruments, contact CryptoStruct.
-
The feed is not tied to a connection. Packets start arriving as soon as the market moves, whether or not you have anything else connected, and there is nothing to reconnect after an outage on your side.
-
Receiving is a plain UDP read. Bind a UDP socket to the agreed port and read datagrams. Nothing else is required, and nothing is sent back.
For anything outside the agreed set, or for any other market-data topic, use a WebSocket connection with the regular subscription flow. Running both side by side is normal: UDP for the instruments you care about most, the regular connection for everything else.
Packet layout
One event per datagram. A UDP datagram is self-delimiting.
All multi-byte integers are big-endian (network byte order).
Warning
This is the opposite of SBE, which is little-endian. Only the decimal mantissa is big-endian in both encodings.
Header
A fixed 30-byte header:
Send time and sequence number
sendTimeAndSequence packs two values into one 64-bit integer:
sendTime = sendTimeAndSequence >> 12
sequence = sendTimeAndSequence & 0xFFF
52 bits of microseconds last until the year 2112. Because the send time
occupies the upper bits, the packed value as a whole increases
monotonically from packet to packet. See
Decimal fields
The header is followed by exactly four variable-length decimal fields, in this fixed order:
- bid price
- bid quantity
- ask price
- ask quantity
Each field is encoded as:
The value is reconstructed exactly as for SBE decimals:
number = mantissa * (10 ^ -scale)
See Decimal encoding for the full explanation.
The mantissa is written at its minimal width, so N is at most 16. A
present value of zero is encoded with length = 1 and a single 0x00
mantissa byte, which is what distinguishes it from an absent field.
Absent sides
A side (bid or ask) counts as present only if both its price and its
quantity carry a mantissa. An absent side is encoded as four zero bytes:
scale = 0 and length = 0 for its price and for its quantity.
Unlike the JSON and SBE top-of-book events, where the order of the two sides is undefined, the UDP layout is positional: bid always comes before ask.
Packet size
Example
Instrument 42, send time 1700000000000000 µs, sequence number
999, event ID 100, exchange timestamp 1500 µs and adapter
timestamp 40 µs before the send time, bid 99.50 for 1.25, ask
99.51 for 4.00. 45 bytes in total:
Detecting packet loss
The 12-bit sequence is assigned by the broadcaster and increments by
exactly 1 per packet sent, wrapping from 4095 back to 0. There is
one sequence per feed, shared by all instruments sent to your address,
not one per instrument. It starts at 0 when the adapter starts.
How to use it:
- Track the last seen
sequencefor the feed. - Compute the distance modulo 4096:
gap = (sequence - last) & 0xFFF. gap == 1means the packet is the expected next one.- Any other value means packets were lost, or this packet is a duplicate or arrived out of order.
To tell loss apart from duplicates and reordering, compare the full
64-bit sendTimeAndSequence value with the last one seen. It increases
monotonically, so a value that is not larger than the last one belongs to
a duplicate or a reordered packet, and should be dropped. The send time
also covers what the 12-bit sequence cannot: a gap of 4096 packets or
more, and adapter restarts, which reset the sequence to 0 but never move
the send time backwards.
The sequence number is not the market-data event ID. eventId
identifies the market-data event and is carried separately in the same
packet, so a gap in eventId does not imply packet loss (not every event
is broadcast) and a gap in sequence does.
Timestamps
Timestamps on the wire have microsecond resolution, not the nanoseconds of the JSON and SBE protocols.
The exchange and adapter timestamps have the same meaning as in the JSON
protocol, but are not sent as absolute values. Each
is sent as its age relative to sendTime, which fits into 32 bits:
exchangeTimestamp = sendTime - exchangeTimestampAge
adapterTimestamp = sendTime - adapterTimestampAge
Details:
-
An
exchangeTimestampAgeof0xFFFFFFFFmeans the exchange did not supply a timestamp. -
Ages are capped at
0xFFFFFFFEµs (about 71 minutes). An older timestamp decodes as exactly that far before the send time. -
A timestamp ahead of the send time, for example because of exchange clock skew, is sent as age
0and decodes as equal to the send time.
sendTime is taken when the packet leaves the broadcaster. Comparing it with your own receive time
gives the one-way latency of the link, provided the clocks are
synchronised.
Validation
Reject a datagram when:
- It is shorter than the 30-byte header.
protocolVersionis not1.messageTypeis not6.- A
lengthbyte exceeds16. - A
lengthbyte claims more mantissa bytes than the datagram still holds, or the variable section is cut mid-field.
Because packets arrive unsolicited from the network, treat every one of these as a malformed packet to drop and count, not as a fatal error.
Comparison with the proxy path
Both paths carry the same RF-accelerated top-of-book data. They differ in what you have to handle.
Because no previous event ID is transmitted, a UDP receiver cannot chain events the way a book-building client does. This is not a limitation in practice: each packet carries the complete top of book, so the latest packet is always sufficient on its own.
See Also
- Accessing Data. How to connect and subscribe.
- Protocol. Market data protocol specification.
- SBE Encoding. Simple Binary Encoding and decimal encoding.