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