Skip to main content

rustrade_data/exchange/
mod.rs

1use self::subscription::ExchangeSub;
2use crate::{
3    MarketStream, SnapshotFetcher,
4    instrument::InstrumentData,
5    subscriber::{Subscriber, validator::SubscriptionValidator},
6    subscription::{Map, SubscriptionKind},
7};
8use rustrade_instrument::exchange::ExchangeId;
9use rustrade_integration::{
10    Validator, error::SocketError, protocol::websocket::WsMessage, subscription::SubscriptionId,
11};
12use serde::{Deserialize, Serialize, de::DeserializeOwned};
13use std::{fmt::Debug, time::Duration};
14use url::Url;
15
16/// `BinanceSpot` & `BinanceFuturesUsd` [`Connector`] and [`StreamSelector`] implementations.
17pub mod binance;
18
19/// `Bitfinex` [`Connector`] and [`StreamSelector`] implementations.
20pub mod bitfinex;
21
22/// `Bitmex [`Connector`] and [`StreamSelector`] implementations.
23pub mod bitmex;
24
25/// `Bybit` ['Connector'] and ['StreamSelector'] implementation
26pub mod bybit;
27
28/// `Coinbase` [`Connector`] and [`StreamSelector`] implementations.
29pub mod coinbase;
30
31/// `GateioSpot`, `GateioFuturesUsd` & `GateioFuturesBtc` [`Connector`] and [`StreamSelector`]
32/// implementations.
33pub mod gateio;
34
35/// `Kraken` [`Connector`] and [`StreamSelector`] implementations.
36pub mod kraken;
37
38/// `Okx` [`Connector`] and [`StreamSelector`] implementations.
39pub mod okx;
40
41/// `Hyperliquid` and `HyperliquidSpot` `Connector` and `StreamSelector` implementations (behind `hyperliquid` feature).
42#[cfg(feature = "hyperliquid")]
43pub mod hyperliquid;
44
45/// `Ibkr` market data stream (behind `ibkr` feature).
46#[cfg(feature = "ibkr")]
47pub mod ibkr;
48
49/// `Alpaca` market data stream (behind `alpaca` feature).
50#[cfg(feature = "alpaca")]
51pub mod alpaca;
52
53/// `Databento` historical and live market data (behind `databento` feature).
54#[cfg(feature = "databento")]
55pub mod databento;
56
57/// `Massive` (formerly Polygon.io) market data (behind `massive` feature).
58#[cfg(feature = "massive")]
59pub mod massive;
60
61// No `///` here, unlike its siblings: that file carries its own `//!` documentation, and supplying
62// both makes rustdoc resolve the file's inner links in THIS module's scope rather than the child's,
63// so every one of them renders as dead text. Its summary and the redistribution warning open that
64// file's first paragraph instead.
65#[cfg(feature = "lse")]
66pub mod lse;
67
68/// OSI option contract symbols, shared by the providers that spell contracts that way.
69#[cfg(any(feature = "lse", feature = "massive"))]
70pub(crate) mod osi;
71
72/// Defines the generic [`ExchangeSub`] containing a market and channel combination used by an
73/// exchange [`Connector`] to build [`WsMessage`] subscription payloads.
74pub mod subscription;
75
76/// Internal HTTP helpers shared by the REST-based exchange integrations (Massive, IBKR Flex,
77/// Binance).
78///
79/// Not feature-gated: the Binance surface is always compiled and uses every helper here, so all
80/// three REST clients bound their error-path body reads identically.
81pub(crate) mod http;
82
83/// Default [`Duration`] the [`Connector::SubValidator`] will wait to receive all success responses to actioned
84/// `Subscription` requests.
85pub const DEFAULT_SUBSCRIPTION_TIMEOUT: Duration = Duration::from_secs(10);
86
87/// Defines the [`MarketStream`] kind associated with an exchange
88/// `Subscription` [`SubscriptionKind`].
89///
90/// ### Notes
91/// Must be implemented by an exchange [`Connector`] if it supports a specific
92/// [`SubscriptionKind`].
93pub trait StreamSelector<Instrument, Kind>
94where
95    Self: Connector,
96    Instrument: InstrumentData,
97    Kind: SubscriptionKind,
98{
99    type SnapFetcher: SnapshotFetcher<Self, Kind>;
100    type Stream: MarketStream<Self, Instrument, Kind>;
101}
102
103/// Primary exchange abstraction. Defines how to translate Barter types into exchange specific
104/// types, as well as connecting, subscribing, and interacting with the exchange server.
105///
106/// ### Notes
107/// This must be implemented for a new exchange integration!
108pub trait Connector
109where
110    Self: Clone + Default + Debug + for<'de> Deserialize<'de> + Serialize + Sized,
111{
112    /// Unique identifier for the exchange server being connected with.
113    const ID: ExchangeId;
114
115    /// Type that defines how to translate a Barter `Subscription` into an exchange specific
116    /// channel to be subscribed to.
117    ///
118    /// ### Examples
119    /// - [`BinanceChannel("@depth@100ms")`](binance::channel::BinanceChannel)
120    /// - [`KrakenChannel("trade")`](kraken::channel::KrakenChannel)
121    type Channel: AsRef<str>;
122
123    /// Type that defines how to translate a Barter
124    /// `Subscription` into an exchange specific market that
125    /// can be subscribed to.
126    ///
127    /// ### Examples
128    /// - [`BinanceMarket("btcusdt")`](binance::market::BinanceMarket)
129    /// - [`KrakenMarket("BTC/USDT")`](kraken::market::KrakenMarket)
130    type Market: AsRef<str>;
131
132    /// [`Subscriber`] type that establishes a connection with the exchange server, and actions
133    /// `Subscription`s over the socket.
134    type Subscriber: Subscriber;
135
136    /// [`SubscriptionValidator`] type that listens to responses from the exchange server and
137    /// validates if the actioned `Subscription`s were
138    /// successful.
139    type SubValidator: SubscriptionValidator;
140
141    /// Deserialisable type that the [`Self::SubValidator`] expects to receive from the exchange server in
142    /// response to the `Subscription` [`Self::requests`]
143    /// sent over the [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket). Implements
144    /// [`Validator`] in order to determine if [`Self`]
145    /// communicates a successful `Subscription` outcome.
146    type SubResponse: Validator<Error = SocketError> + Debug + DeserializeOwned;
147
148    /// Base [`Url`] of the exchange server being connected with.
149    fn url() -> Result<Url, url::ParseError>;
150
151    /// Defines [`PingInterval`] of custom application-level
152    /// [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket) pings for the exchange
153    /// server being connected with.
154    ///
155    /// Defaults to `None`, meaning that no custom pings are sent.
156    fn ping_interval() -> Option<PingInterval> {
157        None
158    }
159
160    /// Defines how to translate a collection of [`ExchangeSub`]s into the [`WsMessage`]
161    /// subscription payloads sent to the exchange server.
162    fn requests(exchange_subs: Vec<ExchangeSub<Self::Channel, Self::Market>>) -> Vec<WsMessage>;
163
164    /// Number of `Subscription` responses expected from the
165    /// exchange server in responses to the requests send. Used to validate all
166    /// `Subscription`s were accepted.
167    fn expected_responses<InstrumentKey>(map: &Map<InstrumentKey>) -> usize {
168        map.0.len()
169    }
170
171    /// The subscription a successful [`Self::SubResponse`] acknowledges, as the [`SubscriptionId`]
172    /// the mapper keyed it under.
173    ///
174    /// Lets a failed validation name the subscriptions left unacknowledged. Defaults to `None`,
175    /// for venues that acknowledge a whole batch at once or do not echo the subscription; the
176    /// failure then names the whole batch. An override must build exactly the identifier the
177    /// mapper produced: one that never matches makes the failure name the whole batch too.
178    fn acknowledged_subscription(_response: &Self::SubResponse) -> Option<SubscriptionId> {
179        None
180    }
181
182    /// Expected [`Duration`] the [`SubscriptionValidator`] will wait to receive all success
183    /// responses to actioned `Subscription` requests.
184    fn subscription_timeout() -> Duration {
185        DEFAULT_SUBSCRIPTION_TIMEOUT
186    }
187}
188
189/// Used when an exchange has servers different
190/// [`InstrumentKind`](rustrade_instrument::instrument::kind::InstrumentKind) market data on distinct servers,
191/// allowing all the [`Connector`] logic to be identical apart from what this trait provides.
192///
193/// ### Examples
194/// - [`BinanceServerSpot`](binance::spot::BinanceServerSpot)
195/// - [`BinanceServerFuturesUsd`](binance::futures::BinanceServerFuturesUsd)
196pub trait ExchangeServer: Default + Debug + Clone + Send {
197    const ID: ExchangeId;
198    fn websocket_url() -> &'static str;
199}
200
201/// Defines the frequency and construction function for custom
202/// [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket) pings - used for exchanges
203/// that require additional application-level pings.
204#[derive(Debug)]
205pub struct PingInterval {
206    pub interval: tokio::time::Interval,
207    pub ping: fn() -> WsMessage,
208}