Skip to main content

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}