15#include "fastmm/core/config_macros.hpp"
40 return "sequence gap";
42 return "buffer overflow";
44 return "snapshot too old";
50 return "checksum mismatch";
70struct BinanceSpotSyncTraits {
74 return d.last_update_id <= snap;
77 return d.first_update_id <= snap + 1 && snap + 1 <= d.last_update_id;
80 return d.first_update_id == prev_u + 1;
91 return d.last_update_id < snap;
94 return d.first_update_id <= snap && d.last_update_id >= snap;
97 return d.prev_update_id == prev_u;
109 return d.last_update_id <= snap;
112 return d.last_update_id > snap;
115 return d.last_update_id > prev_u;
118 return d.last_update_id == 1 && !d.is_snapshot();
122template <
class Traits,
class Sink>
129 : sink_(sink), buf_bytes_(Traits::kBuffersDeltas ? buffer_bytes : 0) {
130 if (buf_bytes_ > 0) {
131 buf_.reset(
new std::byte[buf_bytes_]);
139 [[nodiscard]] std::uint32_t
resync_count() const noexcept {
return resyncs_; }
140 [[nodiscard]] std::size_t
buffered() const noexcept {
return count_; }
143 void start() noexcept {
145 awaiting_first_ =
false;
147 if constexpr (Traits::kNeedsRestSnapshot) sink_.request_snapshot();
154 sink_.on_resync(reason);
161 if (d.is_snapshot()) {
165 if (Traits::is_snapshot_marker(d)) {
174 if constexpr (Traits::kBuffersDeltas) {
179 if constexpr (Traits::kBuffersDeltas) {
183 if (FASTMM_UNLIKELY(awaiting_first_)) {
184 if (Traits::is_stale(d, prev_u_))
return;
185 if (!Traits::first_applies(d, prev_u_)) {
189 awaiting_first_ =
false;
190 prev_u_ = d.last_update_id;
195 if (FASTMM_LIKELY(Traits::next_applies(d, prev_u_))) {
196 prev_u_ = d.last_update_id;
198 }
else if (!Traits::is_stale(d, prev_u_)) {
207 void on_snapshot(
const BookDeltaMsg& snap)
noexcept {
209 const std::uint64_t L = snap.last_update_id;
210 if constexpr (Traits::kBuffersDeltas) {
213 while (i < count_ && Traits::is_stale(*at(i), L)) ++i;
214 if (i < count_ && !Traits::first_applies(*at(i), L)) {
221 sink_.request_snapshot();
224 sink_.on_snapshot(snap);
228 for (; i < count_; ++i) {
230 const bool ok = first ? Traits::first_applies(d, L) : Traits::next_applies(d, prev_u_);
237 awaiting_first_ =
false;
239 sink_.request_snapshot();
246 awaiting_first_ = first;
249 sink_.on_snapshot(snap);
259 void resync_keeping(
const BookDeltaMsg& d)
noexcept {
261 if constexpr (Traits::kBuffersDeltas) {
266 bool buffer(
const BookDeltaMsg& d)
noexcept {
267 if (count_ >=
kMaxBuffered || used_ + d.hdr.len > buf_bytes_)
return false;
268 std::memcpy(buf_.get() + used_, &d, d.hdr.len);
269 offsets_[count_++] =
static_cast<std::uint32_t
>(used_);
273 [[nodiscard]]
const BookDeltaMsg* at(std::size_t i)
const noexcept {
274 return reinterpret_cast<const BookDeltaMsg*
>(buf_.get() + offsets_[i]);
276 void drop_front(std::size_t n)
noexcept {
282 const std::uint32_t base = offsets_[n];
283 std::memmove(buf_.get(), buf_.get() + base, used_ - base);
284 for (std::size_t i = n; i < count_; ++i) offsets_[i - n] = offsets_[i] - base;
288 void reset_buffer() noexcept {
295 bool awaiting_first_ =
false;
296 std::uint64_t prev_u_ = 0;
297 std::uint32_t resyncs_ = 0;
298 std::unique_ptr<std::byte[]> buf_;
299 std::unique_ptr<std::uint32_t[]> offsets_;
300 std::size_t buf_bytes_;
301 std::size_t used_ = 0;
302 std::size_t count_ = 0;
Definition book_syncer.hpp:125
static constexpr std::size_t kDefaultBufferBytes
Definition book_syncer.hpp:128
bool synced() const noexcept
Definition book_syncer.hpp:139
void resync(SyncReason reason) noexcept
Force a resync (e.g. crossed book beyond grace, or a disconnect).
Definition book_syncer.hpp:153
std::uint32_t resync_count() const noexcept
Definition book_syncer.hpp:141
std::uint64_t last_update_id() const noexcept
Definition book_syncer.hpp:140
void on_delta(const BookDeltaMsg &d) noexcept
Delta from the stream.
Definition book_syncer.hpp:162
SyncState state() const noexcept
Definition book_syncer.hpp:138
void start() noexcept
Begin (or restart) synchronisation.
Definition book_syncer.hpp:145
std::size_t buffered() const noexcept
Definition book_syncer.hpp:142
void on_snapshot(const BookDeltaMsg &snap) noexcept
Snapshot (REST response or in-stream snapshot). Replays the buffer.
Definition book_syncer.hpp:209
static constexpr std::size_t kMaxBuffered
Definition book_syncer.hpp:127
Event bus message structs (5.5).
Definition strategy.hpp:16
SyncState
Definition book_syncer.hpp:27
SyncReason
Definition book_syncer.hpp:28
@ ChecksumMismatch
the venue's book checksum disagrees with ours (OKX)
@ SnapshotTooOld
buffered deltas start after the snapshot; need a newer one
@ SnapshotMarker
venue signalled a reset (Bybit u == 1)
constexpr std::string_view to_string(ParamType t) noexcept
Definition params.hpp:63
Binance USDT-M futures: first applied delta must have U <= L and u >= L; afterwards each delta's pu m...
Definition book_syncer.hpp:89
static constexpr bool kBuffersDeltas
Definition book_syncer.hpp:91
static constexpr bool is_snapshot_marker(const BookDeltaMsg &) noexcept
Definition book_syncer.hpp:101
static constexpr bool kNeedsRestSnapshot
Definition book_syncer.hpp:90
static constexpr bool next_applies(const BookDeltaMsg &d, std::uint64_t prev_u) noexcept
Definition book_syncer.hpp:98
static constexpr bool first_applies(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:95
static constexpr bool is_stale(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:92
static constexpr bool kBuffersDeltas
Definition book_syncer.hpp:74
static constexpr bool next_applies(const BookDeltaMsg &d, std::uint64_t prev_u) noexcept
Definition book_syncer.hpp:81
static constexpr bool is_snapshot_marker(const BookDeltaMsg &) noexcept
Definition book_syncer.hpp:84
static constexpr bool kNeedsRestSnapshot
Definition book_syncer.hpp:73
static constexpr bool first_applies(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:78
static constexpr bool is_stale(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:75
Bids then asks follow the fixed part as a flexible array of Level (bid_count + ask_count).
Definition messages.hpp:99
std::uint64_t last_update_id
Binance u / Bybit u.
Definition messages.hpp:104
Bybit v5: the stream itself sends a snapshot first (kSnapshot flag), then deltas whose u must be stri...
Definition book_syncer.hpp:107
static constexpr bool next_applies(const BookDeltaMsg &d, std::uint64_t prev_u) noexcept
Definition book_syncer.hpp:116
static constexpr bool kBuffersDeltas
Definition book_syncer.hpp:109
static constexpr bool is_snapshot_marker(const BookDeltaMsg &d) noexcept
Definition book_syncer.hpp:119
static constexpr bool is_stale(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:110
static constexpr bool first_applies(const BookDeltaMsg &d, std::uint64_t snap) noexcept
Definition book_syncer.hpp:113
static constexpr bool kNeedsRestSnapshot
Definition book_syncer.hpp:108