Skip to main content

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(&quotes));
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}