barter_data/exchange/bitfinex/mod.rs
1//!
2//! ### Notes
3//! #### SubscripionId
4//! - Successful Bitfinex subscription responses contain a numeric `CHANNEL_ID` that must be used to
5//! identify future messages relating to that subscription (not persistent across connections).
6//! - To identify the initial subscription response containing the `CHANNEL_ID`, the "channel" &
7//! "market" identifiers can be used for the `SubscriptionId(channel|market)`
8//! (eg/ SubscriptionId("trades|tBTCUSD")).
9//! - Once the subscription has been validated and the `CHANNEL_ID` determined, each `SubscriptionId`
10//! in the `SubscriptionIds` `HashMap` is mutated to become `SubscriptionId(CHANNEL_ID)`.
11//! eg/ SubscriptionId("trades|tBTCUSD") -> SubscriptionId(69)
12//!
13//! #### Connection Limits
14//! - The user is allowed up to 20 connections per minute on the public API.
15//! - Each connection can be used to connect up to 25 different channels.
16//!
17//! #### Trade Variants
18//! - Bitfinex trades subscriptions results in receiving tag="te" & tag="tu" trades.
19//! - Both appear to be identical payloads, but "te" arriving marginally faster.
20//! - Therefore, tag="tu" trades are filtered out and considered only as additional Heartbeats.
21
22use self::{
23 channel::BitfinexChannel, market::BitfinexMarket, message::BitfinexMessage,
24 subscription::BitfinexPlatformEvent, validator::BitfinexWebSocketSubValidator,
25};
26use crate::{
27 ExchangeWsStream, NoInitialSnapshots,
28 exchange::{Connector, ExchangeSub, StreamSelector},
29 instrument::InstrumentData,
30 subscriber::WebSocketSubscriber,
31 subscription::trade::PublicTrades,
32 transformer::stateless::StatelessTransformer,
33};
34use barter_instrument::exchange::ExchangeId;
35use barter_integration::protocol::websocket::{WebSocketSerdeParser, WsMessage};
36use barter_macro::{DeExchange, SerExchange};
37use derive_more::Display;
38use serde_json::json;
39use url::Url;
40
41/// Defines the type that translates a Barter [`Subscription`](crate::subscription::Subscription)
42/// into an exchange [`Connector`] specific channel used for generating [`Connector::requests`].
43pub mod channel;
44
45/// Defines the type that translates a Barter [`Subscription`](crate::subscription::Subscription)
46/// into an exchange [`Connector`] specific market used for generating [`Connector::requests`].
47pub mod market;
48
49/// [`BitfinexMessage`] type for [`Bitfinex`].
50pub mod message;
51
52/// [`Subscription`](crate::subscription::Subscription) response types and response
53/// [`Validator`](barter_integration::Validator) for [`Bitfinex`].
54pub mod subscription;
55
56/// Public trade types for [`Bitfinex`].
57pub mod trade;
58
59/// Custom `SubscriptionValidator` implementation for [`Bitfinex`].
60pub mod validator;
61
62/// [`Bitfinex`] server base url.
63///
64/// See docs: <https://docs.bitfinex.com/docs/ws-general>
65pub const BASE_URL_BITFINEX: &str = "wss://api-pub.bitfinex.com/ws/2";
66
67/// Convenient type alias for a Bitfinex [`ExchangeWsStream`] using [`WebSocketSerdeParser`](barter_integration::protocol::websocket::WebSocketSerdeParser).
68pub type BitfinexWsStream<Transformer> = ExchangeWsStream<WebSocketSerdeParser, Transformer>;
69
70/// [`Bitfinex`] exchange.
71///
72/// See docs: <https://docs.bitfinex.com/docs/ws-general>
73#[derive(
74 Copy,
75 Clone,
76 Eq,
77 PartialEq,
78 Ord,
79 PartialOrd,
80 Hash,
81 Debug,
82 Default,
83 Display,
84 DeExchange,
85 SerExchange,
86)]
87pub struct Bitfinex;
88
89impl Connector for Bitfinex {
90 const ID: ExchangeId = ExchangeId::Bitfinex;
91 type Channel = BitfinexChannel;
92 type Market = BitfinexMarket;
93 type Subscriber = WebSocketSubscriber;
94 type SubValidator = BitfinexWebSocketSubValidator;
95 type SubResponse = BitfinexPlatformEvent;
96
97 fn url() -> Result<Url, url::ParseError> {
98 Url::parse(BASE_URL_BITFINEX)
99 }
100
101 fn requests(exchange_subs: Vec<ExchangeSub<Self::Channel, Self::Market>>) -> Vec<WsMessage> {
102 exchange_subs
103 .into_iter()
104 .map(|ExchangeSub { channel, market }| {
105 WsMessage::text(
106 json!({
107 "event": "subscribe",
108 "channel": channel.as_ref(),
109 "symbol": market.as_ref(),
110 })
111 .to_string(),
112 )
113 })
114 .collect()
115 }
116}
117
118impl<Instrument> StreamSelector<Instrument, PublicTrades> for Bitfinex
119where
120 Instrument: InstrumentData,
121{
122 type SnapFetcher = NoInitialSnapshots;
123 type Stream = BitfinexWsStream<
124 StatelessTransformer<Self, Instrument::Key, PublicTrades, BitfinexMessage>,
125 >;
126}