Skip to main content

bybit_rust_api/ws/public/
ticker.rs

1//! Ticker stream — 24hr rolling window statistics.
2//!
3//! # Topic format
4//! `tickers.{symbol}` — e.g. `tickers.BTCUSDT`
5//!
6//! Works for all categories: linear, inverse, spot, option.
7
8use serde::Deserialize;
9
10/// Ticker data for a single symbol (24hr stats).
11#[derive(Debug, Clone, Deserialize)]
12pub struct TickerData {
13    /// Symbol
14    #[serde(rename = "symbol")]
15    #[serde(default)]
16    pub symbol: Option<String>,
17    /// Last traded price
18    #[serde(rename = "lastPrice")]
19    #[serde(default)]
20    pub last_price: Option<String>,
21    /// 24hr high
22    #[serde(rename = "highPrice24h")]
23    #[serde(default)]
24    pub high_price_24h: Option<String>,
25    /// 24hr low
26    #[serde(rename = "lowPrice24h")]
27    #[serde(default)]
28    pub low_price_24h: Option<String>,
29    /// Previous 24hr price (for % change calc)
30    #[serde(rename = "prevPrice24h")]
31    #[serde(default)]
32    pub prev_price_24h: Option<String>,
33    /// 24hr price change %
34    #[serde(rename = "price24hPcnt")]
35    #[serde(default)]
36    pub price_24h_pcnt: Option<String>,
37    /// 24hr volume
38    #[serde(rename = "volume24h")]
39    #[serde(default)]
40    pub volume_24h: Option<String>,
41    /// 24hr turnover (USDT value)
42    #[serde(rename = "turnover24h")]
43    #[serde(default)]
44    pub turnover_24h: Option<String>,
45    /// Open interest (derivatives)
46    #[serde(rename = "openInterest")]
47    #[serde(default)]
48    pub open_interest: Option<String>,
49    /// Open interest value
50    #[serde(rename = "openInterestValue")]
51    #[serde(default)]
52    pub open_interest_value: Option<String>,
53    /// Index price (derivatives)
54    #[serde(rename = "indexPrice")]
55    #[serde(default)]
56    pub index_price: Option<String>,
57    /// Mark price (derivatives)
58    #[serde(rename = "markPrice")]
59    #[serde(default)]
60    pub mark_price: Option<String>,
61    /// Funding rate (derivatives)
62    #[serde(rename = "fundingRate")]
63    #[serde(default)]
64    pub funding_rate: Option<String>,
65    /// Next funding timestamp
66    #[serde(rename = "nextFundingTime")]
67    #[serde(default)]
68    pub next_funding_time: Option<String>,
69    /// Best bid price
70    #[serde(rename = "bid1Price")]
71    #[serde(default)]
72    pub bid1_price: Option<String>,
73    /// Best ask price
74    #[serde(rename = "ask1Price")]
75    #[serde(default)]
76    pub ask1_price: Option<String>,
77    /// Category: "spot", "linear", "inverse", "option"
78    #[serde(rename = "category")]
79    #[serde(default)]
80    pub category: Option<String>,
81}
82
83/// Typed wrapper for ticker stream data.
84pub struct TickerStream;
85
86impl TickerStream {
87    /// Parse raw WS data into typed TickerData.
88    pub fn parse(data: &serde_json::Value) -> serde_json::Result<TickerData> {
89        serde_json::from_value(data.clone())
90    }
91
92    /// Check if the given topic matches a ticker channel.
93    pub fn matches_topic(topic: &str) -> bool {
94        topic.starts_with("tickers.")
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_parse_ticker() {
104        let json = serde_json::json!({
105            "symbol": "BTCUSDT",
106            "lastPrice": "50000.00",
107            "highPrice24h": "51000.00",
108            "lowPrice24h": "49000.00",
109            "volume24h": "15000.5",
110            "turnover24h": "750000000.00",
111            "price24hPcnt": "0.025",
112            "category": "linear"
113        });
114
115        let ticker = TickerStream::parse(&json).unwrap();
116        assert_eq!(ticker.symbol.as_deref(), Some("BTCUSDT"));
117        assert_eq!(ticker.last_price.as_deref(), Some("50000.00"));
118        assert_eq!(ticker.category.as_deref(), Some("linear"));
119    }
120
121    #[test]
122    fn test_matches_topic() {
123        assert!(TickerStream::matches_topic("tickers.BTCUSDT"));
124        assert!(!TickerStream::matches_topic("orderbook.1.BTCUSDT"));
125    }
126}