Skip to main content

rustrade_data/exchange/alpaca/
channel.rs

1use super::Alpaca;
2use crate::{
3    Identifier,
4    subscription::{Subscription, book::OrderBooksL1, quote::Quotes, trade::PublicTrades},
5};
6
7/// Alpaca WebSocket channel types.
8///
9/// Maps to the subscription arrays in the subscribe message:
10/// ```json
11/// {"action":"subscribe","trades":["AAPL"],"quotes":["AAPL"]}
12/// ```
13#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
14pub enum AlpacaChannel {
15    /// Real-time trades stream.
16    Trades,
17    /// Real-time quotes stream (NBBO for equities, bid/ask for crypto).
18    Quotes,
19}
20
21impl AlpacaChannel {
22    /// The channel [`AsRef<str>`] spells as `name`, if any.
23    pub fn from_name(name: &str) -> Option<Self> {
24        match name {
25            "trades" => Some(Self::Trades),
26            "quotes" => Some(Self::Quotes),
27            _ => None,
28        }
29    }
30}
31
32impl AsRef<str> for AlpacaChannel {
33    fn as_ref(&self) -> &str {
34        match self {
35            Self::Trades => "trades",
36            Self::Quotes => "quotes",
37        }
38    }
39}
40
41impl<Server, Instrument> Identifier<AlpacaChannel>
42    for Subscription<Alpaca<Server>, Instrument, PublicTrades>
43{
44    fn id(&self) -> AlpacaChannel {
45        AlpacaChannel::Trades
46    }
47}
48
49impl<Server, Instrument> Identifier<AlpacaChannel>
50    for Subscription<Alpaca<Server>, Instrument, Quotes>
51{
52    fn id(&self) -> AlpacaChannel {
53        AlpacaChannel::Quotes
54    }
55}
56
57/// Alpaca's top of book is its quote, so an L1 stream reads the `quotes` channel. It shares the
58/// `(channel, symbol)` pair with any [`Quotes`] stream on the same symbol and feed.
59impl<Server, Instrument> Identifier<AlpacaChannel>
60    for Subscription<Alpaca<Server>, Instrument, OrderBooksL1>
61{
62    fn id(&self) -> AlpacaChannel {
63        AlpacaChannel::Quotes
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_channel_as_ref() {
73        assert_eq!(AlpacaChannel::Trades.as_ref(), "trades");
74        assert_eq!(AlpacaChannel::Quotes.as_ref(), "quotes");
75    }
76
77    #[test]
78    fn every_channel_round_trips_through_its_name() {
79        for channel in [AlpacaChannel::Trades, AlpacaChannel::Quotes] {
80            assert_eq!(AlpacaChannel::from_name(channel.as_ref()), Some(channel));
81        }
82        assert_eq!(AlpacaChannel::from_name("bars"), None);
83    }
84}