QuoteManager (5.6): diffs the strategy's DesiredQuotes against the orders resting at the venue and emits the minimal set of New / Cancel / Replace actions.
More...
QuoteManager (5.6): diffs the strategy's DesiredQuotes against the orders resting at the venue and emits the minimal set of New / Cancel / Replace actions.
Rules:
- level i of a side maps to slot i (one order per slot);
- hysteresis: keep an order whose price is within min_requote_ticks of the desired price and whose leaves cover min_qty_bps of the desired quantity;
- never re-quote a slot within min_requote_interval of its last change;
- orders in a Pending* state are never touched: the slot records the target instead and applies it when the order's ack or terminal update arrives via on_order_update() (dropped if the instrument is pulled first);
- a slot only counts an order as its own if it is live and carries the slot's tag (order slots are reused, and a replace changes the order's id);
- while an instrument is pulled, an order that becomes working late (its ack arrived after the pull) is cancelled at once;
- a New rejected by the venue (other than a post-only cross) blocks new orders on that side for reject_backoff, doubling on each further reject up to reject_backoff_max and reset by an ack on that side, so an unfundable side is not resent on every requote;
- an instrument whose venue supports replace (set_replace(), with supports_replace) gets a single Replace; otherwise Cancel now and New only once the cancel's terminal update arrives via on_order_update() (cancel-then-new keeps momentary exposure down and never double-quotes a level, and the New is checked against the balance once the old order's hold is released);
- such a deferred New (QuoteAction::deferred) that the balance no longer covers -- the order it replaced filled instead of cancelling -- is withheld (QuoteAction::withheld, kept_balance) rather than refused by risk: the target predates the fill, the strategy's next quotes decide;
- pull_quotes(keep_desired) pauses an instrument (the engine during reconciliation): resume() re-applies the last desired quotes unless the instrument was pulled for good meanwhile;
- a New or Replace the placer holds back for want of an order token (QuoteAction::rate_limited) is neither a reject nor a backoff: the instrument joins a FIFO of starved instruments, and the engine re-applies their last desired quotes (retry()) in that order as tokens come back, so a burst of requotes on many instruments is served in turn instead of refused event by event.
Actions are executed by the caller through a Placer callable so the QuoteManager stays independent of risk/OMS/transport wiring: bool place(QuoteAction& a); // New: sets a.handle on success; returns false on reject