FastMM documentation
FastMM C++ API 0.6.0
Public headers, tier 1 and tier 2
Loading...
Searching...
No Matches
fastmm::Oms Class Reference

#include <fastmm/core/oms.hpp>

Public Member Functions

 Oms (std::uint16_t session_epoch=1, std::uint64_t max_seq=kMaxSeq) noexcept
 max_seq is the highest client order id sequence this session may issue; only tests lower it from kMaxSeq (reaching it takes 4.3 billion orders).
 
 Oms (const Oms &)=delete
 
Oms & operator= (const Oms &)=delete
 
std::uint16_t session_epoch () const noexcept
 
ClientOrderId next_cl_ord_id () noexcept
 An invalid id once the session's 32-bit sequence is used up: the wire form carries 48 bits (epoch 16 + seq 32), so reusing a sequence would repeat a ClientOrderId within the session and let a late venue message match the wrong order.
 
std::uint64_t ids_left () const noexcept
 Client order ids left in this session.
 
const OmsStats & stats () const noexcept
 
std::uint32_t open_count () const noexcept
 
std::uint32_t open_count (InstrumentId id) const noexcept
 
Qty open_qty (InstrumentId id, Side s) const noexcept
 Sum of leaves of open orders on (instrument, side): "in-flight same-side exposure".
 
Price best_own_px (InstrumentId id, Side s) const noexcept
 Best price among our own open orders on (instrument, side); Price{} if none. For STP.
 
Result< Handle< Order >, RejectReason > submit (const NewOrderRequest &req, ClientOrderId id, Timestamp now) noexcept
 
Result< void, RejectReason > request_cancel (Handle< Order > h) noexcept
 
Result< void, RejectReason > request_cancel_unacked (Handle< Order > h) noexcept
 Cancel of an order that is still waiting for its ack (the ack-timeout sweep only).
 
Result< void, RejectReason > request_replace (Handle< Order > h, ClientOrderId new_id, Price px, Qty qty, Timestamp now={}) noexcept
 new_id may equal the current id for venues that amend in place.
 
OmsUpdate on_ack (const OrderAckMsg &m) noexcept
 
OmsUpdate on_reject (const OrderRejectMsg &m) noexcept
 
OmsUpdate on_cancel_ack (const OrderCancelAckMsg &m) noexcept
 
OmsUpdate on_cancel_reject (const OrderCancelRejectMsg &m) noexcept
 
OmsUpdate on_fill (const OrderFillMsg &m) noexcept
 
OmsUpdate on_expired (const OrderExpiredMsg &m) noexcept
 
void reconcile_begin (VenueId venue=VenueId::invalid(), std::optional< ClientOrderId > sent_watermark=std::nullopt) noexcept
 Starts reconciling venue's orders (an invalid venue: every venue).
 
OmsUpdate reconcile_open_order (const ReconcileMsg &m) noexcept
 Venue reports an open order. Unknown -> CancelUnknown (engine cancels by venue id).
 
template<class F >
void reconcile_end (F &&f, VenueId venue=VenueId::invalid()) noexcept
 Every open order of venue (invalid: every venue) the snapshot did not report is marked Canceled, except orders sent after the snapshot was requested (see reconcile_begin).
 
template<class F >
std::size_t sweep_pending (Timestamp now, Duration timeout, F &&f) noexcept
 Orders still PendingNew timeout after they were submitted: the request or its ack was lost, and nothing else ever frees them.
 
const Order & get (Handle< Order > h) const noexcept
 
Order & get (Handle< Order > h) noexcept
 
bool is_live (Handle< Order > h) const noexcept
 
const OrderTimes & times (Handle< Order > h) const noexcept
 Send and ack times of an open order.
 
Handle< Order > find (ClientOrderId id) const noexcept
 
OrderClass classify (ClientOrderId id) const noexcept
 
template<class F >
void for_each_open_order (F &&f) const noexcept
 Ascending handle order (deterministic). F(Handle<Order>, const Order&).
 
template<class F >
void for_each_open_order (InstrumentId id, F &&f) const noexcept
 
void warm_up () noexcept
 

Constructor & Destructor Documentation

◆ Oms() [1/2]

fastmm::Oms::Oms ( std::uint16_t  session_epoch = 1,
std::uint64_t  max_seq = kMaxSeq 
)
inlineexplicitnoexcept

max_seq is the highest client order id sequence this session may issue; only tests lower it from kMaxSeq (reaching it takes 4.3 billion orders).

◆ Oms() [2/2]

fastmm::Oms::Oms ( const Oms &  )
delete

Member Function Documentation

◆ operator=()

Oms & fastmm::Oms::operator= ( const Oms &  )
delete

◆ session_epoch()

std::uint16_t fastmm::Oms::session_epoch ( ) const
inlinenoexcept

◆ next_cl_ord_id()

ClientOrderId fastmm::Oms::next_cl_ord_id ( )
inlinenoexcept

An invalid id once the session's 32-bit sequence is used up: the wire form carries 48 bits (epoch 16 + seq 32), so reusing a sequence would repeat a ClientOrderId within the session and let a late venue message match the wrong order.

The engine turns that into a kill switch.

◆ ids_left()

std::uint64_t fastmm::Oms::ids_left ( ) const
inlinenoexcept

Client order ids left in this session.

◆ stats()

const OmsStats & fastmm::Oms::stats ( ) const
inlinenoexcept

◆ open_count() [1/2]

std::uint32_t fastmm::Oms::open_count ( ) const
inlinenoexcept

◆ open_count() [2/2]

std::uint32_t fastmm::Oms::open_count ( InstrumentId  id) const
inlinenoexcept

◆ open_qty()

Qty fastmm::Oms::open_qty ( InstrumentId  id,
Side  s 
) const
inlinenoexcept

Sum of leaves of open orders on (instrument, side): "in-flight same-side exposure".

◆ best_own_px()

Price fastmm::Oms::best_own_px ( InstrumentId  id,
Side  s 
) const
inlinenoexcept

Best price among our own open orders on (instrument, side); Price{} if none. For STP.

◆ submit()

Result< Handle< Order >, RejectReason > fastmm::Oms::submit ( const NewOrderRequest &  req,
ClientOrderId  id,
Timestamp  now 
)
inlinenoexcept

< cannot fail: one entry per pool slot

◆ request_cancel()

Result< void, RejectReason > fastmm::Oms::request_cancel ( Handle< Order >  h)
inlinenoexcept

◆ request_cancel_unacked()

Result< void, RejectReason > fastmm::Oms::request_cancel_unacked ( Handle< Order >  h)
inlinenoexcept

Cancel of an order that is still waiting for its ack (the ack-timeout sweep only).

A venue that never saw the order answers VenueUnknownOrder, and on_cancel_reject ends it.

◆ request_replace()

Result< void, RejectReason > fastmm::Oms::request_replace ( Handle< Order >  h,
ClientOrderId  new_id,
Price  px,
Qty  qty,
Timestamp  now = {} 
)
inlinenoexcept

new_id may equal the current id for venues that amend in place.

now: the replace's send time, which becomes OrderTimes::sent once it is acknowledged.

◆ on_ack()

OmsUpdate fastmm::Oms::on_ack ( const OrderAckMsg &  m)
inlinenoexcept

< a live order we do not know: cancel it

Reconciliation took it for gone, yet the venue has it (the snapshot missed an order still in flight). Nothing tracks it any more: cancel it rather than leave it live.

< late ack for a terminal order

Only the replacement's ack completes it (the same id for an in-place amend). An ack that repeats the current id while a replace to a new id is in flight is a duplicate of the original ack (Binance sends one from the WS API response and one from the user stream): applying it would take the replace for confirmed, leave the new id mapped after the order ends and let the new leg's ack read a freed slot while that order stays live untracked.

An in-place amend keeps the venue's order even when it is given a new client id (Binance Spot keepPriority), so the fills booked against it stay.

< duplicate ack

A venue that answers twice (API response and user stream) may put its time on either.

◆ on_reject()

OmsUpdate fastmm::Oms::on_reject ( const OrderRejectMsg &  m)
inlinenoexcept

Replace failed. If the venue already cancelled the original (cancel-then-new style replace) the order is gone; otherwise it keeps working unchanged.

◆ on_cancel_ack()

OmsUpdate fastmm::Oms::on_cancel_ack ( const OrderCancelAckMsg &  m)
inlinenoexcept

Old leg of a cancel-then-new replace: wait for the new leg's ack/reject.

The cancel raced a fill that finished the order: it is Filled, not Canceled.

◆ on_cancel_reject()

OmsUpdate fastmm::Oms::on_cancel_reject ( const OrderCancelRejectMsg &  m)
inlinenoexcept

< e.g. already filled: ignore

The venue has no such order: it is gone (filled/cancelled elsewhere).

◆ on_fill()

OmsUpdate fastmm::Oms::on_fill ( const OrderFillMsg &  m)
inlinenoexcept

A replayed execution may be one the venue already counted into a cum_qty the engine booked as a synthetic fill. Taking that quantity out of the pool here is what keeps it from being booked twice, whether the order is still open, recently terminal or gone.

A live execution can also arrive after the cum_qty that covers it: venues that publish order states and executions on separate topics (Bybit's order and execution) may end an order with its cumulative quantity first. The quantity was booked then as a synthetic fill; the part of this execution at or below that cum_qty (this execution spans cum_qty - qty to cum_qty on the venue's count) is the estimate being named, not new quantity. Without a cum_qty (Deribit's trades) only an order that has ended can tell: the venue's final cum_qty was all it will ever fill, so the execution is within the estimate.

Only the part the position does not already hold moves the order forward: a replayed execution carries no cumulative quantity of its own.

< out-of-order cum: never go backwards

◆ on_expired()

OmsUpdate fastmm::Oms::on_expired ( const OrderExpiredMsg &  m)
inlinenoexcept

< an IOC that filled completely is Filled, not Expired

◆ reconcile_begin()

void fastmm::Oms::reconcile_begin ( VenueId  venue = VenueId::invalid(),
std::optional< ClientOrderId >  sent_watermark = std::nullopt 
)
inlinenoexcept

Starts reconciling venue's orders (an invalid venue: every venue).

sent_watermark is the highest id the venue had sent when it requested the snapshot: orders above it cannot be in the snapshot, and reconcile_end() leaves them alone. Without it every unreported order ends.

◆ reconcile_open_order()

OmsUpdate fastmm::Oms::reconcile_open_order ( const ReconcileMsg &  m)
inlinenoexcept

Venue reports an open order. Unknown -> CancelUnknown (engine cancels by venue id).

The venue has it, so a new order was accepted. A cancel or replace is left pending: its ack or reject is still on the way and settles the order (clearing it made that cancel ack look unsolicited while the quote manager kept the order as a working quote).

◆ reconcile_end()

template<class F >
void fastmm::Oms::reconcile_end ( F &&  f,
VenueId  venue = VenueId::invalid() 
)
inlinenoexcept

Every open order of venue (invalid: every venue) the snapshot did not report is marked Canceled, except orders sent after the snapshot was requested (see reconcile_begin).

F(const OmsUpdate&) runs after each order ends and outside the pool iteration, so it may place or cancel orders.

< not sent yet

Working quantity nobody accounted for: the snapshot proves the order is over, not how it ended. Treating it as cancelled is a guess, so report it instead of hiding it.

◆ sweep_pending()

template<class F >
std::size_t fastmm::Oms::sweep_pending ( Timestamp  now,
Duration  timeout,
F &&  f 
)
inlinenoexcept

Orders still PendingNew timeout after they were submitted: the request or its ack was lost, and nothing else ever frees them.

They hold a pool slot, a max_open_orders slot and same-side open quantity that feeds max_position, so the engine force-cancels them (the venue may know the order even though we never saw its ack). F(Handle<Order>, const Order&) runs outside the pool iteration, so it may send. Returns the number reported.

◆ get() [1/2]

const Order & fastmm::Oms::get ( Handle< Order >  h) const
inlinenoexcept

◆ get() [2/2]

Order & fastmm::Oms::get ( Handle< Order >  h)
inlinenoexcept

◆ is_live()

bool fastmm::Oms::is_live ( Handle< Order >  h) const
inlinenoexcept

◆ times()

const OrderTimes & fastmm::Oms::times ( Handle< Order >  h) const
inlinenoexcept

Send and ack times of an open order.

◆ find()

Handle< Order > fastmm::Oms::find ( ClientOrderId  id) const
inlinenoexcept

◆ classify()

OrderClass fastmm::Oms::classify ( ClientOrderId  id) const
inlinenoexcept

◆ for_each_open_order() [1/2]

template<class F >
void fastmm::Oms::for_each_open_order ( F &&  f) const
inlinenoexcept

Ascending handle order (deterministic). F(Handle<Order>, const Order&).

◆ for_each_open_order() [2/2]

template<class F >
void fastmm::Oms::for_each_open_order ( InstrumentId  id,
F &&  f 
) const
inlinenoexcept

◆ warm_up()

void fastmm::Oms::warm_up ( )
inlinenoexcept