14#include "fastmm/core/config_macros.hpp"
15#include "fastmm/core/containers/static_vector.hpp"
25template <std::
size_t kMaxDepth = 256>
27 static_assert(kMaxDepth >= 2);
30 static constexpr std::size_t
kDepth = kMaxDepth;
37 void clear() noexcept {
40 truncated_[0] = truncated_[1] =
false;
41 have_snapshot_ =
false;
49 auto& v = levels(side);
52 std::size_t i = v.size();
57 const Price p = v[i - 1].price;
63 if (
better(side, price, p))
break;
66 if (!found && i == stop && stop > 0) {
69 std::size_t hi = stop;
71 const std::size_t
mid = lo + (hi - lo) / 2;
79 found = i < v.size() && v[i].price == price;
89 if (qty.is_zero())
return true;
90 if (FASTMM_UNLIKELY(v.full())) {
91 truncated_[
static_cast<std::size_t
>(side)] =
true;
92 if (i == 0)
return false;
96 v.insert_at(i, Level{price, qty});
101 std::span<const Level> asks,
107 have_snapshot_ =
true;
117 if (d.is_snapshot()) {
124 if (FASTMM_UNLIKELY((d.hdr.flags & kCut) != 0)) trim_truncated(d);
125 seq_ = d.last_update_id;
130 void set_seq(std::uint64_t s)
noexcept { seq_ = s; }
137 return bids_.empty() ?
Level{} : bids_.back();
140 return asks_.empty() ?
Level{} : asks_.back();
143 if (bids_.empty() || asks_.empty())
return Price{};
144 return Price::from_raw((bids_.back().price.raw + asks_.back().price.raw) / 2);
147 if (bids_.empty() || asks_.empty())
return Price{};
148 return asks_.back().price - bids_.back().price;
152 const auto& v = levels(side);
153 return i < v.size() ? v[v.size() - 1 - i] :
Level{};
155 [[nodiscard]] std::size_t
depth(
Side side)
const noexcept {
return levels(side).size(); }
156 [[nodiscard]] std::size_t
depth() const noexcept {
return bids_.size() + asks_.size(); }
160 const auto& v = levels(side);
162 for (std::size_t i = v.size(); i > 0; --i) {
163 const Level& l = v[i - 1];
172 const auto& v = levels(side);
174 for (std::size_t i = v.size(); i > 0; --i) {
176 if (cum >= qty)
return v[i - 1].price;
183 const auto& v = levels(side);
184 for (std::size_t i = v.size(); i > 0; --i) {
185 if constexpr (std::is_same_v<std::invoke_result_t<F, const Level&>,
bool>) {
186 if (!f(v[i - 1]))
return;
192 template <std::
size_t N>
195 const auto& v = levels(side);
196 const std::size_t n = v.size() < N ? v.size() : N;
197 for (std::size_t i = 0; i < n; ++i) out.
levels[i] = v[v.size() - 1 - i];
198 out.
count =
static_cast<std::uint32_t
>(n);
203 return !bids_.empty() && !asks_.empty() && bids_.back().price >= asks_.back().price;
207 return crossed_since_.
valid() ? now - crossed_since_ :
Duration{};
210 return truncated_[
static_cast<std::size_t
>(side)];
212 [[nodiscard]]
bool truncated() const noexcept {
return truncated_[0] || truncated_[1]; }
213 [[nodiscard]]
bool has_snapshot() const noexcept {
return have_snapshot_; }
215 return have_snapshot_ && !bids_.empty() && !asks_.empty() && !
crossed();
217 [[nodiscard]] std::uint64_t
seq() const noexcept {
return seq_; }
221 [[nodiscard]]
const StaticVector<Level, kMaxDepth>&
raw(
Side side)
const noexcept {
226 FASTMM_FORCE_INLINE StaticVector<Level, kMaxDepth>& levels(
Side s)
noexcept {
229 FASTMM_FORCE_INLINE
const StaticVector<Level, kMaxDepth>& levels(
Side s)
const noexcept {
236 [[gnu::noinline, gnu::cold]]
void trim_truncated(
const BookDeltaMsg& d)
noexcept {
240 void trim_behind(
Side side, std::span<const Level> carried)
noexcept {
241 if (carried.empty())
return;
242 Price bound = carried[0].price;
243 for (
const Level& l : carried) {
244 if (
better(side, bound, l.price)) bound = l.price;
246 auto& v = levels(side);
248 while (k < v.size() &&
better(side, bound, v[k].price)) ++k;
251 truncated_[
static_cast<std::size_t
>(side)] =
true;
253 void update_crossed(Timestamp ts)
noexcept {
255 if (!crossed_since_.
valid()) crossed_since_ = ts;
257 crossed_since_ = Timestamp{};
261 StaticVector<Level, kMaxDepth> bids_;
262 StaticVector<Level, kMaxDepth> asks_;
263 std::uint64_t seq_ = 0;
264 Timestamp last_update_{};
265 Timestamp crossed_since_{};
266 bool truncated_[2] = {
false,
false};
267 bool have_snapshot_ =
false;
270static_assert(BookView<L2Book<256>>);
BookView: the read interface every book implementation (L2Book, L3Book::to_l2 view,...
void mark_snapshot() noexcept
Definition l2_book.hpp:133
std::size_t depth() const noexcept
Definition l2_book.hpp:156
Price price_for_qty(Side side, Qty qty) const noexcept
Price of the level at which cumulative quantity from the best reaches qty; Price{} if the side is too...
Definition l2_book.hpp:171
void clear() noexcept
Definition l2_book.hpp:38
Price mid() const noexcept
Definition l2_book.hpp:142
std::uint64_t seq() const noexcept
Definition l2_book.hpp:217
bool is_valid() const noexcept
Definition l2_book.hpp:214
Qty qty_at_or_better(Side side, Price limit) const noexcept
Total quantity on side at prices at-or-better than limit.
Definition l2_book.hpp:159
Level level(Side side, std::size_t i) const noexcept
i == 0 is best. Level{} if out of range.
Definition l2_book.hpp:151
Timestamp last_update() const noexcept
Definition l2_book.hpp:218
void for_each_level(Side side, F &&f) const noexcept
Visits levels best-first. F(const Level&) may return bool (false stops) or void.
Definition l2_book.hpp:182
static constexpr std::size_t kLinearScan
Definition l2_book.hpp:33
Price spread() const noexcept
Definition l2_book.hpp:146
std::size_t depth(Side side) const noexcept
Definition l2_book.hpp:155
bool truncated(Side side) const noexcept
Definition l2_book.hpp:209
bool crossed() const noexcept
Definition l2_book.hpp:202
bool truncated() const noexcept
Definition l2_book.hpp:212
void set_seq(std::uint64_t s) noexcept
Definition l2_book.hpp:131
void apply_snapshot(std::span< const Level > bids, std::span< const Level > asks, std::uint64_t seq, Timestamp ts) noexcept
Definition l2_book.hpp:101
FASTMM_FORCE_INLINE Level best_ask() const noexcept
Definition l2_book.hpp:139
FASTMM_FORCE_INLINE bool apply_level(Side side, Price price, Qty qty) noexcept
Sets/updates/deletes (qty == 0) one level.
Definition l2_book.hpp:49
static constexpr std::size_t kDepth
Definition l2_book.hpp:32
const StaticVector< Level, kMaxDepth > & raw(Side side) const noexcept
Raw access (worst..best order) for tests/tools.
Definition l2_book.hpp:221
void set_last_update(Timestamp t) noexcept
Definition l2_book.hpp:132
Duration crossed_for(Timestamp now) const noexcept
How long the book has been crossed as of now (zero if not crossed).
Definition l2_book.hpp:206
bool has_snapshot() const noexcept
Definition l2_book.hpp:213
FASTMM_FORCE_INLINE Level best_bid() const noexcept
Definition l2_book.hpp:136
L2Book() noexcept=default
void apply_delta(const BookDeltaMsg &d) noexcept
Applies a BookDeltaMsg (or snapshot with kSnapshot).
Definition l2_book.hpp:116
TopLevels< N > top(Side side) const noexcept
Definition l2_book.hpp:193
Event bus message structs (5.5).
Definition strategy.hpp:16
Side
Definition enums.hpp:12
Fixed< struct QtyTag > Qty
Definition fixed_point.hpp:333
constexpr bool at_or_better(Side s, Price p, Price q) noexcept
true if p is at least as good as q from the point of view of side s.
Definition book_view.hpp:45
Fixed< struct PriceTag > Price
Definition fixed_point.hpp:332
constexpr bool better(Side s, Price p, Price q) noexcept
Definition book_view.hpp:48
Bids then asks follow the fixed part as a flexible array of Level (bid_count + ask_count).
Definition messages.hpp:99
static constexpr Fixed from_raw(std::int64_t r) noexcept
Definition fixed_point.hpp:155
One price level. Shared by book messages and the L2 book.
Definition messages.hpp:30
Price price
Definition messages.hpp:31
Qty qty
Definition messages.hpp:32
constexpr bool valid() const noexcept
Definition time.hpp:55
Fixed-size result of top<N>().
Definition book_view.hpp:20
std::uint32_t count
Definition book_view.hpp:22
Level levels[N]
Definition book_view.hpp:21