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::{error::SocketError, protocol::websocket::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/// [`Bitfinex`] exchange.
68///
69/// See docs: <https://docs.bitfinex.com/docs/ws-general>
70#[derive(
71 Copy,
72 Clone,
73 Eq,
74 PartialEq,
75 Ord,
76 PartialOrd,
77 Hash,
78 Debug,
79 Default,
80 Display,
81 DeExchange,
82 SerExchange,
83)]
84pub struct Bitfinex;
85
86impl Connector for Bitfinex {
87 const ID: ExchangeId = ExchangeId::Bitfinex;
88 type Channel = BitfinexChannel;
89 type Market = BitfinexMarket;
90 type Subscriber = WebSocketSubscriber;
91 type SubValidator = BitfinexWebSocketSubValidator;
92 type SubResponse = BitfinexPlatformEvent;
93
94 fn url() -> Result<Url, SocketError> {
95 Url::parse(BASE_URL_BITFINEX).map_err(SocketError::UrlParse)
96 }
97
98 fn requests(exchange_subs: Vec<ExchangeSub<Self::Channel, Self::Market>>) -> Vec<WsMessage> {
99 exchange_subs
100 .into_iter()
101 .map(|ExchangeSub { channel, market }| {
102 WsMessage::text(
103 json!({
104 "event": "subscribe",
105 "channel": channel.as_ref(),
106 "symbol": market.as_ref(),
107 })
108 .to_string(),
109 )
110 })
111 .collect()
112 }
113}
114
115impl<Instrument> StreamSelector<Instrument, PublicTrades> for Bitfinex
116where
117 Instrument: InstrumentData,
118{
119 type SnapFetcher = NoInitialSnapshots;
120 type Stream = ExchangeWsStream<
121 StatelessTransformer<Self, Instrument::Key, PublicTrades, BitfinexMessage>,
122 >;
123}