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/// Defines the generic [`ExchangeSub`] containing a market and channel combination used by an
67/// exchange [`Connector`] to build [`WsMessage`] subscription payloads.
68pub mod subscription;
69
70/// Internal HTTP helpers shared by the REST-based exchange integrations (Massive, IBKR Flex,
71/// Binance).
72///
73/// Not feature-gated: the Binance surface is always compiled and uses every helper here, so all
74/// three REST clients bound their error-path body reads identically.
75pub(crate) mod http;
76
77/// Default [`Duration`] the [`Connector::SubValidator`] will wait to receive all success responses to actioned
78/// `Subscription` requests.
79pub const DEFAULT_SUBSCRIPTION_TIMEOUT: Duration = Duration::from_secs(10);
80
81/// Defines the [`MarketStream`] kind associated with an exchange
82/// `Subscription` [`SubscriptionKind`].
83///
84/// ### Notes
85/// Must be implemented by an exchange [`Connector`] if it supports a specific
86/// [`SubscriptionKind`].
87pub trait StreamSelector<Instrument, Kind>
88where
89 Self: Connector,
90 Instrument: InstrumentData,
91 Kind: SubscriptionKind,
92{
93 type SnapFetcher: SnapshotFetcher<Self, Kind>;
94 type Stream: MarketStream<Self, Instrument, Kind>;
95}
96
97/// Primary exchange abstraction. Defines how to translate Barter types into exchange specific
98/// types, as well as connecting, subscribing, and interacting with the exchange server.
99///
100/// ### Notes
101/// This must be implemented for a new exchange integration!
102pub trait Connector
103where
104 Self: Clone + Default + Debug + for<'de> Deserialize<'de> + Serialize + Sized,
105{
106 /// Unique identifier for the exchange server being connected with.
107 const ID: ExchangeId;
108
109 /// Type that defines how to translate a Barter `Subscription` into an exchange specific
110 /// channel to be subscribed to.
111 ///
112 /// ### Examples
113 /// - [`BinanceChannel("@depth@100ms")`](binance::channel::BinanceChannel)
114 /// - [`KrakenChannel("trade")`](kraken::channel::KrakenChannel)
115 type Channel: AsRef<str>;
116
117 /// Type that defines how to translate a Barter
118 /// `Subscription` into an exchange specific market that
119 /// can be subscribed to.
120 ///
121 /// ### Examples
122 /// - [`BinanceMarket("btcusdt")`](binance::market::BinanceMarket)
123 /// - [`KrakenMarket("BTC/USDT")`](kraken::market::KrakenMarket)
124 type Market: AsRef<str>;
125
126 /// [`Subscriber`] type that establishes a connection with the exchange server, and actions
127 /// `Subscription`s over the socket.
128 type Subscriber: Subscriber;
129
130 /// [`SubscriptionValidator`] type that listens to responses from the exchange server and
131 /// validates if the actioned `Subscription`s were
132 /// successful.
133 type SubValidator: SubscriptionValidator;
134
135 /// Deserialisable type that the [`Self::SubValidator`] expects to receive from the exchange server in
136 /// response to the `Subscription` [`Self::requests`]
137 /// sent over the [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket). Implements
138 /// [`Validator`] in order to determine if [`Self`]
139 /// communicates a successful `Subscription` outcome.
140 type SubResponse: Validator<Error = SocketError> + Debug + DeserializeOwned;
141
142 /// Base [`Url`] of the exchange server being connected with.
143 fn url() -> Result<Url, url::ParseError>;
144
145 /// Defines [`PingInterval`] of custom application-level
146 /// [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket) pings for the exchange
147 /// server being connected with.
148 ///
149 /// Defaults to `None`, meaning that no custom pings are sent.
150 fn ping_interval() -> Option<PingInterval> {
151 None
152 }
153
154 /// Defines how to translate a collection of [`ExchangeSub`]s into the [`WsMessage`]
155 /// subscription payloads sent to the exchange server.
156 fn requests(exchange_subs: Vec<ExchangeSub<Self::Channel, Self::Market>>) -> Vec<WsMessage>;
157
158 /// Number of `Subscription` responses expected from the
159 /// exchange server in responses to the requests send. Used to validate all
160 /// `Subscription`s were accepted.
161 fn expected_responses<InstrumentKey>(map: &Map<InstrumentKey>) -> usize {
162 map.0.len()
163 }
164
165 /// Expected [`Duration`] the [`SubscriptionValidator`] will wait to receive all success
166 /// responses to actioned `Subscription` requests.
167 fn subscription_timeout() -> Duration {
168 DEFAULT_SUBSCRIPTION_TIMEOUT
169 }
170}
171
172/// Used when an exchange has servers different
173/// [`InstrumentKind`](rustrade_instrument::instrument::kind::InstrumentKind) market data on distinct servers,
174/// allowing all the [`Connector`] logic to be identical apart from what this trait provides.
175///
176/// ### Examples
177/// - [`BinanceServerSpot`](binance::spot::BinanceServerSpot)
178/// - [`BinanceServerFuturesUsd`](binance::futures::BinanceServerFuturesUsd)
179pub trait ExchangeServer: Default + Debug + Clone + Send {
180 const ID: ExchangeId;
181 fn websocket_url() -> &'static str;
182}
183
184/// Defines the frequency and construction function for custom
185/// [`WebSocket`](rustrade_integration::protocol::websocket::WebSocket) pings - used for exchanges
186/// that require additional application-level pings.
187#[derive(Debug)]
188pub struct PingInterval {
189 pub interval: tokio::time::Interval,
190 pub ping: fn() -> WsMessage,
191}