38#include "fastmm/core/config_macros.hpp"
39#include "fastmm/core/containers/ring_buffer.hpp"
40#include "fastmm/core/containers/static_vector.hpp"
55 StaticVector<Level, kMaxQuoteLevels>
bids;
56 StaticVector<Level, kMaxQuoteLevels>
asks;
70 [[nodiscard]]
const StaticVector<Level, kMaxQuoteLevels>&
side(
Side s)
const noexcept {
73 [[nodiscard]]
bool empty() const noexcept {
return bids.empty() &&
asks.empty(); }
77 return px.is_positive() && qty.is_positive() &&
bids.push_back(
Level{px, qty});
80 return px.is_positive() && qty.is_positive() &&
asks.push_back(
Level{px, qty});
129 std::uint64_t
news = 0;
152 [[nodiscard]]
const QuoteStats&
stats() const noexcept {
return stats_; }
155 InstState& st = state_[
id.value];
156 st.venue_no_replace = !on;
159 [[nodiscard]]
bool replaces(
InstrumentId id)
const noexcept {
return state_[
id.value].replace; }
162 [[nodiscard]]
static constexpr std::uint32_t
make_tag(
Side s, std::uint32_t level)
noexcept {
163 return 0x5100'0000U | (
static_cast<std::uint32_t
>(s) << 8) | level;
165 [[nodiscard]]
static constexpr bool is_quote_tag(std::uint32_t tag)
noexcept {
166 return (tag & 0xFFFF'0000U) == 0x5100'0000U;
170 template <
class Placer>
175 Placer&& place)
noexcept {
176 InstState& st = state_[inst.id.value];
178 st.resumable =
false;
180 std::uint32_t actions = 0;
182 const auto& want = st.desired.
side(side);
184 Slot& slot = st.slots[
static_cast<std::size_t
>(side)][lvl];
185 const bool has_want = lvl < want.size() && want[lvl].qty.is_positive();
186 actions += reconcile_slot(inst,
192 has_want ? want[lvl] :
Level{},
193 st.desired.account(side, lvl),
204 template <
class Placer>
208 bool keep_desired =
false) noexcept {
209 InstState& st = state_[inst.
id.
value];
211 st.resumable = st.resumable || (!st.pulled && !st.desired.empty());
213 st.resumable =
false;
217 std::uint32_t actions = 0;
220 Slot& slot = st.slots[
static_cast<std::size_t
>(side)][lvl];
221 slot.apply_want =
false;
222 if (!owns(oms, inst, side, lvl, slot))
continue;
223 const Order& o = oms.
get(slot.handle);
225 actions += cancel(inst, side, lvl, slot, place);
232 template <
class Placer>
236 Placer&& place)
noexcept {
237 InstState& st = state_[inst.id.value];
238 if (!st.resumable)
return 0;
243 return state_[
id.value].resumable;
247 [[nodiscard]]
bool starved() const noexcept {
return !starved_.empty(); }
248 [[nodiscard]] std::size_t
starved_count() const noexcept {
return starved_.size(); }
253 state_[
id.value].starved =
false;
258 template <
class Placer>
262 Placer&& place)
noexcept {
263 InstState& st = state_[inst.id.value];
264 if (st.pulled)
return 0;
274 template <
class Placer>
279 Placer&& place)
noexcept {
281 const Side side =
static_cast<Side>((u.order.user_tag >> 8) & 1U);
282 const std::uint32_t lvl = u.order.user_tag & 0xFFU;
284 InstState& st = state_[inst.id.value];
285 Slot& slot = st.slots[
static_cast<std::size_t
>(side)][lvl];
288 st.backoff[
static_cast<std::size_t
>(side)] =
Duration{};
289 if (!u.handle.valid() || slot.handle.idx != u.handle.idx ||
290 !owns(oms, inst, side, lvl, slot) || !u.order.is_working())
293 static_cast<void>(cancel(inst, side, lvl, slot, place));
296 if (slot.apply_want &&
298 slot.apply_want =
false;
299 static_cast<void>(reconcile_slot(
300 inst, st, oms, side, lvl, slot, slot.want, slot.want_account, now, place));
305 on_venue_reject(st, side, u.order.reject_reason, now);
309 if (owns(oms, inst, side, lvl, slot))
return;
312 slot.awaiting_terminal =
false;
313 if (st.pulled || !slot.apply_want)
return;
314 slot.apply_want =
false;
315 if (!slot.want.qty.is_positive())
return;
320 submit_new(inst, side, lvl, slot, slot.want, slot.want_account, now, place,
true);
325 std::uint32_t level)
const noexcept {
326 return state_[
id.value].slots[
static_cast<std::size_t
>(s)][level].handle;
328 [[nodiscard]]
bool pulled(
InstrumentId id)
const noexcept {
return state_[
id.value].pulled; }
331 return state_[
id.value].desired;
334 [[nodiscard]]
bool starved(
InstrumentId id)
const noexcept {
return state_[
id.value].starved; }
344 Timestamp last_requote{};
347 bool apply_want =
false;
348 bool awaiting_terminal =
false;
352 DesiredQuotes desired;
354 bool resumable =
false;
355 bool venue_no_replace =
false;
356 bool replace =
false;
357 Duration backoff[2] = {};
358 Timestamp blocked_until[2] = {};
359 bool starved =
false;
362 [[nodiscard]]
static bool backing_off(
const InstState& st,
Side side, Timestamp now)
noexcept {
363 const auto i =
static_cast<std::size_t
>(side);
364 return st.backoff[i].ns > 0 && now < st.blocked_until[i];
366 void on_venue_reject(InstState& st,
Side side,
RejectReason reason, Timestamp now)
noexcept {
370 const auto i =
static_cast<std::size_t
>(side);
371 Duration next = st.backoff[i].ns <= 0 ? params_.
reject_backoff : st.backoff[i] + st.backoff[i];
374 st.backoff[i] = next;
375 st.blocked_until[i] = now + next;
381 template <
class Placer>
382 std::uint32_t reconcile_slot(
const Instrument& inst,
391 Placer& place)
noexcept {
392 const bool has_want = target.qty.is_positive();
393 if (owns(oms, inst, side, lvl, slot)) {
394 const Order& o = oms.get(slot.handle);
399 slot.want_account = account;
400 slot.apply_want =
true;
403 slot.apply_want =
false;
404 if (!has_want)
return cancel(inst, side, lvl, slot, place);
406 if (account.valid() && o.venue != account) {
408 slot.want_account = account;
409 slot.apply_want =
true;
410 return cancel(inst, side, lvl, slot, place);
412 const std::int64_t dpx = (target.price - o.price).abs().raw / inst.tick.raw;
413 const bool qty_ok =
static_cast<Int128
>(o.leaves_qty().raw) * 10'000 >=
414 static_cast<Int128
>(target.qty.raw) * params_.
min_qty_bps;
437 held_back(st, inst.id, a);
441 slot.last_requote = now;
445 slot.want_account = account;
446 slot.apply_want =
true;
447 return cancel(inst, side, lvl, slot, place);
452 slot.handle = Handle<Order>{};
453 slot.awaiting_terminal =
false;
454 slot.apply_want =
false;
455 if (!has_want)
return 0;
460 return submit_new(inst, side, lvl, slot, target, account, now, place);
464 [[nodiscard]]
static bool owns(
const Oms& oms,
465 const Instrument& inst,
468 const Slot& slot)
noexcept {
469 if (!slot.handle.valid() || !oms.is_live(slot.handle))
return false;
470 const Order& o = oms.get(slot.handle);
471 return o.instrument == inst.id && o.user_tag ==
make_tag(side, lvl);
474 template <
class Placer>
475 std::uint32_t cancel(
476 const Instrument& inst,
Side side, std::uint32_t lvl, Slot& slot, Placer& place)
noexcept {
494 slot.awaiting_terminal =
true;
497 template <
class Placer>
498 std::uint32_t submit_new(
const Instrument& inst,
506 bool deferred =
false) noexcept {
520 if (!place(a) || !a.handle.valid()) {
524 held_back(state_[inst.id.value], inst.id, a);
529 slot.handle = a.handle;
530 slot.cl_ord_id = a.cl_ord_id;
531 slot.last_requote = now;
532 slot.awaiting_terminal =
false;
538 void held_back(InstState& st,
InstrumentId id,
const QuoteAction& a)
noexcept {
539 if (!a.rate_limited) {
544 if (st.starved)
return;
546 static_cast<void>(starved_.try_push(
static_cast<std::uint16_t
>(
id.value)));
549 void resolve_replace() noexcept {
550 for (InstState& st : state_) st.replace = params_.supports_replace && !st.venue_no_replace;
556 RingBuffer<std::uint16_t, kMaxInstruments> starved_;
const Order & get(Handle< Order > h) const noexcept
Definition oms.hpp:582
Definition quote_manager.hpp:145
const QuoteParams & params() const noexcept
Definition quote_manager.hpp:149
bool starved() const noexcept
Instruments whose quotes were held back for want of an order token, oldest first.
Definition quote_manager.hpp:249
std::uint32_t reconcile(const Instrument &inst, const DesiredQuotes &desired, const Oms &oms, Timestamp now, Placer &&place) noexcept
Reconciles desired vs resting for one instrument. Returns the number of actions placed.
Definition quote_manager.hpp:173
std::size_t starved_count() const noexcept
Definition quote_manager.hpp:250
static constexpr std::uint32_t make_tag(Side s, std::uint32_t level) noexcept
user_tag encoding so a terminal OmsUpdate can be mapped back to its slot.
Definition quote_manager.hpp:164
const QuoteStats & stats() const noexcept
Definition quote_manager.hpp:154
bool resumable(InstrumentId id) const noexcept
Definition quote_manager.hpp:244
bool backing_off(InstrumentId id, Side s, Timestamp now) const noexcept
The side is in its venue-reject backoff at now.
Definition quote_manager.hpp:338
std::uint32_t retry(const Instrument &inst, const Oms &oms, Timestamp now, Placer &&place) noexcept
Re-applies the last desired quotes of an instrument popped from the starved queue; one that was pulle...
Definition quote_manager.hpp:261
static constexpr bool is_quote_tag(std::uint32_t tag) noexcept
Definition quote_manager.hpp:167
const DesiredQuotes & desired(InstrumentId id) const noexcept
The last ladder reconcile() applied to the instrument (empty after a pull).
Definition quote_manager.hpp:332
std::uint32_t resume(const Instrument &inst, const Oms &oms, Timestamp now, Placer &&place) noexcept
Re-applies the desired quotes kept by pull_quotes(keep_desired). Returns the actions placed.
Definition quote_manager.hpp:235
void set_replace(InstrumentId id, bool on) noexcept
Whether the instrument's venue amends in place (default true; supports_replace still applies).
Definition quote_manager.hpp:156
bool replaces(InstrumentId id) const noexcept
Definition quote_manager.hpp:161
void set_params(const QuoteParams &p) noexcept
Definition quote_manager.hpp:150
Handle< Order > slot_handle(InstrumentId id, Side s, std::uint32_t level) const noexcept
Definition quote_manager.hpp:325
bool pulled(InstrumentId id) const noexcept
Definition quote_manager.hpp:330
void on_order_update(const OmsUpdate &u, const Instrument &inst, const Oms &oms, Timestamp now, Placer &&place) noexcept
Feed every OmsUpdate here.
Definition quote_manager.hpp:277
InstrumentId pop_starved() noexcept
Takes the oldest starved instrument off the queue (the caller checks starved() first).
Definition quote_manager.hpp:252
std::uint32_t pull_quotes(const Instrument &inst, const Oms &oms, Placer &&place, bool keep_desired=false) noexcept
Cancels every working quote on the instrument and suppresses re-quoting until the next reconcile().
Definition quote_manager.hpp:207
Instrument: the single definition of a tradable contract (5.3 / 5.15).
Event bus message structs (5.5).
Definition strategy.hpp:16
StrongId< struct ClientOrderTag, std::uint64_t, 0 > ClientOrderId
48-bit: session_epoch(16) << 32 | seq(32). 0 is never issued.
Definition strong_id.hpp:41
constexpr Duration milliseconds(std::int64_t v) noexcept
Definition time.hpp:38
constexpr bool is_pending(OrderState s) noexcept
Definition enums.hpp:93
RejectReason
Ordered exactly like RiskEngine::check_new evaluates them (5.7), followed by OMS / transport / venue ...
Definition enums.hpp:123
Side
Definition enums.hpp:12
Fixed< struct QtyTag > Qty
Definition fixed_point.hpp:333
StrongId< struct InstrumentTag, std::uint32_t > InstrumentId
Dense index into the engine's instrument table.
Definition strong_id.hpp:38
Fixed< struct PriceTag > Price
Definition fixed_point.hpp:332
constexpr std::size_t kMaxInstruments
Definition instrument.hpp:26
QuoteActionKind
Definition quote_manager.hpp:108
constexpr std::size_t kMaxQuoteLevels
Definition quote_manager.hpp:54
StrongId< struct VenueTag, std::uint8_t > VenueId
Definition strong_id.hpp:39
Order management (5.8): a Pool<Order> + OpenHashMap<ClientOrderId, Handle> + a ring of recently termi...
Definition quote_manager.hpp:56
StaticVector< Level, kMaxQuoteLevels > asks
Definition quote_manager.hpp:58
std::array< VenueId, kMaxQuoteLevels > ask_account
Definition quote_manager.hpp:62
void clear() noexcept
Definition quote_manager.hpp:63
const StaticVector< Level, kMaxQuoteLevels > & side(Side s) const noexcept
Definition quote_manager.hpp:72
VenueId account(Side s, std::uint32_t lvl) const noexcept
Definition quote_manager.hpp:69
bool bid(Price px, Qty qty) noexcept
Append the next level of a side (index 0 first).
Definition quote_manager.hpp:78
StaticVector< Level, kMaxQuoteLevels > bids
index 0 = closest to mid
Definition quote_manager.hpp:57
bool empty() const noexcept
Definition quote_manager.hpp:75
std::array< VenueId, kMaxQuoteLevels > bid_account
The pool account a level's order goes from (NewOrderRequest::account); invalid = the engine's automat...
Definition quote_manager.hpp:61
bool ask(Price px, Qty qty) noexcept
Definition quote_manager.hpp:81
void uncross(Price tick) noexcept
Never cross ourselves at level 0: an ask at or below the best bid moves one tick above it.
Definition quote_manager.hpp:85
std::int64_t ns
Definition time.hpp:23
Definition strong_id.hpp:54
Definition instrument.hpp:29
InstrumentId id
4
Definition instrument.hpp:42
One price level. Shared by book messages and the L2 book.
Definition messages.hpp:30
constexpr bool is_working() const noexcept
Definition order.hpp:49
Definition quote_manager.hpp:110
bool post_only
Definition quote_manager.hpp:119
bool withheld
New output: not sent, the balance does not cover it (deferred only)
Definition quote_manager.hpp:123
VenueId account
New: the pool account to send it from (invalid = automatic)
Definition quote_manager.hpp:127
bool rate_limited
New / Replace output: not sent, no order token for it now (QuoteParams::token_reserve); the instrumen...
Definition quote_manager.hpp:126
bool deferred
New: the target was recorded while an earlier order held the slot and is placed now that it ended (on...
Definition quote_manager.hpp:122
InstrumentId instrument
Definition quote_manager.hpp:112
Price price
Definition quote_manager.hpp:117
ClientOrderId cl_ord_id
New output (the placer fills it)
Definition quote_manager.hpp:116
Side side
Definition quote_manager.hpp:113
std::uint32_t level
Definition quote_manager.hpp:114
Qty qty
Definition quote_manager.hpp:118
QuoteActionKind kind
Definition quote_manager.hpp:111
Handle< Order > handle
Cancel/Replace input; New output.
Definition quote_manager.hpp:115
Definition quote_manager.hpp:91
Duration min_requote_interval
Definition quote_manager.hpp:93
Duration reject_backoff
0 = no backoff after venue rejects
Definition quote_manager.hpp:100
std::int64_t min_qty_bps
leaves >= 80 % of desired -> qty ok
Definition quote_manager.hpp:94
Duration reject_backoff_max
Definition quote_manager.hpp:101
std::int64_t min_requote_ticks
|desired - resting| < this -> keep
Definition quote_manager.hpp:92
std::int64_t token_reserve
Order tokens ([risk] orders_per_sec) a quote that does not reduce the position leaves for the orders ...
Definition quote_manager.hpp:105
bool replace_all_venues
Replace only if every instrument's venue can (the engine before replace was per venue; set to replay ...
Definition quote_manager.hpp:98
bool post_only
Definition quote_manager.hpp:99
bool supports_replace
off: never replace; on: where the instrument's venue can
Definition quote_manager.hpp:95
Definition quote_manager.hpp:130
std::uint64_t rejected
Definition quote_manager.hpp:137
std::uint64_t kept_hysteresis
Definition quote_manager.hpp:134
std::uint64_t cancels
Definition quote_manager.hpp:132
std::uint64_t kept_interval
Definition quote_manager.hpp:135
std::uint64_t reject_backoffs
venue rejects that started or extended a side backoff
Definition quote_manager.hpp:138
std::uint64_t retries
retry() calls that re-applied a starved instrument's quotes
Definition quote_manager.hpp:142
std::uint64_t kept_backoff
News withheld because their side was backing off.
Definition quote_manager.hpp:139
std::uint64_t news
Definition quote_manager.hpp:131
std::uint64_t skipped_pending
Definition quote_manager.hpp:136
std::uint64_t kept_balance
deferred News withheld: the balance no longer covers them
Definition quote_manager.hpp:140
std::uint64_t replaces
Definition quote_manager.hpp:133
std::uint64_t kept_rate_limit
News / Replaces held back for want of an order token.
Definition quote_manager.hpp:141
Rep value
Definition strong_id.hpp:26