Struct UdCore
pub struct UdCore { /* private fields */ }Expand description
Sans-io user data core: order statuses, fills and portfolio updates from the WebSocket channels.
It turns frames into Events (orders, executions, portfolio), delivers each
fill once even if the broker repeats it (de-duplicated by executionId, the last 20 000 are
remembered), and remembers which broker order id belongs to which client order id. It does no I/O.
§Examples
Feed one order event from the orders/events/ws channel and read the event it makes:
use std::time::Instant;
use brokapi_bcs_protocol::ws::client::BcsWsChannel;
use brokapi_bcs::UdCore;
use brokapi_core::{ClientOrderId, Event, OrderState, SubscriptionId};
use brokapi_sansio::{
BrokerCore, DesiredSubscription, EventSink, SubscriptionKind, SubscriptionSet,
};
let mut core = UdCore::new();
let sub = SubscriptionId::new(1001);
core.apply(&SubscriptionSet::with_subscriptions(vec![DesiredSubscription {
id: sub,
kind: SubscriptionKind::OrderState,
}]));
let cid = ClientOrderId::new_v4();
let frame = format!(
r#"{{"originalClientOrderId":"{cid}","clientOrderId":"{cid}","data":{{
"messageType":"8","orderStatus":"0","executionType":"0","orderQuantity":10,
"executedQuantity":0,"lastQuantity":0,"remainedQuantity":10,"ticker":"SBER",
"classCode":"TQBR","side":"1","orderType":"2","averagePrice":0,"price":100,
"orderId":"20261019-TQBR-1","currency":"RUB","transactionTime":"2026-10-19T10:00:00.000Z"}}}}"#
);
let mut out = EventSink::new();
core.feed_ws(BcsWsChannel::OrderEvents, &frame, Instant::now(), &mut out);
let events = out.drain();
assert_eq!(events.len(), 1);
assert_eq!(events[0].sub, Some(sub));
let Event::Order(order) = &events[0].payload else { panic!("an order event") };
assert!(matches!(order.state, OrderState::Acked { .. }));
// The core now knows which of our orders the broker's id is.
assert_eq!(core.cid_of_order_id("20261019-TQBR-1"), Some(cid));Implementations§
§impl UdCore
impl UdCore
pub fn new() -> UdCore
pub fn new() -> UdCore
Creates a core with no subscriptions and no known orders. The answer timer for a registered
place command is 30 seconds (see register_place).
pub fn learn_order_id(&mut self, order_id: &str, cid: Uuid)
pub fn learn_order_id(&mut self, order_id: &str, cid: Uuid)
Remembers that the broker’s order order_id is our cid.
pub fn cid_of_order_id(&self, order_id: &str) -> Option<Uuid>
pub fn cid_of_order_id(&self, order_id: &str) -> Option<Uuid>
Our cid of the broker’s order order_id, if this process has seen it.
pub fn orders(&self) -> &OrderRegistry
pub fn orders(&self) -> &OrderRegistry
The orders this core tracks (state machine per client order id).
pub fn orders_mut(&mut self) -> &mut OrderRegistry
pub fn orders_mut(&mut self) -> &mut OrderRegistry
The same registry, for changes. Meant for tests and replays.
pub fn register_place(&mut self, cid: Uuid, now: Instant)
pub fn register_place(&mut self, cid: Uuid, now: Instant)
Registers a place command that was just sent, and starts the 30 second answer timer for it.
UserDataConnector does not call it (it tracks sent orders in its
own runtime). It is here to drive the core by hand.
pub fn on_incoming(
&mut self,
msg: IncomingMessage,
now: Instant,
out: &mut EventSink,
)
pub fn on_incoming( &mut self, msg: IncomingMessage, now: Instant, out: &mut EventSink, )
Handles one message already parsed by the protocol layer.
This is what the pump calls. Order messages push Event::Order, and a message with a fill
(lastQuantity above zero) also pushes Event::Execution once per executionId, but only
while somebody is subscribed to executions. Portfolio messages push Event::Portfolio. Other
messages are skipped.
pub fn feed_ws(
&mut self,
channel: BcsWsChannel,
text: &str,
now: Instant,
out: &mut EventSink,
)
pub fn feed_ws( &mut self, channel: BcsWsChannel, text: &str, now: Instant, out: &mut EventSink, )
Parses one raw text frame of a WebSocket channel and handles it like
on_incoming. A frame that cannot be parsed is skipped, there is no
error to return.
Trait Implementations§
§impl BrokerCore for UdCore
impl BrokerCore for UdCore
§type Frame = UdFrame
type Frame = UdFrame
String for WebSocket text, or a decoded message.§fn on_frame(
&mut self,
frame: <UdCore as BrokerCore>::Frame,
now: Instant,
out: &mut EventSink,
)
fn on_frame( &mut self, frame: <UdCore as BrokerCore>::Frame, now: Instant, out: &mut EventSink, )
now. Read more§fn poll_transmit(&mut self) -> Option<Outbound>
fn poll_transmit(&mut self) -> Option<Outbound>
None.§fn poll_timeout(&self) -> Option<Instant>
fn poll_timeout(&self) -> Option<Instant>
§fn on_timeout(&mut self, now: Instant, out: &mut EventSink)
fn on_timeout(&mut self, now: Instant, out: &mut EventSink)
now is the time the timer was due.Auto Trait Implementations§
impl Freeze for UdCore
impl RefUnwindSafe for UdCore
impl Send for UdCore
impl Sync for UdCore
impl Unpin for UdCore
impl UnsafeUnpin for UdCore
impl UnwindSafe for UdCore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request§impl<L> LayerExt<L> for L
impl<L> LayerExt<L> for L
§fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>where
L: Layer<S>,
Layered].