brokapi_sansio/subscription.rs
1//! Desired subscription set passed into sans-io cores.
2
3use brokapi_core::{InstrumentId, SubscriptionId, Timeframe};
4
5/// Kind of streaming subscription the connector should maintain.
6///
7/// Market data kinds carry the instrument. Account kinds ([`OrderState`](Self::OrderState),
8/// [`Portfolio`](Self::Portfolio), [`Executions`](Self::Executions)) are per account and carry
9/// nothing.
10#[derive(Debug, Clone, PartialEq, Eq, Hash)]
11pub enum SubscriptionKind {
12 /// Order book updates.
13 OrderBook {
14 /// The instrument to follow.
15 instrument: InstrumentId,
16 /// Number of price levels per side.
17 depth: u32,
18 },
19 /// Best bid and ask updates.
20 Quotes {
21 /// The instrument to follow.
22 instrument: InstrumentId,
23 },
24 /// Trades printed on the market, by all participants.
25 LastTrades {
26 /// The instrument to follow.
27 instrument: InstrumentId,
28 },
29 /// Updates of the current candle.
30 LastCandle {
31 /// The instrument to follow.
32 instrument: InstrumentId,
33 /// Candle length.
34 timeframe: Timeframe,
35 },
36 /// State changes of the account's own orders.
37 OrderState,
38 /// Portfolio, positions and balances updates.
39 Portfolio,
40 /// Own fills, pushed as `Event::Execution`.
41 Executions,
42}
43
44/// One wanted subscription: what to follow, under which id.
45///
46/// The id is given by the runtime and stays the same for the life of the subscription. Events
47/// for it carry this id.
48#[derive(Debug, Clone, PartialEq, Eq, Hash)]
49pub struct DesiredSubscription {
50 /// The id events of this subscription are tagged with.
51 pub id: SubscriptionId,
52 /// What the subscription follows.
53 pub kind: SubscriptionKind,
54}
55
56/// The full set of subscriptions the consumer wants: the input of
57/// [`BrokerCore::apply`](crate::BrokerCore::apply).
58///
59/// It is a plain list in the order given. The set does not check for duplicates: two entries with
60/// the same id both stay, and [`find`](Self::find) returns the first.
61///
62/// # Examples
63///
64/// ```
65/// use brokapi_core::{InstrumentId, InstrumentKey, NativeId, SubscriptionId};
66/// use brokapi_sansio::{DesiredSubscription, SubscriptionKind, SubscriptionSet};
67///
68/// let sber = InstrumentId::new(
69/// InstrumentKey::new("SBER", "TQBR"),
70/// NativeId::TickerClass { ticker: "SBER".into(), class_code: "TQBR".into() },
71/// );
72/// let quotes = DesiredSubscription {
73/// id: SubscriptionId::new(1),
74/// kind: SubscriptionKind::Quotes { instrument: sber.clone() },
75/// };
76/// let book = DesiredSubscription {
77/// id: SubscriptionId::new(2),
78/// kind: SubscriptionKind::OrderBook { instrument: sber, depth: 10 },
79/// };
80///
81/// let set = SubscriptionSet::with_subscriptions(vec![quotes.clone(), book]);
82/// assert_eq!(set.subs().len(), 2);
83/// assert_eq!(set.find(SubscriptionId::new(1)), Some("es));
84/// assert!(set.find(SubscriptionId::new(9)).is_none());
85/// assert!(SubscriptionSet::new().is_empty());
86/// ```
87#[derive(Debug, Clone, Default, PartialEq, Eq)]
88pub struct SubscriptionSet {
89 subs: Vec<DesiredSubscription>,
90}
91
92impl SubscriptionSet {
93 /// Creates an empty set: no subscriptions wanted.
94 pub fn new() -> Self {
95 Self::default()
96 }
97
98 /// Creates a set from a list, keeping its order.
99 pub fn with_subscriptions(subs: Vec<DesiredSubscription>) -> Self {
100 Self { subs }
101 }
102
103 /// The subscriptions, in the order given.
104 pub fn subs(&self) -> &[DesiredSubscription] {
105 &self.subs
106 }
107
108 /// Whether the set wants nothing.
109 pub fn is_empty(&self) -> bool {
110 self.subs.is_empty()
111 }
112
113 /// Iterates over the subscriptions, in the order given.
114 pub fn iter(&self) -> impl Iterator<Item = &DesiredSubscription> {
115 self.subs.iter()
116 }
117
118 /// The subscription with this id, or `None`.
119 pub fn find(&self, id: SubscriptionId) -> Option<&DesiredSubscription> {
120 self.subs.iter().find(|s| s.id == id)
121 }
122}