Skip to main content

crypto_ws_client/clients/bybit/
bybit_linear_swap.rs

1use async_trait::async_trait;
2
3use crate::{
4    clients::common_traits::{
5        Candlestick, Level3OrderBook, OrderBook, OrderBookTopK, Ticker, Trade, BBO,
6    },
7    common::{command_translator::CommandTranslator, ws_client_internal::WSClientInternal},
8    WSClient,
9};
10
11use super::utils::{BybitMessageHandler, EXCHANGE_NAME};
12
13const WEBSOCKET_URL: &str = "wss://stream.bybit.com/realtime_public";
14
15/// Bybit LinearSwap market.
16///
17/// * WebSocket API doc: <https://bybit-exchange.github.io/docs/inverse/#t-websocket>
18/// * Trading at: <https://www.bybit.com/trade/inverse/>
19pub struct BybitLinearSwapWSClient {
20    client: WSClientInternal<BybitMessageHandler>,
21    translator: BybitLinearCommandTranslator,
22}
23
24impl_new_constructor!(
25    BybitLinearSwapWSClient,
26    EXCHANGE_NAME,
27    WEBSOCKET_URL,
28    BybitMessageHandler {},
29    BybitLinearCommandTranslator {}
30);
31
32impl_trait!(Trade, BybitLinearSwapWSClient, subscribe_trade, "trade");
33#[rustfmt::skip]
34// Prefer orderBookL2_25 over orderBook_200.100ms because /public/orderBook/L2
35// returns a top 25 snapshot, which is the same depth as orderBookL2_25.
36impl_trait!(OrderBook, BybitLinearSwapWSClient, subscribe_orderbook, "orderBookL2_25");
37#[rustfmt::skip]
38impl_trait!(Ticker, BybitLinearSwapWSClient, subscribe_ticker, "instrument_info.100ms");
39impl_candlestick!(BybitLinearSwapWSClient);
40panic_bbo!(BybitLinearSwapWSClient);
41panic_l3_orderbook!(BybitLinearSwapWSClient);
42panic_l2_topk!(BybitLinearSwapWSClient);
43
44impl_ws_client_trait!(BybitLinearSwapWSClient);
45
46struct BybitLinearCommandTranslator {}
47
48impl BybitLinearCommandTranslator {
49    // https://bybit-exchange.github.io/docs/linear/#t-websocketkline
50    fn to_candlestick_raw_channel(interval: usize) -> String {
51        let interval_str = match interval {
52            60 => "1",
53            180 => "3",
54            300 => "5",
55            900 => "15",
56            1800 => "30",
57            3600 => "60",
58            7200 => "120",
59            14400 => "240",
60            21600 => "360",
61            86400 => "D",
62            604800 => "W",
63            2592000 => "M",
64            _ => panic!(
65                "Bybit LinearSwap has intervals 1min,5min,15min,30min,60min,4hour,1day,1week,1mon"
66            ),
67        };
68        format!("candle.{interval_str}")
69    }
70}
71
72impl CommandTranslator for BybitLinearCommandTranslator {
73    fn translate_to_commands(&self, subscribe: bool, topics: &[(String, String)]) -> Vec<String> {
74        vec![super::utils::topics_to_command(topics, subscribe)]
75    }
76
77    fn translate_to_candlestick_commands(
78        &self,
79        subscribe: bool,
80        symbol_interval_list: &[(String, usize)],
81    ) -> Vec<String> {
82        let topics = symbol_interval_list
83            .iter()
84            .map(|(symbol, interval)| {
85                let channel = Self::to_candlestick_raw_channel(*interval);
86                (channel, symbol.to_string())
87            })
88            .collect::<Vec<(String, String)>>();
89        self.translate_to_commands(subscribe, &topics)
90    }
91}